microsoft / vscode

Visual Studio Code

Home Page:https://code.visualstudio.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Expose 'change language' as command

ctlajoie opened this issue · comments

I have a modelines plugin but it currently lacks the ability to set the language of the file. In order to implement this I would need an API to allow it to be set.

As an example, a Vagrantfile is a ruby script, but Code opens it as plain text. The API should allow plugins to determine the type of file by arbitrary means and set the language appropriately.

there should be a command that allows to change the mine, like from the status bar.

@jrieken Are you saying there is already a way to do it by sending a command?

yes and no. there is command but I believe it won't work the way it should.

It should be like vscode.editor.changeLanguage with uri, languageid or so. basically whatever gets executed when a selection in language picker is made

I think this action does not exist the way wanted, it just opens the mode picker. Having a way to change the mode on a opened document is maybe something that should be exposed as API?

we cannot make it a setting because by the logic of the document API and synching it will remove that document and create a new one. like calling document.languageId = 'foo' will make it disappear.

Any update on this issue? I just started using vscode after many years on sublime and the lack of modeline support is hugely annoying...enough to switch back.

Also, this issue ought to be merged with:

#1651 Detect Language Mode from Modeline Comment

@markeissler This is about adding API to allow extensions to change the mode. I believe you are looking for a user interaction, right? There is the mode switcher at the bottom of the editor

No, this is exactly about the API. It's standard practice to use vi/vim/emacs modeline indicators in header comments of a file so that an editor can override whatever it's best "guess" is to select the correct language. Usually, the guess is based on the file extension but it has become common for certain files not to carry a filename extension (the OP started this thread with the example of a Vagrantfile, which is actually a ruby file but without an extension). I'm facing the same issue with large shell utilities whose library files don't tend to carry an extension. It's a huge drag to have to manually select the correct language each time I open a file...especially when you are working on a project with dozens of extension-less files.

Sublime Text, for example, has a couple of plugins that implement this functionality (reading the first X number of lines of a file in search of a modeline, if it exists select the language from the modeline, otherwise try and use the file extension, otherwise fall back to plain text). The OP (@ctlajoie) created such a plugin for vscode but is unable to implement language selection because of the lack of support by the vscode API.

Any update on this issue ?

writing my first extension and have spent the past 12 hours trying to figure out a work around for this. Need this ability desperately.., I don't want to use the previewHtml.

created a textdocumentcontentprovider, the contents of which are JSON and I'd like to set the languageId to json so the user doesn't have to do it manually..

I need this as well for some extensions I'm working with

I'd like this to work with .asp files that are all JScript, so that when I switch to an include file that is pure JScript I can quickly press a chord and get javascript syntax while still tabbing over to mixed files. This is exactly what was brought up in #21826.

Example keybindings.json (which I just tried to make and use but failed 😢)

{
  "key": "ctrl+alt+shift+j",
  "command": "workbench.action.editor.changeLanguageMode",
  "args": { "langauge": "javascript" }
}

Thanks for reading!

This could be a solution to #670 for php. Could hook into the selection changed event when in and out of php tags to automatically toggle active language.

Would love to see this added either as an arg we can pass or as a separate command.

I need this feature to support multiple delimiters in rainbow_csv extension. For my use case it is critical, that it would be possible to set language by relative path to the corresponding "tmLanguage" file (e.g.
document.set_syntax("relative/path/to/syntax_file.tmLanguage.json") , which I would like to hide from the VSCode, otherwise these pseudo-languages would pollute language selection menu as there could be as many as 100 different "languages" - syntaxes. So setting language by "language_id" is not an option in my case, because the languages should be hidden from the editor.

It's insane that this still isn't supported. I would expect any remotely mature IDE to at least enable an extension to set the language mode of a file. I'm having to manually select the language on almost every file I'm working with right now even though they all have modelines which is beyond frustrating. Is there some significant technical challenge to providing a language mode API?

Can anyone from the vscode team give us an idea of what priority level this feature request is to the team? (For me personally it will give me an idea as to whether to wait for this feature to come out in the next few months, or create a json viewer and use previewHtml which I'm trying to avoid)

I need this feature as well. I'm writing an extension to syntax-highlight C++ standard headers such as <vector> and <map>, which do not have .h file extension. My extension scans some number of lines from top of a file, and if it finds a include guard (a pair of #ifndef _FOO_H and #define _FOO_H) it sets the language mode to C++. But lack of "change language" API makes this impossible.

commented

@jrieken Will external contribution be considered for this feature? Wondering what the architectural ramifications of such a API would be, and whether any discussions have occurred regarding such ramifications.

Will external contribution be considered for this feature

You mean a PR? Then sure, go ahead.

If @johnwoolee doesn't make it, could we appeal #1651 getting locked? @lloeki was right: #1651 is only fixable with an extension if #1800 is fixed.

This would be very useful when writing unit tests for an extension (as I am now). I believe currently the only approach must be to open a file in the editor of the appropriate type so that the correct language can be selected for the unit test.

I've just submitted a PR and the code doesn't look very complex. Maybe I am missing something?
And please disregard my previous comment here about language hiding.

Thanks @mechatroner! I have left some PR comments - target is to ship this in August as we are finishing the July release atm (and since I'll be out for the next week 🚵)

Sure, there is no need to hurry!
I was also thinking that in the future we might need another similar API function: boolean SuggestLanguageChange(uri, languageId).

So basically there are two different ways of how an extension can change a language using a language change function:

  1. Automatically, without user involvement (most likely as a result of some auto-detection logic). In this case well-behaving extensions should use SuggestLanguageChange, which would fail if user has already manually picked language for the file or if some other extension already assigned another language to it.
  2. Manually, in response to some user action. I.e. some UI switch or command (user understands that his action will result in language switch). In this case extensions should use simple void ChangeLanguageById(uri, language_id). Additionally this language can be remembered for future sessions (once #17115 is implemented).

The logic is there. Kudus to @mechatroner 👏. Next month we will finalise the API so that it will be generally available.

Is there a way to get an extension id from a filename string, say 'file.js'?

@alexandrudima Thinking about the API for this and I wonder why we decided that changing a mode is expressed as a close/open-event-sequence. See https://github.com/Microsoft/vscode/blob/a69c03e4ca08f58b67ed4b91eaa57e2db44592e6/src/vs/workbench/api/node/extHostDocuments.ts#L103
Seems like we have done since day one but I don't remember why? Us just being pragmatic or not? My idea is that we could simply make TextDocument#languageId writable (like editor selections et al) instead of adding a separate function like changeLanguage

Ok, one advantage of sending a close/open-sequence is that validation participants have an easy way to 'follow' documents of a certain language

Current finalisation proposal

/**
 * Set (and change) the [language](#TextDocument.languageId) that is associated
 * with the given document.
 *
 * *Note* that calling this function will trigger the [`onDidCloseTextDocument`](#languages.onDidCloseTextDocument) event
 * followed by the [`onDidOpenTextDocument`](#languages.onDidOpenTextDocument) event.
 *
 * @param document The document which language is to be changed
 * @param languageId The new language identifier.
 * @returns A thenable that resolves with the updated document.
 */
export function setTextDocumentLanguage(document: TextDocument, languageId: string): Thenable<TextDocument>;

This is API now

How do you use this? is there documentation for it?

@bbrendon you can take a look at "Rainbow CSV" or "vscode-modelines" source code for usage examples.