Get notification in a VS Code extension when the Python interpreter is changed - visual-studio-code

I am writing a VS Code extension that depends on the currently set Python interpreter. When I change the Python Interpreter via the VS Code UI, the extension needs to refresh and get the latest Python path (mainly to show the right environment settings in the TreeView). For now, I have a refresh button in my custom TreeView that I need to press after selecting a different Python interpreter.
However, this is a second manual step. Is there a way to get a notification in my extension, when a user changes the Python Interpreter, e.g., an event the extension can listen to?
I only found VS Code's Activation Events, but it doesn't look like this would help. I didn't find any other events that get triggered after the command python.setInterpreter is executed

Finally found it. The right config to watch for is python.defaultInterpreterPath
vscode.workspace.onDidChangeConfiguration(event => {
let affected = event.affectsConfiguration("python.defaultInterpreterPath");
if (affected) {
doSomething();
}
});
To support the usingNewInterpreterStorage case (default today), add:
const extension = vscode.extensions.getExtension('ms-python.python')!;
await extension.activate();
extension.exports.settings.onDidChangeExecutionDetails((event: any) => {
doSomething();
});

Related

Error handling in extensions to visual studio code

Can someone point me to best practices for error handling in a Visual Studio Code extension?
I'm writing an extension in TypeScript that contributes a debugger. I want to log unexpected behavior, sometimes as information to the user explaining that something didn't go right, sometimes to create a trail for debugging, but certainly not to fail silently. Using console.log or console.error shows up in the debug output when I am debugging the extension, but I can't find it when the extension is installed. Do I have to open an output channel specifically for my extension and write everything there? Should I be throwing up showInformationMessage and showErrorMessage windows? Should I just be throwing exceptions and hope that code will do the right thing?
In my extension I use two ways for feedback. One is an output channel for errors produced by an external process that I'm using for the work.
Create the channel in your activation method:
outputChannel = window.createOutputChannel("ANTLR4 Errors");
and push output to it whenever you have something:
} catch (reason) {
outputChannel.appendLine("Cannot parse sentence generation config file:");
outputChannel.appendLine((reason as SyntaxError).message);
outputChannel.show(true);
return;
}
The other one is what you already considered:
if (workspace.getConfiguration("antlr4.generation").mode === "none") {
void window.showErrorMessage("Interpreter data generation is disabled in the preferences (see " +
"'antlr4.generation'). Set this at least to 'internal' to enable debugging.");
return null;
}
which is for messages I create in the extension and that users need to see and take seriously.

How to trigger activation of the vscode markdown extension

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.

Go to definition, go to implementation, autogenerate import for Ember

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

IPython/Jupyter Installing Extensions

I'm having troubles installing extensions in IPython. The problem is that i can't get the extensions load automatically, i have followed the instructions in the github page but it just doesn't work. According the the homepage i need to modify the custom.js file by adding some lines. I want to install the codefolding, hide_input_all and runtools extensions. This is how my custom.js file looks:
// activate extensions only after Notebook is initialized
require(["base/js/events"], function (events) {
$([IPython.events]).on("app_initialized.NotebookApp", function () {
/* load your extension here */
IPython.load_extensions('usability/codefolding/codefolding')
IPython.load_extensions('usability/runtools/runtools')
require(['/static/custom/hide_input_all.js'])
});
});
The extensions work well if i call them manually, for example, if i type
%%javascript
IPython.load_extensions('usability/runtools/runtools/main');
the runtools appear and works perfectly, but i want the extensions to be loaded automatically and not to have to call them manually every time. Could someone tell me where is my mistake?
There's been a little change to the syntax. Nowadays, $ might not be defined by the time your custom.js loads, so instead of something like
$([IPython.events]).on("app_initialized.NotebookApp", function () {
IPython.load_extensions("whatever");
});
you should do something like
require(['base/js/namespace', 'base/js/events'], function(IPython, events) {
events.on('app_initialized.NotebookApp', function(){
IPython.load_extensions("whatever");
})
});
with the appropriate changes to braces and parentheses. For me, the former will work more often than not, but certainly not always; it fails maybe ~1/3 of the time.
If that doesn't do it for you, open up Developer Tools (or whatever is relevant for your browser) and look at the javascript console for errors. That'll help figure out what's going wrong.

Turn off auto-closing parentheses in ipython

