lazyvim 折腾日记(2)

lazyvim 折腾日记(2)

前言

我的目标是争取在不使用 gui 的前提下完成开发,运维等工作

前一篇讲述的是 lazyvim 安装及基本概念,这一篇要讲的是如何在 lazyvim 中使用中文输入法

有这个想法是因为在 nvim 使用中文输入法非常的不便捷,但是又不可避免的有着写文档的需求,在这种情况下需要借助一些工具完善在 nvim 中的中文输入体验.

具体思路

完成中文输入的改进,基本需要以下几个步骤

  1. 完成 rime 与 本地 cmp 的结合
  2. 将本地搜索插件加入搜索中文的功能
  3. 增强 e b 等快捷键的功能,使得这些快捷键能够按词移动

以上的三个步骤分别依赖于 rime-ls hop hop-zh-by-flypy jieba.nvim 总共4个插件的安装与配置,下文将按照上述步骤进行安装调试

rime 语言服务器的安装

rime-ls 通过将 cmp 与 rime-ls 结合实现通过 cmp 候选框选择中文,其中的核心在于 rime-ls 的安装 以及 cmp 的配置

rime-ls 依赖 librime 这个 rime 的核心引擎,也就是说安装这个插件的前提是首先在本机上已经安装好 rime 在本机上使用的是 fcitx5-rime

直接编译 rime-ls 比较麻烦,需要提前安装好 clang 如果使用的是 arch 系列系统,可以直接从 aur 中进行安装,本机额外安装了 rust 以及 clang 对项目进行编译,这个过程不是本篇文章主题,按下不表

安装编译后的目录如下文所示

$> pwd
/home/soapsu/.local/bin/rime-ls
$> tree -L 1
├── Cargo.lock
├── Cargo.toml
├── CHANGELOG.md
├── doc
├── docker-compose.yaml
├── Dockerfile
├── LICENSE
├── README.md
├── src
└── target

4 directories, 7 files

$> tree -L 2 ./target # 其中 rime_ls 就是我们所编译好的文件
./target
├── CACHEDIR.TAG
└── release
    ├── build
    ├── deps
    ├── examples
    ├── incremental
    ├── librime_ls.d
    ├── librime_ls.rlib
    ├── rime_ls
    └── rime_ls.d

6 directories, 5 files

将编译好的文件路径加入环境变量中

$> echo "export RIME_HOME="$HOME/.local/bin/rime-ls/" > ~/.zshrc  
$> source ~/.zshrc

配置 lazyvim 文件

$> cd /home/soapsu/.config/nvim/lua/plugins
$> tree -L 1 ./
.
├── ai
├── catppuccin.lua
├── cmp.lua
├── dadbod
├── java
├── lualine.lua
├── nvim-treesitter.lua
├── rime.lua # 新增该文件
└── zh-input.lua

4 directories, 6 files

在新增文件中写入如下内容

local M = {}

function M.setup_rime()
  -- global status
  vim.g.rime_enabled = false

  -- update lualine
  local function rime_status()
    if vim.g.rime_enabled then
      return "ㄓ"
    else
      return ""
    end
  end

  require("lualine").setup({
    sections = {
      lualine_x = { rime_status, "encoding", "fileformat", "filetype" },
    },
  })

  -- add rime-ls to lspconfig as a custom server
  -- see `:h lspconfig-new`
  local lspconfig = require("lspconfig")
  local configs = require("lspconfig.configs")
  if not configs.rime_ls then
    configs.rime_ls = {
      default_config = {
        name = "rime_ls",
        cmd = { "rime_ls" },
        -- cmd = vim.lsp.rpc.connect("127.0.0.1", 9257),
        filetypes = { "*" },
        single_file_support = true,
      },
      settings = {},
      docs = {
        description = [[
https://www.github.com/wlh320/rime-ls

A language server for librime
]],
      },
    }
  end

  local rime_on_attach = function(client, _)
    local toggle_rime = function()
      client.request("workspace/executeCommand", { command = "rime-ls.toggle-rime" }, function(_, result, ctx, _)
        if ctx.client_id == client.id then
          vim.g.rime_enabled = result
        end
      end)
    end
    -- keymaps for executing command

    vim.keymap.set("i", "<C-x>", function()
      toggle_rime()
    end)
    vim.keymap.set("n", "<leader>rs", function()
      vim.lsp.buf.execute_command({ command = "rime-ls.sync-user-data" })
    end)
  end

  -- nvim-cmp supports additional completion capabilities, so broadcast that to servers
  local capabilities = vim.lsp.protocol.make_client_capabilities()
  capabilities = require("cmp_nvim_lsp").default_capabilities(capabilities)

  lspconfig.rime_ls.setup({
    init_options = {
      enabled = vim.g.rime_enabled,
      shared_data_dir = "/usr/share/rime-data",
      user_data_dir = "~/.local/share/rime-ls",
      log_dir = "~/.local/share/rime-ls",
      max_candidates = 9,
      trigger_characters = {},
      schema_trigger_character = "&", -- [since v0.2.0] 当输入此字符串时请求补全会触发 “方案选单”
    },
    on_attach = rime_on_attach,
    capabilities = capabilities,
  })
