diff --git a/config/neovim/lua/opdavies/lsp/init.lua b/config/neovim/lua/opdavies/lsp/init.lua
index b86a9034..7533e3d5 100644
--- a/config/neovim/lua/opdavies/lsp/init.lua
+++ b/config/neovim/lua/opdavies/lsp/init.lua
@@ -1,85 +1,138 @@
-local cmp = require('cmp')
-local lsp = require('lsp-zero')
-local lspconfig = require('lspconfig')
-
-lsp.preset("recommended")
-
-local on_attach = function(client, bufnr)
-  lsp.default_keymaps({buffer = bufnr})
-
-  local opts = { buffer = true }
-
-  vim.keymap.set("i", "<C-h>", function() vim.lsp.buf.signature_help() end, opts)
-  vim.keymap.set("n", "<leader>ca", function() vim.lsp.buf.code_action() end, opts)
-  vim.keymap.set("n", "<leader>f", function() vim.lsp.buf.format({ async = true }) end, opts)
-  vim.keymap.set("n", "<leader>rn", function() vim.lsp.buf.rename() end, opts)
+local has_lsp, lspconfig = pcall(require, "lspconfig")
+if not has_lsp then
+  return
 end
 
-lsp.on_attach(on_attach)
+local nvim_status = require "lsp-status"
 
-lsp.set_preferences({
-  sign_icons = {},
-})
+local imap = require("opdavies.keymap").imap
+local nmap = require("opdavies.keymap").nmap
 
-lsp.setup_servers({
-  'ansiblels',
-  'astro',
-  'bashls',
-  'cssls',
-  'dockerls',
-  'html',
-  'intelephense',
-  'jsonls',
-  'nixd',
-  'tailwindcss',
-  'terraformls',
-  'tsserver',
-  'volar',
-  'vuels',
-  'yamlls'
-})
+local telescope_mapper = require "opdavies.telescope.mappings"
 
-lsp.setup()
+local buf_nnoremap = function(opts)
+  opts.buffer = 0
+  nmap(opts)
+end
 
-lspconfig.tailwindcss.setup({
-  on_attach = on_attach,
+local buf_inoremap = function(opts)
+  opts.buffer = 0
+  imap(opts)
+end
 
-  filetypes = {
-    "astro",
-    "html",
-    "html.twig",
-    "javascript",
-    "php",
-    "twig",
-    "typescript",
-    "vue",
+local default_capabilities = vim.lsp.protocol.make_client_capabilities()
+default_capabilities = require("cmp_nvim_lsp").default_capabilities(default_capabilities)
+
+local custom_init = function(client)
+  client.config.flags = client.config.flags or {}
+  client.config.flags.allow_incremental_sync = true
+end
+
+local custom_attach = function(client)
+  local filetype = vim.api.nvim_buf_get_option(0, "filetype")
+
+  nvim_status.on_attach(client)
+
+  buf_inoremap { "<C-s>", vim.lsp.buf.signature_help }
+  buf_nnoremap { "<leader>d", vim.diagnostic.open_float }
+  buf_nnoremap { "<leader>[d", vim.diagnostic.goto_prev }
+  buf_nnoremap { "<leader>]d", vim.diagnostic.goto_next }
+  buf_nnoremap { "<leader>ca", vim.lsp.buf.code_action }
+  buf_nnoremap { "<leader>rn", vim.lsp.buf.rename }
+  buf_nnoremap { "<leader>rr", "<cmd>LspRestart<cr>" }
+  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 }
+  end
+
+  telescope_mapper("<leader>dl", "diagnostics", nil, true)
+
+  -- Set autocommands conditional on server_capabilities
+  if client.server_capabilities.document_highlight then
+    vim.cmd [[
+      augroup lsp_document_highlight
+        autocmd! * <buffer>
+        autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()
+        autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()
+      augroup END
+    ]]
+  end
+
+  -- Attach any filetype specific options to the client
+  -- filetype_attach[filetype](client)
+end
+
+local servers = {
+  ansiblels = true,
+  astro = true,
+  bashls = true,
+  cssls = true,
+  gopls = true,
+  html = true,
+  rnix = true,
+  tailwindcss = true,
+  tsserver = true,
+  vuels = true,
+  yamlls = true,
+
+  intelephense = {
+    filetypes = { "php", "module", "test", "inc" },
   },
 
-  init_options = {
-    userLanguages = {
-      ["html.twig"] = "html",
+  lua_ls = {
+    settings = {
+      Lua = {
+        diagnostics = {
+          globals = { "vim" },
+        },
+      },
     },
   },
-})
+}
 
-lspconfig.yamlls.setup({
-  settings = {
-    yaml = {
-      keyOrdering = false,
-    }
-  }
-})
+local setup_server = function(server, config)
+  if not config then
+    return
+  end
 
-vim.diagnostic.config({
-  virtual_text = true,
-})
+  if type(config) ~= "table" then
+    config = {}
+  end
 
-cmp.setup({
-  preselect = 'item',
-  completion = {
-    completeopt = 'menu,menuone,noinsert'
+  config = vim.tbl_deep_extend("force", {
+    on_init = custom_init,
+    on_attach = custom_attach,
+    capabilities = default_capabilities,
+    flags = {
+      debounce_text_changes = nil,
+    },
+  }, config)
+
+  lspconfig[server].setup(config)
+end
+
+for server, config in pairs(servers) do
+  setup_server(server, config)
+end
+
+vim.diagnostic.config {
+  float = {
+    source = true,
   },
-})
+  signs = true,
+  underline = false,
+  update_in_insert = false,
+  virtual_text = { spacing = 2 },
+}
+
+vim.keymap.set("n", "<leader>f", function()
+  vim.lsp.buf.format { async = true }
+end
+);
 
 require "opdavies.lsp.null-ls"
 require "opdavies.lsp.signature"
diff --git a/system/shared/home-manager.nix b/system/shared/home-manager.nix
index b9ccfe4d..d34f200d 100644
--- a/system/shared/home-manager.nix
+++ b/system/shared/home-manager.nix
@@ -557,7 +557,6 @@ in
       vimPlugins.nvim-treesitter-textobjects
 
       # LSP
-      inputs.nixpkgs-unstable.legacyPackages."${system}".vimPlugins.lsp-zero-nvim
       inputs.nixpkgs-unstable.legacyPackages."${system}".vimPlugins.nvim-lspconfig
       vimPlugins.null-ls-nvim
       vimPlugins.lsp-status-nvim