Visual Studio Code (VS Code) foi construído com extensibilidade em mente. Quase todas as partes do VS Code podem ser personalizadas e aprimoradas por meio da API de extensão . Na verdade, muitos recursos principais do VS Code são construídos como extensões , e você também pode construir o seu próprio, é claro!

A filosofia de desenvolvimento de produto do VS Code é que o editor é configurado para desenvolvimento web por padrão. Ele cobre HTML, CSS, JavaScript, TypeScript e Markdown. Esses recursos são gerenciados pela Microsoft e aceitam contribuições da comunidade. Tudo fora disso é deixado para a comunidade fornecer como extensões. As extensões podem ser disponibilizadas para outras pessoas publicando-as no VS Code Marketplace .

Agora, você deve estar se perguntando: como faço para escrever um, então? Devo apenas seguir os documentos oficiais ?

Você pode! Mas o VS Code é construído com electron , o que significa que você pode escrever uma extensão em JavaScript ou qualquer coisa que possa ser transpilada para JavaScript, como TypeScript. A base de código do VS Code é escrita em TypeScript, portanto, os documentos são orientados para TypeScript. Todos os exemplos de código fornecidos pela Microsoft são escritos em TypeScript. Portanto, se você não conhece o TypeScript, terá alguns problemas de velocidade ao longo do caminho.

Neste artigo, discutirei o seguinte:

  • Forneça informações suplementares para que os desenvolvedores de JavaScript criem extensões
  • Expanda alguns tópicos que considero negligenciados nos documentos oficiais
  • Discuta como configurar um projeto e escrever sua primeira extensão
  • Forneça exemplos para você experimentar por si mesmo

Tipos de extensões de código VS

Existem diferentes tipos de extensões que você pode escrever, e algumas nem requerem JavaScript. Em termos gerais, eles se enquadram nas seguintes categorias:

  • Snippets : uma coleção de snippets de código que se destinam a um determinado idioma ou estrutura. Os snippets são declarados em arquivos JSON. Nenhum JavaScript é necessário. Você pode ler o Guia de trechos para mais informações
  • Temas de cores : um tema de cores permite que você personalize as cores nos componentes da IU e o texto no editor. As cores são configuradas em arquivos JSON. Nenhum JavaScript é necessário . Você pode ler o artigo Criando um tema de código VS para mais informações
  • Pacotes de extensão : um pacote de extensão é uma coleção de extensões que podem ser instaladas como uma única extensão. Eles são úteis para criar uma coleção com curadoria para recomendar a outras pessoas e para facilitar a ativação/desativação de um conjunto relacionado de extensões para determinados projetos. Todo o trabalho é feito no package.json . Nenhum JavaScript é necessário . Você pode ler o artigo VSCode: como criar seu próprio pacote de extensão para obter mais informações
  • Pacotes de idiomas (localização) : um pacote de idiomas permite aos usuários alterar o idioma de exibição do VS Code. Eles consistem em um conjunto específico de arquivos JSON contendo os recursos de string localizados para diferentes partes da IU. Nenhum JavaScript é necessário
  • Outro : cobre tudo o mais que você gostaria de personalizar ou aprimorar no VS Code. É aqui que usamos JavaScript. Alguns exemplos do que você pode construir são:
    • Adicionando componentes e visualizações personalizados na IU
    • Suporte a uma nova linguagem de programação
    • Suporta depuração de um tempo de execução específico

Vamos nos concentrar na categoria “outros” neste artigo. A partir de agora, quando me refiro a extensões, esse é o tipo de extensão a que me refiro.

Primeiros passos

Você precisa ter uma configuração típica de ambiente JavaScript . Você precisa ter Node e um gerenciador de pacotes ( yarn ou NPM ) instalado.

Se você já tem, pode ler o Seu primeiro guia de extensão para configurar um novo projeto. O guia recomenda usar Yeoman para gerar um projeto padrão para você. Ele oferece uma experiência semelhante à de um assistente para criar o projeto na linha de comando. Para criar um projeto JavaScript, você seleciona a opção Nova extensão (JavaScript) .

Yo Code

Ele produzirá um projeto padrão com o comando “Hello World” e um conjunto de testes vazio.

Acho que é melhor criar nosso primeiro projeto do zero. Vou criar uma versão mais enxuta do projeto padrão. Isso deve ajudá-lo a ter uma compreensão mais clara do código com menos distrações.

Escrevendo sua primeira extensão

Vamos criar o exemplo “Hello World” do zero. Queremos criar um comando Hello World que mostrará uma mensagem pop-up dizendo (rufar de tambores), “Hello World!”

Hello World

O manifesto de extensão ( package.json )

Como um projeto Node típico, usamos o NPM para lidar com a configuração e as dependências do nosso projeto. A configuração do projeto está contida em package.json . Isso é conhecido como Manifesto de extensão na documentação. Você pode ler este guia em package.json se você precisar de uma atualização.

Vamos criar nosso package.json . Sempre precisamos preencher pelo menos meia dúzia de campos, conforme abaixo.

 { "nome":"exemplo", "versão":"0.0.1", "motores": { "vscode":"^ 1.32.0" }, "main":"extension.js", "contribui": { "comandos": [ { "command":"example.helloWorld", "title":"Hello World" } ] }, "activationEvents": [ "onCommand: example.helloWorld" ]
}

Você precisa fornecer as propriedades nome , versão , engines e main como faria para um projeto Node típico. Criaremos um arquivo JavaScript na mesma pasta chamada extension.js para ser nosso módulo principal em um minuto.

As propriedades específicas de um código VS que devem ser declaradas são:

Queremos adicionar um novo comando à paleta de comandos. Especificamos isso na propriedade contributes.commands . Atribuímos um ID exclusivo na subpropriedade command . A convenção de nomenclatura que a Microsoft parece seguir é . , mas não há restrições. Este ID é referenciado no código para fornecer funcionalidade para o comando.

A subpropriedade title é o texto que aparece na paleta de comandos para o comando (como abaixo).

Hello World Command

Queremos apenas que a extensão esteja ativa quando o comando for executado, então usaremos o evento de ativação onCommand .

O manifesto da extensão está pronto.

Você pode ler a referência do Código VS do Manifesto de Extensão para obter mais informações sobre as propriedades.

Módulo principal

Vamos criar extension.js agora.

 const vscode=require ("vscode"); module.exports={ ativar, desativar,
}; função ativar (contexto) { //Isso deve corresponder à propriedade do comando no package.json const commandID="exemplo.helloWorld"; let disposable=vscode.commands.registerCommand (commandID, digaHello); context.subscriptions.push (descartável);
} function sayHello () { vscode.window.showInformationMessage ("Hello World!");
} function deactivate () {}

Você pode tratar seus arquivos da mesma forma que faria em um aplicativo Node.js típico. Cada arquivo é tratado como um módulo separado que segue a sintaxe do módulo commonJS .

Você precisa importar o módulo vscode para usar a API de extensibilidade do código VS. Ele está disponível por padrão.

Você deve sempre ter uma função activate em seu módulo principal . A função activate é executada quando um de seus eventos de ativação declarados acontece. É aqui que você configura as principais tarefas de inicialização da extensão. Vinculamos o comando declarado no package.json à nossa função sayHello por meio do commands.registerCommand .

Se você criar objetos e quiser que os recursos sejam liberados quando a extensão for descarregada (desativada), você pode adicioná-lo à matriz ExtensionContext.subscriptions . O Código VS refere-se a eles como descartáveis.

A função deactivate dá a você uma chance de limpar antes que sua extensão seja descarregada. Não precisamos fazer uma limpeza explícita com frequência-você pode omitir o método deactivate se for o caso. Se você precisar limpar algo de forma assíncrona, certifique-se de retornar um destino Promessa da função.

Executando a extensão

Execute a extensão iniciando uma sessão de depuração. Você pode pressionar F5 ou selecionar Run> Start Debugging no menu para iniciar a sessão. Isso irá compilar e executar a extensão em uma nova janela Host de desenvolvimento de extensão se houver uma configuração .vscode/launch.json no projeto.

Se não houver configuração, pode ser solicitado que você selecione um ambiente para a configuração se o VS Code detectar o tipo de projeto. Caso contrário, você pode ter que criar manualmente um launch.json .

Você pode clicar no botão Adicionar configuração para fornecer assistência ao preenchimento automático, selecionar Desenvolvimento de extensão de código VS como a opção e preencherá as propriedades.

Launch Config

Execute o comando Hello World da Paleta de comandos ( Ctrl + Shift + P ) e você verá uma mensagem pop-up dizendo “Hello World!”. Muito bem, você escreveu sua primeira extensão do VS Code!

Estrutura de projeto típica para extensões de código VS

Se você usou o Yeoman Generator para criar um projeto para você, crie a estrutura de pastas conforme descrito abaixo. Eu descrevo a função de cada arquivo:

.
├──.vscode
│ ├── launch.json//Config para iniciar e depurar a extensão. Isso é criado por padrão quando você executa o projeto.
├── README.md//Descrição de sua extensão. Isso é usado pelo VS Code Marketplace como o
├── extension.js//Código-fonte da extensão
├── teste
│ └── runTest.js//Código-fonte para executar seu conjunto de testes
│ └── suite
│ └── extension.test.js//Aqui é onde você escreve seus casos de teste
│ └── index.js//Configuração do Mocha e do conjunto de testes
├── package.json//manifesto de extensão

Uma coisa que eu mudaria é adicionar uma pasta src para colocar os arquivos JavaScript. Aqui, extension.js está na pasta raiz e isso pode ficar desorganizado rapidamente quando você constrói uma extensão mais substancial.

Familiarizando-se com a API

Leva algum tempo para se familiarizar com qualquer API. Cada API tem suas próprias convenções e idiossincrasias. Acho que alguma orientação e um bom conjunto de exemplos ajudam muito a fornecer um caminho de aprendizagem feliz.

Não achei a API do VS Code intuitiva de aprender. As descrições das funções são curtas e carecem de contexto em algumas áreas. Eu me peguei olhando exemplos e o código-fonte de extensões publicadas e, em seguida, voltando para a API para realizar tarefas na ocasião.

O que eu gostaria de ter à minha disposição inicialmente é uma visão geral da arquitetura e uma maneira de aprender o vocabulário da API. Esse tipo de orientação é vital para ser produtivo rapidamente. Vamos cobrir a arquitetura primeiro.

Visão geral da arquitetura da API

A captura de tela abaixo descreve como são chamados os principais componentes da interface do usuário do aplicativo. Eles são a Barra de atividades , a barra lateral , Editor, Painel e o Status Bar .

Visão geral do código VS

Achei a terminologia da documentação um pouco incoerente sobre os componentes da IU além disso.

Você pode considerar referências a visualizações para significar um componente de IU personalizado e atômico. Uma visualização pode ser:

Uma visão é colocada dentro de um contêiner de visão. Uma visualização pode ser adicionada a um dos seguintes:

  • Contêiner de visualização do Explorer na barra de atividades
  • Contêiner de visualização do Source Control Management (SCM) na barra de atividades
  • Executar e depurar o contêiner de visualização na barra de atividades
  • Testar o contêiner de visualização na barra de atividades
  • Seu próprio contêiner de visualização

Você pode ver todas as visualizações disponíveis executando o comando Visualizar: Abrir Visualização .

Visualizações

Uma visualização é declarada com propriedade contributes.views no package.json .

Um contêiner de visualização pode ser adicionado à barra de atividades ou ao painel. É declarado em contributes.viewsContainers no package.json .

Abaixo está um exemplo que mostra um “Package Explorer” personalizado view container adicionado à barra de atividades, que tem duas views personalizadas.

Contêiner de visualizações personalizadas

Os outros componentes da IU que você gostaria de criar geralmente são feitos por meio de funções no window , por exemplo, itens da barra de status. Discutiremos isso na próxima seção.

Se desejar oferecer suporte a outra linguagem de programação, você pode ler o Visão geral das extensões de idioma que cobre a arquitetura por trás disso. Agora, a maioria das linguagens de programação tem extensões, então é improvável que você se aventure por esse caminho!

Visão geral dos namespaces

Vamos discutir os namespaces que você usará com mais frequência.

O namespace mais importante para os componentes da IU é janela . Refere-se à janela atual do aplicativo. Ele tem funções para acessar e manipular a maioria dos componentes da IU:

  • Para acessar alguns componentes da IU, há várias propriedades: activeTextEditor é o arquivo aberto que foi focado ou alterado mais recentemente e activeTerminal é o painel do terminal que tem foco ou mudou mais recentemente
  • Para criar um novo componente, ele possui funções createXXX como createTreeView (..) , createStatusBarItem (..) e createWebview (..)
  • Para mostrar notificações e diálogos, possui funções showXXX como showInformationMessage (..) , showQuickpick (..) e showInputBox (..) . Uma exceção a esse padrão é para notificações de progresso, que são criadas com a função withProgress(..)
  • Para informações contextuais dentro de um documento, existem funções registerXXX como registerCodeLensProvider (..) para lentes de código e registerHoverProvider para dicas de ferramentas

Você pode preencher o conteúdo de uma visualização com:

O namespace para manipular o projeto aberto no explorador de arquivos é espaço de trabalho . Você pode executar ações nos arquivos e responder a eventos do sistema de arquivos.

Para editar um documento, os namespaces são TextEditor and TextDocument . The text content is available through the TextEditor.document property. TextDocument allows you retrieve text through ranges and lines in TextEditor.

The commands namespace deals with commands, which are the units of functionality you can reference. Commands can be added to the editor using the registerCommand and registerTextEditorCommand functions. Commands can be executed in the UI through the command palette, menus, and other contribution points. You can also programmatically execute commands.

The namespace for all global, user, and workspace settings is WorkspaceConfiguration.

The ExtensionContext namespace provides contextual properties for your extension, such as the global filepath, some logging info, and storage of secrets. An instance of an ExtensionContext is provided as the first parameter to the activate function.

The docs lists a few common API patterns also.

Interpreting the API without TypeScript knowledge

In TypeScript, you provide types for variables, and define your own types. When you write JavaScript, you don’t need to have any types, so I guess we can just ignore the types in the API right?

No — you still need to understand what values you need to provide for parameters and as return values. You need to meet the expectations of the API. You still need to know if you should provide a number or a string. The difference is that you do not need to assign types explicitly along the way.

Let’s look at a few examples to clarify how this plays out in reality.

Handling enumerations

Let’s add an item to the status bar, as below. The code for this can be found here.

Status Bar Item

From our namespace overview, we know that window.createStatusBarItem(..) is the function we are interested in. The function definition is below.

Create Status Bar Item

The first parameter is named alignment and has a type of StatusBarAlignment. So what value do we provide for that?

Looking at the definition, we see it is an enumeration.

Status Bar Alignment

An enumeration defines a fixed list of values. The native value of the enumeration is a number. So, if we want our status bar item aligned left: we can provide a value of 1 or vscode.StatusBarAlignment.Left for this parameter. The latter is more readable.

The second parameter is a number. Simply provide a number of your choosing.

let item=vscode.window.createStatusBarItem( vscode.StatusBarAlignment.Left, 1
); item.text=`$(megaphone) 0 line(s) selected`;
item.show();

We can then consult the StatusBarItem definition to understand how to add a label and display the item. The code above is sufficient to display a status bar item.

How to handle objects and callbacks

Let’s create a progress notification, as below. The code for this can be found here.

Progress

From our namespace overview, we know that window.withProgress(..) is the function we are interested in. The function definition is below.

With Progress

This definition is more complicated, but don’t be intimidated.

The first parameter, options, is a type of ProgressOptions. You need to check the definition and create an object literal for it.

Progress Options

The properties cancellable and title are primitive types. The location property is an enumeration again.

let progressOptions={ cancellable: true, location: vscode.ProgressLocation.Notification, title:"I am long running!",
};

The second parameter is a callback with its own set of parameters. Here, I create an anonymous function with the two parameters I am interested in using. The progress parameter is what we use to report the status of our task.

The return type of this function is Thenable, which is VS Code’s type for a promise. We create some timeouts to simulate a running task and resolve a promise when we are done. We return this promise from the function to satisfy the asynchronous behavior expected.

vscode.window.withProgress(progressOptions, (progress, token)=> { token.onCancellationRequested(()=> { console.log("User canceled the long running operation"); }); progress.report({ increment: 0 }); setTimeout(()=> { progress.report({ increment: 50, message:"Half way done!", }); }, 2000); const p=new Promise((resolve)=> { setTimeout(()=> { resolve(); }, 4000); }); return p; });
}

Examples of VS Code extensions in JavaScript

I gathered a collection of example, which can be found in the GitHub repo.

Testing extensions

You should test your extensions the same as any JavaScript code.

The Yeoman Generator creates a boilerplate test suite for you using the Mocha test framework. You can use whatever testing framework you want. If you are happy with Mocha, the testing extensions guide covers the basics.

Note that if you try to run tests from the command-line, it will throw an error:

Running extension tests from the command line is currently only supported if no other instance of Code is running.

This is a limitation of running potentially different versions of VS Code concurrently. The solution is to use VS Code Insiders for development where you can run tests from the command-line. Or you can launch the extension tests from the debug launch config (as below).

Testing

Publishing extensions

If you want to share your extension with others, you can publish it to the VS Code Extension Marketplace. Alternatively, you can package an extension into the installable VSIX format, and distribute it yourself. You can read the publishing extension guide for the rundown on this.

Conclusion

Writing your own VS Code extension can be a fun and rewarding project. It can be incredibly satisfying to build something that you use every day to assist your workflow. It does require some time and effort to get to grips with the development environment and learn how to use the API effectively. If you have experience with Node already, it is not much of a stretch.

The key takeaway is that knowing TypeScript is not a prerequisite — anyone with some JavaScript knowledge should be able to build their own extension without headaches. I hope that this article is able to provide a smooth learning path for building extensions with plain ‘ole JavaScript.

The post Writing VS Code extensions in JavaScript appeared first on LogRocket Blog.

Source link