从null-ls归档再看nvim的代码格式化与lint方案
由于null-lsp的归档和暂停更新,我们需要重新审视并思考还有哪些架构简单易于理解的插件配置方案。本文将介绍脱离null-ls插件体系下的代码格式化和lint的插件配置方案。
在之前的文章中《详解nvim内建LSP体系与基于nvim-cmp的代码补全体系 - 知乎 (zhihu.com)》中我们提到了null-ls这个插件的目的与作用:诸如prettier、eslint等本身不属于LSP范畴,但又对代码具有解析、处理的外部工具,我们可以通过null-ls插件暴露为语言服务(Language Server),于是用户可以直接使用nvim内置的vim.lsp.*相关的API来调用这些prettier、eslint等工具所提供的代码解析、格式化等功能。
然而,null-lsp由于某些原因,即将归档并停止更新了(可以看这里:IMPORTANT: Archiving null-ls)。在这个背景下,笔者不得不重新审视目前关于代码格式化以及代码lint的插件方案。经过笔者的调研和实践,发现除了null-ls体系以外,其实还有很多架构简单易于理解的配置方案,本文将进行简单的介绍系下的代码格式化和lint配置方案。
代码格式化方案
nvim的代码格式化有一个比较经典的插件:mhartington/formatter.nvim。插件安装就不再赘述了,这里主要讲解下formatter这个插件的基本配置思路。
首先,这个插件不会提供格式化代码的能力,它只是一个调用者,你的机器是需要安装相关的代码格式化工具的(譬如要使用prettier,则要通npm install -g prettier安装)。
其次,formatter这个插件的思路也很简单:你可以为每一种文件类型(filetype)配置想要调用外部的格式化工具,然后一旦使用插件提供的指令(譬如:Format),它就会调用你所配置的外部格式化工具。

而这个插件具体的配置方式,通过官方文档我们知道,我们需要在给formatter这个插件进行setup的时候,传入一个filetype的字段,这个字段值是一个table,里面的每一个key就是一个filetype,而值则是对应要调用的格式化工具的一段配置。
formatter插件库实际上已经给很多主流的语言都编写了默认的格式化工具调用代码,包括javascript的prettier等。比如,你可以按照如下的方式来配置javascript使用formatter内置编写好的prettier调用代码:
require("formatter").setup {
-- ... ...
filetype = {
javascipt = { require('formatter.filetypes.javascript').prettier }
}
-- ... ...
}
那么这个'formatter.filetypes.javascript'是什么呢?翻阅formatter插件代码,可以看到路径lua/formatter/filetypes/javascript.lua代码:

而该代码中的local defaults = require "formatter.default"就来源于lua/formatter/defaults目录下的模块,像prettier就来自于对应文件preitter.lua:

这里也能很清晰的看到,formatter调用prettier的时候,就是调用的命令行环境中的prettier,所以我们才在一开始的时候提到,需要安装对应外部格式化工具,并且能在命令行形式被访问调用。
那么,再次回到笔者自己的配置:

主要分为了两个部分:
针对javascript、typescript以及它们的react扩展(jsx、tsx)文件类型,我们都配置了对应的格式化器使用prettier;这里通过lua脚本for遍历来方便的为一系列的文件类型均使用了prettier。
keymap按键映射。使用leader+大小写f键,来映射调用formatter插件提供的FormatWrite和Format指令。
需要注意的是,这里的格式化要和nvim的lsp格式化(vim.lsp.buf.format())区别开来。formatter插件的格式化,主要是使用外部格式化工具进行,往往更加专注代码格式化本身;而lsp的格式化是通过语言服务(往往伴随更加复杂的代码分析)完成的。它们的各有各的侧重点,但在笔者看来,如果一门语言有更加专业的格式化方案(譬如本例中js使用prettier这种成熟方案),那么笔者建议使用formatter插件配合对应的专业格式化工具来完成代码格式化,而之前文章《详解nvim内建LSP体系与基于nvim-cmp的代码补全体系 - 知乎 (zhihu.com)》中提到的监听LspAttach事件,然后注册keymap映射<cmd>lua vim.lsp.buf.format()<CR>可以用来兜底哪些暂时不使用专门的格式化工具的场景:

于是,在笔者的配置下,如果本人正打开的是有prettier规范的前端项目的时候,总是会使用<leader>+f/F来调用prettier来进行代码格式化;而假设正在编辑一段lua代码,那么会使用ctrl+alt+L来通过lua的语言服务进行代码格式化。读者在理解了这两种格式化机制以后,自行涉及方案了。
lint方案
lint方案和上面的格式化会有所差别。在不使用null-ls的情况下,lint方案实际上完全可以通过nvim自己的lsp模块配置外部工具完成。翻阅lspconfig目前已经支持的语言服务,会看到eslint也在其中,同时你也能看到很多其他语言的lint都在这个语言服务的说明文件里面。

也就是说,至少对于lspconfig插件,它将各种lint也都视为了语言服务(至于格式化为什么没有作为语言服务,个人觉得格式化的功能比较单一)。同样的,我们只需要安装lint外部的命令行工具或者已经包含了lint功能的语言服务工具(说到底还是要在机器上安装对应的命令行工具),就能够获得lint的能力了。
比如,在笔者的机器上为了使用eslint功能,则会全局安装vscode-langservers-extracted,里面就包含了一个名为vscode-eslint-language-server的专门做ESlint的语言服务能够在命令行中访问。然后只需要像配置普通的语言服务一样来启动eslint:
require("lspconfig").eslint.setup({})
总结
总的来说,在没有null-ls这套体系的参与下,我们同样也能够很方便的配置格式化和lint。
先说代码格式化,在nvim中,格式化有两种形式,一种是调用外部独立专用的格式化工具来完成代码格式化;另一种就是通过nvim提供的lsp模块的format来进行格式化,从本质上来讲,后者和前者是一样的,毕竟语言服务不过也是一种特殊的外部工具而已;
再讲nvim工程调用lint工具,这里lspconfig讲lint工具也视为了一种特殊的语言服务,因为lint就支持diagnostics、code actions等。所以,实际上只需要安装了对应的lint工具(或是包含了lint功能的语言服务),然后通过lspconfig就能很方便的启用了。
PS:笔者已经将自己的nvim配置中的null-ls和需要基于null-ls的prettier.nvim、eslint.nvim都删除了;换成使用formatter.nvim和lspconfig启用eslint来分别替代代码格式化和eslint检查了。
从null-ls归档再看nvim的代码格式化与lint方案的更多相关文章
- 再看Ajax
再回顾Ajax相关的内容,再次梳理学习还是很有必要的,尤其是实际的开发中,ajax更是必不可少,仔细学习以便避免不必要的错误. 文章导读: --1.使用XMLHttpRequest---------- ...
- 再看ftp上传文件
前言 去年在项目中用到ftp上传文件,用FtpWebRequest和FtpWebResponse封装一个帮助类,这个在网上能找到很多,前台使用Uploadify控件,然后在服务器上搭建Ftp服务器,在 ...
- Android菜鸟的成长笔记(17)—— 再看Android中的Unbounded Service
原文:Android菜鸟的成长笔记(17)-- 再看Android中的Unbounded Service 前面已经写过关于startService(Unbounded Service)的一篇文章:&l ...
- mysql索引设计的注意事项(大量示例,收藏再看)
mysql索引设计的注意事项(大量示例,收藏再看) 目录 一.索引的重要性 二.执行计划上的重要关注点 (1).全表扫描,检索行数 (2).key,using index(覆盖索引) (3).通过ke ...
- 再看 AspriseOCR - OCR应用开发 -20151124
再看 AspriseOCR - OCR应用开发 我写这个博文时间为 2015/11/24日,注意时间因为,网上很多文章时间上很久远,有的已经不能参考了 很多人面对从图片中识别文字或者数字0~9 A~ ...
- 再看case语句
再看case语句,case语句只处理单条记录,而不是set 列名的使用,可以当做数值来使用: case when 后面简直是完美的的,什么东西都是能放的,只要是一个逻辑上的true/false的逻辑就 ...
- android 智能指针的学习先看邓凡平的书扫盲 再看前面两片博客提升
android 智能指针的学习先看邓凡平的书扫盲 再看前面两片博客提升
- python基础----再看property、描述符(__get__,__set__,__delete__)
一.再看property 一个静态属性property ...
- perf使用的问题,再看perf record,perf record 设置的采样频率,采样频率是如何体现在
当perf stat -e branches 是统计 再看perf record,perf record是为了是记录时间发生的时候的调用栈, 在我的测试代码中总共有200,000,000条branch ...
- 再看Scrapy(1) 基本概念
再看Scrapy(1) 基本概念 1 准备 安装scrapy: 国内镜像源(官方的pypi不稳定)安装 pip3 install -i https://pypi.douban.com/simple/ ...
随机推荐
- ABC 310
E \(dp[i][j]\) 表示前 \(i\) 个里有多少个后缀答案为 \(j\). \(if (c[i] == '0') \{\) \(dp[i][0] = 1;\) \(dp[i][1] = d ...
- C++文件输入输出的简单实现(Debug)
1.前言: 文件输入输出是个很有用的东西,有时比赛时要有:要求使用文件输入输出,还有时候-- 遇到这种时间限制非常恶心的题目:手动测试会有误差-- 文件输入输出是个很好的选择! 2.写法: C C语言 ...
- DOM和BOM的区别
DOM和BOM的区别 在浏览器中运行的JavaScript可以认为由三部分组成:ECMAScript描述了该语言的语法和基本对象,DOM文档对象模型描述了处理网页内容的方法和接口,BOM浏览器对象模型 ...
- Java设计模式-装饰者模式Decorator
介绍 装饰者模式的核心思想是通过创建一个装饰对象(即装饰者),动态扩展目标对象的功能,并且不会改变目标对象的结构,提供了一种比继承更灵活的替代方案.需要注意的是,装饰对象要与目标对象实现相同的接口,或 ...
- image could not be accessed on a registry to record its digest
问题说明: 在管理节点执行docker stack xxx 方式运行服务,报如题错误. 问题原因: docker swarm运行需要一个镜像仓库才行,所有节点都去这个仓库统一镜像. 来看下官方的解释: ...
- error C2039: "function": 不是 "std" 的成员的解决方法
这个错误通过某度没找到合适的解决方案,故记录下来 其实如果使用 google 搜索错误的英文关键词,大概第一条就是解决问题的链接 Large number of "'function' is ...
- 【小记事】如何设置vscode代码格式化时不要自动换行
最近一格式化就给我分好多行,好气哦(`ヘ´)=3 在setting.json中添加如下代码: "vetur.format.defaultFormatter.html": " ...
- 【Azure Cloud Service】Cloud Service(Classic) 迁移失败,找不到解决方案怎么办?
问题描述 很老很老的云服务,在迁移到 Cloud Service(Extended Support)[云服务外延支持] 时,迁移的验证步骤不通过,因为资源中没有包含虚拟网络(Virtual Netwo ...
- 【Azure 应用服务】如何从App Service for Linux 的环境中下载Container中非Home目录下的文件呢?
问题描述 在App Service for Linux的环境中,我们能通过SSH进入到Container的环境中,并且可以通过在kudu站点的URL后面添加 /newui 打开一个适用于Linux环境 ...
- 手把手教你python数据处理项目——探索ebay汽车销售数据
探索Ebay汽车销售数据 一.实验目的 1. 熟悉清理数据的流程: 2. 分析Ebay二手车销售数据: 3. 了解jupyter notebook为pandas提供的一些独特特性. 二.实验开发环 ...