1
0
mirror of https://github.com/salexdv/bsl_console.git synced 2025-02-15 13:53:04 +02:00

Подказка через точку для свойств и методов объектов, полученных через какую-либо функцию.

Например, для результата запроса полученного через Запрос.Выгрузить().
Подказка параметров методов для объектов, полученных через какую-либо функцию, либо через точку.
Например, Таблица1 = Новый ТаблицаЗначений(); Таблица2 = Таблица1.Скопировать(); Таблица2.ВыгрузитьКолонку( - тут подсказка параметров
This commit is contained in:
salexdv 2020-08-04 21:12:21 +03:00
parent 625955b273
commit 45fd8df100
6 changed files with 1959 additions and 1754 deletions

View File

@ -68,8 +68,14 @@ define(['vs/editor/editor.main'], function () {
cmd: 0,
order: 0,
callback: function (e, obj) {
if (obj && obj.hasOwnProperty('ref')) {
refs.set(editor.getPosition().toString(), obj);
if (obj && obj.hasOwnProperty('data')) {
let position = editor.getPosition();
let lineContextData = contextData.get(position.lineNumber);
if (!lineContextData) {
contextData.set(position.lineNumber, new Map());
}
lineContextData = contextData.get(position.lineNumber);
lineContextData.set(obj.name, obj.data);
}
return null;
}

File diff suppressed because it is too large Load Diff

View File

@ -368,13 +368,25 @@ class bslHelper {
signatures = this.getMethodsSignature(mvalue);
if (signatures.length == 0 || (signatures.length == 1 && signatures[0].parameters.length == 0))
postfix = '()';
let command = null;
let ref = null;
if (mvalue.hasOwnProperty('ref'))
ref = mvalue.ref;
if (ref || signatures) {
// If the attribute contains a ref, we need to run the command to save the position of ref
command = { id: 'vs.editor.ICodeEditor:1:saveref', arguments: [{ "name": mvalue[this.nameField], "data": { "ref": ref, "sig": signatures } }] }
}
suggestions.push({
label: mvalue[this.nameField],
kind: monaco.languages.CompletionItemKind.Function,
insertText: mvalue.name + postfix,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
detail: mvalue.description
detail: mvalue.description,
command: command
});
}
@ -384,6 +396,42 @@ class bslHelper {
}
/**
* Fills the suggestions for reference-type object
*
* @param {array} suggestions the list of suggestions
* @param {string} wordRef reference string like classes.HTTPОтвет
*/
getRefSuggestions(suggestions, wordContext) {
if (wordContext && wordContext.ref) {
let refArray = wordContext.ref.split('.');
if (refArray.length == 2) {
let itemName = refArray[0];
let subItemName = refArray[1];
if (itemName == 'classes' || itemName == 'types') {
if (this.objectHasProperties(bslGlobals, itemName, subItemName)) {
this.getClassSuggestions(suggestions, bslGlobals[itemName][subItemName]);
}
}
else {
if (this.objectHasProperties(bslMetadata, itemName, 'items', subItemName, 'properties')) {
this.fillSuggestionsForMetadataItem(suggestions, bslMetadata[itemName].items[subItemName]);
this.getMetadataMethods(suggestions, bslMetadata[itemName], 'refMethods');
}
}
}
}
}
/**
* Fills the suggestions for reference-type object
* if a reference was found in the previous position
@ -392,7 +440,7 @@ class bslHelper {
*/
getRefCompletition(suggestions) {
const match = this.model.findPreviousMatch('.', this.position, false);
let match = this.model.findPreviousMatch('.', this.position, false);
if (match) {
@ -400,30 +448,31 @@ class bslHelper {
if (position.lineNumber = this.lineNumber) {
let positionRef = refs.get(position.toString())
let lineContextData = contextData.get(position.lineNumber)
if (lineContextData) {
let wordUntil = this.model.getWordUntilPosition(position);
this.getRefSuggestions(suggestions, lineContextData.get(wordUntil.word))
if (positionRef) {
let wordUntil = this.model.getWordUntilPosition(position);
if (positionRef.name == wordUntil.word) {
}
else {
match = this.model.findPreviousMatch('(?<!\\/\\/.*)' + this.lastRawExpression + '\\s?=\\s?.*\\.([^.]*?)\\s?(?:;|\\()', this.position, true, false, null, true);
if (match) {
let refArray = positionRef.ref.split('.');
if (refArray.length == 2) {
lineContextData = contextData.get(match.range.startLineNumber);
if (this.objectHasProperties(bslMetadata, refArray[0], 'items', refArray[1], 'properties')) {
this.fillSuggestionsForMetadataItem(suggestions, bslMetadata[refArray[0]].items[refArray[1]]);
this.getMetadataMethods(suggestions, bslMetadata[refArray[0]], 'refMethods');
}
}
if (lineContextData)
this.getRefSuggestions(suggestions, lineContextData.get(match.matches[match.matches.length - 1]));
}
}
}
}
}
}
/**
@ -437,7 +486,7 @@ class bslHelper {
getCustomObjectsCompletition(suggestions, data, kind) {
let objName = this.getLastNExpression(2);
let word = this.getLastRawExpression();
let word = this.lastRawExpression;
if (objName) {
@ -478,6 +527,70 @@ class bslHelper {
}
/**
* Fills the suggestions for objects from bslGlobals
* like classes or types
*
* @param {array} suggestions the list of suggestions
* @param {object} obj object from BSL-JSON dictionary
*/
getClassSuggestions(suggestions, obj) {
if (obj.hasOwnProperty('methods')) {
for (const [mkey, mvalue] of Object.entries(obj.methods)) {
let description = mvalue.hasOwnProperty('returns') ? mvalue.returns : '';
let signatures = this.getMethodsSignature(mvalue);
let postfix = '';
if (signatures.length == 0 || (signatures.length == 1 && signatures[0].parameters.length == 0))
postfix = '()';
let command = null;
let ref = null;
if (mvalue.hasOwnProperty('ref'))
ref = mvalue.ref;
if (ref || signatures) {
// If the attribute contains a ref, we need to run the command to save the position of ref
command = { id: 'vs.editor.ICodeEditor:1:saveref', arguments: [{ "name": mvalue[this.nameField], "data": { "ref": ref, "sig": signatures } }] };
}
suggestions.push({
label: mvalue[this.nameField],
kind: monaco.languages.CompletionItemKind.Method,
insertText: mvalue[this.nameField] + postfix,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
detail: mvalue.description,
documentation: description,
command: command
});
}
}
if (obj.hasOwnProperty('properties')) {
for (const [pkey, pvalue] of Object.entries(obj.properties)) {
suggestions.push({
label: pvalue[this.nameField],
kind: monaco.languages.CompletionItemKind.Field,
insertText: pvalue[this.nameField],
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
detail: pvalue.description,
documentation: '',
command: null
});
}
}
}
/**
* Fills array of completition for class methods, properties and
* system enumarations
@ -499,74 +612,26 @@ class bslHelper {
classExists = true;
let values = [];
if (value.hasOwnProperty('methods')) {
for (const [mkey, mvalue] of Object.entries(value.methods)) {
let description = mvalue.hasOwnProperty('returns') ? mvalue.returns : '';
let signatures = this.getMethodsSignature(mvalue);
let postfix = '';
if (signatures.length == 0 || (signatures.length == 1 && signatures[0].parameters.length == 0))
postfix = '()';
values.push({
name: mvalue[this.nameField],
postfix: postfix,
detail: mvalue.description,
description: description,
kind: monaco.languages.CompletionItemKind.Method,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
});
}
}
if (value.hasOwnProperty('properties')) {
for (const [pkey, pvalue] of Object.entries(value.properties)) {
values.push({
name: pvalue[this.nameField],
detail: pvalue.description,
description: '',
postfix: '',
kind: monaco.languages.CompletionItemKind.Field
});
}
}
this.getClassSuggestions(suggestions, value);
if (value.hasOwnProperty('values')) {
for (const [vkey, vvalue] of Object.entries(value.values)) {
values.push({
name: vvalue[this.nameField],
suggestions.push({
label: vvalue[this.nameField],
kind: monaco.languages.CompletionItemKind.Field,
insertText: vvalue[this.nameField],
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
detail: vvalue.description,
description: '',
postfix: '',
kind: monaco.languages.CompletionItemKind.Field
});
documentation: '',
command: null
});
}
}
values.forEach(function (value) {
suggestions.push({
label: value.name,
kind: value.kind,
insertText: value.name + value.postfix,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
detail: value.detail,
documentation: value.description
});
});
}
}
@ -588,15 +653,12 @@ class bslHelper {
let classExists = false;
let className = '';
let exp = this.getLastRawExpression();
let exp = this.lastRawExpression;
let fullText = this.getFullTextBeforePosition();
let regex = new RegExp(exp + '\\s?=\\s?(?:новый|new)\\s(.*)\\(.*\\);', 'gi');
const match = this.model.findPreviousMatch('(?<!\\/\\/.*)' + exp + '\\s?=\\s?(?:new|новый)\\s+(.*?)(?:\\(|;)', this.position, true, false, null, true);
regex = regex.exec(fullText);
if (regex && 1 < regex.length) {
className = regex[1];
if (match) {
className = match.matches[match.matches.length - 1].toLowerCase();
}
else {
className = exp;
@ -678,7 +740,7 @@ class bslHelper {
let itemExists = false;
let exp = this.getLastRawExpression();
let exp = this.lastRawExpression;
if (exp) {
@ -876,51 +938,48 @@ class bslHelper {
for (const [key, value] of Object.entries(data)) {
let values = [];
if (!subType) {
for (const [inkey, invalue] of Object.entries(value)) {
if (!subType) {
let suggestion = {
label: inkey,
kind: kind,
insertText: inkey,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
}
if (invalue.hasOwnProperty('ref')) {
suggestion.insertText += '.';
suggestion['command'] = { id: 'editor.action.triggerSuggest', title: 'suggest_type' };
}
else {
suggestion.insertText += '"';
}
suggestions.push(suggestion);
let suggestion = {
label: key,
kind: kind,
insertText: key,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
}
if (value.hasOwnProperty('ref')) {
suggestion.insertText += '.';
suggestion['command'] = { id: 'editor.action.triggerSuggest', title: 'suggest_type' };
}
else {
suggestion.insertText += '"';
}
if (inkey.toLowerCase() == subType) {
suggestions.push(suggestion);
if (invalue.hasOwnProperty('ref') && bslMetadata.hasOwnProperty(invalue.ref) && bslMetadata[invalue.ref].hasOwnProperty('items')) {
}
else {
for (const [mkey, mvalue] of Object.entries(bslMetadata[invalue.ref].items)) {
if (key.toLowerCase() == subType) {
suggestions.push({
label: mkey,
kind: kind,
insertText: mkey + '"',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
});
if (value.hasOwnProperty('ref') && bslMetadata.hasOwnProperty(value.ref) && bslMetadata[value.ref].hasOwnProperty('items')) {
for (const [mkey, mvalue] of Object.entries(bslMetadata[value.ref].items)) {
suggestions.push({
label: mkey,
kind: kind,
insertText: mkey + '"',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
});
}
}
}
}
}
}
}
@ -1349,6 +1408,50 @@ class bslHelper {
}
/**
* Fills signatures provided for reference-type object
* if a reference was found in the previous position
*
* @param {aaray} suggestions the list of suggestions
*/
getRefSigHelp() {
let helper = null;
let match = this.model.findPreviousMatch('(', this.position, false);
if (match) {
const position = new monaco.Position(match.range.startLineNumber, match.range.startColumn);
if (position.lineNumber = this.lineNumber) {
let lineContextData = contextData.get(position.lineNumber)
let wordContext = null;
if (lineContextData) {
let wordUntil = this.model.getWordUntilPosition(position);
wordContext = lineContextData.get(wordUntil.word);
if (wordContext && wordContext.sig) {
helper = {
activeParameter: this.textBeforePosition.split(',').length - 1,
activeSignature: 0,
signatures: wordContext.sig,
}
}
}
}
}
return helper;
}
/**
* Signature help provider
*
@ -1358,7 +1461,10 @@ class bslHelper {
if (this.lastOperator != ')') {
let helper = this.getMetadataSigHelp(bslMetadata);
let helper = this.getRefSigHelp();
if (!helper)
helper = this.getMetadataSigHelp(bslMetadata);
if (!helper)
helper = this.getClassSigHelp(bslGlobals.classes);

View File

@ -5,7 +5,7 @@ define(['bslGlobals', 'bslMetadata', 'snippets', 'bsl_language', 'vs/editor/edit
selectionText = '';
engLang = false;
decorations = [];
refs = new Map();
contextData = new Map();
sendEvent = function(eventName, eventParams) {

View File

@ -83,6 +83,8 @@
'\t|ИЗ',
'\t| Документ.АвансовыйОтчет КАК АвансовыйОтчет");',
'\t',
'\tРезультат = Запрос.',
'\t',
'КонецФункции',
].join('\n');;
}

View File

@ -123,6 +123,7 @@ describe("Проверка автокомлита и подсказок реда
let suggestions = [];
bsl.getClassCompletition(suggestions, bslGlobals.classes);
expect(suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.some(suggest => suggest.label === "УстановитьПараметр"), false);
});
it("проверка автокомплита для экземпляра объекта HTTPЗапрос (список свойств и методов)", function () {
@ -400,7 +401,9 @@ describe("Проверка автокомлита и подсказок реда
it("проверка подсказки ссылочных реквизитов", function () {
bsl = helper('_ОстаткиТовара.Номенклатура.');
let suggestions = [];
refs.set(new monaco.Position(bsl.position.lineNumber, bsl.position.column - 1).toString(), {"name": "Номенклатура", ref: "catalogs.Товары"});
contextData = new Map([
[1, new Map([["Номенклатура", { "ref": "catalogs.Товары", "sig": null }]])]
]);
bsl.getRefCompletition(suggestions);
expect(suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.some(suggest => suggest.label === "СтавкаНДС"), true);
@ -408,7 +411,41 @@ describe("Проверка автокомлита и подсказок реда
bsl = helper('_ОстаткиТовара.Наминклатура.');
bsl.getRefCompletition(suggestions);
expect(suggestions).to.be.an('array').that.is.empty;
refs = new Map();
contextData = new Map();
});
it("проверка подсказки для таблицы, полученной из результата запроса", function () {
bsl = helper('ОбъектЗапрос = Новый Запрос();\nРезультат = ОбъектЗапрос.Выполнить();\nТаблица = Результат.Выгрузить();\nТаблица.');
let suggestions = [];
contextData = new Map([
[2, new Map([["Выполнить", { "ref": "types.РезультатЗапроса", "sig": null }]])],
[3, new Map([["Выгрузить", { "ref": "classes.ТаблицаЗначений", "sig": null }]])]
]);
bsl.getRefCompletition(suggestions);
expect(suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.some(suggest => suggest.label === "ВыгрузитьКолонку"), true);
contextData = new Map();
});
it("проверка подсказки параметров для функции ВыгрузитьКолонку таблицы значений, полученной из другой таблицы", function () {
bsl = helper('Таблица1 = Новый ТаблицаЗначений();\nТаблица2 = Таблица1.Скопировать();\nТаблица2.ВыгрузитьКолонку(');
let suggestions = [];
let signature = {
"default": {
"СтрокаПараметров": "(Колонка: Число): Массив",
"Параметры": {
"Колонка": "Колонка, из которой нужно выгрузить значения. В качестве значения параметра может быть передан индекс колонки, имя колонки, либо колонка дерева значений."
}
}
};
contextData = new Map([
[2, new Map([["Скопировать", { "ref": "classes.ТаблицаЗначений", "sig": null }]])],
[3, new Map([["ВыгрузитьКолонку", { "ref": "classes.Массив", "sig": signature }]])]
]);
let help = bsl.getRefSigHelp();
console.log(help);
expect(help).to.have.property('activeParameter');
contextData = new Map();
});
}