再次折腾 vim 配置之 neovim

经验

更新 2023.3

突然发现之前的配置好像没有正确使用 lazy.nvim, 准备从 NvChad 那里再抄一些新东西过来, 最新版的配置可以在 这里 找到。

引言

本周,我总计第三次折腾了自己的 neovim 配置,目前感觉还可以。 之后这段时间计划尝试长期使用,不知道能坚持多久。

  • 第一次用 neovim 是在刚加入浮动窗口那段时间,我抄了大部分之前的 vim 配置, 然后尝试用 coc.nvim 做补全,一段时间后还是回去用 VSCode 了。

  • 第二次用是听说 neovim 加入了内置的 LSP 支持,再次尝试折腾,但是 懒得学了,于是用了现成的 lunarvim 项目,自己基本没做配置。 这个项目用了大量 lua 写的新一代插件,感觉体验是比之前好多了, 但不是自己配置还是有些不顺手,一段时间后发现还是 VSCode 用得更多。

  • 这次是因为看到了 kickstart.nvim 这个项目,感觉自己配置好像也并不复杂, 于是简单学了下 lua 相关的配置方式,在这基础上修改成现在的配置。

此外,最近我 Windows 用得比较多, 这次配置的最终目标不仅是配好服务器, 还包括改进我在 Windows 下的使用体验,使其能够作为日常编辑器使用。

最终,除了 Windows 上面编译 tree-sitter 的语言支持稍微麻烦了一点, 由于 LSP 的存在,感觉一套配置跨平台的使用体验基本上是一致的。

下图是在 Windows 用 fvim 连接服务端编辑远程文件的截图: 截图

基本配置

基本是照抄 kickstart.nvim, 也加了一些自己的配置,比如折行,相对行号.

-- [[ Basic Settings ]]

-- Set highlight on search
vim.o.hlsearch = false

-- Make line numbers default
vim.wo.number = true

-- Enable mouse mode
vim.o.mouse = 'a'

-- Enable break indent
vim.o.breakindent = true

-- Save undo history
vim.o.undofile = true

-- Case insensitive searching UNLESS /C or capital in search
vim.o.ignorecase = true
vim.o.smartcase = true

-- Decrease update time
vim.o.updatetime = 250
vim.wo.signcolumn = 'yes'

-- Set color
vim.o.termguicolors = true
-- Set completeopt to have a better completion experience
vim.o.completeopt = 'menuone,noselect'

-- my custom setting
vim.opt.cmdheight = 1
vim.opt.spelllang = "cjk"
vim.opt.relativenumber = true
vim.wo.cursorline = true
vim.wo.wrap = false
-- my default tabwidth
local TABWIDTH = 4
vim.opt.tabstop = TABWIDTH
vim.opt.shiftwidth = TABWIDTH
vim.opt.expandtab = true

-- [[ Basic Keymaps ]]

-- Set <space> as the leader key
-- NOTE: Must happen before plugins are required (otherwise wrong leader will be used)
vim.g.mapleader = ' '
vim.g.maplocalleader = ' '

-- Keymaps for better default experience
vim.keymap.set({ 'n', 'v' }, '<Space>', '<Nop>', { silent = true })

-- Remap for dealing with word wrap
vim.keymap.set('n', 'k', "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true })
vim.keymap.set('n', 'j', "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true })

-- use Alt-hjkl to move between windows
vim.keymap.set('n', '<A-h>', '<C-w>h')
vim.keymap.set('n', '<A-j>', '<C-w>j')
vim.keymap.set('n', '<A-k>', '<C-w>k')
vim.keymap.set('n', '<A-l>', '<C-w>l')

-- keymap for toggle some plugin
vim.keymap.set('n', '<leader>t', '<cmd>exe v:count1 . "ToggleTerm"<cr>')
vim.keymap.set('n', '<leader>T', '<cmd>exe v:count1 . "ToggleTerm direction=vertical"<cr>')
vim.keymap.set('n', '<C-t>', '<cmd>exe v:count1 . "ToggleTerm direction=float"<cr>')
vim.keymap.set('n', '<leader>e', '<cmd>NvimTreeToggle<cr>')

-- Highlight on yank
local highlight_group = vim.api.nvim_create_augroup('YankHighlight', { clear = true })
vim.api.nvim_create_autocmd('TextYankPost', {
  callback = function()
    vim.highlight.on_yank()
  end,
  group = highlight_group,
  pattern = '*',
})

插件配置

插件方面,我基本没有修改 LSP, tree-sitter 和补全相关的插件配置, 其他一部分常用插件稍微研究了一下做了些增减和配置。

此外,我把插件管理从 Packer 迁移到了比较新的 lazy.nvim, 并稍微配了一下懒加载, 将 Windows 下的启动速度提高了不少(300ms -> 70ms)。

我还是更习惯所有配置写到一个文件里, 所以没有用推荐的更模块化的写法,仅用注释将不同插件配置简单隔开。 由于插件不算多,配置总行数在 600 左右,多数配置不用动,目前维护还不算麻烦。

-- [[ Plugin Settings ]]

-- Install lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    "git",
    "clone",
    "--filter=blob:none",
    "https://github.com/folke/lazy.nvim.git",
    "--branch=stable", -- latest stable release
    lazypath,
  })
