GnikDroy / projections.nvim

A map to your filesystem
GNU General Public License v3.0
236 stars 8 forks source link

setup() has no effect / workspace not detected / projects not listed #20

Closed jaidetree closed 1 year ago

jaidetree commented 1 year ago

Reproduction

  1. Configure projections using the config below
  2. Restart neovim
  3. Open :Telescope projections either from hotkey or manual cmd

Expected

Actual

Exploration

Read through some of the code and pinpointed it to:

Workspace.get_workspaces_from_config()

Returning an empty table, even though projections.config.config.workspaces has the table as defined below.

Config


;; In my packer config

(use "gnikdroy/projections.nvim"
    {:after [:telescope.nvim]
     :config #(require :config.plugins.projections)})

;; In config/plugins/projections.fnl

(projections.setup
  {:workspaces [["~/projects"   [".git"]]
                ["~/dotfiles"   [".git" "*.org"]]]})
GnikDroy commented 1 year ago

Okay, firstly, patterns is not regexp. So, *.org doesn't work as expected. This is mentioned in the docs, but apparently not enough.

patterns used to be a regular regexp, then transformed to lua patterns, and now finally doesn't do any pattern matching at all. This was supposedly done to improve performance and complxity, although I didn't benchmark :P. And because usually there is a better pattern out there which doesn't require this. Supporting lua patterns is certainly possible and pretty painless, so I will think about it, after benchmarking a bit.

Does ~/projects and ~/dotfiles contain a subdirectory with .git directory inside? If not, the bug is explained. I think ~/dotfiles at least doesn't have such directory.

Also note that it has to be a direct subdirectory. ~/projects/A/B/.git doesn't count. Only ~/projects/A/.git does.

Information that will be helpful:

I will look at your issue further in a couple of hours. I do not use fennel, so I will need to learn some things first.

jaidetree commented 1 year ago

My mistake on missing the pattern matching. What about supporting a predicate function or table for the patterns? Then in userland could do pattern matching at own peril or other testing methods.

No need to worry about fennel if not interested, here's the lua equivalent:

use("gnikdroy/projections.nvim", {
  after={"telescope.nvim"},
  config=function () require("config.plugins.projections") end
})

-- Equivalent lua of config/plugins/projections.fnl

local projections = require("projections")

projections.setup({
  workspaces={
   {"~/projects", {".git"}},
   {"~/dotfiles", {".git", ".org"}} -- Fixed this given the above
  }
})
Projects, some results filtered out ``` /Users/j/projects ├── .DS_Store ├── .prettierrc.json ├── .tool-versions ├── beecat │   ├── .DS_Store │   ├── .git │   ├── .gitignore │   ├── .lsp │   ├── .shadow-cljs │   ├── README.org │   ├── backend │   ├── cypress │   ├── cypress.json │   ├── docker │   ├── docker-compose.yml │   ├── game │   ├── node_modules │   ├── package-lock.json │   ├── package.json │   ├── shadow-cljs.edn │   ├── src │   └── yarn.lock ├── benfrankenberg.com │   ├── .git │   ├── .gitignore │   ├── LICENSE │   ├── README.org │   ├── design │   ├── externs │   ├── gulpfile.js │   ├── package-lock.json │   ├── package.json │   ├── shadow-cljs.edn │   └── src ├── braincore │   ├── .DS_Store │   ├── .calva │   ├── .clj-kondo │   ├── .cpcache │   ├── .env │   ├── .git │   ├── .github │   ├── .gitignore │   ├── .log │   ├── .lsp │   ├── .nrepl-port │   ├── .shadow-cljs │   ├── .tool-versions │   ├── bin │   ├── blocks.edn │   ├── debug-out.edn │   ├── debug.edn │   ├── debug.txt │   ├── deps.edn │   ├── docs │   ├── entry.edn │   ├── env.example │   ├── events.edn │   ├── googleauth.private.json │   ├── linear.edn │   ├── node_modules │   ├── package.json │   ├── readme.org │   ├── request.json │   ├── scripts │   ├── shadow-cljs.edn │   ├── src │   ├── tailwind.config.js │   ├── yarn-error.log │   └── yarn.lock ├── brainframe │   ├── .clj-kondo │   ├── .cpcache │   ├── .env │   ├── .envrc │   ├── .git │   ├── .lsp │   ├── .nbb │   ├── .nrepl-port │   ├── compose.yml │   ├── config │   ├── deps.edn │   ├── migrations │   ├── nbb.edn │   ├── node_modules │   ├── package-lock.json │   ├── package.json │   ├── src │   └── yarn-error.log ├── cherry │   ├── .clj-kondo │   ├── .git │   ├── .github │   ├── .gitignore │   ├── .nojekyll │   ├── README.md │   ├── bb │   ├── bb.edn │   ├── cljs.core.js │   ├── compile.clj │   ├── corpus │   ├── deps.edn │   ├── epl-v10.html │   ├── examples │   ├── index.html │   ├── index.js │   ├── node_cli.js │   ├── notes │   ├── package.json │   ├── project.clj │   ├── resources │   ├── shadow-cljs.edn │   ├── src │   └── test ├── clj-cgi-example │   ├── .git │   ├── .gitignore │   ├── LICENSE │   ├── README.org │   ├── build-pods │   ├── depjar │   ├── docker │   └── example ├── cljs-ring-express │   ├── .DS_Store │   ├── .git │   ├── .gitignore │   ├── .lsp │   ├── .shadow-cljs │   ├── README.org │   ├── build │   ├── node_modules │   ├── package-lock.json │   ├── package.json │   ├── shadow-cljs.edn │   └── src ├── cljs-tui-template │   ├── .circleci │   ├── .git │   ├── .gitignore │   ├── CHANGELOG.md │   ├── LICENSE │   ├── README.md │   ├── build.sh │   ├── doc │   ├── examples │   ├── pom.xml │   ├── project.clj │   ├── repl.sh │   ├── resources │   ├── run.sh │   ├── src │   ├── target │   └── test.sh ├── conjure │   ├── .circleci │   ├── .dockerignore │   ├── .envrc │   ├── .fs.test │   ├── .git │   ├── .gitattributes │   ├── .github │   ├── .gitignore │   ├── .lnvim.fnl │   ├── .nrepl-port │   ├── CONTRIBUTING.adoc │   ├── Dockerfile │   ├── Makefile │   ├── README.adoc │   ├── UNLICENSE │   ├── deps │   ├── deps.edn │   ├── dev │   ├── doc │   ├── docs │   ├── fnl │   ├── lua │   ├── notes │   ├── package-lock.json │   ├── package.json │   ├── plugin │   ├── project.clj │   ├── rplugin │   ├── scripts │   ├── shadow-cljs.edn │   ├── shell.nix │   ├── test │   └── tests.edn ├── doom-icon │   ├── .DS_Store │   ├── .git │   ├── .gitignore │   ├── LICENSE │   ├── README.org │   ├── abject-doom │   ├── cute-doom │   ├── emacs-doom │   ├── emacs-yak │   ├── howto-use-icon.gif │   └── scripts ├── echo │   ├── .breakpoints │   ├── .clj-kondo │   ├── .env │   ├── .git │   ├── .gitignore │   ├── .log │   ├── .lsp │   ├── .nrepl-port │   ├── .replit │   ├── .tool-versions │   ├── node_modules │   ├── package-lock.json │   ├── package.json │   ├── public │   ├── readme.md │   ├── replit.nix │   ├── screenshot.webp │   └── src ├── fonts │   ├── .DS_Store │   ├── font-patcher │   ├── nerd-fonts │   ├── patched │   ├── src │   └── unpatched ├── gracieanimator │   ├── .DS_Store │   ├── .clj-kondo │   ├── .cpcache │   ├── .env │   ├── .git │   ├── .gitignore │   ├── .log │   ├── .lsp │   ├── .netlify │   ├── .nrepl-port │   ├── LICENSE │   ├── assets │   ├── build │   ├── deps.edn │   ├── imgs │   ├── netlify │   ├── netlify.toml │   ├── node_modules │   ├── package.json │   ├── public │   ├── readme.org │   ├── resources │   ├── src │   ├── tailwind.config.js │   ├── workers │   ├── yarn-error.log │   └── yarn.lock ├── hammerspoon -> /Users/j/.hammerspoon/ ├── jeejah │   ├── .git │   ├── Changelog.md │   ├── LICENSE │   ├── Makefile │   ├── Readme.md │   ├── bencode.lua │   ├── bin │   ├── fennel.lua │   ├── fennelview.fnl │   ├── jeejah │   ├── jeejah.lua │   ├── monroe-lua-complete.el │   ├── rockspecs │   └── serpent.lua ├── nbb │   ├── .circleci │   ├── .clj-kondo │   ├── .cpcache │   ├── .git │   ├── .github │   ├── .gitignore │   ├── .lsp │   ├── .shadow-cljs │   ├── CHANGELOG.md │   ├── LICENSE │   ├── README.md │   ├── appveyor.yml │   ├── bb.edn │   ├── deps.edn │   ├── doc │   ├── examples │   ├── externs │   ├── img │   ├── index.mjs │   ├── interop.cljs │   ├── logo │   ├── node_modules │   ├── out │   ├── package.json │   ├── pnpm-lock.yaml │   ├── script │   ├── shadow-cljs.edn │   ├── shadow-tests.edn │   ├── src │   ├── test │   ├── test-scripts │   ├── test_redefs.cljs │   └── yarn.lock ├── nbb-fetch-ws-example │   ├── .breakpoints │   ├── .clj-kondo │   ├── .git │   ├── .lsp │   ├── .replit │   ├── .tool-versions │   ├── node_modules │   ├── package-lock.json │   ├── package.json │   ├── public │   ├── readme.md │   ├── replit.nix │   ├── screenshot.webp │   └── src ├── nbb-netlify-demo │   ├── .DS_Store │   ├── .clj-kondo │   ├── .cpcache │   ├── .env │   ├── .git │   ├── .gitignore │   ├── .log │   ├── .lsp │   ├── .netlify │   ├── README.md │   ├── deps.edn │   ├── dist │   ├── netlify │   ├── netlify.toml │   ├── node_modules │   ├── package-lock.json │   ├── package.json │   ├── src │   ├── tailwind.config.js │   └── yarn.lock ├── notion-cms │   ├── .env │   ├── index.js │   ├── node_modules │   ├── package.json │   ├── public │   ├── src │   ├── tailwind.config.js │   ├── yarn-error.log │   └── yarn.lock ├── spacehammer -> /Users/j/.spacehammer ├── spinnerette │   ├── .DS_Store │   ├── .git │   ├── .github │   ├── .gitignore │   ├── .gitmodules │   ├── LICENSE │   ├── Makefile │   ├── README.md │   ├── bindings │   ├── deps │   ├── docs │   ├── examples │   ├── go.mod │   ├── libs │   ├── main.go │   └── spinnerette ```
dotfiles ``` /Users/j/dotfiles ├── .DS_Store ├── .clj-kondo │   └── .cache ├── .dir-locals.el ├── .git │   ├── COMMIT_EDITMSG │   ├── FETCH_HEAD │   ├── HEAD │   ├── NEOGIT_COMMIT_EDITMSG │   ├── ORIG_HEAD │   ├── config │   ├── description │   ├── hooks │   ├── index │   ├── info │   ├── logs │   ├── objects │   ├── packed-refs │   └── refs ├── .gitignore ├── .lsp │   └── .cache ├── README.org ├── Spoons ├── alacritty │   └── alacritty.yml ├── doom.d │   ├── .DS_Store │   ├── config.el │   ├── config.org │   ├── init.el │   ├── local.el │   ├── local.org │   ├── modules │   ├── packages.el │   └── snippets ├── elvish │   ├── db │   ├── elvish.org │   ├── install.sh │   ├── lib │   └── rc.elv ├── emacs │   ├── #init.el# │   ├── .DS_Store │   ├── .gitignore │   ├── README.md │   ├── custom.el │   ├── customizations │   ├── init.el │   └── themes ├── fish │   ├── config.fish │   ├── fishd.1094bbcbf31a │   ├── functions │   └── theme.fish ├── install.sh ├── iterm2 │   └── fishing-line.itermcolors ├── mosh │   └── com.mosh.plist ├── nvim │   ├── .DS_Store │   ├── .gitignore │   ├── Makefile │   ├── cspell.json │   ├── fnl │   ├── init.lua │   ├── lua │   ├── neovim.norg │   ├── neovim.org │   ├── output.secret.txt │   └── plugin ├── omf │   ├── .DS_Store │   ├── bundle │   ├── channel │   ├── functions │   ├── init.fish │   ├── install.sh │   ├── oh-my-fish.org │   ├── theme │   └── themes ├── spacehammer │   ├── .DS_Store │   ├── .nrepl-port │   ├── advice-test.el │   ├── advice.org │   ├── config.fnl │   ├── console.fnl │   ├── elementspecs.txt │   ├── guides.fnl │   ├── idle.fnl │   ├── init.fnl │   ├── layouts.fnl │   ├── modal2.fnl │   ├── run │   ├── run-fennel-file.fnl │   ├── run-repl.fnl │   ├── run-test │   ├── run.lua │   ├── scratch.fnl │   ├── shadow.fnl │   ├── spotify.fnl │   ├── stream │   ├── testing.org │   ├── tmux.fnl │   ├── url-handlers.fnl │   └── zoom.fnl ├── tmux │   ├── base.conf │   ├── install.sh │   ├── osx.conf │   ├── tmux.conf │   ├── tmux.org │   └── unix.conf ├── zsh │   ├── .DS_Store │   ├── lib │   ├── shellvars.zsh │   ├── themes │   ├── zshrc │   └── zshrc.org ```
jaidetree commented 1 year ago

Lastly, just looked for ~/.local/share/nvim/projections_workspaces.json but it does not seem to exist.

GnikDroy commented 1 year ago

Supporting a predicate function would be fine. But then these types of thing can only be done from config and not from the json file.

I am open to bringing back lua patterns, which would enable a lot. The more worrying issue is that it is not even recognizing .git folders. I will report after testing a bit.

GnikDroy commented 1 year ago

I cannot reproduce this at all, sadly.

Workspace.get_workspaces_from_config()

Returning an empty table, even though projections.config.config.workspaces has the table as defined below

This shouldn't happen, the function itself is very simple. https://github.com/GnikDroy/projections.nvim/blob/07540a1c089785cafe8690e096447cf1a166c497/lua/projections/workspace.lua#L113-L128

Since, you have a fork setup on your machine anyway, can you test out that function on your machine?

packer supports including plugins from your filesystem, so it is pretty simple to do this. Just replace

use("gnikdroy/projections.nvim", {

with

use(vim.fs.normalize("/path/to/plugin"), {

Maybe replace the function with,

 function Workspace.get_workspaces_from_config() 
     local workspaces = {} 
     vim.pretty_print(config.workspaces)
     for _, ws in ipairs(config.workspaces) do 
         -- has been configured for { path, patterns } 
         vim.pretty_print(ws)
         if type(ws) == "table" then 
             local path, patterns = unpack(ws) 
             table.insert(workspaces, Workspace.new(Path.new(path), patterns)) 
         end 
         -- has been configured for "path" 
         if type(ws) == "string" then 
             table.insert(workspaces, Workspace.new(Path.new(ws), config.patterns)) 
         end 
     end 
     vim.pretty_print(workspaces)
     workspaces = utils._unique_workspaces(workspaces) 
     vim.pretty_print(workspaces)
     return workspaces 
 end

and post the result of :messages here

GnikDroy commented 1 year ago

You can also try with an empty patterns list {}. This will select all subdirectories.

GnikDroy commented 1 year ago

23 will bring back support for lua patterns.

Any performance regressions will be handled once they arrive.

jaidetree commented 1 year ago

💡 Aha figured it out!

I was able to get it working by replacing the definition of the get_workspaces_from_config with an identical definition at runtime and that worked.

This got me thinking it had something to do with timing like perhaps the extension was calling get_workspaces_from_config before projections was setup, which would explain why the function returned an empty table.

I tried moving the Sessions require below my setup call. My config/plugins/projections.fnl started from:

(local projections (require :projections))
(local Session (require :projections.session))
(local telescope (require :telescope))

(projections.setup
  {:workspaces [["~/projects"   [".git"]]
                ["~/dotfiles"   []]]})

;; Switch to project if vim was started in project dir
(let [switcher (require :projections.switcher)]
  (vim.api.nvim_create_autocmd 
    [:VimEnter]
    {:callback #(when (= (vim.fn.argc) 0)
                  (switcher.switch (vim.loop.cwd)))}))

;; Auto-save session on exit
(vim.api.nvim_create_autocmd 
  [:VimLeavePre] 
  {:callback #(Session.store (vim.loop.cwd))})

;; Register a command to restore the last project session
(vim.api.nvim_create_user_command 
 :RestoreProjectSession
 (fn []
  (Session.restore (vim.loop.cwd)))
 {})

(vim.opt.sessionoptions:append "localoptions")

(telescope.load_extension :projections)

Then changed it to:

(local projections (require :projections))
(local telescope (require :telescope))

(projections.setup
  {:workspaces [["~/projects"   [".git"]]
                ["~/dotfiles"   []]]})

(local Session (require :projections.session))

;; Switch to project if vim was started in project dir
(let [switcher (require :projections.switcher)]
  (vim.api.nvim_create_autocmd 
    [:VimEnter]
    {:callback #(when (= (vim.fn.argc) 0)
                  (switcher.switch (vim.loop.cwd)))}))

;; Auto-save session on exit
(vim.api.nvim_create_autocmd 
  [:VimLeavePre] 
  {:callback #(Session.store (vim.loop.cwd))})

;; Register a command to restore the last project session
(vim.api.nvim_create_user_command 
 :RestoreProjectSession
 (fn []
  (Session.restore (vim.loop.cwd)))
 {})

(vim.opt.sessionoptions:append "localoptions")

(telescope.load_extension :projections)

The only difference was moving:

(local Session (require :projections.session))

Below the setup call, and sure enough once I restarted neovim it started working correctly showing all the projects I can switch to and even restored the last file I had open in them!

I have not looked into why the require order matters so much here. Happy to look into it further but at the same time I don't think it would be unreasonable to see if someone else runs into it before spending more time on it as my configuration is not likely the most common setup.

Thanks for giving it a thorough look. That was a tricky one!

GnikDroy commented 1 year ago

I see. Yes the order matters here, probably in a lot of other plugins as well.

Session uses projection.config and projection.config is setup by setup(). If you load Session before calling setup, Session will cache the value of config (which has default values!) and subsequent setup() will have no effect on Session.

I can remove the caching behavior, but I think most people do call setup() before loading anything. So, I will keep the current behavior. I have renamed the issue to better reflect the problem for future users.