Skip to content

Commit 6c39c00

Browse files
authored
Jump definition implementation (#12)
* 🚀 Add more code snippets Add more code snippets * ✨ proto3 snippets && syntaxes * 📝add image * 📝update image * Update package.json set language `proto3` * 🚧 Add some features 🚧 Add some features * ✨ 代码高亮&代码提示 调整了生成样式 * 🚧 #1 CompletionItemProvider CompletionItemProvider * 🔧 丰富设置 * Create LICENSE * Update package.json * ✨ #2 proto file to markdown :sparkles: #2 proto file to markdown * 📝 enrich documentation * ✨ #2 假设工具已安装后代码执行逻辑 * ✨ #2 支持语言设置 * ⚗️ #2 安装生成文档工具测试代码 * ✨ Automatic installation of generation tools * #3 using clang-format * #4 fixed: The request is abandoned. * #4 remove @ * remove @, fixed #5 * #2 proto-doc download link is redirected. * format code * Fix the problem of downloading file failure, close #2 * feat: update readme * #3 feat: clang-format options config * #3 feat: installation tips and parameter options * update readme * Formatting proto files (#8) * 🚀 Add more code snippets Add more code snippets * ✨ proto3 snippets && syntaxes * 📝add image * 📝update image * Update package.json set language `proto3` * 🚧 Add some features 🚧 Add some features * ✨ 代码高亮&代码提示 调整了生成样式 * 🚧 #1 CompletionItemProvider CompletionItemProvider * 🔧 丰富设置 * Create LICENSE * Update package.json * ✨ #2 proto file to markdown :sparkles: #2 proto file to markdown * 📝 enrich documentation * ✨ #2 假设工具已安装后代码执行逻辑 * ✨ #2 支持语言设置 * ⚗️ #2 安装生成文档工具测试代码 * ✨ Automatic installation of generation tools * #3 using clang-format * #4 fixed: The request is abandoned. * #4 remove @ * remove @, fixed #5 * #2 proto-doc download link is redirected. * format code * Fix the problem of downloading file failure, close #2 * feat: update readme * #3 feat: clang-format options config * #3 feat: installation tips and parameter options * update readme * update version * Formatting proto files (#8) * 🚀 Add more code snippets Add more code snippets * ✨ proto3 snippets && syntaxes * 📝add image * 📝update image * Update package.json set language `proto3` * 🚧 Add some features 🚧 Add some features * ✨ 代码高亮&代码提示 调整了生成样式 * 🚧 #1 CompletionItemProvider CompletionItemProvider * 🔧 丰富设置 * Create LICENSE * Update package.json * ✨ #2 proto file to markdown :sparkles: #2 proto file to markdown * 📝 enrich documentation * ✨ #2 假设工具已安装后代码执行逻辑 * ✨ #2 支持语言设置 * ⚗️ #2 安装生成文档工具测试代码 * ✨ Automatic installation of generation tools * #3 using clang-format * #4 fixed: The request is abandoned. * #4 remove @ * remove @, fixed #5 * #2 proto-doc download link is redirected. * format code * Fix the problem of downloading file failure, close #2 * feat: update readme * #3 feat: clang-format options config * #3 feat: installation tips and parameter options * update readme Update version (#9) * update version * update version * update version * Update .gitignore to include .direnv directory * #11 Implement definition provider for proto3 files and refactor command registration in extension.ts * Update CHANGELOG, README, and package version to 0.2.1; enhance documentation and features including Go to Definition, completion items, and CI workflows. * - Added support for additional completion items in the proto3 language. - Improved error handling in document generation and directory creation functions. - Updated the `.gitignore` to include `.direnv/`. - Refactored `formatFile` to handle errors more gracefully. - Enhanced `rightClickGenDoc` to catch and log errors during execution. (cherry picked from commit 9ee2714)
1 parent 9a049d3 commit 6c39c00

7 files changed

Lines changed: 299 additions & 26 deletions

File tree

CHANGELOG.md

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,48 @@
11
# Change Log
22

3-
All notable changes to the "vscode-proto3-tools" extension will be documented in this file.
3+
All notable changes to the **vscode-proto3-tools** extension are documented in this file.
44

5-
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7-
## [0.1.0.1018_beta]
7+
## [0.2.1]
88

9-
- snippets
10-
- syntaxes
9+
### Added
1110

12-
## [0.1.2]
11+
- **Go to Definition** (`DefinitionProvider`): jump to `message`, `enum`, `service`, and `rpc` declarations; resolves symbols from `import "relative/path.proto"` when the file exists on disk.
12+
13+
## [0.1.5] - 2026-04-30
14+
15+
Enhance proto3 extension with improved completion item provider and error handling.
16+
17+
### Added
18+
19+
- Additional **completion** items for the `proto3` language (`CompletionItemProvider`: keywords, scalar types, symbols in the current file, common `google.protobuf.*`, service / `rpc` / `returns` contexts, and trigger characters `.`, `"`, `(`).
20+
- **GitHub Actions**: CI workflow (install, compile, lint on push/PR to `main` or `master`); release workflow on `v*` tags (VSIX, GitHub Release, publish to VS Code Marketplace when `VSCE_PAT` is set).
21+
22+
### Fixed
23+
24+
- **Document generation**: safer async flow for `proto-doc` (`execFile` / promises) and fewer unhandled rejections.
25+
- **Directory creation**: `createDir` returns a `Promise` and no longer throws from callbacks after showing errors.
26+
- **Download / install paths**: avoid throwing inside `https` / mkdir / decompress error handlers.
27+
28+
### Changed
29+
30+
- **`formatFile`**: wrap `clang-format` / `execSync` in `try` / `catch`, show an error message, and return no edits on failure.
31+
- **`rightClickGenDoc`**: surface failures via `catch` / logging instead of leaving floating promises.
32+
- **`.gitignore`**: ignore `.direnv/`.
33+
- **Docs**: `CHANGELOG` / readme previously referenced a mistaken **1.0.5**; the published line on `main` is **0.1.5** (`v0.1.5`).
34+
- **Dependencies**: added `@vscode/vsce` and scripts `ci`, `vsix` for packaging and automation.
1335

14-
- Gen Api Doc
1536

1637
## [0.1.3]
1738

18-
- format code
39+
- Format code (clang-format).
40+
41+
## [0.1.2]
42+
43+
- Generate API documentation (external `proto-doc` CLI).
44+
45+
## [0.1.0.1018_beta]
46+
47+
- Snippets.
48+
- Syntax highlighting.

README.md

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,33 @@
44
<img src="./images/logo.png">
55
</p>
66

7+
8+
<div align="center">
9+
10+
[![License](https://img.shields.io/badge/License-MIT-green?style=flat-square)](LICENSE)
11+
[![Release](https://img.shields.io/github/v/release/kalifun/vscode-proto3-tools?style=flat-square)](https://github.com/kalifun/vscode-proto3-tools/releases)
12+
13+
</div>
14+
715
> proto3 language service
816
9-
I'm sure you're no stranger to api documentation, but when there's no common place to store it, it can lead to a variety of formats and fragmentation. This causes us to collect the api documentation is so painful. So I wonder why we don't define some important parameters in advance when we write `proto` and stuff the valid data through `comment` form. When we define the api to complete the api documentation, that's great!
17+
I'm sure you're no stranger to API documentation, but when there's no common place to store it, it can lead to a variety of formats and fragmentation. That makes collecting API docs painful. This extension helps you capture structure and comments in `proto` files, and generate docs where it fits your workflow.
1018

11-
## Feature
19+
## Features
1220

13-
> More features will come
21+
### Implemented
22+
23+
| Area | Description |
24+
|------|-------------|
25+
| **Snippets** | Common `proto3` patterns (messages, RPCs, fields, etc.). |
26+
| **Syntax** | TextMate grammar for `.proto` (language id `proto3`). |
27+
| **Generate doc** | Commands / context menu to run the external [**proto-doc**](https://github.com/kalifun/proto-doc) CLI; configurable output path and `zh` / `en` template language. |
28+
| **Format** | Document formatting via **clang-format** (style options in settings). |
29+
| **Completion** | Keyword / scalar / file-local types, service keywords, and types in `rpc` / `returns` parentheses; trigger characters include `.`, `"`, `(`. |
30+
| **Go to Definition** | Jump to `message`, `enum`, `service`, and `rpc` definitions in the current file and in imported `.proto` files (relative `import` paths on disk). |
31+
| **CI / release** | GitHub Actions: lint + compile on PR/push; tag `v*.*.*` builds a VSIX, creates a GitHub Release, and can publish to the Marketplace (requires `VSCE_PAT`). |
32+
33+
Screenshots: snippets, syntax, doc, and format — see sections below.
1434

1535
### Snippets
1636

@@ -28,14 +48,26 @@ I'm sure you're no stranger to api documentation, but when there's no common pla
2848

2949
![](images/format.gif)
3050

31-
## Todo
51+
## Roadmap / not yet done
52+
53+
- [ ] **AIP / api-linter**: `proto3.disable_rules` exists in settings but is not wired to a linter or diagnostics in the editor.
54+
- [ ] **clang-format detection**: reliably detect whether `clang-format` is on `PATH` before offering format (today formatting may no-op or error depending on environment).
55+
- [ ] **References & symbols**: “Find all references”, document outline / workspace symbol list from parsed protos.
56+
- [ ] **Imports**: `buf.work.yaml` / multi-root–aware and `protoc` include paths for imports beyond simple relative files.
57+
- [ ] **Tests**: automated `@vscode/test-electron` (or similar) suite in CI.
58+
- [ ] **Optional**: Open VSX / other registries, semantic highlighting, deeper comment-aware parsing.
59+
60+
## Todo checklist (high level)
3261

33-
- [x] Snippets
34-
- [x] Syntaxes
35-
- [x] Gen Api Doc
36-
- [x] Format code
62+
- [x] Snippets
63+
- [x] Syntaxes
64+
- [x] Gen API doc (via proto-doc)
65+
- [x] Format code (clang-format)
66+
- [x] Completion
67+
- [x] Go to Definition (basic + import)
68+
- [x] CI & release automation
3769

3870
# Acknowledgement
3971

4072
[vscode-proto3](https://github.com/zxh0/vscode-proto3)
41-
[language_grammars](https://macromates.com/manual/en/language_grammars#naming_conventions)
73+
[language_grammars](https://macromates.com/manual/en/language_grammars#naming_conventions)

docs/readme_zh.md

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,31 @@
44
<img src="../images/logo.png">
55
</p>
66

7+
<div align="center">
8+
9+
[![License](https://img.shields.io/badge/License-MIT-green?style=flat-square)](LICENSE)
10+
[![Release](https://img.shields.io/github/v/release/kalifun/vscode-proto3-tools?style=flat-square)](https://github.com/kalifun/vscode-proto3-tools/releases)
11+
12+
</div>
13+
714
> proto3 language service
815
9-
我想接口文档大家肯定不陌生,可是当没有一个公共存储的地方,则会导致我们的接口文档有着各种各样的格式,且是零散的。这导致我们收集接口文档是那么的痛苦。所以我在想我们在编写`proto`的时候为啥不提前将一些重要参数定义好,通过`注释`这种形式将有效数据塞入。当我们在定义接口时就完成了接口文档的编写,那不是妙哉!
16+
17+
我想接口文档大家肯定不陌生,可是当没有一个公共存储的地方,则会导致我们的接口文档有着各种各样的格式,且是零散的。这导致我们收集接口文档是那么的痛苦。所以在编写 `proto` 时提前用注释等方式把关键信息写清楚,并在需要时一键生成文档,会省事很多;本扩展围绕 **proto3 编辑体验****与 proto-doc 的衔接** 来做。
1018

1119
## 功能
1220

13-
> 将会有更多功能到来
21+
### 已实现
22+
23+
| 能力 | 说明 |
24+
|------|------|
25+
| **代码片段** | 常见 message / rpc / 字段等模板。 |
26+
| **语法高亮** | `.proto` 的 TextMate 语法(语言 id:`proto3`)。 |
27+
| **生成文档** | 命令与右键菜单调用外部 [**proto-doc**](https://github.com/kalifun/proto-doc);可配置输出目录与中英模板。 |
28+
| **格式化** | 使用本机 **clang-format**(可在设置里选风格与缩进)。 |
29+
| **补全** | 按上下文补关键字、标量类型、当前文件内的 message/enum、常见 `google.protobuf.*`,以及 `rpc` / `returns` 括号内的类型等。 |
30+
| **跳转定义** | 跳转到本文件内的 `message` / `enum` / `service` / `rpc` 定义;支持通过相对路径 `import` 打开的其它 `.proto` 中的同名符号(当前文件优先覆盖 import)。 |
31+
| **CI / 发版** | GitHub Actions:PR/推送时编译 + lint;推送 `v*` 标签时打 VSIX、建 GitHub Release,并在配置 `VSCE_PAT` 时发布到 VS Code 扩展市场。 |
1432

1533
### 代码片段
1634

@@ -20,14 +38,35 @@
2038

2139
![](../images/syntaxes.png)
2240

23-
## Todo
41+
### 文档
42+
43+
![](../images/doc.png)
44+
45+
### 格式化
46+
47+
![](../images/format.gif)
48+
49+
## 尚未实现 / 规划中
50+
51+
- [ ] **AIP / api-linter**:设置里已有 `proto3.disable_rules` 等项,但尚未接入诊断或调用 api-linter。
52+
- [ ] **clang-format 检测**:更可靠地判断本机是否已安装 `clang-format`,再决定是否提供格式化。
53+
- [ ] **引用与大纲**:查找所有引用、工作区/文档符号列表等。
54+
- [ ] **复杂 import**`buf.work.yaml``protoc -I` 多根路径等,不仅限于「相对当前文件的 import 路径」。
55+
- [ ] **自动化测试**:在 CI 中跑扩展集成测试。
56+
- [ ] **其它**:Open VSX、语义高亮、更强注释/字符串内解析等。
57+
58+
## Todo 总览
2459

25-
- [x] Snippets
26-
- [x] Syntaxes
27-
- [ ] Gen Api Doc
60+
- [x] Snippets
61+
- [x] Syntaxes
62+
- [x] Gen Api Doc(proto-doc)
63+
- [x] Format code
64+
- [x] 补全(Completion)
65+
- [x] 跳转定义(Definition)
66+
- [x] CI 与 Release 工作流
2867

2968
# 鸣谢
3069

31-
[vscode-proto3](https://github.com/zxh0/vscode-proto3)  
70+
[vscode-proto3](https://github.com/zxh0/vscode-proto3)
3271

33-
[language_grammars](https://macromates.com/manual/en/language_grammars#naming_conventions)
72+
[language_grammars](https://macromates.com/manual/en/language_grammars#naming_conventions)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "vscode-proto3-tools",
33
"displayName": "Proto3 Tools",
4-
"version": "0.1.5",
4+
"version": "0.2.1",
55
"description": "proto3 language service",
66
"engines": {
77
"vscode": "^1.71.0"
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import * as fs from 'fs';
2+
import * as path from 'path';
3+
import * as vscode from 'vscode';
4+
5+
const WORD_RE = /[A-Za-z_][A-Za-z0-9_.]*/;
6+
7+
/** import "path"; 或 import public "path"; */
8+
const IMPORT_RE = /\bimport\s+(?:public\s+|weak\s+)?"([^"]+)"\s*;/g;
9+
10+
const DEF_PATTERNS: { re: RegExp }[] = [
11+
{ re: /\bmessage\s+(\w+)\s*\{/g },
12+
{ re: /\benum\s+(\w+)\s*\{/g },
13+
{ re: /\bservice\s+(\w+)\s*\{/g },
14+
{ re: /\brpc\s+(\w+)\s*\(/g },
15+
];
16+
17+
function offsetToPosition(fullText: string, offset: number): vscode.Position {
18+
const upTo = fullText.slice(0, offset);
19+
const lines = upTo.split('\n');
20+
const line = lines.length - 1;
21+
const character = lines[line].length;
22+
return new vscode.Position(line, character);
23+
}
24+
25+
function stripLineCommentsForScan(line: string): string {
26+
return line.split('//')[0];
27+
}
28+
29+
/**
30+
* 从文本中收集符号名 → 定义位置(同一文件内 uri)。
31+
* 行尾 // 注释不参与匹配,减少误匹配注释里的 message 等字样。
32+
*/
33+
function collectDefinitionsInText(text: string, uri: vscode.Uri): Map<string, vscode.Location> {
34+
const map = new Map<string, vscode.Location>();
35+
let idx = 0;
36+
while (idx < text.length) {
37+
const nl = text.indexOf('\n', idx);
38+
const lineEnd = nl === -1 ? text.length : nl;
39+
let raw = text.slice(idx, lineEnd);
40+
if (raw.endsWith('\r')) {
41+
raw = raw.slice(0, -1);
42+
}
43+
const line = stripLineCommentsForScan(raw);
44+
const lineStart = idx;
45+
46+
for (const { re } of DEF_PATTERNS) {
47+
re.lastIndex = 0;
48+
let m: RegExpExecArray | null;
49+
while ((m = re.exec(line)) !== null) {
50+
const name = m[1];
51+
const nameInLine = m.index + m[0].indexOf(name);
52+
const start = lineStart + nameInLine;
53+
const endOff = start + name.length;
54+
const loc = new vscode.Location(
55+
uri,
56+
new vscode.Range(offsetToPosition(text, start), offsetToPosition(text, endOff))
57+
);
58+
map.set(name, loc);
59+
}
60+
}
61+
62+
if (nl === -1) {
63+
break;
64+
}
65+
idx = nl + 1;
66+
}
67+
return map;
68+
}
69+
70+
function extractImportPaths(text: string): string[] {
71+
const paths: string[] = [];
72+
let m: RegExpExecArray | null;
73+
IMPORT_RE.lastIndex = 0;
74+
while ((m = IMPORT_RE.exec(text)) !== null) {
75+
paths.push(m[1]);
76+
}
77+
return paths;
78+
}
79+
80+
function resolveImportUri(fromDoc: vscode.TextDocument, importPath: string): vscode.Uri | undefined {
81+
if (fromDoc.uri.scheme !== 'file') {
82+
return undefined;
83+
}
84+
const dir = path.dirname(fromDoc.uri.fsPath);
85+
const full = path.normalize(path.join(dir, importPath));
86+
if (fs.existsSync(full) && fs.statSync(full).isFile()) {
87+
return vscode.Uri.file(full);
88+
}
89+
return undefined;
90+
}
91+
92+
function lookupSymbol(
93+
map: Map<string, vscode.Location>,
94+
word: string
95+
): vscode.Location | undefined {
96+
if (map.has(word)) {
97+
return map.get(word);
98+
}
99+
const dot = word.lastIndexOf('.');
100+
if (dot !== -1) {
101+
const tail = word.slice(dot + 1);
102+
return map.get(tail);
103+
}
104+
return undefined;
105+
}
106+
107+
async function buildDefinitionMap(document: vscode.TextDocument, token: vscode.CancellationToken): Promise<Map<string, vscode.Location>> {
108+
const merged = new Map<string, vscode.Location>();
109+
const body = document.getText();
110+
const imports = extractImportPaths(body);
111+
112+
for (const imp of imports) {
113+
if (token.isCancellationRequested) {
114+
return merged;
115+
}
116+
const uri = resolveImportUri(document, imp);
117+
if (!uri) {
118+
continue;
119+
}
120+
try {
121+
const imported = await vscode.workspace.openTextDocument(uri);
122+
const part = collectDefinitionsInText(imported.getText(), imported.uri);
123+
for (const [k, v] of part) {
124+
if (!merged.has(k)) {
125+
merged.set(k, v);
126+
}
127+
}
128+
} catch {
129+
// 忽略无法打开的 import
130+
}
131+
}
132+
133+
if (token.isCancellationRequested) {
134+
return merged;
135+
}
136+
const local = collectDefinitionsInText(body, document.uri);
137+
for (const [k, v] of local) {
138+
merged.set(k, v);
139+
}
140+
return merged;
141+
}
142+
143+
export function createProto3DefinitionProvider(): vscode.DefinitionProvider {
144+
return {
145+
async provideDefinition(
146+
document: vscode.TextDocument,
147+
position: vscode.Position,
148+
token: vscode.CancellationToken
149+
): Promise<vscode.Location | vscode.Location[] | undefined> {
150+
const range = document.getWordRangeAtPosition(position, WORD_RE);
151+
if (!range) {
152+
return undefined;
153+
}
154+
const word = document.getText(range);
155+
if (!word) {
156+
return undefined;
157+
}
158+
159+
const map = await buildDefinitionMap(document, token);
160+
const loc = lookupSymbol(map, word);
161+
return loc;
162+
},
163+
};
164+
}

src/extension.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import * as vscode from 'vscode';
44
import cp = require('child_process');
55
import { Proto3CompletionItemProvider } from './api/completion/completion';
6+
import { createProto3DefinitionProvider } from './api/definition/protoDefinition';
67
import { Proto3 } from './conf/config';
78
import { generateMarkdown, rightClickGenDoc } from './repo/doc/doc';
89
import {formatFile, isClangFormat} from "./repo/format/format";

0 commit comments

Comments
 (0)