Erlang LS指南(三)

工作区符号

立即跳转到您正在寻找的模块。

001

折叠(folding)

专注于重要的事情,放弃其余的。

002

代码片段

快速插入参数化、可重用的代码片段。

003

类型规格(Type Specs)的自动建议

使用类型信息进行 Erlang 程序的类型注释。

004

调用层次(Call Hierarchy )结构

Call Hierarchy 功能可让您探索给定函数的调用者(称为传入调用),以及显示给定函数调用了哪些函数(称为传出调用)。

有关调用层次结构的概述,请观看此视频

VS Code

005

要显示 Call Hierarchy 面板,请右键单击函数名称并选择 Show Call Hierarchy。 您可以使用新打开的面板在调用层次结构中导航。

要在传入调用和传出调用之间切换,只需使用面板右上角的call图标。

Emacs

006

该功能由 lsp-treemacs 包提供。

要显示传入调用层次结构:

M-x lsp-treemacs-call-hierarchy

要显示传出调用层次结构:

C-u M-x lsp-treemacs-call-hierarchy

有关更多信息,请参阅官方 lsp-treemacs 文档。

Code Actions

代码操作是一种在错误或警告旁边为用户提供可能的纠正操作的机制。 如果有可用的操作,错误或警告旁边会出现一个灯泡或类似图标。 当用户单击灯泡(或点击快捷方式)时,会显示可用代码操作的列表。

目前 Erlang LS 支持以下代码操作:

  • 导出未使用的函数
  • 在未使用的变量前添加下划线 (_)
  • 更正未绑定变量的错误名称
  • 修复模块名称以匹配相应的文件名

相关配置

erlang_ls.config 文件

可以通过名为 erlang_ls.config 的配置文件自定义 erlang_ls 服务器的行为。 erlang_ls.config 文件应放置在给定项目的根目录中,以存储该项目的配置。

示例 erlang_ls.config 文件如下所示:

otp_path: "/path/to/otp/lib/erlang"
deps_dirs:
  - "lib/*"
diagnostics:
  enabled:
    - crossref
  disabled:
    - dialyzer
include_dirs:
  - "include"
  - "_build/default/lib"
lenses:
  enabled:
    - ct-run-test
  disabled:
    - show-behaviour-usages
macros:
  - name: DEFINED_WITH_VALUE
    value: 42
  - name: DEFINED_WITHOUT_VALUE
code_reload:
  node: node@example

文件格式为 yaml。

可以进行以下自定义:

参数说明
apps_dirs包含项目应用程序的目录列表。它支持通配符。
code_reload是否应该对远程节点进行 rpc 调用以编译和重新加载模块
deps_dirs包含依赖项的目录列表。它支持通配符。
diagnostics自定义活动诊断列表。请参阅下面的可用诊断列表。
include_dirs作为包含目录提供给编译器的目录列表。它支持通配符。
incremental_sync是否支持客户端中文本更改的增量同步。默认启用。
lenses自定义活动code lenses列表
macros要传递给编译器的自定义宏列表,表示为名称/值对。如果该值被省略或无效,则使用“真”。
otp_apps_exclude不会被索引的 OTP 应用程序列表(默认:megaco、diameter、snmp、wx)
otp_pathOTP 安装路径
plt_pathDialyzer PLT 文件的路径。如果没有提供,Dialyzer诊断将不可用。
code_path_extra_dirserlang_ls 将使用代码add_path/1添加的通配符路径列表
elvis_config_path elvis.config文件的路径。默认为 ROOT_DIR/elvis.config
exclude_unused_includes从 Unused Includes 警告中排除的包含文件列表
compiler_telemetry_enabled启用后,发送telmetry/event LSP 消息,其中包含文件中存在的任何诊断的代码字段。默认为假。

诊断

打开或保存文件时,会在后台运行诊断列表,将代码库的最终问题报告给编辑器。 可以使用以下诊断:

诊断名称用途默认值
bound_var_in_pattern报告已在模式中绑定的变量(受 pinning 运算符的启发)enabled
compiler报告来自 Erlang 编译器的内联警告和错误enabled
crossref使用来自 Erlang LS 数据库的信息来找出未定义函数disabled
dialyzer使用 dialyzer 静态分析工具查找代码中的差异enabled
elvis使用 elvis 查看 Erlang 代码的样式enabled
unused_includes警告包含但未使用的头文件enabled
unused_macros警告已定义但未使用的宏enabled

可以为特定项目定制诊断。 例如:

