diff --git a/init.lua b/init.lua
index 55a13f8..44842ec 100644
--- a/init.lua
+++ b/init.lua
@@ -169,6 +169,7 @@ vim.keymap.set('n', '<Leader>qh', '<Cmd>colder<CR>', { desc = 'Older list' })
 vim.keymap.set('n', '<Leader>ql', '<Cmd>cnewer<CR>', { desc = 'Newer list' })
 vim.keymap.set('n', '<Leader>c', '<Cmd>vert te<CR>', { desc = 'Terminal (vsplit)' })
 vim.keymap.set('n', '<Leader>C', '<Cmd>tab te<CR>', { desc = 'Terminal (tab)' })
+vim.keymap.set('t', '<C-s>', '<C-\\><C-n>', { desc = 'Normal mode' })
 
 -- Diagnostic mappings
 vim.keymap.set('n', '<Leader>eo', vim.diagnostic.open_float, { desc = 'Open diagnostic' })
@@ -187,6 +188,12 @@ vim.keymap.set('n', '<Leader>eh', vim.diagnostic.hide, { desc = 'Hide diagnostic
 vim.keymap.set('n', '<Leader>es', vim.diagnostic.show, { desc = 'Show diagnostics' })
 vim.keymap.set('n', '<Leader>eC', vim.diagnostic.reset, { desc = 'Clear diagnostics' })
 
+if vim.g.neovide then
+	vim.keymap.set('l', '<C-v>', '<C-r>+', { desc = 'Paste' })
+	vim.keymap.set('l', '<C-S-v>', '<C-r>+', { desc = 'Paste' })
+	vim.keymap.set('t', '<C-S-v>', '<C-\\><C-n>pi', { desc = 'Paste' })
+end
+
 -- Commands
 vim.cmd [[
 command! Light set background=light
@@ -246,7 +253,7 @@ au('LspAttach', { callback = function(event)
 			i = {'<Cmd>Telescope lsp_implementations<CR>', 'Implementation'},
 			I = {vim.lsp.buf.implementation, 'Implementation (quickfix)'},
 			r = {vim.lsp.buf.rename, 'Rename'},
-			h = {function() vim.lsp.inlay_hint.enable(0, not vim.lsp.inlay_hint.is_enabled()) end, 'Inlay hints'},
+			h = {function() vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled()) end, 'Inlay hints'},
 			l = {vim.lsp.codelens.refresh, 'Show codelenses'},
 			L = {vim.lsp.codelens.run, 'Run codelens'},
 			t = {'<Cmd>Telescope lsp_type_definitions<CR>', 'Type definition'},
@@ -297,10 +304,12 @@ require('lazy').setup({
 	'rhysd/vim-crystal',
 	'bakpakin/fennel.vim',
 	'mboughaba/i3config.vim',
+	{'OXY2DEV/markview.nvim', lazy = false, opts = { initial_state = false }},
 	'mracos/mermaid.vim',
 	'lifepillar/pgsql.vim',
 	'ajouellette/sway-vim-syntax',
 	'cespare/vim-toml',
+	'mfussenegger/nvim-ansible',
 
 	-- Editing
 	{'LunarWatcher/auto-pairs', init = function()
@@ -354,7 +363,9 @@ require('lazy').setup({
 	{'kylechui/nvim-surround', opts = {}},
 	'wellle/targets.vim',
 	{'vim-test/vim-test', init = function()
-		vim.g['test#neovim#term_position'] = 'vert'
+		-- Uncomment to move test output to the side instead of bottom
+		-- vim.g['test#neovim#term_position'] = 'vert'
+		vim.g['echo_command'] = 1
 		vim.g['test#strategy'] = 'neovim'
 	end},
 	{'julian/vim-textobj-variable-segment', dependencies = {'kana/vim-textobj-user'}},
@@ -392,6 +403,7 @@ require('lazy').setup({
 		lspconfig.util.default_config.capabilities = capabilities
 
 		-- Set up language servers
+		lspconfig.ansiblels.setup {}
 		lspconfig.bashls.setup {}
 		lspconfig.clangd.setup {}
 		lspconfig.eslint.setup { autostart = false }
@@ -583,6 +595,11 @@ require('lazy').setup({
 
 					on_attach = function(client, bufnr)
 						jdtls.setup_dap()
+						vim.keymap.set('n', '<Leader>lo', jdtls.organize_imports, { desc = 'Organize imports', buffer = bufnr })
+						vim.keymap.set('n', '<Leader>Xm', jdtls.test_nearest_method, { desc = 'Test nearest method', buffer = bufnr })
+						vim.keymap.set('n', '<Leader>Xc', jdtls.test_class, { desc = 'Test class', buffer = bufnr })
+						vim.keymap.set('n', '<Leader>Xg', jdtls.tests.goto_subjects, { desc = 'Go to test', buffer = bufnr })
+						vim.keymap.set('n', '<Leader>Xb', 'JdtCompile full', { desc = 'Build', buffer = bufnr })
 					end,
 				}
 
@@ -638,7 +655,7 @@ require('lazy').setup({
 			},
 			tsserver_plugins = (function ()
 				if fn.has('nvim-0.10') == 0 then return end
-				if vim.system({'npm', 'list', '-g', '@styled/typescript-styled-plugin'}):wait().code == 0 then
+				if vim.fn.executable('npm') == 1 and vim.system({'npm', 'list', '-g', '@styled/typescript-styled-plugin'}):wait().code == 0 then
 					return {'@styled/typescript-styled-plugin'}
 				else
 					return {}
@@ -742,7 +759,7 @@ require('lazy').setup({
 				code_action = vim.lsp.buf.code_action
 			end
 			vim.keymap.set('n', 'ga', code_action, { buffer = event.buf, desc = 'Code action' })
-			vim.keymap.set('n', '<Leader>la', code_action, { buffer = event.buf, desc = 'Code action' })
+			vim.keymap.set('n', '<Leader>la', vim.lsp.buf.code_action, { buffer = event.buf, desc = 'Code action' })
 		end })
 	end},
 	{'MattesGroeger/vim-bookmarks', config = function()
@@ -915,12 +932,29 @@ require('lazy').setup({
 		clear_on_continue = true,
 	}},
 	{'LiadOz/nvim-dap-repl-highlights', opts = {}},
+	{'lucaSartore/nvim-dap-exception-breakpoints', dependencies = {'mfussenegger/nvim-dap'}, config = function()
+		vim.keymap.set('n', '<Leader>de', require'nvim-dap-exception-breakpoints', { desc = 'Exception breakpoints'})
+	end},
 	{'sindrets/diffview.nvim', opts = {
 		-- Use nicer highlighting for diffs
 		enhanced_diff_hl = true,
+		win_config = {
+			win_opts = {
+				wrap = false,
+			}
+		},
+		key_bindings = {
+			view = {
+				["gq"] = "<CMD>DiffviewClose<CR>",
+			},
+			file_panel = {
+				["gq"] = "<CMD>DiffviewClose<CR>",
+			}
+		}
 	}},
 	{'stevearc/dressing.nvim', opts = {
 		input = {
+			-- Allow exiting insert mode in picker
 			insert_only = false,
 			win_options = {
 				-- Reuse telescope's highlights for windows made by dressing
@@ -960,12 +994,23 @@ require('lazy').setup({
 		require'gitlab.server'.build(true)
 	end, opts = {
 		attachment_dir = vim.fn.expand('~/Downloads/'),
+		keymaps = {
+			global = {
+				disable_all = true,
+			}
+		},
 		popup = {
-			temp_registers = {"p"}
+			-- Backup popup input in these registers
+			temp_registers = {'p', 'P'}
 		},
 		discussion_tree = {
+			-- Place the discussion tree at the bottom
 			position = 'bottom',
 		},
+		create_mr = {
+			-- Mark source branch for deletion by default
+			delete_branch = true,
+		}
 	}, config = function(plugin, opts)
 		local gitlab = require('gitlab')
 		gitlab.setup(opts)
@@ -975,14 +1020,22 @@ require('lazy').setup({
 				o = {gitlab.review, 'Review'},
 				s = {gitlab.summary, 'Summary'},
 				a = {gitlab.add_assignee, 'Add assignee'},
+				A = {gitlab.delete_assignee, 'Remove assignee'},
 				r = {gitlab.add_reviewer, 'Add reviewer'},
-				A = {gitlab.approve, 'Approve'},
-				c = {gitlab.create_comment, 'Comment'},
+				R = {gitlab.delete_reviewer, 'Remove reviewer'},
+				Y = {gitlab.approve, 'Approve'},
+				N = {gitlab.revoke, 'Unapprove'},
+				M = {gitlab.merge, 'Merge'},
+				f = {gitlab.choose_merge_request, 'Pick MR'},
 				n = {gitlab.create_note, 'Note'},
 				m = {gitlab.create_mr, 'Create MR'},
 				x = {gitlab.open_in_browser, 'Open in browser'},
 				p = {gitlab.pipeline, 'Pipeline'},
-				q = {gitlab.close_review, 'Close review'},
+				P = {gitlab.publish_all_drafts, 'Publish all drafts'},
+				q = {function ()
+					gitlab.close_review()
+					require'gitlab.server'.shutdown()
+				end, 'Close review'},
 			}
 		}
 		require'which-key'.register({
@@ -995,16 +1048,14 @@ require('lazy').setup({
 	{'lewis6991/gitsigns.nvim', dependencies = {'folke/which-key.nvim'}, opts = {
 		on_attach = function()
 			local gitsigns = require'gitsigns'
-			vim.keymap.set('n', ']c', gitsigns.next_hunk, {desc = 'Next hunk'})
-			vim.keymap.set('n', '[c', gitsigns.prev_hunk, {desc = 'Previous hunk'})
+			vim.keymap.set('n', ']c', function() gitsigns.nav_hunk('next') end, {desc = 'Next hunk'})
+			vim.keymap.set('n', '[c', function() gitsigns.nav_hunk('prev') end, {desc = 'Previous hunk'})
 
 			require'which-key'.register {
 				['<Leader>h'] = {
 					name = '+gitsigns',
 					s = {gitsigns.stage_hunk, 'Stage hunk'},
 					S = {gitsigns.stage_buffer, 'Stage buffer'},
-					u = {gitsigns.unstage_hunk, 'Unstage hunk'},
-					U = {gitsigns.unstage_buffer, 'Unstage buffer'},
 					r = {gitsigns.reset_hunk, 'Reset hunk'},
 					v = {gitsigns.select_hunk, 'Visual select hunk'},
 					d = {gitsigns.toggle_deleted, 'Toggle deleted lines'},
@@ -1050,7 +1101,8 @@ require('lazy').setup({
 		{'<Leader><C-g>', '<Cmd>Neogit<CR>', { desc = 'Neogit' }}
 	}},
 	{'rcarriga/nvim-notify', dependencies = {'nvim-telescope/telescope.nvim'}, opts = {
-		stages = 'fade'
+		stages = 'fade',
+		render = 'compact',
 	}, config = function(_, opts)
 		require'notify'.setup(opts)
 		vim.notify = require'notify'
@@ -1080,11 +1132,11 @@ require('lazy').setup({
 		g.startify_fortune_use_unicode = 1
 		-- Items to show on the startup screen
 		g.startify_lists = {
-			{ type = 'dir',       header = {'   Recently used ' .. fn.getcwd()} },
-			{ type = 'files',     header = {'   Recently used'} },
 			{ type = 'sessions',  header = {'   Sessions'} },
 			{ type = 'bookmarks', header = {'   Bookmarks'} },
 			{ type = 'commands',  header = {'   Commands'} },
+			{ type = 'dir',       header = {'   Recently used ' .. fn.getcwd()} },
+			{ type = 'files',     header = {'   Recently used'} },
 		}
 		g.startify_bookmarks = {
 			{ c = '~/.config/nvim/init.lua' },
@@ -1095,9 +1147,11 @@ require('lazy').setup({
 		}
 	end},
 	{'nvim-telescope/telescope.nvim', dependencies = {
+		'LunarWatcher/auto-pairs',
 		'nvim-telescope/telescope-fzf-native.nvim',
 		'nvim-telescope/telescope-file-browser.nvim',
 		'nvim-telescope/telescope-project.nvim',
+		'nvim-telescope/telescope-live-grep-args.nvim',
 		'nvim-telescope/telescope-ui-select.nvim',
 		'nvim-telescope/telescope-dap.nvim',
 		'debugloop/telescope-undo.nvim',
@@ -1136,6 +1190,7 @@ require('lazy').setup({
 				['ui-select'] = require'telescope.themes'.get_cursor {
 					layout_config = {
 						height = 15,
+						width = 100,
 					},
 				},
 			},
@@ -1145,7 +1200,7 @@ require('lazy').setup({
 				name = 'Telescope',
 				["<Space>"] = {'<Cmd>Telescope<CR>', 'List pickers'},
 				f = {'<Cmd>Telescope find_files<CR>', 'Files'},
-				F = {'<Cmd>Telescope file_browser<CR>', 'File browser'},
+				F = {'<Cmd>Telescope file_browser hidden=true<CR>', 'File browser'},
 				['<C-f>'] = {
 					function()
 						vim.ui.input(
@@ -1157,7 +1212,7 @@ require('lazy').setup({
 				},
 				d = {'<Cmd>Telescope find_files find_command=fd,--type,d,-I<CR>', 'Directories'},
 				r = {'<Cmd>Telescope oldfiles<CR>', 'Recent files'},
-				g = {'<Cmd>Telescope live_grep<CR>', 'Grep'},
+				g = {'<Cmd>Telescope live_grep_args<CR>', 'Grep'},
 				G = {function()
 					vim.ui.input({ completion = 'dir' }, function(input)
 						if not input then return end
@@ -1180,6 +1235,7 @@ require('lazy').setup({
 		}
 		require'telescope'.load_extension('fzf')
 		require'telescope'.load_extension('file_browser')
+		require'telescope'.load_extension('live_grep_args')
 		require'telescope'.load_extension('project')
 		require'telescope'.load_extension('ui-select')
 		require'telescope'.load_extension('dap')
@@ -1219,7 +1275,7 @@ require('lazy').setup({
 		disable_netrw = false,
 		-- Show LSP diagnostics in the sign column
 		diagnostics = {
-			enable = true,
+			--enable = true, -- triggers deprecation warning
 			icons = {
 				hint = "",
 			},