{"article":{"slug":"interactive-refactoring-in-gopls","title":"Interactive refactoring in gopls","subtitle":null,"summary":"The Go team introduces interactive refactoring in gopls, built on a new Language Server Protocol capability designed with the Dart team as an open standard, which lets refactorings run as dynamic multi-step dialogs inside any editor. The post explains the LSP background, walks through example refactorings, and outlines what comes next and how to give feedback.","content_type":"announcement","language":"en","canonical_url":"https://go.dev/blog/interactive-refactoring","author":{"name":"Hongxiang Jiang","url":null,"person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"The Go Blog","url":"https://go.dev/blog/","listing_slug":null,"listing":null},"topics":[{"name":"Programming Languages","slug":"programming-languages","url":"https://listedarticles.com/topics/programming-languages"},{"name":"Developer Tools","slug":"developer-tools","url":"https://listedarticles.com/topics/developer-tools"},{"name":"Programming","slug":"programming","url":"https://listedarticles.com/topics/programming"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":1468,"reading_minutes":6,"published_at":"2026-10-16T00:00:00.000Z","added_at":"2026-10-17T02:19:11.475Z","updated_at":"2026-10-17T02:19:11.475Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/interactive-refactoring-in-gopls","markdown_url":"https://listedarticles.com/articles/interactive-refactoring-in-gopls.md","example":false,"citation":"Hongxiang Jiang, The Go Blog. \"Interactive refactoring in gopls.\" 16 Oct 2026. https://go.dev/blog/interactive-refactoring (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://go.dev/blog/interactive-refactoring"},"body_markdown":"# Interactive refactoring in gopls\n\nHongxiang Jiang\n16 October 2026\n\nWhen editing code in a modern IDE or editor, developers rely on its refactoring\nfeatures to automate common transformations. Today, we are excited to introduce\n**interactive refactoring** in [gopls](https://go.dev/gopls), powered by a new capability we are\nproposing for the [Language Server Protocol (LSP)](https://microsoft.github.io/language-server-protocol/)\nthat brings dynamic, multi-step dialogs directly into your favorite editor.\nCrucially, we designed this capability (in collaboration with the Dart team)\nnot just for Go, but as an open standard for all programming languages and\neditor ecosystems. Working support is already available in gopls [v0.24.0](https://go.dev/gopls/release/v0.24.0) and\nthe official Go extension for VS Code v0.56.0.\n\n### What is the Language Server Protocol (LSP)?\n\nThe LSP is an open standard that decouples language-specific\nfeatures from specific text editors. As you navigate and edit code, your\neditor (such as VS Code, Neovim, or Emacs) and a language server (like gopls)\nengage in a continuous JSON-RPC exchange to provide features like autocomplete,\nhover documentation, diagnostics, and code actions.\n\n### Multi-step code transformation\n\nToday, almost every code transformation in the LSP is like a function of no\nparameters: you trigger the operation, and the server immediately computes the\nedits. (Renaming a symbol is the sole exception: because it is a function of one\nparameter, the desired new name, it required its own dedicated `PrepareRename`\nRPC in the protocol.)\n\n*\"Add struct tags\", without questions*\n\nThe language server must deduce the user’s intent from context alone, namely\nthe cursor position and the enclosing syntax tree. When that context is not\nenough, the server is forced into one of two choices: apply a one-size-fits-all\ndefault, or refrain from offering the transformation altogether. The limitation\nlies not in gopls’s ability to compute the necessary edits, but in the\nLSP’s lack of a mechanism for language servers to ask the user for input.\n\nFor many transformations, this parameterless model works well. But many others\nneed additional input from the user: which struct tags to add and in what\nnaming convention, which interface to implement, which file to move a\ndeclaration to. Without a way to ask, gopls could only guess—“Add struct\ntags”, for example, always produced `json` tags in `camelCase`—or not offer the\nrefactoring at all. With interactive refactoring, language servers can now\neasily provide new operations with one or more parameters.\n\n*\"Add struct tags\", with questions*\n\nWhile some language extensions have worked around this limitation by embedding\ncustom, language-specific dialog logic directly into individual editors, doing\nso leaves behind other editors (such as Neovim and Emacs) that stick strictly\nto the LSP with minimal custom client code. More importantly, editor-specific\nworkarounds go against the fundamental purpose of the LSP: to decouple\nlanguage-specific features from editors so that each server improvement benefits\nevery client.\n\nOur [LSP interactive refactoring proposal](https://go.googlesource.com/proposal/+/refs/heads/master/design/76331-lsp-interactive-refactoring.md)\n([microsoft/language-server-protocol#1164](https://github.com/microsoft/language-server-protocol/issues/1164))\nsolves this by establishing a standard mechanism for\nlanguage servers to collect user input before computing text edits. For Go\ndevelopers, this unlocks a suite of long-awaited refactorings, including:\n\n- [golang/go#70583](https://go.dev/issue/70583): Move Declaration\n- [golang/go#38028](https://go.dev/issue/38028): Change Signature\n- [golang/vscode-go#1547](https://github.com/golang/vscode-go/issues/1547): Implement Interface\n- [golang/vscode-go#2002](https://github.com/golang/vscode-go/issues/2002): Modify Struct Tags\n\namong many others.\n\n## Interactive refactorings in action\n\n**Adding and removing struct tags (gopls v0.23.0)**\n\nWhen configuring serialization formats, developers frequently need custom tags\nand casing conventions. Previously, running “Add struct tags” unconditionally\ninjected `json` tags using `camelCase` formatting.\n\nWith interactive refactoring:\n\n1. Place your cursor on any struct definition and select the\n   **“Add struct tags”** code action.\n2. An input dialog appears, pre-filled with `json`, allowing you to customize\n   any combination of tags (such as `json,yaml,db`).\n3. A second dialog lets you select your desired naming convention (such as\n   `camelCase`, `snake_case`, or `PascalCase`).\n4. Gopls generates and applies the formatted struct tags across your type\n   definition.\n\n*Interactive \"Add struct tags\" in VS Code*\n\nHere is the before-and-after transformation:\n\n```\ntype UserProfile struct {\n    ID        int64\n    FirstName string\n    LastName  string\n    EmailAddr string\n}\n```\n\n```\ntype UserProfile struct {\n    ID        int64  `json:\"id\" db:\"id\"`\n    FirstName string `json:\"first_name\" db:\"first_name\"`\n    LastName  string `json:\"last_name\" db:\"last_name\"`\n    EmailAddr string `json:\"email_addr\" db:\"email_addr\"`\n}\n```\n\nSimilarly, **“Remove struct tags”** now asks you for the specific tag keys\nyou wish to delete (for example, removing only `db` tags while preserving the `json`\ntag), rather than wiping out all struct tags indiscriminately.\n\n*Interactive \"Remove struct tags\" in VS Code*\n\n**Implementing interfaces with dynamic symbol search**\n\nWhen creating a type to satisfy an interface, developers previously had to copy\nthe interface declaration and manually turn it into a set of methods on the\nreceiver type (or rely on external tools like `impl` by manually typing the\nreceiver and qualifying the name of the interface).\n\nSince gopls v0.23.0, with interactive refactoring:\n\n1. Place your cursor on any concrete type and select the\n   **“Add methods to X to implement an interface…”** code action.\n2. A text entry field appears, inviting you to choose the name of an interface\n   type. It makes dynamic queries to gopls to auto-complete names of types in\n   your workspace and the standard library (for example, `maphash.Hasher`).\n3. If the selected interface has type parameters, gopls asks for a\n   concrete type argument for each type parameter (such as `Foo`).\n4. Gopls generates complete method stubs with appropriate receiver names and\n   instantiated method signatures.\n\n*Interactive \"Add methods to implement an interface...\" in\nVS Code*\n\n```\ntype Foo struct{}\n\ntype MyHasher struct{}\n```\n\n```\ntype Foo struct{}\n\ntype MyHasher struct{}\n\n// Equal implements [maphash.Hasher].\nfunc (m *MyHasher) Equal(x Foo, y Foo) bool {\n    panic(\"unimplemented\")\n}\n\n// Hash implements [maphash.Hasher].\nfunc (m *MyHasher) Hash(*maphash.Hash, Foo) {\n    panic(\"unimplemented\")\n}\n```\n\n**Moving declarations across files and packages (preview)**\n\nMoving declarations manually by cutting and pasting can easily break references\nand requires tedious import cleanup across multiple files. While scheduled for\nan upcoming gopls release, our working implementation already demonstrates how\ninteractive file selection streamlines cross-file and cross-package moves:\n\n1. Place your cursor on any top-level declaration and select the\n   **“Move declaration X”** code action.\n2. A file picker dialog lets you choose an existing destination `.go` file or\n   specify a new file path.\n3. Gopls moves the declaration along with its dependent declarations (such as\n   unexported helpers or methods) while leaving unrelated symbols in place,\n   updates references across your workspace, and cleans up imports in both the\n   source and destination files.\n\n*Interactive \"Move declaration\" in VS Code*\n\nIn the example below, we move the type `Foo` from package `from` to package\n`to`. Its method `Print` and the unexported constant `bar`, which only `Foo`\nuses, move along with it, while the unrelated function `Baz` stays behind:\n\n```\n// from/from.go\npackage from\n\nimport (\n    \"fmt\"\n    \"strings\"\n)\n\nconst bar = \"bar\"\n\n// Doc comment for Foo\ntype Foo struct{}\n\nfunc (f Foo) Print() {\n    fmt.Println(bar)\n}\n\nfunc Baz() string {\n    return strings.ToUpper(\"baz\")\n}\n```\n\n```\n// from/from.go\npackage from\n\nimport \"strings\"\n\nfunc Baz() string {\n    return strings.ToUpper(\"baz\")\n}\n\n// to/to.go\npackage to\n\nimport \"fmt\"\n\nconst bar = \"bar\"\n\n// Doc comment for Foo\ntype Foo struct{}\n\nfunc (f Foo) Print() {\n    fmt.Println(bar)\n}\n```\n\n**Slaying the dragon (gopls v0.24.0)**\n\nAs a demonstration of multi-step interactive dialogs and a self-contained test\ncase for client editor implementations, gopls v0.24.0 offers a **“Slay the\ndragon”** code action when you place your cursor on a package-level variable\nnamed `dragonSlayer` (for example, `var dragonSlayer string`). Happy hunting!\n\n## What’s on the Horizon\n\nInteractive refactoring establishes a foundational capability in gopls,\nopening up several exciting directions on our roadmap:\n\n- **Change signature refactoring ([#38028](https://go.dev/issue/38028))**: Adding, removing,\n  or reordering function parameters across a workspace requires input that\n  cannot be deduced from syntax alone, such as the new parameter order or the\n  default argument expression to insert at existing call sites. Interactive\n  forms allow gopls to collect these details before rewriting the declaration\n  and all call sites.\n- **Interactive conflict resolution**: When a code transformation encounters\n  naming collisions, identifier shadowing, or ambiguous references, gopls can\n  ask the user for guidance, such as asking for permission to proceed or\n  offering to rename conflicting symbols on the fly.\n- **Interactive commands beyond code edits**: Because interactivity is modeled\n  at the LSP [command](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#command)\n  layer, it naturally generalizes to non-edit server\n  operations that require user configuration, such as configuring test or\n  benchmark runs with profiling flags (CPU, memory, tracing).\n\n## Getting Started and Sharing Feedback\n\nInteractive refactoring is available in gopls [v0.24.0](https://go.dev/gopls/release/v0.24.0)\nand `vscode-go` [v0.56.0](https://github.com/golang/vscode-go/releases/tag/v0.56.0)\n(with proof-of-concept client integrations also explored for\n[Neovim](https://github.com/h9jiang/neovim/tree/interactive-refactoring) and\n[Emacs](https://go-review.googlesource.com/c/tools/+/800220)).\n\nWe would love to hear your thoughts as we continue\nrefining interactive code actions in gopls:\n\n- For general feedback or feature requests, file an issue on the [Go issue tracker](https://go.dev/issue/new).\n- To read the full technical specification—including the stateless form\n  protocol design and alternative approaches we explored—or to join the\n  discussion with the broader LSP community, check out the\n  [LSP Interactive Code Actions design document](https://go.googlesource.com/proposal/+/refs/heads/master/design/76331-lsp-interactive-refactoring.md)\n  and the ongoing conversation in [microsoft/language-server-protocol#1164](https://github.com/microsoft/language-server-protocol/issues/1164).\n\n*(Special thanks to Alan Donovan, Alex Putman, Brian Wilkerson, Danny Tuppeny,\nHana Kim, Madeline Kalil, Peter Weinberger, and Robert Findley for their\ninsights, discussions, feedback, and collaboration on this work.)*\n\nHappy refactoring!\n","body_html":"<h1 id=\"interactive-refactoring-in-gopls\">Interactive refactoring in gopls</h1>\n<p>Hongxiang Jiang\n16 October 2026</p>\n<p>When editing code in a modern IDE or editor, developers rely on its refactoring\nfeatures to automate common transformations. Today, we are excited to introduce\n<strong>interactive refactoring</strong> in <a href=\"https://go.dev/gopls\" rel=\"nofollow ugc noopener\">gopls</a>, powered by a new capability we are\nproposing for the <a href=\"https://microsoft.github.io/language-server-protocol/\" rel=\"nofollow ugc noopener\">Language Server Protocol (LSP)</a>\nthat brings dynamic, multi-step dialogs directly into your favorite editor.\nCrucially, we designed this capability (in collaboration with the Dart team)\nnot just for Go, but as an open standard for all programming languages and\neditor ecosystems. Working support is already available in gopls <a href=\"https://go.dev/gopls/release/v0.24.0\" rel=\"nofollow ugc noopener\">v0.24.0</a> and\nthe official Go extension for VS Code v0.56.0.</p>\n<h3 id=\"what-is-the-language-server-protocol-lsp\">What is the Language Server Protocol (LSP)?</h3>\n<p>The LSP is an open standard that decouples language-specific\nfeatures from specific text editors. As you navigate and edit code, your\neditor (such as VS Code, Neovim, or Emacs) and a language server (like gopls)\nengage in a continuous JSON-RPC exchange to provide features like autocomplete,\nhover documentation, diagnostics, and code actions.</p>\n<h3 id=\"multi-step-code-transformation\">Multi-step code transformation</h3>\n<p>Today, almost every code transformation in the LSP is like a function of no\nparameters: you trigger the operation, and the server immediately computes the\nedits. (Renaming a symbol is the sole exception: because it is a function of one\nparameter, the desired new name, it required its own dedicated <code>PrepareRename</code>\nRPC in the protocol.)</p>\n<p><em>&quot;Add struct tags&quot;, without questions</em></p>\n<p>The language server must deduce the user’s intent from context alone, namely\nthe cursor position and the enclosing syntax tree. When that context is not\nenough, the server is forced into one of two choices: apply a one-size-fits-all\ndefault, or refrain from offering the transformation altogether. The limitation\nlies not in gopls’s ability to compute the necessary edits, but in the\nLSP’s lack of a mechanism for language servers to ask the user for input.</p>\n<p>For many transformations, this parameterless model works well. But many others\nneed additional input from the user: which struct tags to add and in what\nnaming convention, which interface to implement, which file to move a\ndeclaration to. Without a way to ask, gopls could only guess—“Add struct\ntags”, for example, always produced <code>json</code> tags in <code>camelCase</code>—or not offer the\nrefactoring at all. With interactive refactoring, language servers can now\neasily provide new operations with one or more parameters.</p>\n<p><em>&quot;Add struct tags&quot;, with questions</em></p>\n<p>While some language extensions have worked around this limitation by embedding\ncustom, language-specific dialog logic directly into individual editors, doing\nso leaves behind other editors (such as Neovim and Emacs) that stick strictly\nto the LSP with minimal custom client code. More importantly, editor-specific\nworkarounds go against the fundamental purpose of the LSP: to decouple\nlanguage-specific features from editors so that each server improvement benefits\nevery client.</p>\n<p>Our <a href=\"https://go.googlesource.com/proposal/+/refs/heads/master/design/76331-lsp-interactive-refactoring.md\" rel=\"nofollow ugc noopener\">LSP interactive refactoring proposal</a>\n(<a href=\"https://github.com/microsoft/language-server-protocol/issues/1164\" rel=\"nofollow ugc noopener\">microsoft/language-server-protocol#1164</a>)\nsolves this by establishing a standard mechanism for\nlanguage servers to collect user input before computing text edits. For Go\ndevelopers, this unlocks a suite of long-awaited refactorings, including:</p>\n<ul><li><a href=\"https://go.dev/issue/70583\" rel=\"nofollow ugc noopener\">golang/go#70583</a>: Move Declaration</li><li><a href=\"https://go.dev/issue/38028\" rel=\"nofollow ugc noopener\">golang/go#38028</a>: Change Signature</li><li><a href=\"https://github.com/golang/vscode-go/issues/1547\" rel=\"nofollow ugc noopener\">golang/vscode-go#1547</a>: Implement Interface</li><li><a href=\"https://github.com/golang/vscode-go/issues/2002\" rel=\"nofollow ugc noopener\">golang/vscode-go#2002</a>: Modify Struct Tags</li></ul>\n<p>among many others.</p>\n<h2 id=\"interactive-refactorings-in-action\">Interactive refactorings in action</h2>\n<p><strong>Adding and removing struct tags (gopls v0.23.0)</strong></p>\n<p>When configuring serialization formats, developers frequently need custom tags\nand casing conventions. Previously, running “Add struct tags” unconditionally\ninjected <code>json</code> tags using <code>camelCase</code> formatting.</p>\n<p>With interactive refactoring:</p>\n<ol><li><p>Place your cursor on any struct definition and select the</p><p> <strong>“Add struct tags”</strong> code action.</p></li><li><p>An input dialog appears, pre-filled with <code>json</code>, allowing you to customize</p><p> any combination of tags (such as <code>json,yaml,db</code>).</p></li><li><p>A second dialog lets you select your desired naming convention (such as</p><p> <code>camelCase</code>, <code>snake_case</code>, or <code>PascalCase</code>).</p></li><li><p>Gopls generates and applies the formatted struct tags across your type</p><p> definition.</p></li></ol>\n<p><em>Interactive &quot;Add struct tags&quot; in VS Code</em></p>\n<p>Here is the before-and-after transformation:</p>\n<pre><code>type UserProfile struct {\n    ID        int64\n    FirstName string\n    LastName  string\n    EmailAddr string\n}</code></pre>\n<pre><code>type UserProfile struct {\n    ID        int64  `json:&quot;id&quot; db:&quot;id&quot;`\n    FirstName string `json:&quot;first_name&quot; db:&quot;first_name&quot;`\n    LastName  string `json:&quot;last_name&quot; db:&quot;last_name&quot;`\n    EmailAddr string `json:&quot;email_addr&quot; db:&quot;email_addr&quot;`\n}</code></pre>\n<p>Similarly, <strong>“Remove struct tags”</strong> now asks you for the specific tag keys\nyou wish to delete (for example, removing only <code>db</code> tags while preserving the <code>json</code>\ntag), rather than wiping out all struct tags indiscriminately.</p>\n<p><em>Interactive &quot;Remove struct tags&quot; in VS Code</em></p>\n<p><strong>Implementing interfaces with dynamic symbol search</strong></p>\n<p>When creating a type to satisfy an interface, developers previously had to copy\nthe interface declaration and manually turn it into a set of methods on the\nreceiver type (or rely on external tools like <code>impl</code> by manually typing the\nreceiver and qualifying the name of the interface).</p>\n<p>Since gopls v0.23.0, with interactive refactoring:</p>\n<ol><li><p>Place your cursor on any concrete type and select the</p><p> <strong>“Add methods to X to implement an interface…”</strong> code action.</p></li><li><p>A text entry field appears, inviting you to choose the name of an interface</p><p> type. It makes dynamic queries to gopls to auto-complete names of types in\n your workspace and the standard library (for example, <code>maphash.Hasher</code>).</p></li><li><p>If the selected interface has type parameters, gopls asks for a</p><p> concrete type argument for each type parameter (such as <code>Foo</code>).</p></li><li><p>Gopls generates complete method stubs with appropriate receiver names and</p><p> instantiated method signatures.</p></li></ol>\n<p>*Interactive &quot;Add methods to implement an interface...&quot; in\nVS Code*</p>\n<pre><code>type Foo struct{}\n\ntype MyHasher struct{}</code></pre>\n<pre><code>type Foo struct{}\n\ntype MyHasher struct{}\n\n// Equal implements [maphash.Hasher].\nfunc (m *MyHasher) Equal(x Foo, y Foo) bool {\n    panic(&quot;unimplemented&quot;)\n}\n\n// Hash implements [maphash.Hasher].\nfunc (m *MyHasher) Hash(*maphash.Hash, Foo) {\n    panic(&quot;unimplemented&quot;)\n}</code></pre>\n<p><strong>Moving declarations across files and packages (preview)</strong></p>\n<p>Moving declarations manually by cutting and pasting can easily break references\nand requires tedious import cleanup across multiple files. While scheduled for\nan upcoming gopls release, our working implementation already demonstrates how\ninteractive file selection streamlines cross-file and cross-package moves:</p>\n<ol><li><p>Place your cursor on any top-level declaration and select the</p><p> <strong>“Move declaration X”</strong> code action.</p></li><li><p>A file picker dialog lets you choose an existing destination <code>.go</code> file or</p><p> specify a new file path.</p></li><li><p>Gopls moves the declaration along with its dependent declarations (such as</p><p> unexported helpers or methods) while leaving unrelated symbols in place,\n updates references across your workspace, and cleans up imports in both the\n source and destination files.</p></li></ol>\n<p><em>Interactive &quot;Move declaration&quot; in VS Code</em></p>\n<p>In the example below, we move the type <code>Foo</code> from package <code>from</code> to package\n<code>to</code>. Its method <code>Print</code> and the unexported constant <code>bar</code>, which only <code>Foo</code>\nuses, move along with it, while the unrelated function <code>Baz</code> stays behind:</p>\n<pre><code>// from/from.go\npackage from\n\nimport (\n    &quot;fmt&quot;\n    &quot;strings&quot;\n)\n\nconst bar = &quot;bar&quot;\n\n// Doc comment for Foo\ntype Foo struct{}\n\nfunc (f Foo) Print() {\n    fmt.Println(bar)\n}\n\nfunc Baz() string {\n    return strings.ToUpper(&quot;baz&quot;)\n}</code></pre>\n<pre><code>// from/from.go\npackage from\n\nimport &quot;strings&quot;\n\nfunc Baz() string {\n    return strings.ToUpper(&quot;baz&quot;)\n}\n\n// to/to.go\npackage to\n\nimport &quot;fmt&quot;\n\nconst bar = &quot;bar&quot;\n\n// Doc comment for Foo\ntype Foo struct{}\n\nfunc (f Foo) Print() {\n    fmt.Println(bar)\n}</code></pre>\n<p><strong>Slaying the dragon (gopls v0.24.0)</strong></p>\n<p>As a demonstration of multi-step interactive dialogs and a self-contained test\ncase for client editor implementations, gopls v0.24.0 offers a <strong>“Slay the\ndragon”</strong> code action when you place your cursor on a package-level variable\nnamed <code>dragonSlayer</code> (for example, <code>var dragonSlayer string</code>). Happy hunting!</p>\n<h2 id=\"what-s-on-the-horizon\">What’s on the Horizon</h2>\n<p>Interactive refactoring establishes a foundational capability in gopls,\nopening up several exciting directions on our roadmap:</p>\n<ul><li><p><strong>Change signature refactoring (<a href=\"https://go.dev/issue/38028\" rel=\"nofollow ugc noopener\">#38028</a>)</strong>: Adding, removing,</p><p>or reordering function parameters across a workspace requires input that\ncannot be deduced from syntax alone, such as the new parameter order or the\ndefault argument expression to insert at existing call sites. Interactive\nforms allow gopls to collect these details before rewriting the declaration\nand all call sites.</p></li><li><p><strong>Interactive conflict resolution</strong>: When a code transformation encounters</p><p>naming collisions, identifier shadowing, or ambiguous references, gopls can\nask the user for guidance, such as asking for permission to proceed or\noffering to rename conflicting symbols on the fly.</p></li><li><p><strong>Interactive commands beyond code edits</strong>: Because interactivity is modeled</p><p>at the LSP <a href=\"https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#command\" rel=\"nofollow ugc noopener\">command</a>\nlayer, it naturally generalizes to non-edit server\noperations that require user configuration, such as configuring test or\nbenchmark runs with profiling flags (CPU, memory, tracing).</p></li></ul>\n<h2 id=\"getting-started-and-sharing-feedback\">Getting Started and Sharing Feedback</h2>\n<p>Interactive refactoring is available in gopls <a href=\"https://go.dev/gopls/release/v0.24.0\" rel=\"nofollow ugc noopener\">v0.24.0</a>\nand <code>vscode-go</code> <a href=\"https://github.com/golang/vscode-go/releases/tag/v0.56.0\" rel=\"nofollow ugc noopener\">v0.56.0</a>\n(with proof-of-concept client integrations also explored for\n<a href=\"https://github.com/h9jiang/neovim/tree/interactive-refactoring\" rel=\"nofollow ugc noopener\">Neovim</a> and\n<a href=\"https://go-review.googlesource.com/c/tools/+/800220\" rel=\"nofollow ugc noopener\">Emacs</a>).</p>\n<p>We would love to hear your thoughts as we continue\nrefining interactive code actions in gopls:</p>\n<ul><li>For general feedback or feature requests, file an issue on the <a href=\"https://go.dev/issue/new\" rel=\"nofollow ugc noopener\">Go issue tracker</a>.</li><li><p>To read the full technical specification—including the stateless form</p><p>protocol design and alternative approaches we explored—or to join the\ndiscussion with the broader LSP community, check out the\n<a href=\"https://go.googlesource.com/proposal/+/refs/heads/master/design/76331-lsp-interactive-refactoring.md\" rel=\"nofollow ugc noopener\">LSP Interactive Code Actions design document</a>\nand the ongoing conversation in <a href=\"https://github.com/microsoft/language-server-protocol/issues/1164\" rel=\"nofollow ugc noopener\">microsoft/language-server-protocol#1164</a>.</p></li></ul>\n<p>*(Special thanks to Alan Donovan, Alex Putman, Brian Wilkerson, Danny Tuppeny,\nHana Kim, Madeline Kalil, Peter Weinberger, and Robert Findley for their\ninsights, discussions, feedback, and collaboration on this work.)*</p>\n<p>Happy refactoring!</p>","headings":[{"level":1,"text":"Interactive refactoring in gopls","id":"interactive-refactoring-in-gopls"},{"level":3,"text":"What is the Language Server Protocol (LSP)?","id":"what-is-the-language-server-protocol-lsp"},{"level":3,"text":"Multi-step code transformation","id":"multi-step-code-transformation"},{"level":2,"text":"Interactive refactorings in action","id":"interactive-refactorings-in-action"},{"level":2,"text":"What’s on the Horizon","id":"what-s-on-the-horizon"},{"level":2,"text":"Getting Started and Sharing Feedback","id":"getting-started-and-sharing-feedback"}]}}