diagnostics:
  disabled:
    - dialyzer
  enabled:
    - crossref

自动代码重新加载

code_reload 采用以下选项:

参数描述
node为代码重新加载而调用的节点。 例如 erlang_ls@hostname

Code Lenses

Code Lenses 也可以在 Erlang LS 中使用。 Erlang LS 提供以下lenses:

Code Lens 名称用途
ct-run-test在通用测试用例旁边显示一个运行按钮
function-references显示对函数的引用数
server-info在每个模块的顶部显示一些 Erlang LS 服务器信息。 仅用于调试。
show-behaviour-usages显示实现行为的模块数量
suggest-spec使用来自Dialyzer的信息来建议spec

默认启用以下code lenses:show-behaviour-usage 可以为特定项目定制code lenses。 例如:

lenses:
  enabled:
    - ct-run-test
  disabled:
    - show-behaviour-usages

全局配置

也可以将系统范围的默认配置存储在位于 User Config 目录中的 erlang_ls.config 文件中。 User Config 目录的确切位置取决于所使用的操作系统,可以通过在 Erlang shell 上执行以下命令来识别它:

> filename:basedir(user_config, "erlang_ls").

通常,User Config 目录的位置是:

操作系统User Config 目录
Linux/home/USER/.config/erlang_ls
OS X/Users/USER/Library/Application\ Support/erlang_ls
Windowsc:/Users/USER/AppData/Local/erlang_ls

因此,例如在 Linux 上,默认配置文件的完整路径是 /home/USER/.config/erlang ls/erlang ls.config

常见配置

许多 Erlang 存储库都遵循相同的结构。 我们在本节中包含了常见的 Erlang LS 配置,以便于重用。

rebar3 项目

以下配置可用于大多数基于 rebar3 的项目。

apps_dirs:
  - "_build/default/lib/*"
include_dirs:
  - "_build/default/lib/*/include"
  - "include"

rebar3 umbrella 项目

如果您的 rebar3 项目包含多个应用程序(例如,在应用程序文件夹中),您可能需要调整您的 Erlang LS 配置,如下所示。

apps_dirs:
  - "apps/*"
deps_dirs:
  - "_build/default/lib/*"
include_dirs:
  - "apps"
  - "apps/*/include"
  - "_build/default/lib/"
  - "_build/default/lib/*/include"

The erlang/otp repository

为了能够在 erlang/otp 存储库中使用主要的 Erlang LS 功能,以下最小配置就足够了。

otp_path: "/path/to/otp"
apps_dirs:
  - "lib/*"
include_dirs:
  - "lib"
  - "lib/*/include"

相关讨论

Boost your Productivity with the Erlang Language Server

2020-09-11 Code BEAM Stockholm (Virtual)

为编程语言实现自动完成或转到定义等功能并非易事。 传统上,必须为每个开发工具重复这项工作,并且需要目标编程语言和所选开发工具内部使用的编程语言的专业知识组合。

一个绝妙的直觉,“语言服务器协议”(LSP),改变了游戏规则。 对 Erlang 社区来说是一个真正的祝福。

论文

提及 Erlang LS 的学术论文列表如下:

  • B.Benavides, L.Castro, 2021 – Detecting Oxbow Code in Erlang Codebases with the Highest Degree of Certainty – Proceedings of the 20th ACM SIGPLAN International Workshop on Erlang (Erlang ’21).

如何使用调试器

Erlang LS 通过Debug Adapter Protocol(简称 DAP)提供调试功能。 鉴于协议与编辑器无关的特性,所有支持 DAP 协议的文本编辑器和 IDE 都可以进行调试。 这是 Emacs 中调试会话的样子:

007

当前的底层实现基于 Erlang/OTP 附带的 Erlang 解释器。 顺便说一句,官方 OTP 调试器也由同一个解释器提供支持。

在本教程中,我们将引导一个示例项目,看看我们如何使用 Erlang LS 调试我们的代码。

安装调试器

Erlang LS 中通过名为 els_dap 的单独可执行文件(Erlang escript)提供了调试功能。

VS Code

该可执行文件与 Erlang LS 扩展捆绑在一起,因此不需要任何额外的安装步骤。 您可以通过指定不同的 DAP 路径来配置 Erlang LS 扩展以使用自定义版本的调试器:

Extension Settings > DAP Path

Emacs

如果您使用的是 Emacs,那么您很可能是从源代码构建 Erlang LS。 要生成 els_dap 脚本:

