You've already forked bsl_console
mirror of
https://github.com/salexdv/bsl_console.git
synced 2025-11-06 08:59:16 +02:00
Описание языка bsl в отдельном файле.
Провайдер (provideFoldingRanges) для определения сворачиваемых блоков (циклы, условия, тексты запросов). Провайдер (provideHover) для простых всплывающих подсказок по глобальным функциям и классам. В bslGlobals для keywords добавлено новое поле prefix, для автодополнения, например точкой с запятой.
This commit is contained in:
@@ -1,16 +1,16 @@
|
|||||||
## 0.1.2 (20.07.2020)
|
## 0.1.2 (21.07.2020)
|
||||||
### Новое:
|
### Новое:
|
||||||
* Добавлена обработка подсказок для предопределенных значений элементов
|
* Добавлена обработка подсказок для предопределенных значений элементов
|
||||||
|
* Сворачивание циклов, условий и текстов запросов
|
||||||
|
* Простые всплювающие подсказки для глобальных функций, перечислений и классов
|
||||||
|
|
||||||
### Улучшения:
|
### Улучшения:
|
||||||
* Отказ от хранения описаний конструкций языка и метаданных в файлах JSON из-за CORS policy
|
* Отказ от хранения описаний конструкций языка и метаданных в файлах JSON из-за CORS policy
|
||||||
|
* Добавление **;** после ключевых слов *КонецЦикла*, *КонецЕсли* (поле Prefix в bslGlobals)
|
||||||
|
|
||||||
### Исправления:
|
### Исправления:
|
||||||
* Выделение ключевого слова *Выполнить*
|
* Выделение ключевого слова *Выполнить*
|
||||||
|
|
||||||
### Исправления:
|
|
||||||
* Исправлен сниппет для выборки из регистра накопления
|
|
||||||
|
|
||||||
## 0.1.1 (19.07.2020)
|
## 0.1.1 (19.07.2020)
|
||||||
|
|
||||||
### Новое:
|
### Новое:
|
||||||
|
|||||||
@@ -5656,11 +5656,15 @@ define([], function () {
|
|||||||
"Если": {},
|
"Если": {},
|
||||||
"Тогда": {},
|
"Тогда": {},
|
||||||
"ИначеЕсли": {},
|
"ИначеЕсли": {},
|
||||||
"КонецЦикла": {},
|
"КонецЦикла": {
|
||||||
|
"postfix": ";\n"
|
||||||
|
},
|
||||||
"Иначе": {},
|
"Иначе": {},
|
||||||
"Исключение": {},
|
"Исключение": {},
|
||||||
"КонецПопытки": {},
|
"КонецПопытки": {},
|
||||||
"КонецЕсли": {},
|
"КонецЕсли": {
|
||||||
|
"postfix": ";\n"
|
||||||
|
},
|
||||||
"Попытка": {},
|
"Попытка": {},
|
||||||
"Пока": {},
|
"Пока": {},
|
||||||
"Для": {},
|
"Для": {},
|
||||||
@@ -5693,7 +5697,9 @@ define([], function () {
|
|||||||
"Else": {},
|
"Else": {},
|
||||||
"ElsIf": {},
|
"ElsIf": {},
|
||||||
"Then": {},
|
"Then": {},
|
||||||
"EndIf": {},
|
"EndIf": {
|
||||||
|
"postfix": ";\n"
|
||||||
|
},
|
||||||
"Try": {},
|
"Try": {},
|
||||||
"Except": {},
|
"Except": {},
|
||||||
"EndTry": {},
|
"EndTry": {},
|
||||||
@@ -5704,7 +5710,9 @@ define([], function () {
|
|||||||
"In": {},
|
"In": {},
|
||||||
"To": {},
|
"To": {},
|
||||||
"Do": {},
|
"Do": {},
|
||||||
"EndDo": {},
|
"EndDo": {
|
||||||
|
"postfix": ";\n"
|
||||||
|
},
|
||||||
"NOT": {},
|
"NOT": {},
|
||||||
"AND": {},
|
"AND": {},
|
||||||
"OR": {},
|
"OR": {},
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ class bslHelper {
|
|||||||
constructor(model, position) {
|
constructor(model, position) {
|
||||||
|
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.position = position;
|
this.lineNumber = position.lineNumber;
|
||||||
|
this.column = position.column;
|
||||||
|
|
||||||
let wordData = model.getWordAtPosition(position);
|
let wordData = model.getWordAtPosition(position);
|
||||||
this.word = wordData ? wordData.word.toLowerCase() : '';
|
this.word = wordData ? wordData.word.toLowerCase() : '';
|
||||||
@@ -31,7 +32,7 @@ class bslHelper {
|
|||||||
|
|
||||||
this.textBeforePosition = this.getTextBeforePosition();
|
this.textBeforePosition = this.getTextBeforePosition();
|
||||||
this.lastExpression = this.getLastExpression();
|
this.lastExpression = this.getLastExpression();
|
||||||
this.lastRawExpression = this.getLastRawExpression();
|
this.lastRawExpression = this.getLastRawExpression();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +84,7 @@ class bslHelper {
|
|||||||
*/
|
*/
|
||||||
getFullTextBeforePosition() {
|
getFullTextBeforePosition() {
|
||||||
|
|
||||||
return this.model.getValueInRange({ startLineNumber: 1, startColumn: 1, endLineNumber: this.position.lineNumber, endColumn: this.position.column }).trim().toLowerCase();
|
return this.model.getValueInRange({ startLineNumber: 1, startColumn: 1, endLineNumber: this.lineNumber, endColumn: this.column }).trim().toLowerCase();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ class bslHelper {
|
|||||||
*/
|
*/
|
||||||
getTextBeforePosition() {
|
getTextBeforePosition() {
|
||||||
|
|
||||||
let text = this.model.getValueInRange({ startLineNumber: this.position.lineNumber, startColumn: 1, endLineNumber: this.position.lineNumber, endColumn: this.position.column });
|
let text = this.model.getValueInRange({ startLineNumber: this.lineNumber, startColumn: 1, endLineNumber: this.lineNumber, endColumn: this.column });
|
||||||
this.hasWhitespace = (text.substr(-1) == ' ');
|
this.hasWhitespace = (text.substr(-1) == ' ');
|
||||||
return text.trim().toLowerCase();
|
return text.trim().toLowerCase();
|
||||||
|
|
||||||
@@ -271,7 +272,10 @@ class bslHelper {
|
|||||||
else {
|
else {
|
||||||
|
|
||||||
for (const [inkey, invalue] of Object.entries(value)) {
|
for (const [inkey, invalue] of Object.entries(value)) {
|
||||||
values.push({ name: inkey, detail: '', description: '', postfix: '' });
|
let postfix = '';
|
||||||
|
if (invalue.hasOwnProperty('postfix'))
|
||||||
|
postfix = invalue.postfix;
|
||||||
|
values.push({ name: inkey, detail: '', description: '', postfix: postfix });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -699,6 +703,48 @@ class bslHelper {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completition provider
|
||||||
|
*
|
||||||
|
* @returns {array} array of completition
|
||||||
|
*/
|
||||||
|
getCompletition() {
|
||||||
|
|
||||||
|
let suggestions = [];
|
||||||
|
|
||||||
|
if (!this.getClassCompletition(suggestions, bslGlobals.classes)) {
|
||||||
|
|
||||||
|
if (!this.getClassCompletition(suggestions, bslGlobals.systemEnum)) {
|
||||||
|
|
||||||
|
if (!this.getMetadataCompletition(suggestions, bslMetadata)) {
|
||||||
|
|
||||||
|
this.getCommonCompletition(suggestions, bslGlobals.keywords, monaco.languages.CompletionItemKind.Keyword.ru, true);
|
||||||
|
this.getCommonCompletition(suggestions, bslGlobals.keywords, monaco.languages.CompletionItemKind.Keyword.en, true);
|
||||||
|
|
||||||
|
if (this.requireClass()) {
|
||||||
|
this.getCommonCompletition(suggestions, bslGlobals.classes, monaco.languages.CompletionItemKind.Constructor, false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.getCommonCompletition(suggestions, bslGlobals.globalfunctions, monaco.languages.CompletionItemKind.Function, true);
|
||||||
|
this.getCommonCompletition(suggestions, bslGlobals.globalvariables, monaco.languages.CompletionItemKind.Class, false);
|
||||||
|
this.getCommonCompletition(suggestions, bslGlobals.systemEnum, monaco.languages.CompletionItemKind.Enum, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getSnippets(suggestions, snippets);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suggestions.length)
|
||||||
|
return { suggestions: suggestions }
|
||||||
|
else
|
||||||
|
return [];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns array of parametrs as described in JSON-dictionary
|
* Returns array of parametrs as described in JSON-dictionary
|
||||||
* for current node (method)
|
* for current node (method)
|
||||||
@@ -1046,6 +1092,26 @@ class bslHelper {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signature help provider
|
||||||
|
*
|
||||||
|
* @returns {object} helper
|
||||||
|
*/
|
||||||
|
getSigHelp() {
|
||||||
|
|
||||||
|
let helper = this.getMetadataSigHelp(bslMetadata);
|
||||||
|
|
||||||
|
if (!helper)
|
||||||
|
helper = this.getClassSigHelp(bslGlobals.classes);
|
||||||
|
|
||||||
|
if (!helper)
|
||||||
|
helper = this.getCommonSigHelp(bslGlobals.globalfunctions);
|
||||||
|
|
||||||
|
if (helper)
|
||||||
|
return new SignatureHelpResult(helper);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates bslMetadata from JSON-string which
|
* Updates bslMetadata from JSON-string which
|
||||||
* was received from 1C
|
* was received from 1C
|
||||||
@@ -1076,4 +1142,183 @@ class bslHelper {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds blocks like conditions (if...endif) and loops (while...enddo)
|
||||||
|
* when start column startString equal start column endString
|
||||||
|
*
|
||||||
|
* @param {ITextModel} current model of editor
|
||||||
|
* @param {string} regexp to detect opening construction
|
||||||
|
* @param {string} regexp to detect closing construction
|
||||||
|
*
|
||||||
|
* @returns {array} - array of folding ranges
|
||||||
|
*/
|
||||||
|
static getRangesForConstruction(model, startString, endString) {
|
||||||
|
|
||||||
|
let ranges = [];
|
||||||
|
|
||||||
|
const startMatches = model.findMatches("(?:^|\\b)?(" + startString + ") ", false, true)
|
||||||
|
let startMatch = null;
|
||||||
|
|
||||||
|
const endMatches = model.findMatches("(?:^|\\b)?(" + endString + ") ?;", false, true)
|
||||||
|
let endMatch = null;
|
||||||
|
|
||||||
|
let structFound = false;
|
||||||
|
let subidx = 0;
|
||||||
|
|
||||||
|
if (startMatches && endMatches) {
|
||||||
|
|
||||||
|
for (let idx = 0; idx < startMatches.length; idx++) {
|
||||||
|
|
||||||
|
structFound = false;
|
||||||
|
startMatch = startMatches[idx];
|
||||||
|
|
||||||
|
subidx = 0;
|
||||||
|
|
||||||
|
while (!structFound && subidx < endMatches.length) {
|
||||||
|
|
||||||
|
endMatch = endMatches[subidx];
|
||||||
|
|
||||||
|
if (endMatch.range.startColumn == startMatch.range.startColumn && startMatch.range.startLineNumber < endMatch.range.startLineNumber) {
|
||||||
|
structFound = true;
|
||||||
|
ranges.push(
|
||||||
|
{
|
||||||
|
kind: monaco.languages.FoldingRangeKind.Region,
|
||||||
|
start: startMatch.range.startLineNumber,
|
||||||
|
end: endMatch.range.startLineNumber
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
subidx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ranges;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds blocks like functions by regexp
|
||||||
|
*
|
||||||
|
* @param {ITextModel} current model of editor
|
||||||
|
* @param {string} regexp to detect block
|
||||||
|
*
|
||||||
|
* @returns {array} - array of folding ranges
|
||||||
|
*/
|
||||||
|
static getRangesForRegexp(model, regexp) {
|
||||||
|
|
||||||
|
let ranges = [];
|
||||||
|
let match = null;
|
||||||
|
const matches = model.findMatches(regexp, false, true, false, null, true)
|
||||||
|
|
||||||
|
if (matches) {
|
||||||
|
|
||||||
|
for (let idx = 0; idx < matches.length; idx++) {
|
||||||
|
match = matches[idx];
|
||||||
|
ranges.push(
|
||||||
|
{
|
||||||
|
kind: monaco.languages.FoldingRangeKind.Region,
|
||||||
|
start: match.range.startLineNumber,
|
||||||
|
end: match.range.endLineNumber
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ranges;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for folding blocks
|
||||||
|
* @param {ITextModel} current model of editor
|
||||||
|
*
|
||||||
|
* @returns {array} - array of folding ranges
|
||||||
|
*/
|
||||||
|
static getFoldingRanges(model) {
|
||||||
|
|
||||||
|
let ranges = this.getRangesForRegexp(model, "\"(?:\\n|\\r|\\|)*(?:выбрать|select)(?:(?:.|\\n|\\r)*?)?\"");
|
||||||
|
ranges = ranges.concat(this.getRangesForRegexp(model, "(?:^|\\b)(?:функция|процедура).*\\((?:.|\\n|\\r)*?(?:конецпроцедуры|конецфункции)"));
|
||||||
|
ranges = ranges.concat(this.getRangesForRegexp(model, "(?:^|\\b)#.+(?:.|\\n|\\r)*?#.+$"));
|
||||||
|
ranges = ranges.concat(this.getRangesForConstruction(model, "пока|while", "конеццикла|enddo"));
|
||||||
|
ranges = ranges.concat(this.getRangesForConstruction(model, "для .*(?:по|из) .*|for .* (?:to|each) .*", "конеццикла|enddo"));
|
||||||
|
ranges = ranges.concat(this.getRangesForConstruction(model, "если|if", "конецесли|endif"));
|
||||||
|
|
||||||
|
return ranges;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for hover popoup
|
||||||
|
*
|
||||||
|
* @returns {object} - hover object or null
|
||||||
|
*/
|
||||||
|
getHover() {
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(bslGlobals)) {
|
||||||
|
|
||||||
|
for (const [ikey, ivalue] of Object.entries(value)) {
|
||||||
|
|
||||||
|
if (ivalue.hasOwnProperty('name')) {
|
||||||
|
|
||||||
|
if (ivalue.name.toLowerCase() == this.word) {
|
||||||
|
|
||||||
|
let contents = [
|
||||||
|
{ value: '**' + ivalue.name + '**' },
|
||||||
|
{ value: ivalue.description }
|
||||||
|
]
|
||||||
|
|
||||||
|
if (ivalue.hasOwnProperty('returns')) {
|
||||||
|
contents.push(
|
||||||
|
{ value: 'Возвращает: ' + ivalue.returns }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
range: new monaco.Range(this.lineNumber, this.column, this.lineNumber, this.model.getLineMaxColumn(this.lineNumber)),
|
||||||
|
contents: contents
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns query's text from current position
|
||||||
|
*
|
||||||
|
* @returns {object} object with text and range or null
|
||||||
|
*/
|
||||||
|
getQuery() {
|
||||||
|
|
||||||
|
const matches = this.model.findMatches("\"(?:\\n|\\r|\\|)*(?:выбрать|select)(?:(?:.|\\n|\\r)*?)?\"", false, true, false, null, true)
|
||||||
|
|
||||||
|
let idx = 0;
|
||||||
|
let match = null;
|
||||||
|
let queryFound = false;
|
||||||
|
|
||||||
|
if (matches) {
|
||||||
|
|
||||||
|
while (idx < matches.length && !queryFound) {
|
||||||
|
match = matches[idx];
|
||||||
|
queryFound = (match.range.startLineNumber <= this.lineNumber && this.lineNumber <= match.range.endLineNumber);
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryFound ? { text: match.matches[0], range: match.range } : null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
165
src/bsl_language.js
Normal file
165
src/bsl_language.js
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
define([], function () {
|
||||||
|
|
||||||
|
language = {
|
||||||
|
|
||||||
|
id: 'bsl',
|
||||||
|
rules: {
|
||||||
|
defaultToken: '',
|
||||||
|
tokenPostfix: 'bsl',
|
||||||
|
ignoreCase: true,
|
||||||
|
brackets: [
|
||||||
|
{ open: '[', close: ']', token: 'delimiter.square' },
|
||||||
|
{ open: '(', close: ')', token: 'delimiter.parenthesis' },
|
||||||
|
],
|
||||||
|
keywords: [
|
||||||
|
'КонецПроцедуры', 'EndProcedure', 'КонецФункции', 'EndFunction',
|
||||||
|
'Прервать', 'Break', 'Продолжить', 'Continue', 'Возврат', 'Return',
|
||||||
|
'Если', 'If', 'Иначе', 'Else', 'ИначеЕсли', 'ElsIf', 'Тогда', 'Then',
|
||||||
|
'КонецЕсли', 'EndIf', 'Попытка', 'Try', 'Исключение', 'Except',
|
||||||
|
'КонецПопытки', 'EndTry', 'Raise', 'ВызватьИсключение', 'Пока',
|
||||||
|
'While', 'Для', 'For', 'Каждого', 'Each', 'Из', 'In', 'По', 'To', 'Цикл',
|
||||||
|
'Do', 'КонецЦикла', 'EndDo', 'НЕ', 'NOT', 'И', 'AND', 'ИЛИ', 'OR', 'Новый',
|
||||||
|
'New', 'Процедура', 'Procedure', 'Функция', 'Function', 'Перем', 'Var',
|
||||||
|
'Экспорт', 'Export', 'Знач', 'Val', 'Неопределено', 'Выполнить'
|
||||||
|
],
|
||||||
|
namespaceFollows: [
|
||||||
|
'namespace', 'using',
|
||||||
|
],
|
||||||
|
parenFollows: [
|
||||||
|
'if', 'for', 'while', 'switch', 'foreach', 'using', 'catch', 'when'
|
||||||
|
],
|
||||||
|
operators: ['=', '<=', '>=', '<>', '<', '>', '+', '-', '*', '/', '%'],
|
||||||
|
symbols: /[=><!~?:&+\-*\/\^%]+/,
|
||||||
|
// escape sequences
|
||||||
|
escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
|
||||||
|
// The main tokenizer for our languages
|
||||||
|
tokenizer: {
|
||||||
|
root: [
|
||||||
|
[/[a-zA-Z\u0410-\u044F_][a-zA-Z\u0410-\u044F_0-9]*/, { cases: { '@keywords': 'keyword', '@default': 'identifier' } }],
|
||||||
|
// whitespace
|
||||||
|
{ include: '@whitespace' },
|
||||||
|
// delimiters and operators
|
||||||
|
[/}/, {
|
||||||
|
cases: {
|
||||||
|
'$S2==interpolatedstring': { token: 'string.quote', next: '@pop' },
|
||||||
|
'$S2==litinterpstring': { token: 'string.quote', next: '@pop' },
|
||||||
|
'@default': '@brackets'
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
[/^\s*#.*$/, 'preproc'],
|
||||||
|
[/[()\[\]]/, '@brackets'],
|
||||||
|
[/@symbols/, {
|
||||||
|
cases: {
|
||||||
|
'@operators': 'delimiter',
|
||||||
|
'@default': ''
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
// numbers
|
||||||
|
[/[0-9_]*\.[0-9_]+([eE][\-+]?\d+)?[fFdD]?/, 'number.float'],
|
||||||
|
[/[0-9_]+/, 'number'],
|
||||||
|
// delimiter: after number because of .\d floats
|
||||||
|
[/[;,.]/, 'delimiter'],
|
||||||
|
// strings
|
||||||
|
[/"([^"\\]|\\.)*$/, 'string.invalid'],
|
||||||
|
[/["|]/, { token: 'string.quote', next: '@string' }],
|
||||||
|
[/\$\@"/, { token: 'string.quote', next: '@litinterpstring' }],
|
||||||
|
[/\@"/, { token: 'string.quote', next: '@litstring' }],
|
||||||
|
[/\$"/, { token: 'string.quote', next: '@interpolatedstring' }],
|
||||||
|
// characters
|
||||||
|
[/'[^\\']'/, 'string'],
|
||||||
|
[/(')(@escapes)(')/, ['string', 'string.escape', 'string']],
|
||||||
|
[/'/, 'string.invalid']
|
||||||
|
],
|
||||||
|
comment: [
|
||||||
|
[/\/\/.*$/, 'comment'],
|
||||||
|
],
|
||||||
|
string: [
|
||||||
|
[/[^\\"]+/, 'string'],
|
||||||
|
[/@escapes/, 'string.escape'],
|
||||||
|
[/\\./, 'string.escape.invalid'],
|
||||||
|
[/"/, { token: 'string.quote', next: '@pop' }],
|
||||||
|
[/\|.*"/, { token: 'string.quote', next: '@pop' }],
|
||||||
|
],
|
||||||
|
litstring: [
|
||||||
|
[/[^"]+/, 'string'],
|
||||||
|
[/""/, 'string.escape'],
|
||||||
|
[/"/, { token: 'string.quote', next: '@pop' }]
|
||||||
|
],
|
||||||
|
litinterpstring: [
|
||||||
|
[/[^"{]+/, 'string'],
|
||||||
|
[/""/, 'string.escape'],
|
||||||
|
[/{{/, 'string.escape'],
|
||||||
|
[/}}/, 'string.escape'],
|
||||||
|
[/{/, { token: 'string.quote', next: 'root.litinterpstring' }],
|
||||||
|
[/"/, { token: 'string.quote', next: '@pop' }]
|
||||||
|
],
|
||||||
|
interpolatedstring: [
|
||||||
|
[/[^\\"{]+/, 'string'],
|
||||||
|
[/@escapes/, 'string.escape'],
|
||||||
|
[/\\./, 'string.escape.invalid'],
|
||||||
|
[/{{/, 'string.escape'],
|
||||||
|
[/}}/, 'string.escape'],
|
||||||
|
[/{/, { token: 'string.quote', next: 'root.interpolatedstring' }],
|
||||||
|
[/"/, { token: 'string.quote', next: '@pop' }]
|
||||||
|
],
|
||||||
|
whitespace: [
|
||||||
|
[/\/\/.*$/, 'comment'],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
themes: {
|
||||||
|
whiteTheme: {
|
||||||
|
base: 'vs',
|
||||||
|
name: 'bsl-white',
|
||||||
|
inherit: true,
|
||||||
|
rules: [
|
||||||
|
{ token: 'commentbsl', foreground: '008000' },
|
||||||
|
{ token: 'keywordbsl', foreground: 'ff0000' },
|
||||||
|
{ token: 'delimiterbsl', foreground: 'ff0000' },
|
||||||
|
{ token: 'delimiter.squarebsl', foreground: 'ff0000' },
|
||||||
|
{ token: 'delimiter.parenthesisbsl', foreground: 'ff0000' },
|
||||||
|
{ token: 'identifierbsl', foreground: '0000ff' },
|
||||||
|
{ token: 'stringbsl', foreground: '000000' },
|
||||||
|
{ token: 'string.quotebsl', foreground: '000000' },
|
||||||
|
{ token: 'string.invalidbsl', foreground: '000000' },
|
||||||
|
{ token: 'numberbsl', foreground: '000000' },
|
||||||
|
{ token: 'number.floatbsl', foreground: '000000' },
|
||||||
|
{ token: 'preprocbsl', foreground: '963200' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
blackTheme: {
|
||||||
|
base: 'vs',
|
||||||
|
name: 'bsl-dark',
|
||||||
|
inherit: true,
|
||||||
|
colors: {
|
||||||
|
'foreground': '#d4d4d4',
|
||||||
|
'editor.background': '#1e1e1e',
|
||||||
|
'editor.selectionBackground': '#062f4a',
|
||||||
|
'editorCursor.foreground': '#d4d4d4',
|
||||||
|
'editorSuggestWidget.background': '#252526',
|
||||||
|
'editorSuggestWidget.foreground': '#d4d4d4',
|
||||||
|
'editorSuggestWidget.selectedBackground': '#062f4a',
|
||||||
|
'editorWidget.background': '#252526',
|
||||||
|
'editorWidget.foreground': '#d4d4d4',
|
||||||
|
'editorWidget.border': '#d4d4d4'
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
{ token: 'commentbsl', foreground: '6A9955' },
|
||||||
|
{ token: 'keywordbsl', foreground: '499caa' },
|
||||||
|
{ token: 'delimiterbsl', foreground: 'd4d4d4' },
|
||||||
|
{ token: 'delimiter.squarebsl', foreground: 'd4d4d4' },
|
||||||
|
{ token: 'delimiter.parenthesisbsl', foreground: 'd4d4d4' },
|
||||||
|
{ token: 'identifierbsl', foreground: 'd4d4d4' },
|
||||||
|
{ token: 'stringbsl', foreground: 'c3602c' },
|
||||||
|
{ token: 'string.quotebsl', foreground: 'c3602c' },
|
||||||
|
{ token: 'string.invalidbsl', foreground: 'c3602c' },
|
||||||
|
{ token: 'numberbsl', foreground: 'b5cea8' },
|
||||||
|
{ token: 'number.floatbsl', foreground: 'b5cea8' },
|
||||||
|
{ token: 'preprocbsl', foreground: '963200' },
|
||||||
|
{ background: '#1e1e1e' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
259
src/editor.js
259
src/editor.js
@@ -1,4 +1,4 @@
|
|||||||
define(['bslGlobals', 'bslMetadata', 'snippets', 'vs/editor/editor.main'], function () {
|
define(['bslGlobals', 'bslMetadata', 'snippets', 'bsl_language', 'vs/editor/editor.main'], function () {
|
||||||
|
|
||||||
setText = function(txt, range) {
|
setText = function(txt, range) {
|
||||||
|
|
||||||
@@ -23,26 +23,8 @@ define(['bslGlobals', 'bslMetadata', 'snippets', 'vs/editor/editor.main'], funct
|
|||||||
|
|
||||||
getQuery = function () {
|
getQuery = function () {
|
||||||
|
|
||||||
let position = editor.getPosition();
|
let bsl = new bslHelper(editor.getModel(), editor.getPosition());
|
||||||
|
return bsl.getQuery();
|
||||||
const matches = editor.getModel().findMatches("\"(?:\\n|\\r|\\|)*(?:выбрать|select)(?:(?:.|\\n|\\r)*?)?\"", false, true, false, null, true)
|
|
||||||
const lineNumber = position.lineNumber;
|
|
||||||
|
|
||||||
let idx = 0;
|
|
||||||
let match = null;
|
|
||||||
let queryFound = false;
|
|
||||||
|
|
||||||
if (matches) {
|
|
||||||
|
|
||||||
while (idx < matches.length && !queryFound) {
|
|
||||||
match = matches[idx];
|
|
||||||
queryFound = (match.range.startLineNumber <= lineNumber && lineNumber <= match.range.endLineNumber);
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return queryFound ? { text: match.matches[0], range: match.range } : null;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,239 +34,68 @@ define(['bslGlobals', 'bslMetadata', 'snippets', 'vs/editor/editor.main'], funct
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTheme = function (theme) {
|
||||||
|
|
||||||
|
monaco.editor.setTheme(theme);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Register a new language
|
// Register a new language
|
||||||
monaco.languages.register({ id: 'bsl' });
|
monaco.languages.register({ id: language.id });
|
||||||
|
|
||||||
// Register a tokens provider for the language
|
// Register a tokens provider for the language
|
||||||
monaco.languages.setMonarchTokensProvider('bsl', {
|
monaco.languages.setMonarchTokensProvider(language.id, language.rules);
|
||||||
defaultToken: '',
|
|
||||||
tokenPostfix: 'bsl',
|
|
||||||
brackets: [
|
|
||||||
{ open: '[', close: ']', token: 'delimiter.square' },
|
|
||||||
{ open: '(', close: ')', token: 'delimiter.parenthesis' },
|
|
||||||
],
|
|
||||||
keywords: [
|
|
||||||
'КонецПроцедуры', 'EndProcedure', 'КонецФункции', 'EndFunction',
|
|
||||||
'Прервать', 'Break', 'Продолжить', 'Continue', 'Возврат', 'Return',
|
|
||||||
'Если', 'If', 'Иначе', 'Else', 'ИначеЕсли', 'ElsIf', 'Тогда', 'Then',
|
|
||||||
'КонецЕсли', 'EndIf', 'Попытка', 'Try', 'Исключение', 'Except',
|
|
||||||
'КонецПопытки', 'EndTry', 'Raise', 'ВызватьИсключение', 'Пока',
|
|
||||||
'While', 'Для', 'For', 'Каждого', 'Each', 'Из', 'In', 'По', 'To', 'Цикл',
|
|
||||||
'Do', 'КонецЦикла', 'EndDo', 'НЕ', 'NOT', 'И', 'AND', 'ИЛИ', 'OR', 'Новый',
|
|
||||||
'New', 'Процедура', 'Procedure', 'Функция', 'Function', 'Перем', 'Var',
|
|
||||||
'Экспорт', 'Export', 'Знач', 'Val', 'Неопределено', 'Выполнить'
|
|
||||||
],
|
|
||||||
namespaceFollows: [
|
|
||||||
'namespace', 'using',
|
|
||||||
],
|
|
||||||
parenFollows: [
|
|
||||||
'if', 'for', 'while', 'switch', 'foreach', 'using', 'catch', 'when'
|
|
||||||
],
|
|
||||||
operators: ['=', '<=', '>=', '<>', '<', '>', '+', '-', '*', '/', '%'],
|
|
||||||
symbols: /[=><!~?:&+\-*\/\^%]+/,
|
|
||||||
// escape sequences
|
|
||||||
escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
|
|
||||||
// The main tokenizer for our languages
|
|
||||||
tokenizer: {
|
|
||||||
root: [
|
|
||||||
[/[a-zA-Z\u0410-\u044F_][a-zA-Z\u0410-\u044F_0-9]*/, { cases: { '@keywords': 'keyword', '@default': 'identifier' } }],
|
|
||||||
// whitespace
|
|
||||||
{ include: '@whitespace' },
|
|
||||||
// delimiters and operators
|
|
||||||
[/}/, {
|
|
||||||
cases: {
|
|
||||||
'$S2==interpolatedstring': { token: 'string.quote', next: '@pop' },
|
|
||||||
'$S2==litinterpstring': { token: 'string.quote', next: '@pop' },
|
|
||||||
'@default': '@brackets'
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
[/^\s*#.*$/, 'preproc'],
|
|
||||||
[/[()\[\]]/, '@brackets'],
|
|
||||||
[/@symbols/, {
|
|
||||||
cases: {
|
|
||||||
'@operators': 'delimiter',
|
|
||||||
'@default': ''
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
// numbers
|
|
||||||
[/[0-9_]*\.[0-9_]+([eE][\-+]?\d+)?[fFdD]?/, 'number.float'],
|
|
||||||
[/[0-9_]+/, 'number'],
|
|
||||||
// delimiter: after number because of .\d floats
|
|
||||||
[/[;,.]/, 'delimiter'],
|
|
||||||
// strings
|
|
||||||
[/"([^"\\]|\\.)*$/, 'string.invalid'],
|
|
||||||
[/["|]/, { token: 'string.quote', next: '@string' }],
|
|
||||||
[/\$\@"/, { token: 'string.quote', next: '@litinterpstring' }],
|
|
||||||
[/\@"/, { token: 'string.quote', next: '@litstring' }],
|
|
||||||
[/\$"/, { token: 'string.quote', next: '@interpolatedstring' }],
|
|
||||||
// characters
|
|
||||||
[/'[^\\']'/, 'string'],
|
|
||||||
[/(')(@escapes)(')/, ['string', 'string.escape', 'string']],
|
|
||||||
[/'/, 'string.invalid']
|
|
||||||
],
|
|
||||||
comment: [
|
|
||||||
[/\/\/.*$/, 'comment'],
|
|
||||||
],
|
|
||||||
string: [
|
|
||||||
[/[^\\"]+/, 'string'],
|
|
||||||
[/@escapes/, 'string.escape'],
|
|
||||||
[/\\./, 'string.escape.invalid'],
|
|
||||||
[/"/, { token: 'string.quote', next: '@pop' }],
|
|
||||||
[/\|.*"/, { token: 'string.quote', next: '@pop' }],
|
|
||||||
],
|
|
||||||
litstring: [
|
|
||||||
[/[^"]+/, 'string'],
|
|
||||||
[/""/, 'string.escape'],
|
|
||||||
[/"/, { token: 'string.quote', next: '@pop' }]
|
|
||||||
],
|
|
||||||
litinterpstring: [
|
|
||||||
[/[^"{]+/, 'string'],
|
|
||||||
[/""/, 'string.escape'],
|
|
||||||
[/{{/, 'string.escape'],
|
|
||||||
[/}}/, 'string.escape'],
|
|
||||||
[/{/, { token: 'string.quote', next: 'root.litinterpstring' }],
|
|
||||||
[/"/, { token: 'string.quote', next: '@pop' }]
|
|
||||||
],
|
|
||||||
interpolatedstring: [
|
|
||||||
[/[^\\"{]+/, 'string'],
|
|
||||||
[/@escapes/, 'string.escape'],
|
|
||||||
[/\\./, 'string.escape.invalid'],
|
|
||||||
[/{{/, 'string.escape'],
|
|
||||||
[/}}/, 'string.escape'],
|
|
||||||
[/{/, { token: 'string.quote', next: 'root.interpolatedstring' }],
|
|
||||||
[/"/, { token: 'string.quote', next: '@pop' }]
|
|
||||||
],
|
|
||||||
whitespace: [
|
|
||||||
[/\/\/.*$/, 'comment'],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// Register a completion item provider for the new language
|
// Register a completion item provider for the new language
|
||||||
monaco.languages.registerCompletionItemProvider('bsl', {
|
monaco.languages.registerCompletionItemProvider(language.id, {
|
||||||
|
|
||||||
triggerCharacters: [' ', '.'],
|
triggerCharacters: [' ', '.'],
|
||||||
|
|
||||||
provideCompletionItems: function (model, position) {
|
provideCompletionItems: function (model, position) {
|
||||||
|
|
||||||
let suggestions = [];
|
|
||||||
|
|
||||||
let bsl = new bslHelper(model, position);
|
let bsl = new bslHelper(model, position);
|
||||||
|
return bsl.getCompletition();
|
||||||
if (!bsl.getClassCompletition(suggestions, bslGlobals.classes)) {
|
|
||||||
|
|
||||||
if (!bsl.getClassCompletition(suggestions, bslGlobals.systemEnum)) {
|
|
||||||
|
|
||||||
if (!bsl.getMetadataCompletition(suggestions, bslMetadata)) {
|
|
||||||
|
|
||||||
bsl.getCommonCompletition(suggestions, bslGlobals.keywords, monaco.languages.CompletionItemKind.Keyword.ru, true);
|
|
||||||
bsl.getCommonCompletition(suggestions, bslGlobals.keywords, monaco.languages.CompletionItemKind.Keyword.en, true);
|
|
||||||
|
|
||||||
if (bsl.requireClass()) {
|
|
||||||
bsl.getCommonCompletition(suggestions, bslGlobals.classes, monaco.languages.CompletionItemKind.Constructor, false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bsl.getCommonCompletition(suggestions, bslGlobals.globalfunctions, monaco.languages.CompletionItemKind.Function, true);
|
|
||||||
bsl.getCommonCompletition(suggestions, bslGlobals.globalvariables, monaco.languages.CompletionItemKind.Class, false);
|
|
||||||
bsl.getCommonCompletition(suggestions, bslGlobals.systemEnum, monaco.languages.CompletionItemKind.Enum, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bsl.getSnippets(suggestions, snippets);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (suggestions.length)
|
|
||||||
return { suggestions: suggestions }
|
|
||||||
else
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
monaco.languages.registerSignatureHelpProvider('bsl', {
|
monaco.languages.registerFoldingRangeProvider(language.id, {
|
||||||
|
|
||||||
|
provideFoldingRanges: function (model, context, token) {
|
||||||
|
return bslHelper.getFoldingRanges(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
monaco.languages.registerSignatureHelpProvider(language.id, {
|
||||||
|
|
||||||
signatureHelpTriggerCharacters: ['(', ','],
|
signatureHelpTriggerCharacters: ['(', ','],
|
||||||
|
|
||||||
provideSignatureHelp: (model, position) => {
|
provideSignatureHelp: (model, position) => {
|
||||||
|
|
||||||
let bsl = new bslHelper(model, position);
|
let bsl = new bslHelper(model, position);
|
||||||
let helper = bsl.getMetadataSigHelp(bslMetadata);
|
return bsl.getSigHelp();
|
||||||
|
|
||||||
if (!helper)
|
|
||||||
helper = bsl.getClassSigHelp(bslGlobals.classes);
|
|
||||||
|
|
||||||
if (!helper)
|
|
||||||
helper = bsl.getCommonSigHelp(bslGlobals.globalfunctions);
|
|
||||||
|
|
||||||
if (helper)
|
|
||||||
return new SignatureHelpResult(helper);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
monaco.editor.defineTheme('bsl-white', {
|
monaco.languages.registerHoverProvider(language.id, {
|
||||||
base: 'vs',
|
|
||||||
inherit: true,
|
|
||||||
rules: [
|
|
||||||
{ token: 'commentbsl', foreground: '008000' },
|
|
||||||
{ token: 'keywordbsl', foreground: 'ff0000' },
|
|
||||||
{ token: 'delimiterbsl', foreground: 'ff0000' },
|
|
||||||
{ token: 'delimiter.squarebsl', foreground: 'ff0000' },
|
|
||||||
{ token: 'delimiter.parenthesisbsl', foreground: 'ff0000' },
|
|
||||||
{ token: 'identifierbsl', foreground: '0000ff' },
|
|
||||||
{ token: 'stringbsl', foreground: '000000' },
|
|
||||||
{ token: 'string.quotebsl', foreground: '000000' },
|
|
||||||
{ token: 'string.invalidbsl', foreground: '000000' },
|
|
||||||
{ token: 'numberbsl', foreground: '000000' },
|
|
||||||
{ token: 'number.floatbsl', foreground: '000000' },
|
|
||||||
{ token: 'preprocbsl', foreground: '963200' },
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
monaco.editor.defineTheme('bsl-dark', {
|
provideHover: function (model, position) {
|
||||||
base: 'vs',
|
let bsl = new bslHelper(model, position);
|
||||||
inherit: true,
|
return bsl.getHover();
|
||||||
colors: {
|
}
|
||||||
'foreground': '#d4d4d4',
|
|
||||||
'editor.background': '#1e1e1e',
|
|
||||||
'editor.selectionBackground': '#062f4a',
|
|
||||||
'editorCursor.foreground': '#d4d4d4',
|
|
||||||
'editorSuggestWidget.background': '#252526',
|
|
||||||
'editorSuggestWidget.foreground': '#d4d4d4',
|
|
||||||
'editorSuggestWidget.selectedBackground': '#062f4a',
|
|
||||||
'editorWidget.background': '#252526',
|
|
||||||
'editorWidget.foreground': '#d4d4d4',
|
|
||||||
'editorWidget.border': '#d4d4d4'
|
|
||||||
},
|
|
||||||
rules: [
|
|
||||||
{ token: 'commentbsl', foreground: '6A9955' },
|
|
||||||
{ token: 'keywordbsl', foreground: '499caa' },
|
|
||||||
{ token: 'delimiterbsl', foreground: 'd4d4d4' },
|
|
||||||
{ token: 'delimiter.squarebsl', foreground: 'd4d4d4' },
|
|
||||||
{ token: 'delimiter.parenthesisbsl', foreground: 'd4d4d4' },
|
|
||||||
{ token: 'identifierbsl', foreground: 'd4d4d4' },
|
|
||||||
{ token: 'stringbsl', foreground: 'c3602c' },
|
|
||||||
{ token: 'string.quotebsl', foreground: 'c3602c' },
|
|
||||||
{ token: 'string.invalidbsl', foreground: 'c3602c' },
|
|
||||||
{ token: 'numberbsl', foreground: 'b5cea8' },
|
|
||||||
{ token: 'number.floatbsl', foreground: 'b5cea8' },
|
|
||||||
{ token: 'preprocbsl', foreground: '963200' },
|
|
||||||
{ background: '#1e1e1e' }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
monaco.editor.setTheme('bsl-dark');
|
});
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(language.themes)) {
|
||||||
|
monaco.editor.defineTheme(value.name, value);
|
||||||
|
monaco.editor.setTheme(value.name);
|
||||||
|
}
|
||||||
|
|
||||||
editor = monaco.editor.create(document.getElementById("container"), {
|
editor = monaco.editor.create(document.getElementById("container"), {
|
||||||
theme: "bsl-white",
|
theme: "bsl-white",
|
||||||
value: getCode(),
|
value: getCode(),
|
||||||
language: 'bsl'
|
language: language.id
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
10
src/test.js
10
src/test.js
@@ -239,6 +239,16 @@ describe("Проверка автокомлита и подсказок реда
|
|||||||
bslMetadata = JSON.parse(JSON.stringify(mCopy));
|
bslMetadata = JSON.parse(JSON.stringify(mCopy));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("проверка всплывающей подсказки", function () {
|
||||||
|
let model = getModel("Найти(");
|
||||||
|
let position = new monaco.Position(1, 2);
|
||||||
|
bsl = new bslHelper(model, position);
|
||||||
|
assert.notEqual(bsl.getHover(), null);
|
||||||
|
model = getModel("НайтиЧтоНибудь(");
|
||||||
|
bsl = new bslHelper(model, position);
|
||||||
|
assert.equal(bsl.getHover(), null);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mocha.run();
|
mocha.run();
|
||||||
|
|||||||
Reference in New Issue
Block a user