编程语言服务器协议 已翻译 100%

oschina 投递于 2018/11/08 12:12 (共 14 段, 翻译完成于 11-22)
阅读 3821
收藏 10
2
加载中

上个月,Apple 在 Swift.org 论坛上宣布,它正在开始采用 Swift 和 C 语言的语言服务器协议(LSP)

在 Apple,我们优先考虑为所有 Swift 开发者提供高质量的工具,包括那些在不在 Apple 平台上开发的开发者。我们希望和开源社区合作并且集中精力建设可以由 Xcode 和其他编辑器和平台共享的公共基础设施,因此,我们选择采用 LSP。

Argyrios Kyrtzidis,2018年10月15日

工匠驿站
工匠驿站
翻译于 2018/11/09 18:39
0

这可以说是自 2014 年 Swift 开源发布以来苹果公司对 Swift 做出的最重要的决定。这是苹果应用开发者的大事件,更是在其它平台的 Swift 开发者的大事件。

为什么这件事情这么重要?本文会对语言服务协议进行介绍,讲解它能解决什么问题,如何解决这些问题,以及可能会带来什么样的长期影响。

我们假设有这样一个表格,它的行代表不同的编程语言(Swift、JavaScript、Ruby、Python 等),每一列代表不同的代码编辑器(XCode、Visual Studio、Vim、Atom 等)。这样一来,表内的每个单元格都表示某个编辑器对某种语言的支持程度。

边城
边城
翻译于 2018/11/16 11:48
0

现在,你会发现不同的组合之间兼容性很差。有一些编辑器对少数几种语言进行了深度集成,几乎不支持任何其他语言,也有一些编辑器则致力于支持语言的通用特性,对大量的语言进行了较为浅层的支持。(IDE 通常是指前者。)

举例来说,不使用 XCode 开发苹果应用是件很难理解的事情,而使用 XCode 开发其它东西简直就是傻

为了让编辑器对语言支持得更好,它需要编写集成语言特性的代码 —— 直接在项目代码中编写,或者采用插件系统的方式。语言和编辑器之间会存在差异,比如在 Vim 中改进了对 Ruby 的支持并不能同时让 Vim 对 Python 支持得更好,也不能让 Ruby 在 Atom 中更好地工作。结果就是:对各种技术之的支持不能达成一致,会浪费大量的精力。

这里描述的情况通常被称为 M × N 问题,它要处理的问题数是 M 种编辑器和 N 语言的乘积。语言服务协议要做的就是把 M × N 的问题变成 M + N 的问题。

边城
边城
翻译于 2018/11/16 12:04
0

编辑器不用支持每一种语言,只需要支持 LSP。然后,所有支持 LSP 的语言都会在这个编辑器中得到相同级别的支持。

Tomohiro Matsuyama 在 2010 年写了一篇标题为 “Emacs は死んだ” (“Emacs 已死”) 的文章,对这个问题进行了很好地总结。Matsuyama 在描述 Emacs 脚本语言的局限(没有多线程、低层次的 API 少、用户群不大)时提出他的观点。他认为插件应该与外部程序接口,而不应该是本地实现。

边城
边城
翻译于 2018/11/16 14:54
0

语言服务器协议对其支持的语言提供了一系列通用的功能,包括:

  • 语法高亮

  • 自动格式化

  • 自动完成

  • 语法(检查)

  • 提示

  • 内部诊断

  • 跳转到定义

  • 在项目中查找引用

  • 高级文本或符合搜索

在 LSP 的支持下,工具和编辑器可以更加专注于处理可用性和高级功能,而不需要为每个新技术做重复性的工作。

边城
边城
翻译于 2018/11/16 15:18
0

语言服务协议是怎么起作用的

如果你是 iOS 开发者,你可能最熟悉的“服务”和“协议”概念是建立在 Web 应用基于 HTTP 和 JSON 的通信技术之上。这实际上与语言服务协议如何工作并没多大关系。

对于 LSP 来说,客户端就是编辑器 —— 或者更普适性的说法是工具 —— 而服务端是指运行在本地另一个进程中的外部程序。

