From 128895c54464a5249e328b7c092584a9d2dd45a4 Mon Sep 17 00:00:00 2001 From: alkoleft Date: Thu, 9 Jan 2025 02:53:21 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=20=D0=BE?= =?UTF-8?q?=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B8=D1=8F=20=D1=81=D0=B8=D0=BC?= =?UTF-8?q?=D0=B2=D0=BE=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bsl/features/completionItemProvider.ts | 5 +- src/bsl/features/signatureHelpProvider.ts | 33 ++++++++++++ src/bsl/platform/enums.ts | 7 ++- src/bsl/platform/globalFunctions.ts | 5 +- src/bsl/platform/globalVariables.ts | 3 +- src/bsl/scopeProvider.ts | 63 +++++++++++++++++----- src/languages/bsl/contribution.ts | 4 +- src/main.ts | 9 +++- src/scope/Scope.ts | 4 +- src/yaxunit/scope.ts | 17 ++++-- 10 files changed, 123 insertions(+), 27 deletions(-) create mode 100644 src/bsl/features/signatureHelpProvider.ts diff --git a/src/bsl/features/completionItemProvider.ts b/src/bsl/features/completionItemProvider.ts index 39269a5..3b7fbcf 100644 --- a/src/bsl/features/completionItemProvider.ts +++ b/src/bsl/features/completionItemProvider.ts @@ -19,7 +19,7 @@ const completionItemProvider: languages.CompletionItemProvider = { scope.forEachMembers(m => suggestions.push(newCompletionItem(m, range))) console.debug('suggestions', suggestions) - + return { suggestions: suggestions } @@ -35,7 +35,8 @@ function newCompletionItem(symbol: Symbol, range: Range): languages.CompletionIt label: symbol.name, kind: completionItemKind(symbol.kind), range: range, - insertText: insertText + insertText: insertText, + documentation: symbol.description } } diff --git a/src/bsl/features/signatureHelpProvider.ts b/src/bsl/features/signatureHelpProvider.ts new file mode 100644 index 0000000..68328ab --- /dev/null +++ b/src/bsl/features/signatureHelpProvider.ts @@ -0,0 +1,33 @@ +import { editor, languages, Position } from 'monaco-editor'; +import { scopeProvider } from '../scopeProvider'; + +const signatureHelpProvider: languages.SignatureHelpProvider = { + signatureHelpRetriggerCharacters: ['(', ','], + signatureHelpTriggerCharacters: [')'], + + provideSignatureHelp(model: editor.ITextModel, position: Position): languages.ProviderResult { + const symbol = scopeProvider.currentSymbol(model, position) + if (symbol) { + return { + value: { + signatures: [{ + label: symbol.name, + parameters: [], + documentation: { + value: symbol.description??'' + } + }], + activeParameter: 0, + activeSignature: 0 + }, dispose: () => { } + } + } else { + return undefined + } + + }, +} + +export { + signatureHelpProvider +} \ No newline at end of file diff --git a/src/bsl/platform/enums.ts b/src/bsl/platform/enums.ts index 18a0b5a..a47351f 100644 --- a/src/bsl/platform/enums.ts +++ b/src/bsl/platform/enums.ts @@ -19603,14 +19603,17 @@ GlobalScope.registerGlobalSymbols(definition.map(d => { const t = new PredefinedType(d.name_en, d.values.map(v => { return { name: v.name, - kind: SymbolType.property, type: 'unknown' + kind: SymbolType.property, + description: (v as any).description ?? '', + type: 'unknown' } })) symbols.push(t) return { name: d.name, kind: SymbolType.enum, - type: d.name_en + type: d.name_en, + description: d.description } })) diff --git a/src/bsl/platform/globalFunctions.ts b/src/bsl/platform/globalFunctions.ts index f392f47..84c72d6 100644 --- a/src/bsl/platform/globalFunctions.ts +++ b/src/bsl/platform/globalFunctions.ts @@ -4993,7 +4993,7 @@ const definition = [ { "name": "УстановитьОбновлениеПредопределенныхДанныхИнформационнойБазы", "name_en": "SetInfoBasePredefinedDataUpdate", - "description": "Устанавливает новое значение режима обновления предопределенных данных для информационной базы. Для выполнения требуются права администратора информационной базы. - Если для объекта метаданных в данных установлен режим обновления, отличный от Авто, то используется это значение. - Иначе, если для объекта метаданных в конфигурации установлен режим обновления, отличный от Авто, то используется это значение. - Иначе, если для информационной базы установлен режим обновления, отличный от Авто, то используется это значение. - Иначе, если это периферийный узел РИБ, то предопределенные данные не будут обновлены. Если проверка выполняется для центрального узла РИБ, или для базы не являющейся РИБ, обновление предопределенных данных будет выполнено. Метод доступен только из сеанса, в котором не используется ни один разделитель.", + "description": "Устанавливает новое значение режима обновления предопределенных данных для информационной базы. Для выполнения требуются права администратора информационной базы.\n- Если для объекта метаданных в данных установлен режим обновления, отличный от Авто, то используется это значение.\n- Иначе, если для объекта метаданных в конфигурации установлен режим обновления, отличный от Авто, то используется это значение.\n- Иначе, если для информационной базы установлен режим обновления, отличный от Авто, то используется это значение.\n- Иначе, если это периферийный узел РИБ, то предопределенные данные не будут обновлены. Если проверка выполняется для центрального узла РИБ, или для базы не являющейся РИБ, обновление предопределенных данных будет выполнено. Метод доступен только из сеанса, в котором не используется ни один разделитель.", "signature": { "default": { "СтрокаПараметров": "(ОбновлениеПредопределенныхДанных?: ОбновлениеПредопределенныхДанных)", @@ -5292,6 +5292,7 @@ GlobalScope.registerGlobalSymbols(definition.map(d => { return { name: d.name, kind: SymbolType.function, - type: d.returns + type: d.returns, + description: d.description } })) \ No newline at end of file diff --git a/src/bsl/platform/globalVariables.ts b/src/bsl/platform/globalVariables.ts index 609ac78..77cc009 100644 --- a/src/bsl/platform/globalVariables.ts +++ b/src/bsl/platform/globalVariables.ts @@ -404,6 +404,7 @@ GlobalScope.registerGlobalSymbols(definition.map(d => { return { name: d.name, kind: SymbolType.property, - type: d.name_en + type: d.name_en, + description: d.description } })) \ No newline at end of file diff --git a/src/bsl/scopeProvider.ts b/src/bsl/scopeProvider.ts index 400331b..281fc63 100644 --- a/src/bsl/scopeProvider.ts +++ b/src/bsl/scopeProvider.ts @@ -1,7 +1,7 @@ import { editor, Position } from 'monaco-editor'; import tokensProvider, { TokensSequence } from './tokensProvider' import { getModelScope, UnionScope } from '../scope/scopeStore'; -import { Scope } from '../scope/Scope'; +import { Scope, Symbol } from '../scope/Scope'; import globalScope from '../scope/globalScope' const scopeProvider = { @@ -20,6 +20,29 @@ const scopeProvider = { } else { return objectScope(tokensSequence, scope, position.lineNumber) } + }, + currentSymbol(model: editor.ITextModel, position: Position): Symbol | undefined { + const tokensSequence = tokensProvider.resolve(model, position) + + console.debug('tokensSequence: ', tokensSequence) + if (tokensSequence === undefined || tokensSequence.lastSymbol === ')') { + return undefined + } + + const scope = getModelScope(model) + const word = model.getWordAtPosition(position)?.word + return currentMember(tokensSequence, scope, position.lineNumber, word) + } +} + +function currentMember(tokensSequence: TokensSequence, unionScope: UnionScope, lineNumber: number, word?:string): Symbol | undefined { + tokensSequence.closed = false + if (tokensSequence.tokens.length === 1) { + return globalScopeMember(word??tokensSequence.tokens[0], unionScope, lineNumber) + } + const scope = objectScope(tokensSequence, unionScope, lineNumber) + if (scope) { + return findMember(scope, word??tokensSequence.tokens[tokensSequence.tokens.length - 1]) } } @@ -28,8 +51,8 @@ function objectScope(tokensSequence: TokensSequence, unionScope: UnionScope, lin console.debug('calculate objectScope'); const tokens = tokensSequence.tokens - const lastToken = tokens[tokens.length - 1]; - let scope = resolveInUnionScope(lastToken, unionScope, lineNumber) + const firstToken = tokens[tokens.length - 1]; + let scope = resolveInUnionScope(firstToken, unionScope, lineNumber) if (!scope) { console.debug('don\'t found in global scope') @@ -52,7 +75,7 @@ function objectScope(tokensSequence: TokensSequence, unionScope: UnionScope, lin token = token.substring(0, pos2) } - const member = scope.getMembers().find(s => s.name.localeCompare(token, undefined, { sensitivity: 'accent' }) === 0) + const member = findMember(scope, token) if (member !== undefined && member.type !== undefined) { const tokenScope = globalScope.resolveType(member.type) if (tokenScope !== undefined) { @@ -69,25 +92,37 @@ function objectScope(tokensSequence: TokensSequence, unionScope: UnionScope, lin return scope } -function resolveInUnionScope(token: string, unionScope: UnionScope, lineNumber: number): Scope | undefined { +function findMember(scope: Scope, token: string): Symbol | undefined { + return scope.getMembers().find(s => s.name.localeCompare(token, undefined, { sensitivity: 'accent' }) === 0) +} + +function globalScopeMember(token: string, unionScope: UnionScope, lineNumber: number): Symbol | undefined { const scopes = unionScope.getScopes(lineNumber); for (let index = scopes.length - 1; index >= 0; index--) { const scope = scopes[index] - const member = scope.getMembers().find(s => s.name.localeCompare(token, undefined, { sensitivity: 'accent' }) === 0) - if (member !== undefined) { - if (member.type !== undefined) { - const tokenScope = globalScope.resolveType(member.type) - if (tokenScope !== undefined) { - return tokenScope - } - } - return undefined + const member = findMember(scope, token) + if (member) { + return member } } return undefined } +function resolveInUnionScope(token: string, unionScope: UnionScope, lineNumber: number): Scope | undefined { + const member = globalScopeMember(token, unionScope, lineNumber) + + if (member) { + if (member.type) { + const tokenScope = globalScope.resolveType(member.type) + if (tokenScope) { + return tokenScope + } + } + return undefined + } +} + export { scopeProvider } diff --git a/src/languages/bsl/contribution.ts b/src/languages/bsl/contribution.ts index 7832609..e4f7741 100644 --- a/src/languages/bsl/contribution.ts +++ b/src/languages/bsl/contribution.ts @@ -1,5 +1,6 @@ import { languages } from 'monaco-editor'; import { completionItemProvider } from '../../bsl/features/completionItemProvider' +import { signatureHelpProvider } from '../../bsl/features/signatureHelpProvider' interface ILangImpl { conf: languages.LanguageConfiguration; @@ -17,6 +18,7 @@ languages.onLanguage(language.id, () => { import("./configuration").then((module: ILangImpl) => { languages.setLanguageConfiguration(language.id, module.conf); languages.setMonarchTokensProvider(language.id, module.language); - languages.registerCompletionItemProvider(language.id, completionItemProvider) + languages.registerCompletionItemProvider(language.id, completionItemProvider); + languages.registerSignatureHelpProvider(language.id, signatureHelpProvider) }); }); diff --git a/src/main.ts b/src/main.ts index f6108e8..cbcf335 100644 --- a/src/main.ts +++ b/src/main.ts @@ -44,15 +44,22 @@ const content: string = КонецПроцедуры Процедура ТестУспешно() Экспорт - ЮТест.ОжидаетЧто(1).Равно(1); + + Результат = 1; + ЮТест.ОжидаетЧто(Результат).Равно(1); + КонецПроцедуры Процедура ТестОшибка() Экспорт + ЮТест.ОжидаетЧто(1).Равно(2); + КонецПроцедуры Процедура ТестСломан() Экспорт + ЮТест.ОжидаетЧто(1).ОтсутствующийМетод(2); + КонецПроцедуры `; diff --git a/src/scope/Scope.ts b/src/scope/Scope.ts index 8ebd1db..40350a5 100644 --- a/src/scope/Scope.ts +++ b/src/scope/Scope.ts @@ -8,8 +8,10 @@ export enum SymbolType { export interface Symbol { kind: SymbolType, name: string, - type?: string + type?: string, + description?: string } + export interface MethodSymbol extends Symbol { params: Parameter[], } diff --git a/src/yaxunit/scope.ts b/src/yaxunit/scope.ts index 647fd97..74d0a2a 100644 --- a/src/yaxunit/scope.ts +++ b/src/yaxunit/scope.ts @@ -1,4 +1,4 @@ -import { TypeDefinition, SymbolType, PredefinedType } from "../scope/Scope" +import { TypeDefinition, SymbolType, PredefinedType, MethodSymbol } from "../scope/Scope" import GlobalScope from "../scope/globalScope" const scope: TypeDefinition = new PredefinedType('', [ @@ -14,8 +14,19 @@ const symbols: TypeDefinition[] = [ { kind: SymbolType.function, name: 'ОжидаетЧто', - type: 'CommonModule.ЮТУтверждения' - }, + params: [ + { + name: 'ПроверяемоеЗначение', + type: 'Произвольный', + def: 'Проверяемое фактическое значение' + }, { + name: 'Сообщение', + type: 'Строка', + def: 'Описание проверки, которое будет выведено при возникновении ошибки' + } + ], + type: 'CommonModule.ЮТУтверждения' + } as MethodSymbol, { kind: SymbolType.function, name: 'ОжидаетЧтоТаблицаБазы',