I stay up-to-date with ipython's dev branch (because ipython is pretty much the most awesome thing ever). Fairly recently (before yesterday's awesome ipython 2.0 release) I noticed that it has started to automatically close parentheses, brackets, quotes, etc., as I type them. It happens in both terminal [nothing else I use in terminal does it] and notebook sessions, so I assume it was an intentional choice on the part of the developers. I can respect that other people might like this feature, but it drives me completely nuts.
I can't find any option for it in the configuration files. I can't even google for it, because I don't know what it's called. The only thing that comes up is the different feature of automatic parentheses. I did actually find this question, but that's old, and suggests that the behavior I'm seeing can't happen.
How can I turn this feature off?
[I mostly just use the notebook interface anyway, so just turning it off there would be fine, but I'd prefer to turn it off in both notebooks and ipython sessions at the terminal.]
#minrk's answer is the meat and bones of the fix, but you'll need to wrap it in an initialization callback, at least with IPython-3.1.0. In your custom.js:
require(['base/js/namespace', 'base/js/events'], function(IPython, events) {
events.on('app_initialized.NotebookApp', function() {
IPython.CodeCell.options_default.cm_config.autoCloseBrackets = false;
});
});
Thanks #Mike for your comment about IPython's RequireJS dependency loading and the pointer to a better formulation at IPython/Jupyter Installing Extensions.
Edit for Jupyter 4.0.x:
The current IPython notebook implementation, Jupyter 4.0.0, revamped JS customizations. It now uses ~/.jupyter/custom/custom.js by default, and you'll need to replace that whole require(... events.on(...)) snippet with just the following in global scope:
IPython.CodeCell.options_default.cm_config.autoCloseBrackets = false;
Likewise, if you want to use jQuery to manipulate anything, just use the jQuery global directly. For example, I like to hide the fixed header by default, which gives me another 40px of space for my code, which I find a bit more valuable than looking at the Jupyter logo all the time:
jQuery('#header-container').hide();
Edit for Jupyter ≥ 4.0.6 (but < Jupyter Lab):
If the custom.js solution above doesn't work, try adding the following to your ~/.jupyter/nbconfig/notebook.json:
{
"CodeCell": {
"cm_config": {
"autoCloseBrackets": false
}
}
}
The notebook behavior is the result of the CodeMirror autoCloseBrackets plugin. You can turn this off by editing (create it with ipython profile create if you haven't already) ~/.ipython/profile_default/static/custom/custom.js and adding:
if (IPython.CodeCell) {
IPython.CodeCell.options_default.cm_config.autoCloseBrackets = false;
}
As for the terminal, I don't see the parenthesis behavior you describe. Do you perhaps have a PYTHONSTARTUP defined? IPython executes this file by default, which you can disable by adding to ~/.ipython/profile_default/ipython_config.py:
c.InteractiveShellApp.exec_PYTHONSTARTUP = False
If you want to do it just from python:
from notebook.services.config import ConfigManager
c = ConfigManager()
c.update('notebook', {"CodeCell": {"cm_config": {"autoCloseBrackets": False}}})
This is what works for me in Jupyter 4.0.6:
require(['notebook/js/codecell'], function (codecell) {
codecell.CodeCell.options_default.cm_config.autoCloseBrackets = false;
})
in ~/.jupyter/custom/custom.js.
BTW, If you additionally want to switch off the syntax higlighting of matching parentheses:
codecell.CodeCell.options_default.cm_config.matchBrackets = false;
In the JupyterLab Notebook you can turn off the autoClosingBrackets plugin in the settings menu. Go to Settings --> Advanced Settings Editor and add the following in the User Overrides section:
{
"codeCellConfig": {
"autoClosingBrackets": false
}
}
Screenshot
This worked with JupyterLab 0.32.1 and jupyter_core 4.4.0
The above suggestions didn't worked for me in Jupyter 4.3.0 with Jupyter Notebook 5.0.0
I found that I needed to create a file called ~/.jupyter/custom/custom.js with the following contents:
var cell = Jupyter.notebook.get_selected_cell();
var patch = {
CodeCell: {
cm_config: {
autoCloseBrackets: false,
}
}
}
cell.config.update(patch);
Note that the directory ~/.juypter/custom didn't exist before I did this.
This was hacked together from suggestions in v5.0 docs, and for future readers these are the latest
For Jupyter Notebook 5.1 use the same thing as for 4.2, i.e. put the following snippet into ~/.jupyter/custom/custom.js:
require(['notebook/js/codecell'], function (codecell) {
codecell.CodeCell.options_default.cm_config.autoCloseBrackets = false;
})
I found it was not mentioned in other answers. In my case(OS X, Jupyter 4.2.0), custom.js is located in
~/anaconda/lib/python3.5/site-packages/notebook/static/custom/custom.js
I think it may help somebody like me.
We can do that from jupyter console, try it.