eclipse-langium / langium

Next-gen language engineering / DSL framework
https://langium.org/
MIT License
725 stars 65 forks source link

Consecutive keyword not proposed without space #1313

Open cdietrich opened 10 months ago

cdietrich commented 10 months ago

given the grammar

Person:
    'person' name=ID;

Greeting:
    'Hello' ':' person=[Person:ID] '!';

in the the sample model

person A
Hello|

the : keyword is not proposed

in the completion provider i allow proposals for previous/next context and for single char keywords

export class HelloWorldCompletionProvider extends DefaultCompletionProvider {

    protected override continueCompletion(items: CompletionItem[]): boolean {
        return true
    }

    protected override filterKeyword(context: CompletionContext, keyword: GrammarAST.Keyword): boolean {
        return true
    }
}
msujew commented 10 months ago

It's not a bug, it's a feature, see: https://github.com/eclipse-langium/langium/blob/bef6560ff94bf5107cac8855aab36f132916c9c7/packages/langium/src/lsp/completion/completion-provider.ts#L311-L317

cdietrich commented 10 months ago

i will check

cdietrich commented 10 months ago

i wonder if we can have access to both the current and following token. thus we can decide if we need a space between two alphanumeric things or not. or should this be done in completionFor ?

cdietrich commented 10 months ago

this is also hard to achieve. backtrackToAnyToken wont give a whitespace token

something like

    protected override async completionFor(context: CompletionContext, next: NextFeature<GrammarAST.AbstractElement>, acceptor: CompletionAcceptor): Promise<void> {
        const { nextTokenStart, previousTokenStart, previousTokenEnd } = this.backtrackToAnyToken(context.textDocument.getText(), context.tokenEndOffset)
        if (previousTokenEnd === nextTokenStart) {
            const x = context.textDocument.getText().slice(previousTokenStart, previousTokenEnd)
            if (HelloWorldCompletionProvider.AllKeywords.has(x)) {
                if (GrammarAST.isKeyword(next.feature)) {
                    const kw = next.feature.value
                    if (/^[a-z0-9]+$/i.test(kw.charAt(0))) {
                        return;
                    }
                } else {
                    return;
                }
            }
        }

        await super.completionFor(context, next, acceptor)
    }

seems to work

cdietrich commented 10 months ago

pot. workaround: adjust keyword completion to add the :