跳到正文
cccskills
免费在 GitHub 公开中文介绍

Language server

本技能介绍Carbon语言服务器及其VS Code扩展的实现,包括LSP请求注册与处理、文档类型、SemIR文本读取,以及使用file_test编写和更新测试期望值。

原文查看原文说明

Instructions for working on Carbon's LSP language server, including its architecture, its file_test-based tests, and the VS Code extension.

carbon-language/carbon-lang星标 33,929(GitHub 33,929 + cccskills 0)

实测评分 未实测

查看安装方法

适用场景

  • 查找LSP处理器的添加位置
  • 编写语言服务器测试
  • 更新测试期望值
  • 检查VS Code扩展启动设置

中文介绍

功能

本技能介绍Carbon语言服务器及启动它的VS Code扩展。内容说明LSP请求在哪里注册、处理器与文档上下文如何分工,以及Carbon源码文档和测试数据在处理方式上的区别。测试部分讲解如何使用file_test输入分段和LSP调用关键字,并通过自动更新脚本更新期望输出。还介绍SemIR文本中的名称查找、UTF-16位置偏移,以及测试通信格式需要留意的事项。

适用场景

开发Carbon语言服务器的新功能或追踪现有请求处理流程时,可以参考本技能。编写或更新测试,以及检查VS Code扩展如何启动服务器时也适用。

使用示例

  • “这个LSP请求的处理器应添加在哪里?”
  • “请创建一个检查悬停和跳转到定义的file_test。”
  • “请说明VS Code扩展如何启动服务器。”

注意事项

运行测试需要bazelisk和file_test。VS Code扩展通过stdio启动carbonPath设置所指定的可执行文件。

本介绍由 AI(OpenAI Codex)根据公开的 SKILL.md 撰写。准确的规格请查看下方原文。

文档检查

AI 根据 SKILL.md 的内容检查了需要注意的操作和使用前提。评分只依据实际运行的结果(实测对比)。

安全性发送数据、删除文件、执行命令等是否有说明
A良好资料涉及测试和VS Code设置,未提及删除、外发或读取凭据。
安装难易度所需工具和 API 密钥是否少且有说明
B部分不足资料以bazelisk、file_test及配置carbonPath的VS Code扩展为前提,但未说明安装步骤。

不计入评分。 由 AI(OpenAI Codex)于 2026年10月26日 评估。仅供参考,安装前请同时查看原文。

如果您认为评估有误,请申请复核

请写明哪一项有误以及原因。无需登录。我们会对照 SKILL.md 重新评估,并在此处更新结果。

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

包含的文件(1)

  • SKILL.md8.3 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Language server

<!-- Part of the Carbon Language project, under the Apache License v2.0 with LLVM Exceptions. See /LICENSE for license information. SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -->

Introduction

This skill covers toolchain/language_server/, which implements carbon language-server, and utils/vscode/, the VS Code extension that launches it.

Architecture

The server is built on clangd's LSP transport (clang::clangd), not on a Carbon-specific one. That means clangd's Protocol.h types (Position, Range, Location, Hover, MarkupContent) are the interface currency.

  • server.cpp / incoming_messages.cpp: message dispatch. A handler must be registered in incoming_messages.cpp before it can be called.
  • handle_*.cpp: one file per request family, each declaring its entry point in handle.h.
  • handle_initialize.cpp: the advertised capabilities. Adding a capability changes Content-Length in every test that calls initialize, so expect a large autoupdate diff.
  • context.h / context.cpp: Context::File per open document, plus the compile driver. Context::File::unit() has a CARBON_CHECK on the compile driver, so any handler that reaches for the parse tree must first rule out documents that were never compiled.
  • position.h, sem_ir_index.h: mapping source positions to SemIR instructions for real Carbon files.
  • sem_ir_text.h, handle_sem_ir_text.h: navigation within the formatted SemIR in a test file's // CHECK:STDOUT: lines. This is a heuristic text index, deliberately independent of the real SemIR data structures. See the SemIR text reader.

Document kinds

