Open15

Neovim やる

おーみーおーみー

とりあえずLanguage Server Protocolに基づいた補完が出ないとどうにもならないのでLSP周りを調べていく。

Neovimにはbuilt-inでLSPクライアントが搭載されていて、neovim/nvim-lspconfigを入れるといい感じの設定が入るらしい。

https://github.com/neovim/nvim-lspconfig

おーみーおーみー

パッケージマネージャを導入するのがめんどくさいなあ。標準でも特定のパスにパッケージをぶち込めばいけるらしい。~/.config/nvim/pack/xxx/ に入れればいけるっぽいね。:set packpath で把握できる。

最強のインストールコマンド

gh repo clone neovim/nvim-lspconfig ~/.config/nvim/pack/nvim-lspconfig
おーみーおーみー

https://vim.blue/command/

:command を使って :Format のようなコマンドを定義できる。キーバインドを当てるほどでもないけどいざ打つときに :lua vim.lsp.buf.hogehoge とか打つのはめんどくさいというような操作に便利そう。

おーみーおーみー

:Tutor やってる。dw を打つと次の単語まで削除、d$ を打つと行末まで削除になるが、これは d (delete) というoperatorに w $ というmotionを組み合わせたものと解される。また dd はよく使うので特別に1行削除に割り当てられている。

u でundo、<C-r> でredo。

おーみーおーみー

p P で前に削除したテキストを貼り付けできる。c は文字を削除してインサートモードに入る。/ で前方、? で後方に検索。% で対応する括弧に飛べる。

おーみーおーみー

:s/thee/the で現在の行の最初の theethe に置き換える。:s/thee/the/g ですべて置き換え、:%s/thee/the/g でファイル全体。

おーみーおーみー

:!ls のようにしてシェルコマンドを実行する。v でビジュアル選択モードに移行、カーソルを動かすと選択できる。その状態で :w するとそこだけ保存できる。

:r ファイル名 でファイルの内容を展開できる。:r !ls のようにしてコマンドの結果を展開できる。

おーみーおーみー

v でよしなに選択して y でヤンク (コピー)、p P でペースト。yw とかも使える。

おーみーおーみー

tree-sitterというやつでシンタックスハイライトをより強力にできる (標準のハイライトは正規表現ベースらしい)。

https://github.com/nvim-treesitter/nvim-treesitter

VS CodeではGitHub Dark Defaultを使っていたのだが、

https://github.com/projekt0n/github-nvim-theme

を使えばNeovimでも同じようなテーマが使えることがわかった。tree-sitterに対応している上に各ターミナル向けの色設定まであって最高。

おーみーおーみー
-- Packages

require('packer').startup(function(use)
  use 'wbthomason/packer.nvim'
  use 'neovim/nvim-lspconfig'

  use 'hrsh7th/nvim-cmp'
  use 'hrsh7th/cmp-nvim-lsp'

  use 'L3MON4D3/LuaSnip'
  use 'saadparwaiz1/cmp_luasnip'

  use 'lambdalisue/fern.vim'
  use 'antoinemadec/FixCursorHold.nvim'

  use 'nvim-treesitter/nvim-treesitter'

  use 'projekt0n/github-nvim-theme'

  use {
    'nvim-telescope/telescope.nvim',
    requires = {{'nvim-lua/plenary.nvim'}}
  }

  use {
    'jose-elias-alvarez/null-ls.nvim',
    requires = {{'nvim-lua/plenary.nvim'}}
  }

  use 'ray-x/lsp_signature.nvim'

  use {
    "folke/trouble.nvim",
    requires = "kyazdani42/nvim-web-devicons",
    config = function()
      require'trouble'.setup {}
    end
  }

  use 'machakann/vim-sandwich'

  use 'windwp/nvim-autopairs'

  use {
    'nvim-neo-tree/neo-tree.nvim',
      branch = 'v2.x',
      requires = {
        'nvim-lua/plenary.nvim',
        'kyazdani42/nvim-web-devicons',
        'MunifTanjim/nui.nvim',
      }
  }
end)

vim.cmd([[let g:neo_tree_remove_legacy_commands = 1]])

