1
0
mirror of https://github.com/salexdv/bsl_console.git synced 2025-09-16 09:06:17 +02:00

Merge pull request #293 from salexdv/develop

Update master from develop
This commit is contained in:
Alexander Shkuraev
2022-10-14 09:52:01 +03:00
committed by GitHub
13 changed files with 1022 additions and 21831 deletions

View File

@@ -1,3 +1,17 @@
## 0.3.3 (14.10.2022)
### Улучшения:
* Добавлена подсказка табличных частей в источниках запроса
* Добавлена подсказка реквизитов табличных частей в запросе
* Добавлена подсказка для функции ВЫРАЗИТЬ в запросе
* Устранены зависания редактора в режиме запроса, возникающие при расчете сворачиваемых блоков
* Доработано получение параметров из описания процедур/функций при загрузке текстов модулей
* Расширен API для взаимодействия с редактором из 1С
* Функция для изменения масштаба
* Функция для перехода к строке
* Исправлены выявленные ошибки
## 0.3.2 (25.08.2022)
### Новое:

View File

@@ -88,6 +88,7 @@
| `enableQuickSuggestions` | Включает/выключает режим быстрых подсказок |
| `minimap` | Включает/выключает отображение карты кода |
| [`compare`](docs/compare.md) | Включает/выключает режим сравнения текстов |
| `getDiffCount` | Возвращает количество изменений в режиме сравнения |
| `nextDiff` | Переход с следующему изменению в режиме сравнения |
| `previousDiff` | Переход с предыдущему изменению в режиме сравнения |
| `getVarsNames` | Возвращает имена всех объявленных в коде переменных |
@@ -170,6 +171,11 @@
| `unfold` | Разворачивает текущий блок |
| `foldAll` | Сворачиват все блоки |
| `unfoldAll` | Разворачивает все блоки |
| [`showVariablesDescription`]((docs/show_var_description.md)) | Вывод окна со значениями переменных (табло) |
| [`updateVariableDescription`]((docs/upd_var_drscription.md)) | Обновление значения переменной в табло |
| `scale` | Изменение масштаба (+1 - увеличить, -1 - уменьшить, 0 - сбросить) |
| `gotoLine` | Перейти к строке... |
| `setActiveSuggestionAcceptors` | Установка символов, подтверждающих выбор текущего пункта подсказки (в дополнение к Enter) |
## События, генерируемые редактором для 1С:Предприятия
@@ -193,6 +199,7 @@
| `EVENT_GET_DEFINITION` | При переходе к определению [(подробнее)](docs/get_definition_event.md) |
| `EVENT_ON_KEY_DOWN` | При нажатии на клавиатуру [(подробнее)](docs/key_down_event.md) |
| `EVENT_ON_INSERT_SNIPPET` | При вставке сниппета (шаблона) [(подробнее)](docs/insert_snippet_event.md) |
| `EVENT_GET_VARIABLE_DATA` | При расшифровке значения переменной в табло [(подробнее)](docs/get_var_data_event.md) |
*Перед началом работы с редактором из 1С Предприятия желательно вызвать функцию инициализации и передать в нее текущую версию платформы.*
Пример:

View File

@@ -0,0 +1,11 @@
# Событие *EVENT_GET_VARIABLE_DATA*
## Назначение события
Событие генерируется при расшифровке значения переменной в табло. См. [`showVariablesDescription`](show_var_description.md)
## Параметры события
* **variableId** - уникальный ключ (идентификатор) переменной, который ранее был передан в [`showVariablesDescription`](show_var_description.md)/[`updateVariableDescription`](upd_var_description.md)
* **variablePath** - путь для получения значение переменной
* **variableName** - имя переменной

View File

@@ -0,0 +1,44 @@
# Функция *showVariablesDescription*
## Назначение функции
Вывод окна со значениями переменных после выполнения кода.
## Параметры функции
* **variablesJSON** - *string*, массив переменных в виде JSON-объекта, со следующими полями:
* [label] - *строка*, имя переменной
* [value] - *строка*, значение переменной
* [type] - *строка*, тип переменной
* [path] - *строка*, путь для получения значения переменной. Используется в событии [`EVENT_GET_VARIABLE_DATA`](get_var_data_event.md)
* [class] - *строка*, **final** для переменных, дальнейшая расшифровка которых не требуется. Например, для переменных с примитивны типами
* [icon] - *строка*, картинка для переменной. Может принимать значения с именами файлов из каталога `./tree/icons`
## Примеры вызова функции
```javascript
updateMetadata(`{
"var_a1d9567a17e94693a19426783ac8f70a": {
"label": "ВидНоменклатуры",
"value": "<a href='e1cib/data/Справочник.ВидыНоменклатуры?ref=80e20050569f16cd11e6d8d63deb713b'>Услуги</a>",
"type": "Вид номенклатуры",
"path": "",
"class": "",
"icon": "catalog.png"
},
"var_6831a574610a499cad80fe79ed554d29": {
"label": "НачалоПериода",
"value": "26.08.2022 14:38:21",
"type": "Дата",
"path": "",
"class": "final",
"icon": "date.png"
}
}`);
```
## Обновление переменных
Обновление значений переменных производится с помощью вызова [`updateVariableDescription`](upd_var_description.md)

View File

@@ -0,0 +1,66 @@
# Функция *updateVariableDescription*
## Назначение функции
Используется для обновления значения переменной в табло. Функцию следует использовать для ответа на событие [`EVENT_GET_VARIABLE_DATA`](get_var_data_event.md)
## Параметры функции
* **variableId** - *string*, уникальный ключ (идентификатор) переменной
* **variableJSON** - *string*, массив с данными переменной виде JSON-объекта, со следующими полями:
* [label] - *строка*, имя переменной
* [value] - *строка*, значение переменной
* [type] - *строка*, тип переменной
* [path] - *строка*, путь для получения значения переменной.
* [class] - *строка*, **final** для переменных, дальнейшая расшифровка которых не требуется. Например, для переменных с примитивны типами
* [icon] - *строка*, картинка для переменной. Может принимать значения с именами файлов из каталога `./tree/icons`
* [children] - *строка*, данные переменной (реквизиты, табличные части и т.п.), содержащие поля, указанные выше
## Примеры вызова функции
```javascript
updateVariableDescription('var_b13b613706d945b6a7cb73faaeceff8d', `{
"var_b13b613706d945b6a7cb73faaeceff8d": {
"label": "ВидНоменклатуры",
"value": "<a href='e1cib/data/Справочник.ВидыНоменклатуры?ref=80e20050569f16cd11e6d8d63deb713b'>Услуги</a>",
"type": "Вид номенклатуры",
"path": "var_b13b613706d945b6a7cb73faaeceff8d",
"class": "",
"icon": "catalog.png",
"children": {
"var_e00ab5471573473e81a0c02299da5880": {
"label": "УникальныйИдентификатор",
"value": "3deb713b-d8d6-11e6-80e2-0050569f16cd",
"type": "Уникальный идентификатор",
"path": "var_b13b613706d945b6a7cb73faaeceff8d.УникальныйИдентификатор",
"class": "final",
"icon": "uuid.png"
},
"var_b8d81a566dcc4441b3bd754fd1b954cf": {
"label": "ПометкаУдаления",
"value": "Нет",
"type": "Булево",
"path": "var_b13b613706d945b6a7cb73faaeceff8d.ПометкаУдаления",
"class": "final",
"icon": "boolean.png"
},
"var_3a30ab9aabaa432a80372f590ca10c97": {
"label": "Наименование",
"value": "Услуги",
"type": "Строка",
"path": "var_b13b613706d945b6a7cb73faaeceff8d.Наименование",
"class": "final",
"icon": "string.png"
},
"var_5aa921edaf774a8bb3e82f604a901cbd": {
"label": "ГруппаАналитическогоУчета",
"value": "",
"type": "Группа аналитического учета номенклатуры",
"path": "var_b13b613706d945b6a7cb73faaeceff8d.ГруппаАналитическогоУчета",
"class": "",
"icon": "catalog.png"
}
}
}
}`);
```