The server handles two kinds of document, distinguished by the languageId from textDocument/didOpen, with a content sniff as a fallback:

  • carbon: a real Carbon file. Compiled; diagnostics published.
  • carbon-testdata: a test file. Not compiled, because we lack logic to split it into one file per // --- split marker.

[!IMPORTANT] A handler that assumes every file was compiled will crash on a test file. When adding one, give the test-file path an explicit early return.

Tests

There is no language-server-specific test target. toolchain/language_server/BUILD only declares filegroup(name = "testdata"), which is pulled into //toolchain/testing:all_testdata and run by //toolchain/testing:file_test.

# Run just the language server tests (or any subset).
bazelisk test //toolchain/testing:file_test \
    --test_arg=--file_tests=toolchain/language_server/testdata/position/hover_and_goto.carbon

# See the raw output, which is much easier to read than a test failure.
bazelisk run //toolchain/testing:file_test -- --dump_output \
    --file_tests=toolchain/language_server/testdata/position/hover_and_goto.carbon

# Update expectations. Never hand-write CHECK lines.
./toolchain/autoupdate_testdata.py toolchain/language_server/testdata/...

These tests run serially, because clangd's logging is a global singleton.

Test file shape

The request stream is a // --- STDIN split written with the [[@LSP-*]] keywords, and the responses land in a trailing // --- AUTOUPDATE-SPLIT. Documents come from other splits by way of "text": "FROM_FILE_SPLIT", which is substituted with the content of the split whose name matches the uri.

// --- position.carbon
fn Abs(n: i32) -> i32 { return n; }

// --- STDIN
[[@LSP-CALL:initialize:"capabilities": {}]]
[[@LSP-NOTIFY:textDocument/didOpen:
  "textDocument": {
    "uri": "file:/position.carbon",
    "languageId": "carbon",
    "text": "FROM_FILE_SPLIT"
  }
]]
[[@LSP-CALL:textDocument/hover:
  "textDocument": {"uri": "file:/position.carbon"},
  "position": {"line": 0, "character": 3}
]]
[[@LSP-CALL:shutdown]]
[[@LSP-NOTIFY:exit]]

// --- AUTOUPDATE-SPLIT

Full keyword documentation is in testing/file_test/README.md.

Traps

[!WARNING] A blank line inside the STDIN split breaks the JSON transport. It terminates a header block, so clangd logs a timestamped Warning: Missing Content-Length header, or zero-length message. The timestamp makes the test unreproducible, so it fails on the next run. Comment lines between messages are fine; blank lines are not. A single blank line immediately before // --- AUTOUPDATE-SPLIT is also fine.

Other things worth knowing:

  • positionEncoding is UTF-16. A character is a UTF-16 code unit offset, not a byte offset.
  • Line and character numbers in requests are 0-based, while the locN_M suffixes in SemIR output are 1-based. Off-by-ones here are silent: the request succeeds and returns the wrong thing.
  • A split can hold a document that itself contains // CHECK:STDOUT: lines, because CHECK lines only form expectations inside the AUTOUPDATE-SPLIT. Such a document still can't contain a literal // --- line, which would split the enclosing test file; write it as [[@0x2f]]/ --- name.carbon.

The SemIR text reader

sem_ir_text.cpp indexes the formatted SemIR inside a test file's // CHECK:STDOUT: lines so that hover and go-to-definition work on operand names. It is a heuristic reader, not a parser, and its correctness rests on facts about toolchain/sem_ir/formatter.cpp and toolchain/sem_ir/inst_namer.cpp. Re-check these if the formatter changes:

  • There are exactly four scope keywords: file, generated, imports, and constants (InstNamer::GetScopeName). Everything else is @entityname.
  • A reference is %name within its own scope and scope.%name otherwise (InstNamer::GetNameFor). Names may contain . and may start with one, as in %.Self.frozen.
  • Type annotations are printed in the constants scope. Formatter::FormatTypeOfInst does llvm::SaveAndRestore file_scope(scope_, InstNamer::ScopeId::Constants), so in %x: %foo = ... a bare %foo means constants.%foo. This does not apply to ordinary operands or to [concrete = ...] annotations.
  • *_decl braces hold the declared entity's scope. The braces of %F.decl: ... = fn_decl @F [...] { ... } { ... } are lexically inside file { }, but their names belong to @F.
  • !with Self: switches scope without a brace, until !members: switches it back. Brace counting alone cannot see this.
  • A specific @F(args) { } block uses @F's scope and defines nothing; each %name => value row references an instruction of the generic.

