wincent / command-t

⌨️ Fast file navigation for Neovim and Vim
BSD 2-Clause "Simplified" License
2.74k stars 317 forks source link

Implement Lua equivalent of `g:CommandTTraverseSCM` setting #416

Open niloct opened 1 year ago

niloct commented 1 year ago

Hi,

Thanks for the continued support on this tool, it's very useful!

Nevertheless, I am facing an issue with CommandT on Neovim:

NVIM v0.8.1
Build type: Release
LuaJIT 2.1.0-beta3
Compilado por macports@catalina.internal.macports.net

Features: +acl +iconv +tui

When I navigate a folder deep down the git repository, CommandT can't find files in parent directories on the same repository.

This was very useful on earlier ruby version, because I could just not care on which directory I spawned neovim, using CommandT I could find all files on the repository. My init.vim

  Plug 'wincent/command-t'
  let g:CommandTMaxHeight=30
  let g:CommandTMatchWindowReverse=0
  let g:CommandTPreferredImplementation='lua'
  let g:CommandTFileScanner='git'  
  nmap <Leader>t :CommandTGit<CR>

Could you see any wrong configuration ?

Thanks in advance for your attention, Nilo

wincent commented 1 year ago

Good catch @niloct. This is a missing feature in the Lua version. The Ruby version used the g:CommandTTraverseSCM setting to control this behavior, so we'll need something similar for the Lua version for parity. Quoting the docs to describe how this worked:

                                            *g:CommandTTraverseSCM*
  |g:CommandTTraverseSCM|                     string (default: 'file')

      Instructs Command-T how to choose a root path when opening a file finder
      without an explicit path argument. Possible values are:

      - "file": starting from the file currently being edited, traverse
        upwards through the filesystem hierarchy until you find an SCM root
        (as indicated by the presence of a ".git", ".hg" or similar directory)
        and use that as the base path. If no such root is found, fall back to
        using Vim's present working directory as a root. The list of SCM
        directories that Command-T uses to detect an SCM root can be
        customized with the |g:CommandTSCMDirectories| option.

      - "dir": traverse upwards looking for an SCM root just like the "file"
        setting (above), but instead of starting from the file currently being
        edited, start from Vim's present working directory instead.

      - "pwd": use Vim's present working directory as a root (ie. attempt no
        traversal).

So we'll have to add that functionality back in.

The other thing is about your set-up:

Plug 'wincent/command-t'
let g:CommandTMaxHeight=30
let g:CommandTMatchWindowReverse=0
let g:CommandTPreferredImplementation='lua'
let g:CommandTFileScanner='git'  
nmap <Leader>t :CommandTGit<CR>

When you're running the Lua version, none of the g: switches do anything, except for g:CommandTPreferredImplementation. There is no equivalent of g:CommandTFileScanner in the Lua version; you're just supposed to call :CommandTGit like you're doing in your mapping. For the other two settings, it would be this in Vimscript:

lua << EOF
require('wincent.commandt').setup({
  height = 30,
  order = 'forward', -- Note: This is the default now, so you don't need it.
})
EOF

or this in init.lua:

require('wincent.commandt').setup({
  height = 30,
})
wincent commented 1 year ago

Just to document the old logic here while it's still fresh in my mind, here are the relevant bits copied from various places:

def pwd
  ::VIM::evaluate 'getcwd()'
end

def current_file_dir
  ::VIM::evaluate 'expand("%:p:h")'
end

def nearest_ancestor(starting_directory, markers)
  path = File.expand_path(starting_directory)
  while !markers.
    map { |dir| File.join(path, dir) }.
    map { |dir| File.exist?(dir) }.
    any?
    next_path = File.expand_path(File.join(path, '..'))
    return nil if next_path == path
    path = next_path
  end
  path
end

def scm_markers
  markers = VIM::get_string('g:CommandTSCMDirectories')
  markers = markers && markers.split(/\s*,\s*/)
  markers = %w[.git .hg .svn .bzr _darcs] unless markers && markers.any?
  markers
end

traverse = VIM::get_string('g:CommandTTraverseSCM') || 'file'
case traverse
when 'file'
  @path = nearest_ancestor(VIM::current_file_dir, scm_markers) || VIM::pwd
when 'dir'
  @path = nearest_ancestor(VIM::pwd, scm_markers) || VIM::pwd
else
  @path = VIM::pwd
end

More generally, but closely related to this, is the way the Lua implementation handles path arguments.

I think overall I should change the behavior of the Lua version to match the Ruby one — conceptually, it behaves as if you cd into the specified directory before showing the results, and when you choose an item, it figures out how to turn the selection into a relative or absolute path (ie. in "some/subdirectory" if you choose "foo" it tells Neovim to open "some/subdirectory/foo").

niloct commented 1 year ago

Hi wincent,

Sorry for asking, but this is a much needed feature, do you estimate when it's gonna be available for the lua implementation ?

Thanks.

wincent commented 1 year ago

I already started working on it, but it's unpleasantly complicated. I need to refactor to work around some assumptions that make it hard to do the simple thing (eg. cd into the right directory before running the scanner). I'll push up the branch I'm working on later so you can see the progress.

wincent commented 1 year ago

traverse branch has my work-in-progress on it, although I just stupidly ran git reset --hard and blew away some uncomitted changes that I had 😭.