This commit is contained in:
2026-03-03 23:03:34 +01:00
parent 2270ab9069
commit 66e032ee38
14 changed files with 338 additions and 356 deletions

View File

@@ -3,26 +3,11 @@ function denote#commands#load()
if exists('g:denote_commands_loaded') && g:denote_commands_loaded
return
endif
let g:denote_commands_loaded = 1
" Register user commands
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=+ DenoteGrep call denote#notes#grep(<q-args>) | lcl | lopen
command -nargs=1 DenoteNew call denote#notes#new(<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

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
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:tags=[]
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
return uniq(sort(l:tags))->join("\n")
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,10 +5,10 @@ endfunction
" Local helper function to retrieve and format the title.
function s:titleFromBuf(buf)
let l:name=denote#meta#noteTitleFromFile(bufname(a:buf))
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 - 1) .. 's', l:name) .. '…'
let l:name = libdenote#scheme_metadata(bufname(a:buf)).title
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 - 1) .. 's', l:name) .. '…'
endfunction
" Local helper function to truncate text with match at the given column as a
@@ -20,7 +20,7 @@ function s:formatText(text, col, width)
endfunction
" 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:l=[]
let l:width=winwidth(0) - g:denote_loc_title_columns - 19
@@ -37,15 +37,15 @@ function denote#loclist#textReferences(info)
endfunction
" 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:l=[]
for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
let l:e=l:items[idx]
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)
endfor
endfor
return l:l
endfunction
@@ -56,7 +56,7 @@ function denote#loclist#fill(title, files, Gfun)
" Set properties
call setloclist(0, [], 'r',
\ {'title': a:title,
\ 'quickfixtextfunc' : 'denote#loclist#textNoteList',
\ 'quickfixtextfunc' : 's:textNoteList',
\ 'context' : {'denote': 'list', 'gfun': a:Gfun}})
" Populate
let l:notes=[]
@@ -73,7 +73,7 @@ endfunction
function denote#loclist#setgrep(title, Gfun)
call setloclist(0, [], 'r',
\ {'title': a:title,
\ 'quickfixtextfunc' : 'denote#loclist#textReferences',
\ 'quickfixtextfunc' : 's:textReferences',
\ 'context' : {'denote': 'grep', 'gfun': a:Gfun}})
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

@@ -27,15 +27,15 @@ function denote#notes#grep(re)
endfunction
" This creates a new denote entry with the given title and of the given
" filetype. The title may be empty.
function denote#notes#new(title, ft=g:denote_new_ft)
" extension. The title may be empty.
function denote#notes#new(title, ext=g:denote_new_ext)
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
call denote#loclist#jumptowindow()
" Open file and write front matter
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))
endfunction
" Function to set the title of the selected entry
@@ -48,22 +48,25 @@ function denote#notes#settitle(linenr, title)
let l:item = l:items[a:linenr-1]
let l:bufnr = l:item['bufnr']
let l:filename = bufname(l:bufnr)
let l:noteid = denote#meta#noteIdFromFile(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:meta = libdenote#scheme_metadata(l:filename)
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
" file. Otherwise, we rename the file only.
if index(g:denote_note_file_extensions, l:ext) >= 0
" Handle front matter
call denote#frontmatter#setTitle(l:filename, a:title)
call bufload(l:filename)
let l:frontmatter = getbufline(l:filename,
\ 1, 1 + libdenote#fm_len(fnamemodify(l:filename, ':e')))
let l:frontmatter = libdenote#fm_alter(l:frontmatter, {'title': a:title})
call setbufline(l:filename, 1, l:frontmatter)
let curl=line('.')
call denote#loclist#jumptowindow()
exe l:bufnr .. 'buf'
exe 'silent buf ' .. l:bufnr
exe 'silent file ' .. l:newfilename
exe 'silent w'
exe 'lopen'
exe curl
if fnamemodify(l:filename, ':t') != fnamemodify(l:newfilename, ':t')
call delete(l:filename)
endif
@@ -87,32 +90,34 @@ function denote#notes#tagmod(line1, line2, tag, add)
let l:item = l:items[i-1]
let l:bufnr = l:item['bufnr']
let l:filename = bufname(l:bufnr)
let l:noteid = denote#meta#noteIdFromFile(l:filename)
let l:notetags = denote#meta#noteTagsFromFile(l:filename)
let l:idx = index(l:notetags, a:tag)
let l:meta = libdenote#scheme_metadata(l:filename)
let l:idx = index(l:meta.tags, a:tag)
if a:add
if l:idx >= 0
continue
endif
call add(l:notetags, a:tag)
call add(l:meta.tags, a:tag)
else
if l:idx == -1
continue
endif
call remove(l:notetags, l:idx)
call remove(l:meta.tags, l:idx)
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: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
" Handle front matter
call denote#frontmatter#setTags(l:filename, l:notetags)
call bufload(l:filename)
let l:frontmatter = getbufline(l:filename, 1, 1 + libdenote#fm_len(fnamemodify(l:filename, ':e')))
let l:frontmatter = libdenote#fm_alter(l:frontmatter, {'tags': l:meta.tags})
call setbufline(l:filename, 1, l:frontmatter)
let curl=line('.')
call denote#loclist#jumptowindow()
exe l:bufnr .. 'buf'
exe 'silent buf ' .. l:bufnr
exe 'silent file ' .. l:newfilename
exe 'silent w'
exe 'lopen'
exe curl
call delete(l:filename)
else
if fnamemodify(l:filename, ':t') == fnamemodify(l:newfilename, ':t')
@@ -134,20 +139,19 @@ function denote#notes#copy(origfile)
let l:title = fnamemodify(a:origfile, ':t:r')
let l:ext = fnamemodify(a:origfile, ':e')
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))
" Write front matter, if this is supported
if index(g:denote_note_file_extensions, l:ext) >= 0
call denote#loclist#jumptowindow()
exe 'edit ' .. 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))
exe 'w'
endif
endfunction
" Delete notes from denote directory
function denote#notes#rm(line1, line2, bang)
echom "bang set to:"..a:bang
let l:items = getloclist(0, {'items': 1})['items']
if empty(l:items)
return
@@ -156,7 +160,7 @@ function denote#notes#rm(line1, line2, bang)
let l:item = l:items[i-1]
let l:bufnr = l:item['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
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

View File

@@ -163,33 +163,47 @@ function libdenote#fm_gen(ext, id, title, tags=[], md_type='yaml')
endfunction
" Alter front matter
" This function returns the (modified) a:fm front matter. For any of the
" arguments a:id, a:title, and a:tags, if the argument is specified (for the
" tag, it may also be an empty list), then the value of the argument is used as
" a replacement in the input front matter a:fm.
" 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: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] or v:false:
" List of strings that specify the tags
" @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, ext, id='', title='', tags=v:false)
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(a:ext, a:id ?? '', a:title ?? '', a:tags ?? [])
if a:id
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 : [])
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 a:title
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 type(a:tags) == v:t_list
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
" Returns the length of a front matter (number of lines)
" @argument a:ext string: File extension
function libdenote#fm_len(ext)
return a:ext == 'org' ? 4
\ : a:ext == 'txt' ? 5
\ : 6
endfunction