rebar3 as dap escriptize

或者简单地说:

make

然后,您将在以下位置找到 els_dap 脚本:

_build/dap/bin/els_dap

确保生成的 els_dap escript 位于 Emacs 已知的 PATH 中。

官方 dap-mode 包支持 Erlang,因此需要该包和 Erlang 插件:

(require 'dap-mode)
(require 'dap-erlang)

您可以参考官方 dap-mode 文档以获取有关如何安装和配置 dap-mode 软件包及其插件的更多信息。

设置示例项目

为了展示 Erlang LS 调试器,我们将使用 Cowboy 网络服务器中的 Hello World 示例。 让我们从clone项目开始:

git clone https://github.com/ninenines/cowboy.git
cd cowboy/examples/hello_world

该项目使用 erlang.mk 构建系统和 relx 发布汇编器。 为了能够在我们的示例项目中使用调试器,我们需要对项目进行两个小的修改:

  • 包含 Erlang 调试器作为依赖项
  • 告诉 erlang.mk 符号链接版本中的 hello_world 应用程序

要将调试器添加为依赖项,请将以下行添加到项目的 Makefile 中的 include ../../erlang.mk 行之前:

LOCAL_DEPS = debugger

要对应用程序进行符号链接,请将以下行添加到 relx.config 文件中:

{overrides, [{hello_world, "../hello_world"}]}.

我们现在可以运行我们的网络服务器:

make run

以上应该会导致终端中运行一个新的 Erlang 节点,名为 hello_world_example@[HOSTNAME]。

我们现在应该可以将浏览器指向 http://localhost:8080 以查看我们辉煌的 Hello world!字符串。

让我们保持服务器运行。 打开一个新终端并继续执行以下步骤。

创建启动配置

我们需要告诉调试器如何连接到正在运行的节点。 我们将通过启动配置来做到这一点。

VS Code

导航到 Run and Debug 面板并单击 Create a launch.json file 链接并选择 Erlang OTP Debugger 选项。

008

这将在 .vscode/launch.json 中创建一个文件。 将文件内容替换为以下内容:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Existing Erlang Node",
            "type": "erlang",
            "request": "attach",
            "projectnode": "hello_world_example",
            "cookie": "hello_world_example",
            "timeout": 300,
            "cwd": "${workspaceRoot}"
        }
    ]
}

Emacs

我们需要在项目的顶层目录中创建一个名为 launch.json 的文件。 在我们的例子中,该文件将驻留在 cowboy/examples/hello_world/launch.json 中:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Existing Erlang Node",
            "type": "erlang",
            "request": "attach",
            "projectnode": "hello_world_example",
            "cookie": "hello_world_example",
            "timeout": 300
        }
    ]
}

添加断点

VS Code

访问 src/toppage_h.erl 文件并通过单击与 init/2 函数体的第一行对应的行号旁边的来添加断点。

009

Emacs

导航到 src/toppage_h.erl,移动到 init/2 函数体的第一行并运行:

M-x dap-breakpoint-add

010

Related Posts

2021 年你需要知道的关于 Erlang 的一切

今天,我们将看一个相当古老且有些古怪的东西。 你们大多数人可能没有注意到的语言。 虽然 Erlang 不像某些现代编程语言那样流行,但它安静地运行着 WhatsApp 和微信等每天为大量用户提供服务的应用程序。 在这篇文章中,我将告诉你关于这门语言的更多事情、它的历史,以及你是否应该考虑自己学习它。 ## 什么是 Erlang,它在哪里使用? Erl

Read More

Erlang JIT中基于类型的优化

这篇文章探讨了 Erlang/OTP 25 中基于类型的新优化,其中编译器将类型信息嵌入到 BEAM 文件中,以帮助JIT(即时编译器)生成更好的代码。 ## 两全其美 OTP 22 中引入的基于SSA的编译器处理步骤进行了复杂的类型分析,允许进行更多优化和更好的生成代码。然而,Erlang 编译器可以做什么样的优化是有限制的,因为 BEAM 文件必须

Read More

Erlang JIT之路

自从Erlang 存在,就一直有让它更快的需求和野心。这篇博文是一堂历史课,概述了主要的 Erlang 实现以及如何尝试提高 Erlang 的性能。 ## Prolog 解释器 Erlang 的第一个版本是在 1986 年在 Prolog 中实现的。那个版本的 Erlang 对于创建真正的应用程序来说太慢了,但它对于找出Erlang语言的哪些功能有用,哪

Read More