如何使用纯手工制作一个漂亮的 vim 状态栏

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用纯手工制作一个漂亮的 vim 状态栏相关的知识,希望对你有一定的参考价值。

我将 space-vim 的状态栏单独提取成为一个插件: .. , 可直接安装试用。

首先看一下最后的效果:

知己知彼,百战不殆。先来分析一下使用 airline 与 lightline 有什么好处?

    漂亮,酷炫,这毋庸置疑。

    airline 与很多插件集成的非常好,真是省心又省力。

    那有什么不足之处呢?

    airline 可能会导致 100 ms 的启动延迟。具体可以看这里 xu..., 这里也有一篇关于 vim 启动优化非常好的文章。

    定制性依旧不高,或者说深度定制的门槛有点高,不是那么容易上手。我曾经尝试过深入修改过 airline,不过并不顺利。

    它们所提供的信息可能过于庞杂,显得有些冗余。

    那么如何通过纯手工制作一个与 airline/lightline 相比也还不错的 statusline 呢?

    什么叫不错?这个因人而异,按照我个人的审美而言,首先不能太单调(我只关心漂不漂亮),其次得显示出一些有用的信息。那么就会涉及到以下一些内容:

    颜色转换,也就是各部分前景色,背景色之类的。

    一些有用的信息,比如语法检查的内容信息。

    为了漂亮,我们可能还会选择添加一些 Unicode 字符进去。

    function! Buf_total_num()
       return len(filter(range(1, bufnr(\'$\')), \'buflisted(v:val)\'))endfunctionfunction! File_size(f)
       let l:size = getfsize(expand(a:f))    if l:size == 0 || l:size == -1 || l:size == -2
           return \'\'
       endif
       if l:size < 1024
           return l:size.\' bytes\'
       elseif l:size < 1024*1024
           return printf(\'%.1f\', l:size/1024.0).\'k\'
       elseif l:size < 1024*1024*1024
           return printf(\'%.1f\', l:size/1024.0/1024.0) . \'m\'
       else
           return printf(\'%.1f\', l:size/1024.0/1024.0/1024.0) . \'g\'
       endifendfunctionset statusline=%<%1*[B-%n]%*" TOT is an abbreviation for totalset statusline+=%2*[TOT:%Buf_total_num()]%*set statusline+=%3*\\ %File_size(@%)\\ %*set statusline+=%4*\\ %F\\ %*set statusline+=%5*『\\ %exists(\'g:loaded_ale\')?ALEGetStatusLine():\'\'』%exists(\'g:loaded_fugitive\')?fugitive#statusline():\'\'%*set statusline+=%6*\\ %m%r%y\\ %*set statusline+=%=%7*\\ %&ff\\ \\|\\ %\\"\\".(&fenc==\\"\\"?&enc:&fenc).((exists(\\"+bomb\\")\\ &&\\ &bomb)?\\",B\\":\\"\\").\\"\\ \\|\\"\\ %-14.(%l:%c%V%)%*set statusline+=%8*\\ %P\\ %*" default bg for statusline is 236 in space-vim-darkhi User1 cterm=bold ctermfg=232 ctermbg=179hi User2 cterm=None ctermfg=214 ctermbg=242hi User3 cterm=None ctermfg=251 ctermbg=240hi User4 cterm=bold ctermfg=169 ctermbg=239hi User5 cterm=None ctermfg=208 ctermbg=238hi User6 cterm=None ctermfg=246 ctermbg=237hi User7 cterm=None ctermfg=250 ctermbg=238hi User8 cterm=None ctermfg=249 ctermbg=240

    简单介绍一下重点:%1*[foo]%*, hi User1 ......, 改变的便是 [foo] 部分的 style, 比如前景色,背景色,粗体等等。如果你也想要尝试自己定制一番,按照个人喜好照葫芦画瓢即可 :p.

    上面的示例似乎有些复杂,下面给出一个简略版本:

    set statusline+=%4*\\ %F\\ %*
    hi User4 cterm=bold ctermfg=169 ctermbg=239

    分两步:

    %数字* + 后面跟上所要在 statusline 中显示的内容 +%*,圈出所要进行操作的范围,比如简略版本中为 \\ %F \\ , 即为 空格 文件的全路径 空格。

    hi User数字 cterm=bold ctermfg=111 ctermbg=111 gui=bold guifg=111 guibg=111 ,就会 highlight 上面圈出的范围。 cterm, gui 分别指的是 terminal 与 GUI 环境。 fg,bg 为前景,背景色。数字可以自己定义。 hi User1 ... 就会对 %1* ... %* 所圈中的 ... 进行 highlight 操作。

    也可以不用数字,采用自定义名称。 比如%4* 可替换为%#highlightgroup#, highlightgroup 为一个自定义的名称,那么%4*\\ %F\\ %* 也可以写为 %#fullPath#\\ %F\\ %*, hi fullPath ... 进行 highlight 就可以了。

    至此你应该可以操作自己的 statusline 了。这里是 256 色对照表 , 这里 是我给出的示例出处。

    如果你不喜欢 airline 可能导致 vim 启动延迟 100 ms, 或是喜欢无插件版本的 vim, 就可以使用这个方法来进行 statusline 的美化了。实际上,这同样也适用于 tabline.

    顺便介绍一下 space-vim 的 statusline 值得关注的一些部分,[B-1] 代表 buffer 1, 1 为当前 buffer 对应的编号。[TOT 3], TOT 指的是 total, 当前共有多少 buffer,可以使用 Tab 快速切换。文件完整路径后面采用橙色前景色显示的是 ale 语法检查的信息。其他部分比较显然,值得关注的点也不多就不介绍了。

    末了,说一下上面的缺点:所有 window 的 statusline 都是很相似的,可能不能像 airline/lightline 那样容易区分出哪个是当前光标所在的 window。 而且跟你的 colorscheme 可能不搭。不过我个人来讲,愿意接受这些不足。

    仅仅是分享一个方案,如何选择取决于你自己。

参考技术A 使用到字符界面下实现简单图形的库了吧(比如那个curses)~~具体的实现不清楚,这个库也没用过~~

从零开始配置 vim(15)——状态栏配置

vim 下侧有一个状态栏,会显示当前打开的文件等一系列内容,只是我们很少去关注它。而且原生的vim也支持对状态栏进行自定义。这篇文章主要介绍如何自定义状态栏

设置状态栏

我们可以采用 set statusline 来设置状态栏。
例如我们输入 :set statusline=%f\\ -\\ FileType=%y。之后我们可以发现它变成了如下这个样子


statusline 的值是一个格式字符串。上述命令我们使用了 %f 表示当前文件名称 。

从上面的命令中明显感觉到只输出两个内容就已经开始显的比较繁琐了,如果显示的内容多了是不是就更加难以阅读和书写了呢?好在我们还能使用 lua来做设置。上述内容可以翻译为如下的 lua代码

vim.o.statusline = "%f - FileType=%y"

我们保存之后发现下方的状态栏显示内容已经发生变化。

控制边距和宽度

如果你写过 c 或者其他编程语言中的输出语句,应该很容易理解如何控制输出的格式,一般使用类似 `%4l`` 这样的语句来控制该项占4个字符宽度。这里的设置也是类似的

vim.o.statusline = "%20f - FileType=%y"

它表示 文件名这项应该站20个字符宽度。最终效果如下所示

默认它的边距是添加在左边的,这样会让左侧空出一大半,会显得比较难看,我们可以使用 -来使空白站位符显示在右侧

vim.o.statusline = "%-20f - FileType=%y"

当然我们也可以控制一下输出字符的最大长度,例如使用如下代码

vim.o.statusline = "%0.10F - FileType=%y"

使用 %F可以显示文件的全路径。这里我们发现全路径大于10个字符,但是它只是显示了10个字符。使用这个方法可以防止某些超长的字符串破坏了我之前的布局

分割

我们再来介绍一个符号 %=,它表示将 %= 后面的内容全局居右对齐,例如

vim.o.statusline = "%f %= FileType=%y"

将得到如下显示内容

更多的关于各个标识符代表的含义可以使用 :help statusline 来查看。

练习

最后我们来做一个小练习,我们希望将状态栏显示为如下内容

mode | filename[status] | currentline:totalline                       |encoding|filetype|

其中 mode 代表当前所处模式、filename 代表文件名称、status 代表文件状态(是否可读写、是否保存)、currentline 代表光标当前所在行数、totalline 代表文件一共多少行、encoding 代表文件编码、filetype 代表文件类型

我们通过查阅文档可以知道:

  • 文件名称可以使用 %f 来显示
  • 文件状态可以使用 %m 来显示
  • 当前行可以使用 %l
  • 当前buffer总行数可以使用 %L
  • 文件类型可以使用 %y 来显示

至于当前模式和文件类型我们先不管它,根据这些内容我们可以写下如下代码

vim.o.statusline = "mode|%f%m|%l:%L%=encoding|%y"


[+] 表示对缓冲区所做的修改还没有写入到磁盘中。执行:w写入之后发现它直接消失了

我们可以通过 vim.g.encoding 来获取当前文件的编码方式,因此我们改一下当前代码

vim.o.statusline = "mode|%f%m|%l:%L%=" .. vim.g.encoding .. "|%y"

我们发现此时的状态已经改过来了。


最麻烦的是模式,vim 中提供了一个可以获取当前模式的函数 mode 。但是在 lua 接口中我没有找到对应的函数。因此我们仍然采用在 lua 中调用 vimscript 的方式。这次我们使用函数 vim.api.nvim_eval()。它可以执行 vim 命令并将返回执行的结果。

我们可以定义一个函数返回当前所处模式

function get_mode()
    local mode = vim.api.nvim_eval([[mode]])
    if mode == "n" then
        return "Normal"
    elseif mode == "v" then
        return "Visual"
    elseif mode == "i" then
        return "Insert"
    else
        return ""
    end
end

这里我们为了演示只返回了 3中模式的字符串,更多模式可以查看vim的帮助文档

我们希望模式改变时对应的就修改 mode 对应的字段,此时我们应该采用自动命令。查看vim的用户手册我们发现,针对模式变化这一事件有一个叫做 ModeChanged 的事件类型,因此我们可以写下一些代码

local cmd_statusline = vim.api.nvim_create_autogroup("SET_STATUS_LINE", clear = true)

vim.api.nvim_create_autocmd("ModeChanged", 
    pattern = "*",
    group = cmd_statusline,
    callback = function()
      local win_id = vim.api.nvim_eval([[win_getid()]]) --获取当前window id
      vim.wo[win_id].statusline = get_mode() .. "|%f%m|%l:%L%=" .. vim.g.encoding .. "|%y" -- 使用 setlocal 针对窗口设置本地化配置
    end
)

后面我们可以对字符串进行一些格式控制,这里就不展开了。我们将这些代码写到 init.lua中,保存后发现它大致效果如下

我们发现就是简单的设置状态栏的工作也是比较麻烦的。而且有时候我们又想它好看,带点颜色什么的。这就更麻烦了。好在有大量的插件可以帮助我们来完成这一工作

lualine 插件

lualine 是一个用 lua 语言开发的 neovim 的状态栏美化插件,可以使用如下代码进行安装

use 
  'nvim-lualine/lualine.nvim',
  requires =  'kyazdani42/nvim-web-devicons', opt = true 

我们创建 lualine 的配置文件,加入加载 lualine 的代码

require("lualine").setup()

然后在主配置文件中加载该文件

require("plugin-config/lualine")

lualine 官方提供了3种主题的配色,我们可以直接在代码中引用,例如我这里引用 evil_lualine 这个配置,然后将 theme改为之前我们安装的 tokyonight主题

theme = "tokyonight"

到这里我们已经完成了 状态栏的美化,其实主要靠插件,本篇一大部分写了如何使用原生的statusline 设置主要是自己手工设置比较有意思,而且也可以凑文章字数,其实你不知道statusline 这个也无所谓,很多插件都都对原生的方式进行了大量封装,而且能进行高度的自定义。完全可以满足你各种奇怪的口味。

当然状态栏配置并不只有这一种插件,如果你知道有哪些状态栏的插件也欢迎在评论区留言给出

以上是关于如何使用纯手工制作一个漂亮的 vim 状态栏的主要内容,如果未能解决你的问题,请参考以下文章

史上最全面的纯手工打造 Vim 神器操作手册

如何在不使其全屏的情况下删除颤振闪屏状态栏的颜色覆盖?

在片段中使用 CoordinatorLayout 时如何使状态栏透明

如何使状态栏透明?

如何在php中制作活动导航栏?

从零开始配置 vim(15)——状态栏配置