end
vim.opt.rtp:prepend(lazypath)

-- Config Catppuccin
local catppuccin = {
  'catppuccin/nvim',
  name = 'catppuccin',
  lazy = false,
  priority = 1000,
  config = function()
    require('catppuccin').setup({
      flavour = 'mocha', -- latte, frappe, macchiato, mocha
      transparent_background = true,
    })
    vim.cmd.colorscheme 'catppuccin'
  end
}

-- Config lualine
local lualine = {
  'nvim-lualine/lualine.nvim', -- Fancier statusline
  dependencies = { 'catppuccin/nvim' },
  event = "VeryLazy",
  config = function()
    require('lualine').setup {
      options = {
        icons_enabled = false,
        theme = 'catppuccin',
        component_separators = '|',
        section_separators = '',
      },
    }
  end
}

-- Config indent_blankline
local indent_blankline = {
  'lukas-reineke/indent-blankline.nvim', -- Add indentation guides even on blank lines
  event = { "BufReadPre", "BufNewFile" },
  config = function()
    require('indent_blankline').setup {
      char = '┊',
      show_trailing_blankline_indent = false,
    }
  end
}

-- Config gitsigns
local gitsigns = {
  'lewis6991/gitsigns.nvim',
  event = { "BufReadPre", "BufNewFile" },
  config = function()
    require('gitsigns').setup {
      signs = {
        add = { text = '+' },
        change = { text = '~' },
        delete = { text = '_' },
        topdelete = { text = '‾' },
        changedelete = { text = '~' },
      },
    }
    -- keymap for previewing hunks
    vim.keymap.set('n', '<leader>gh', '<cmd>Gitsigns preview_hunk<cr>', { desc = '[G]itsigns preview [H]unks' })
    vim.keymap.set('n', '<leader>gp', '<cmd>Gitsigns prev_hunk<cr>', { desc = '[G]itsigns [P]revious hunk' })
    vim.keymap.set('n', '<leader>gn', '<cmd>Gitsigns next_hunk<cr>', { desc = '[G]itsigns [N]ext hunk' })
  end
}

