6

Background: I am doing more and more stuff directly from inside Neovim, and less and less from the terminal or even the terminal emulator. So instead of going to the desired directory to work in, and then starting Neovim, I prefer to just start Neovim, and then change to the desired directory. This next part is a bit of a tangent so you can skip to the next paragrapah if you just want the important details, but I know people tend to want to know why I am doing things a certain way so they can potentially suggest a better way. I do this because I will often need to change to different directories anyway multiple times at different points after I start working in Neovim. This way I don't have to close Neovim and open it again from another directory, or else start another instance of Neovim and then not be able to yank and put between them and have to keep track of which running Neovim instance is for what. In order to make it easier to work with a single Neovim instance and change directories, I do 2 things. I have NERDTree setup so that changing the current working directory in Neovim also changes the tree root in NERDTree, and vice versa. I also create commands to quickly navigate to different commonly used directores. Think of these like aliases. These all start with :C. For example if I want to work on my vim-project-tags plugin, I enter the command :Cproj and this will change to the directory where that code is.

Problem: When I first start Neovim, the current buffer is not pointed at any file. If I run the vim-fugitive command :G this only works if the directory I started Neovim in has a git repository. So far this is fine. The problem comes in when I then change to a different working directory from inside Neovim, and then run the :G command. At this point, the command is still associated with the directory I started Neovim in, not the current working directory. This works the same way in regular Vim. It doesn't matter to me at this point if I previously had a buffer open to a certain file and this still exists or not. I still want fugitive to use the current working directory even in that case. I'm not saying I want fugitive to become working directory based in stead of buffer based. I'm saying I want it to use the last changed of the two, either I opened a buffer to a different file, or I changed the working directory.

Question: How do I get vim-fugitive to base its commands on the current working directory when the current buffer is not pointed at a file?

Further Thoughts: I know I could just start editing a file from that project, and then vim-fugitive will know which repository to work with. But that is precisely what I am trying to avoid. For me, one of the main appeals of Vim/Neovim is you can do micro-optimizations for everything about your workflow. I don't want to have to change to the correct directory and open a file from it before I can work with vim-fugitive because it is less steps to just change to that directory and then start working with it. I realize that I could accomplish this in the same number of steps by somehow opening the desired file without changing to that directory first, and then working with vim-fugitive, but that would be harder to accomplish and less useful for me. It is easier to edit the files of choice when the current working directory is the project root directory, and this makes working with that project much easier in lots of ways. Alternatively, I could make the command/alias I use to change to the directory of choice also open some kind of default/index file for that project in addition to changing to that directory, but that is not ideal for me. I would have to decide which file is the default/index file for each project. Having it automatically open that file would typically be mentally distracting and then I would have one more buffer I need to delete at some point if I don't want to work with it. Also, there would be times that I change to the directory of choice in a different way, such as navigating around with NERDTree.

10
  • Seeing your question is really precise, I think you will find more help on the repository of the plugin.
    – nobe4
    Jun 15, 2016 at 17:29
  • @nobe4 I thought bout using the issue tracker their, but sometimes people get upset when I use issue tracker as a help/question request. It is hard to know where to draw the line. This might be considered a feature request, unless there is a good way to make it do that already. Jun 15, 2016 at 17:31
  • 1
    I doubt Tim will help with this issue as this related to issue #327 and issue #45. Personally I would just update your :Cproj command to search for some kind default file. Jun 15, 2016 at 17:35
  • 2
    Fugitive.vim uses VimEnter autocmd to execute call fugitive#detect(getcwd()) as a special case which is noted in issue #45. Jun 15, 2016 at 17:55
  • 1
    @PeterRincker Issue 45 was the closest matching issue opened so I took up the discussion there. Also, myself and Tim Pope came to the conclusion that a good autocmd for the current directory changing is what is missing, so I opened a feature request for this: github.com/vim/vim/issues/868 I will post my current favorite workaround as an answer soon. Jun 15, 2016 at 20:56

2 Answers 2

2

Here is a hack/workaround I am using in my config file. It is not an ideal solution, but it is the best I can come up with until someone hopefully makes an autocmd event for the current working directory changing. I created a custom function that changes the current working directory. I try to use that function to change the directory as much as possible instead of the built in way. This relies in internal code from Fugitive, so it may stop working if the Fugitive code changes.

function! ChangeDirectoryCustom(dir_path)
    let before_dir= getcwd()
    execute 'cd '.fnameescape(a:dir_path)
    let after_dir= getcwd()
    if before_dir !=# after_dir
        " place custom current directory changed event handler code here
        " Make vim-fugitive use the new current directory repository if there is no current file
        let current_file_name= expand('%')
        if current_file_name == ''
            if exists('b:git_dir')
                unlet b:git_dir
            endif
            call FugitiveDetect(getcwd())
        endif
    endif
endfunction

After many years, I'm now realizing this approach doesn't make any sense. It doesn't change what git directory fugitive works with, it changes what git directory fugitive associates with the current buffer even though it could be for a file from a different/irrelevant directory/git repo.

1
  • Even though I no longer like this solution, I am leaving it here as its own answer because it has been up for so long, someone may wish to reference it again. Feb 4, 2023 at 21:38
0

One solution is to use the autocmd DirChanged to open a new buffer every time the directory changes. This way vim-fugitive will associate the new buffer with the new directory. As fugitive associates each buffer with a particular git directory, this is better than somehow forcing fugitive to consider the old buffer to be associated with the working directory you just changed to.

augroup all_autocmd_group
    autocmd DirChanged * call DirChangedHandler(v:event.cwd)
augroup END

function! DirChangedHandler(cwd)
    " This can be helpful because vim-fugitive is extremely buffer based. It
    " associates each buffer with its own git directory. So this can help if
    " you want fugitive to work with the directory you just changed to,
    " without doing something crazy like forcing it to associate the buffer you
    " already had open with the changed directory.
    enew
endfunction

If you also want to have a function that you use from custom commands to quickly change directories to common projects you work in as I hinted to in my question, you can, but it would basically just be helping you call :cd more safely:

function! DreamyChangeDirectory(dir_path)
    execute 'cd ' . fnameescape(a:dir_path)
endfunction

command! C1 call DreamyChangeDirectory("$HOME/hacking/Project1")
command! C2 call DreamyChangeDirectory("$HOME/hacking/Project2")

You would change "C1" and "C2" to C and of course the path would have to be corrected.

One potential drawback I can see with this approach is depending on your workflow or how/why the working directory changed, it might be undesirable to immediately open a new buffer when that happens. This is why I am doing this from the DirChangedHandler() function instead of directly on the autocmd DirChanged line. This gives you a place to put some additional customizations or checks in as needed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.