···
1
+
require('gruvbox').setup {
2
+
terminal_colors = false,
4
+
vim.cmd [[colorscheme gruvbox]]
5
+
vim.api.nvim_command('hi Normal guibg=NONE ctermbg=NONE')
7
+
highlight SignColumn ctermbg=none guibg=none
11
+
vim.o.mousemodel = 'extend'
13
+
vim.o.shiftwidth = 4
15
+
vim.o.softtabstop = 4
16
+
vim.bo.autoindent = true
17
+
vim.bo.smartindent = true
19
+
vim.o.fixendofline = false
21
+
vim.o.conceallevel = 0
22
+
vim.wo.signcolumn = 'yes'
24
+
vim.o.smartcase = true
26
+
vim.o.spelllang = 'en'
27
+
vim.o.spellfile = os.getenv('HOME') .. '/.config/vim/spell.en.utf-8.add'
28
+
vim.opt_local.spell = true
29
+
vim.opt_local.spelllang = 'en_gb'
31
+
vim.wo.number = true
32
+
vim.api.nvim_create_augroup('numbertoggle', { clear = true })
33
+
vim.api.nvim_create_autocmd({ 'BufEnter', 'FocusGained', 'InsertLeave', 'WinEnter' }, {
34
+
group = 'numbertoggle',
36
+
callback = function()
37
+
if vim.wo.number and vim.fn.mode() ~= 'i' then
38
+
vim.wo.relativenumber = true
42
+
vim.api.nvim_create_autocmd({ 'BufLeave', 'FocusLost', 'InsertEnter', 'WinLeave' }, {
43
+
group = 'numbertoggle',
45
+
callback = function()
46
+
if vim.wo.number then
47
+
vim.wo.relativenumber = false
52
+
vim.g.mapleader = ' '
54
+
vim.opt.timeout = false
55
+
-- remove warning delay
56
+
vim.opt.readonly = false
58
+
vim.opt.undodir = vim.fn.stdpath('data') .. 'undodir'
59
+
vim.opt.undofile = true
61
+
vim.opt.hlsearch = false
63
+
vim.opt.updatetime = 500
65
+
vim.o.foldlevel = 99
67
+
vim.g.vim_markdown_follow_anchor = 1
69
+
vim.o.cursorcolumn = true
70
+
vim.o.cursorline = true
72
+
local key_mapper = function(mode, key, result)
73
+
vim.api.nvim_set_keymap(
77
+
{ noremap = true, silent = true }
81
+
key_mapper('n', '<leader>w', ':w<CR>')
83
+
key_mapper('n', 'ZA', ':cquit<Enter>')
85
+
key_mapper('t', '<Esc>', '<C-\\><C-n>')
87
+
key_mapper('n', '<leader>id',
88
+
[[<Cmd>lua vim.api.nvim_put({vim.fn.strftime('%Y-%m-%d')}, 'c', true, true)<CR>]])
90
+
key_mapper('n', '!', ':term ')
92
+
vim.keymap.set('n', '<leader>v', vim.cmd.Git)
94
+
key_mapper('n', '<leader>m', ':make<Enter>')
96
+
-- go though spelling mistakes
97
+
key_mapper('n', '<C-s>', ']s1z=')
99
+
key_mapper('v', '<C-J>', ":m '>+1<CR>gv=gv")
100
+
key_mapper('v', '<C-K>', ":m '<-2<CR>gv=gv")
102
+
key_mapper('n', '<C-d>', '<C-d>zz')
103
+
key_mapper('n', '<C-u>', '<C-u>zz')
104
+
key_mapper('n', 'n', 'nzzzv')
105
+
key_mapper('n', 'N', 'Nzzzv')
107
+
vim.keymap.set({ 'n', 'v' }, '<leader>y', [["+y]])
108
+
vim.keymap.set({ 'n', 'v' }, '<leader>p', [["+p]])
109
+
vim.keymap.set({ 'n', 'v' }, '<leader>P', [["+P]])
110
+
vim.keymap.set({ 'n', 'v' }, '<leader>d', [["+d]])
111
+
vim.keymap.set({ 'n', 'v' }, '<leader>D', [["+D]])
112
+
vim.keymap.set('n', '<leader>Y', [["+Y]])
114
+
vim.keymap.set('x', '<leader><C-p>', [["_dP]])
115
+
vim.keymap.set({ 'n', 'v' }, '<leader><C-d>', [["_d]])
117
+
vim.keymap.set('n', '<leader>S', [[:%s/\<<C-r><C-w>\>/<C-r><C-w>/gI<Left><Left><Left>]])
119
+
vim.keymap.set('n', '<leader>tc', ':tabnew<CR>')
120
+
vim.keymap.set('n', '<leader>te', ':tabedit ')
121
+
vim.keymap.set('n', '<leader>tn', ':tabnext<CR>')
122
+
vim.keymap.set('n', '<leader>tp', ':tabprevious<CR>')
123
+
vim.keymap.set('n', '<leader>tN', ':tabmove +1<CR>')
124
+
vim.keymap.set('n', '<leader>tP', ':tabmove -1<CR>')
125
+
vim.keymap.set('n', '<leader>tq', ':tabclose<CR>')
127
+
-- if in an SSH session enable OSC 52 system clipboard
128
+
-- required as neovim can't detect alacritty capabilities as it doesn't support XTGETTCAP
129
+
if os.getenv('SSH_TTY') then
130
+
vim.g.clipboard = {
133
+
['+'] = require('vim.ui.clipboard.osc52').copy('+'),
134
+
['*'] = require('vim.ui.clipboard.osc52').copy('*'),
137
+
['+'] = require('vim.ui.clipboard.osc52').paste('+'),
138
+
['*'] = require('vim.ui.clipboard.osc52').paste('*'),
143
+
vim.api.nvim_create_autocmd('TermOpen', {
145
+
command = 'startinsert',
150
+
require('nvim-surround').setup({})
151
+
require('Comment').setup()
152
+
vim.keymap.set('n', '<leader>u', vim.cmd.UndotreeToggle)
156
+
vim.g.gitgutter_map_keys = 0
157
+
vim.api.nvim_set_keymap('n', ']c', '<Plug>(GitGutterNextHunk)', {})
158
+
vim.api.nvim_set_keymap('n', '[c', '<Plug>(GitGutterPrevHunk)', {})
159
+
vim.api.nvim_set_keymap('n', '<Leader>hp', '<Plug>(GitGutterPreviewHunk)', {})
160
+
vim.api.nvim_set_keymap('n', '<Leader>hs', '<Plug>(GitGutterStageHunk)', {})
161
+
vim.api.nvim_set_keymap('n', '<Leader>hu', '<Plug>(GitGutterUndoHunk)', {})
163
+
highlight GitGutterAdd ctermbg=none guibg=none
164
+
highlight GitGutterDelete ctermbg=none guibg=none
165
+
highlight GitGutterChange ctermbg=none guibg=none
170
+
require('telescope').load_extension('fzf')
171
+
require("telescope").load_extension("undo")
172
+
require('telescope').setup {
176
+
["<C-Down>"] = require('telescope.actions').cycle_history_next,
177
+
["<C-Up>"] = require('telescope.actions').cycle_history_prev,
185
+
["<cr>"] = require("telescope-undo.actions").yank_additions,
186
+
["<S-cr>"] = require("telescope-undo.actions").yank_deletions,
187
+
["<C-cr>"] = require("telescope-undo.actions").restore,
188
+
-- alternative defaults, for users whose terminals do questionable things with modified <cr>
189
+
["<C-y>"] = require("telescope-undo.actions").yank_deletions,
190
+
["<C-r>"] = require("telescope-undo.actions").restore,
193
+
["y"] = require("telescope-undo.actions").yank_additions,
194
+
["Y"] = require("telescope-undo.actions").yank_deletions,
195
+
["u"] = require("telescope-undo.actions").restore,
201
+
vim.keymap.set('n', '<leader>ff', require('telescope.builtin').find_files, {})
202
+
vim.keymap.set('n', '<leader>fg', require('telescope.builtin').live_grep, {})
203
+
vim.keymap.set('n', '<leader>fv', require('telescope.builtin').git_files, {})
204
+
vim.keymap.set('n', '<leader>fb', function() require('telescope.builtin').buffers({ sort_mru = true }) end, {})
205
+
vim.keymap.set('n', '<leader>fh', require('telescope.builtin').help_tags, {})
206
+
vim.keymap.set('n', '<leader>fq', require('telescope.builtin').command_history, {})
207
+
vim.keymap.set('n', '<leader>fs', require('telescope.builtin').search_history, {})
208
+
vim.keymap.set('n', '<leader>fj', require('telescope.builtin').jumplist, {})
209
+
vim.keymap.set('n', '<leader>fm', require('telescope.builtin').marks, {})
210
+
vim.keymap.set('n', '<leader>fx', require('telescope.builtin').diagnostics, {})
211
+
vim.keymap.set('n', '<leader>fy', require('telescope.builtin').registers, {})
212
+
vim.keymap.set('n', '<leader>fr', require('telescope.builtin').lsp_references, {})
213
+
vim.keymap.set('n', '<leader>fS', require('telescope.builtin').lsp_document_symbols, {})
214
+
vim.keymap.set('n', '<leader>fc', require('telescope.builtin').lsp_incoming_calls, {})
215
+
vim.keymap.set('n', '<leader>fo', require('telescope.builtin').lsp_outgoing_calls, {})
216
+
vim.keymap.set('n', '<leader>fi', require('telescope.builtin').lsp_implementations, {})
217
+
vim.keymap.set('n', '<leader>fu', require('telescope').extensions.undo.undo, {})
221
+
require('trouble').setup {
225
+
vim.keymap.set('n', '<leader>xx', function() require('trouble').toggle() end)
226
+
vim.keymap.set('n', '<leader>xw', function() require('trouble').toggle('workspace_diagnostics') end)
227
+
vim.keymap.set('n', '<leader>xd', function() require('trouble').toggle('document_diagnostics') end)
228
+
vim.keymap.set('n', '<leader>xq', function() require('trouble').toggle('quickfix') end)
229
+
vim.keymap.set('n', '<leader>xl', function() require('trouble').toggle('loclist') end)
230
+
vim.keymap.set('n', '<leader>xr', function() require('trouble').toggle('lsp_references') end)
234
+
filetype plugin indent on
240
+
local ls = require('luasnip')
241
+
local s = ls.snippet
242
+
local f = ls.function_node
243
+
local t = ls.text_node
244
+
local i = ls.insert_node
245
+
local c = ls.choice_node
246
+
local sn = ls.snippet_node
247
+
local d = ls.dynamic_node
249
+
local function date_input()
250
+
return os.date('%Y-%m-%d')
253
+
local function amount_spacing(args)
254
+
local account_length = #args[1][1]
255
+
local amount = args[2][1]
256
+
if amount == '' then
259
+
local desired_column = vim.g.ledger_align_at or 50
260
+
local current_column = 2 + account_length + 2 -- 2 spaces after account
261
+
local period_position = amount:find('%.') or (#amount + 1)
262
+
local pre_period_length = period_position - 1
263
+
local total_length = current_column + pre_period_length
264
+
local spaces_needed = desired_column - total_length
265
+
if spaces_needed < 0 then spaces_needed = 1 end
266
+
return string.rep(' ', spaces_needed)
269
+
local function recursive_accounts()
271
+
t({ '', ' ' }), i(1, 'Account'), f(amount_spacing, { 1, 2 }),
274
+
sn(nil, { i(1, '£') })
278
+
d(nil, recursive_accounts)
283
+
ls.add_snippets('all', {
288
+
i(1, f(date_input)), t(' '), i(2, 'Description'),
290
+
sn(nil, { t({ '', ' ; ' }), i(1, 'Comment') }),
293
+
t({ '', ' ' }), i(4, 'Account'), f(amount_spacing, { 4, 5 }),
295
+
sn(nil, { i(1, '£') }),
298
+
d(6, recursive_accounts),
302
+
ls.add_snippets('mail', {
304
+
t({ '<#part filename=' }),
307
+
sn(nil, { t({ ' description="', }), i(1, ''), t({ '"', }) }),
310
+
t({ '><#/part>', '' }),
315
+
vim.keymap.set({ 'i' }, '<C-k>', function() ls.expand() end, { silent = true })
316
+
vim.keymap.set({ 'i', 's' }, '<C-l>', function() ls.jump(1) end, { silent = true })
317
+
vim.keymap.set({ 'i', 's' }, '<C-h>', function() ls.jump(-1) end, { silent = true })
318
+
vim.keymap.set({ 'i', 's' }, '<C-j>', function()
319
+
if ls.choice_active() then
320
+
ls.change_choice(1)
322
+
end, { silent = true })
326
+
local cmp = require 'cmp'
329
+
expand = function(args)
330
+
require('luasnip').lsp_expand(args.body)
334
+
format = function(entry, vim_item)
337
+
nvim_lsp = '[LSP]',
338
+
nvim_lsp_signature_help = '[Signature]',
340
+
buffer = '[Buffer]',
343
+
})[entry.source.name]
349
+
i = cmp.mapping.confirm({ select = false }),
350
+
c = cmp.mapping.confirm({ select = false }),
353
+
i = cmp.mapping.abort(),
354
+
c = cmp.mapping.abort(),
357
+
i = cmp.mapping.complete(),
358
+
c = cmp.mapping.complete(),
361
+
i = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }),
362
+
c = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }),
365
+
i = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }),
366
+
c = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }),
369
+
sources = cmp.config.sources({
370
+
{ name = 'nvim_lsp_signature_help', priority = 1000 },
371
+
{ name = 'nvim_lsp', priority = 900 },
372
+
{ name = 'luasnip', priority = 800 },
373
+
{ name = 'omni', priority = 700 },
374
+
{ name = 'buffer', priority = 600 },
375
+
{ name = 'path', priority = 500 },
379
+
option = { preselect_correct_word = false }
383
+
priority_weight = 2,
385
+
cmp.config.compare.offset,
386
+
cmp.config.compare.exact,
387
+
-- cmp.config.compare.scopes,
388
+
cmp.config.compare.score,
389
+
cmp.config.compare.recently_used,
390
+
cmp.config.compare.locality,
391
+
cmp.config.compare.kind,
392
+
-- cmp.config.compare.sort_text,
393
+
-- cmp.config.compare.length,
394
+
cmp.config.compare.order,
398
+
-- `/` cmdline setup.
399
+
cmp.setup.cmdline('/', {
401
+
{ name = 'buffer' }
404
+
-- `:` cmdline setup.
405
+
cmp.setup.cmdline(':', {
406
+
sources = cmp.config.sources({
409
+
{ name = 'cmdline' }
415
+
vim.g.ledger_fuzzy_account_completion = true
416
+
vim.g.ledger_extra_options = '--pedantic'
417
+
vim.g.ledger_align_at = 50
418
+
vim.g.ledger_accounts_cmd = 'ledger accounts --add-budget'
420
+
-- session management
422
+
local session_dir = vim.fn.stdpath('data') .. '/sessions/'
424
+
local function ensure_dir_exists(dir)
425
+
if vim.fn.isdirectory(dir) == 0 then
426
+
vim.fn.mkdir(dir, 'p')
430
+
local function sanitize_path(path)
431
+
return path:gsub('[\\/]+', '_'):gsub('^_*', ''):gsub('_*$', '')
434
+
local function session_file_name(name)
435
+
local cwd = vim.fn.getcwd()
436
+
local sanitized_cwd = sanitize_path(cwd)
437
+
if name and #name > 0 then
438
+
return session_dir .. 'session:' .. sanitized_cwd .. ':' .. sanitize_path(name) .. '.vim'
440
+
return session_dir .. 'session:' .. sanitized_cwd .. '.vim'
444
+
local function save_session(args)
445
+
ensure_dir_exists(session_dir)
446
+
local session_file = session_file_name(args.args)
447
+
vim.cmd('mksession! ' .. vim.fn.fnameescape(session_file))
450
+
local function load_session(args)
451
+
local session_file = session_file_name(args.args)
452
+
if vim.fn.filereadable(session_file) == 1 then
453
+
vim.cmd('source ' .. vim.fn.fnameescape(session_file))
455
+
print('No session file found for ' .. (args.args == '' and 'this directory' or args.args))
459
+
local function session_completion(arg_lead, cmd_line, cursor_pos)
460
+
local files = vim.fn.globpath(session_dir, 'session:' .. sanitize_path(vim.fn.getcwd()) .. ':*', 0, 1)
461
+
local sessions = {}
462
+
for _, file in ipairs(files) do
463
+
local session = file:match('session:' .. sanitize_path(vim.fn.getcwd()) .. ':(.+)%.vim$')
464
+
if session and session:find(arg_lead, 1, true) == 1 then
465
+
table.insert(sessions, session)
471
+
vim.api.nvim_create_autocmd('VimLeave', {
473
+
callback = function() save_session({ args = '' }) end,
476
+
vim.api.nvim_create_user_command('SaveSession', save_session, { nargs = '?', complete = session_completion })
477
+
vim.api.nvim_create_user_command('LoadSession', load_session, { nargs = '?', complete = session_completion })
479
+
key_mapper('n', '<leader>ss', ':SaveSession<CR>')
480
+
key_mapper('n', '<leader>sl', ':LoadSession<CR>')
484
+
-- Open agenda prompt: <Leader>oa
485
+
-- Open capture prompt: <Leader>oc
486
+
-- In any orgmode buffer press g? for help
487
+
require('orgmode').setup({
488
+
org_agenda_files = { '~/vault/agenda/*.org' },
489
+
org_default_notes_file = '~/vault/refile.org',
494
+
require('calendar')
496
+
-- free real-estate
507
+
augroup RememberView
509
+
autocmd BufWinLeave * let b:win_view = winsaveview()
510
+
autocmd BufWinEnter * if exists('b:win_view') | call winrestview(b:win_view) | endif
515
+
--- underline errors rather than highlight
516
+
vim.lsp.handlers['textDocument/publishDiagnostics'] = vim.lsp.with(
517
+
vim.lsp.diagnostic.on_publish_diagnostics, {
519
+
---virtual_text = true,
521
+
update_in_insert = true,
526
+
-- Use an on_attach function to only map the following keys
527
+
-- after the language server attaches to the current buffer
528
+
On_attach = function(client, bufnr)
530
+
-- See `:help vim.lsp.*` for documentation on any of the below functions
531
+
local bufopts = function(desc)
532
+
return { noremap = true, silent = true, buffer = bufnr, desc = desc }
534
+
vim.keymap.set('n', 'K', vim.lsp.buf.hover, bufopts('Hover'))
535
+
vim.keymap.set('n', 'gd', vim.lsp.buf.definition, bufopts('Goto definition'))
536
+
vim.keymap.set('n', '[d', vim.diagnostic.goto_next, bufopts('Goto next issue'))
537
+
vim.keymap.set('n', ']d', vim.diagnostic.goto_prev, bufopts('Goto prev issue'))
538
+
vim.keymap.set('n', '<leader>li', vim.lsp.buf.implementation, bufopts('Goto implementation'))
539
+
vim.keymap.set('n', '<leader>lt', vim.lsp.buf.type_definition, bufopts('Goto type definition'))
540
+
vim.keymap.set('n', '<leader>lr', vim.lsp.buf.references, bufopts('Show references'))
541
+
vim.keymap.set('n', '<leader>la', vim.lsp.buf.code_action, bufopts('Code action'))
542
+
vim.keymap.set('n', '<leader>lR', vim.lsp.buf.rename, bufopts('Rename'))
543
+
vim.keymap.set('n', '<leader>lf', function() vim.lsp.buf.format { async = true } end, bufopts('Format'))
544
+
vim.keymap.set('n', '<leader>le', vim.diagnostic.open_float, bufopts('Get error'))
547
+
-- Add additional capabilities supported by nvim-cmp
548
+
Capabilities = vim.tbl_deep_extend('force',
549
+
vim.lsp.protocol.make_client_capabilities(),
550
+
require('cmp_nvim_lsp').default_capabilities()
552
+
Capabilities.workspace.didChangeWatchedFiles.dynamicRegistration = false
554
+
local lspconfig = require('lspconfig')
556
+
-- Enable some language servers with the additional completion capabilities offered by nvim-cmp
557
+
local servers = { 'nixd', 'ocamllsp', 'clangd', 'rust_analyzer', 'pyright', 'tsserver', 'gopls', 'typst_lsp' }
558
+
for _, lsp in ipairs(servers) do
559
+
lspconfig[lsp].setup {
560
+
on_attach = On_attach,
561
+
capabilities = Capabilities,
565
+
lspconfig['lua_ls'].setup {
566
+
on_attach = On_attach,
567
+
capabilities = Capabilities,
571
+
-- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim)
572
+
version = 'LuaJIT',
575
+
-- Get the language server to recognize the `vim` global
576
+
globals = { 'vim' },
579
+
-- Make the server aware of Neovim runtime files
580
+
library = vim.api.nvim_get_runtime_file('', true),
581
+
checkThirdParty = false,
583
+
-- Do not send telemetry data containing a randomized but unique identifier
591
+
-- wrapper around lspconfig['ltex-ls'] with support for hide false positive
592
+
require('ltex-ls').setup {
593
+
on_attach = On_attach,
594
+
capabilities = Capabilities,
595
+
use_spellfile = false,
596
+
filetypes = { 'markdown', 'latex', 'tex', 'bib', 'plaintext', 'mail', 'gitcommit', 'typst' },
599
+
flags = { debounce_text_changes = 300 },
600
+
language = 'en-GB',
601
+
sentenceCacheSize = 2000,
604
+
'MORFOLOGIK_RULE_EN_GB',
605
+
'OXFORD_SPELLING_Z_NOT_S',
612
+
vim.cmd [[autocmd BufWritePre <buffer> lua vim.lsp.buf.format()]]
620
+
local dap = require('dap')
621
+
dap.adapters.ocamlearlybird = {
622
+
type = 'executable',
623
+
command = 'ocamlearlybird',
627
+
dap.configurations.ocaml = {
630
+
type = 'ocamlearlybird',
631
+
request = 'launch',
632
+
program = function()
633
+
local path = vim.fn.input({
634
+
prompt = 'Path to executable: ',
635
+
default = vim.fn.getcwd() .. '/_build/default/bin/',
636
+
completion = 'file'
638
+
return (path and path ~= "") and path or dap.ABORT
643
+
vim.keymap.set('n', '<leader>;c', function() require('dap').continue() end)
644
+
vim.keymap.set('n', '<leader>;s', function() require('dap').step_over() end)
645
+
vim.keymap.set('n', '<leader>;i', function() require('dap').step_into() end)
646
+
vim.keymap.set('n', '<leader>;o', function() require('dap').step_out() end)
647
+
vim.keymap.set('n', '<leader>;b', function() require('dap').toggle_breakpoint() end)
648
+
vim.keymap.set('n', '<leader>;m',
649
+
function() require('dap').set_breakpoint(nil, nil, vim.fn.input('Log point message: ')) end)
650
+
vim.keymap.set('n', '<leader>;r', function() require('dap').repl.open() end)
651
+
vim.keymap.set('n', '<leader>;l', function() require('dap').run_last() end)
652
+
vim.keymap.set('n', '<leader>;f', function()
653
+
local widgets = require('dap.ui.widgets')
654
+
widgets.centered_float(widgets.frames)
656
+
vim.keymap.set('n', '<leader>;S', function()
657
+
local widgets = require('dap.ui.widgets')
658
+
widgets.centered_float(widgets.scopes)