Edit page nwiz.lua
[wiki.git] / nwiz.lua
1 --
2 -- “This is the editor of a Real Coder.
3 --  Not as clumsy as a full blown IDE.
4 --  An elegant editor for a more civilized age.”
5 --    ― Bernie Innocenti, https://codewiz.org
6 --
7
8 -- Set this to replace GitHub default URLs
9 -- local github_url = 'https://github.com/'
10 local github_url = 'git@github.com:'
11
12 -- Bootstrap Packer if not already installed
13 local fn = vim.fn
14 local install_path = fn.stdpath('data')..'/site/pack/packer/start/packer.nvim'
15 if fn.empty(fn.glob(install_path)) > 0 then
16   local packer_url = github_url .. "wbthomason/packer.nvim"
17   print("Bootstrapping packer from ", packer_url)
18   packer_bootstrap = fn.system({'git', 'clone', '--depth', '1', packer_url, install_path})
19 end
20
21 require('packer').startup({function(use)
22   use 'wbthomason/packer.nvim'
23   use { 'nvim-treesitter/nvim-treesitter',
24         run = function() require('nvim-treesitter.install').update({ with_sync = true }) end, }
25   use { 'nvim-telescope/telescope.nvim', requires = { {'nvim-lua/plenary.nvim'} } }
26   use { 'nvim-lualine/lualine.nvim', requires = { 'kyazdani42/nvim-web-devicons', opt = true } }
27   use { 'kyazdani42/nvim-tree.lua', requires = { 'kyazdani42/nvim-web-devicons', }, tag = 'nightly' }
28   use 'dstein64/nvim-scrollview'
29
30   use 'neovim/nvim-lspconfig'
31   use 'hrsh7th/cmp-nvim-lsp'
32   use 'hrsh7th/cmp-buffer'
33   use 'hrsh7th/cmp-path'
34   use 'hrsh7th/cmp-cmdline'
35   use 'hrsh7th/nvim-cmp'
36   use 'hrsh7th/cmp-vsnip'
37   use 'hrsh7th/vim-vsnip'
38   -- use 'hrsh7th/cmp-nvim-lsp-signature-help'
39   use "ray-x/lsp_signature.nvim"
40
41   if packer_bootstrap then
42     -- FIXME: this runs asynchronously, causing the rest of the
43     --        lua script to fail on first run
44     require('packer').sync()
45   end
46 end,
47 config = {
48   git = { default_url_format = github_url .. '%s.git' }
49 }})
50
51 -- nvim-treesitter --
52
53 if github_url ~= nil then
54   -- Replace GitHub url for all treesitter plugins
55   for _, config in pairs(require("nvim-treesitter.parsers").get_parser_configs()) do
56     config.install_info.url = config.install_info.url:gsub("https://github.com/", github_url)
57   end
58 end
59
60 require("nvim-treesitter.install").prefer_git = true
61 require("nvim-treesitter.configs").setup {
62   highlight = {
63     enable = true,
64   },
65 }
66
67 local opts = { noremap=true, silent=true }
68 local map = vim.api.nvim_set_keymap
69
70 require("telescope").setup()
71 map('n', '<C-p>', '<cmd>Telescope git_files<cr>', opts)
72 map('n', 'ff', '<cmd>Telescope find_files<cr>', opts)
73 map('n', 'fg', '<cmd>Telescope live_grep<cr>', opts)
74 map('n', 'fb', '<cmd>Telescope buffers<cr>', opts)
75 map('n', 'fh', '<cmd>Telescope help_tags<cr>', opts)
76
77 require("nvim-tree").setup()
78 map('n', 'o', ':NvimTreeFocus<CR>', opts)
79 map('n', '<S-o>', ':NvimTreeClose<CR>', opts)
80 map('n', '<C-o>', ':NvimTreeFindFile<CR>', opts)
81
82 require('lualine').setup {
83   options = {
84     theme = 'codedark',
85     section_separators = { left = '', right = '' },
86     component_separators = { left = '', right = '' },
87     -- section_separators = '', component_separators = '',
88     show_filename_only = false,
89     globalstatus = false,
90   },
91   sections = {
92     lualine_a = {
93       { 'mode', fmt = function(str) return str:sub(1,1) end }
94     },
95     lualine_b = {
96       { 'branch', fmt = function(branch) return branch == 'master' and '' or branch end },
97     },
98     lualine_c = {
99       { 'filename', path = 1, },
100     },
101     lualine_x = {
102       { 'filetype', icon_only = true, },
103     },
104     lualine_y = {},
105   },
106 }
107
108 -- nvim-cmp --
109
110 local kind_icons = {
111   Text = "",
112   Method = "",
113   Function = "",
114   Constructor = "",
115   Field = "",
116   Variable = "",
117   Class = "ﴯ",
118   Interface = "",
119   Module = "",
120   Property = "ﰠ",
121   Unit = "",
122   Value = "",
123   Enum = "",
124   Keyword = "",
125   Snippet = "",
126   Color = "",
127   File = "",
128   Reference = "",
129   Folder = "",
130   EnumMember = "",
131   Constant = "",
132   Struct = "",
133   Event = "",
134   Operator = "",
135   TypeParameter = ""
136 }
137
138 local has_words_before = function()
139   local line, col = unpack(vim.api.nvim_win_get_cursor(0))
140   return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil
141 end
142
143 local feedkey = function(key, mode)
144   vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, true, true), mode, true)
145 end
146
147 local cmp = require'cmp'
148 cmp.setup({
149   -- view  = { entries = "native" },
150   formatting = {
151     fields = {
152       "kind",
153       "abbr",
154       "menu",
155     },
156     format = function(entry, vim_item)
157       vim_item.kind = kind_icons[vim_item.kind]
158       local max_width = 25
159       if vim_item.menu ~= nil and string.len(vim_item.menu) > max_width then
160         vim_item.menu = string.sub(vim_item.menu, 1, max_width - 1) .. "…"
161       end
162       return vim_item
163     end,
164   },
165   snippet = {
166     -- REQUIRED - you must specify a snippet engine
167     expand = function(args)
168       vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users.
169     end,
170   },
171   mapping = cmp.mapping.preset.insert({
172     ['<C-b>'] = cmp.mapping(cmp.mapping.scroll_docs(-4), { 'i', 'c' }),
173     ['<C-f>'] = cmp.mapping(cmp.mapping.scroll_docs(4), { 'i', 'c' }),
174     ['<C-Space>'] = cmp.mapping(cmp.mapping.complete(), { 'i', 'c' }),
175     ['<C-y>'] = cmp.config.disable, -- Specify `cmp.config.disable` if you want to remove the default `<C-y>` mapping.
176     ['<C-e>'] = cmp.mapping({
177       i = cmp.mapping.abort(),
178       c = cmp.mapping.close(),
179     }),
180     ['<CR>'] = cmp.mapping.confirm({ select = true }),
181
182     ["<Tab>"] = cmp.mapping(function(fallback)
183       if cmp.visible() then
184         cmp.select_next_item()
185       elseif vim.fn["vsnip#available"](1) == 1 then
186         feedkey("<Plug>(vsnip-expand-or-jump)", "")
187       elseif has_words_before() then
188         cmp.complete()
189       else
190         fallback() -- Sends a already mapped key. In this case, it's probably `<Tab>`.
191       end
192     end, { "i", "s" }),
193
194     ["<S-Tab>"] = cmp.mapping(function()
195       if cmp.visible() then
196         cmp.select_prev_item()
197       elseif vim.fn["vsnip#jumpable"](-1) == 1 then
198         feedkey("<Plug>(vsnip-jump-prev)", "")
199       end
200     end, { "i", "s" }),
201   }),
202   sources = cmp.config.sources({
203     { name = 'nvim_lsp' },
204     -- { name = 'nvim_lsp_signature_help', },
205   }, {
206     { name = 'vsnip' },
207     -- { name = 'buffer' },
208   })
209 })
210
211 -- cmp.setup.cmdline('/', {
212 --  mapping = cmp.mapping.preset.cmdline(),
213 --  completion = {
214 --    keyword_length = 2,
215 --  },
216 --  sources = {
217 --    { name = 'buffer' }
218 --  }
219 --})
220
221 cmp.setup.cmdline(':', {
222   mapping = cmp.mapping.preset.cmdline(),
223   completion = {
224     keyword_length = 2,
225   },
226   sources = cmp.config.sources({
227     { name = 'path' }
228   }, {
229     { name = 'cmdline' }
230   })
231 })
232
233
234 local capabilities = vim.lsp.protocol.make_client_capabilities()
235 capabilities = require('cmp_nvim_lsp').update_capabilities(capabilities)
236
237 -- Disable snippets support for rust-analyzer because it spams the completion
238 capabilities.textDocument.completion.completionItem.snippetSupport = false
239 -- print(vim.inspect(capabilities))
240
241 -- lsp-config --
242
243 -- vim.lsp.set_log_level("debug")
244 vim.diagnostic.config({
245   underline = true,
246   virtual_text = false,
247   update_in_insert = false,
248   float = {
249     focusable = false,
250     style = 'minimal',
251     border = 'rounded',
252     source = 'always',
253     header = '',
254     prefix = '',
255   }
256 })
257
258 local on_attach = function(client, bufnr)
259   local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
260   local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end
261
262   buf_set_option("formatexpr", "v:lua.vim.lsp.formatexpr()")
263   buf_set_option("omnifunc", "v:lua.vim.lsp.omnifunc")
264   buf_set_option("tagfunc", "v:lua.vim.lsp.tagfunc")
265
266   vim.opt.completeopt = {"menu", "menuone", "noinsert"}
267
268   require "lsp_signature".on_attach({
269     hi_parameter = "IncSearch"
270   })
271
272   local opts = { noremap=true, silent=true }
273   -- See `:help vim.lsp.*` for documentation on any of the below functions
274   buf_set_keymap('n', 'gD', '<Cmd>lua vim.lsp.buf.declaration()<CR>', opts)
275   buf_set_keymap('n', '<C-]>', '<Cmd>lua vim.lsp.buf.declaration()<CR>', opts)
276   buf_set_keymap('n', 'gd', '<Cmd>lua vim.lsp.buf.definition()<CR>', opts)
277   buf_set_keymap('n', 'K',  '<Cmd>lua vim.lsp.buf.hover()<CR>', opts)
278   buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
279   buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
280   buf_set_keymap('n', '<space>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
281   buf_set_keymap('n', '<space>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
282   buf_set_keymap('n', '<space>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
283   buf_set_keymap('n', '<space>D', '<cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
284   buf_set_keymap('n', '<space>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
285   buf_set_keymap('n', '<space>ca', '<cmd>lua vim.lsp.buf.code_action()<CR>', opts)
286   buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
287
288   buf_set_keymap('n', '<space>e', '<cmd>lua vim.diagnostic.open_float()<CR>', opts)
289   buf_set_keymap('n', '<space>q', '<cmd>lua vim.diagnostic.setloclist()<CR>', opts)
290   buf_set_keymap('n', '[d', '<cmd>lua vim.diagnostic.goto_prev()<CR>', opts)
291   buf_set_keymap('n', ']d', '<cmd>lua vim.diagnostic.goto_next()<CR>', opts)
292
293   buf_set_keymap('n', "=", "<cmd>lua vim.lsp.buf.formatting()<CR>", opts)
294   buf_set_keymap('v', "=", "<cmd>lua vim.lsp.buf.formatting()<CR>", opts)
295   buf_set_keymap('n', "gq", "<cmd>lua vim.lsp.buf.formatting()<CR>", opts)
296   buf_set_keymap('v', "gq", "<cmd>lua vim.lsp.buf.formatting()<CR>", opts)
297 end
298
299 local lspconfig = require'lspconfig';
300 lspconfig.rust_analyzer.setup{
301   on_attach = on_attach,
302   capabilities = capabilities,
303 }
304 lspconfig.tsserver.setup{
305   on_attach = on_attach,
306   capabilities = capabilities,
307 }
308 lspconfig.clangd.setup{
309   on_attach = on_attach,
310   capabilities = capabilities,
311   -- cmd = { vim.loop.os_homedir() .. "clangd", "--background-index" },
312   cmd = { "clangd", "--background-index" },
313   root_dir = lspconfig.util.root_pattern("compile_commands.json", "compile_flags.txt"),
314 }
315 lspconfig.pylsp.setup{
316   on_attach = on_attach,
317   capabilities = capabilities,
318   settings = {
319     pylsp = {
320       configurationSources = {"pylint"},
321       plugins = {
322         autopep8 = { enabled = true },
323         mypy = { enabled = true },
324         pylint = { enabled = true },
325         flake8 = { enabled = false },
326         pycodestyle = { enabled = false },
327         pyflakes = { enabled = false },
328       }
329     }
330   }
331 }
332
333 -- Alt-key window navication and more
334 map('t', '<A-h>', '<C-\\><C-n>h', opts)
335 map('t', '<A-j>', '<C-\\><C-n>j', opts)
336 map('t', '<A-k>', '<C-\\><C-n>k', opts)
337 map('t', '<A-l>', '<C-\\><C-n>l', opts)
338 map('i', '<A-h>', '<C-\\><C-n>h', opts)
339 map('i', '<A-j>', '<C-\\><C-n>j', opts)
340 map('i', '<A-k>', '<C-\\><C-n>k', opts)
341 map('i', '<A-l>', '<C-\\><C-n>l', opts)
342 map('n', '<A-h>', '<C-w>h', opts)
343 map('n', '<A-j>', '<C-w>j', opts)
344 map('n', '<A-k>', '<C-w>k', opts)
345 map('n', '<A-l>', '<C-w>l', opts)
346