diff --git a/roles/neovim/files/lua/opdavies/lsp/init.lua b/roles/neovim/files/lua/opdavies/lsp/init.lua
index 2009b31b..0ccc86d1 100644
--- a/roles/neovim/files/lua/opdavies/lsp/init.lua
+++ b/roles/neovim/files/lua/opdavies/lsp/init.lua
@@ -39,13 +39,13 @@ local custom_attach = function(client)
   buf_nnoremap { "<leader>ca", vim.lsp.buf.code_action }
   buf_nnoremap { "<leader>dn", vim.diagnostic.goto_next }
   buf_nnoremap { "<leader>dp", vim.diagnostic.goto_prev }
-  buf_nnoremap { "<leader>gD", vim.lsp.buf.declaration }
-  buf_nnoremap { "<leader>gT", vim.lsp.buf.type_definition }
-  buf_nnoremap { "<leader>gd", vim.lsp.buf.definition }
-  buf_nnoremap { "<leader>gi", vim.lsp.buf.implementation }
   buf_nnoremap { "<leader>rn", vim.lsp.buf.rename }
   buf_nnoremap { "<leader>rr", "<cmd>LspRestart<cr>" }
   buf_nnoremap { "K", vim.lsp.buf.hover }
+  buf_nnoremap { "gD", vim.lsp.buf.declaration }
+  buf_nnoremap { "gT", vim.lsp.buf.type_definition }
+  buf_nnoremap { "gd", vim.lsp.buf.definition }
+  buf_nnoremap { "gi", vim.lsp.buf.implementation }
 
   if filetype ~= "lua" then
     buf_nnoremap { "K", vim.lsp.buf.hover }
@@ -154,12 +154,12 @@ for server, config in pairs(servers) do
   setup_server(server, config)
 end
 
-vim.diagnostic.config({
+vim.diagnostic.config {
   signs = true,
   underline = false,
   update_in_insert = false,
   virtual_text = { spacing = 2 },
-})
+}
 
 require "opdavies.lsp.null-ls"
 require "opdavies.lsp.signature"
diff --git a/roles/neovim/files/lua/opdavies/lsp/null-ls.lua b/roles/neovim/files/lua/opdavies/lsp/null-ls.lua
index 810aa535..d6d89c60 100644
--- a/roles/neovim/files/lua/opdavies/lsp/null-ls.lua
+++ b/roles/neovim/files/lua/opdavies/lsp/null-ls.lua
@@ -3,21 +3,47 @@ if not status_ok then
   return
 end
 
+local lsp_formatting = function(bufnr)
+  vim.lsp.buf.format {
+    filter = function(client)
+      return client.name == "null-ls"
+    end,
+    bufnr = bufnr,
+  }
+end
+
+local augroup = vim.api.nvim_create_augroup("LspFormatting", {})
+
 local completion = null_ls.builtins.completion
 local diagnostics = null_ls.builtins.diagnostics
 local formatting = null_ls.builtins.formatting
 
 null_ls.setup {
+  on_attach = function(client, bufnr)
+    if client.supports_method "textDocument/formatting" then
+      vim.api.nvim_clear_autocmds { group = augroup, buffer = bufnr }
+      vim.api.nvim_create_autocmd("BufWritePre", {
+        buffer = bufnr,
+        callback = function()
+          lsp_formatting(bufnr)
+        end,
+        group = augroup,
+      })
+    end
+  end,
+
   sources = {
+    formatting.phpcbf,
+    formatting.markdownlint,
     formatting.prettier,
     formatting.rustywind,
     formatting.stylua,
 
     diagnostics.eslint,
+    diagnostics.markdownlint,
     diagnostics.php,
     diagnostics.phpcs,
     diagnostics.phpstan,
-
-    completion.spell,
+    diagnostics.shellcheck,
   },
 }
diff --git a/roles/neovim/files/lua/opdavies/telescope/init.lua b/roles/neovim/files/lua/opdavies/telescope/init.lua
index 1ba83c36..8ab34a86 100644
--- a/roles/neovim/files/lua/opdavies/telescope/init.lua
+++ b/roles/neovim/files/lua/opdavies/telescope/init.lua
@@ -18,7 +18,23 @@ function M.current_buf()
     previewer = false,
   }
 
-  require "telescope.builtin".current_buffer_fuzzy_find(opts)
+  require("telescope.builtin").current_buffer_fuzzy_find(opts)
+end
+
+M.diagnostics = function()
+  local theme = require("telescope.themes").get_dropdown {
+    previewer = false,
+  }
+
+  require("telescope.builtin").diagnostics(theme)
+end
+
+function M.lsp_document_symbols()
+  local theme = require("telescope.themes").get_dropdown {
+    previewer = false,
+  }
+
+  require("telescope.builtin").lsp_document_symbols(theme)
 end
 
 function M.edit_neovim()
@@ -50,7 +66,7 @@ end
 function M.file_browser()
   local opts = {
     cwd = vim.fn.expand "%:p:h",
-    sorting_strategy = "ascending"
+    sorting_strategy = "ascending",
   }
 
   require("telescope").extensions.file_browser.file_browser(opts)
@@ -66,6 +82,16 @@ function M.fd()
   require("telescope.builtin").find_files(opts)
 end
 
+function M.git_files()
+  local opts = themes.get_ivy {
+    file_ignore_patterns = { ".git/", "vendor" },
+    hidden = true,
+    no_ignore = true,
+  }
+
+  require("telescope.builtin").git_files(opts)
+end
+
 function M.live_grep()
   require("telescope.builtin").live_grep {
     file_ignore_patterns = { ".git/" },
diff --git a/roles/neovim/files/lua/opdavies/telescope/mappings.lua b/roles/neovim/files/lua/opdavies/telescope/mappings.lua
index 843917be..69ed002c 100644
--- a/roles/neovim/files/lua/opdavies/telescope/mappings.lua
+++ b/roles/neovim/files/lua/opdavies/telescope/mappings.lua
@@ -28,6 +28,9 @@ telescope_mapper("<leader>fg", "git_files")
 telescope_mapper("<leader>fh", "help_tags")
 telescope_mapper("<leader>fl", "live_grep")
 
+telescope_mapper("<leader>ds", "lsp_document_symbols")
+telescope_mapper("<leader>dl", "diagnostics")
+
 telescope_mapper("<leader>en", "edit_neovim")
 telescope_mapper("<leader>ez", "edit_zsh")