I am looking at some code where some of the variables are really obscure. For example,
h582=30
where h582 might mean temperature. I have a dictionary that tells me what each variable means. Is there any existing feature or would it be possible to extend visual studio code easily to show me the meaning of each variable on mouse hover?
I would recommend using find/replace on the workspace to rewrite the variables to their readable names (I would go crazy trying to read code like that).
But if you can't do that and want to see the real name when you hover the variable, you could write a vscode extension for this. It would not be too hard - you just need to implement a hover provider which would check the name of the token under the cursor, look it up in the dictionary, and return the result. Example:
vscode.languages.registerHoverProvider('javascript', {
provideHover(document, position, token) {
const hoveredWord = document.getText(document.getWordRangeAtPosition(position));
const mappedWord = dictionary[hoveredWord]
if (mappedWord) {
return new Hover(mappedWord);
} else {
return null;
}
}
});
See the docs here: https://code.visualstudio.com/docs/extensionAPI/vscode-api#_languages
Related
I am working on a VsCode extension in that I want to provide custom snippets for code completion.
I know about the option of using snippet json files directly, however those have the limitation of not being able to utilize the CompletionItemKind property that determines the icon next to the completion suggestion in the pop-up.
My issue:
If I implement a simple CompletionItemProvider like this:
context.subscriptions.push(
vscode.languages.registerCompletionItemProvider(
{scheme:"file",language:"MyLang"},
{
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) {
let item = new vscode.CompletionItem('test');
item.documentation = 'my test function';
item.kind = vscode.CompletionItemKind.Function;
return [item];
}
}
)
)
then the original VsCode IntelliSense text suggestions are not shown anymore, only my own. Should I just return a kind of an empty response, like
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) {
return [null|[]|undefined];
}
the suggestions appear again as they should. It seems to me that instead of merging the results of the built-in IntelliSense and my own provider, the built-in ones get simply overridden.
Question:
How can I keep the built-in IntelliSense suggestions while applying my own CompletionItems?
VsCode Version: v1.68.1 Ubuntu
I seem to have found the answer for my problem, so I will answer my question.
Multiple providers can be registered for a language. In that case providers are sorted
by their {#link languages.match score} and groups of equal score are sequentially asked for
completion items. The process stops when one or many providers of a group return a
result.
My provider seems to provide results that are just higher scored than those of IntelliSense.
Since I didn't provide any trigger characters, my CompletionItems were comteping directly with the words found by the built-in system by every single pressed key and won.My solution is to simply parse and register the words in my TextDocument myself and extend my provider results by them. I could probably just as well create and register a new CompletionItemProvider for them if I wanted to, however I decided to have a different structure for my project.
In my VS Code extension I have some code that uses the built in Markdown extension. I capture a reference to it by registering as a markdown plugin and putting the following code at the end of my extension's activate method.
return {
extendMarkdownIt(mdparam: any) {
return md = mdparam;
}
};
Markdown calls this when it activates.
Generally this is not a problem. Most of the use cases for my extension involve a markdown file already loaded into the active editor, and the loading of this file triggers activation of the markdown extension.
However there are some legitimate use cases in which this is not so.
I need to programmatically trigger activation of the markdown extension. Some of these cases involve having a different kind of file open in the active editor so loading a markdown file into it is not an acceptable option.
Some potential strategies:
Change the language mode. There is a command workbench.action.editor.changeLanguageMode but no documentation. I tried
vscode.commands.executeCommand('workbench.action.editor.changeLanguageMode', 'md');
but this triggers the UI
so I tried a pattern I've seen in the parameters of other commands and added , true. This suppressed the UI but doesn't seem to work.
Load a markdown file into a new editor then close it again. This should work, but it's ugly.
Put something in the contributions section of my extension that changes the activation trigger for the markdown extension so that it is triggered by the other file types on which my extension operates.
Of these options my favourite would be 3 but I don't even know whether this is even possible. Option 1 is hampered by the crappy (in many cases non-existent) documentation for vscode internal commands.
Option 1 it is. If anyone knows how to do option 3 please tell, the solution below is a ghastly hack.
It is possible to trigger activation of the Markdown extension by changing the document language of any open editor to markdown. In the event that there are no open editors a document with the markdown language set can be created in memory and loaded into an editor.
If VS Code is busy loading extensions activation can take several hundred milliseconds so the best thing to do is watch the variable into which markdown-it is captured.
The variable md is a global (global to my extension, not the whole of VS Code) into which a reference is acquired as shown in the question.
let ed = vscode.window.activeTextEditor;
if (ed) {
let lid = ed.document.languageId;
if (lid !== "markdown") {
vscode.languages.setTextDocumentLanguage(ed.document, "markdown").then(
function waitForMd() {
if (md) {
vscode.languages.setTextDocumentLanguage(ed!.document, lid);
} else {
setTimeout(waitForMd, 100);
}
}
);
}
} else {
vscode.workspace.openTextDocument({ language: "markdown" }).then(doc => {
vscode.window.showTextDocument(doc).then(
function waitForMd() {
if (md) {
vscode.commands.executeCommand("workbench.action.closeActiveEditor");
} else {
setTimeout(waitForMd, 100);
}
});
});
}
Once the capture completes we can restore the true language or close the editor as appropriate. To be realistic the second case (no active editor) is unlikely because my own extension won't activate until you load something. At any rate it works stably now. The larger project is progressing nicely.
Im using Ember with VS Code.
What I need is to generate import string on a fly when I encounter dependency. For example I write someting like:
#tracked isLarge = false;
But I don’t have “#tracked” imported yet. So the otion could be to set the coursor on #tracked, press something like “Action + .” and pick “generate import”. It should generate import string:
import { tracked } from '#ember/tracking';
But it doesn’t work out of the box. How can I do that?
UPDATE: the same question about:
go to definition
go to implementation
cmd+click to navigate to implementation/component
You can use the extension My Code Actions
You can create actions that just insert the text independent of an error.
"my-code-actions.actions": {
"[javascript]": {
"import tracked": {
"where": "insertAfter",
"insertFind": "^import",
"text": "import { tracked } from '#ember/tracking';\n"
}
}
}
The key combo to use is the Code Action combo: Ctrl+.
If you get a diagnostic (PROBLEM panel, and squiggle) you can use that to further customize the action and you can use text from the diagnostics message.
I'm current adding the possibility to make multiple edits in an action and to use further customization and generalization.
"Ember Language Server" brings some solution. But it works mostly with library code that has .d.ts typings.
In case of custom JS code it still doesn't work.
So there is no straight solution. Only 2 ways:
Write .d.ts typing for custom code JS files
Move project to typescript
I'm trying to develop a Language Server to a new language in VS Code and I'm using the Microsoft sample as reference (https://github.com/microsoft/vscode-extension-samples/tree/master/lsp-sample).
In their sample the autocompletion is done in this chunk of code:
connection.onCompletion(
(_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
// The pass parameter contains the position of the text document in
// which code complete got requested. For the example we ignore this
// info and always provide the same completion items.
return [
{
label: 'TypeScript',
kind: CompletionItemKind.Text,
data: 1
},
{
label: 'JavaScript',
kind: CompletionItemKind.Text,
data: 2
}
];
}
);
As the comment says, it's a dumb autocompletion system, since it always provides the same suggestions.
I can see that there's an input parameter of type TextDocumentPositionParams and this type has the following interface:
export interface TextDocumentPositionParams {
/**
* The text document.
*/
textDocument: TextDocumentIdentifier;
/**
* The position inside the text document.
*/
position: Position;
}
It has the cursor position and a TextDocumentIdentifier but the last only has a uri property.
I want to create an intelligent autocomplete system, based on the type of the object of the word in the cursor position.
This sample is very limited and I'm kinda lost here. I guess I could read the file in the uri property and based on the cursor position I could figure out which items I should suggest. But how about when the file is not saved? If I read the file I would read the data that is on disk, and not what is currently shown in the editor.
What's the best approach to do that?
The Language Server Protocol supports text synchronization, see TextDocumentSyncOptions in ServerCapabilities and the corresponding methods (textDocument/didChange, didChange, didClose...). A Language Server will usually keep a copy of all open documents in memory.
The sample you linked actually makes use of this, but the synchronization itself is abstracted away into the TextDocuments class from vscode-languageserver. As a result server.ts doesn't have to do much more than this:
let documents: TextDocuments = new TextDocuments();
[...]
documents.listen(connection);
You can then simply use documents.get(uri).getText() to obtain the text shown in the editor.
I am writing an extension for visual studio code where I want to evaluate the current variables of a javascript debug session. These variables are normally shown when one have open the debug pane under the section VARIABLES. See the attached screenshot.
I want to get access to these variables when the user right clicks the editor, but I don't know how.
My current extension setting for this is like that: in the package.json I have registered a menu contribution along with a command:
"contributes": {
"menus": {
"editor/context": [{
"command": "extension.showVariables",
"group": "navigation"
}]
}
}
In my extension.ts I register the command like that:
export function activate(context: vscode.ExtensionContext) {
let disposable = vscode.commands.registerCommand('extension.showVariables', () => {
// TODO: let variables = vscode.debug.activeDebugSession.variables.toString();
vscode.window.showInformationMessage(variables);
});
}
I have tried to get them through vscode.debug.activeDebugSession but there is no API for variables here. I also tried to register an event handler for vscode.debug.onDidReceiveDebugSessionCustomEvent but I can't figure out where to search for the debug variables.
Is it even possible to access these variables in an vs extension or do I need to implement my own debugger?
I have managed to get access to the local variables although this is not a general solution - it may only work in a single threaded debugger. If you know any better way, please answer or comment.
Say, the debugger breaks in a method that has a local variable car.
To get the value of car, I am using the customRequest method on the active debug session:
const session = vscode.debug.activeDebugSession;
const response = await session.customRequest('evaluate', { expression: 'car', frameId: frameId });
const car = response.result;
To get the frameId, I use another call of customRequest:
const session = vscode.debug.activeDebugSession;
const response = await session.customRequest('stackTrace', { threadId: 1 })
const frameId = response.stackFrames[0].id;
To get a real car object (not a string representation) in my extension, I pass "JSON.stringify(car)" as expression in the evaluate customRequest. Then, I can use JSON.parse(response.result).
To get all scopes, stacks and variables, have a look at the
Debug Session API and the specification of the DebugProtocol.
You have to talk to the debug adapter using the debug adapter protocol directly using vscode.debug.activeDebugSession.customRequest(command: string, args?: any) (Ref)
This function receives 2 parameters: command and args. Check out this resource to find all possible values of those parameters. One example is the 'evaluate' command that Michael Hilus uses in his answer:
If you want to get the variables in a multi threaded debug session, you must do these requests in this order
Threads Request: Get the thread ids
StackTrace Request: Get the frame ids
Scopes Request: Get the variablesReference
Variables Request: Finally, get the variable names with their values. If a variable is an object you might want to use Variables Request again with the variablesReference of the variable with an object value.
PS: It's kind of hard to find what you want in the DAP specification, so here is a tip:
Go to the 'Types' section in the right menu and find what you want. For instance, Breakpoints.
Ctrl+F and search ': Breakpoint'
Take a look at all matches in the response section of each request.
In the case of variablesReference I had to search variablesReference: number to find it in the responses of Evaluate Request, Scope (type) and Variable (also type).