feat: denote directory support
This commit is contained in:
@@ -1,5 +1,15 @@
|
||||
" Global configurations {{{1
|
||||
|
||||
" List of denote directories:
|
||||
if !exists('g:denote_directories')
|
||||
let g:denote_directories=[]
|
||||
endif
|
||||
call map(g:denote_directories, {_, d -> fnamemodify(d, ':p')})
|
||||
" If only one directory has been specified, use that as denote directory
|
||||
if ! empty(g:denote_directories)
|
||||
let t:denote_directory = g:denote_directories[0]
|
||||
endif
|
||||
|
||||
" Restrict basic operations to these files:
|
||||
if !exists('g:denote_note_file_extensions')
|
||||
let g:denote_note_file_extensions=['md', 'org', 'txt']
|
||||
@@ -30,10 +40,15 @@ endif
|
||||
" Put all notes of the given tag to the location list. The tag argument is
|
||||
" mandatory.
|
||||
function s:DenoteNotesByTag(tag)
|
||||
if !exists('t:denote_directory')
|
||||
echohl WarningMsg
|
||||
echom "Denote directory not specified, see |vim-denote|."
|
||||
return
|
||||
endif
|
||||
" Clear location list
|
||||
call denote#loclist#clear()
|
||||
" Find files
|
||||
let files = glob("*_" .. a:tag .. "*", 0, v:true)->filter('v:val =~ "_' .. a:tag .. '\\(==\\|@@\\|__\\|_\\|\\.\\)"')
|
||||
let files = glob(t:denote_directory .. "*_" .. a:tag .. "*", 0, v:true)->filter('v:val =~ "_' .. a:tag .. '\\(==\\|@@\\|__\\|_\\|\\.\\)"')
|
||||
" Populate location list
|
||||
let locTitle="Denote notes: " .. a:tag
|
||||
call setloclist(0, [], 'r',
|
||||
@@ -52,11 +67,16 @@ endfunction
|
||||
" Put all notes of the given tag to the location list. The search argument may be
|
||||
" empty. For improving search, white spaces are replaced by the * |wildcard|.
|
||||
function s:DenoteNotes(search)
|
||||
if !exists('t:denote_directory')
|
||||
echohl WarningMsg
|
||||
echom "Denote directory not specified, see |vim-denote|."
|
||||
return
|
||||
endif
|
||||
let s = substitute(" " .. a:search .. " ", " ", "*", "g")
|
||||
" Clear location list
|
||||
call denote#loclist#clear()
|
||||
" Find files
|
||||
let files = glob(s, 0, v:true)
|
||||
let files = glob(t:denote_directory .. s, 0, v:true)
|
||||
" Populate location list
|
||||
let locTitle="Denote notes search:" .. a:search
|
||||
call setloclist(0, [], 'r',
|
||||
@@ -75,11 +95,16 @@ endfunction
|
||||
" This function implements the similar functionality of :vimgrep, but for
|
||||
" denote notes.
|
||||
function s:DenoteGrep(search)
|
||||
if !exists('t:denote_directory')
|
||||
echohl WarningMsg
|
||||
echom "Denote directory not specified, see |vim-denote|."
|
||||
return
|
||||
endif
|
||||
" Clear location list
|
||||
call denote#loclist#clear()
|
||||
" Grep all greppable files
|
||||
let fpat=map(copy(g:denote_note_file_extensions), {_, e -> "*." .. e})->join()
|
||||
execute "lvimgrep " .. a:search .. " " .. fpat
|
||||
let fpat=map(copy(g:denote_note_file_extensions), {_, e -> t:denote_directory .. "*." .. e})->join()
|
||||
execute "silent! lvimgrep " .. a:search .. " " .. fpat
|
||||
" Adjust location list: set title and specify display function
|
||||
call setloclist(0, [], 'r',
|
||||
\ {'title': 'Denote grep: ' .. a:search,
|
||||
@@ -90,7 +115,7 @@ endfunction
|
||||
|
||||
" This function is used to autocomplete the tags in user commands.
|
||||
function s:tagList(ArgLead, cmdLine, CursorPos)
|
||||
let files=glob("*", 0, v:true)
|
||||
let files=glob(t:denote_directory .. "*", 0, v:true)
|
||||
let tags=[]
|
||||
for f in files
|
||||
let tags=extend(tags, denote#meta#noteTagsFromFile(f))
|
||||
@@ -101,22 +126,79 @@ endfunction
|
||||
" This creates a new denote entry with the given title and of the given
|
||||
" filetype. The title may be empty.
|
||||
function s:DenoteNew(title, ft=g:denote_new_ft)
|
||||
if !exists('t:denote_directory')
|
||||
echohl WarningMsg
|
||||
echom "Denote directory not specified, see |vim-denote|."
|
||||
return
|
||||
endif
|
||||
let identifier=denote#meta#identifier_generate()
|
||||
let fn=identifier .. '--' .. a:title
|
||||
\ ->tolower()
|
||||
\ ->substitute('[^[:fname:]]\|/', '-', 'g')
|
||||
\ ->substitute('-\+', '-', 'g')
|
||||
\ ->trim('-') .. '.' .. a:ft
|
||||
execute "edit " .. fn
|
||||
execute "edit " .. t:denote_directory .. fn
|
||||
call setline(1, denote#frontmatter#new(a:ft, identifier, a:title))
|
||||
endfunction
|
||||
|
||||
" Transform full path into canonical form WITH trailing '/'
|
||||
function s:canonicalFullPath(path)
|
||||
let parts = split(a:path, '/')
|
||||
let result = []
|
||||
for part in parts
|
||||
if part == '.' || part == ''
|
||||
continue
|
||||
elseif part == '..'
|
||||
if len(result) > 0
|
||||
call remove(result, len(result)-1)
|
||||
endif
|
||||
else
|
||||
call add(result, part)
|
||||
endif
|
||||
endfor
|
||||
return empty(result) ? '/' : '/' .. join(result, '/') .. '/'
|
||||
endfunction
|
||||
|
||||
" Compute the relative path from start to target. Both arguments are given as
|
||||
" full paths.
|
||||
function s:relativePath(start, target)
|
||||
let a = s:canonicalFullPath(a:start)
|
||||
let b = s:canonicalFullPath(a:target)
|
||||
" Simple cases first: both paths are the same, or the target is a subpath
|
||||
" from the start.
|
||||
if a == b[:strlen(a)-1]
|
||||
return b[strlen(a):]
|
||||
endif
|
||||
" Now, we need to go back. If the following match fails, then we need to go
|
||||
" back all the way
|
||||
let l = matchstrpos(a .. b, '^\(/.*\)/\zs.*/\ze\1')
|
||||
return l[1] == -1
|
||||
\ ? substitute(a[1:-2], '[^/]\+', '..', 'g') .. b
|
||||
\ : substitute(l[0], '[^/]\+', '..', 'g') .. b[l[1]:]
|
||||
endfunction
|
||||
|
||||
" Complete all paths to the denote directories. This functions completes the
|
||||
" paths to the configured directories, TODO: but also shows the directories
|
||||
" accessible from the current position.
|
||||
function s:denoteDirectoryList(ArgLead, CmdLine, CursorPos)
|
||||
let prefix = fnamemodify(a:ArgLead ?? '/', ':p')
|
||||
let res = []
|
||||
for dendir in g:denote_directories
|
||||
if prefix == dendir[:strlen(prefix)-1]
|
||||
call add(res, substitute(a:ArgLead .. '/' .. s:relativePath(prefix, dendir), '/\+', '/', 'g'))
|
||||
endif
|
||||
endfor
|
||||
" TODO: Append all subdirectories (default directory completion)
|
||||
return res->join("\n")
|
||||
endfunction
|
||||
|
||||
" Public commands and key mappings {{{1
|
||||
command -nargs=* Denote :call <SID>DenoteNotes(<q-args>)
|
||||
command -nargs=1 -complete=custom,<SID>tagList DenoteTag :call <SID>DenoteNotesByTag(<q-args>)
|
||||
command -nargs=+ DenoteGrep :call <SID>DenoteGrep(<q-args>)
|
||||
command -nargs=1 DenoteNew :call <SID>DenoteNew(<q-args>)
|
||||
command -nargs=1 -complete=custom,<SID>denoteDirectoryList Denote let t:denote_directory = fnamemodify(<q-args>, ':p')
|
||||
command -nargs=* DenoteSearch call <SID>DenoteNotes(<q-args>)
|
||||
command -nargs=1 -complete=custom,<SID>tagList DenoteTag call <SID>DenoteNotesByTag(<q-args>)
|
||||
command -nargs=+ DenoteGrep call <SID>DenoteGrep(<q-args>)
|
||||
command -nargs=1 DenoteNew call <SID>DenoteNew(<q-args>)
|
||||
|
||||
" Useful key mappings
|
||||
nnoremap <silent> <Plug>DenoteList :Denote<CR>:lclose<CR>:lopen<CR>:resize 20<CR>
|
||||
nnoremap <silent> <Plug>DenoteList :DenoteSearch<CR>:lclose<CR>:lopen<CR>:resize 20<CR>
|
||||
nnoremap <silent> <Plug>DenoteBackReferences :DenoteBackReferences<CR>:lclose<CR>:lopen<CR>:resize 20<CR>
|
||||
|
||||
Reference in New Issue
Block a user