-- Config barbar
local barbar = {
  'romgrk/barbar.nvim',
  dependencies = 'nvim-tree/nvim-web-devicons',
  event = "BufAdd",
  config = function()
    -- use shift-hl to move between tabs, <leader>cb to close buffer
    vim.keymap.set('n', '<S-h>', '<cmd>BufferPrevious<cr>')
    vim.keymap.set('n', '<S-l>', '<cmd>BufferNext<cr>')
    vim.keymap.set('n', '<leader>cb', '<cmd>BufferClose<cr>')
    vim.keymap.set('n', '<leader>cp', '<cmd>BufferPickDelete<cr>')
    -- set nvimtree sidebar offset (FIXME: resize not follow mouse click issue #1545)
    local nvim_tree_events = require('nvim-tree.events')
    local bufferline_api = require('bufferline.api')

    local function get_tree_size()
      return require('nvim-tree.view').View.width
    end

    -- subscribe nvim-tree events
    nvim_tree_events.subscribe("TreeOpen", function()
      bufferline_api.set_offset(get_tree_size(), 'File Explorer')
    end)
    nvim_tree_events.subscribe("Resize", function()
      bufferline_api.set_offset(get_tree_size(), 'File Explorer')
    end)
    nvim_tree_events.subscribe("TreeClose", function()
      bufferline_api.set_offset(0)
    end)
    -- better Resize event for nvim-tree (with mouse and `<C-w><>` support)
    if vim.fn.has('nvim-0.9') == 1 then
      local group = vim.api.nvim_create_augroup("nvim_tree_resize", { clear = true })
      vim.api.nvim_create_autocmd('WinResized', {
        group = group,
        pattern = { "*" },
        callback = function()
          local windows = vim.v.event.windows
          for _, win_id in ipairs(windows) do
            local buf = vim.api.nvim_win_get_buf(win_id)
            if buf and vim.bo[buf].filetype == "NvimTree" then
              local width = vim.api.nvim_win_get_width(win_id)
              require('nvim-tree.view').resize(width)
              break
            end
          end
        end,
      })
    end
  end
}

-- Config toggleterm
local toggleterm = {
  'akinsho/toggleterm.nvim',
  version = '*', -- Terminal
  cmd = { 'ToggleTerm' },
  config = function()
    require('toggleterm').setup({
      size = function(term)
        if term.direction == 'horizontal' then
          return 15
        elseif term.direction == 'vertical' then
          return vim.o.columns * 0.4
        end
      end
    })
    -- set keymaps to easily move between buffers and terminal
    function _G.set_terminal_keymaps()
      local opts = { buffer = 0 }
      vim.keymap.set('t', '<esc>', [[<C-\><C-n>]], opts)
      vim.keymap.set('t', 'jk', [[<C-\><C-n><Cmd>ToggleTerm<CR>]], opts)
    end

    vim.cmd('autocmd! TermOpen term://* lua set_terminal_keymaps()')
  end
}

-- Config nvim-tree
local nvimtree = {
  'nvim-tree/nvim-tree.lua',
  dependencies = 'nvim-tree/nvim-web-devicons',
  cmd = { 'NvimTreeToggle', 'NvimTreeFocus' },
  config = function()
    require('nvim-tree').setup({
      actions = {
        change_dir = {
          enable = true,
          global = true
        }
      },
      renderer = {
        indent_markers = {
          enable = true
        }
      }
    })
  end
}

-- Config treesitter
local treesitter = {
  'nvim-treesitter/nvim-treesitter',
  event = "BufReadPost",
  build = function()
    pcall(require('nvim-treesitter.install').update { with_sync = true })
  end,
  config = function()
    require('nvim-treesitter.configs').setup {
      -- Add languages to be installed here that you want installed for treesitter
      ensure_installed = { 'c', 'cpp', 'go', 'lua', 'python', 'rust', 'help' },

      highlight = { enable = true },
      indent = { enable = true, disable = { 'python' } },
      incremental_selection = {
        enable = true,
        keymaps = {
          init_selection = '<c-space>',
          node_incremental = '<c-space>',
          scope_incremental = '<c-s>',
          node_decremental = '<c-backspace>',
        },
      },
      textobjects = {
        select = {
          enable = true,
          lookahead = true, -- Automatically jump forward to textobj, similar to targets.vim
          keymaps = {
            -- You can use the capture groups defined in textobjects.scm
            ['aa'] = '@parameter.outer',
            ['ia'] = '@parameter.inner',
            ['af'] = '@function.outer',
            ['if'] = '@function.inner',
            ['ac'] = '@class.outer',
            ['ic'] = '@class.inner',
          },
        },
        move = {
          enable = true,
          set_jumps = true, -- whether to set jumps in the jumplist
          goto_next_start = {
            [']m'] = '@function.outer',
            [']c'] = '@class.outer',
          },
          goto_next_end = {
            [']M'] = '@function.outer',
            [']C'] = '@class.outer',
          },
          goto_previous_start = {
            ['[m'] = '@function.outer',
            ['[c'] = '@class.outer',
          },
          goto_previous_end = {
            ['[M'] = '@function.outer',
            ['[C'] = '@class.outer',
          },
        },
        swap = {
          enable = true,
          swap_next = {
            ['<leader>a'] = '@parameter.inner',
          },
          swap_previous = {
            ['<leader>A'] = '@parameter.inner',
          },
        },
      },
    }
    -- Diagnostic keymaps
    vim.keymap.set('n', '[d', vim.diagnostic.goto_prev)
    vim.keymap.set('n', ']d', vim.diagnostic.goto_next)
    vim.keymap.set('n', '<leader>df', vim.diagnostic.open_float) -- diagnostic float
    vim.keymap.set('n', '<leader>dq', vim.diagnostic.setloclist) -- diagnostic quickfix
  end
}

-- Config luasnip
local lua_snip = {
  'L3MON4D3/LuaSnip',
  event = "InsertEnter",
  dependencies = {
    'rafamadriz/friendly-snippets',
    config = function()
      require('luasnip.loaders.from_vscode').lazy_load()
    end,
  },
}

-- Config nvim-cmp
local cmp = {
  'hrsh7th/nvim-cmp',
  event = "InsertEnter",
  dependencies = { 'hrsh7th/cmp-buffer', 'hrsh7th/cmp-path', 'hrsh7th/cmp-nvim-lsp',
    'hrsh7th/cmp-nvim-lsp-signature-help',
    'L3MON4D3/LuaSnip', 'saadparwaiz1/cmp_luasnip',
  },
  config = function()
    local cmp = require 'cmp'
    local luasnip = require 'luasnip'

    cmp.setup {
      snippet = {
        expand = function(args)
          luasnip.lsp_expand(args.body)
        end,
      },
      mapping = cmp.mapping.preset.insert {
        ['<C-d>'] = cmp.mapping.scroll_docs(-4),
        ['<C-f>'] = cmp.mapping.scroll_docs(4),
        ['<C-Space>'] = cmp.mapping.complete(),
        ['<CR>'] = cmp.mapping.confirm {
          behavior = cmp.ConfirmBehavior.Replace,
          select = true,
        },
        ['<Tab>'] = cmp.mapping(function(fallback)
          if cmp.visible() then
            cmp.select_next_item()
          elseif luasnip.expand_or_jumpable() then
            luasnip.expand_or_jump()
          else
            fallback()
          end
        end, { 'i', 's' }),
        ['<S-Tab>'] = cmp.mapping(function(fallback)
          if cmp.visible() then
            cmp.select_prev_item()
          elseif luasnip.jumpable(-1) then
            luasnip.jump(-1)
          else
            fallback()
          end
        end, { 'i', 's' }),
      },
      sources = {
        { name = 'nvim_lsp' },
        { name = 'luasnip' },
        { name = 'buffer' },
        { name = 'path' },
        { name = 'nvim_lsp_signature_help' }
      },
    }
  end
}

-- Config LSP
local lspconfig = {
  'neovim/nvim-lspconfig',
  event = { "BufReadPre", "BufNewFile" },
  dependencies = {
    -- Automatically install LSPs to stdpath for neovim
    { 'williamboman/mason.nvim', config = true, cmd = "Mason" },
    'williamboman/mason-lspconfig.nvim',
    -- Useful status updates for LSP
    { 'j-hui/fidget.nvim', config = true },
    -- Additional lua configuration, makes nvim stuff amazing
    { 'folke/neodev.nvim', config = true },
    'hrsh7th/cmp-nvim-lsp',
  },
  config = function()
    -- LSP settings.
    --  This function gets run when an LSP connects to a particular buffer.
    local on_attach = function(_, bufnr)
      -- In this case, we create a function that lets us more easily define mappings specific
      -- for LSP related items. It sets the mode, buffer and description for us each time.
      local nmap = function(keys, func, desc)
        if desc then
          desc = 'LSP: ' .. desc
        end
        vim.keymap.set('n', keys, func, { buffer = bufnr, desc = desc })
      end

      nmap('<leader>rn', vim.lsp.buf.rename, '[R]e[n]ame')
      nmap('<leader>ca', vim.lsp.buf.code_action, '[C]ode [A]ction')

      nmap('gd', vim.lsp.buf.definition, '[G]oto [D]efinition')
      nmap('gr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences')
      nmap('gI', vim.lsp.buf.implementation, '[G]oto [I]mplementation')
      nmap('<leader>D', vim.lsp.buf.type_definition, 'Type [D]efinition')
      nmap('<leader>ds', require('telescope.builtin').lsp_document_symbols, '[D]ocument [S]ymbols')
      nmap('<leader>ws', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[W]orkspace [S]ymbols')

      -- See `:help K` for why this keymap
      nmap('K', vim.lsp.buf.hover, 'Hover Documentation')
      nmap('<C-k>', vim.lsp.buf.signature_help, 'Signature Documentation')

      -- Lesser used LSP functionality
      nmap('gD', vim.lsp.buf.declaration, '[G]oto [D]eclaration')
      nmap('<leader>wa', vim.lsp.buf.add_workspace_folder, '[W]orkspace [A]dd Folder')
      nmap('<leader>wr', vim.lsp.buf.remove_workspace_folder, '[W]orkspace [R]emove Folder')
      nmap('<leader>wl', function()
        print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
      end, '[W]orkspace [L]ist Folders')

      -- Create a command `:Format` local to the LSP buffer
      vim.api.nvim_buf_create_user_command(bufnr, 'Format', function(_)
        vim.lsp.buf.format()
      end, { desc = 'Format current buffer with LSP' })
      vim.keymap.set('n', '<Leader>f', ":Format<cr>")
    end

    -- Enable the following language servers
    local servers = {
      -- clangd = {},
      -- gopls = {},
      -- pyright = {},
      -- rust_analyzer = {},
      -- pylsp = {
      --   configurationSources = { "flake8" },
      --   plugins = {
      --     jedi_completion = {
      --       include_params = true -- this line enables snippets
      --     },
      --   },
      -- },
      sumneko_lua = {
        Lua = {
          workspace = { checkThirdParty = false },
          telemetry = { enable = false },
        },
      },
    }

    -- 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)

    -- Ensure the servers above are installed
    local mason_lspconfig = require 'mason-lspconfig'
    mason_lspconfig.setup {
      ensure_installed = vim.tbl_keys(servers),
    }
    mason_lspconfig.setup_handlers {
      function(server_name)
        require('lspconfig')[server_name].setup {
          capabilities = capabilities,
          on_attach = on_attach,
          settings = servers[server_name],
        }
      end,
    }
  end
}

-- Config autopairs
local autopairs = {
  "windwp/nvim-autopairs",
  event = "InsertEnter",
  config = function()
    require("nvim-autopairs").setup {}
    -- config autopairs
    local cmp_autopairs = require('nvim-autopairs.completion.cmp')
    local nvim_cmp = require('cmp')
    nvim_cmp.event:on(
      'confirm_done',
      cmp_autopairs.on_confirm_done()
    )
  end
}

-- Config illuminate
local illuminate = {
  'RRethy/vim-illuminate',
  event = "BufReadPost",
  config = function()
    require("illuminate").configure({
      delay = 200,
      filetypes_denylist = {
        "NvimTree",
        "toggleterm",
        "TelescopePrompt",
      },
    })
  end,
  keys = {
    {
      "]r",
      function()
        require("illuminate").goto_next_reference(false)
      end,
      desc = "illuminate Next Reference",
    },
    {
      "[r",
      function()
        require("illuminate").goto_prev_reference(false)
      end,
      desc = "illuminate Prev Reference",
    },
  },
}

-- Config telescope
local telescope = {
  'nvim-telescope/telescope.nvim',
  version = '0.1.x',
  dependencies = { 'nvim-lua/plenary.nvim' },
  config = function()
    require('telescope').setup {
      defaults = {
        mappings = {
          i = {
            ['<C-u>'] = false,
            ['<C-d>'] = false,
          },
        },
      },
    }

    -- Enable telescope fzf native, if installed
    pcall(require('telescope').load_extension, 'fzf')

    -- Keymap for toggling telescope
    vim.keymap.set('n', '<leader>?', require('telescope.builtin').oldfiles, { desc = '[?] Find recently opened files' })
    vim.keymap.set('n', '<leader><space>', require('telescope.builtin').buffers, { desc = '[ ] Find existing buffers' })
    vim.keymap.set('n', '<leader>sb', function()
      -- You can pass additional configuration to telescope to change theme, layout, etc.
      require('telescope.builtin').current_buffer_fuzzy_find(require('telescope.themes').get_dropdown {
        winblend = 10,
        previewer = false,
      })
    end, { desc = '[S]earch [B]uffer' })
    vim.keymap.set('n', '<leader>p', require('telescope.builtin').find_files,
      { desc = 'Ctrl-P: Search file in current directory' })
    vim.keymap.set('n', '<leader>sh', require('telescope.builtin').help_tags, { desc = '[S]earch [H]elp' })
    vim.keymap.set('n', '<leader>sw', require('telescope.builtin').grep_string, { desc = '[S]earch current [W]ord' })
    vim.keymap.set('n', '<leader>sg', require('telescope.builtin').live_grep, { desc = '[S]earch by [G]rep' })
    vim.keymap.set('n', '<leader>sd', require('telescope.builtin').diagnostics, { desc = '[S]earch [D]iagnostics' })
  end
}

-- Config Lazy
require('lazy').setup({

  -- Theme
  catppuccin,

  -- UI related
  lualine,
  indent_blankline,
  gitsigns,
  barbar,
  toggleterm,
  nvimtree,

  -- Coding
  treesitter,
  { 'nvim-treesitter/nvim-treesitter-textobjects', event = "BufReadPost", dependencies = { 'nvim-treesitter' } },
  lua_snip,
  cmp,
  lspconfig,
  autopairs,
  illuminate,
  { 'numToStr/Comment.nvim', config = true }, -- "gc" to comment visual regions/lines}
  'tpope/vim-sleuth', -- Detect tabstop and shiftwidth automatically

  -- Fuzzy Finder (files, lsp, etc)
  telescope,
  -- Fuzzy Finder Algorithm which requires local dependencies to be built. Only load if `make` is available
  { 'nvim-telescope/telescope-fzf-native.nvim', build = 'make', cond = vim.fn.executable 'make' == 1 },

})

