5

我试图通过将语言定义添加到 VSC 来使 VSC 显示包含 DSL(域特定语言)的文档的结构。该结构应出现在 VSC“大纲视图”中,其中显示已安装语言的所有文档结构(如 json、markdown、html 等)

DSL 非常简单,只有一些大写字母的元素应该出现在大纲中并保持层次结构:

WORD xxx
GRAMMAR xxx
STRUCTURE xxx xxx
     xxx xxx xxx xxx
MEANING xxx xxx xxx 
    SUB_MEANING xxx xxx xxx xxx
        SUB_SUB_MEANING xxx xxx xxx

我遵循了关于 stackoverflow 的所有提示,这些提示都导致了 VSC 和/或语言服务器协议 (LSP) 的官方文档。但是,没有任何帮助,一点也没有 -.- 是的,我可以使用 CodeMap 扩展,但我不想依赖它,因为 VSC 实际上能够理解新语言。对于众所周知的语言,不需要创建专用的树视图元素或其他东西,因此必须有一种方法让 VSC 解析语言结构。

VSC 中的“大纲视图”仍然为空。我发现如果删除 VSC 扩展文件夹中的文件夹“xxx-language-features”(xxx 代表语言),安装的(例如)markdown 或 json 的语言支持也不会为“大纲”生成任何内容. 所以看来我也需要一个语言功能扩展。

我浏览了https://code.visualstudio.com/api/language-extensions/language-configuration-guidehttps://microsoft.github.io/language-server-protocol/以及许多其他东西,包括 LSP-example来自 VSC 的 Github-Repo,但对此没有任何帮助。我还尝试借助“哟代码”创建一种新语言。没有什么。Microsoft 提供的 LSP 示例是针对纯文本文件的……为纯文本创建语言服务器有多大用处?!我想举一个关于语言的例子。查看扩展中的已编译文件无济于事,因为它们已被缩小。

在该问题上没有完整的“如何做” - 因此,感谢任何帮助!如何告诉 VSC 将文档结构解析为“大纲视图”?

4

3 回答 3

5

你有几种方法可以解决这个问题,你可以:

  1. 创建一个 IDE 独有的扩展来完成所有工作(解析文件、理解所有标记的含义并提供符号列表等)
  2. 通过使用实现Microsoft 指定的语言服务器协议的语言服务器来创建语言服务器客户端扩展。在这种情况下,您的 VSCode 扩展本质上将是一个启动语言服务器并与之通信的“shell”扩展。如何处理服务器返回的信息已经由vscode-languageclient包的LanguageClient类开箱即用地实现了。

选项 2. 有一个巨大的优势:它修复了 N*M 问题:所有支持语言服务器协议的编辑器都可以与您的语言服务器通信,因此可以轻松地为多个编辑器(VSCode、Visual Studio、Atom、Vim)提供语言支持, emacs 等, IntelliJ 以有限的方式使用 3rd 方插件) 以最小的努力。

在您的问题中,我不清楚您是否打算编写一个可以完成所有工作的扩展程序,或者您是否打算开发一个语言服务器和一个语言客户端扩展程序来配合它。

答案实际上取决于您的语言(或 DSL)的复杂性。如果它有一些复杂的语法并且你已经有一个编译器,那么制作一个语言服务器是有意义的,因为大部分解析和逻辑已经在编译器中实现了。如果您的语言真的像您给出的示例一样简单并且没有语法,那么它可能是矫枉过正的。

如果你走“语言服务器”路线,那么有不同语言的库可以简化服务器的实现,它们负责 LSP 的 JSON-RPC 部分,你只需要覆盖语言服务器定义的方法协议(例如,用于任何 JVM 语言的 LSP4J,或用于NodeJS 的 vscode-languageserver(尽管它的名称,该包并不特定于 VSCode))。在这种情况下,用符号的层次结构填充 VSCode 的大纲视图只需要您在语言服务器中实现textDocument/documentSymbol请求,而无需在扩展中执行其他任何操作,它由vscode-languageclient包的LanguageClient类负责!

  • 如果您的语言客户端支持分层文档符号:在语言服务器initialize方法中,您将收到 InitializeParams textDocument.documentSymbol.hierarchicalDocumentSymbolSupport == true(VSCode 确实支持这一点)然后您返回DocumentSymbol[](它有一个children属性,从而为您的客户端提供符号树)。
  • 如果您的语言服务器客户端不支持分层文档符号(例如 Visual Studio),那么您返回SymbolInformation[],这是一个平面符号列表。

