280 lines
9.2 KiB
VimL
280 lines
9.2 KiB
VimL
" 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 ' .. 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
|