You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(rename): Allow RPCs, fields, reference sites to be renamed with rpc/request/response chains (#131)
I would like the "rename" action to just work everywhere for the symbol
under the cursor. This is wired into my muscle-memory from using other
editors and I tend to do it even when it's a bit silly, like in cases
where the symbol just would never be referenced from anywhere else (such
as a service name in Protobuf). I like to just not have to think about
it.
I filed an issue before (#129) about wanting to be able to rename a
message from a referenced site. This PR includes that, but also some
other rename improvements. If you would rather want me to split it into
separate PRs, let me know.
I find the rpc/Request/Response chain rename especially useful. I
realize all protobuf users may not follow this convention, but it should
(hopefully) not get in the way for people who don't. Let me know if you
would rather like this to be configurable.
## Additions
**Service and RPC symbol rename.** `can_rename` was gated on
`message_name`/`enum_name` parents only, so invoking rename on a service
or RPC method was a silent no-op. A new `is_renameable` predicate
accepts `service_name` and `rpc_name`, and `rename_tree`'s
empty-ancestor path returns a single in-file edit (services/RPCs have no
cross-file references to propagate).
**Rename from a type-reference site.** Previously you had to navigate to
the declaration first. Now invoking rename on a `MyRequest` reference
inside `rpc DoThing(MyRequest)` — or on the inner segment of a qualified
type like `Outer.Inner` — works: the LSP resolves the partial qualified
path under the cursor to the declaration via the existing definition
machinery and runs the regular rename from there. The user's "rename the
segment under cursor" intent is honored: cursor on `Outer` renames
`Outer`, cursor on `Inner` renames `Inner`.
**Field name, oneof, and enum-value rename.** Identifiers whose parent
is `field`, `map_field`, `oneof_field`, `oneof`, or `enum_field` are now
renameable. Each is single-site — these don't appear as type references
in other `.proto` files — so the workspace pass is intentionally a no-op
for them, avoiding accidental renames if a lowercase type happens to
share a name.
**Chained `rpc`/`Request`/`Response` rename.** When an `rpc` follows the
`rpc <Name>(<Name>Request) returns (<Name>Response)` convention from the
[Google API design guide](https://google.aip.dev/) (AIPs 131–136),
renaming any one of the three triggers a chained rename of the other
two. The chain only kicks in when all of these hold:
- the matching message name follows the convention exactly (trailing
segment of its qualified text),
- the request/response is used by exactly one rpc in the workspace, and
- the user's new name preserves the convention (e.g. renaming a request,
the new name still ends with `Request`).
If any check fails, only the symbol the user invoked rename on is
renamed — the primary rename is never blocked by chain-detection
failures.
## Implementation
This implementation has been assisted by Claude Code using Opus 4.7. I
have read and generally understood the code and sign off on it as a
human being. I have previous experience with Rust, but would not
consider myself an expert. I have no previous experience with writing
LSP:s.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Ashar <coder3101@users.noreply.github.com>
Co-authored-by: Ashar <ashar786khan@gmail.com>
@@ -170,6 +171,9 @@ include_paths = ["foobar", "bazbaaz"] # Include paths to look for protofiles dur
170
171
[config.path]
171
172
clang_format = "clang-format"
172
173
protoc = "protoc"
174
+
175
+
[config.rename]
176
+
chain_rpc_request_response = false# Also rename <Rpc>Request/<Rpc>Response messages when renaming an rpc
173
177
```
174
178
175
179
### Configuration Sections
@@ -197,6 +201,16 @@ The `[config.path]` section contains path for various tools used by LSP.
197
201
-`clang_format`: Uses clang_format from this path for formatting
198
202
-`protoc`: Uses protoc from this path for diagnostics
199
203
204
+
#### Rename Configuration
205
+
206
+
The `[config.rename]` section tunes rename behaviour.
207
+
208
+
-`chain_rpc_request_response` (default `false`): when enabled, renaming an `rpc`
209
+
also renames its convention-named `<Rpc>Request` and `<Rpc>Response` messages —
210
+
and renaming such a message renames the `rpc` and its sibling message. The chain
211
+
only fires when the names follow the [Google API design guide](https://cloud.google.com/apis/design/naming_convention#request_and_response_messages)
212
+
convention and the messages are used by exactly one `rpc`.
213
+
200
214
---
201
215
202
216
## 🛠 Usage
@@ -233,7 +247,9 @@ Hover over any symbol or imports to get detailed documentation and comments asso
233
247
234
248
### Rename Symbols
235
249
236
-
Rename symbols like messages or enums, and Propagate the changes throughout the codebase. Currently, field renaming within symbols is not supported.
250
+
Rename symbols like messages, enums, services and RPC methods, and propagate the changes throughout the codebase. Rename also works when invoked on a type reference (e.g. the request or response type of an `rpc`) — the LSP pivots to the declaration and applies the rename from there. Field names, oneof names, and enum values can also be renamed at their declaration site (single-site rename, since they aren't referenced as types from other `.proto` files).
251
+
252
+
When an `rpc` follows the `rpc <Name>(<Name>Request) returns (<Name>Response)` convention from the [Google API design guide](https://google.aip.dev/) (AIPs 131–136), renaming any one of the three triggers a chained rename of the other two — but only when (a) the matching message name follows the convention exactly, (b) the request/response is used by exactly one rpc in the workspace, and (c) the user's new name preserves the convention. If any check fails, only the symbol the user invoked rename on is renamed.
0 commit comments