-- The line beneath this is called `modeline`. See `:help modeline`
-- vim: ts=2 sts=2 sw=2 et

图形界面

虽然在 Windows Terminal 里用 TUI 的体验已经挺不错了, 但单独的 GUI 程序还是有必要的。

之前用图形界面主要尝试过 neovide,buffer 的平滑滚动很舒服, 这次发现在 Windows 下用问题还是有点多。

后来我找到了 fvim 这个项目, 解决了很多痛点,可配置项很多,配置也很方便,输入法界面也正常。 可惜看起来最近维护不是很活跃,希望这个项目能继续长久发展下去。

我的 ginit.vim 文件:

lua << EOF

-- config neovide
if vim.fn.exists("g:neovide") == 1 then
  vim.g.neovide_transparency = 0.98
  vim.g.neovide_floating_blur_amount_x = 2.0
  vim.g.neovide_floating_blur_amount_y = 2.0
  vim.opt.guifont = { "JetBrainsMono NF", ":h11" }
end

-- config fvim
if vim.fn.exists('g:fvim_loaded') == 1 then
  vim.opt.guifont = { "JetBrains Mono", ":h15" } -- with embedded NF font
  vim.keymap.set('n', '<C-ScrollWheelUp>', '<cmd>set guifont=+<cr>', { silent = true })
  vim.keymap.set('n', '<C-ScrollWheelDown>', '<cmd>set guifont=-<cr>', { silent = true })
  vim.keymap.set('n', '<A-CR>', '<cmd>FVimToggleFullScreen<cr>', { silent = true })
  vim.cmd [[ FVimCursorSmoothMove v:true ]]
  vim.cmd [[ FVimCursorSmoothBlink v:true ]]
  vim.cmd [[ FVimBackgroundComposition 'blur' ]]
  vim.cmd [[ FVimBackgroundOpacity 0.9 ]]
  vim.cmd [[ FVimBackgroundAltOpacity 0.9 ]]
  vim.cmd [[ FVimCustomTitleBar v:true ]]
  vim.cmd [[ FVimUIPopupMenu v:true ]]