View File

@@ -4238,6 +4238,7 @@ define([], function () {
"name": "СоздатьФабрикуXDTO",
"name_en": "CreateXDTOFactory",
"returns": "Тип: ФабрикаXDTO. ",
"ref": "classes.ФабрикаXDTO",
"signature": {
"ПоИмениФайла": {
"СтрокаПараметров": "(Путь: Строка, Пакеты?: Массив): ФабрикаXDTO",
@@ -5614,7 +5615,8 @@ define([], function () {
"ФабрикаXDTO": {
"name": "ФабрикаXDTO",
"name_en": "XDTOFactory",
"description": "Фабрика XDTO, содержащая все пакеты XDTO, имеющиеся в конфигурации, а также предопределенные пакеты (например, пакет типов XML схемы)."
"description": "Фабрика XDTO, содержащая все пакеты XDTO, имеющиеся в конфигурации, а также предопределенные пакеты (например, пакет типов XML схемы).",
"ref": "classes.ФабрикаXDTO"
},
"ФайловыеПотоки": {
"name": "ФайловыеПотоки",
@@ -6509,6 +6511,15 @@ define([], function () {
}
}
}
},
"constructors": {
"На основании текста": {
"description": "Создает запрос с указанным текстом.",
"signature": "(ТекстЗапроса?)",
"params": {
"ТекстЗапроса": "Строка с текстом запроса"
}
}
}
},
"COMОбъект": {
@@ -12407,6 +12418,358 @@ define([], function () {
"signature": "()"
}
}
},
"Картинка": {
"name": "Картинка",
"name_en": "Picture",
"description": "Представляет собой картинку из коллекции картинок, пустую картинку, либо картинку, загруженную из внешнего файла, или ссылку на стандартную картинку.",
"properties": {
"Вид": {
"name": "Вид",
"name_en": "Type",
"access": "Чтение",
"description": "Содержит вид картинки",
"value": "ВидКартинки"
},
"НаборВариантов": {
"name": "НаборВариантов",
"name_en": "VariantSet",
"access": "Чтение",
"description": "Истина - картинка содержит несколько вариантов изображений.",
"value": "Булево"
}
},
"methods": {
"Высота": {
"name": "Высота",
"name_en": "Height",
"returns": "Число/Неопределено",
"description": "Возвращает высоту картинки (в пикселях)."
},
"ГлубинаЦвета": {
"name": "ГлубинаЦвета",
"name_en": "ColorDepth",
"returns": "ГлубинаЦвета/Неопределено",
"description": "Возвращает глубину цвета картинки - количество бит для хранения цвета каждой точки изображения."
},
"Записать": {
"name": "Записать",
"name_en": "Write",
"description": "Записывает картинку в файл/поток",
"signature": {
"ВФайл": {
"СтрокаПараметров": "(ИмяФайла, ВсеВарианты?, ПодобратьВариант?)",
"Параметры": {
"ИмяФайла": "Строка, Полное имя файла, в котором будет сохранена картинка",
"ВсеВарианты": "Булево, Данный параметр используется, если картинка представлена архивом, содержащим варианты этой картинки",
"ПодобратьВариант": "Соответствие/Неопределено, Данный параметр используется только, если картинка представлена архивом"
}
},
"ВПоток": {
"СтрокаПараметров": "(Поток, ВсеВарианты?, ПодобратьВариант?)",
"Параметры": {
"Поток": "Поток для записи картинки.",
"ВсеВарианты": "Булево, Данный параметр используется, если картинка представлена архивом, содержащим варианты этой картинки",
"ПодобратьВариант": "Соответствие/Неопределено, Данный параметр используется только, если картинка представлена архивом"
}
}
}
},
"КоличествоКадров": {
"name": "КоличествоКадров",
"name_en": "FrameCount",
"returns": "Число",
"description": "Возвращает количество кадров картинки (применимо для многостраничных файлов TIFF)."
},
"ОттенкиСерого": {
"name": "ОттенкиСерого",
"name_en": "GrayScale",
"returns": "Булево/Неопределено",
"description": "Возвращает признак того, что изображение хранится в виде оттенков серого."
},
"ПлотностьПоВертикали": {
"name": "ПлотностьПоВертикали",
"name_en": "VerticalDensity",
"returns": "Число/Неопределено",
"description": "Возвращает плотность изображения по вертикали - число точек на дюйм (DPI)."
},
"ПлотностьПоГоризонтали": {
"name": "ПлотностьПоГоризонтали",
"name_en": "HorizontalDensity",
"returns": "Число/Неопределено",
"description": "Возвращает плотность изображения по горизонтали - число точек на дюйм (DPI)."
},
"ПолучитьДвоичныеДанные": {
"name": "ПолучитьДвоичныеДанные",
"name_en": "GetBinaryData",
"returns": "ДвоичныеДанные",
"description": "Преобразует картинку в двоичные данные",
"ref": "classes.ДвоичныеДанные",
"signature": {
"ПоУмолчанию": {
"СтрокаПараметров": "(ВсеВарианты?, ПодобратьВариант?)",
"Параметры": {
"ВсеВарианты": "Булево, Данный параметр используется, если картинка представлена архивом, содержащим варианты этой картинки",
"ПодобратьВариант": "Соответствие/Неопределено, Данный параметр используется только, если картинка представлена архивом"
}
}
}
},
"РазмерФайла": {
"name": "РазмерФайла",
"name_en": "FileSize",
"returns": "Число/Неопределено",
"description": "Возвращает размер изображения на диске (в байтах)."
},
"ФильтрИменФайлов": {
"name": "ФильтрИменФайлов",
"name_en": "FileNameFilter",
"returns": "Строка, Фильтр для диалога выбора файлов.",
"description": "Получает фильтры для диалога выбора файлов, соответствующие формату картинки.",
"signature": {
"ПоУмолчанию": {
"СтрокаПараметров": "(ВсеВарианты?, ПодобратьВариант?)",
"Параметры": {
"ВсеВарианты": "Булево, Данный параметр используется, если картинка представлена архивом, содержащим варианты этой картинки",
"ПодобратьВариант": "Соответствие/Неопределено, Данный параметр используется только, если картинка представлена архивом"
}
}
}
},
"Формат": {
"name": "Формат",
"name_en": "Format",
"returns": "Формат картинки",
"description": "Получает формат картинки."
},
"Ширина": {
"name": "Ширина",
"name_en": "Width",
"returns": "Число/Неопределено",
"description": "Возвращает ширину картинки (в пикселях)."
}
},
"constructors": {
"По умолчанию": {
"description": "Создает пустую картинку.",
"signature": "Картинка()"
},
"На основании файла": {
"description": "Создает объект и загружает картинку из указанного файла картинки.",
"signature": "(ИмяФайла, ПрозрачныйФон?)",
"params": {
"ИмяФайла": "Строка, Имя файла, из которого будет загружена картинка.",
"ПрозрачныйФон": "Булево, Определяет, будет ли картинка иметь прозрачные области."
}
},
"Из двоичных данных": {
"description": "Создает объект из двоичных данных.",
"signature": "(ДвоичныеДанные, ПрозрачныйФон?)",
"params": {
"ДвоичныеДанные": "Двоичные данные изображения, из которого будет сформирован объект",
"ПрозрачныйФон": "Булево, Определяет, будет ли картинка иметь прозрачные области."
}
}
}
},
"ФабрикаXDTO": {
"name": "ФабрикаXDTO",
"name_en": "XDTOFactory",
"description": "Фабрика типов XDTO",
"properties": {
"Пакеты": {
"name": "Пакеты",
"name_en": "Packages",
"access": "Чтение",
"description": "Содержит коллекцию пакетов XDTO, составляющих фабрику.",
"value": " КоллекцияПакетовXDTO."
}
},
"methods": {
"ЗаписатьJSON": {
"name": "ЗаписатьJSON",
"name_en": "WriteJSON",
"description": "Записывает указанный элемент данных XDTO в объект записи JSON",
"signature": {
"ПоУмолчанию": {
"СтрокаПараметров": "(ЗаписьJSON, Значение, НазначениеТипаXML?)",
"Параметры": {
"ЗаписьJSON": "ЗаписьJSON, Объект, через который осуществляется запись JSON.",
"Значение": "ЗначениеXDTO/ОбъектXDTO/Неопределено. Записываемое в поток JSON значение.",
"НазначениеТипаXML": "НазначениеТипаXML. Вариант назначения типа элемента данных XDTO."
}
}
}
},
"ЗаписатьXML": {
"name": "ЗаписатьXML",
"name_en": "WriteXML",
"description": "Записывает указанный элемент данных XDTO в объект записи XML.",
"signature": {
"ПоУмолчанию": {
"СтрокаПараметров": "(ЗаписьXML, Элемент, ЛокальноеИмя?, URIПространстваИмен?, Форма?, УказаниеТипа?)",
"Параметры": {
"ЗаписьXML": "Объект записи XML",
"Элемент": "Записываемое значение",
"ЛокальноеИмя": "Локальное имя записываемого элемента данных.",
"URIПространстваИмен": "URI пространства имен записываемого элемента данных.",
"Форма": "Форма представления элемента данных в XDTO.",
"УказаниеТипа": "Вариант назначения типа элемента данных XDTO."
}
}
}
},
"Привести": {
"name": "Привести",
"name_en": "Cast",
"description": "Осуществляет попытку преобразования значения XDTO одного типа в значение XDTO данного типа.",
"signature": {
"ПоУмолчанию": {
"СтрокаПараметров": "(Тип, Значение)",
"Параметры": {
"Тип": "Тип, к которому необходимо привести значение",
"Значение": "Значение, которое необходимо преобразовать к значению указанного типа."
}
}
}
},
"ПрочитатьJSON": {
"name": "ПрочитатьJSON",
"name_en": "ReadJSON",
"description": "Читает элемент данных XDTO указанного типа из объекта чтения JSON.",
"signature": {
"ПоУмолчанию": {
"СтрокаПараметров": "(ЧтениеJSON, Тип?, ИмяФункцииВосстановления?, МодульФункцииВосстановления?, ДополнительныеПараметрыФункцииВосстановления?, ТипыДляОбработкиВосстановления?, ИменаСвойствДляВосстановления?)",
"Параметры": {
"ЧтениеJSON": "Объект чтения JSON",
"Тип": "Тип элемента данных XDTO",
"ИмяФункцииВосстановления": "Имя функции восстановления значения",
"МодульФункцииВосстановления": "Указывает модуль, процедура которого будет использована для восстановления значения",
"ДополнительныеПараметрыФункцииВосстановления": "Дополнительные параметры для функции восстановления.",
"ТипыДляОбработкиВосстановления": "Массив объектов ТипОбъектаXDTO, соответствующих типам XDTO, для которых требуется вызвать функцию восстановления",
"ИменаСвойствДляВосстановления": "Имена свойств, для которых нужно вызвать функцию восстановления"
}
}
}
},
"ПрочитатьXML": {
"name": "ПрочитатьXML",
"name_en": "ReadXML",
"description": "Читает элемент данных XDTO указанного типа из объекта чтения XML.",
"signature": {
"ПоУмолчанию": {
"СтрокаПараметров": "(ЧтениеXML, Тип?)",
"Параметры": {
"ЧтениеXML": "Объект чтения XML",
"Тип": "Тип элемента данных XDTO"
}
}
}
},
"Создать": {
"name": "Создать",
"name_en": "Create",
"description": "Создает значение XDTO по произвольному значению",
"returns": "ЗначениеXDTO",
"signature": {
"ИзЗначения": {
"СтрокаПараметров": "(Тип, Значение)",
"Параметры": {
"Тип": "Тип, значение которого необходимо создать",
"Значение": "Произвольное значение, на основе которого должно быть создано значение XDTO"
}
},
"ПоЛексическомуПредставлению": {
"СтрокаПараметров": "(Тип, Строка)",
"Параметры": {
"Тип": "Тип, значение которого необходимо создать",
"Строка": "Лексическое представление значения."
}
},
"ПоТипу": {
"СтрокаПараметров": "(Тип)",
"Параметры": {
"Тип": "Тип, значение которого необходимо создать"
}
}
}
},
"Тип": {
"name": "Тип",
"name_en": "Type",
"description": "Получение типа XDTO",
"returns": "ТипЗначенияXDTO, ТипОбъектаXDTO, Неопределено",
"signature": {
"URIПространстваИмен": {
"СтрокаПараметров": "(URIПространстваИмен, Имя)",
"Параметры": {
"URIПространстваИмен": "URI пространства имен запрашиваемого типа",
"Имя": "Имя запрашиваемого типа"
}
},
"ИмяXML": {
"СтрокаПараметров": "(ИмяXML)",
"Параметры": {
"ИмяXML": "Расширенное имя XML"
}
},
"ПоТипу": {
"СтрокаПараметров": "(ТипДанных)",
"Параметры": {
"ТипДанных": "Тип данных XML, по которому запрашивается тип XDTO"
}
}
}
},
"ЭкспортМоделиXDTO": {
"name": "ЭкспортМоделиXDTO",
"name_en": "ExportXDTOModel",
"description": "Выполняет экспорт пакетов XDTO, имеющих указанные URI пространства имен в модели XDTO",
"signature": {
"URIПространствИмен": {
"СтрокаПараметров": "(URIПространствИмен)",
"Параметры": {
"URIПространствИмен": "Массив строк или строка, соответствующая URI пространства имен экспортируемых пакетов"
}
}
}
},
"ЭкспортСхемыXML": {
"name": "ЭкспортСхемыXML",
"name_en": "ExportXMLSchema",
"description": "Выполняет экспорт пакетов XDTO, имеющих указанные URI пространства имен в набор схем XML",
"signature": {
"URIПространствИмен": {
"СтрокаПараметров": "(URIПространствИмен)",
"Параметры": {
"URIПространствИмен": "Массив строк или строка, соответствующая URI пространства имен экспортируемых пакетов"
}
}
}
}
},
"constructors": {
"По умолчанию": {
"description": "Создает новую фабрику XDTO.",
"signature": "ФабрикаXDTO()"
},
"НаОснованииМоделиТипов": {
"description": "Создает фабрику типов XDTO по модели типов",
"signature": "(Модель?, Пакеты?)",
"params": {
"Модель": "Модель типов, по которой необходимо сформировать фабрику типов XDTO",
"Пакеты": "Коллекция пакетов для разрешения директив импорта модели типов XDTO"
}
},
"НаОснованииНабораСхем": {
"description": "Создает фабрику типов XDTO по набору схем XML.",
"signature": "(НаборСхемXML?, Пакеты?)",
"params": {
"НаборСхемXML": "Набор схем XML, на основе которого будет создана фабрика XDTO",
"Пакеты": "Коллекция пакетов для разрешения директив импорта модели типов XDTO"
}
}
}
}
},
"systemEnum": {

View File

@@ -751,6 +751,20 @@ class bslHelper {
}
/**
* Determines if the current function of query
* is the CAST func or not
*
* @returns {bool}
*/
isItCastFunction() {
let exp = this.getFuncName();
let word = this.getLastSeparatedWord(this.position).toLowerCase();
return (exp == 'выразить' || exp == 'cast') && (word == 'как' || word == 'as');
}
/**
* Checks if string contain ref constructor (ССЫЛКА|REFS)
*
@@ -2312,6 +2326,7 @@ class bslHelper {
fillSuggestionsForMetadataItem(suggestions, obj, metadataName, metadataItem) {
let objects = [];
let is_query = (isQueryMode() || isDCSMode());
if (obj.hasOwnProperty('properties'))
objects.push(obj.properties);
@@ -2319,7 +2334,7 @@ class bslHelper {
if (obj.hasOwnProperty('resources'))
objects.push(obj.resources);
if (obj.hasOwnProperty('tabulars')) {
if (obj.hasOwnProperty('tabulars') && !is_query) {
this.fillSuggestionsForItemTabulars(suggestions, obj.tabulars, metadataName, metadataItem)
}
@@ -3340,22 +3355,71 @@ class bslHelper {
/**
* Looks for variables into iterations of loops
* in current position
*
* @param {string} pattern to look for variables
*
* @returns {array} array with variables names
*/
getLoopsVarNames() {
getLoopsVarNamesForCurrentPosition(pattern) {
let names = [];
let matches = Finder.findMatches(this.model, '(?:для каждого|for each)\\s+([a-zA-Z0-9\u0410-\u044F_,\\s=]+)\\s+(?:из|in)');
matches = matches.concat(Finder.findMatches(this.model, '(?:для|for)\\s+([a-zA-Z0-9\u0410-\u044F_,\\s=]+)\\s+=.*(?:по|to)'));
for (let idx = 0; idx < matches.length; idx++) {
let loop_start = Finder.findPreviousMatch(this.model, pattern, this.position, false);
let match = matches[idx];
let varDef = match.matches[match.matches.length - 1];
if (loop_start) {
if (!names.some(name => name === varDef))
names.push(varDef);
let start_pos = new monaco.Position(loop_start.range.startLineNumber, loop_start.range.startColumn);
let loop_end = Finder.findNextMatch(this.model, '(?:конеццикла|enddo)', start_pos, false);
if (loop_end) {
let end_pos = new monaco.Position(loop_end.range.startLineNumber, loop_end.range.startColumn);
if (start_pos.isBefore(this.position) && this.position.isBefore(end_pos)) {
names.push(loop_start.matches[loop_start.matches.length - 1]);
}
}
}
return names;
}
/**
* Looks for variables into iterations of loops
*
* @param {int} currentLine the current line
*
* @returns {array} array with variables names
*/
getLoopsVarNames(currentLine) {
let names = [];
let each_pattern = '(?:для каждого|for each)\\s+([a-zA-Z0-9\u0410-\u044F_,\\s=]+)\\s+(?:из|in)';
let for_pattern = '(?:для|for)\\s+([a-zA-Z0-9\u0410-\u044F_,\\s=]+)\\s+=.*(?:по|to)';
if (currentLine == 0) {
let matches = Finder.findMatches(this.model, each_pattern);
matches = matches.concat(Finder.findMatches(this.model, for_pattern));
for (let idx = 0; idx < matches.length; idx++) {
let match = matches[idx];
let varDef = match.matches[match.matches.length - 1];
if (!names.some(name => name === varDef))
names.push(varDef);
}
}
else {
names = this.getLoopsVarNamesForCurrentPosition(each_pattern);
names = names.concat(this.getLoopsVarNamesForCurrentPosition(for_pattern));
}
@@ -3377,9 +3441,7 @@ class bslHelper {
let funcLine = 0;
names = names.concat(this.getFunctionsVarsNames(currentLine, funcLine));
names = names.concat(this.getDefaultVarsNames(currentLine, funcLine));
if (currentLine == 0)
names = names.concat(this.getLoopsVarNames());
names = names.concat(this.getLoopsVarNames(currentLine));
return names;
@@ -3710,6 +3772,138 @@ class bslHelper {
}
/**
* Adds AS-delimiter into CAST function if needed
*
* @param {array} suggestions array of suggestions for provideCompletionItems
*/
getCastDelimiter(suggestions) {
let exp = this.getFuncName();
if (exp == 'выразить' || exp == 'cast') {
let last_expression = this.lastRawExpression;
let text_before = this.textBeforePosition;
let as_require = (last_expression != 'выразить' && last_expression != 'cast');
as_require = as_require && this.getLastCharacter() == ' ';
as_require = as_require && (text_before.indexOf(' как ') < 0 && text_before.indexOf(' as '));
if (as_require) {
let label = engLang ? 'AS ' : 'КАК '
suggestions.push({
label: label,
kind: monaco.languages.CompletionItemKind.Module,
insertText: label,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
command: { id: 'editor.action.triggerSuggest', title: 'suggest_type' }
});
}
}
}
/**
* Fills array of completion for CAST function
*
* @param {array} suggestions array of suggestions for provideCompletionItems
* @param {object} data objects from BSL-JSON dictionary
* @param {CompletionItemKind} kind - monaco.languages.CompletionItemKind (class, function, constructor etc.)
*/
getCastValuesCompletion(suggestions, data) {
let metadataName = '';
let word = this.getLastSeparatedWords(1).toString().toLowerCase();
let exp = this.getLastNExpression(1);
if (word == 'как' || word == 'as' || exp == 'как' || exp == 'as') {
metadataName = ''
let label = engLang ? 'String' : 'Строка';
suggestions.push({
label: label,
kind: monaco.languages.CompletionItemKind.Enum,
insertText: label,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
});
label = engLang ? 'Number' : 'Число';
suggestions.push({
label: label,
kind: monaco.languages.CompletionItemKind.Enum,
insertText: label,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
});
}
else {
if (this.getLastNExpression(1) == '.')
metadataName = this.getLastNExpression(2);
else
metadataName = word;
}
if (word) {
for (const [key, value] of Object.entries(data)) {
if (!metadataName && value.hasOwnProperty('ref')) {
let suggestion = {
label: key,
kind: monaco.languages.CompletionItemKind.Enum,
insertText: key,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
}
if (value.hasOwnProperty('ref') || value.hasOwnProperty('items')) {
suggestion.insertText += '.';
suggestion['command'] = { id: 'editor.action.triggerSuggest', title: 'suggest_type' };
}
suggestions.push(suggestion);
}
else {
if (key.toLowerCase() == metadataName) {
if (value.hasOwnProperty('ref') && bslMetadata.hasOwnProperty(value.ref) && bslMetadata[value.ref].hasOwnProperty('items')) {
if (!Object.keys(bslMetadata[value.ref].items).length) {
requestMetadata(bslMetadata[value.ref].name.toLowerCase());
}
else {
for (const [mkey, mvalue] of Object.entries(bslMetadata[value.ref].items)) {
suggestions.push({
label: mkey,
kind: monaco.languages.CompletionItemKind.Enum,
insertText: mkey + ')',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
});
}
}
}
}
}
}
}
}
/**
* Fills array of completion for query values
*
@@ -4163,6 +4357,47 @@ class bslHelper {
}
/**
* Adds standart tabular attributes to suggestion list
*
* @param {array} suggestions the list of suggestions
* @param {string} ref to tabular owner
*/
addStandardTabularAttributesToQuerySuggestions(suggestions, ref) {
let label = engLang ? 'Ref' : 'Ссылка';
let command = {
id: 'vs.editor.ICodeEditor:1:saveref',
arguments: [
{
"name": label,
"data": {
"ref": ref,
"sig": null
}
}
]
}
suggestions.push({
label: label,
kind: monaco.languages.CompletionItemKind.Field,
insertText: label,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
command: command
});
label = engLang ? 'LineNumber' : 'НомерСтроки';
suggestions.push({
label: label,
kind: monaco.languages.CompletionItemKind.Field,
insertText: label,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
});
}
/**
* Gets the list of properties (attributes) owned by object
* (Catalog, Document, etc) and fills the suggestions by it
@@ -4278,8 +4513,19 @@ class bslHelper {
if (ikey.toLowerCase() == metadataName) {
if (ivalue.hasOwnProperty('properties'))
this.fillSuggestionsForMetadataItemInQuery(suggestions, ivalue, metadataSubtable);
if (ivalue.hasOwnProperty('properties')) {
if (ivalue.hasOwnProperty('tabulars') && 3 == sourceArray.length) {
for (const [tkey, tvalue] of Object.entries(ivalue.tabulars)) {
if (tkey.toLowerCase() == metadataSubtable) {
this.addStandardTabularAttributesToQuerySuggestions(suggestions, key + '.' + ikey);
this.fillSuggestionsForMetadataItemInQuery(suggestions, tvalue, '');
}
}
}
else {
this.fillSuggestionsForMetadataItemInQuery(suggestions, ivalue, metadataSubtable);
}
}
else if (ivalue.hasOwnProperty('tables') && 3 < sourceArray.length &&
value[this.queryNameField + '_tables'].toLowerCase() == metadataSubtable) {
let tableName = sourceArray[3].toLowerCase();
@@ -4499,8 +4745,28 @@ class bslHelper {
if (match) {
// Searching the source
position = new monaco.Position(match.range.endLineNumber, match.range.endColumn);
match = Finder.findPreviousMatch(this.model, '[a-zA-Z0-9\u0410-\u044F]+\\.[a-zA-Z0-9\u0410-\u044F_]+(?:\\.[a-zA-Z0-9\u0410-\u044F_]+)?(?:\\.[a-zA-Z0-9\u0410-\u044F_]+)?', position);
position = new monaco.Position(match.range.endLineNumber, match.range.endColumn);
let bracket_match = this.model.findPrevBracket(position);
if (bracket_match && match.range.startLineNumber < bracket_match.range.startLineNumber) {
position = new monaco.Position(bracket_match.range.startLineNumber, bracket_match.range.startColumn);
let brackets = editor.getModel().matchBracket(position);
if (brackets) {
brackets = brackets.sort();
const open = brackets[0], close = brackets[1];
const bracket_range = new monaco.Range(open.startLineNumber, open.endColumn, close.startLineNumber, close.startColumn);
const bracket_text = this.model.getValueInRange(bracket_range);
const source_text = this.model.getValueInRange(match.range).replace(bracket_text, '');
const source_model = monaco.editor.createModel(source_text);
const model_range = source_model.getFullModelRange();
const model_position = new monaco.Position(model_range.endLineNumber, model_range.endColumn);
match = Finder.findPreviousMatch(source_model, '[a-zA-Z0-9\u0410-\u044F]+\\.[a-zA-Z0-9\u0410-\u044F_]+(?:\\.[a-zA-Z0-9\u0410-\u044F_]+)?(?:\\.[a-zA-Z0-9\u0410-\u044F_]+)?', model_position);
}
else
match = null;
}
else
match = Finder.findPreviousMatch(this.model, '[a-zA-Z0-9\u0410-\u044F]+\\.[a-zA-Z0-9\u0410-\u044F_]+(?:\\.[a-zA-Z0-9\u0410-\u044F_]+)?(?:\\.[a-zA-Z0-9\u0410-\u044F_]+)?', position);
if (match) {
sourceDefinition = match.matches[0];
@@ -4626,28 +4892,47 @@ class bslHelper {
/**
* Fills array of completion for virtual tables of registers in source
* or for tabulars of metadata object
*
* @param {object} data objects from BSL-JSON dictionary
* @param {string} metadataItem name of metadata item like (ЦеныНоменклатуры/ProductPrices, СвободныеОстатки/AvailableStock)
* @param {array} suggestions array of suggestions for provideCompletionItems
*/
getQuerySourceMetadataRegTempraryTablesCompletion(data, metadataItem, suggestions) {
getQuerySourceMetadataTabularsRegTempraryTables(data, metadataItem, suggestions) {
for (const [ikey, ivalue] of Object.entries(data.items)) {
if (ikey.toLowerCase() == metadataItem.toLowerCase() && ivalue.hasOwnProperty('type')) {
if (ikey.toLowerCase() == metadataItem.toLowerCase()) {
if (ivalue.hasOwnProperty('type')) {
let tables = this.getRegisterVirtualTables(ivalue.type);
let tables = this.getRegisterVirtualTables(ivalue.type);
for (const [tkey, tvalue] of Object.entries(tables)) {
for (const [tkey, tvalue] of Object.entries(tables)) {
suggestions.push({
label: tkey,
kind: monaco.languages.CompletionItemKind.Unit,
insertText: tvalue,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
});
suggestions.push({
label: tkey,
kind: monaco.languages.CompletionItemKind.Unit,
insertText: tvalue,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
});
}
}
else if (ivalue.hasOwnProperty('tabulars')) {
for (const [tkey, tvalue] of Object.entries(ivalue.tabulars)) {
suggestions.push({
label: tkey,
kind: monaco.languages.CompletionItemKind.Unit,
insertText: tkey,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
});
}
}
}
@@ -4752,8 +5037,7 @@ class bslHelper {
this.getQuerySourceForExternalData(value, metadataItem, metadataFunc, suggestions, kind);
}
else if (!metadataFunc && 2 < maxLevel) {
this.getQuerySourceMetadataRegTempraryTablesCompletion(value, metadataItem, suggestions)
this.getQuerySourceMetadataTabularsRegTempraryTables(value, metadataItem, suggestions)
}
}
@@ -4938,18 +5222,18 @@ class bslHelper {
if (startMatch) {
let template = '(?:из|from)\\s+(?:(?:.|\\n|\\r)*?)\\s*(?:\\s|\\t)*(?:сгруппировать|объединить|упорядочить|имеющие|где|индексировать|havin|where|index|group|union|order|;)'
let template = '(?:из|from)\\s+(?:[\\s\\S]*?)(?:сгруппировать|объединить|упорядочить|имеющие|где|индексировать|havin|where|index|group|union|order|;)'
let position = new monaco.Position(startMatch.range.startLineNumber, startMatch.range.startColumn);
let fromMatch = Finder.findNextMatch(this.model, template, position);
if (!fromMatch) {
template = '(?:из|from)\\s+(?:(?:.|\\n|\\r)*?)\\s*(?:\\s|\\t)*$';
template = '(?:из|from)\\s+(?:[\\s\\S]*?)$';
fromMatch = Finder.findNextMatch(this.model, template, position);
}
if (fromMatch && fromMatch.range.startLineNumber < startMatch.range.startLineNumber) {
// This is loops to the beginning. Trying another template
fromMatch = Finder.findNextMatch(this.model, '(?:из|from)\\s+(?:(?:.|\\n|\\r)+)$', position);
fromMatch = Finder.findNextMatch(this.model, '(?:из|from)\\s+(?:[\\s\\S]+)$', position);
}
if (fromMatch) {
@@ -5113,7 +5397,11 @@ class bslHelper {
let trigger_char = (context && context.triggerCharacter) ? context.triggerCharacter : '';
if (trigger_char == ' ') {
this.getQueryAliasCompletion(suggestions);
if (!suggestions.length);
this.getCastDelimiter(suggestions);
}
else {
@@ -5121,50 +5409,54 @@ class bslHelper {
if (!suggestions.length && !editor.disableNativeSuggestions) {
if (!this.requireQueryValue()) {
if (!this.requireQueryRef()) {
if (!this.getQuerySourceCompletion(suggestions, monaco.languages.CompletionItemKind.Enum)) {
let functions = null;
if (this.lastOperator != '"') {
functions = this.getQueryFunctions(bslQuery);
this.getRefCompletion(suggestions);
this.getQueryTablesCompletion(suggestions, monaco.languages.CompletionItemKind.Class);
this.getCustomObjectsCompletion(suggestions, bslMetadata.customObjects, monaco.languages.CompletionItemKind.Enum);
}
if (trigger_char == '&')
this.getQueryParamsCompletion(suggestions, monaco.languages.CompletionItemKind.Enum);
this.getQueryFieldsCompletion(suggestions);
if (this.lastExpression.indexOf('.') < 0) {
this.getQueryCommonCompletion(suggestions, monaco.languages.CompletionItemKind.Module);
if (functions)
this.getCommonCompletion(suggestions, functions, monaco.languages.CompletionItemKind.Function, true);
}
this.getSnippets(suggestions, querySnippets, false);
this.getQueryAliasCompletion(suggestions);
}
}
else {
this.getQueryRefCompletion(suggestions, monaco.languages.CompletionItemKind.Enum);
}
}
else {
let interrupt = false;
if (this.requireQueryValue()) {
this.getQueryValuesCompletion(suggestions, bslQuery.values, monaco.languages.CompletionItemKind.Enum);
interrupt = true;
}
if (!interrupt && this.requireQueryRef()) {
this.getQueryRefCompletion(suggestions, monaco.languages.CompletionItemKind.Enum);
interrupt = true;
}
if (!interrupt && this.isItCastFunction()) {
this.getCastValuesCompletion(suggestions, bslQuery.values);
interrupt = true;
}
if (!interrupt && this.getCastDelimiter(suggestions)) {
interrupt = true;
}
if (!interrupt && !this.getQuerySourceCompletion(suggestions, monaco.languages.CompletionItemKind.Enum)) {
let functions = null;
if (this.lastOperator != '"') {
functions = this.getQueryFunctions(bslQuery);
this.getRefCompletion(suggestions);
this.getQueryTablesCompletion(suggestions, monaco.languages.CompletionItemKind.Class);
this.getCustomObjectsCompletion(suggestions, bslMetadata.customObjects, monaco.languages.CompletionItemKind.Enum);
}
if (trigger_char == '&')
this.getQueryParamsCompletion(suggestions, monaco.languages.CompletionItemKind.Enum);
this.getQueryFieldsCompletion(suggestions);
if (this.lastExpression.indexOf('.') < 0) {
this.getQueryCommonCompletion(suggestions, monaco.languages.CompletionItemKind.Module);
if (functions)
this.getCommonCompletion(suggestions, functions, monaco.languages.CompletionItemKind.Function, true);
}
this.getSnippets(suggestions, querySnippets, false);
this.getQueryAliasCompletion(suggestions);
}
}
}
@@ -6079,17 +6371,23 @@ class bslHelper {
line_number++;
let params = parametersStr.split(',');
const params = parametersStr.split(',');
const range = new monaco.Range(line_number, 1, funcLineNumber, 1);
const func_model = monaco.editor.createModel(model.getValueInRange(range));
params.forEach(function (param) {
let param_full_name = param.split('=')[0].trim();
let param_name = param_full_name.replace(/знач\s+/gi, '');
let pattern = '\/\/ параметры:[\\s\\SS\\n\\t]*?' + param_name + '([\\s\\SS\\n\\t]*?)(?:\/\/\\s{1,4}[a-zA-Z0-9\u0410-\u044F_])';
let range = new monaco.Range(line_number, 1, funcLineNumber, 1);
let match = Finder.findMatches(model, pattern, range);
let match = Finder.findMatches(func_model, pattern);
let param_description = '';
if (match && !match.length) {
pattern = '\/\/ параметры:[\\s\\SS\\n\\t]*?' + param_name + '([\\s\\SS\\n\\t]*?)(?:\/\/\\s*$)';
match = Finder.findMatches(func_model, pattern);
}
if (match && match.length) {
param_description = match[0].matches[1];
param_description = param_description.replace(/^\/\/*/gm, '');
@@ -6406,8 +6704,8 @@ class bslHelper {
*/
static getFoldingRanges(model) {
let ranges = this.getRangesForRegexp(model, "\"(?:\\n|\\r|\\|)*(?:выбрать|select)(?:(?:.|\\n|\\r)*?)?\"");
ranges = ranges.concat(this.getRangesForRegexp(model, "(?:^|\\b)(?:функция|процедура).*\\((?:.|\\n|\\r)*?(?:конецпроцедуры|конецфункции)"));
let ranges = this.getRangesForRegexp(model, "\"(?:\\n|\\r|\\|)*(?:выбрать|select)(?:(?:\\s|\\S|\"\")*?)?\"");
ranges = ranges.concat(this.getRangesForRegexp(model, "(?:^|\\b)(?:функция|процедура).*\\([\\s\\S]*?(?:конецпроцедуры|конецфункции)"));
ranges = ranges.concat(this.getRangesForConstruction(model, "пока|while", "конеццикла|enddo", true));
ranges = ranges.concat(this.getRangesForConstruction(model, "для .*(?:по|из) .*|for .* (?:to|each) .*", "конеццикла|enddo", true));
ranges = ranges.concat(this.getRangesForConstruction(model, "если|if", "конецесли|endif", true));
@@ -6580,21 +6878,21 @@ class bslHelper {
ranges = this.getRangesForQuery(model);
ranges = ranges.concat(nestedQueries);
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:выбрать|select)\\s+(?:(?:.|\\n|\\r)*?)\\n(?:\s|\t)*(?:из|from|поместить|into|;)', false, false, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:где|where)\\s+(?:(?:.|\\n|\\r)*?)\\s*(?:\\s|\\t)*(?:сгруппировать|объединить|упорядочить|group|union|order|;)', false, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:где|where)\\s+(?:(?:.|\\n|\\r)*?)\\s*(?:\\s|\\t)*(?:сгруппировать|объединить|упорядочить|group|union|order|;|\\))', nestedQueries, true, true));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:выбор|case)\\s+(?:(?:.|\\n|\\r)*?)\\n(?:\\s|\\t)*(?:конец|end)', false, true, true));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:иначе|else)\\s+(?:(?:.|\\n|\\r)*?)\\n(?:\\s|\\t)*(?:конец|end)', false, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:когда|when)\\s+(?:(?:.|\\n|\\r)*?)\\n(?:\\s|\\t)*(?:тогда|then)', false, true, true));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:левое|внешнее|правое|полное|left|outer|right|full)\\s+(?:соединение|join).*\\s+(?:(?:.|\\n|\\r)*?)\\n(?:\\s|\\t)*(?:где|сгруппировать|объединить|упорядочить|where|group|union|order|;)', false, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:левое|внешнее|правое|полное|left|outer|right|full)\\s+(?:соединение|join).*\\s+(?:(?:.|\\n|\\r)*?)\\n(?:\\s|\\t)*(?:где|сгруппировать|объединить|упорядочить|where|group|union|order|;|\\))', nestedQueries, true, true));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:имеющие|havin)\\s+(?:(?:.|\\n|\\r)*?)\\s*(?:\\s|\\t)*(?:индексировать|индекс|;)', false, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:имеющие|havin)\\s+(?:(?:.|\\n|\\r)*?)\\s*(?:\\s|\\t)*(?:индексировать|индекс|;|\\))', nestedQueries, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:сгруппировать|group)\\s+(?:(?:.|\\n|\\r)*?)\\s*(?:\\s|\\t)*(?:имеющие|having|индексировать|index|;)', false, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:сгруппировать|group)\\s+(?:(?:.|\\n|\\r)*?)\\s*(?:\\s|\\t)*(?:имеющие|having|индексировать|index|;|\\))', nestedQueries, true, true));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:из|from)\\s+(?:(?:.|\\n|\\r)*?)\\s*(?:\\s|\\t)*(?:сгруппировать|объединить|упорядочить|имеющие|где|индексировать|havin|where|index|group|union|order|;)', false, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:из|from)\\s+(?:(?:.|\\n|\\r)*?)\\s*(?:\\s|\\t)*(?:сгруппировать|объединить|упорядочить|имеющие|где|индексировать|havin|where|index|group|union|order|;|\\))', nestedQueries, true, true));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:индексировать|index)\\s+(?:(?:.|\\n|\\r)*?)\\s*(?:\\s|\\t)*;', false, true, true));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:выбрать|select)\\s+(?:[\\s\\S]*?)\\n(?:\s|\t)*(?:из|from|поместить|into|;)', false, false, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:где|where)\\s+(?:[\\s\\S]*?)(?:сгруппировать|объединить|упорядочить|group|union|order|;)', false, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:где|where)\\s+(?:[\\s\\S]*?)(?:сгруппировать|объединить|упорядочить|group|union|order|;|\\))', nestedQueries, true, true));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:выбор|case)\\s+(?:[\\s\\S]*?)(?:конец|end)', false, true, true));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:иначе|else)\\s+(?:[\\s\\S]*?)(?:конец|end)', false, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:когда|when)\\s+(?:[\\s\\S]*?)(?:тогда|then)', false, true, true));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:левое|внешнее|правое|полное|left|outer|right|full)\\s+(?:соединение|join).*\\s+(?:[\\s\\S]*?)(?:где|сгруппировать|объединить|упорядочить|where|group|union|order|;)', false, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:левое|внешнее|правое|полное|left|outer|right|full)\\s+(?:соединение|join).*\\s+(?:[\\s\\S]*?)(?:где|сгруппировать|объединить|упорядочить|where|group|union|order|;|\\))', nestedQueries, true, true));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:имеющие|havin)\\s+(?:[\\s\\S]*?)(?:индексировать|индекс|;)', false, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:имеющие|havin)\\s+(?:[\\s\\S]*?)(?:индексировать|индекс|;|\\))', nestedQueries, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:сгруппировать|group)\\s+(?:[\\s\\S]*?)(?:имеющие|having|индексировать|index|;)', false, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:сгруппировать|group)\\s+(?:[\\s\\S]*?)(?:имеющие|having|индексировать|index|;|\\))', nestedQueries, true, true));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:из|from)\\s+(?:[\\s\\S]*?)(?:сгруппировать|объединить|упорядочить|имеющие|где|индексировать|havin|where|index|group|union|order|;)', false, true, false));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:из|from)\\s+(?:[\\s\\S]*?)(?:сгруппировать|объединить|упорядочить|имеющие|где|индексировать|havin|where|index|group|union|order|;|\\))', nestedQueries, true, true));
ranges = ranges.concat(this.getRangesForQueryBlock(model, '(?:индексировать|index)\\s+(?:[\\s\\S]*?);', false, true, true));
ranges = ranges.concat(this.getRangesForNestedBlock(model, '(?:сумма|максимум|минимум|sum|min|max)\\s*\\('));
return ranges;

