usethesource / rascal-language-servers

An LSP server for Rascal which includes an easy-to-use LSP generator for languages implemented in Rascal, and an interactive terminal REPL.
BSD 2-Clause "Simplified" License
10 stars 7 forks source link

code actions for dsls #402

Open jurgenvinju opened 1 week ago

jurgenvinju commented 1 week ago

This PR connects the codeActions LSP server service for the parametrized LSP server (so for DLSs).

Pico example, where we are looking for a cursor position over an IdType somewhere in a start[Program], and we register the command removeDecl which can be interpreter later:

list[Command] picoActions([*_, IdType x, *_, start[Program] program]) 
    = [removeDecl(program, x, title="remove <x>")];
s.messages += {<src, error("<id> is not defined", src, 
                                               fixes=[changeToFix(src, existing<0>, title="Change to <existing<0>>") | existing <- defs])
                             > 
                            | <src, id> <- uses, id notin defs<0>};

The error constructor now receives an additional fixes keyword field with a list of options on how to fix the broken variable reference. Each generated command fixes the bug in its own way (with a different variable name to use).

jurgenvinju commented 1 week ago

Will post some screenshots later. This is still a draft.

sonarcloud[bot] commented 1 week ago

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarCloud

Catch issues before they fail your Quality Gate with our IDE extension SonarLint

jurgenvinju commented 1 week ago

lightbulb appears next to error message:

image

CMD+dot activates menu:

image

Selecting the right option fixes the issue:

image

Code for the quickfix:

// attaches multiple quickfix command options to every error (one for every proposed new name):
 s.messages += {<src, error("<id> is not defined", src, fixes=[changeToFix(src, existing<0>, title="Change to <existing<0>>") | existing <- defs])> 
                  | <src, id> <- uses, id notin defs<0>};

// executes the command:
value picoCommands(changeToFix(loc src, str newName)) {
    applyDocumentsEdits([changed(src.top, [replace(src, newName)])]);
    return ("result": true);
}
jurgenvinju commented 1 week ago

Looking for suggestions on how to improve the asynchronous code and suggestions how to test the UI part of this. It's most LSP integration code. The algorithm for generating focus lists could be tested as a unit.