end

require('catppuccin').setup({
  flavour = 'mocha', -- latte, frappe, macchiato, mocha
  transparent_background = false,
  term_colors = true,
})
vim.cmd.colorscheme 'catppuccin'

EOF

由于 fvim 发布的只是个压缩包, 为了方便图形界面使用,还需要配置下注册表。 自带的注册功能有些毛病, 现在也还没修,我也不想自己编译,就在注册表的HKEY_CLASSES_ROOT\*\shell 下仿照 VSCode 新建了一项,这样就有右键菜单打开了。不够完善但勉强能用。

我给 command 设置的值是"C:\Program Files\fvim\FVim.exe" "-c" "cd %%:p:h" "%1", 这样写可以右键菜单打开文件的同时同步当前工作目录,与文件管理器的集成更友好。

远程编辑

我一开始觉得 neovim 的远程编辑功能不太有必要,直接 ssh 上去写就可以了, 这次又研究了下觉得还是有用的。

在服务器 nvim --listen <TCP addr> --headless,然后用 TUI / GUI 客户端远程连, 对我来说主要的好处是服务端不退出可以一直保持着这次编辑会话的现场, 跟 VSCode 的远程编辑的体验很像。 fvim 甚至还直接提供了 --ssh 选项直接连 ssh 配置里的机器,更加方便。

当然整体上还是不如 VSCode,现在只有基础的编辑,感觉还缺少一些高级功能。

总结

在编辑器上的折腾肯定是无止境的,一些自以为能增加生产力的想法实际上可能并不行, 更重要的是要去实践。希望这次折腾的成果能持续得长一些。