end

local cmp = require("cmp")
local compare = require("cmp.config.compare")
cmp.setup({
  sorting = {
    priority_weight = 2,
    comparators = {
      compare.sort_text,
      compare.offset,
      compare.exact,
      compare.score,
      compare.recently_used,
      compare.kind,
      compare.length,
      compare.order,
    },
  },
})
local rime_ls_filetypes = { "markdown", "vimwiki" }
local function is_rime_entry(entry)
  return vim.tbl_get(entry, "source", "name") == "nvim_lsp"
    and vim.tbl_get(entry, "source", "source", "client", "name") == "rime_ls"
end

local function auto_upload_rime()
  if not cmp.visible() then
    return
  end
  local entries = cmp.core.view:get_entries()
  if entries == nil or #entries == 0 then
    return
  end
  local first_entry = cmp.get_selected_entry()
  if first_entry == nil then
    first_entry = cmp.core.view:get_first_entry()
  end
  if first_entry ~= nil and is_rime_entry(first_entry) then
    local rime_ls_entries_cnt = 0
    for _, entry in ipairs(entries) do
      if is_rime_entry(entry) then
        rime_ls_entries_cnt = rime_ls_entries_cnt + 1
        if rime_ls_entries_cnt == 2 then
          break
        end
      end
    end
    if rime_ls_entries_cnt == 1 then
      cmp.confirm({
        behavior = cmp.ConfirmBehavior.Insert,
        select = true,
      })
    end
  end
end
vim.api.nvim_create_autocmd("FileType", {
  pattern = rime_ls_filetypes,
  callback = function()
    for numkey = 1, 9 do
      local numkey_str = tostring(numkey)
      vim.api.nvim_buf_set_keymap(0, "i", numkey_str, "", {
        noremap = true,
        silent = false,
        callback = function()
          vim.fn.feedkeys(numkey_str, "n")
          vim.schedule(auto_upload_rime)
        end,
      })
      vim.api.nvim_buf_set_keymap(0, "s", numkey_str, "", {
        noremap = true,
        silent = false,
        callback = function()
          vim.fn.feedkeys(numkey_str, "n")
          vim.schedule(auto_upload_rime)
        end,
      })
    end
  end,
})

return M

再在 init.lua 中加入以下内容

$> pwd
/home/soapsu/.config/nvim
$> tree -L 
.
├── init.lua # 在这里加入以下内容
├── lazy-lock.json
├── lazyvim.json
├── LICENSE
├── lua
├── README.md
└── stylua.toml

2 directories, 6 files
$> echo "require("plugins.rime").setup_rime()"

重新启动 nvim rime 即可使用

对于上面的文件有必要做出如下解释

  1. 以上配置文件全都来源于 rime-ls 的配置文件以及 issue 里的用户配置片段
  2. 在上述的配置文件中, 总共设置了如下功能
  3. 在 lsp 中加入了 rime-ls 语言服务器的使用, 使得 cmp 候选框能够显示来自前者的候选项目
  4. 在 lualine 中设置了与 rime-ls 状态相关的图标, 使得用户能够从 lualine 状态栏中看到 rime-ls 的启动状态
  5. 设置了 rime-ls 的词库位置以及用户数据位置
  6. 设置了 cmp 候选框的排列顺序, 使得用户输入的中文能够在 cmp 候选框的前列并按数字顺序排序
  7. 设置了根据数字按键直接上屏, 具体原理为将 auto_upload_rime 与 nvim_create_autocmd 两个函数相结合实现前文所述功能
  8. 设置了启动 rime-ls 的按键, 为在 insert 模式下按下 键即可启动 rime-ls 服务器

搜索跳转插件的安装

在实际编辑中文文档的时候会高频词使用到搜索跳转功能, 但是现有的 nvim 自身的跳转功能只支持英文, 所以有必要安装中文跳转的插件

在本机使用 hop + hop-zh-by-flypy 实现搜索与跳转功能

hop 插件, hop 插件是 easyMotion 插件的重写, 旨在用于强化在 nvim 下的跳转搜索, 而 hop-zh-by-flypy 则是 hop 插件的一个中文拓展

