From e393100b98a05cfec05f236e16077b5da8597d8a Mon Sep 17 00:00:00 2001
From: Matthew Leong <mattleong91@gmail.com>
Date: Fri, 26 Jan 2024 09:57:15 -0800
Subject: [PATCH] feat: add NX monorepo support

---
 lazy-lock.json                              | 48 +++++------
 lua/cosmic/lsp/commands.lua                 | 95 +++++++++++++++++++++
 lua/cosmic/lsp/init.lua                     |  1 +
 lua/cosmic/plugins/mason-lspconfig/init.lua | 67 +--------------
 4 files changed, 121 insertions(+), 90 deletions(-)
 create mode 100644 lua/cosmic/lsp/commands.lua

diff --git a/lazy-lock.json b/lazy-lock.json
index 2be2907..b2a6a1e 100644
--- a/lazy-lock.json
+++ b/lazy-lock.json
@@ -1,7 +1,7 @@
 {
   "Comment.nvim": { "branch": "master", "commit": "0236521ea582747b58869cb72f70ccfa967d2e89" },
-  "LuaSnip": { "branch": "master", "commit": "82108e7e31cc6fc223cc5df5cae6d89f70bb199f" },
-  "SchemaStore.nvim": { "branch": "main", "commit": "aa03f815694c003892bb80efcf4d7c33aea3e009" },
+  "LuaSnip": { "branch": "master", "commit": "2dbef19461198630b3d7c39f414d09fb07d1fdd2" },
+  "SchemaStore.nvim": { "branch": "main", "commit": "5264dd76f87904592ca5a4302c48389c1277ab28" },
   "auto-session": { "branch": "main", "commit": "51196ca66b38fc1660fdf50031cb0b31a199b7c9" },
   "cmp-buffer": { "branch": "main", "commit": "3022dbc9166796b644a841a02de8dd1cc1d311fa" },
   "cmp-cmdline": { "branch": "main", "commit": "8ee981b4a91f536f52add291594e89fb6645e451" },
@@ -9,35 +9,35 @@
   "cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" },
   "cmp_luasnip": { "branch": "master", "commit": "05a9ab28b53f71d1aece421ef32fee2cb857a843" },
   "cosmic-ui": { "branch": "main", "commit": "c0b14531999f2bfef3d927c4dcd57a1a8fed5ee9" },
-  "friendly-snippets": { "branch": "main", "commit": "69a2c1675b66e002799f5eef803b87a12f593049" },
-  "gitsigns.nvim": { "branch": "main", "commit": "4aaacbf5e5e2218fd05eb75703fe9e0f85335803" },
-  "lazy.nvim": { "branch": "main", "commit": "96584866b9c5e998cbae300594d0ccfd0c464627" },
-  "lualine.nvim": { "branch": "master", "commit": "566b7036f717f3d676362742630518a47f132fff" },
-  "mason-lspconfig.nvim": { "branch": "main", "commit": "0989bdf4fdf7b5aa4c74131d7ffccc3f399ac788" },
-  "mason.nvim": { "branch": "main", "commit": "e110bc3be1a7309617cecd77bfe4bf86ba1b8134" },
-  "neodev.nvim": { "branch": "main", "commit": "dde00106b9094f101980b364fae02fd85d357306" },
-  "noice.nvim": { "branch": "main", "commit": "92433164e2f7118d4122c7674c3834d9511722ba" },
-  "none-ls.nvim": { "branch": "main", "commit": "7e146f3a188853843bb4ca1bff24c912bb9b7177" },
+  "friendly-snippets": { "branch": "main", "commit": "aced40b66b7bae9bc2c37fd7b11841d54727a7b0" },
+  "gitsigns.nvim": { "branch": "main", "commit": "fb9fd5312476b51a42a98122616e1c448d823d5c" },
+  "lazy.nvim": { "branch": "main", "commit": "aedcd79811d491b60d0a6577a9c1701063c2a609" },
+  "lualine.nvim": { "branch": "master", "commit": "7d131a8d3ba5016229e8a1d08bf8782acea98852" },
+  "mason-lspconfig.nvim": { "branch": "main", "commit": "b9084b1f42f790d6230dc66dbcb6bcc35b148552" },
+  "mason.nvim": { "branch": "main", "commit": "dcd0ea30ccfc7d47e879878d1270d6847a519181" },
+  "neodev.nvim": { "branch": "main", "commit": "64b2a51b02c6f2ae177c745e4d8bc801a339fe09" },
+  "noice.nvim": { "branch": "main", "commit": "bf67d70bd7265d075191e7812d8eb42b9791f737" },
+  "none-ls.nvim": { "branch": "main", "commit": "a311c7cc8f17543143a7482cdbe3a384c371d56a" },
   "nui.nvim": { "branch": "main", "commit": "35da9ca1de0fc4dda96c2e214d93d363c145f418" },
