Neovim is grabbing more and more pieces of my workflow from other systems, and last two pieces are notes and tasks.
Org-mode plugins are great, but focused more on tasks.
However, one small thing almost made me adopt org-mode instead of VimWiki. That is ease of creating .org files anywhere, and that usually means in many of my project folders. I like to have all my project related stuff inside individual project folders, leave it or hide it from source control, backup, sync, ... I don't like scattered files.
Of course, VimWiki can have multiple wikis... just add them to your config. Ah, not my preferred way of managing any list. Who wants to edit wiki config manually every time there is a new project.
So this is what I did to automate it. Please note it requires Neovim (script is written in Lua), Linux (or better to say find
which I use for searching folders, and optionally Fzf (but this can be easily changed).
General idea
... is to use find
to search for a wiki folder recursively in projects_folder
. Then, result list is used to dynamically populate VimWiki global variable containing list of wikis (g:vimwiki_list
) and tell VimWiki to refresh the list. Now, VimWiki's <Leader>ws
is populated with project wikis! Wikis defined in config are there too, so you can still manually add wikis outside of projects folder if you want.
Using VimWiki's original wiki search feature
Minimal code for the above is:
-- configuration
local config = {
projectsFolder = '/home/your_user/work/', --full path without ~
maxDepth = 3,
ignoreFolders = { 'node_modules', '.git' },
rootWikiFolder = '_wiki',
wikiConfig = { syntax='markdown', ext='.md' }
}
-- store original vimwiki_list config, we will need it later
-- !!!make sure vimwiki plugin is loaded before running this!!!
if vim.g.vimwiki_list == nil then
error('VimWiki not loaded yet! make sure VimWiki is initialized before my-projects-wiki')
else
_G.vimwiki_list_orig = vim.fn.copy(vim.g.vimwiki_list) or {}
end
-- function to update g:vimwiki_list config item from list of subfolder names (append project wikis)
-- this way, orginal <Leader>ws will get new project wikis in the list and also keep ones from config
local function updateVimwikiList(folders)
local new_list = vim.fn.copy(vimwiki_list_orig)
for _, f in ipairs(folders) do
local item = {
path = config.projectsFolder..f,
syntax = config.wikiConfig.syntax,
ext = config.wikiConfig.ext
}
table.insert(new_list, item)
end
vim.g.vimwiki_list = new_list
vim.api.nvim_call_function('vimwiki#vars#init',{})
end
-- function to search project folders for root wiki folders (returns system list)
local function searchForWikis()
local command = 'find ' .. config.projectsFolder ..
' -maxdepth ' .. config.maxDepth
if #config.ignoreFolders > 0 then command = command .. " \\(" end
for _, f in ipairs(config.ignoreFolders) do
command = command .. " -path '*/"..f.."/*' -prune"
if next(config.ignoreFolders,_) == nil then
command = command .. " \\) -o"
else
command = command .. " -o"
end
end
command = command .. ' -type d -name ' .. config.rootWikiFolder
command = command .. ' -print | '
command = command .. ' sed s#' .. config.projectsFolder .. '##'
local list = vim.api.nvim_call_function('systemlist', {command})
return list
end
Now, you just have to call updateVimwikiList(searchForWikis())
somewhere to populate VimWiki with project wikis. There are so many options to do this. You can define a new command to do it manually, you can remap VimWiki's <Leader>ws
to execute it before displaying a list of wikis, or you can simply call it at the bottom of the script to refresh the list on Neovim start (downside of this method is that new _wiki folders will not be detected till you restart).
Extend it with Fzf fuzzy-find menu
However, I took a different approach. Script is really fast, so I don't mind running it every time I'm searching for wikis. Also, I use Fzf fuzzy-finder. So I decided to feed the list to Fzf for a nice fuzzy-find menu. This will replace default VimWiki's wiki select feature which is not very nice, especially for larger number of projects.
Here is the additional code, just below the above code:
-- wrapper for Vimwiki's goto_index() to bypass :VimWikiUISelect and use FZF instead
-- if wiki is passed to the function, index page is opened directly, bypassing FZF
function _G.ProjectWikiOpen(name)
-- show fzf wiki search if no wiki passed
if not name then
local wikis = searchForWikis()
updateVimwikiList(searchForWikis())
for _,f in ipairs(vimwiki_list_orig) do table.insert(wikis,f.path) end
local options = {
sink = function(selected) ProjectWikiOpen(selected) end,
source = wikis,
options = '--ansi --reverse --no-preview',
window = {
width = 0.3,
height = 0.6,
border = 'sharp'
}
}
vim.fn.call('fzf#run', {options})
else
for i, v in ipairs(vim.g.vimwiki_list) do
if v.path == name or v.path == config.projectsFolder..name then
vim.fn.call('vimwiki#base#goto_index',{i})
return
end
end
print("Error. Selected project wiki not found")
end
end
-- add commands
vim.api.nvim_command([[command! -nargs=? ProjectWikiOpen lua ProjectWikiOpen(<f-args>)]])
-- add keybindings
vim.api.nvim_set_keymap("n", "<Leader>wp", ":ProjectWikiOpen<CR>", { noremap=true })
So, a new :ProjectWikiOpen
command is registered and mapped to wp. I like this key combo better than original <Leader>ws
. This leaves you with a very simple workflow... just add _wiki
folder to any project and hit <Leader>wp
. Fzf menu will open and it will already be there. Just select it and VimWiki takes over.
todo
1) Finish Project/Session switcher script - For me, everything is a project and everything project related is in a project folder. That's why I also have a few scripts to easily manage/switch my projects in Neovim. Those integrate project sessions (using mksession
), automatic fuzzy-finder for projects (using find
to search for .git
folders to find roots), and Kitty terminal project launcher integrated in Dmenu which starts project environment using Kitty terminal: opens few Kitty windows and tabs with Neovim (session preloaded), LazyGit, few terminals, etc. It's almost done so hopefully I find the time to publish that too.
2) Finish synchronization with mobile phone - I want my wikis on the go too. This is almost done with Syncthing client on my laptop, server (Nextcloud) and mobile phone. Wikis are pushed and synchronized on all devices. Currently trying Obsidian Android app to read/manage wikis on the mobile side.
3) Integrate VimWiki tasks and taskwarrior (or similar)
Top comments (0)