作为协议本身,LSP 有点像 HTTP 的简单版:

  • 每个消息都包含头和内容两个部分。

  • 头部需要用 Content-Length 参数来描述内容部分的字节数,以及可选的 Content-Type 参数(默认是 application/vscode-jsonrpc; charset=utf-8

  • 内容部分是请求、响应和通知的内容,其数据结构遵循 JSON-RPC 规范。

边城
边城
翻译于 2018/11/16 15:34
0

一旦工具有变化,比如用户条到了一个标记的定义之类的,工具都会向服务端发送一个请求。服务端收到这个请求之后返回对应的响应。

例如,想象一下用户在一个支持编程语言服务协议的类Xcode的编辑器中打开如下Swfit代码:

Swift

class Parent {}
class Child: Parent {}

当用户 ⌘-单击第二行的继承语句中的 Parent 标记的时候,编辑器跳到了第一行的 Parent  类定义处。

adoontheway
adoontheway
翻译于 2018/11/16 20:56
0

以下是LSP如何在银幕背后让这个交互实现的:

首先,当用户打开 Swfit 代码的时候,编辑器在一个单独的进程中启动了他的 Swift语言服务器,如果没有运行起来的话,会实施一些额外的设置。

当用户执行 “跳转到定义” 的命令时,编辑器将如下请求发送到 Swift语言服务器:

JSON

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "textDocument/definition",
  "params": {
    "textDocument": {
      "uri": "file:///Users/NSHipster/Example.swift"
    },
    "position": {
      "line": 1,
      "character": 13
    }
  }
}
adoontheway
adoontheway
翻译于 2018/11/16 21:00
0

收到这个请求之后, Swift 语言服务使用像 SourceKit 这样的编译工具把代码实体标识出来,并在前面的代码中查找其声明位置。语言服务随后响应这样的消息:

JSON

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "uri": "file:///Users/NSHipster/Example.swift",
    "range": {
      "start": {
        "line": 0,
        "character": 6
      },
      "end": {
        "line": 0,
        "character": 12
      }
    }
  }
}

 最后,编辑器导航到相应的文件(示例中就是打开的这个文件),将光标移动到响应指示的位置,把标识高亮显示出来。

这种方法的美妙之处在于编辑器在做这些事情的时候,不需要知道任何与 Swift 编译语言相关的事情,它在乎 .swift 文件与 Swift 代码之间的关联。编辑器需要做的事情就是与语言服务对话,并更新 UI。只要编辑器能做这件事情,那就可以按照相同的处理过程,实现任意语言的代码与相应的语言服务之间进行交互。

边城
边城
翻译于 2018/11/19 20:54
0

Clang/LLVM的语言服务协议支持

如果上面的M + N的图看起来很熟悉,可能是因为LLVM采用了相同的方法。

LLVM的核心是一个中间表示(IR)。支持的语言使用前端编译器生成IR,然后该IR可以生成任何后端编译器所支持的平台的机器码。

如果你对关于Swift代码如何编译感兴趣,请阅读我们关于SwiftSyntax的文章

琪花亿草
琪花亿草
翻译于 2018/11/19 10:39
0
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(7)

y
yuu2lee4
不就是vscode?
海淀游民
海淀游民

引用来自“LinkerLin”的评论

Swift和苹果绑定,但是现在苹果的手机和平板并不好卖了。
海军资助的"自媒体" 能信?看京东的评价数,iPhone X Max(最贵的那款) 单品的评价数是 华为 Mate 20 Pro 全系列的五倍还多
LinkerLin
LinkerLin
Swift和苹果绑定,但是现在苹果的手机和平板并不好卖了。
fy0
fy0
我还奇怪呢 微软不是早就搞了并在vscode里大规模使用来支持自动完成了吗?
昵称非法已被屏蔽
用了微软的LSP,文章没提到微软半个字。
白衣卿卿
白衣卿卿
bhh
全体人员
全体人员
微软拯救世界系列?正是语言服务协议让vscode所向披靡。
返回顶部
顶部