-  "nvim-autopairs": { "branch": "master", "commit": "9fd41181693dd4106b3e414a822bb6569924de81" },
+  "nvim-autopairs": { "branch": "master", "commit": "096d0baecc34f6c5d8a6dd25851e9d5ad338209b" },
   "nvim-cmp": { "branch": "main", "commit": "538e37ba87284942c1d76ed38dd497e54e65b891" },
   "nvim-colorizer.lua": { "branch": "master", "commit": "36c610a9717cc9ec426a07c8e6bf3b3abcb139d6" },
-  "nvim-lspconfig": { "branch": "master", "commit": "e47ccfae775f0d572ef0f3a7d245f043b259dafc" },
-  "nvim-notify": { "branch": "master", "commit": "1576123bff3bed67bc673a3076e591abfe5d8ca9" },
-  "nvim-tree.lua": { "branch": "master", "commit": "b8c3a23e76f861d5f0ff3f6714b9b56388984d0b" },
-  "nvim-treesitter": { "branch": "master", "commit": "8cd2b230174efbf7b5d9f49fe2f90bda6b5eb16e" },
+  "nvim-lspconfig": { "branch": "master", "commit": "8917d2c830e04bf944a699b8c41f097621283828" },
+  "nvim-notify": { "branch": "master", "commit": "80b67b265530632505193553d05127ae7fe09ddd" },
+  "nvim-tree.lua": { "branch": "master", "commit": "7bdb220d0fe604a77361e92cdbc7af1b8a412126" },
+  "nvim-treesitter": { "branch": "master", "commit": "efda19a54a157da8635aa6cb84f56a10593b1a23" },
   "nvim-treesitter-refactor": { "branch": "master", "commit": "65ad2eca822dfaec2a3603119ec3cc8826a7859e" },
-  "nvim-ts-autotag": { "branch": "main", "commit": "8515e48a277a2f4947d91004d9aa92c29fdc5e18" },
+  "nvim-ts-autotag": { "branch": "main", "commit": "a65b202cfd08e0e69e531eab737205ff5bc082a4" },
   "nvim-ts-context-commentstring": { "branch": "main", "commit": "1277b4a1f451b0f18c0790e1a7f12e1e5fdebfee" },
-  "nvim-web-devicons": { "branch": "master", "commit": "db0c864375c198cacc171ff373e76bfce2a85045" },
-  "plenary.nvim": { "branch": "master", "commit": "55d9fe89e33efd26f532ef20223e5f9430c8b0c0" },
+  "nvim-web-devicons": { "branch": "master", "commit": "b427ac5f9dff494f839e81441fb3f04a58cbcfbc" },
+  "plenary.nvim": { "branch": "master", "commit": "663246936325062427597964d81d30eaa42ab1e4" },
   "popup.nvim": { "branch": "master", "commit": "b7404d35d5d3548a82149238289fa71f7f6de4ac" },
   "telescope-fzf-native.nvim": { "branch": "main", "commit": "6c921ca12321edaa773e324ef64ea301a1d0da62" },