Validating a change to the reader

The unit tests only cover a handful of cases. To check a change against the real corpus, drive the server over a sample of check testdata, hovering on every %name, and compare the resolved fraction before and after. Roughly 99% of names resolve; the residue are names the formatter references but never emits a definition line for, such as %I.WithSelf.F, which only ever appears inside a [symbolic = ...] annotation.

Two things to get right in such a harness:

  • Feed the request stream from a file, not a pipe. The server reads stdin as a file and reports error: Input/output error on a pipe.
  • Read the output as bytes. Python's text=True rewrites the \r\n framing, and Content-Length counts bytes.

VS Code extension

utils/vscode/ declares three languages in package.json:

Language idApplies to
carbon*.carbon
carbon-testdata**/testdata/**/*.carbon
semir*.semir

[!NOTE] The TextMate scope for SemIR is source.carbon-semir, but the language id is semir. Markdown code fences in hover text resolve language ids, so a fence must say ```semir.

extension.ts launches the server over stdio, using the carbonPath setting (default ./bazel-bin/toolchain/carbon). Its documentSelector controls which files are sent to the server at all; a new document kind has to be added there as well as in the server.

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

本技能介绍如何使用命令行`gh`只读查看GitHub issue正文和评论,支持通过编号或URL定位,也可指定其他仓库,并说明如何提取大量评论。

  • 查看issue正文和评论
  • 通过URL读取issue
  • 查看其他仓库的issue
carbon-language/carbon-lang3.4万2026年10月26日 更新

Agent tools

免费有简介

本技能为在 Carbon 代码库中工作的 AI 助手规定文件查看、搜索和编辑工具,并说明临时文件的存放与清理规则,以及何时可以编写和运行自定义程序。

  • 按规定工具搜索Carbon文件
  • 为文件编辑选择专用工具
  • 确认临时文件的存放与清理规则
carbon-language/carbon-lang3.4万2026年10月26日 更新

Bazel usage

免费有简介

了解如何在 Carbon 项目中通过 Bazelisk 构建、测试和运行程序,包括指定目标、启用 ASan,以及系统依赖变更后重建缓存。

  • 构建 Carbon 代码
  • 运行与修改相关的测试
  • 启动 Bazel 构建的程序
carbon-language/carbon-lang3.4万2026年10月26日 更新

Builtin functions

免费有简介

本技能介绍如何为Carbon编译器添加内置函数,包括类型注册、签名验证、常量求值、运行时LLVM IR生成、Prelude绑定,以及使用最小Prelude编写针对性测试。

  • 注册内置函数
  • 实现常量求值
  • 添加LLVM IR生成
carbon-language/carbon-lang3.4万2026年10月26日 更新

Code style

免费有简介

了解 Carbon 工具链对 Bazel、C++、Carbon、Markdown 和 Python 文件的格式规范,并查看注释、文档、命名、设计及提交说明的写作要求。

  • 整理 Carbon 代码格式
  • 检查注释和文档
  • 确认名称是否符合实际含义
carbon-language/carbon-lang3.4万2026年10月26日 更新

Diagnostics

免费有简介

本技能介绍如何在Carbon工具链中添加或修改错误和警告,包括注册诊断类型、用带类型的参数构造消息、为源码位置添加标签和上下文,以及检查措辞规范和测试覆盖。

  • 添加诊断消息
  • 为源码位置添加标签
  • 统一诊断措辞
carbon-language/carbon-lang3.4万2026年10月26日 更新

查看 carbon-language 的全部技能

报告此技能的问题