The Wrangler Language Server is an extension to the Erlang Language Server. It provides Erlang refactorings while implementing the Language Server Protocol through Erlang LS.
You can read more about Wrangler in the Wrangler documentation.
Follow the installation instructions of Wrangler.
Install the Erlang Language Server in your chosen text editor.
Modify the erlang_ls.config file. Example:
...
wrangler:
enabled: true
path: "/path/to/wrangler/ebin"
tab_width: 8
search_paths: ["folder/where/you/use/refactorings"]
enabled_refactorings:
- "comment-out-spec"
- "fold-expression"
- "generalise-fun"
- "move-fun"
- "new-fun"
- "new-macro"
- "new-var"
- "rename-fun"
- "rename-var"
- "inline-var"
enabled
and enabled_refactorings
are required properties.path
can be omitted if Wrangler is added to the PATH environment variable.search_paths
will be checked once a refactoring needs to change multiple files in a project. The default value is the project directory. It is recommended to narrow down the search space for large projects.In some cases, refactorings can be done in multiple places. Wrangler highlights the possible refactor candidates that you can choose from in a way we call Wrangler forms.
Select Refactor this instance
in all the places you want the execute the refactoring.
Until you choose exit
or select all the possible refactorings, please do not change the file manually.
For example, while folding fun_to_fold
:
comment-out-spec
Comment out all the lines starting with -spec in a file.
This can be initiated by a code lens at the beginning of the file:
fold-expression
With Wrangler form, replace instances of the function body by the corresponding function definition.
inline-var
With Wrangler form, replace instances of a variable with its corresponding value.
generalise-fun
Refactor the highlighted expression as the function’s new argument.
new-var
Refactor the highlighted expression as a new variable.
move-fun
Move a function definition from its current module to another module. It changes all function calls in the working directory.
new-fun
Introduce a new function definition to represent a selected expression sequence inside an existing function. That selected sequence of expressions is replaced by a call to the new function.
new-macro
Define a macro to represent a selected sequence of expressions.
rename-fun
Rename a function.
rename-var
Rename a variable.
Wrangler-ls extends Erlang-ls with additional codeActions, codeLens etc. The wls_utils
module is used to convert between Erlang-ls/LSP and Wrangler type representations (eg. positions) and to provide some LSP request/notification constructors (eg. textEdit, showMessage).
In the Erlang-ls side, first, Erlang-ls loads the Wrangler modules and starts Wrangler. Then, wrangler_handler
module adds the corresponding language features for all possible requests.
In the Wrangler side, you can find similar files and erlang behaviours to ELS’ els_code_actions
, els_code_lens
, els_execute_command_provider
modules. (These files are prefixed with wls_
).
Used LSP features:
codeAction
- to offer refactorings for the userexecuteCommand
- to execute the refactoringsapplyEdit
- to apply the code changes on the code editor sideshowMessage
- to inform the user about success/errorsemantic tokens
- used in Wrangler forms to colorize the code`s foregrounddocumentHighlight
- used in Wrangler forms to colorize the code`s backgroundcodeLens
- used in Wrangler forms to act as buttonsUser inputs (eg. asking for a new variable name) are handled by a middleware in the extension since these functions are not yet supported by LSP.
To request an input from the user, add the following attribute to the command arguments (text
field is not required):
user_input => #{'type' => variable|atom|macro|file, 'text' => <<"Placeholder text">>}
On successful inputs, a value
field will be added to the user_input
with the given value.
User inputs are yet only supported in the VSCode`s extension. In other editors, default names will be used (eg. “NewVar”)
To make a refactoring available through LSP, create a new Code Action module prefixed with wls_code_action_
implementing wls_code_actions
behaviour:
%% Title which is shown to the user.
-callback title() -> binary().
%% Identifier of the action and the commands.
%% Same as the file's name without the wls_code_action_ prefix.
-callback id() -> action_id().
%% Initialize the action.
%% Optional callback.
-callback init(els_core:uri(), els_core:range()) -> state().
%% Whether the action is offered based on the highlighted range.
%% Optional callback, defaults to true.
-callback precondition(els_core:uri(), els_core:range()) -> boolean().
%% The command`s arguments.
-callback command_args(els_core:uri(), els_core:range(), state()) -> map().
%% Execute the command with the given arguments.
%% The first element of the argument list is the one returned by command_args.
-callback execute_command([any()]) -> [map()].
Register the code action in wls_code_actions:available_actions/0
You can see several examples for this in the projecc. For example, wls_code_action_generalise_fun.erl
that implements the generalise refactoring.
Alternatively, to understand how ELS Code Lenses works, see this article: How to: Code Lenses. Code Actions has a similar behaviour.
For refactorings that need more complex io (eg. fold), Wrangler forms are introduced.
To make these forms, highlight, semantic token and code lens LSP features are used.
The form’s state are handled by wls_server
that can be extended with more of these refactorings.