I always appreciate a project-switching interface in my editor.
I didn't expect Kakoune, a barebones terminal editor, to have a built-in project switcher. But, after executing cd $project_dir; kak for the nth time, I started looking for a solution.
VS Code provides a project switcher through Open Recent action, bound to Ctrl + R on Linux. In my experience, any file or folder opened with VS Code's Open File or Open Folder dialogs show up here. So its a bit of a stretch to call it a project switcher if you frequently open files directly.
The following video snippet demonstrates VS Code's switcher:
JetBrains IDEs offer an unbounded Open Recent Project action, which opens the switcher at the tip of the cursor. though I use a FrameSwitcher plugin which performs the job better.
The following video snippet demonstrates WebStorm's switcher:
I identify two essential elements of a project switcher interface:
Kakoune's scripting primitives, combined with its philosophy to use shell scripting to extend itself, were adequate tools to build a simple project switcher.
I needed a place to persistently register opened project directories in Kakoune. I chose a plaintext projects file that sits besides kakoune's config file ~/.config/kak/kakrc. Each line in projects store a path to a project dir.
I wrote a Kakoune command :project-add that:
projects file
Here is the implementation:
define-command project-add \
-docstring "Add a project" \
-params 1 %{
nop %sh{ printf "%s\n" "$1" >> ~/.config/kak/projects }
change-directory %arg{1}
exec ":file-picker "
}
complete-command project-add file
I implemented a Kakoune command :project-pick that:
projects file using Kakoune's completion interface. The completion interface also sorts and excludes duplicate entries.
Here is the implementation:
define-command project-pick \
-docstring "Pick a project" \
-params 1 %{
change-directory %arg{1}
exec ":file-picker "
}
complete-command project-pick \
shell-script-candidates \
%{ cat ~/.config/kak/projects | sort | uniq }
Both :project-add and :project-pick commands lands the user on a file picker interface, which again builds on top of Kakoune's completion interface, so that they can start working right away on their project.
define-command file-picker \
-docstring "Pick a file from current directory" \
-params 1 %{ edit %arg{1} }
complete-command file-picker \
shell-script-candidates \
%{ git ls-files -c -o --exclude-standard }
Both the commands received their own keybindings for quick execution. Kakoune offers custom user modes which can act as namespaces to neatly tuck away related keybindings. I created a project user mode to do just that for my project switcher.
# Define project user mode
declare-user-mode project
map global project p ":project-pick " \
-docstring "Pick a project"
map global project a ":project-add " \
-docstring "Add a project"
# Now tie up project mode to the global user mode
# so that project mode becomes a submode to the
# global user mode
map global user p ":enter-user-mode project<ret>" \
-docstring "Project commands"
Now, Space + p + a triggers :project-add, while Space + p + p triggers :project-pick.
The video snippet below showcases the final result. I apologise for a cropped Kakoune's modeline in the video. I don't know why that happened, and I can't be bothered with making another video since the cropped modeline is still comprehensible.
I could implement guardrails like checking for existence of the projects file, or add a :project-delete command, but I'm satisfied with the current state. Any comments are welcome.