diff --git a/home/editors/coc.vim b/home/editors/coc.vim
deleted file mode 100644
index 13950dd..0000000
--- a/home/editors/coc.vim
+++ /dev/null
@@ -1,105 +0,0 @@
-" You will have bad experience for diagnostic messages when it's default 4000.
-set updatetime=300
-
-" don't give |ins-completion-menu| messages.
-set shortmess+=c
-
-" Use tab for trigger completion with characters ahead and navigate.
-" Use command ':verbose imap <tab>' to make sure tab is not mapped by other plugin.
-inoremap <silent><expr> <TAB>
-  \ pumvisible() ? "\<C-n>" :
-  \ <SID>check_back_space() ? "\<TAB>" :
-  \ coc#refresh()
-inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"
-
-function! s:check_back_space() abort
-  let col = col('.') - 1
-  return !col || getline('.')[col - 1]  =~# '\s'
-endfunction
-
-" Use <c-space> to trigger completion.
-inoremap <silent><expr> <c-space> coc#refresh()
-
-" Use <cr> to confirm completion, `<C-g>u` means break undo chain at current position.
-inoremap <expr> <cr> complete_info()["selected"] != "-1" ? "\<C-y>" : "\<C-g>u\<CR>"
-
-" Use `[g` and `]g` to navigate diagnostics
-nmap <silent> [g <Plug>(coc-diagnostic-prev)
-nmap <silent> ]g <Plug>(coc-diagnostic-next)
-
-" Remap keys for gotos
-nmap <silent> gd <Plug>(coc-definition)
-nmap <silent> gy <Plug>(coc-type-definition)
-nmap <silent> gi <Plug>(coc-implementation)
-nmap <silent> gr <Plug>(coc-references)
-
-" Use K to show documentation in preview window
-nnoremap <silent> K :call <SID>show_documentation()<CR>
-
-function! s:show_documentation()
-  if (index(['vim','help'], &filetype) >= 0)
-    execute 'h '.expand('<cword>')
-  else
-    call CocAction('doHover')
-  endif
-endfunction
-
-" Highlight symbol under cursor on CursorHold
-autocmd CursorHold * silent call CocActionAsync('highlight')
-
-" Remap for rename current word
-nmap <leader>rn <Plug>(coc-rename)
-
-" Remap for format selected region
-xmap <leader>f  <Plug>(coc-format-selected)
-nmap <leader>f  <Plug>(coc-format-selected)
-
-augroup mygroup
-  autocmd!
-  " Setup formatexpr specified filetype(s).
-  autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected')
-  " Update signature help on jump placeholder
-  autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')
-augroup end
-
-" Remap for do codeAction of selected region, ex: `<leader>aap` for current paragraph
-xmap <leader>a  <Plug>(coc-codeaction-selected)
-nmap <leader>a  <Plug>(coc-codeaction-selected)
-
-" Remap for do codeAction of current line
-nmap <leader>ac  <Plug>(coc-codeaction)
-" Fix autofix problem of current line
-nmap <leader>qf  <Plug>(coc-fix-current)
-
-" Create mappings for function text object, requires document symbols feature of languageserver.
-xmap if <Plug>(coc-funcobj-i)
-xmap af <Plug>(coc-funcobj-a)
-omap if <Plug>(coc-funcobj-i)
-omap af <Plug>(coc-funcobj-a)
-
-" Use `:Format` to format current buffer
-command! -nargs=0 Format :call CocAction('format')
-
-" Use `:Fold` to fold current buffer
-command! -nargs=? Fold :call     CocAction('fold', <f-args>)
-
-" use `:OR` for organize import of current buffer
-command! -nargs=0 OR   :call     CocAction('runCommand', 'editor.action.organizeImport')
-
-" Using CocList
-" Show all diagnostics
-nnoremap <silent> <space>a  :<C-u>CocList diagnostics<cr>
-" Manage extensions
-nnoremap <silent> <space>e  :<C-u>CocList extensions<cr>
-" Show commands
-nnoremap <silent> <space>c  :<C-u>CocList commands<cr>
-" Find symbol of current document
-nnoremap <silent> <space>o  :<C-u>CocList outline<cr>
-" Search workspace symbols
-nnoremap <silent> <space>s  :<C-u>CocList -I symbols<cr>
-" Do default action for next item.
-nnoremap <silent> <space>j  :<C-u>CocNext<CR>
-" Do default action for previous item.
-nnoremap <silent> <space>k  :<C-u>CocPrev<CR>
-" Resume latest coc list
-nnoremap <silent> <space>p  :<C-u>CocListResume<CR>
diff --git a/home/editors/lsp.vim b/home/editors/lsp.vim
index bd59e4d..9cb420f 100644
--- a/home/editors/lsp.vim
+++ b/home/editors/lsp.vim
@@ -3,14 +3,12 @@ set completeopt=menu,preview,menuone,noinsert
 set omnifunc=v:lua.vim.lsp.omnifunc
 
 let g:deoplete#enable_at_startup = 1
-" let g:deoplete#auto_refresh_delay = 10 " TODO disable it again if it doesn't make a difference
 let g:deoplete#smart_case = 1
-let g:deoplete#min_pattern_length = 1
 
 " Use <c-space> to trigger completion.
 inoremap <silent><expr> <c-space> deoplete#manual_complete()
 
-"Autocomplete and cycle from top-to-bottom of suggestions using <Tab>.
+" Autocomplete and cycle from top-to-bottom of suggestions using <Tab>.
 inoremap <expr><TAB> pumvisible() ? "\<c-n>" : "\<TAB>"
 
 " <TAB>: completion.
@@ -25,19 +23,170 @@ function! s:check_back_space() abort
   return !col || getline('.')[col - 1]  =~# '\s'
 endfunction
 
-" these will likely interfere with coc.vim maps
-nnoremap <silent> gd    <cmd>lua vim.lsp.buf.declaration()<CR>
-nnoremap <silent> <c-]> <cmd>lua vim.lsp.buf.definition()<CR>
-nnoremap <silent> K     <cmd>lua vim.lsp.buf.hover()<CR>
-nnoremap <silent> gD    <cmd>lua vim.lsp.buf.implementation()<CR>
-nnoremap <silent> <c-k> <cmd>lua vim.lsp.buf.signature_help()<CR>
-nnoremap <silent> 1gD   <cmd>lua vim.lsp.buf.type_definition()<CR>
-nnoremap <silent> gr    <cmd>lua vim.lsp.buf.references()<CR>
-nnoremap <silent> g0    <cmd>lua vim.lsp.buf.document_symbol()<CR>
+" maps
+nnoremap <silent> gd        <cmd>lua vim.lsp.buf.declaration()<CR>
+nnoremap <silent> <c-]>     <cmd>lua vim.lsp.buf.definition()<CR>
+nnoremap <silent> K         <cmd>lua vim.lsp.buf.hover()<CR>
+nnoremap <silent> gD        <cmd>lua vim.lsp.buf.implementation()<CR>
+nnoremap <silent> <c-k>     <cmd>lua vim.lsp.buf.signature_help()<CR>
+nnoremap <silent> 1gD       <cmd>lua vim.lsp.buf.type_definition()<CR>
+nnoremap <silent> gr        <cmd>lua vim.lsp.buf.references()<CR>
+nnoremap <silent> g0        <cmd>lua vim.lsp.buf.document_symbol()<CR>
+nnoremap <silent> <leader>f <cmd>lua vim.lsp.buf.formatting()<CR>
+nnoremap <silent> <leader>a <cmd>lua vim.lsp.buf.code_action()<CR>
+nnoremap <silent> <leader>r <cmd>lua vim.lsp.buf.rename()<CR>
 
 " nvim-lsp config
 packloadall " https://github.com/neovim/neovim/issues/11407
 lua << EOF
 local nvim_lsp = require'nvim_lsp'
+local configs = require'nvim_lsp/configs'
+local util = require'nvim_lsp/util'
+
+-- remove once omnisharp support is merged
+configs.omnisharp_lsp = {
+  default_config = {
+    cmd = {"omnisharp","-lsp"};
+    filetypes = {"cs"};
+    root_dir = util.root_pattern("*.csproj", "*.sln", ".git");
+    settings = {};
+  };
+}
+
 nvim_lsp.tsserver.setup{}
+nvim_lsp.omnisharp_lsp.setup{}
+
+-- TODO install globally or use :LspInstall
+nvim_lsp.bashls.setup{}
+nvim_lsp.html.setup{}
+nvim_lsp.cssls.setup{}
+nvim_lsp.yamlls.setup{}
+nvim_lsp.jsonls.setup{}
+nvim_lsp.vimls.setup{}
+nvim_lsp.dockerls.setup{}
+
+-- based on: https://github.com/mikew/vimrc/blob/master/src/nvim/coc-settings.json
+nvim_lsp.diagnosticls.setup{
+  filetypes = {
+    "javascript",
+    "javascript.jsx",
+    "javascriptreact",
+    "typescript",
+    "typescript.jsx",
+    "typescriptreact",
+    "json",
+    "yaml",
+    "markdown",
+    "html",
+    "css"
+  };
+  init_options = {
+    linters = {
+      eslint = {
+        command = "eslint";
+        args = {
+          "--stdin",
+          "--stdin-filename",
+          "%filepath",
+          "--format",
+          "json"
+        };
+        rootPatterns = {".git"};
+        debounce = 50;
+        sourceName = "eslint";
+        parseJson = {
+          errorsRoot = "[0].messages";
+          line = "line";
+          column = "column";
+          endLine = "endLine";
+          endColumn = "endColumn";
+          message = "${message} [${ruleId}]";
+          security = "severity";
+        };
+        securities = {
+          ["2"] = "error";
+          ["1"] = "warning";
+        };
+      };
+      stylelint = {
+        command = "stylelint";
+        args = {
+          "--stdin",
+          "--formatter",
+          "json",
+          "--file",
+          "%filepath"
+        };
+        rootPatterns = {".git"};
+        debounce = 50;
+        sourceName = "stylelint";
+        parseJson = {
+          errorsRoot = "[0].warnings";
+          line = "line";
+          column = "column";
+          message = "${text}";
+          security = "severity";
+        };
+        securities = {
+          error = "error";
+          warning = "warning";
+        };
+      };
+    };
+    filetypes = {
+      javascript = {"eslint"};
+      ["javascript.jsx"] = {"eslint"};
+      javascriptreact = {"eslint"};
+      typescript = {"eslint"};
+      ["typescript.jsx"] = {"eslint"};
+      typescriptreact = {"eslint"};
+      css = {"stylelint"};
+    };
+    formatters = {
+      eslint = {
+        command = "eslint";
+        args = {
+          "--fix",
+          "%file"
+        };
+        rootPatterns = {".git"};
+        isStdout = 1;
+        doesWriteToFile = 1;
+      };
+      stylelint = {
+        command = "stylelint";
+        args = {
+          "--stdin",
+          "--fix",
+          "--file",
+          "%filepath"
+        };
+        rootPatterns = {".git"};
+      };
+      prettier = {
+        command = "prettier";
+        args = {
+          "--stdin",
+          "--stdin-filepath",
+          "%filepath"
+        };
+        rootPatterns = {".git"};
+      };
+    };
+    formatFiletypes = {
+      javascript = {"eslint"};
+      ["javascript.jsx"] = {"eslint"};
+      javascriptreact = {"eslint"};
+      typescript = {"eslint"};
+      ["typescript.jsx"] = {"eslint"};
+      typescriptreact = {"eslint"};
+      json = {"prettier"};
+      yaml = {"prettier"};
+      markdown = {"prettier"};
+      html = {"prettier"};
+      css = {"stylelint"};
+    };
+  };
+}
+
 EOF
diff --git a/home/editors/neovim.nix b/home/editors/neovim.nix
index fb2fb58..aa3eee2 100644
--- a/home/editors/neovim.nix
+++ b/home/editors/neovim.nix
@@ -2,12 +2,12 @@
 
 let
   neovim-unwrapped = pkgs.neovim-unwrapped.overrideAttrs (oldAttrs: rec {
-    version = "2020-08-13";
+    version = "2020-08-26";
     src = pkgs.fetchFromGitHub {
       owner = "neovim";
       repo = "neovim";
-      rev = "6a8dcfab4b2bada9c68379ee17235974fa8ad411";
-      sha256 = "1hlfcxjmp3xihqb5z90bih4j2lvzypgdbqh7w3y3qvxgsaz07bzv";
+      rev = "91109ffda23d0ce61cec245b1f4ffb99e7591b62";
+      sha256 = "1rq7j6r1hfkxwmbf688fkwy9j86zam8rywy4796fwkb3imxw64rs";
     };
     nativeBuildInputs = oldAttrs.nativeBuildInputs ++ [
       pkgs.utf8proc
@@ -35,14 +35,14 @@ let
       rev = "fc9d94ef006e082596c2e8724eb3f1c92ff203c7";
       sha256 = "1byji4p0xigyp8y71s00fs2vrhgz3xkf51mmyz489pp52c7nfx4v";
     };
+    # required until omnisharp support is merged
+    patches = with pkgs; [
+      (fetchpatch { url = "https://patch-diff.githubusercontent.com/raw/neovim/nvim-lsp/pull/296.patch";
+                    sha256 = "084ryddj0j7jialx91z6iqawf4s2hhn5d7wpd19cg1sl18vlyzp4"; })
+    ];
   };
 in
 {
-  home.packages = with pkgs; [
-    # nodejs-12_x
-    # haskellPackages.ghcide
-  ];
-
   programs.neovim = {
     enable = true;
     package = neovim-unwrapped;
@@ -71,39 +71,21 @@ in
       argtextobj-vim
 
       nvim-lsp
+
+      # might require :UpdateRemotePlugins
       deoplete-nvim
       deoplete-lsp
 
       vim-orgmode
       vim-nix
-
-      coc-nvim
-      coc-pairs
-      coc-emmet
-      coc-snippets
-      coc-highlight
-      coc-html
-      coc-css
-      coc-tsserver
-      coc-json
-      coc-yaml
-      coc-eslint
-      coc-stylelint
-      coc-prettier
-      # not yet in nixpkgs:
-      # coc-angular
-      # coc-omnisharp # not really maintained
-
-      ale # only used for omnisharp-vim
-      omnisharp-vim
     ];
     extraConfig = with builtins;
       readFile ./init.vim +
       readFile ./vim-surround-fix.vim +
       readFile ./which-key.vim +
-      readFile ./coc.vim;
-      # readFile ./lsp.vim;
+      readFile ./lsp.vim;
     withNodeJs = true;
+    withPython = false;
   };
 
   xdg.configFile."nvim/coc-settings.json".source = ./coc-settings.json;
diff --git a/home/editors/omnisharp.nix b/home/editors/omnisharp.nix
index 1e4228d..f1e9396 100644
--- a/home/editors/omnisharp.nix
+++ b/home/editors/omnisharp.nix
@@ -1,13 +1,28 @@
 { config, pkgs, ... }:
 
+let
+  omnisharp-roslyn = pkgs.omnisharp-roslyn.overrideAttrs(oldAttrs: rec {
+    pname = "omnisharp-roslyn";
+    version = "1.37.0";
+
+    src = pkgs.fetchurl {
+      url = "https://github.com/OmniSharp/omnisharp-roslyn/releases/download/v${version}/omnisharp-mono.tar.gz";
+      sha256 = "1lbwfx1nn1bjgbm8pjmr89kbvf69lwj237np3m52r3qw7pfrmqc9";
+    };
+  });
+in
 {
   home.packages = with pkgs; [
     omnisharp-roslyn
   ];
 
+  # UseLegacySdkResolver: true is currently required
   home.file.".omnisharp/omnisharp.json" = {
     text = ''
       {
+        "MsBuild": {
+          "UseLegacySdkResolver": true
+        },
         "FormattingOptions": {
           "EnableEditorConfigSupport": true
         },