vim.cmd([[
  augroup packer_user_config
    autocmd!
    autocmd BufWritePost init.lua source <afile> | PackerCompile
  augroup end
]])


-- Autopairs
require'nvim-autopairs'.setup {}

-- Completions

local cmp_autopairs = require'nvim-autopairs.completion.cmp'
local cmp = require'cmp'

cmp.event:on('confirm_done', cmp_autopairs.on_confirm_done { map_char = { tex = '' } })

cmp.setup({
  snippet = {
    expand = function(args)
      require('luasnip').lsp_expand(args.body)
    end,
  },
  mapping = cmp.mapping.preset.insert({
    ['<C-b>'] = cmp.mapping.scroll_docs(-4),
    ['<C-f>'] = cmp.mapping.scroll_docs(4),
    ['<C-Space>'] = cmp.mapping.complete(),
    ['<C-e>'] = cmp.mapping.abort(),
    ['<CR>'] = cmp.mapping.confirm({ select = true }),
  }),
  sources = cmp.config.sources({
    { name = 'nvim_lsp' },
    { name = 'luasnip' },
  })
})


-- Ex Commands

vim.cmd('command! Format :lua vim.lsp.buf.formatting()')
vim.cmd('command! -nargs=* Terminal vsplit | wincmd j | vertical resize 80 | terminal <args>')


-- Keybindings

local opts = { noremap = true, silent = true }

vim.api.nvim_set_keymap('n', '<Space>p', '<cmd>Telescope fd<CR>', opts)
vim.keymap.set('n', '<Space>e', '<cmd>Fern . -drawer <CR>')
vim.keymap.set('n', '<Space>t', '<cmd>Terminal<CR>')
vim.keymap.set('n', '<Space>f', '<cmd>Format<CR>')

-- Move focus
vim.keymap.set('n', '<Space>j', '<C-w>w')
vim.keymap.set('n', '<Space>k', '<C-w>W')


-- Language servers

local lsp_set_keymap = function(client, bufnr)
  vim.api.nvim_buf_set_keymap(bufnr, 'n', 'K', '<cmd>lua vim.lsp.buf.hover()<CR>', opts)

end

local servers = { 'rust_analyzer', 'ocamllsp', 'eslint', 'prismals'}
for _, lsp in pairs(servers) do
  require('lspconfig')[lsp].setup {
    on_attach = function(client, bufnr)
      lsp_set_keymap(client, bufnr)
    end,
  }
end

-- In some languages we prefer to use external formatters (i.e. Prettier) rather than ones servers provide
local formatting_disabled_servers = { 'jsonls', 'html', 'cssls', 'volar', 'graphql', 'tsserver' }
for _, lsp in pairs(formatting_disabled_servers) do
  require('lspconfig')[lsp].setup {
    on_attach = function(client, bufnr)
      lsp_set_keymap(client, bufnr)
      client.resolved_capabilities.document_formatting = false
    end,
  }
end


-- lsp_signature
require'lsp_signature'.setup {}

-- null-ls
local nullls = require'null-ls'
nullls.setup {
  sources = {
    nullls.builtins.formatting.prettier,
  },
}


-- Tree-sitter
require'nvim-treesitter.configs'.setup {
  highlight = {
    enable = true,
    disable = {},
  },
  incremental_selection = {
    enable = true,
    keymaps = {
      init_selection = "gnn",
      node_incremental = "grn",
      node_decremental = "grm",
    },
  },
  ensure_installed = {
    'bash',
    'c',
    'clojure',
    'cpp',
    'css',
    'dockerfile',
    'go',
    'html',
    'javascript',
    'json',
    'jsonc',
    'lua',
    'make',
    'nix',
    'ocaml',
    'ocaml_interface',
    'prisma',
    'rust',
    'scheme',
    'toml',
    'typescript',
    'vue',
    'yaml',
  },
}


-- Color theme

require'github-theme'.setup {
  theme_style = 'dark_default',
}

-- General configurations

vim.wo.number = true
vim.o.expandtab = true
vim.o.tabstop = 2
vim.o.shiftwidth = 0
-- Open terminal in insert mode
vim.cmd('autocmd TermOpen * startinsert')