-  "telescope.nvim": { "branch": "master", "commit": "da8b3d485975a8727bea127518b65c980521ae22" },
-  "todo-comments.nvim": { "branch": "main", "commit": "4a6737a8d70fe1ac55c64dfa47fcb189ca431872" },
-  "tokyonight.nvim": { "branch": "main", "commit": "f247ee700b569ed43f39320413a13ba9b0aef0db" },
-  "typescript-tools.nvim": { "branch": "master", "commit": "1469468977ea32dbcba0116c8f8fb19f1f902dca" },
+  "telescope.nvim": { "branch": "master", "commit": "1bfbb1fb5c56d2dbe33216fcb2ebe82e499aa06c" },
+  "todo-comments.nvim": { "branch": "main", "commit": "833d8dd8b07eeda37a09e99460f72a02616935cb" },
+  "tokyonight.nvim": { "branch": "main", "commit": "e3301873c1e96903daebb98cc9b5926810bf73dd" },
+  "typescript-tools.nvim": { "branch": "master", "commit": "c43d9580c3ff5999a1eabca849f807ab33787ea7" },
   "vim-floaterm": { "branch": "master", "commit": "3f01a623376957437f9376327637491b74719e38" },
-  "vim-fugitive": { "branch": "master", "commit": "59659093581aad2afacedc81f009ed6a4bfad275" },
+  "vim-fugitive": { "branch": "master", "commit": "854a8df0d06b8d3fcb30fa7f2b08c62b553eee3b" },
   "which-key.nvim": { "branch": "main", "commit": "4433e5ec9a507e5097571ed55c02ea9658fb268a" }
 }
\ No newline at end of file
diff --git a/lua/cosmic/lsp/commands.lua b/lua/cosmic/lsp/commands.lua
new file mode 100644
index 0000000..0ada101
--- /dev/null
+++ b/lua/cosmic/lsp/commands.lua
@@ -0,0 +1,95 @@
+-- Major props to @failen here
+-- https://github.com/pmizio/typescript-tools.nvim/issues/124
+vim.api.nvim_create_user_command('NxInit', function()
+  local now = tostring(os.time())
+  local fileName = string.format('%s_graph.json', now)
+  -- @TODO check if we should use yarn or npx
+  local cmd = string.format('yarn -s nx graph --file=%s', fileName)
+
+  local function handle_response(_, code)
+    -- read the file into memory
+    local projectGraphFile = io.open(fileName, 'r')
+    if projectGraphFile then
+      -- read project graph from file
+      local projectGraph = vim.json.decode(projectGraphFile:read('*a'))
+      projectGraphFile:close()
+
+      -- remove the graph file
+      os.remove(fileName)
+
+      -- get typescript-tools lsp client
+      local lspClients = vim.lsp.get_clients()
+      local tsclient
+      for _, client in ipairs(lspClients) do
+        if client.name == 'typescript-tools' then
+          tsclient = client
+        end
+      end
+      if not tsclient then
+        print('typescript-tools.nvim not active')
+        return
+      end
+
+      -- get workspace root
+      -- always first? alternatives to get absolute workspace root?
+      local workspacePath = tsclient.config.workspace_folders[1].name
+      if not workspacePath then
+        print('Could not figure out workspace path')
+        return
+      end
+
+      -- create external files for monodon
+      local externalFiles = {}
+      for _, project in pairs(projectGraph.graph.nodes) do
+        local sourceRoot = project.data.sourceRoot
+
+        -- skip the root
+        if sourceRoot ~= '.' and sourceRoot then
+          -- localte the entry file. perhaps use tsconfig.[app|lib].json
+          local mainFile
+          if
+            project.data
+            and project.data.targets
+            and project.data.targets.build
+            and project.data.targets.build.options
+            and project.data.targets.build.options.main
+          then
+            mainFile = workspacePath .. '/' .. project.data.targets.build.options.main
+          else
+            mainFile = workspacePath .. '/' .. sourceRoot .. '/index.ts'
+          end
+
+          -- insert to config
+          table.insert(externalFiles, {
+            mainFile = mainFile, -- this is not always index.ts!
+            directory = workspacePath .. '/' .. sourceRoot,
+          })
+        end
+      end
+
+      -- print(vim.inspect(externalFiles))
+      -- send configuration request of monodon plugin to tsserver
+      local constants = require('typescript-tools.protocol.constants')
+      local method = constants.CustomMethods.ConfigurePlugin
+      local args = {
+        pluginName = '@monodon/typescript-nx-imports-plugin',
+        configuration = {
+          externalFiles = externalFiles,
+        },
+      }
+
+      ---@diagnostic disable-next-line: missing-parameter
+      tsclient.request(method, args, function()
+        print('tsserver handled configuration request', method)
+      end)
+      print('NX Plugin initialized!')
+    end
+  end
+
+  -- call nx deamon with graph request, run it in the background with job
+  vim.fn.jobstart(cmd, {
+    on_exit = handle_response,
+    stdout_buffered = true,
+    stderr_buffered = true,
+  })
+end, {})
diff --git a/lua/cosmic/lsp/init.lua b/lua/cosmic/lsp/init.lua
index 92f7ba0..0666bb2 100644
--- a/lua/cosmic/lsp/init.lua
+++ b/lua/cosmic/lsp/init.lua
@@ -1,3 +1,4 @@
 require('cosmic.lsp.diagnostics')
