libdenote added (not used yet)

This commit is contained in:
2026-03-02 16:50:09 +01:00
parent c3ed08e42f
commit 2270ab9069
2 changed files with 268 additions and 7 deletions

195
autoload/libdenote.vim Normal file
View File

@@ -0,0 +1,195 @@
" 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. 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.
"
" @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
" @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)
let l:new = copy(a:fm)
let l:repl = libdenote#fm(a:ext, a:id ?? '', a:title ?? '', a:tags ?? [])
if a: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
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
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

@@ -15,6 +15,12 @@ CONTENTS *vim-denote* *denote*
3. Settings |denote-settings|
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*
@@ -245,4 +251,64 @@ dd Delete the selected entry.
{Visual}d Delete the visually selected entries.
==============================================================================
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 fmt_, 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}, {md_type})
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. Per default {tags} is set to the empty list
[]. Finally, {md_type} 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}, {ext}, {id}, {title}, {tags}, {md_type})
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 alters the title or tags associated with
the note. The arguments {title} and {tags} are optional. When set,
then {fm} is returned with the corresponding replaced lines.
vim:tw=78:sw=4:ts=8:noet:ft=help:norl: