TL;DR: uma nova proposta de design para o Language Server Protocol (LSP) cria um fluxo padronizado em que o gopls pode pedir informações ao desenvolvedor, validar as respostas e só então executar uma refatoração. Isso abre caminho para operações como mover declarações entre arquivos, alterar assinaturas e configurar tags de structs com uma interface consistente entre editores. A recomendação usa command/resolve, evita bloquear o servidor enquanto o usuário responde e já foi validada em versões do gopls e da extensão Go para VS Code.

O limite das refatorações atuais

O LSP permite que editores como VS Code, Vim e Emacs usem um servidor de linguagem para oferecer navegação, diagnósticos e transformações de código. Em Go, esse servidor é o gopls. O protocolo funciona bem quando uma ação pode ser calculada imediatamente: organizar imports, extrair uma variável ou aplicar uma correção sugerida.

O problema aparece quando a transformação precisa fazer perguntas. Para mover uma declaração, o servidor precisa saber o arquivo ou pacote de destino. Para alterar a assinatura de uma função, precisa coletar novos parâmetros. Para adicionar tags a uma struct, pode ser necessário escolher nomes, convenções de caixa e quais tags gerar.

Hoje, cada extensão pode criar uma interface própria para isso, mas a solução fica acoplada ao editor. A proposta tenta colocar o fluxo no LSP: o servidor preserva a inteligência da operação, enquanto o cliente decide se mostra um formulário, menus ou perguntas sequenciais.

Como funciona o ciclo interativo

A ideia central é um formulário sem estado, parecido com uma submissão HTTP. O servidor retorna campos em formFields; o editor coleta respostas e as devolve em formAnswers. O servidor pode aceitar, apontar um erro ou fazer uma nova rodada de perguntas.

Uma versão simplificada do intercâmbio para adicionar tags seria:

command: gopls.modify_tags
formFields:
  - id: tags
    tipo: string
    obrigatório: sim
  - id: case
    tipo: enum
    opções: [snake_case, camelCase]

Se o usuário fornecer uma tag inválida, o gopls devolve o formulário com uma mensagem associada ao campo. Quando não houver mais formFields, o comando está pronto para execução.

Os tipos previstos cobrem texto, booleanos, números, arquivos, listas e enums. Há ainda um lazyEnum, útil para conjuntos grandes ou dinâmicos: em vez de mandar milhares de símbolos ou caminhos de uma vez, o editor consulta opções conforme o usuário digita.

Ser sem estado é uma escolha importante. O servidor não precisa manter uma chamada RPC aberta, uma thread bloqueada ou um snapshot pesado do workspace enquanto alguém pensa no que responder. As respostas completas acompanham cada rodada; portanto, o fluxo também pode sobreviver a uma reinicialização do servidor de linguagem.

Por que command/resolve foi recomendado

O documento analisa quatro pontos possíveis para inserir a interação. A recomendação é resolver um comando antes de executá-lo, por meio de command/resolve — ou, futuramente, de um padrão mais geral <método>/resolve.

Esse nível traz três vantagens práticas:

  1. A interação só começa após uma ação explícita. Alguns clientes resolvem ações antecipadamente para mostrar previews ao passar o mouse. Perguntar algo nessa etapa produziria diálogos inesperados.
  2. O mecanismo não fica limitado a edições de texto. Um comando interativo também pode iniciar testes com opções de cobertura, executar govulncheck, abrir relatórios ou controlar ferramentas de linha de comando.
  3. Não há uma requisição reversa bloqueada. Pedir dados do servidor para o editor durante um comando manteria recursos presos e poderia ultrapassar timeouts de clientes, que às vezes são de poucos segundos.

A desvantagem é que ações interativas precisam ser representadas como comandos. Elas não podem ser apenas um WorkspaceEdit pronto para o editor aplicar. Para refatorações cujo resultado depende das respostas, porém, um preview calculado antes da interação seria pouco confiável de qualquer maneira.

O que muda para quem programa em Go

A proposta não significa que todos os editores ganharão imediatamente botões para “mover declaração” ou “alterar assinatura”. Ela define a infraestrutura para que clientes LSP implementem uma experiência interoperável. Servidor e cliente também negociam capacidades, incluindo quais tipos de entrada o editor consegue renderizar.

Há um sinal concreto de maturidade: o caminho recomendado foi testado em produção com gopls v0.23.0 e VS Code Go v0.56.0, inicialmente no fluxo de modificação de tags. Isso reduz o risco de o design ser apenas teórico, embora sua padronização e adoção mais ampla ainda dependam do ecossistema LSP.

Para equipes Go, o benefício potencial é diminuir refatorações manuais e específicas de IDE. Operações que exigem conhecimento semântico do workspace podem continuar no gopls, aproveitando análise de tipos e referências, enquanto cada editor oferece a interface adequada. Isso complementa recursos como o inliner em nível de código-fonte, já usado por refatorações e pelo go fix.

O efeito mais interessante é arquitetural: uma refatoração complexa deixa de ser uma feature exclusiva de uma IDE e passa a poder ser um recurso do servidor oficial de Go, consumido por qualquer cliente que implemente o protocolo.

Saiba mais