Skip to content

Commit

Permalink
feat: контекстаная подсказка - параметры метода
Browse files Browse the repository at this point in the history
  • Loading branch information
alkoleft committed Jan 10, 2025
1 parent d90a811 commit c70f7ac
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 5,744 deletions.
53 changes: 40 additions & 13 deletions src/bsl/features/signatureHelpProvider.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import { editor, languages, Position } from 'monaco-editor';
import { scopeProvider } from '../scopeProvider';
import { editor, languages, Position, CancellationToken } from 'monaco-editor'
import { scopeProvider } from '../scopeProvider'
import { Symbol, PlatformMethodSymbol, SymbolType } from '../../scope'

const signatureHelpProvider: languages.SignatureHelpProvider = {
signatureHelpRetriggerCharacters: ['(', ','],
signatureHelpTriggerCharacters: [')'],

provideSignatureHelp(model: editor.ITextModel, position: Position): languages.ProviderResult<languages.SignatureHelpResult> {
const symbol = scopeProvider.currentSymbol(model, position)
provideSignatureHelp(model: editor.ITextModel, position: Position, _: CancellationToken, context: languages.SignatureHelpContext): languages.ProviderResult<languages.SignatureHelpResult> {
const symbol = scopeProvider.currentMethod(model, position)
if (symbol) {
const signatures = (symbol.kind === SymbolType.function || symbol.kind === SymbolType.procedure) ?
methodSignature(symbol) :
[{
label: symbol.name,
parameters: [],
documentation: {
value: symbol.description ?? ''
}
}]

return {
value: {
signatures: [{
label: symbol.name,
parameters: [],
documentation: {
value: symbol.description??''
}
}],
activeParameter: 0,
activeSignature: 0
signatures: signatures,
activeParameter: context.activeSignatureHelp?.activeParameter ?? 0,
activeSignature: context.activeSignatureHelp?.activeSignature ?? 0
}, dispose: () => { }
}
} else {
Expand All @@ -28,6 +33,28 @@ const signatureHelpProvider: languages.SignatureHelpProvider = {
},
}

function isPlatformMethod(symbol: Symbol): symbol is PlatformMethodSymbol {
return (<PlatformMethodSymbol>symbol).signatures !== undefined
}

function methodSignature(symbol: Symbol): languages.SignatureInformation[] {
if (isPlatformMethod(symbol)) {
return symbol.signatures.map(s => {
return {
label: s.description === '' ? symbol.name : s.description,
documentation: s.description === '' ? symbol.description : s.description, activeParameter: 0,
parameters: s.params.map(p => {
return {
label: p.name,
documentation: p.description ? { value: p.description } : 'Type: ' + p.type
}
})
}
})
}
return []
}

export {
signatureHelpProvider
}
5,306 changes: 14 additions & 5,292 deletions src/bsl/platform/globalFunctions.ts

Large diffs are not rendered by default.

399 changes: 1 addition & 398 deletions src/bsl/platform/globalVariables.ts

Large diffs are not rendered by default.

25 changes: 21 additions & 4 deletions src/bsl/scopeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,44 @@ const scopeProvider = {
}
},
currentSymbol(model: editor.ITextModel, position: Position): Symbol | undefined {
console.debug('current symbol')
const tokensSequence = tokensProvider.resolve(model, position)

console.debug('tokensSequence: ', tokensSequence)
if (tokensSequence === undefined || tokensSequence.lastSymbol === ')') {
return undefined
}

tokensSequence.closed = false

const scope = EditorScope.getScope(model)
const word = model.getWordAtPosition(position)?.word
return currentMember(tokensSequence, scope, position.lineNumber, word)
},
currentMethod(model: editor.ITextModel, position: Position): Symbol | undefined {
console.debug('current word', model.getWordUntilPosition(position)?.word)

console.debug('current symbol')
const tokensSequence = tokensProvider.findMethod(model, position)

console.debug('tokensSequence: ', tokensSequence)
if (tokensSequence === undefined) {
return undefined
}

tokensSequence.closed = true
const scope = EditorScope.getScope(model)
return currentMember(tokensSequence, scope, position.lineNumber)
}
}

function currentMember(tokensSequence: TokensSequence, editorScope: EditorScope, lineNumber: number, word?:string): Symbol | undefined {
tokensSequence.closed = false
function currentMember(tokensSequence: TokensSequence, editorScope: EditorScope, lineNumber: number, word?: string): Symbol | undefined {
if (tokensSequence.tokens.length === 1) {
return globalScopeMember(word??tokensSequence.tokens[0], editorScope, lineNumber)
return globalScopeMember(word ?? tokensSequence.tokens[0], editorScope, lineNumber)
}
const scope = objectScope(tokensSequence, editorScope, lineNumber)
if (scope) {
return findMember(scope, word??tokensSequence.tokens[tokensSequence.tokens.length - 1])
return findMember(scope, word ?? tokensSequence.tokens[tokensSequence.tokens.length - 1])
}
}

Expand Down
107 changes: 73 additions & 34 deletions src/bsl/tokensProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,57 +7,93 @@ export interface TokensSequence {
closed: boolean
}
export default {
resolve: collectTokens
resolve: collectTokens,
findMethod
}

type checkStateType = (state: State, value: string, token: Token) => void

function findMethod(model: editor.ITextModel, startPosition: Position): TokensSequence | undefined {
let isMethod = false
return walkTokens(model, startPosition, (state: State, value: string, token: Token) => {

if (isMethod) {
state.skipSymbol = false
checkState(state, value, token)
} else {
if (tokenIs(token, TokenType.MetaTag) || value === ';') {
state.done = true
} else if (value === '(' && state.parenthesisLevel < 0) {
isMethod = true
state.lastToken = ''
state.parenthesisLevel = 0
state.squareLevel = 0
state.skipSymbol = true
} else {
state.skipSymbol = true
}
}
})
}

function collectTokens(model: editor.ITextModel, startPosition: Position): TokensSequence | undefined {
return walkTokens(model, startPosition, checkState)
}

function checkState(state: State, value: string, token: Token) {
if (state.squareLevel < 0) {
state.done = true
} else if (state.parenthesisLevel < 0) {
state.done = true
} else if (isBreak(token, value)) {
state.done = true
} else if (state.isLastToken && isString(token)) {
state.done = true
}
}

function walkTokens(model: editor.ITextModel, startPosition: Position, fn: checkStateType) {
let line = model.getLineContent(startPosition.lineNumber).substring(0, startPosition.column - 1);

const symbols: string[] = []

let lineNumber = startPosition.lineNumber
let isFirst = true
const state: State = baseState(startPosition.lineNumber)

const state: State = { parenthesisLevel: 0, squareLevel: 0, done: false, currentSymbol: '', lastToken: '' }

while (!state.done && lineNumber > 0) {
while (!state.done && state.lineNumber > 0) {
if (line !== '') {
const lineTokens = getTokens(line)
if (isFirst) {
if (isString(lineTokens[lineTokens.length - 1])) {
return undefined
}
isFirst = false
}
let lastTokenOffset = line.length;

for (let index = lineTokens.length - 1; index >= 0; index--) {
const token = lineTokens[index];
const value = line.substring(token.offset, lastTokenOffset);

updateState(state, value, token)
fn(state, value, token)

if (state.done || isBreak(token, value)) {
state.done = true
if (state.done) {
break;
}
if (value === '.') {
symbols.push(state.currentSymbol)
state.currentSymbol = ''
} else {
state.currentSymbol = value + state.currentSymbol;

if (!state.skipSymbol) {
if (value === '.') {
symbols.push(state.currentSymbol)
state.currentSymbol = ''
} else {
state.currentSymbol = value + state.currentSymbol;
}
}
lastTokenOffset = token.offset
console.debug('Tokens resolve state: ', state)
}
}
if (lineNumber === 1) {
if (state.lineNumber === 1) {
state.done = true
}

if (!state.done) {
lineNumber--;
line = model.getLineContent(lineNumber)
state.lineNumber--;
line = model.getLineContent(state.lineNumber)
}
}
if (state.currentSymbol !== '') {
Expand All @@ -74,39 +110,42 @@ function collectTokens(model: editor.ITextModel, startPosition: Position): Token
closed: state.lastToken === '.',
lastSymbol: state.lastToken
}

}

function updateState(state: State, value: string, token: Token): void {
console.debug('Token: ', token)
if (!state.lastToken && !tokenIs(token, TokenType.Source)) {
state.lastToken = value
state.isLastToken = true
} else if (state.isLastToken) {
state.isLastToken = false
}

if (value === ']') {
state.squareLevel++;
}
else if (value === ')') {
} else if (value === ')') {
state.parenthesisLevel++;
}
else if (value === '[') {
} else if (value === '[') {
state.squareLevel--;
if (state.squareLevel < 0) {
state.done = true
}
}
else if (value === '(') {
} else if (value === '(') {
state.parenthesisLevel--;
if (state.parenthesisLevel < 0) {
state.done = true
}
}
}

function baseState(lineNumber: number): State {
return { parenthesisLevel: 0, squareLevel: 0, done: false, currentSymbol: '', lastToken: '', lineNumber: lineNumber, skipSymbol: false, isLastToken: false }
}

interface State {
squareLevel: number,
parenthesisLevel: number,
done: boolean,
currentSymbol: string,
lastToken: string,
isLastToken: boolean
lineNumber: number,
skipSymbol: boolean
}

function getTokens(line: string): Token[] {
Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const content: string =
Процедура ТестУспешно() Экспорт
Результат = 1;
Результат = СтрНайти("90", "9");
ЮТест.ОжидаетЧто(Результат).Равно(1);
КонецПроцедуры
Expand Down
11 changes: 10 additions & 1 deletion src/scope/symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,17 @@ export interface MethodSymbol extends Symbol {
params: Parameter[],
}

export interface PlatformMethodSymbol extends Symbol {
signatures: MethodSignature[],
}

export interface MethodSignature {
description: string,
params: Parameter[],
}

export interface Parameter {
name: string,
type: string,
def: string
description: string
}
2 changes: 1 addition & 1 deletion src/yaxunit/features/lensProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const codeLensProvider: languages.CodeLensProvider = {

provideCodeLenses: function () {
const editor = getActiveEditor()
const lenses = editor ? editor.module.module.methods.map(m => {
const lenses = editor ? editor.scope.getMethods().map(m => {
return {
range: {
startLineNumber: m.startLine,
Expand Down

0 comments on commit c70f7ac

Please sign in to comment.