View File

@@ -320,6 +320,14 @@ define(['bslGlobals', 'bslMetadata', 'snippets', 'bsl_language', 'vs/editor/edit
let isCompareMode = (editor.navi != undefined);
queryMode = (mode == 'bsl_query');
DCSMode = (mode == 'dcs_query');
if (queryMode || DCSMode)
editor.updateOptions({ foldingStrategy: "indentation" });
else
editor.updateOptions({ foldingStrategy: "auto" });
if (isCompareMode) {
monaco.editor.setModelLanguage(editor.getModifiedEditor().getModel(), mode);
monaco.editor.setModelLanguage(editor.getOriginalEditor().getModel(), mode);
@@ -328,9 +336,6 @@ define(['bslGlobals', 'bslMetadata', 'snippets', 'bsl_language', 'vs/editor/edit
monaco.editor.setModelLanguage(editor.getModel(), mode);
}
queryMode = (mode == 'bsl_query');
DCSMode = (mode == 'dcs_query');
let currentTheme = getCurrentThemeName();
setTheme(currentTheme);
@@ -427,7 +432,7 @@ define(['bslGlobals', 'bslMetadata', 'snippets', 'bsl_language', 'vs/editor/edit
if (endLineNumber <= getLineCount()) {
let range = new monaco.Range(startLineNumber, startColumn, endLineNumber, endColumn);
editor.setSelection(range);
editor.revealLineInCenterIfOutsideViewport(startLineNumber);
editor.revealPositionInCenterIfOutsideViewport(range.getEndPosition());
return true;
}
else
@@ -441,7 +446,7 @@ define(['bslGlobals', 'bslMetadata', 'snippets', 'bsl_language', 'vs/editor/edit
let endPosition = editor.getModel().getPositionAt(end - 1);
let range = new monaco.Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);
editor.setSelection(range);
editor.revealPositionInCenterIfOutsideViewport(startPosition);
editor.revealPositionInCenterIfOutsideViewport(endPosition);
return true;
@@ -1418,6 +1423,24 @@ define(['bslGlobals', 'bslMetadata', 'snippets', 'bsl_language', 'vs/editor/edit
}
scale = function(direction) {
if (direction == 0)
editor.trigger('', 'editor.action.fontZoomReset');
else if (0 < direction)
editor.trigger('', 'editor.action.fontZoomIn');
else
editor.trigger('', 'editor.action.fontZoomOut');
}
gotoLine = function() {
editor.trigger('', 'editor.action.gotoLine');
getQuickOpenWidget().widget.quickOpenWidget.inputElement.focus();
}
showVariablesDescription = function(variablesJSON) {
try {
@@ -1703,8 +1726,12 @@ define(['bslGlobals', 'bslMetadata', 'snippets', 'bsl_language', 'vs/editor/edit
let target = editor.getModel().getWordAtPosition(position);
if (target)
setSelection(position.lineNumber, target.startColumn, position.lineNumber, target.endColumn)
if (target) {
let current_selection = editor.getSelection();
let target_selection = new monaco.Range(position.lineNumber, target.startColumn, position.lineNumber, target.endColumn);
if (!current_selection.containsRange(target_selection))
setSelection(position.lineNumber, target.startColumn, position.lineNumber, target.endColumn)
}
}
@@ -2194,6 +2221,12 @@ define(['bslGlobals', 'bslMetadata', 'snippets', 'bsl_language', 'vs/editor/edit
}
function getQuickOpenWidget() {
return getActiveEditor()._overlayWidgets['editor.contrib.quickOpenEditorWidget'];
}
function getNativeLinkHref(element, isForwardDirection) {
let href = '';

View File

@@ -163,7 +163,16 @@ describe("Проверка автокомлита и подсказок реда
' ',
' Возврат Результат.Ошибки;',
'',
'КонецФункции'].join('\n');
'КонецФункции',
'',
'// Выполняет фрагмент кода, который передается ему в качестве строкового значения',
'//',
'// Параметры:',
'// __Текст__ - Строка - Строка, содержащая текст исполняемого кода',
'//',
'Процедура __Выполнить__(__Текст__) Экспорт',
' Вычислить(__Текст__);',
'КонецПроцедуры'].join('\n');
}
@@ -926,6 +935,18 @@ describe("Проверка автокомлита и подсказок реда
suggestions = bsl.getCodeCompletion({triggerCharacter: ''});
expect(suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.some(suggest => suggest.label === "ЗначениеРеквизитаОбъекта"), true);
bsl = helper('ЕстьСсылкиНаОбъект(');
let context = bsl.getLastSigMethod({});
let help = bsl.getCommonSigHelp(context, bslGlobals.globalfunctions);
expect(help).to.have.property('signatures');
expect(help.signatures).to.be.an('array').that.not.is.empty;
assert.equal(
help.signatures.some(
signature => expect(signature).to.have.property('parameters') &&
signature.parameters.some(param => param.documentation.indexOf('ЛюбаяСсылка, Массив - объект или список объектов') === 0)
), true
);
});

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/2.0.0/chai.js"></script>
<link href="./decorations.css" rel="stylesheet">
<link href="./tree/tree.css" rel="stylesheet">
</head>
<body>
@@ -1120,7 +1121,7 @@
' Справочник.Товары КАК Товары',
' ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(',
' &Период,',
' Номенклатура В (&СписокНоменклатуры),',
' Номенклатура.ВидНоменклатуры В (&СписокВидовНоменклатуры),',
' ) КАК Цены',
' ПО Товары.Ссылка = Цены.Номенклатура',
' ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки КАК Остатки',
@@ -1177,6 +1178,15 @@
</script>
<div id="container" style="width:100%;height:600px;border:1px solid grey"></div>
<div id="display">
<div id="display-header">
<div id="display-title"></div>
<div id="display-close"></div>
</div>
<div id="variables-display">
<div id="variables-tree"></div>
</div>
</div>
<button id="event-button"></button>
<script src="./vs/loader.js"></script>
@@ -1185,6 +1195,7 @@
<script src="./bsl_helper.js"></script>
<script src="./test_query.js"></script>
<script src="./init.js"></script>
<script src="./tree/tree.js"></script>
<div id="mocha"></div>

View File

@@ -386,8 +386,7 @@ describe("Проверка автокомлита и подсказок реда
let suggestions = [];
bsl.getQuerySourceCompletion(suggestions, null);
expect(suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.some(suggest => suggest.label === "РозничныйСайт"), true);
assert.equal(suggestions.some(suggest => suggest.label === "РозничныйСайт"), true);
});
it("проверка подсказки поля 'Таблица' внешнего источника в конструкции ИЗ ИЛИ СОЕДИНЕНИЕ ", function () {
@@ -398,8 +397,7 @@ describe("Проверка автокомлита и подсказок реда
let suggestions = [];
bsl.getQuerySourceCompletion(suggestions, null);
expect(suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.some(suggest => suggest.label === "Таблица"), true);
assert.equal(suggestions.some(suggest => suggest.label === "Таблица"), true);
});
it("проверка подсказки таблиц внешнего источника в конструкции ИЗ ИЛИ СОЕДИНЕНИЕ ", function () {
@@ -410,8 +408,7 @@ describe("Проверка автокомлита и подсказок реда
let suggestions = [];
bsl.getQuerySourceCompletion(suggestions, null);
expect(suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.some(suggest => suggest.label === "Customers"), true);
assert.equal(suggestions.some(suggest => suggest.label === "Customers"), true);
});
it("проверка подсказки полей таблицы внешнего источника", function () {
@@ -423,7 +420,56 @@ describe("Проверка автокомлита и подсказок реда
bsl.getQueryFieldsCompletion(suggestions);
expect(suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.some(suggest => suggest.label === "customer_id"), true);
});
it("проверка подсказки табличных частей в конструкции ИЗ или СОЕДИНЕНИЕ", function () {
bsl = helper(`ВЫБРАТЬ
*
ИЗ
Справочник.Товары.`);
let suggestions = bsl.getQueryCompletion();
expect(suggestions).to.be.an('object');
expect(suggestions.suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.suggestions.some(suggest => suggest.label === "ДополнительныеРеквизиты"), true);
});
it("проверка подсказки реквизитов табличных частей", function () {
bsl = helper(`ВЫБРАТЬ
ДопРеквизиты.
ИЗ
Справочник.Товары.ДополнительныеРеквизиты КАК ДопРеквизиты`, 2, 20);
let suggestions = [];
bsl.getQueryFieldsCompletion(suggestions);
expect(suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.some(suggest => suggest.label === "Ссылка"), true);
assert.equal(suggestions.some(suggest => suggest.label === "ИмяРеквизита"), true);
});
it("проверка подсказки для функции ВЫРАЗИТЬ", function () {
bsl = helper("ВЫРАЗИТЬ(");
let suggestions = bsl.getQueryCompletion();
expect(suggestions).to.be.an('array').that.is.empty;
bsl = helper("ВЫРАЗИТЬ(Товары.Код ");
suggestions = bsl.getQueryCompletion();
expect(suggestions).to.be.an('object');
expect(suggestions.suggestions).to.be.an('array').that.is.not.empty;
assert.equal(suggestions.suggestions.some(suggest => suggest.label === "КАК "), true);
bsl = helper("ВЫРАЗИТЬ(Товары.Код КАК ");
suggestions = bsl.getQueryCompletion();
expect(suggestions).to.be.an('object');
expect(suggestions.suggestions).to.be.an('array').that.is.not.empty;
assert.equal(suggestions.suggestions.some(suggest => suggest.label === "Строка"), true);
assert.equal(suggestions.suggestions.some(suggest => suggest.label === "Справочник"), true);
bsl = helper("ВЫРАЗИТЬ(Товары.Код КАК Справочник.");
suggestions = bsl.getQueryCompletion();
expect(suggestions).to.be.an('object');
expect(suggestions.suggestions).to.be.an('array').that.is.not.empty;
assert.equal(suggestions.suggestions.some(suggest => suggest.label === "Товары"), true);
});
setLanguageMode('bsl_query');

File diff suppressed because it is too large Load Diff