需要注意的一件重要事情:VSCode在显示符号树(在大纲视图中)时会考虑 的range属性。DocumentSymbol您的子符号range必须包含在其父range符号中,否则 VSCode 将不会在大纲视图中显示任何符号,即使您的符号树结构和selectionRanges 是正确的。这range定义范围(符号的整个定义,例如对于打字稿类,它从关键字开始class并以结束符结束})并且selectionRange通常只是符号的标记范围(但根据规范,它还可以包括doc 注释块和可见性修饰符,这是实现者的选择)。例如

class MyClass {
  /**
   * Some method documentation
   */
  private function myFunction(param1) {
    console.log(param1);
  }
}

在这种情况下,范围将是

rangeOfClass = {
  "start": { "line": 0, "character": 0 },
  "end": { "line": 7, "character": 1 }
};
rangeOfMethod = {
  "start": { "line": 4, "character": 2 },
  "end": { "line": 6, "character": 3 }
};

并且 selectionRange 可能只是符号的名称

selectionRangeOfClass = {
  "start": { "line": 0, "character": 6 },
  "end": { "line": 0, "character": 13 }
};
selectionRangeOfMethod = {
  "start": { "line": 4, "character": 19 },
  "end": { "line": 4, "character": 29 }
};

或者它可以包括从文档、关键字和修饰符到符号的末尾

selectionRangeOfClass = {
  "start": { "line": 0, "character": 0 },
  "end": { "line": 0, "character": 13 }
};
selectionRangeOfMethod = {
  "start": { "line": 1, "character": 2 },
  "end": { "line": 4, "character": 29 }
};

有了这个,你会得到一个很好的大纲: 在此处输入图像描述

于 2020-07-23T18:25:41.377 回答
1

大纲视图由Document Symbols Request填充。面包屑导航也是如此,当然还有常规的文档符号弹出窗口(Go → Go to Symbol in File...)。

层次结构是通过使用DocumentSymbol.children而不是返回平面列表来实现的。

于 2019-04-25T12:56:01.130 回答
1

我在错误的地方寻找解决方案,在浪费了几天之后,我可能会因为树木而错过森林。然后,一位同事对这个问题进行了处女的研究,几个小时后他想出了下面的解决方案。基本上,DocumentSymbolProvider是一个人所需要的。

搜索此关键字会提供一些示例,例如此处。然而,官方文档只提供了您可以创建实例的信息,而有关如何使用它的重要代码由.... 哇-这就是我所说的医生-.-

仍然有一些不清楚的地方,但至少我们现在可以使用该基础:

class MLWDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
public provideDocumentSymbols(document: vscode.TextDocument,
        token: vscode.CancellationToken): Thenable<vscode.SymbolInformation[]> {
    return new Promise((resolve, reject) => {

      // that's the important variable. It must be a multidimensional array, one dimension for each level you need to display.
      let symbols = [];

      let icon_main = vscode.SymbolKind.Class;
      let icon_second = vscode.SymbolKind.Field;
      let icon_third = vscode.SymbolKind.String;

      // check each line of the document about your keywords
      for (let i = 0; i < document.lineCount; i++) {
        let line = document.lineAt(i);
        if(line.text.trim().startsWith("WORD")) {
          symbols.push(new vscode.DocumentSymbol("Level 1: WORD", document.lineAt(i+1).text.trim(), icon_main, line.range, line.range ));
        } /* elses for the levels below */
       }

      resolve(symbols);
        });
    }

}

我猜 Gamma11 的答案很接近,不知何故。由于官方文档中缺乏关于在何处以及如何使用它的信息,不幸的是它并不能真正帮助我们。

获得有关 VSC 编码的知识似乎非常困难,因为除了基本结构之外,文档没有提供太多信息。如果有人知道某个站点包含有关类/接口/功能的完整示例或描述,请发表评论。在近 20 年的编码中,我从未见过如此庞大的项目如此缺乏文档,其中主要部分由对象表示...或根本没有对象 -.-

于 2019-05-02T08:54:28.460 回答