Add Your Own Code Actions!
Everyone who appreciates the help of a smart IDE surely has noticed the tiny yellow light bulbs that occasionally occur next to a line or a piece of code. Clicking on that light bulb gives the choice from a wide variety of actions that the IDE can perform, ranging from adding suitable directives to open namespaces to restructuring code entirely – admittedly, we don’t quite go that far in Q# yet. Our extensions suggest helpful little edits e.g. for adding documentation, removing unreachable code, or rephrasing for-loops.
But how do these so-called code actions work? How does the IDE know what to suggest and what to do? The answer is simple; it asks the Q# compiler of course! When you open a Q# file in Visual Studio Code or Visual Studio, our extensions will launch a process in the background, which runs a server that keeps talking to the IDE as you edit your file. The server collects and maintains information about what projects exist in a workspace, what they depend on, and how they are modified. It maintains a compilation for each project, and tasks the Q# compiler with updating bits and pieces of it when its files change. It also asks the compiler to suggest actions that can be performed for a certain range within a file. And it’s not that difficult to make the compiler recognize a particular pattern. Do you keep forgetting to put parenthesis around operation types? Or would you like a quick fix to address the type mismatch when you type an arithmetic expression like 2*PI() ? Not a problem! Give it a go with adding the functionality you always wanted to our extensions.
The source code for the Q# compiler, language server, and the extensions lives on this GitHub repository. The CompilationManager coordinates access to a Q# compilation. It handles incremental updates and processes design-time queries. This is the piece we want to extend. More precisely, we want to extend the code actions listed in EditorCommands.cs. Going to the definition of any of the queried methods will bring you to the CodeActions.cs file; this is a good place to add your own ideas. You want to add something similar to this:
Each item in the returned array results in an action to choose from when clicking on the light bulb shown if the cursor is within the given range. The diagnostics passed as argument are the ones that the Q# compiler has generated for the code within that range. For each of the returned tuples, the first item contains the description to show, e.g. “Add documentation for TwoBitPE_Reference” above. The second item contains the actual edit to perform if that action is selected. Looking at the other “SuggestionsFor…” methods in the file should give you some hints for how to construct a suitable WorkspaceEdit. The passed FileContentManager and the CompilationUnit provide an arsenal of helpful tools that are already implemented. They can e.g. provide information about the symbol at a given position, find the containing declaration, or list all defined types, callables, and variables. Take a look and see if you can find anything useful!
If this blog has inspired you to try out some ideas, and you would like to share them with other people, we are excited to see your contribution to our repository! Just file an issue describing what you would like to do, and we are happy to help. Or check out the issues that other people have filed to see which one(s) you would like to contribute to; our contribution guide contains more details on collaborations. Happy coding!
This post is part of the Q# Advent Calendar 2019. Follow the calendar for other great posts!