mawww / kakoune

mawww's experiment for a better code editor
http://kakoune.org
The Unlicense
9.7k stars 705 forks source link

Add EnterDirectory hook #5185

Closed PJungkamp closed 3 days ago

PJungkamp commented 4 weeks ago

We currently don't have any way to detect a change to the current working directory.

I like to base my kakoune session name on my working directory and I'd like for it to be able to change when I use change-directory in kakoune... This doesn't currently seem to be possible.

I've started considering this after the recently added SessionRename and ClientRename hooks that allowed more complex plugins to tolerate name changes.

PJungkamp commented 3 weeks ago

I think we should pass the result of parse_filename(target) as the filter string, so that hooks can be added to trigger on specific directories.

I thought about this hook as a way to update, do housekeeping on some background tasks that might need to be reconfigured if they depend on e.g. configuration files from the current working directory, I didn't consider any use case for filtering.


I can imagine several different approaches to this hook:

  1. DirectoryChanged: no parameters, just an event so one can reparse e.g. config files searched in the current working directory.

  2. EnterDirectory <path>: the new path as the parameter.

    • Should that path be absolute? Probably?
    • The name suggests it to be triggered on startup. Should it? Before or after KakBegin?
  3. ChangeDirectory <path>: the new path as the parameter.

    • I'd assume a Change/Rename hook to provide both the old and new directory, see ModeChange/{Session/Client}Renamed. It isn't possible to choose a reliable separator for arbitraty paths.
    • This runs on changes but not initially.
  4. ChangeDirectory <old name>/<new name>: the old and new direcotory basename separated by a slash as the parameter.

    • This is more inline with the other Rename/Change hook. although the used separator differs.

I've chosen the first option since I found it to be straight forward and sufficient for my use case. But if there were to be a parameter I'm not sure which of the other approaches I'd like best.

@mawww What's your preference here?

PJungkamp commented 3 weeks ago

A simple example would be loading a local .kakrc.local file on directory change in addition to startup.

try %{ source .kakrc.local }
hook global DirectoryChanged .* %{
  try %{ source .kakrc.local }
}
hook global EnterDirectory .* %{
  try %{ source .kakrc.local }
}

Another interesting use case is adding configuration for specific directories comparable to [includeIf "gitdir:~/Documents/home/"] in git.


An additional consideration is that the new path in the hook param should match the output of pwd or $PWD in a shell environment because the only way to query the current directory otherwise is through shell expansion.

mawww commented 2 weeks ago

EnterDirectory <absolute path> sounds good and yes, it should be emitted on startup as well (either after or just before KakBegin). I dont think we need a separate ChangeDirectory hook, just re-exec EnterDirectory whenever we change the current directory.

PJungkamp commented 2 weeks ago

I reworked it to EnterDirectory with the new real_path as the hook parameter.

EDIT: I had to fix the documentation to mention that the hook runs on startup.


Here's a little snippet to use the current working directory as the session name or, if it's part of a git tree, use the git directories name. I don't know whether I'll use it in my actual configuration, as the rename-session is executed after kakrc has been sourced. Plugins relying on a stable session name will break (most plugins that spawn background processes, e.g. kak-lsp and kak-tree-sitter).

hook global EnterDirectory .*/(?<name>[^/]*)/? %{ evaluate-commands %sh{
    if toplevel="$(git rev-parse --show-toplevel 2> /dev/null)" && [ "$toplevel" != / ]; then
        name="$(basename "$toplevel")"
    else
        name="$kak_hook_param_capture_name"
    fi

    if [ -n "$name" ] && [ "$name" != "$kak_session" ]; then
        printf "%s\n" "rename-session %/$name/"
    fi
}}
mawww commented 1 week ago

Thanks, the last missing piece is a copyright waiver commit from you as I do not think I have one from you yet. See the CONTRIBUTING file.

PJungkamp commented 1 week ago

Thanks, the last missing piece is a copyright waiver commit from you as I do not think I have one from you yet. See the CONTRIBUTING file.

Done!