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
|
||||
* Добавление **;** после ключевых слов *КонецЦикла*, *КонецЕсли* (поле Prefix в bslGlobals)
|
||||
|
||||
### Исправления:
|
||||
* Выделение ключевого слова *Выполнить*
|
||||
|
||||
### Исправления:
|
||||
* Исправлен сниппет для выборки из регистра накопления
|
||||
|
||||
## 0.1.1 (19.07.2020)
|
||||
|
||||
### Новое:
|
||||
|
||||
@@ -5656,11 +5656,15 @@ define([], function () {
|
||||
"Если": {},
|
||||
"Тогда": {},
|
||||
"ИначеЕсли": {},
|
||||
"КонецЦикла": {},
|
||||
"КонецЦикла": {
|
||||
"postfix": ";\n"
|
||||
},
|
||||
"Иначе": {},
|
||||
"Исключение": {},
|
||||
"КонецПопытки": {},
|
||||
"КонецЕсли": {},
|
||||
"КонецЕсли": {
|
||||
"postfix": ";\n"
|
||||
},
|
||||
"Попытка": {},
|
||||
"Пока": {},
|
||||
"Для": {},
|
||||
@@ -5693,7 +5697,9 @@ define([], function () {
|
||||
"Else": {},
|
||||
"ElsIf": {},
|
||||
"Then": {},
|
||||
"EndIf": {},
|
||||
"EndIf": {
|
||||
"postfix": ";\n"
|
||||
},
|
||||
"Try": {},
|
||||
"Except": {},
|
||||
"EndTry": {},
|
||||
@@ -5704,7 +5710,9 @@ define([], function () {
|
||||
"In": {},
|
||||
"To": {},
|
||||
"Do": {},
|
||||
"EndDo": {},
|
||||
"EndDo": {
|
||||
"postfix": ";\n"
|
||||
},
|
||||
"NOT": {},
|
||||
"AND": {},
|
||||
"OR": {},
|
||||
|
||||
@@ -21,7 +21,8 @@ class bslHelper {
|
||||
constructor(model, position) {
|
||||
|
||||
this.model = model;
|
||||
this.position = position;
|
||||
this.lineNumber = position.lineNumber;
|
||||
this.column = position.column;
|
||||
|
||||
let wordData = model.getWordAtPosition(position);
|
||||
this.word = wordData ? wordData.word.toLowerCase() : '';
|
||||
@@ -31,7 +32,7 @@ class bslHelper {
|
||||
|
||||
this.textBeforePosition = this.getTextBeforePosition();
|
||||
this.lastExpression = this.getLastExpression();
|
||||
this.lastRawExpression = this.getLastRawExpression();
|
||||
this.lastRawExpression = this.getLastRawExpression();
|
||||
|
||||
}
|
||||
|
||||
@@ -83,7 +84,7 @@ class bslHelper {
|
||||
*/
|
||||
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() {
|
||||
|
||||
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) == ' ');
|
||||
return text.trim().toLowerCase();
|
||||
|
||||
@@ -271,7 +272,10 @@ class bslHelper {
|
||||
else {
|
||||
|
||||
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
|
||||
* 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
|
||||
* 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) {
|
||||
|
||||
@@ -23,26 +23,8 @@ define(['bslGlobals', 'bslMetadata', 'snippets', 'vs/editor/editor.main'], funct
|
||||
|
||||
getQuery = function () {
|
||||
|
||||
let position = editor.getPosition();
|
||||
|
||||
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;
|
||||
let bsl = new bslHelper(editor.getModel(), editor.getPosition());
|
||||
return bsl.getQuery();
|
||||
|
||||
}
|
||||
|
||||
@@ -52,239 +34,68 @@ define(['bslGlobals', 'bslMetadata', 'snippets', 'vs/editor/editor.main'], funct
|
||||
|
||||
}
|
||||
|
||||
setTheme = function (theme) {
|
||||
|
||||
monaco.editor.setTheme(theme);
|
||||
|
||||
}
|
||||
|
||||
// Register a new language
|
||||
monaco.languages.register({ id: 'bsl' });
|
||||
monaco.languages.register({ id: language.id });
|
||||
|
||||
// Register a tokens provider for the language
|
||||
monaco.languages.setMonarchTokensProvider('bsl', {
|
||||
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'],
|
||||
],
|
||||
},
|
||||
});
|
||||
monaco.languages.setMonarchTokensProvider(language.id, language.rules);
|
||||
|
||||
|
||||
// Register a completion item provider for the new language
|
||||
monaco.languages.registerCompletionItemProvider('bsl', {
|
||||
monaco.languages.registerCompletionItemProvider(language.id, {
|
||||
|
||||
triggerCharacters: [' ', '.'],
|
||||
|
||||
provideCompletionItems: function (model, position) {
|
||||
|
||||
let suggestions = [];
|
||||
|
||||
let bsl = new bslHelper(model, position);
|
||||
|
||||
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 [];
|
||||
return bsl.getCompletition();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
monaco.languages.registerSignatureHelpProvider('bsl', {
|
||||
monaco.languages.registerFoldingRangeProvider(language.id, {
|
||||
|
||||
provideFoldingRanges: function (model, context, token) {
|
||||
return bslHelper.getFoldingRanges(model);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
monaco.languages.registerSignatureHelpProvider(language.id, {
|
||||
|
||||
signatureHelpTriggerCharacters: ['(', ','],
|
||||
|
||||
provideSignatureHelp: (model, position) => {
|
||||
|
||||
let bsl = new bslHelper(model, position);
|
||||
let helper = bsl.getMetadataSigHelp(bslMetadata);
|
||||
|
||||
if (!helper)
|
||||
helper = bsl.getClassSigHelp(bslGlobals.classes);
|
||||
|
||||
if (!helper)
|
||||
helper = bsl.getCommonSigHelp(bslGlobals.globalfunctions);
|
||||
|
||||
if (helper)
|
||||
return new SignatureHelpResult(helper);
|
||||
|
||||
return bsl.getSigHelp();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
monaco.editor.defineTheme('bsl-white', {
|
||||
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.languages.registerHoverProvider(language.id, {
|
||||
|
||||
monaco.editor.defineTheme('bsl-dark', {
|
||||
base: 'vs',
|
||||
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' }
|
||||
]
|
||||
});
|
||||
provideHover: function (model, position) {
|
||||
let bsl = new bslHelper(model, position);
|
||||
return bsl.getHover();
|
||||
}
|
||||
|
||||
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"), {
|
||||
theme: "bsl-white",
|
||||
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));
|
||||
});
|
||||
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user