一句话:介绍 OCaml 语言服务器 Merlin 的设计经验,聚焦增量处理、不完整程序与编辑器交互。
本文是 Merlin 的开发经验报告。Merlin 自 2013 年起开发,作为守护进程连接编辑器,为 OCaml 提供警告与错误即时反馈、自动补全、光标处类型、跳转到定义等服务。语言服务器需处理不完整甚至部分错误的程序,并在小编辑后增量更新以减少重算。作者通过改造 OCamllex 与 Menhir,使其更好支持增量性、不完整输入和错误恢复;这些扩展通用且优雅,并被社区发现出意外用途,也可用于其他语言前端。文章还讨论 Merlin 与编辑器的通信方式、若干高要求特性背后的设计决策,以及构建良好编辑器支持时来自表达力强语言或工具生态的非显性困难。
We report on the experience of developing Merlin, a language server for the OCaml programming language in development since 2013. Merlin is a daemon that connects to your favourite text editor and provides services that require a fine-grained understanding of the programming language syntax and static semantics: instant feedback on warnings and errors, autocompletion, "type of the code under the cursor", "go to definition", etc. Language servers need to handle incomplete and partially-incorrect programs, and try to be incremental to minimize recomputation after small editing actions. Merlin was built by carefully adapting the existing tools (the OCamllex lexer and Menhir parser generators) to better support incrementality, incompleteness and error handling. These extensions are elegant and general, as demonstrated by the interesting, unplanned uses that the OCaml community found for them. They could be adapted to other frontends -- in any language. Besides incrementality, we discuss the way Merlin communicates with editors, describe the design decisions that went into some demanding features and report on some of the non-apparent difficulties in building good editor support, emerging from expressive programming languages or frustrating tooling ecosystems. We expect this experience report to be of interest to authors of interactive language tooling for any programming language; many design choices may be reused, and some hard-won lessons can serve as warnings.
@article{paperbot292,
title = {Merlin: a language server for OCaml (experience report)},
author = {Frédéric Bour and Thomas Refis and Gabriel Scherer},
journal = {Proceedings of the ACM on Programming Languages},
volume = {2},
number = {ICFP},
year = {2018},
doi = {10.1145/3236798}
}