制詳解)
開發(fā)工具【免費(fèi)下載鏈接】language-server-protocolDefines a common protocol for language servers.項(xiàng)目地址https://gitcode.com/gh_mirrors/la/language-server-protocol點(diǎn)擊查看免費(fèi)下載Code Lens代碼透鏡是 LSPLanguage Server Protocol中一類特殊的界面增強(qiáng)能力它允許語言服務(wù)器在編輯器中的源碼文本行上方渲染一個(gè)可點(diǎn)擊的交互提示例如“N 處引用”“運(yùn)行測試”“查看實(shí)現(xiàn)”等。本文以當(dāng)前倉庫 codeLens.md 為骨架結(jié)合倉庫內(nèi)的 metaModel.json 元模型定義系統(tǒng)講解 3.17 規(guī)范中 Code Lens 的完整消息鏈路textDocument/codeLens、codeLens/resolve、workspace/codeLens/refresh、全部類型定義、能力協(xié)商與動(dòng)態(tài)注冊方式并給出可直接落地的實(shí)戰(zhàn)示例。讀完本文你將能夠?yàn)樽约旱恼Z言服務(wù)器實(shí)現(xiàn) Code Lens 的計(jì)算、惰性解析與項(xiàng)目級刷新同時(shí)理解客戶端應(yīng)如何聲明能力并消費(fèi)這些請求。一、Code Lens 在 LSP 中的定位Code Lens 與普通 hover、補(bǔ)全等請求的最大區(qū)別在于兩點(diǎn)它附著在源碼文本上每個(gè) Code Lens 都通過range與文檔中的某個(gè)通常是單行的區(qū)域綁定它的核心價(jià)值是命令化——每個(gè) Code Lens 本質(zhì)上是一個(gè)可執(zhí)行的Command如運(yùn)行測試、查看引用數(shù)用戶點(diǎn)擊透鏡文本即可觸發(fā)對應(yīng)操作。協(xié)議為 Code Lens 設(shè)計(jì)了兩階段模型先批量計(jì)算未解析unresolved的透鏡只有 range沒有 command再按需逐條解析出真正的命令。這樣做的目的在規(guī)范中寫得很明確——性能計(jì)算 code lens 和解析 command 是兩個(gè)階段避免一次性為所有透鏡生成完整命令帶來不必要的開銷見 codeLens.md 中CodeLens接口注釋。二、能力協(xié)商Client Capability 與 Server Capability與所有 LSP 功能一樣Code Lens 在使用前需要經(jīng)過initialize階段的能力協(xié)商。相關(guān)定義位于 initialize.md 描述的初始化握手流程中。2.1 客戶端能力textDocument.codeLens客戶端在initialize請求的capabilities.textDocument中聲明export interface CodeLensClientCapabilities { /** * Whether code lens supports dynamic registration. */ dynamicRegistration?: boolean; }dynamicRegistration可選客戶端是否支持對 code lens 進(jìn)行動(dòng)態(tài)注冊。如果為true服務(wù)器可以在運(yùn)行時(shí)通過client/registerCapability動(dòng)態(tài)注冊/注銷 code lens 提供者否則服務(wù)器只能在初始化時(shí)靜態(tài)聲明。對應(yīng)能力屬性名為textDocument.codeLens見 codeLens.md 中的 Client Capability 一節(jié)。2.2 服務(wù)端能力codeLensProvider服務(wù)器在initialize響應(yīng)的capabilities.codeLensProvider中聲明export interface CodeLensOptions extends WorkDoneProgressOptions { /** * Code lens has a resolve provider as well. */ resolveProvider?: boolean; }resolveProvider可選服務(wù)器是否額外實(shí)現(xiàn)了codeLens/resolve解析處理器。這是兩階段模型的關(guān)鍵開關(guān)為false時(shí)服務(wù)器在textDocument/codeLens返回的每個(gè)透鏡都必須自帶完整的command為true時(shí)服務(wù)器可以先返回只有range和data的未解析透鏡客戶端在需要時(shí)如用戶點(diǎn)擊透鏡再發(fā)送codeLens/resolve請求。CodeLensOptions還繼承了WorkDoneProgressOptions意味著服務(wù)器可以在 code lens 請求處理期間通過$/progress上報(bào)工作進(jìn)度工作進(jìn)度相關(guān)定義見 workDoneProgress.md。2.3 注冊選項(xiàng)CodeLensRegistrationOptions無論是靜態(tài)注冊初始化響應(yīng)還是動(dòng)態(tài)注冊client/registerCapabilitycode lens 提供者的注冊選項(xiàng)統(tǒng)一為export interface CodeLensRegistrationOptions extends TextDocumentRegistrationOptions, CodeLensOptions { }它同時(shí)繼承了TextDocumentRegistrationOptions聲明該提供者適用于哪些文檔通過documentSelector指定語言/模式過濾條件相關(guān)定義見 textDocumentRegistrationOptions 相關(guān)類型頁CodeLensOptions即上述服務(wù)端能力含resolveProvider與工作進(jìn)度選項(xiàng)。在 metaModel.json 中CodeLensRegistrationOptions被建模為同時(shí)extends這兩個(gè)接口的結(jié)構(gòu)對應(yīng)條目中extends數(shù)組包含TextDocumentRegistrationOptions與CodeLensOptions。三、主請求textDocument/codeLens3.1 請求定義當(dāng)客戶端需要為一個(gè)文本文檔計(jì)算 code lens 時(shí)發(fā)送請求項(xiàng)目值methodtextDocument/codeLensparamsCodeLensParamsresultCodeLens[]|nullpartial resultCodeLens[]errorcode 與 message請求處理期間發(fā)生異常時(shí)設(shè)置參數(shù)類型interface CodeLensParams extends WorkDoneProgressParams, PartialResultParams { /** * The document to request code lens for. */ textDocument: TextDocumentIdentifier; }textDocument要計(jì)算 code lens 的目標(biāo)文檔標(biāo)識TextDocumentIdentifier見 textDocumentIdentifier.md繼承WorkDoneProgressParams可附帶工作進(jìn)度令牌繼承PartialResultParams可附帶部分結(jié)果令牌客戶端支持時(shí)服務(wù)器可通過$/partialResult分塊返回透鏡列表相關(guān)基礎(chǔ)見 partialResultParams.md 與 partialResults.md。在元模型中該請求被正式記錄為clientToServer方向的消息textDocument/codeLens其result為CodeLens[] | nullpartialResult為CodeLens[]registrationOptions為CodeLensRegistrationOptions見 metaModel.json 中 method 為textDocument/codeLens的 request 條目。3.2 結(jié)果類型CodeLens/** * A code lens represents a command that should be shown along with * source text, like the number of references, a way to run tests, etc. * * A code lens is _unresolved_ when no command is associated to it. For * performance reasons the creation of a code lens and resolving should be done * in two stages. */ interface CodeLens { /** * The range in which this code lens is valid. Should only span a single * line. */ range: Range; /** * The command this code lens represents. */ command?: Command; /** * A data entry field that is preserved on a code lens item between * a code lens and a code lens resolve request. */ data?: LSPAny; }三個(gè)字段的含義range必填該透鏡在文檔中生效的區(qū)間。規(guī)范明確要求應(yīng)當(dāng)只跨越單行Should only span a single line這樣客戶端才能把透鏡渲染在該行上方。范圍類型Range的定義見 range.md。command可選透鏡代表的可執(zhí)行命令。未解析unresolved狀態(tài)下不攜帶該字段。命令結(jié)構(gòu)Command由titleUI 顯示的標(biāo)題、command命令處理器標(biāo)識符和可選的arguments參數(shù)數(shù)組組成完整定義見 command.md。data可選一個(gè)LSPAny任意 JSON 值字段會在textDocument/codeLens與codeLens/resolve兩個(gè)請求之間原樣保留。服務(wù)器通常用它存放定位上下文如符號 ID、文件路徑、行號等供解析階段快速還原命令而不必重新掃描整個(gè)文檔。元模型對這三個(gè)字段的建模與規(guī)范一致range為必填的Range引用command與data均為可選見 metaModel.json 中CodeLens結(jié)構(gòu)條目的properties。3.3 結(jié)果返回約定若服務(wù)器無法/不需要為該文檔提供任何透鏡應(yīng)返回null或空數(shù)組若設(shè)置了resolveProvider返回的透鏡可全部為未解析狀態(tài)僅rangedata響應(yīng)中的錯(cuò)誤字段用于在異常如文檔不存在、內(nèi)部錯(cuò)誤時(shí)返回code與message。四、惰性解析codeLens/resolve4.1 請求定義method: codeLens/resolve params: CodeLens result: CodeLens error: code and message解析期間發(fā)生異常時(shí)設(shè)置客戶端把某個(gè)未解析的CodeLens對象原樣回傳給服務(wù)器包含其range與data服務(wù)器據(jù)此返回補(bǔ)全了command的同一透鏡項(xiàng)目值methodcodeLens/resolveparamsCodeLensresultCodeLenserrorcode 與 message異常時(shí)設(shè)置元模型中該請求同樣被記錄為clientToServer方向params與result均為CodeLens引用見 metaModel.json 中 method 為codeLens/resolve的 request 條目。4.2 為什么需要兩階段主請求輕量化大文件可能有幾十上百個(gè)透鏡若全部立即生成命令包括計(jì)算參數(shù)響應(yīng)會顯著變大、變慢按需計(jì)算只有用戶真正查看/點(diǎn)擊某個(gè)透鏡時(shí)才觸發(fā)該透鏡的命令解析data是橋梁服務(wù)器把解析所需的最小上下文放進(jìn)dataresolve 時(shí)只需反序列化data即可定位到具體符號無需重新分析全文。一個(gè)典型實(shí)現(xiàn)模式textDocument/codeLens階段為每個(gè)候選位置創(chuàng)建{ range, data: { uri, symbolId } }不填commandcodeLens/resolve階段讀取params.data從索引/符號表中查出命令返回{ ...params, command: { title: 運(yùn)行測試, command: extension.runTest, arguments: [...] } }。五、服務(wù)端主動(dòng)刷新workspace/codeLens/refresh5.1 背景與用途自版本 3.16.0 起引入。workspace/codeLens/refresh是由服務(wù)器發(fā)給客戶端的請求方向serverToClient見 metaModel.json 中 method 為workspace/codeLens/refresh的條目標(biāo)注since 3.16.0。典型觸發(fā)場景服務(wù)器檢測到配置或項(xiàng)目范圍的變化導(dǎo)致所有已展示的 code lens 需要重新計(jì)算例如切換了測試框架、啟用了新的 linter 規(guī)則。規(guī)范特別提醒客戶端收到刷新請求后應(yīng)當(dāng)請求服務(wù)器重新計(jì)算當(dāng)前編輯器中展示的透鏡但客戶端仍有權(quán)延遲刷新——例如某個(gè)編輯器當(dāng)前不可見時(shí)可以推遲到其重新可見后再計(jì)算。5.2 客戶端能力聲明客戶端若支持該請求需要在initialize的capabilities.workspace.codeLens中聲明export interface CodeLensWorkspaceClientCapabilities { /** * Whether the client implementation supports a refresh request sent from the * server to the client. * * Note that this event is global and will force the client to refresh all * code lenses currently shown. It should be used with absolute care and is * useful for situation where a server for example detect a project wide * change that requires such a calculation. */ refreshSupport?: boolean; }refreshSupport可選自 3.16.0 起為true表示客戶端支持服務(wù)器發(fā)來的刷新請求。規(guī)范用詞是絕對小心地使用should be used with absolute care——因?yàn)樵撌录侨中缘臅?qiáng)制客戶端刷新當(dāng)前顯示的所有 code lens只應(yīng)在確實(shí)需要全局重算如項(xiàng)目級變更時(shí)使用。5.3 請求與響應(yīng)項(xiàng)目值methodworkspace/codeLens/refreshparamsnone無參數(shù)resultvoiderrorcode 與 message請求處理期間發(fā)生異常時(shí)設(shè)置調(diào)用鏈路服務(wù)器 → 客戶端 → 客戶端據(jù)此再次發(fā)送textDocument/codeLens→ 服務(wù)器重新計(jì)算 → 新透鏡渲染。整個(gè)過程形成一個(gè)服務(wù)器驅(qū)動(dòng)的刷新閉環(huán)。六、三個(gè)請求全鏈路對比請求方向methodparamsresult觸發(fā)時(shí)機(jī)Code Lens Request客戶端 → 服務(wù)器textDocument/codeLensCodeLensParamsCodeLens[] \| null可部分結(jié)果文檔打開/內(nèi)容變化/收到刷新請求Code Lens Resolve Request客戶端 → 服務(wù)器codeLens/resolveCodeLensCodeLens客戶端需要某個(gè)透鏡的命令時(shí)Code Lens Refresh Request服務(wù)器 → 客戶端workspace/codeLens/refresh無void服務(wù)器檢測到項(xiàng)目級配置變化自 3.16.0七、實(shí)戰(zhàn)示例服務(wù)端與客戶端實(shí)現(xiàn)要點(diǎn)以下給出可直接參考的實(shí)現(xiàn)骨架TypeScript 風(fēng)格幫助理解三個(gè)請求如何協(xié)同。7.1 服務(wù)器端靜態(tài)注冊與主請求在initialize響應(yīng)中聲明能力result.capabilities.codeLensProvider { resolveProvider: true // 聲明支持 codeLens/resolve };實(shí)現(xiàn)主請求connection.onRequest(textDocument/codeLens, (params: CodeLensParams): CodeLens[] | null { const doc documents.get(params.textDocument.uri); if (!doc) return null; const lenses: CodeLens[] []; for (const sym of findCandidateSymbols(doc)) { lenses.push({ range: { start: { line: sym.line, character: 0 }, end: { line: sym.line, character: sym.endColumn } }, data: { uri: params.textDocument.uri, symbolId: sym.id } // 橋梁數(shù)據(jù) }); } return lenses; });7.2 服務(wù)器端resolve 處理器connection.onRequest(codeLens/resolve, (lens: CodeLens): CodeLens { const { uri, symbolId } lens.data as ResolveData; const sym symbolTable.get(uri, symbolId); lens.command { title: 運(yùn)行 ${sym.name} 的測試, command: extension.runTest, arguments: [uri, sym.id] }; return lens; });7.3 服務(wù)器端觸發(fā)全局刷新// 檢測到項(xiàng)目配置變化時(shí) if (capabilities.workspace?.codeLens?.refreshSupport) { await connection.sendRequest(workspace/codeLens/refresh); }發(fā)送前應(yīng)檢查客戶端CodeLensWorkspaceClientCapabilities.refreshSupport是否為true避免向不支持該請求的客戶端發(fā)送老版本客戶端沒有該能力。7.4 客戶端端要點(diǎn)initialize中聲明capabilities.textDocument.codeLens { dynamicRegistration: true }capabilities.workspace.codeLens { refreshSupport: true }支持動(dòng)態(tài)注冊時(shí)可在運(yùn)行時(shí)用CodeLensRegistrationOptions含documentSelector注冊/注銷提供者收到workspace/codeLens/refresh后對可見編輯器重新發(fā)起textDocument/codeLens并允許延遲到編輯器可見時(shí)再算把CodeLens[] | null渲染為對應(yīng)range所在行上方的可點(diǎn)擊文本未解析的透鏡在用戶點(diǎn)擊/需要時(shí)再發(fā)codeLens/resolve。八、配套類型與資源索引Code Lens 功能依賴的配套類型散落在規(guī)范各頁便于深入學(xué)習(xí)Command透鏡攜帶的可執(zhí)行命令結(jié)構(gòu)title / command / argumentsRange透鏡的生效區(qū)間規(guī)范要求單行TextDocumentIdentifierCodeLensParams.textDocument的類型workDoneProgress.mdWorkDoneProgressOptions/Params的說明partialResultParams.md 與 partialResults.md部分結(jié)果機(jī)制metaModel.json機(jī)器可讀的元模型包含全部 Code Lens 相關(guān)類型與請求條目適合代碼生成與校驗(yàn)specification.md3.17 規(guī)范全文檔含各語言特性的總覽。結(jié)語Code Lens 是 LSP 中輕計(jì)算 惰性解析 全局刷新設(shè)計(jì)思想的典型代表textDocument/codeLens保證主請求足夠輕量codeLens/resolve把昂貴的命令構(gòu)造推遲到真正需要的時(shí)刻workspace/codeLens/refresh則讓服務(wù)器在項(xiàng)目級變化時(shí)主動(dòng)驅(qū)動(dòng)客戶端重算。理解并正確實(shí)現(xiàn)這三個(gè)請求含各自的能力協(xié)商字段dynamicRegistration、resolveProvider、refreshSupport是讓編輯器內(nèi)的引用計(jì)數(shù)、測試運(yùn)行等交互提示既流暢又省電的關(guān)鍵。贊分享開發(fā)工具【免費(fèi)下載鏈接】language-server-protocolDefines a common protocol for language servers.項(xiàng)目地址https://gitcode.com/gh_mirrors/la/language-server-protocol點(diǎn)擊查看免費(fèi)下載相關(guān)推薦BSC 客戶端 Debian/Ubuntu 打包指南基于 build/ci-notes.md 的 PPA 發(fā)布與本地構(gòu)建全流程BSC 客戶端 Debian/Ubuntu 打包指南基于 build/ci notes.md 的 PPA 發(fā)布與本地構(gòu)建全流程 本文以倉庫 build/ci開發(fā)工具Security-101 之 SecOps 零信任架構(gòu)集中日志收集體系設(shè)計(jì)與現(xiàn)代安全運(yùn)營最佳實(shí)踐Security 101 之 SecOps 零信任架構(gòu)集中日志收集體系設(shè)計(jì)與現(xiàn)代安全運(yùn)營最佳實(shí)踐 零信任Zero Trust不是單一產(chǎn)品而是一套以永不開發(fā)工具slime LLM 后訓(xùn)練框架完整指南用 Megatron 與 SGLang 打通強(qiáng)化學(xué)習(xí)擴(kuò)展的閉環(huán)slime LLM 后訓(xùn)練框架完整指南用 Megatron 與 SGLang 打通強(qiáng)化學(xué)習(xí)擴(kuò)展的閉環(huán) slime 是一個(gè)面向大語言模型LLM后訓(xùn)練的框架開發(fā)工具上一篇用 Forge 的 :fixme 自定義命令自動(dòng)掃描并修復(fù)代碼中的 FIXME 注釋下一篇effect/platform-node v4 變更解讀Node.js 平臺層的能力演進(jìn)與遷移指南創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考