Compare commits

...

7 Commits

15 changed files with 691 additions and 347 deletions

View File

@@ -23,15 +23,16 @@ Also, the present package aims at remaining flexible. Again, both
above-mentioned plugins require the denote note identifiers to follow the rigid above-mentioned plugins require the denote note identifiers to follow the rigid
format `YYYYMMDDTHHMMSS`. Per denote manual, however, the identify may be [any format `YYYYMMDDTHHMMSS`. Per denote manual, however, the identify may be [any
string](https://protesilaos.com/emacs/denote#h:3048f558-7d84-45d6-9ef2-53055483e801) string](https://protesilaos.com/emacs/denote#h:3048f558-7d84-45d6-9ef2-53055483e801)
(free of field delimiters, of course). (free of field delimiters, of course). This package offers great flexibility in
configuration (see `:help denote-settings`).
### Installation ### Installation
You may use any of your favorite plugin managers, or, manually place a copy of You may use any of your favorite plugin managers, or, manually place a copy of
this package in, e.g., `~/.vim/pack/tools/start`. For such a manual this package in, e.g., `~/.vim/pack/tools/start`. For such a manual
installation, you may want to run `:helptags installation, you may want to run `:helptags
~/.vim/pack/tools/start/vim-denote` to regenerate the help files. This allows ~/.vim/pack/tools/start/vim-denote/doc` to regenerate the help files. This
you to display the package documentation using `:help vim-denote` and similar allows you to display the package documentation using `:help vim-denote` and
commands. similar commands.
### Usage ### Usage
vim needs to know where your denote entries are stored. To do so, run the vim needs to know where your denote entries are stored. To do so, run the
@@ -54,7 +55,7 @@ completion](https://vimhelp.org/insert.txt.html#compl-omni) by pressing
`denote:<str>`, then the link is completed for denote entries that have `<str>` `denote:<str>`, then the link is completed for denote entries that have `<str>`
as part of the title. as part of the title.
_Browsing_ and searching notes:_ Browsing and searching is done using vim's _Browsing and searching notes:_ Browsing and searching is done using vim's
[location list](https://vimhelp.org/quickfix.txt.html#location-list). The [location list](https://vimhelp.org/quickfix.txt.html#location-list). The
benefit of doing so is that commands like `:lnext`, `:lprev` etc. become benefit of doing so is that commands like `:lnext`, `:lprev` etc. become
available. available.

View File

@@ -0,0 +1,87 @@
" Run this plugin only if the denote package has been setup
if !exists('g:denote_directory')
finish
endif
" ... and if this filetype is specified as denote-note file
if index(g:denote_note_file_extensions, expand('%:e')) == -1
finish
endif
" ... and if the file is in the denote directory
if g:denote_directory != expand('%:p:h')
finish
endif
" Load only once per buffer
if exists('b:loaded_denote_ftplugin_notes')
finish
endif
let b:loaded_denote_ftplugin_notes = 1
" Link completion
" This works by using the functions s:column(), s:suggestions(),
" s:complete_link(), and by setting 'omnifunc'.
" Find the column where the completion starts. This must be between 1 and
" col('.'). Denote links are of this form: `denote:<identifier>`.
function DenoteNoteCompleteLinkColumn()
" Get the substring from the start of the line until col('.')
let l:x = max([1, col('.')-2])
let l:l = getline('.')[:l:x]
" Take the shortest prefix of a denote link. This may be any of
" \<d$
" ..
" \<denote:$
" \<denote:\f$
" \<denote:\f\f$
" etc.
let l:res = l:l->matchstrpos('\<denote:\f*$')
if l:res[1] >= 0
return l:res[1]
endif
let l:res = l:l->matchstrpos('\<d\f*$')
if l:res[1] == -1
return -3
endif
return 'denote:' =~ '^' .. l:res[0] ? l:res[1] : -3
endfunction
" Return completion items given by the base
function DenoteNoteCompleteLinkSuggestions(base)
let l:prefix = a:base->matchstr('^denote:\zs.*$')
let l:flist = glob(g:denote_directory .. '/' .. (l:prefix ? '*' .. l:prefix .. '*' : '*'), 0, v:true)
let l:res = []
for filename in l:flist
let l:meta = libdenote#scheme_metadata(filename)
if l:meta.id == v:false || (l:meta.id !~ '^' .. l:prefix && l:meta.title !~ l:prefix)
continue
endif
let l:meta.title = l:meta.title ?? '(no title)'
call add(l:res, {
\ 'word' : 'denote:' .. l:meta.id,
\ 'abbr' : l:meta.title,
\ 'menu' : l:meta.tags->join(', ')
\ })
endfor
return l:res
endfunction
" Completion function for denote links
function DenoteNoteCompleteLink(findstart, base)
return a:findstart == 1 ? DenoteNoteCompleteLinkColumn() : DenoteNoteCompleteLinkSuggestions(a:base)
endfunction
setlocal omnifunc=DenoteNoteCompleteLink
" Denote links are of the form 'denote:<note id>'; we require the column.
setlocal isfname+=:
" Set the function to resolve the filename under the cursor (see |gf|).
function DenoteNoteGotoFile()
return v:fname !~ '^denote:'
\ ? v:fname
\ : libdenote#scheme_find(g:denote_directory, v:fname[7:]) ?? v:fname
endfunction
setlocal includeexpr=DenoteNoteGotoFile()
" Back references command
let b:meta = libdenote#scheme_metadata(expand('%:t'))
exe 'command! -buffer DenoteBackReferences DenoteGrep /\<denote:' .. b:meta.id .. '\>/gj'

1
after/ftplugin/org.vim Symbolic link
View File

@@ -0,0 +1 @@
markdown.vim

60
after/ftplugin/qf.vim Normal file
View File

@@ -0,0 +1,60 @@
" Run this plugin only if the denote package has been setup
if !exists('g:denote_directory')
finish
endif
" Load only once per buffer
if exists('b:loaded_denote_ftplugin_qf')
finish
endif
let b:loaded_denote_ftplugin_qf = 1
" This will be called for every location and quickfix, when data is loaded into
" the list. This does nothing for such lists that are note 'denote' lists.
let b:context = getloclist(0, {'context': 1})['context']
if type(b:context) != v:t_dict || !has_key(b:context, 'denote')
" Clear settings
set spell<
nmapclear <buffer>
finish
endif
setlocal nospell
nnoremap <buffer> q :lclose<CR>
" Reload capability
if has_key(b:context, 'gfun')
function DenoteLocListReload()
let curl = line('.')
let Gfun = b:context['gfun']
call denote#loclist#jumptowindow()
exe 'lclose'
call Gfun()
exe 'lwindow'
exe curl
endfunction
nnoremap <buffer> <silent> r :call DenoteLocListReload()<CR>
endif
" Denote-list specific configuration
if b:context['denote'] == 'list'
function OpenDenoteEntry()
let l:item = getloclist(0, {'items': 1})['items'][line('.')-1]
let l:bufnr = l:item['bufnr']
let l:filename = bufname(l:bufnr)
call system('open ' .. shellescape(l:filename))
endfunction
command! -nargs=1 -range -buffer DenoteSetTitle :call denote#notes#settitle(<line1>, <q-args>) | :normal r
command! -nargs=1 -range -buffer -complete=custom,denote#completion#tags DenoteTagAdd :call denote#notes#tagmod(<line1>, <line2>, <q-args>, v:true) | :normal r
command! -nargs=1 -range -buffer -complete=custom,denote#completion#tags DenoteTagRm :call denote#notes#tagmod(<line1>, <line2>, <q-args>, v:false) | :normal r
command! -range -buffer -bang DenoteDelete :call denote#notes#rm(<line1>, <line2>, <bang>0) | :normal r
nnoremap <buffer> C :DenoteSetTitle
nnoremap <buffer> + :DenoteTagAdd
nnoremap <buffer> - :DenoteTagRm
nnoremap <buffer> dd :DenoteDelete<CR>r
nnoremap <buffer> o :call OpenDenoteEntry()<CR>
xnoremap <buffer> + :DenoteTagAdd
xnoremap <buffer> - :DenoteTagRm
xnoremap <buffer> d :DenoteDelete<CR>
endif

1
after/ftplugin/text.vim Symbolic link
View File

@@ -0,0 +1 @@
markdown.vim

View File

@@ -3,26 +3,11 @@ function denote#commands#load()
if exists('g:denote_commands_loaded') && g:denote_commands_loaded if exists('g:denote_commands_loaded') && g:denote_commands_loaded
return return
endif endif
let g:denote_commands_loaded = 1
" Register user commands " Register user commands
command -nargs=* Denote call denote#notes#list(<q-args>) | lcl | lopen command -nargs=* Denote call denote#notes#list(<q-args>) | lcl | lopen
command -nargs=1 -complete=custom,denote#completion#tags DenoteByTag call denote#notes#bytag(<q-args>) | lcl | lopen command -nargs=1 -complete=custom,denote#completion#tags DenoteByTag call denote#notes#bytag(<q-args>) | lcl | lopen
command -nargs=+ DenoteGrep call denote#notes#grep(<q-args>) | lcl | lopen command -nargs=+ DenoteGrep call denote#notes#grep(<q-args>) | lcl | lopen
command -nargs=1 DenoteNew call denote#notes#new(<q-args>) command -nargs=1 DenoteNew call denote#notes#new(<q-args>)
command -nargs=1 -complete=file DenoteCopy call denote#notes#copy(<q-args>) command -nargs=1 -complete=file DenoteCopy call denote#notes#copy(<q-args>)
" Register auto commands
autocmd BufReadPost quickfix call denote#ft#qf()
let l:aupat = map(copy(g:denote_note_file_extensions), {_, v -> '*.' .. v})->join(',')
exe 'autocmd BufReadPost,BufNewFile ' .. l:aupat .. ' call denote#ft#denote()'
" Useful key mappings
" 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>
let g:denote_commands_loaded = v:true
endfunction
" Public commands for the denote-list location list
function denote#commands#loadll()
command DenoteReload call denote#
" command -nargs=1 DenoteSetTitle call denote#notes#settitle(<q-args>)
endfunction endfunction

View File

@@ -1,59 +1,9 @@
" Find the column where the completion starts. This must be between 1 and
" col('.'). Denote links are of this form: `denote:<identifier>`.
function s:column()
" Get the substring from the start of the line until col('.')
let l:l = getline('.')[:col('.')]
" Take the shortest prefix of a denote link. This may be any of
" \<d$
" ..
" \<denote:$
" \<denote:\f$
" \<denote:\f\f$
" etc.
let l:res = l:l->matchstrpos('\<denote:\f*$')
if l:res[1] >= 0
return l:res[1]
endif
let l:res = l:l->matchstrpos('\<d\f*$')
if l:res[1] == -1
return -3
endif
return 'denote:' =~ '^' .. l:res[0] ? l:res[1] : -3
endfunction
" Return completion items given by the base
function s:suggestions(base)
let l:prefix = a:base->matchstr('^denote:\zs.*$')
let l:flist = glob(g:denote_directory .. '/' .. (l:prefix ? '*' .. l:prefix .. '*' : '*'), 0, v:true)
let l:res = []
for filename in l:flist
let l:noteId = denote#meta#noteIdFromFile(filename)
let l:noteTitle = denote#meta#noteTitleFromFile(filename)
if l:noteId == v:false || (l:noteId !~ '^' .. l:prefix && l:noteTitle !~ l:prefix)
continue
endif
let l:noteTitle = l:noteTitle ?? '(no title)'
let l:noteTags = denote#meta#noteTagsFromFile(filename)
call add(l:res, {
\ 'word' : 'denote:' .. l:noteId,
\ 'abbr' : l:noteTitle,
\ 'menu' : l:noteTags->join(', ')
\ })
endfor
return l:res
endfunction
" Completion function for denote links
function denote#completion#get(findstart, base)
return a:findstart == 1 ? s:column() : s:suggestions(a:base)
endfunction
" Completion function for denote tags " Completion function for denote tags
function denote#completion#tags(ArgLead, cmdLine, CursorPos) function denote#completion#tags(ArgLead, CmdLine, CursorPos)
let l:files=glob(g:denote_directory .. '/*', 0, v:true) let l:files=glob(g:denote_directory .. '/*', 0, v:true)
let l:tags=[] let l:tags=[]
for f in l:files for f in l:files
let l:tags=extend(l:tags, denote#meta#noteTagsFromFile(f)) let l:tags=extend(l:tags, libdenote#scheme_metadata(f).tags)
endfor endfor
return uniq(sort(l:tags))->join("\n") return uniq(sort(l:tags))->join("\n")
endfunction endfunction

View File

@@ -1,93 +0,0 @@
" Functions to manipulate and query the front matter
" Helper function to put string in double quotes, and remove inside double
" quotes.
function s:escapeDQ(s)
return '"' .. substitute(a:s, '"', '', 'g') .. '"'
endfunction
" Create front matter (yaml)
function s:md_new_yaml(id, title, tags)
return [
\ '---',
\ 'title: ' .. s:escapeDQ(a:title),
\ 'date: ' .. strftime('%FT%T%z'),
\ 'tags: [' .. map(copy(a:tags), {_, t -> s:escapeDQ(t) })->join(', ') .. ']',
\ 'identifier: ' .. s:escapeDQ(a:id),
\ '---'
\ ]
endfunction
" Create front matter (toml)
function s:md_new_toml(id, title, tags)
return [
\ '+++',
\ 'title ' .. s:escapeDQ(a:title),
\ 'date ' .. strftime('%FT%T%z'),
\ 'tags [' .. map(copy(a:tags), {_, t -> s:escapeDQ(t) })->join(', ') .. ']',
\ 'identifier ' .. s:escapeDQ(a:id),
\ '+++'
\ ]
endfunction
" Create front matter (plain)
function s:plain_new(id, title, tags)
return [
\ 'title: ' .. a:title,
\ 'date: ' .. strftime('%F'),
\ 'tags: ' .. a:tags->join(' '),
\ 'identifier: ' .. a:id,
\ '---------------------------',
\ ]
endfunction
" Create front matter (org)
function s:org_new(id, title, tags)
return [
\ '#+title: ' .. a:title,
\ '#+date: [' .. strftime('%F %a %R') .. ']',
\ '#+filetags: :' .. map(copy(a:tags), {_, t -> substitute(t, ':', '', 'g') })->join(':') .. ':',
\ '#+identifier: ' .. a:id,
\ ]
endfunction
" Create front matter
function denote#frontmatter#new(ft, id, title, tags=[])
return a:ft == 'org' ? s:org_new(a:id, a:title, a:tags)
\ : a:ft == 'plain' ? s:plain_new(a:id, a:title, a:tags)
\ : g:denote_fm_md_type == 'toml' ? s:md_new_toml(a:id, a:title, a:tags)
\ : s:md_new_yaml(a:id, a:title, a:tags)
endfunction
" Return the frontmatter of the specified file (as a list)
function s:getFrontmatter(filename)
let l:ft = fnamemodify(a:filename, ':e')
let l:cnt = l:ft == 'org' ? 4
\ : l:ft == 'txt' ? 5
\ : 6
call bufload(a:filename)
return getbufline(a:filename, 1, 1 + l:cnt)
endfunction
" Get title from front matter
function denote#frontmatter#setTitle(filename, title)
" Retrieve front matter (number of lines depends on ft), and replace title
let l:frontmatter = s:getFrontmatter(a:filename)
call map(l:frontmatter, { _, v -> substitute(v, '^#\?+\?title:\?\s*"\?\zs.\{-\}\ze\"\?$', a:title, '')})
call setbufline(a:filename, 1, l:frontmatter)
endfunction
" Set tags in front matter
function denote#frontmatter#setTags(filename, tags)
let l:frontmatter = s:getFrontmatter(a:filename)
let l:tagline = denote#frontmatter#new(fnamemodify(a:filename, ':t'), '', '', a:tags)
\ ->filter('v:val =~ "^\\(#+file\\)\\?tags"')[0]
call map(l:frontmatter, { _, v -> v =~ '^\(#+file\)\?tags' ? l:tagline : v})
call setbufline(a:filename, 1, l:frontmatter)
endfunction
" Prepend frontmatter to file
function denote#frontmatter#prepend(filename, id, title, tags=[])
let l:frontmatter = denote#frontmatter#new(fnamemodify(a:filename, ':t'), a:id, a:title, a:tags)
call appendbufline(a:filename, 0, l:frontmatter)
endfunction

View File

@@ -1,57 +0,0 @@
" Go to file command |gf| adjustments
" This resolves denote links. The function has access to the variable v:fname,
" which corresponds to the filename under the cursor.
function s:gotofile()
return v:fname !~ '^denote:'
\ ? v:fname
\ : denote#meta#fileFromNoteId(v:fname[7:]) ?? v:fname
endfunction
" Denote note specifics
function denote#ft#denote()
if expand('%:p:h') != g:denote_directory
return
endif
" Link completion
setlocal omnifunc=denote#completion#get
" Denote links are of the form 'denote:<note id>'; we require the column.
setlocal isfname+=:
" Set the function to resolve the filename under the cursor (see |gf|).
setlocal includeexpr=s:gotofile()
" Back references command
let l:noteid = denote#meta#noteIdFromFile(expand('%:t'))
exe 'command! -buffer DenoteBackReferences DenoteGrep /\<denote:' .. l:noteid .. '\>/gj'
endfunction
" Location-list specifics
"
" This will be called for every location and quickfix, when data is loaded into
" the list. This does nothing for such lists that are note 'denote' lists.
function denote#ft#qf()
let l:context = getloclist(0, {'context': 1})['context']
if type(l:context) != v:t_dict || !has_key(l:context, 'denote')
" Clear settings
set spell<
nmapclear <buffer>
return
endif
setlocal nospell
nnoremap <buffer> q :lclose<CR>
if has_key(l:context, 'gfun')
nnoremap <buffer> <silent> r :call denote#loclist#reload()<CR>
endif
" Denote-list specific configuration
if l:context['denote'] == 'list'
command! -nargs=1 -range -buffer DenoteSetTitle :call denote#notes#settitle(<line1>, <q-args>)
command! -nargs=1 -range -buffer -complete=custom,denote#completion#tags DenoteTagAdd :call denote#notes#tagmod(<line1>, <line2>, <q-args>, v:true)
command! -nargs=1 -range -buffer -complete=custom,denote#completion#tags DenoteTagRm :call denote#notes#tagmod(<line1>, <line2>, <q-args>, v:false)
command! -range -buffer -bang DenoteDelete :call denote#notes#rm(<line1>, <line2>, <bang>0)
nnoremap <buffer> C :DenoteSetTitle
nnoremap <buffer> + :DenoteTagAdd
nnoremap <buffer> - :DenoteTagRm
nnoremap <buffer> dd :DenoteDelete<CR>r
xnoremap <buffer> + :DenoteTagAdd
xnoremap <buffer> - :DenoteTagRm
xnoremap <buffer> d :DenoteDelete<CR>
endif
endfunction

View File

@@ -5,7 +5,7 @@ endfunction
" Local helper function to retrieve and format the title. " Local helper function to retrieve and format the title.
function s:titleFromBuf(buf) function s:titleFromBuf(buf)
let l:name=denote#meta#noteTitleFromFile(bufname(a:buf)) let l:name = libdenote#scheme_metadata(bufname(a:buf)).title
return strchars(l:name, 1) <= g:denote_loc_title_columns return strchars(l:name, 1) <= g:denote_loc_title_columns
\ ? printf('%' .. g:denote_loc_title_columns .. 's', l:name) \ ? printf('%' .. g:denote_loc_title_columns .. 's', l:name)
\ : printf('%.' .. (g:denote_loc_title_columns - 1) .. 's', l:name) .. '…' \ : printf('%.' .. (g:denote_loc_title_columns - 1) .. 's', l:name) .. '…'
@@ -20,7 +20,7 @@ function s:formatText(text, col, width)
endfunction endfunction
" This modifies the location list for pretty display. " This modifies the location list for pretty display.
function denote#loclist#textReferences(info) function s:textReferences(info)
let l:items=getloclist(a:info.winid) let l:items=getloclist(a:info.winid)
let l:l=[] let l:l=[]
let l:width=winwidth(0) - g:denote_loc_title_columns - 19 let l:width=winwidth(0) - g:denote_loc_title_columns - 19
@@ -37,13 +37,13 @@ function denote#loclist#textReferences(info)
endfunction endfunction
" This modifies the location list for pretty display. " This modifies the location list for pretty display.
function denote#loclist#textNoteList(info) function s:textNoteList(info)
let l:items=getloclist(a:info.winid) let l:items=getloclist(a:info.winid)
let l:l=[] let l:l=[]
for idx in range(a:info.start_idx - 1, a:info.end_idx - 1) for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
let l:e=l:items[idx] let l:e=l:items[idx]
let l:name=s:titleFromBuf(l:e.bufnr) let l:name=s:titleFromBuf(l:e.bufnr)
let l:ntags=denote#meta#noteTagsFromFile(bufname(l:e.bufnr))->join() let l:ntags = libdenote#scheme_metadata(bufname(l:e.bufnr)).tags->join()
call add(l:l, l:name .. ' | ' .. l:ntags) call add(l:l, l:name .. ' | ' .. l:ntags)
endfor endfor
return l:l return l:l
@@ -56,7 +56,7 @@ function denote#loclist#fill(title, files, Gfun)
" Set properties " Set properties
call setloclist(0, [], 'r', call setloclist(0, [], 'r',
\ {'title': a:title, \ {'title': a:title,
\ 'quickfixtextfunc' : 'denote#loclist#textNoteList', \ 'quickfixtextfunc' : 's:textNoteList',
\ 'context' : {'denote': 'list', 'gfun': a:Gfun}}) \ 'context' : {'denote': 'list', 'gfun': a:Gfun}})
" Populate " Populate
let l:notes=[] let l:notes=[]
@@ -73,7 +73,7 @@ endfunction
function denote#loclist#setgrep(title, Gfun) function denote#loclist#setgrep(title, Gfun)
call setloclist(0, [], 'r', call setloclist(0, [], 'r',
\ {'title': a:title, \ {'title': a:title,
\ 'quickfixtextfunc' : 'denote#loclist#textReferences', \ 'quickfixtextfunc' : 's:textReferences',
\ 'context' : {'denote': 'grep', 'gfun': a:Gfun}}) \ 'context' : {'denote': 'grep', 'gfun': a:Gfun}})
endfunction endfunction

View File

@@ -1,72 +0,0 @@
" Return the filename of the note with id `noteId`. If the file is note found,
" then v:false is returned.
function denote#meta#fileFromNoteId(noteId)
" According to the file-naming scheme, the note id is prefixed with '@@'. If
" the note id appears at the beginning of the filename, then this prefix is
" optional. There may exist another field (such as the signature, title, or
" keywords field) after the note id. These are prefixed with '==', '--', or
" '__'. If the note id is the last field, then the id is followed by the file
" extension, e.g., '.md'.
" (A) First, we get all files that contain the note id as substring.
" (B) Then we ensure that the note id is followed by another field or by the
" file extension.
let l:files = glob(g:denote_directory .. '/*' .. a:noteId .. '*', 0, v:true)
\ ->filter('v:val->split("/")[-1] =~ "' .. a:noteId .. '\\(==\\|--\\|__\\|\\.\\)"')
\ ->filter('v:val->split("/")[-1] =~ "^' .. a:noteId .. '\\|@@' .. a:noteId .. '"')
return empty(l:files) ? v:false : l:files[0]
endfunction
" Return the note id from the filename. On failure, v:false is returned.
function denote#meta#noteIdFromFile(file)
return a:file->fnamemodify(':t')->matchstr('@@\zs.\{-\}\ze\(==\|--\|__\|\..\)')
\ ?? a:file->fnamemodify(':t')->matchstr('^.\{-\}\ze\(==\|--\|__\|\..\)')
\ ?? v:false
endfunction
" Return the note title from the filename.
function denote#meta#noteTitleFromFile(file)
return a:file->fnamemodify(':t')
\ ->matchstr('--\zs.\{-\}\ze\(==\|@@\|__\|\..\)')
\ ->substitute('-', ' ', 'g')
endfunction
" Return the note tags from the filename as a list.
function denote#meta#noteTagsFromFile(file)
return a:file->fnamemodify(':t')
\ ->matchstr('__\zs.\{-\}\ze\(==\|@@\|--\|\..\)')
\ ->split('_')
endfunction
" Return the note signature from the filename.
function denote#meta#noteSignatureFromFile(file)
return a:file->fnamemodify(':t')
\ ->matchstr('==\zs.\{-\}\ze\(==\|@@\|__\|\..\)')
endfunction
" Identifier creation
function denote#meta#identifier_generate()
return exists('*strftime')
\ ? strftime('%Y%m%dT%H%M%S')
\ : rand()
endfunction
" This function removes illegal characters in parts of the filename.
function s:santizefnpart(part)
return a:part->tolower()
\ ->substitute('[^[:alnum:]]', '-', 'g')
\ ->substitute('-\+', '-', 'g')
\ ->substitute('_\+', '_', 'g')
\ ->substitute('=\+', '=', 'g')
\ ->substitute('@\+', '@', 'g')
\ ->trim('-_@=')
endfunction
" Function that returns the filename give all metadata. The filename is
" returned with the path to the denote directory.
function denote#meta#filename(ext, identifier, title='', tags=[], signature='')
let l:f = g:denote_directory .. '/' .. s:santizefnpart(a:identifier)
let l:f ..= len(a:signature) > 0 ? ('==' .. s:santizefnpart(a:signature)) : ''
let l:f ..= len(a:title) > 0 ? ('--' .. s:santizefnpart(a:title)) : ''
let l:f ..= len(a:tags) > 0 ? ('__' .. map(copy(a:tags), {_, v -> s:santizefnpart(v)})->join('_')) : ''
return l:f .. '.' .. a:ext
endfunction

View File

@@ -1,3 +1,90 @@
" Script-local function that retrieves the front-matter of a file.
function s:getfrontmatter(filename)
let l:ext = fnamemodify(a:filename, ':e')
if index(g:denote_note_file_extensions, l:ext) == -1
return []
endif
" The following code aims to be as robust as possible. This is achieved by
" parsing each file-type (extension) separately. A common signature of the
" front matter is the empty line that separates the front matter from the
" rest of the text. As fail safe, we assume that the front matter is shorter
" than l:max lines.
" Markdown:
" - The first line is either '---' or '+++'.
" - The last line is the same as the first line.
" - All entries (apart first and last lines) are of the form '^\w\+:\?'.
" - Contains the entry '^identifier'.
" Org:
" - All lines start with '^#+\w\+:\s*'.
" - Contains the entry '^#identifier:
" Text:
" - The last line is '^-\+$.
" - All lines start with '^\w\+:\s*.
" - Contains the entry '^identifier:'
"
" Note: getbufline() returns an empty list if no more lines are available.
let l:max = 50
call bufload(a:filename)
let l:fmt = []
let l:lnr = 1
let l:identifier_seen = v:false
if l:ext == 'md'
let l:separator = getbufline(a:filename, l:lnr)[0]
if index(['---', '+++'], l:separator) == -1
return []
endif
call add(l:fmt, l:separator)
let l:lnr += 1
while l:lnr < l:max
let l:line = getbufline(a:filename, l:lnr)[0]
if l:line == l:separator
call add(l:fmt, l:line)
return l:identifier_seen && getbufline(a:filename, l:lnr + 1)[0] == '' ? l:fmt : []
endif
if l:line !~ '^\w\+:\?'
return []
endif
call add(l:fmt, l:line)
if l:line =~ '^identifier'
let l:identifier_seen = v:true
endif
let l:lnr += 1
endwhile
elseif l:ext == 'org'
while l:lnr < l:max
let l:line = getbufline(a:filename, l:lnr)[0]
if l:line == ''
return l:identifier_seen ? l:fmt : []
endif
if l:line !~ '^#+\w\+:'
return []
endif
call add(l:fmt, l:line)
if l:line =~ '^#+identifier:'
let l:identifier_seen = v:true
endif
let l:lnr += 1
endwhile
elseif l:ext == 'txt'
while l:lnr < l:max
let l:line = getbufline(a:filename, l:lnr)[0]
if l:line =~ '^-\+$'
call add(l:fmt, l:line)
return l:identifier_seen && getbufline(a:filename, l:lnr + 1)[0] == '' ? l:fmt : []
endif
if l:line !~ '^\w\+:'
return []
endif
call add(l:fmt, l:line)
if l:line =~ '^identifier:'
let l:identifier_seen = v:true
endif
let l:lnr += 1
endwhile
endif
return []
endfunction
" Put all notes of the given tag to the location list. The search argument may be " 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|. " empty. For improving search, white spaces are replaced by the * |wildcard|.
function denote#notes#list(search) function denote#notes#list(search)
@@ -27,15 +114,15 @@ function denote#notes#grep(re)
endfunction endfunction
" This creates a new denote entry with the given title and of the given " This creates a new denote entry with the given title and of the given
" filetype. The title may be empty. " extension. The title may be empty.
function denote#notes#new(title, ft=g:denote_new_ft) function denote#notes#new(title, ext=g:denote_new_ext)
let l:identifier = g:Denote_identifier_fun() let l:identifier = g:Denote_identifier_fun()
let l:fn = denote#meta#filename(a:ft, l:identifier, a:title) let l:fn = g:denote_directory .. '/' .. libdenote#scheme_filename(a:ext, l:identifier, a:title)
" Jump to window this location list belongs to " Jump to window this location list belongs to
call denote#loclist#jumptowindow() call denote#loclist#jumptowindow()
" Open file and write front matter " Open file and write front matter
exe 'edit ' l:fn exe 'edit ' l:fn
call setline(1, denote#frontmatter#new(a:ft, l:identifier, a:title)) call setline(1, libdenote#fm_gen(a:ext, l:identifier, a:title, [], g:denote_fm_md_type))
endfunction endfunction
" Function to set the title of the selected entry " Function to set the title of the selected entry
@@ -48,22 +135,32 @@ function denote#notes#settitle(linenr, title)
let l:item = l:items[a:linenr-1] let l:item = l:items[a:linenr-1]
let l:bufnr = l:item['bufnr'] let l:bufnr = l:item['bufnr']
let l:filename = bufname(l:bufnr) let l:filename = bufname(l:bufnr)
let l:noteid = denote#meta#noteIdFromFile(l:filename) let l:meta = libdenote#scheme_metadata(l:filename)
let l:notetags = denote#meta#noteTagsFromFile(l:filename)
let l:notesignature = denote#meta#noteSignatureFromFile(l:filename)
let l:oldtitle = denote#meta#noteTitleFromFile(l:filename)
let l:ext = fnamemodify(l:filename, ':e') let l:ext = fnamemodify(l:filename, ':e')
let l:newfilename = denote#meta#filename(l:ext, l:noteid, a:title, l:notetags, l:notesignature) let l:newfilename = g:denote_directory .. '/' .. libdenote#scheme_filename(l:ext, l:meta.id, a:title, l:meta.tags, l:meta.sig)
" If this note has a front matter, we rewrite the front matter and rename the " If this note has a front matter, we rewrite the front matter and rename the
" file. Otherwise, we rename the file only. " file. Otherwise, we rename the file only.
if index(g:denote_note_file_extensions, l:ext) >= 0 if index(g:denote_note_file_extensions, l:ext) >= 0
" Handle front matter " Handle front matter
call denote#frontmatter#setTitle(l:filename, a:title) call bufload(l:filename)
let l:frontmatter = s:getfrontmatter(l:filename)
if empty(l:frontmatter)
" Write fresh front matter
let l:frontmatter = libdenote#fm_gen(l:ext, l:meta.id, l:meta.title, l:meta.tags, g:denote_fm_md_type)
call add(l:frontmatter, '')
call appendbufline(l:filename, 0, l:frontmatter)
else
" Modify front matter
let l:frontmatter = libdenote#fm_alter(l:frontmatter, {'title': a:title})
call setbufline(l:filename, 1, l:frontmatter)
endif
let curl = line('.')
call denote#loclist#jumptowindow() call denote#loclist#jumptowindow()
exe l:bufnr .. 'buf' exe 'silent buf ' .. l:bufnr
exe 'silent file ' .. l:newfilename exe 'silent file ' .. l:newfilename
exe 'silent w' exe 'silent w'
exe 'lopen' exe 'lopen'
exe curl
if fnamemodify(l:filename, ':t') != fnamemodify(l:newfilename, ':t') if fnamemodify(l:filename, ':t') != fnamemodify(l:newfilename, ':t')
call delete(l:filename) call delete(l:filename)
endif endif
@@ -87,32 +184,42 @@ function denote#notes#tagmod(line1, line2, tag, add)
let l:item = l:items[i-1] let l:item = l:items[i-1]
let l:bufnr = l:item['bufnr'] let l:bufnr = l:item['bufnr']
let l:filename = bufname(l:bufnr) let l:filename = bufname(l:bufnr)
let l:noteid = denote#meta#noteIdFromFile(l:filename) let l:meta = libdenote#scheme_metadata(l:filename)
let l:notetags = denote#meta#noteTagsFromFile(l:filename) let l:idx = index(l:meta.tags, a:tag)
let l:idx = index(l:notetags, a:tag)
if a:add if a:add
if l:idx >= 0 if l:idx >= 0
continue continue
endif endif
call add(l:notetags, a:tag) call add(l:meta.tags, a:tag)
else else
if l:idx == -1 if l:idx == -1
continue continue
endif endif
call remove(l:notetags, l:idx) call remove(l:meta.tags, l:idx)
endif endif
let l:notesignature = denote#meta#noteSignatureFromFile(l:filename)
let l:title = denote#meta#noteTitleFromFile(l:filename)
let l:ext = fnamemodify(l:filename, ':e') let l:ext = fnamemodify(l:filename, ':e')
let l:newfilename = denote#meta#filename(l:ext, l:noteid, l:title, l:notetags, l:notesignature) let l:newfilename = g:denote_directory .. '/' .. libdenote#scheme_filename(l:ext, l:meta.id, l:meta.title, l:meta.tags, l:meta.sig)
if index(g:denote_note_file_extensions, l:ext) >= 0 if index(g:denote_note_file_extensions, l:ext) >= 0
" Handle front matter " Handle front matter
call denote#frontmatter#setTags(l:filename, l:notetags) call bufload(l:filename)
let l:frontmatter = s:getfrontmatter(l:filename)
if empty(l:frontmatter)
" Write fresh front matter
let l:frontmatter = libdenote#fm_gen(l:ext, l:meta.id, l:meta.title, l:meta.tags, g:denote_fm_md_type)
call add(l:frontmatter, '')
call appendbufline(l:filename, 0, l:frontmatter)
else
" Modify front matter
let l:frontmatter = libdenote#fm_alter(l:frontmatter, {'tags': l:meta.tags})
call setbufline(l:filename, 1, l:frontmatter)
endif
let curl = line('.')
call denote#loclist#jumptowindow() call denote#loclist#jumptowindow()
exe l:bufnr .. 'buf' exe 'silent buf ' .. l:bufnr
exe 'silent file ' .. l:newfilename exe 'silent file ' .. l:newfilename
exe 'silent w' exe 'silent w'
exe 'lopen' exe 'lopen'
exe curl
call delete(l:filename) call delete(l:filename)
else else
if fnamemodify(l:filename, ':t') == fnamemodify(l:newfilename, ':t') if fnamemodify(l:filename, ':t') == fnamemodify(l:newfilename, ':t')
@@ -134,20 +241,19 @@ function denote#notes#copy(origfile)
let l:title = fnamemodify(a:origfile, ':t:r') let l:title = fnamemodify(a:origfile, ':t:r')
let l:ext = fnamemodify(a:origfile, ':e') let l:ext = fnamemodify(a:origfile, ':e')
let l:identifier = g:Denote_identifier_fun() let l:identifier = g:Denote_identifier_fun()
let l:filename = denote#meta#filename(l:ext, l:identifier, l:title) let l:filename = g:denote_directory .. '/' .. libdenote#scheme_filename(l:ext, l:identifier, l:title)
call system('cp ' .. shellescape(a:origfile) .. ' ' .. shellescape(l:filename)) call system('cp ' .. shellescape(a:origfile) .. ' ' .. shellescape(l:filename))
" Write front matter, if this is supported " Write front matter, if this is supported
if index(g:denote_note_file_extensions, l:ext) >= 0 if index(g:denote_note_file_extensions, l:ext) >= 0
call denote#loclist#jumptowindow() call denote#loclist#jumptowindow()
exe 'edit ' .. l:filename exe 'edit ' .. fnameescape(l:filename)
call denote#frontmatter#prepend(l:filename, l:identifier, l:title) call appendbufline(l:filename, 0, libdenote#fm_gen(l:ext, l:identifier, l:title), [], g:denote_fm_md_type)
exe 'w' exe 'w'
endif endif
endfunction endfunction
" Delete notes from denote directory " Delete notes from denote directory
function denote#notes#rm(line1, line2, bang) function denote#notes#rm(line1, line2, bang)
echom "bang set to:"..a:bang
let l:items = getloclist(0, {'items': 1})['items'] let l:items = getloclist(0, {'items': 1})['items']
if empty(l:items) if empty(l:items)
return return
@@ -156,7 +262,7 @@ function denote#notes#rm(line1, line2, bang)
let l:item = l:items[i-1] let l:item = l:items[i-1]
let l:bufnr = l:item['bufnr'] let l:bufnr = l:item['bufnr']
let l:filename = bufname(l:bufnr) let l:filename = bufname(l:bufnr)
let l:title = denote#meta#noteTitleFromFile(l:filename) let l:title = libdenote#scheme_metadata(l:filename).title
if a:bang == v:false if a:bang == v:false
let l:answer = confirm('Are you sure you want to delete the note "' .. l:title .. '"?', "&Yes\n&No\n", 2, 'Question') let l:answer = confirm('Are you sure you want to delete the note "' .. l:title .. '"?', "&Yes\n&No\n", 2, 'Question')
if l:answer != 1 if l:answer != 1

202
autoload/libdenote.vim Normal file
View File

@@ -0,0 +1,202 @@
" libdenote plugin for vim
" This plugin describes basic denote functions. Each one of these functions
" deals wither with the file-naming scheme (prefixed with scheme_), or with the
" front matter (prefixed with fm_). All functions are pure, i.e., have no side
" affects.
"
" FILE-NAMING SCHEME {{{1
"
" Script-local functions {{{2
"
" This function removes illegal characters in parts of the filename.
function s:santizefnpart(part)
return a:part->tolower()
\ ->substitute('[^[:alnum:]]', '-', 'g')
\ ->substitute('-\+', '-', 'g')
\ ->substitute('_\+', '_', 'g')
\ ->substitute('=\+', '=', 'g')
\ ->substitute('@\+', '@', 'g')
\ ->trim('-_@=')
endfunction
" API {{{2
" Identifier creation
" This unction generates a fresh denote identifier
function libdenote#scheme_idgen()
return exists('*strftime')
\ ? strftime('%Y%m%dT%H%M%S')
\ : rand()
endfunction
" Generate file name
" This function returns the Filename given all components in the file-naming
" scheme
"
" @argument a:ext string: File extension
" @argument a:id string: Identifier of denote entry
" @argument a:title string: Title of denote entry
" @argument a:tags list[string]: List of strings that specify the tags
" @argument a:sig string: Signature string of denote entry
function libdenote#scheme_filename(ext, identifier, title='', tags=[], sig='')
let l:f = s:santizefnpart(a:identifier)
let l:f ..= len(a:sig) > 0 ? ('==' .. s:santizefnpart(a:sig)) : ''
let l:f ..= len(a:title) > 0 ? ('--' .. s:santizefnpart(a:title)) : ''
let l:f ..= len(a:tags) > 0 ? ('__' .. map(copy(a:tags), {_, v -> s:santizefnpart(v)})->join('_')) : ''
return l:f .. '.' .. a:ext
endfunction
" Retrieve metadata from file name
" This function returns a dict with the entries 'id', 'title', 'tags', and
" 'sig.' The value type of 'tags' is a list, the other entries hold strings.
"
" @argument a:filename string: Filename or path to file
function libdenote#scheme_metadata(filename)
return {
\ 'id': a:filename->fnamemodify(':t')->matchstr('@@\zs.\{-\}\ze\(==\|--\|__\|\..\)')
\ ?? a:filename->fnamemodify(':t')->matchstr('^.\{-\}\ze\(==\|--\|__\|\..\)'),
\ 'title': a:filename->fnamemodify(':t')->matchstr('--\zs.\{-\}\ze\(==\|@@\|__\|\..\)')
\ ->substitute('-', ' ', 'g'),
\ 'tags': a:filename->fnamemodify(':t')->matchstr('__\zs.\{-\}\ze\(==\|@@\|--\|\..\)')
\ ->split('_'),
\ 'sig': a:filename->fnamemodify(':t')->matchstr('==\zs.\{-\}\ze\(==\|@@\|__\|\..\)')
\}
endfunction
" Get path to file from denote identifier
" This function returns the path to the file the note corresponds to, if it
" exists, and v:false otherwise.
"
" @argument a:dir string: Path to denote directory
" @argument a:id string: Identifier of denote entry
function libdenote#scheme_find(dir, id)
" According to the file-naming scheme, the note id is prefixed with '@@'. If
" the note id appears at the beginning of the file name, then this prefix is
" optional. There may exist another field (such as the signature, title, or
" keywords field) after the note id. These are prefixed with '==', '--', or
" '__'. If the note id is the last field, then the id is followed by the file
" extension, e.g., '.md'.
" (A) First, we get all files that contain the note id as substring.
" (B) Then we ensure that the note id is followed by another field or by the
" file extension.
let l:files = glob(a:dir .. '/*' .. a:id .. '*', 0, v:true)
\ ->filter('v:val->split("/")[-1] =~ "' .. a:id .. '\\(==\\|--\\|__\\|\\.\\)"')
\ ->filter('v:val->split("/")[-1] =~ "^' .. a:id .. '\\|@@' .. a:id .. '"')
return empty(l:files) ? v:false : l:files[0]
endfunction
" FRONT-MATTER HANDLING {{{1
"
" Script-local functions {{{2
"
" Put string in double quotes, and remove inside double quotes.
function s:escapeDQ(s)
return '"' .. substitute(a:s, '"', '', 'g') .. '"'
endfunction
" Create front matter (yaml)
function s:md_new_yaml(id, title, tags)
return [
\ '---',
\ 'title: ' .. s:escapeDQ(a:title),
\ 'date: ' .. strftime('%FT%T%z'),
\ 'tags: [' .. map(copy(a:tags), {_, t -> s:escapeDQ(t) })->join(', ') .. ']',
\ 'identifier: ' .. s:escapeDQ(a:id),
\ '---'
\ ]
endfunction
" Create front matter (toml)
function s:md_new_toml(id, title, tags)
return [
\ '+++',
\ 'title ' .. s:escapeDQ(a:title),
\ 'date ' .. strftime('%FT%T%z'),
\ 'tags [' .. map(copy(a:tags), {_, t -> s:escapeDQ(t) })->join(', ') .. ']',
\ 'identifier ' .. s:escapeDQ(a:id),
\ '+++'
\ ]
endfunction
" Create front matter (plain)
function s:plain_new(id, title, tags)
return [
\ 'title: ' .. a:title,
\ 'date: ' .. strftime('%F'),
\ 'tags: ' .. a:tags->join(' '),
\ 'identifier: ' .. a:id,
\ '---------------------------',
\ ]
endfunction
" Create front matter (org)
function s:org_new(id, title, tags)
return [
\ '#+title: ' .. a:title,
\ '#+date: [' .. strftime('%F %a %R') .. ']',
\ '#+filetags: :' .. map(copy(a:tags), {_, t -> substitute(t, ':', '', 'g') })->join(':') .. ':',
\ '#+identifier: ' .. a:id,
\ ]
endfunction
" API {{{2
" Create front matter
" This function generates a front matter. It may use the global variable
" g:denote_fm_md_type.
"
" @argument a:ext string: Generate front matter for a file of this
" extension
" @argument a:id string: Identifier of the denote note
" @argument a:title string: Title of the denote note
" @argument a:tags list[string]: List of strings that specify the tags
" @argument a:md_type string: Any of 'yaml' (default) or 'toml', for
" markdown front matter
" @return: List of strings with a line-per item that describes the front matter
function libdenote#fm_gen(ext, id, title, tags, md_type='yaml')
return a:ext == 'org' ? s:org_new(a:id, a:title, a:tags)
\ : a:ext == 'txt' ? s:plain_new(a:id, a:title, a:tags)
\ : a:md_type == 'toml' ? s:md_new_toml(a:id, a:title, a:tags)
\ : s:md_new_yaml(a:id, a:title, a:tags)
endfunction
" Alter front matter
" This function returns the (modified) a:fm front matter. The argument a:mod
" of type dict specifies the fields to be updated. If a:mod contains the key
" 'date', then the date field will be updated. If it contains the key 'id',
" then the identifier will be updated with the value a:mod.id. Similar for the
" title (key 'title'), and the tags (key 'tags'). For the tags, the value type
" is a list of strings.
"
" @argument a:fm list[string] List of strings describes a frontmatter
" @argument a:mod dict Dictionary to control updates
" @return: List of strings with a line-per item that describes the front matter
function libdenote#fm_alter(fm, mod)
let l:md_type = a:fm[0] == '+++' ? 'toml' : 'yaml'
let l:ext = { n -> n == 4 ? 'org' : n == 5 ? 'txt' : 'md'}(len(a:fm))
let l:new = copy(a:fm)
let l:repl = libdenote#fm_gen(l:ext,
\ has_key(a:mod, 'id') ? a:mod.id : '',
\ has_key(a:mod, 'title') ? a:mod.title : '',
\ has_key(a:mod, 'tags') ? a:mod.tags : [],
\ g:denote_fm_md_type)
if has_key(a:mod, 'date')
let l:ididx = indexof(l:repl, 'v:val =~ "^\\(#+\\)\\?date"')
call map(l:new, {_, v -> v =~ "^\\(#+\\)\\?date" ? l:repl[l:ididx] : v})
endif
if has_key(a:mod, 'id')
let l:ididx = indexof(l:repl, 'v:val =~ "^\\(#+\\)\\?identifier"')
call map(l:new, {_, v -> v =~ "^\\(#+\\)\\?identifier" ? l:repl[l:ididx] : v})
endif
if has_key(a:mod, 'title')
let l:titleidx = indexof(l:repl, 'v:val =~ "^\\(#+\\)\\?title"')
call map(l:new, {_, v -> v =~ "^\\(#+\\)\\?title" ? l:repl[l:titleidx] : v})
endif
if has_key(a:mod, 'tags')
let l:tagsidx = indexof(l:repl, 'v:val =~ "^\\(#+file\\)\\?tags"')
call map(l:new, {_, v -> v =~ "^\\(#+file\\)\\?tags" ? l:repl[l:tagsidx] : v})
endif
return l:new
endfunction

View File

@@ -1,8 +1,14 @@
*denote.txt* Handling denote entries the vim way *denote.txt* Handling denote entries the vim way
Last change: 2026 Feb 28 Last change: 2026 Mar 4
This is the documentation for the denote plugin. This is the documentation for the denote package. This package also introduces
the |libdenote| plugin in the file autoload/libdenote.vim, which may be of
independent interest. If this package is loaded automatically, but you prefer
to opt-out, then add this line to your vimrc:
>
let g:loaded_denote = 1
<
============================================================================== ==============================================================================
CONTENTS *vim-denote* *denote* CONTENTS *vim-denote* *denote*
@@ -15,6 +21,12 @@ CONTENTS *vim-denote* *denote*
3. Settings |denote-settings| 3. Settings |denote-settings|
4. Keys |denote-keys| 4. Keys |denote-keys|
Appendices
A. The libdenote plugin |libdenote|
A.1 File-naming functions |libdentoe-filenaming|
A.2 Front-matter functions |libdenote-frontmatter|
B. Package API |denote-api|
============================================================================== ==============================================================================
INTRODUCTION *denote-intro* INTRODUCTION *denote-intro*
@@ -41,6 +53,7 @@ prefix of a denote link. This completion also works with titles: by invoking
omni completion after typing "denote:foo", denote links are completed for omni completion after typing "denote:foo", denote links are completed for
entries containing "foo" in the title. entries containing "foo" in the title.
============================================================================== ==============================================================================
COMMANDS *denote-commands* COMMANDS *denote-commands*
@@ -244,5 +257,165 @@ C Change the title of the selected entry.
dd Delete the selected entry. dd Delete the selected entry.
{Visual}d Delete the visually selected entries. {Visual}d Delete the visually selected entries.
*denote-list-o*
o Open the file using the system "open" command.
==============================================================================
APPENDIX A - THE LIBDENOTE PLUGIN *libdenote*
The present package has as constituent the libdenote plugin for basic
denote-centered operations. That plugin is given by the file
autoload/libdenote.vim. Each function in this plugin is pure, i.e., produces
no side effects. There are two classes of functions: functions concerning the
file-naming scheme (prefixed with scheme_, see |libdenote-filenaming|) and
functions concerning the front matter (prefixed with fm_, see
|libdenote-frontmatter|).
*libdenote-filenaming*
File-naming functions~
*libdenote#scheme_idgen()*
libdenote#scheme_idgen()
This function generates a new identifier. If the function |strftime()|
is available, than strftime(%Y%m%dT%H%M%S) is used, otherwise a random
identifier is generated using |rand()|.
*libdenote#scheme_filename()*
libdenote#scheme_filename({ext}, {id}, {title}, {tags}, {sig})
With this, the file name of the denote entry with the given metadata
is returned. The parameter {ext} describes the extension of the file
is is one of 'md', 'txt', or 'org'. The parameter {id} is the denote
identifier, possibly generated via |libdenote#scheme_idgen()|. The
{title} parameter is optional and describes the title of the note. By
default, it is set to the empty string ''. The {tags} parameter is
optional as well, is a list of tags associated to the note. The
default value is the empty list []. Also, the {sig} parameter is
optional, and used to describe the signature of the entry.
*libdenote#scheme_metadata()*
libdenote#scheme_metadata({filename})
This function returns the metadata of the file given by {filename}.
This parameter may describe the path to the file, or the tail only.
The returned |dict| has the keys 'id' for the identifier, 'title' for
the title, 'tags' for the list of tags, and 'sig' for the signature.
*libdenote-frontmatter*
Front-matter functions~
*libdenote#fm_gen()*
libdenote#fm_gen({ext}, {id}, {title}, {tags}, {mdtype})
This function returns the list of lines for the front matter that
stores the given metadata. The paramter {ext} is the extension of the
file, the parameter {id} the identifier, the parameter {title}, the
title of the note, and {tags} the optional parameter as a list of tags
associated to the note. The argument {mdtype} descries the format to
be used in markdown. For markdown files (extension 'md'), two formats
are possible: 'yaml' and 'toml'. The former format is used per
default.
*libdenote#fm_alter()*
libdenote#fm_alter({fm}, {mod})
Similar to |libdenote#fm_gen()|, this function returns a list
containing the lines of a front matter. In contrast to the above
function, this functions takes a front matter {fm} as base (again,
given as list of lines), and updates the fields specified by the
|dict| {mod}. If {mod} contains the key "date", then the date string
will be updated. If {mod} contains the key "id", then the identifier
will be updated with the value a:mod.id. Similarly, the keys "title"
and "tags" are used to update the title and tag list of the front
matter.
==============================================================================
APPENDIX B - PACKAGE API *denote-api*
Here, we list and briefly describe all functions that come with this package.
The aim of providing this information is to keep vim-denote hackable.
*denote#commands#load()*
denote#commands#load()
This function initializes the user commands (see, |denote-commands|)
that are globally available.
*denote#completion#tags()*
denote#completion#tags({ArgLead}, {CmdLine}, {CursorPos})
This is the autocompletion function for tag arguments in the user
commands |:DenoteByTag|, |:DenoteTagAdd|, and |:DenoteTagRm|.
*denote#loclist#clear()*
denote#loclist#clear()
With this, the location list is cleared.
*denote#loclist*fill()*
denote#loclist*fill({title}, {files}, {Gfun})
This function populates the location list with denote entries. The
{title} argument specifies the title of the location list. The {files}
argument is a list of filenames of denote entries. Finally, the {Gfun}
argument is a Funcref to the function that reloads the location list —
this is the function (with all arguments set) that invoked this call
to |denote#loclist#fill()|.
*denote#loclist#setgrep()*
denote#loclist#setgrep({title}, {Gfun})
This function makes the location list fit for showing the result of
|:DenoteGrep|. The {title} and {Gfun} arguments are as in
|denote#loclist#fill()|.
*denote#loclist#reload()*
denote#loclist#reload()
This function reruns the location-list generating function (see {Gfun}
in |denote#loclist#fill()|.
*denote#loclist#jumptowindow()*
denote#loclist#jumptowindow()
With this, the cursor is moved from the location list to the window
the location list belongs to.
*denote#notes#list()*
denote#notes#list({search})
This function searches for denote entries that contain {search} in the
path, and displays the results in the location list. The command
|:Denote| is bound to this function.
*denote#notes#bytag()*
denote#notes#bytag({tag})
This is similar to |denote#notes#list()|, but only entries with the
tag {tag} are put to the location list. This is used by the command
|:DenoteByTag|.
*denote#notes#grep()*
denote#notes#grep({re})
This is the function used by |:DenoteGrep| and |:DenoteBackReferences|
to search for patterns within the denote files.
*denote#notes#new()*
denote#notes#new({title}, {ext})
This function is used by |:DenoteNew|. Here, {title} is the title of
the new note, and {ext} the file extension. This second argument is
optional and has the default value |g:denote_new_ext|.
*denote#notes#settitle()*
denote#notes#settitle({linenr}, {title})
With this, the title of the entry on line {linenr} of the location
list is set to {title}. This is used by |:DenoteSetTitle|.
*denote#notes#tagmod()*
denote#notes#tagmod({line1}, {line2}, {tag}, {add})
This function modifies the tags of the denote entries from line
{line1} to line {line2} of the location list. In each of these
entries, the tag {tag} is added if {add} is 1, and removed if {add} is
0.
*denote#notes#copy()*
denote#notes#copy({origfile})
This copies the file {origfile} to the denote directory, and renames
the copy to make it denote compatible. This function is used by
|:DenoteCopy|.
*denote#notes#rm()*
denote#notes#rm({line1}, {line2}, {bang})
With this, the files that correspond to the entries from line {line1}
to line {line2} of the location list are deleted. If the {bang} is set
to 1, then no confirmation will be asked. Otherwise, the user is asked
to confirm every deletion. This function is used by |:DenoteDelete|.
vim:tw=78:sw=4:ts=8:noet:ft=help:norl: vim:tw=78:sw=4:ts=8:noet:ft=help:norl:

View File

@@ -1,14 +1,14 @@
" Global configurations " Global configurations
if exists('g:loaded_denote')
finish
endif
let g:loaded_denote = 1
" List of denote directories " List of denote directories
if !exists('g:denote_directories') if !exists('g:denote_directories')
let g:denote_directories = [] let g:denote_directories = []
endif endif
call map(g:denote_directories, {_, d -> fnamemodify(d, ':p')}) call map(g:denote_directories, {_, d -> fnamemodify(d, ':p')})
" If only one directory has been specified, use that as denote directory
" if len(g:denote_directories) == 1
" let g:denote_directory = g:denote_directories[0]
" endif
" Restrict basic operations to these files " Restrict basic operations to these files
if !exists('g:denote_note_file_extensions') if !exists('g:denote_note_file_extensions')
@@ -21,8 +21,8 @@ if !exists('g:denote_loc_title_columns')
endif endif
" Default filetype for newly created denote entries " Default filetype for newly created denote entries
if !exists('g:denote_new_ft') if !exists('g:denote_new_ext')
let g:denote_new_ft = 'md' let g:denote_new_ext = 'md'
endif endif
" Default front-matter type for markdown notes, may be one of 'yaml' or 'toml' " Default front-matter type for markdown notes, may be one of 'yaml' or 'toml'
@@ -33,7 +33,7 @@ endif
" By using the following global variable, the user may specify a custom " By using the following global variable, the user may specify a custom
" function for creating identifiers. " function for creating identifiers.
if !exists('g:Denote_identifier_fun') if !exists('g:Denote_identifier_fun')
let g:Denote_identifier_fun = function('denote#meta#identifier_generate') let g:Denote_identifier_fun = function('libdenote#scheme_idgen')
endif endif
" Transform full path into canonical form WITH trailing '/' " Transform full path into canonical form WITH trailing '/'