首先在 plugins 文件夹下的 zh-input.lua 文件下加入以下内容

$> pwd
/home/soapsu/.config/nvim/lua/plugins
$> tree -L 1 ./
./
├── ai
├── catppuccin.lua
├── cmp.lua
├── dadbod
├── java
├── lualine.lua
├── nvim-treesitter.lua
├── rime.lua
└── zh-input.lua # 在该文件下新增内容

4 directories, 6 files

return {
  {
    "phaazon/hop.nvim",
    branch = "v1",
    config = function()
      local hop = require("hop")
      hop.setup({
        keys = "etovxqpdygfblzhckisuran",
        extensions = {
          "hop-zh-by-flypy",
        },
      })
      local directions = require("hop.hint").HintDirection
      vim.keymap.set("", "f", function()
        hop.hint_char1({ direction = directions.AFTER_CURSOR, current_line_only = true })
      end, { remap = true })
      vim.keymap.set("", "F", function()
        hop.hint_char1({ direction = directions.BEFORE_CURSOR, current_line_only = true })
      end, { remap = true })
      vim.keymap.set("", "t", function()
        hop.hint_char1({ direction = directions.AFTER_CURSOR, current_line_only = true, hint_offset = -1 })
      end, { remap = true })
      vim.keymap.set("", "T", function()
        hop.hint_char1({ direction = directions.BEFORE_CURSOR, current_line_only = true, hint_offset = 1 })
      end, { remap = true })
    end,
  },
  {
    "zzhirong/hop-zh-by-flypy",
    dependencies = {
      "phaazon/hop.nvim",
    },
    config = function()
      local hop_flypy = require("hop-zh-by-flypy")
      hop_flypy.setup({
        set_default_mappings = false,
        vim.keymap.set("n", "gf", "<cmd>HopFlypy1<CR>"),
        vim.keymap.set("n", "gs", "<cmd>HopFlypy2<CR>"),
      })
    end,
  },

按照上述配置, 重启 lazyvim 即可安装好以上两个模块

对于以上内容有必要做出如下解释

  1. hop-zh-by-flypy 依赖 hop 插件, 不可单独安装该插件
  2. 直接使用 hop-zh-by-flypy 插件的官方配置会与 lazyvim 自带的 flash 插件按键产生冲突, 所以不能使用默认配置, 需自行配置相关按键,
# f 与 s 按键绑定 flash 插件, 在本机中设置 gf 以及 gs 键绑定 HopFlypy1 以及 HopFlypy2 命令
    1 15时17分26秒 msg_show  map f o  f           * <Lua 554: ~/.local/share/nvim/lazy/flash.nvim/lua/flash/plugins/char.lua:118>
    1 x  f           * <Lua 553: ~/.local/share/nvim/lazy/flash.nvim/lua/flash/plugins/char.lua:118>
    2 n  f           * <Lua 548: ~/.local/share/nvim/lazy/flash.nvim/lua/flash/plugins/char.lua:118>
    3 s  f             <Lua 321: ~/.config/nvim/lua/plugins/zh-input.lua:14>
    4 15时18分01秒 msg_show 5 more lines
    5 15时15分50秒 msg_showcmd :
    6 15时18分38秒 msg_show  map s n  s           * <Lua 227: ~/.local/share/nvim/lazy/LazyVim/lua/lazyvim/plugins/editor.lua:164>
    7                  Flash
    8 x  s           * <Lua 226: ~/.local/share/nvim/lazy/LazyVim/lua/lazyvim/plugins/editor.lua:164>
  1. hop-zh-flypy 使用的是小鹤双拼编码, 具体使用方法为在 n 模式下敲入 gf 输入第一个音节, 按照排序选取中文, 同理敲入 gs 输入双拼完整编码按顺序选取中文
  2. 直接敲入 f 再敲入所需选取的英文, 再按 f 键向下选取

总结: 通过上述配置能够实现中英文的跳转

e w b ge 移动强化

在实际行内移动中, 通常使用 w e 按键实现单词与单词之间的跳转, 很明显 nvim 自身提供的 w e 键移动只针对英文, 所以有必要强化在中文下的单词间移动

在本机中使用 jieba.nvim 对以上两按键进行强化, 该模块使用 jieba 分词实现对中文词语的识别

在上文所提到的配置文件中加入以下内容

  {
    "noearc/jieba.nvim",
    dependencies = { "noearc/jieba-lua" },
  },

即可安装完毕, 优点在于不需要编译, 能够开箱即用

总结

本文通过配置上述插件以达到强化中文输入体验的目的

posted @ 2024-11-13 20:18  五花肉炒河粉  阅读(634)  评论(0)    收藏  举报