" 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 " empty. For improving search, white spaces are replaced by the * |wildcard|. function denote#notes#list(search) let l:s = substitute(' ' .. a:search .. ' ', ' ', '*', 'g') let l:files = glob(g:denote_directory .. '/' .. l:s, 0, v:true) let l:title = 'Denote notes search:' .. a:search let l:Gfun = function('denote#notes#list', [a:search]) call denote#loclist#fill(l:title, l:files, l:Gfun) endfunction " Put all notes of the given tag to the location list. The tag argument is " mandatory. function denote#notes#bytag(tag) let l:files = glob(g:denote_directory .. '/*_' .. a:tag .. '*', 0, v:true)->filter('v:val->split("/")[-1] =~ "_' .. a:tag .. '\\(==\\|@@\\|__\\|_\\|\\.\\)"') let l:title = 'Denote notes: ' .. a:tag let l:Gfun = function('denote#notes#bytag', [a:tag]) call denote#loclist#fill(l:title, l:files, l:Gfun) endfunction " Search in denote notes function denote#notes#grep(re) let l:title = 'Grep results for: ' .. a:re let l:fpat=map(copy(g:denote_note_file_extensions), {_, e -> g:denote_directory .. '/*.' .. e})->join() exe 'silent! lvimgrep ' .. a:re .. ' ' .. l:fpat let l:Gfun = function('denote#notes#grep', [a:re]) call denote#loclist#setgrep(l:title, l:Gfun) endfunction " This creates a new denote entry with the given title and of the given " 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 = 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, libdenote#fm_gen(a:ext, l:identifier, a:title, [], g:denote_fm_md_type)) endfunction " Function to set the title of the selected entry function denote#notes#settitle(linenr, title) " Get file first! let l:items = getloclist(0, {'items': 1})['items'] if empty(l:items) return endif let l:item = l:items[a:linenr-1] let l:bufnr = l:item['bufnr'] let l:filename = bufname(l:bufnr) let l:meta = libdenote#scheme_metadata(l:filename) let l:ext = fnamemodify(l:filename, ':e') 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 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() 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 else if fnamemodify(l:filename, ':t') == fnamemodify(l:newfilename, ':t') return endif call rename(l:filename, l:newfilename) endif endfunction " Function to add or remove a tag to the selected entries. The last argument " a:add, is set to v:true to add, and v:false to remove. function denote#notes#tagmod(line1, line2, tag, add) " Get file first! let l:items = getloclist(0, {'items': 1})['items'] if empty(l:items) return endif for i in range(a:line1, a:line2) let l:item = l:items[i-1] let l:bufnr = l:item['bufnr'] let l:filename = bufname(l:bufnr) 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:meta.tags, a:tag) else if l:idx == -1 continue endif call remove(l:meta.tags, l:idx) endif let l:ext = fnamemodify(l:filename, ':e') 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 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() 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') return endif call rename(l:filename, l:newfilename) endif endfor endfunction " Add file to denote directory function denote#notes#copy(origfile) if !filereadable(a:origfile) echohl WarningMsg echom 'Cannot copy specified file to denote directory.' return endif " Derive title from 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 = 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 ' .. fnameescape(l:filename) call appendbufline(l:filename, 0, libdenote#fm_gen(l:ext, l:identifier, l:title), [], g:denote_fm_md_type) exe 'w' endif endfunction " Delete notes from denote directory function denote#notes#rm(line1, line2, bang) let l:items = getloclist(0, {'items': 1})['items'] if empty(l:items) return endif for i in range(a:line1, a:line2) let l:item = l:items[i-1] let l:bufnr = l:item['bufnr'] let l:filename = bufname(l:bufnr) 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 continue endif endif " Wipe buffer, if it exists if bufexists(l:filename) exe 'silent bwipe ' .. fnameescape(l:filename) endif " Delete file call delete(l:filename) endfor endfunction