+require('cosmic.lsp.commands')
 
 -- LSP server initialization can be found in mason-lspconfig setup
diff --git a/lua/cosmic/plugins/mason-lspconfig/init.lua b/lua/cosmic/plugins/mason-lspconfig/init.lua
index 516c181..2001028 100644
--- a/lua/cosmic/plugins/mason-lspconfig/init.lua
+++ b/lua/cosmic/plugins/mason-lspconfig/init.lua
@@ -50,74 +50,9 @@ return {
         start_server(config_server)
       end
     end
-
-    -- See: https://github.com/neovim/neovim/issues/23291
-    --[[ local watch_type = require('vim._watch').FileChangeType ]]
-    --[[]]
-    --[[ local function handler(res, callback) ]]
-    --[[   if not res.files or res.is_fresh_instance then ]]
-    --[[     return ]]
-    --[[   end ]]
-    --[[]]
-    --[[   for _, file in ipairs(res.files) do ]]
-    --[[     local path = res.root .. '/' .. file.name ]]
-    --[[     local change = watch_type.Changed ]]
-    --[[     if file.new then ]]
-    --[[       change = watch_type.Created ]]
-    --[[     end ]]
-    --[[     if not file.exists then ]]
-    --[[       change = watch_type.Deleted ]]
-    --[[     end ]]
-    --[[     callback(path, change) ]]
-    --[[   end ]]
-    --[[ end ]]
-    --[[]]
-    --[[ local function watchman(path, opts, callback) ]]
-    --[[   vim.system({ 'watchman', 'watch', path }):wait() ]]
-    --[[]]
-    --[[   local buf = {} ]]
-    --[[   local sub = vim.system({ ]]
-    --[[     'watchman', ]]
-    --[[     '-j', ]]
-    --[[     '--server-encoding=json', ]]
-    --[[     '-p', ]]
-    --[[   }, { ]]
-    --[[     stdin = vim.json.encode({ ]]
-    --[[       'subscribe', ]]
-    --[[       path, ]]
-    --[[       'nvim:' .. path, ]]
-    --[[       { ]]
-    --[[         expression = { 'anyof', { 'type', 'f' }, { 'type', 'd' } }, ]]
-    --[[         fields = { 'name', 'exists', 'new' }, ]]
-    --[[       }, ]]
-    --[[     }), ]]
-    --[[     stdout = function(_, data) ]]
-    --[[       if not data then ]]
-    --[[         return ]]
-    --[[       end ]]
-    --[[       for line in vim.gsplit(data, '\n', { plain = true, trimempty = true }) do ]]
-    --[[         table.insert(buf, line) ]]
-    --[[         if line == '}' then ]]
-    --[[           local res = vim.json.decode(table.concat(buf)) ]]
-    --[[           handler(res, callback) ]]
-    --[[           buf = {} ]]
-    --[[         end ]]
-    --[[       end ]]
-    --[[     end, ]]
-    --[[     text = true, ]]
-    --[[   }) ]]
-    --[[]]
-    --[[   return function() ]]
-    --[[     sub:kill('sigint') ]]
-    --[[   end ]]
-    --[[ end ]]
-    --[[]]
-    --[[ if vim.fn.executable('watchman') == 1 then ]]
-    --[[   require('vim.lsp._watchfiles')._watchfunc = watchman ]]
-    --[[ end ]]
   end,
   dependencies = {
     'williamboman/mason.nvim',
   },
-  event = 'BufEnter',
+  --[[ event = 'BufEnter', ]]
 }