Compare commits
26 Commits
6d8f8c720b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 270be048dc | |||
| e1c3ea09da | |||
| 5df2b79938 | |||
| 320bc0b6c0 | |||
| 5b7825d358 | |||
| 66e032ee38 | |||
| 2270ab9069 | |||
| c3ed08e42f | |||
| 040d6397cb | |||
| 0f0a86d1f9 | |||
| 1afd45b91a | |||
| dfc15def2b | |||
| 4fb6e977ff | |||
| 5d631a5506 | |||
| 55bbeecb0a | |||
| 553cf41c96 | |||
| 864b678b9e | |||
| 7a82fe32db | |||
| d6bc3cbb04 | |||
| 2015c0e32c | |||
| ba939661c7 | |||
| e8ff0daf16 | |||
| caf21ab060 | |||
| d4ad71543d | |||
| ac75a8c679 | |||
| d2d01e83e0 |
145
README.md
145
README.md
@@ -4,8 +4,8 @@ a straightforward and handy file-naming scheme for all kinds of files. This,
|
|||||||
e.g., allows altering the title of a note without breaking the web of links.
|
e.g., allows altering the title of a note without breaking the web of links.
|
||||||
|
|
||||||
The present vim package reproduces some of the denote features for vim. The
|
The present vim package reproduces some of the denote features for vim. The
|
||||||
implementation is not complete, and more features are expected. Note that this
|
implementation is yet incomplete; more features are expected. Note that this is
|
||||||
is not the first attempt to handle denote notes within vim.
|
not the first attempt to handle denote notes within vim.
|
||||||
[Conan](https://zansh.in/) developed a [bash
|
[Conan](https://zansh.in/) developed a [bash
|
||||||
script](https://github.com/shuckster/denote-md) for denote and an accompanying
|
script](https://github.com/shuckster/denote-md) for denote and an accompanying
|
||||||
[vim plugin](https://github.com/shuckster/vim-denote-md). Also
|
[vim plugin](https://github.com/shuckster/vim-denote-md). Also
|
||||||
@@ -14,92 +14,107 @@ script](https://github.com/shuckster/denote-md) for denote and an accompanying
|
|||||||
### Why?
|
### Why?
|
||||||
The present package aims at handling denote notes the _vim way._ For instance,
|
The present package aims at handling denote notes the _vim way._ For instance,
|
||||||
both plugins do not bind the default key combination
|
both plugins do not bind the default key combination
|
||||||
[|gf|](https://vimhelp.org/editing.txt.html#gf) to follow links.
|
[`gf`](https://vimhelp.org/editing.txt.html#gf) to follow links.
|
||||||
The vim option
|
The vim option
|
||||||
[|'includeexpr'|](https://vimhelp.org/options.txt.html#%27includeexpr%27),
|
[`'includeexpr'`](https://vimhelp.org/options.txt.html#%27includeexpr%27),
|
||||||
however, exists precisely for solving the problem at hand: following custom-made links.
|
however, exists precisely for solving the problem at hand: following custom-made links.
|
||||||
|
|
||||||
Also, the present package aims at remaining flexible.
|
Also, the present package aims at remaining flexible. Again, both
|
||||||
Again, both 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, 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, place a copy of this
|
You may use any of your favorite plugin managers, or, manually place a copy of
|
||||||
package in `~/.vim/pack/tools/start`. Then, run `:helptags ALL` to regenerate
|
this package in, e.g., `~/.vim/pack/tools/start`. For such a manual
|
||||||
the help files. This will allow you to get more help using `:help denote` or
|
installation, you may want to run `:helptags
|
||||||
|
~/.vim/pack/tools/start/vim-denote/doc` to regenerate the help files. This
|
||||||
|
allows you to display the package documentation using `:help vim-denote` and
|
||||||
similar commands.
|
similar commands.
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
For _following links,_ simply move your cursor to the denote link, and press
|
vim needs to know where your denote entries are stored. To do so, run the
|
||||||
`gf`.
|
command `:DenoteDirectory! <path>` where `<path>` points to your denote
|
||||||
|
directory. You may also define the `g:denote_directories`[^1] variable in your
|
||||||
|
[vimrc](https://vimhelp.org/starting.txt.html#vimrc) as a list of paths to
|
||||||
|
denote directories. The benefit of doing so is that the `:DenoteDirectory`
|
||||||
|
command _(without bang)_ auto completes the paths to these directories.
|
||||||
|
|
||||||
This package also provides denote _link completion_ using the
|
After specifying the denote directory, the following functionalities are
|
||||||
[|'omnifunc'|](https://vimhelp.org/options.txt.html#%27omnifunc%27) option. So,
|
available.
|
||||||
the link is completed after pressing `<C-X><C-O>` while typing any prefix of a
|
|
||||||
denote link `denote:<identifier>`. Even more so, if this completion is invoked
|
|
||||||
after typing `denote:<str>`, then the link is completed for denote entries
|
|
||||||
that have `<str>` as part of the title.
|
|
||||||
|
|
||||||
_Browsing_ and _searching notes_ is implemented using the [location
|
_Following links:_ Simply place your cursor on a denote link and press `gf` or
|
||||||
list](https://vimhelp.org/quickfix.txt.html#location-list).
|
similar keys.
|
||||||
This means that you may navigate your notes using, e.g., `:lopen` to open the
|
|
||||||
list, `:lnext` and `:lprev`, to move to the next or previous entry (the list
|
|
||||||
does not need to be opened for that), and `:lclose` for closing the location
|
|
||||||
list.
|
|
||||||
|
|
||||||
#### Commands
|
_Link completion:_ When editing a note, write any prefix of a denote link
|
||||||
This package defines the following user commands:
|
(`denote:<identifier>`) and invoke [Omni
|
||||||
|
completion](https://vimhelp.org/insert.txt.html#compl-omni) by pressing
|
||||||
|
`<C-X><C-O>`. Even more so, if this completion is invoked after typing
|
||||||
|
`denote:<str>`, then the link is completed for denote entries that have `<str>`
|
||||||
|
as part of the title.
|
||||||
|
|
||||||
- `:Denote [{keyword ..}]`:
|
_Browsing and searching notes:_ Browsing and searching is done using vim's
|
||||||
This command places all denote entries in the location list.
|
[location list](https://vimhelp.org/quickfix.txt.html#location-list). The
|
||||||
You may supply any number of arguments to filter the notes by the given
|
benefit of doing so is that commands like `:lnext`, `:lprev` etc. become
|
||||||
keywords.
|
available.
|
||||||
|
- The command `:Denote [{keyword ..}]` lists all denote entries. The optional
|
||||||
|
argument filters these entries by the appearance of the keyword in the file
|
||||||
|
name.
|
||||||
|
- The command `:DenoteByTag {tag}` lists all denote entries of a given tag.
|
||||||
|
This command come with auto completion.
|
||||||
|
- On an open note, the command `DenoteBackReferences` lists all
|
||||||
|
references to that note.
|
||||||
|
- Finally, the command `:DenoteGrep /{pattern}/[g][j][f]` searches within the
|
||||||
|
denote entries for the given
|
||||||
|
[pattern](https://vimhelp.org/quickfix.txt.html#%3Avimgrep).
|
||||||
|
|
||||||
- `:DenoteTag {tag}`:
|
_Adding notes:_ Run `:DenoteNew {title}` to add a new note with the given
|
||||||
With this, all notes of a given tag are listed.
|
title. You may also copy a file (any file) to your denote directory. To do so,
|
||||||
The `{tag}` may be autocompleted by hitting the tab key.
|
run `:DenoteCopy {file}`.
|
||||||
|
|
||||||
- `:DenoteGrep /{pattern}/[g][j][f]`:
|
_Managing entries:_ You can change the title of denote entries using
|
||||||
This command builds around
|
`:DenoteSetTitle {newtitle}`. Also, you can add and remove tags using
|
||||||
[:vimgrep](https://vimhelp.org/quickfix.txt.html#%3Avimgrep) and can be used to
|
`:DenoteTagAdd {tag}` and `:DenoteTagRm {tag}`, respectively. These latter two
|
||||||
search for patterns within your notes.
|
commands offer auto completion for the tags. Also, they accept line ranges that
|
||||||
|
may be given via, e.g., visual selection. Finally, denote entries are deleted
|
||||||
|
using `:DenoteDelete`. This command again accepts line ranges.
|
||||||
|
|
||||||
- `:DenoteBackReferences`:
|
[^1]: Run `:help g:denote_directories` for more information.
|
||||||
With this, you may populate the location list with all links to the currently
|
|
||||||
opened note.
|
|
||||||
|
|
||||||
- `:DenoteNew {title}`:
|
### Basic keys
|
||||||
With this, a new note entry is generated with the supplied title.
|
The denote location-list window comes with a set of keys:
|
||||||
|
- `q`: close the list
|
||||||
|
- `r`: reload the list
|
||||||
|
- `C`: rename the selected entry
|
||||||
|
- `+`: add a tag to the entry (also in visual mode)
|
||||||
|
- `-`: remove a tag from the entry (also in visual mode)
|
||||||
|
- `dd`: delete the selected entry (also in visual mode, using a single `d`)
|
||||||
|
|
||||||
#### Key mappings
|
### Example setup
|
||||||
This package also defines the following interface for key mappings, which
|
You get a possibly useful setup with a single default denote directory at
|
||||||
automatically open the location window:
|
`~/Documents/notes/` by placing these lines in your vimrc file:
|
||||||
|
```vim
|
||||||
- `<Plug>DenoteList` to list all denote notes, and
|
au VimEnter * DenoteDirectory ~/Documents/notes/
|
||||||
- `<Plug>DenoteBackReferences` to list all back references.
|
nnoremap <silent> <Leader>d :Denote<CR>
|
||||||
|
nnoremap <silent> <Leader>D :DenoteBackReferences<CR>
|
||||||
So, you may want to configure your keys like this:
|
|
||||||
```
|
|
||||||
nnoremap <silent> <Leader>d <Plug>DenoteList;
|
|
||||||
nnoremap <silent> <Leader>D <Plug>DenoteBackReferences;
|
|
||||||
```
|
|
||||||
|
|
||||||
You may also find the following keys favorable for navigation:
|
|
||||||
```
|
|
||||||
nnoremap ]l :lnext<CR>
|
nnoremap ]l :lnext<CR>
|
||||||
nnoremap [l :lprevious<CR>
|
nnoremap [l :lprevious<CR>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
After starting vim (in any directory), you can display all denote entries by
|
||||||
|
using the `<Leader>d` key, move forwards and backwards in the list using the
|
||||||
|
`]l` and `[l` keys, and list all back references to an opened note with the
|
||||||
|
`<Leader>D` key (again, you can jump around the references using `[l` and
|
||||||
|
`]l`).
|
||||||
|
|
||||||
### Customization
|
### Customization
|
||||||
You can customize the behavior of this package using several global variables.
|
You can customize the behavior of this package using several
|
||||||
Customization is explained in the [help file](doc/denote.txt), also accessible
|
global variables. Customization is explained in the [help
|
||||||
through `:help denote-settings`.
|
file](doc/denote.txt), also accessible through `:help denote-settings`.
|
||||||
|
|
||||||
### Future features
|
### Future features
|
||||||
These features are planned:
|
|
||||||
- Tag manipulation
|
|
||||||
- Title manipulation
|
|
||||||
- Signature handling?
|
- Signature handling?
|
||||||
- Note deletion?
|
- Subdirectories
|
||||||
|
- Denote query links
|
||||||
|
|||||||
@@ -1,19 +1,87 @@
|
|||||||
" Link completion {{{1
|
" Run this plugin only if the denote package has been setup
|
||||||
set omnifunc=denote#completion#get
|
if !exists('g:denote_directory')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
" Go to file command |gf| adjustments {{{1
|
" ... and if this filetype is specified as denote-note file
|
||||||
" This resolves denote links. The function has access to the variable v:fname,
|
if index(g:denote_note_file_extensions, expand('%:e')) == -1
|
||||||
" which corresponds to the filename under the cursor.
|
finish
|
||||||
function s:DenoteGotoFile()
|
endif
|
||||||
return v:fname !~ "^denote:"
|
|
||||||
\ ? v:fname
|
" ... and if the file is in the denote directory
|
||||||
\ : denote#meta#fileFromNoteId(v:fname[7:]) ?? v:fname
|
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
|
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.
|
" Denote links are of the form 'denote:<note id>'; we require the column.
|
||||||
setlocal isfname+=:
|
setlocal isfname+=:
|
||||||
" Set the function to resolve the filename under the cursor (see |gf|).
|
" Set the function to resolve the filename under the cursor (see |gf|).
|
||||||
setlocal includeexpr=s:DenoteGotoFile()
|
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 {{{1
|
" Back references command
|
||||||
command! DenoteBackReferences :call denote#loclist#references(denote#meta#noteIdFromFile(expand("%")))
|
let b:meta = libdenote#scheme_metadata(expand('%:t'))
|
||||||
|
exe 'command! -buffer DenoteBackReferences DenoteGrep /\<denote:' .. b:meta.id .. '\>/gj'
|
||||||
|
|||||||
@@ -1,8 +1,60 @@
|
|||||||
" Disable spell checking and set up custom mappings.
|
" Run this plugin only if the denote package has been setup
|
||||||
setlocal nospell
|
if !exists('g:denote_directory')
|
||||||
|
|
||||||
if getwininfo(win_getid())[0].loclist == 0
|
|
||||||
finish
|
finish
|
||||||
endif
|
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>
|
nnoremap <buffer> q :lclose<CR>
|
||||||
nnoremap <buffer> dd :lremove<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
1
after/ftplugin/text.vim
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
markdown.vim
|
||||||
13
autoload/denote/commands.vim
Normal file
13
autoload/denote/commands.vim
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
" Public commands
|
||||||
|
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>)
|
||||||
|
endfunction
|
||||||
@@ -1,59 +1,9 @@
|
|||||||
" Find the column where the completion starts. This must be between 1 and
|
" Completion function for denote tags
|
||||||
" col('.'). Denote links are of this form: `denote:<identifier>`.
|
function denote#completion#tags(ArgLead, CmdLine, CursorPos)
|
||||||
function s:column()
|
let l:files=glob(g:denote_directory .. '/*', 0, v:true)
|
||||||
" Get the substring from the start of the line until col('.')
|
let l:tags=[]
|
||||||
let l = getline(".")[:col('.')]
|
for f in l:files
|
||||||
" Take the shortest prefix of a denote link. This may be any of
|
let l:tags=extend(l:tags, libdenote#scheme_metadata(f).tags)
|
||||||
" \<d$
|
|
||||||
" ..
|
|
||||||
" \<denote:$
|
|
||||||
" \<denote:\f$
|
|
||||||
" \<denote:\f\f$
|
|
||||||
" etc.
|
|
||||||
let res = l->matchstrpos('\<denote:\f*$')
|
|
||||||
if res[1] >= 0
|
|
||||||
return res[1]
|
|
||||||
endif
|
|
||||||
let res = l->matchstrpos('\<d\f*$')
|
|
||||||
if res[1] == -1
|
|
||||||
return -3
|
|
||||||
endif
|
|
||||||
return 'denote:' =~ '^' .. res[0] ? res[1] : -3
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Return completion items given by the base
|
|
||||||
function s:suggestions(base)
|
|
||||||
let prefix = a:base->matchstr('^denote:\zs.*$')
|
|
||||||
let flist = glob(prefix ? "*" .. prefix .. "*" : "*", 0, v:true)
|
|
||||||
let res = []
|
|
||||||
for filename in flist
|
|
||||||
let noteId = denote#meta#noteIdFromFile(filename)
|
|
||||||
let noteTitle = denote#meta#noteTitleFromFile(filename)
|
|
||||||
if noteId == v:false || (noteId !~ '^' .. prefix && noteTitle !~ prefix)
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
let noteTitle = noteTitle ?? '(no title)'
|
|
||||||
let noteTags = denote#meta#noteTagsFromFile(filename)
|
|
||||||
let res = res->add({
|
|
||||||
\ 'word' : 'denote:' .. noteId,
|
|
||||||
\ 'abbr' : noteTitle,
|
|
||||||
\ 'menu' : noteTags->join(', ')
|
|
||||||
\ })
|
|
||||||
endfor
|
endfor
|
||||||
return res
|
return uniq(sort(l:tags))->join("\n")
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! Myomni(findstart, base)
|
|
||||||
if a:findstart == 1
|
|
||||||
let tmp = s:column()
|
|
||||||
return tmp
|
|
||||||
else
|
|
||||||
let tmp = s:suggestions(a:base)
|
|
||||||
return tmp
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Completion function for denote links
|
|
||||||
function denote#completion#get(findstart, base)
|
|
||||||
return a:findstart == 1 ? s:column() : s:suggestions(a:base)
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
" Functions to create the front matter {{{1
|
|
||||||
" 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
|
|
||||||
@@ -5,10 +5,10 @@ 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 name=denote#meta#noteTitleFromFile(bufname(a:buf))
|
let l:name = libdenote#scheme_metadata(bufname(a:buf)).title
|
||||||
return strchars(name, 1) <= g:denote_loc_title_columns
|
return strchars(l:name, 1) <= g:denote_loc_title_columns
|
||||||
\ ? printf('%' .. g:denote_loc_title_columns .. 's', name)
|
\ ? printf('%' .. g:denote_loc_title_columns .. 's', l:name)
|
||||||
\ : printf('%.' .. (g:denote_loc_title_columns - 1) .. 's', name) .. '…'
|
\ : printf('%.' .. (g:denote_loc_title_columns - 1) .. 's', l:name) .. '…'
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Local helper function to truncate text with match at the given column as a
|
" Local helper function to truncate text with match at the given column as a
|
||||||
@@ -20,43 +20,85 @@ 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 items=getloclist(a:info.winid)
|
let l:items=getloclist(a:info.winid)
|
||||||
let l=[]
|
let l:l=[]
|
||||||
let width=winwidth(0) - g:denote_loc_title_columns - 19
|
let l:width=winwidth(0) - g:denote_loc_title_columns - 19
|
||||||
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 e=items[idx]
|
let l:e=l:items[idx]
|
||||||
let name=s:titleFromBuf(e.bufnr)
|
let l:name=s:titleFromBuf(l:e.bufnr)
|
||||||
let lnum=printf('%5d', e.lnum)
|
let l:lnum=printf('%5d', l:e.lnum)
|
||||||
let col=printf('%3d', e.col)
|
let l:col=printf('%3d', l:e.col)
|
||||||
call add(l, name ..
|
call add(l:l, l:name ..
|
||||||
\ ' | ' .. lnum .. ' col ' .. col ..
|
\ ' | ' .. l:lnum .. ' l:col ' .. l:col ..
|
||||||
\ ' | ' .. s:formatText(items[idx].text, col, width))
|
\ ' | ' .. s:formatText(l:items[idx].text, l:col, l:width))
|
||||||
endfor
|
endfor
|
||||||
return l
|
return l:l
|
||||||
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 items=getloclist(a:info.winid)
|
let l:items=getloclist(a:info.winid)
|
||||||
let 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 e=items[idx]
|
let l:e=l:items[idx]
|
||||||
let name=s:titleFromBuf(e.bufnr)
|
let l:name=s:titleFromBuf(l:e.bufnr)
|
||||||
let ntags=denote#meta#noteTagsFromFile(bufname(e.bufnr))->join()
|
let l:ntags = libdenote#scheme_metadata(bufname(l:e.bufnr)).tags->join()
|
||||||
call add(l, name .. ' | ' .. ntags)
|
call add(l:l, l:name .. ' | ' .. l:ntags)
|
||||||
endfor
|
endfor
|
||||||
return l
|
return l:l
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Load all references to the given note into the location list.
|
" Re-populate location list with denote entries
|
||||||
function denote#loclist#references(noteId)
|
function denote#loclist#fill(title, files, Gfun)
|
||||||
" Populate location list
|
" Clear first
|
||||||
execute "lvimgrep /\\<denote:" .. a:noteId .. "\\>/gj *"
|
call setloclist(0, [], ' ')
|
||||||
" Adjust location list: set title and specify display function
|
" Set properties
|
||||||
let file=denote#meta#fileFromNoteId(a:noteId)
|
|
||||||
let noteTitle=denote#meta#noteTitleFromFile(file)
|
|
||||||
call setloclist(0, [], 'r',
|
call setloclist(0, [], 'r',
|
||||||
\ {'title': 'References to ' .. noteTitle .. ' (' .. a:noteId .. ')',
|
\ {'title': a:title,
|
||||||
\ 'quickfixtextfunc' : 'denote#loclist#textReferences'})
|
\ 'quickfixtextfunc' : 's:textNoteList',
|
||||||
|
\ 'context' : {'denote': 'list', 'gfun': a:Gfun}})
|
||||||
|
" Populate
|
||||||
|
let l:notes=[]
|
||||||
|
for f in a:files
|
||||||
|
call add(l:notes, {
|
||||||
|
\ 'filename' : f,
|
||||||
|
\ 'lnum' : 1
|
||||||
|
\ })
|
||||||
|
endfor
|
||||||
|
call setloclist(0, l:notes, 'a')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Specify location list as denote-grep list
|
||||||
|
function denote#loclist#setgrep(title, Gfun)
|
||||||
|
call setloclist(0, [], 'r',
|
||||||
|
\ {'title': a:title,
|
||||||
|
\ 'quickfixtextfunc' : 's:textReferences',
|
||||||
|
\ 'context' : {'denote': 'grep', 'gfun': a:Gfun}})
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Reload location list
|
||||||
|
function denote#loclist#reload()
|
||||||
|
let l:context = getloclist(0, {'context': 1})['context']
|
||||||
|
if has_key(l:context, 'denote') && has_key(l:context, 'gfun')
|
||||||
|
call denote#loclist#jumptowindow()
|
||||||
|
exe 'lclose'
|
||||||
|
call l:context['gfun']()
|
||||||
|
exe 'lwindow'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Jump to window this location list belongs to
|
||||||
|
function denote#loclist#jumptowindow()
|
||||||
|
let l:locprop = getloclist(0, {'filewinid': 0})
|
||||||
|
if type(l:locprop) != v:t_dict || !has_key(l:locprop, 'filewinid')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let l:winid = l:locprop['filewinid']
|
||||||
|
if l:winid == 0
|
||||||
|
exe 'new'
|
||||||
|
exe 'wincmd K'
|
||||||
|
else
|
||||||
|
call win_gotoid(l:winid)
|
||||||
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|||||||
@@ -1,44 +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 files = glob("*" .. a:noteId .. "*", 0, v:true)
|
|
||||||
\ ->filter('v:val =~ "' .. a:noteId .. '\\(==\\|--\\|__\\|\\.\\)"')
|
|
||||||
\ ->filter('v:val =~ "^' .. a:noteId .. '\\|@@' .. a:noteId .. '"')
|
|
||||||
return empty(files) ? v:false : files[0]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Return the note id from the filename. On failure, v:false is returned.
|
|
||||||
function denote#meta#noteIdFromFile(filename)
|
|
||||||
return a:filename->matchstr("@@\\zs.\\{-\\}\\ze\\(==\\|--\\|__\\|\\..\\)")
|
|
||||||
\ ?? a:filename->matchstr("^.\\{-\\}\\ze\\(==\\|--\\|__\\|\\..\\)")
|
|
||||||
\ ?? v:false
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Return the note title from the filename.
|
|
||||||
function denote#meta#noteTitleFromFile(filename)
|
|
||||||
return a:filename->matchstr("--\\zs.\\{-\\}\\ze\\(==\\|@@\\|__\\|\\..\\)")->substitute("-", " ", "g")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Return the note tags from the filename as a list.
|
|
||||||
function denote#meta#noteTagsFromFile(filename)
|
|
||||||
return a:filename->matchstr("__\\zs.\\{-\\}\\ze\\(==\\|@@\\|--\\|\\..\\)")->split("_")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Identifier creation
|
|
||||||
function denote#meta#identifier_generate()
|
|
||||||
if g:denote_identifier_fun
|
|
||||||
return execute "call " .. g:denote_identifier_fun .. "()"
|
|
||||||
endif
|
|
||||||
return exists("*strftime")
|
|
||||||
\ ? strftime("%Y%m%dT%H%M%S")
|
|
||||||
\ : rand()
|
|
||||||
endfunction
|
|
||||||
279
autoload/denote/notes.vim
Normal file
279
autoload/denote/notes.vim
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
" 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
|
||||||
202
autoload/libdenote.vim
Normal file
202
autoload/libdenote.vim
Normal 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
|
||||||
430
doc/denote.txt
430
doc/denote.txt
@@ -1,18 +1,34 @@
|
|||||||
*denote.txt* For Vim version 9.0. Last change: 2026 Feb 18
|
*denote.txt* Handling denote entries – the vim way
|
||||||
|
|
||||||
This is the documentation for the denote plugin.
|
Last change: 2026 Mar 4
|
||||||
|
|
||||||
|
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*
|
||||||
|
|
||||||
1. Introduction |denote-intro|
|
1. Introduction |denote-intro|
|
||||||
2. Commands |denote-commands|
|
2. Commands |denote-commands|
|
||||||
3. Settings |denote-settings|
|
2.1 Universal commands |denote-universal-commands|
|
||||||
4. Mappings |denote-mappings|
|
2.2 Note command |denote-note-command|
|
||||||
|
2.3 Denote-list commands |denote-list-commands|
|
||||||
|
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|
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
*denote-intro*
|
INTRODUCTION *denote-intro*
|
||||||
Introduction ~
|
|
||||||
|
|
||||||
Denote is a file-naming scheme developed by Protesilaos Stavrou and an Emacs
|
Denote is a file-naming scheme developed by Protesilaos Stavrou and an Emacs
|
||||||
tool for handling such files. Notes and other files that follow this scheme
|
tool for handling such files. Notes and other files that follow this scheme
|
||||||
@@ -21,87 +37,385 @@ do adjusting the tags or changing the title of a note. The official manual is
|
|||||||
available online:
|
available online:
|
||||||
https://protesilaos.com/emacs/denote
|
https://protesilaos.com/emacs/denote
|
||||||
|
|
||||||
The denote plugin adds denote functionality to vim --- the vim way. We are
|
The denote plugin adds denote functionality to vim — the vim way. We are aware
|
||||||
aware of two other plugins, but we fear that these plugins are not flexible
|
of two other plugins, but we fear that these plugins are not flexible enough,
|
||||||
enough, and more importantly, do not follow the vim philosophy for handling
|
and more importantly, do not follow the vim philosophy for handling denote
|
||||||
denote notes. These mentioned plugins are available here:
|
notes. These mentioned plugins are available here:
|
||||||
https://github.com/shuckster/denote-md
|
https://github.com/shuckster/denote-md
|
||||||
https://git.sr.ht/~ashton314/vim-denote
|
https://git.sr.ht/~ashton314/vim-denote
|
||||||
|
|
||||||
In contrast to these plugins, the present package relies on the
|
In contrast to these plugins, the present package relies on the
|
||||||
|location-list| features for displaying denote entries, and on the options
|
|location-list| features for displaying denote entries, and on the options
|
||||||
|'quickfixtextfunc'|, |'includeexpr'|, and |'omnifunc'|. With these, denote
|
'quickfixtextfunc', 'includeexpr', and 'omnifunc'. With these, denote links
|
||||||
links can be followed using |gf|, and completed using omni comletion (see,
|
can be followed using |gf|, and completed using omni completion (see,
|
||||||
|compl-omni|). For link completion, press |i_CTRL-X_CTRL-O| after typing any
|
|compl-omni|). For link completion, press |i_CTRL-X_CTRL-O| after typing any
|
||||||
prefix of a denote link. This completion also works with titles: by invoking
|
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.
|
||||||
|
|
||||||
*denote-commands*
|
|
||||||
Commands ~
|
|
||||||
*:Denote*
|
|
||||||
Populate the location list of the current window with the denote entries
|
|
||||||
present in the current directory. This command may be supplemented with any
|
|
||||||
number of arguments that filter the entries.
|
|
||||||
|
|
||||||
*:DenoteTag*
|
==============================================================================
|
||||||
This command takes as argument a tag, and populates the location list with all
|
COMMANDS *denote-commands*
|
||||||
denote entries of that are tagged accordingly. The tags are autocompleted
|
|
||||||
(see, |c_<Tab>|).
|
After loading this package, only the first of the following commands is
|
||||||
|
available. This first command, as descried below, sets the directory to be
|
||||||
|
used for the denote entries. After that command has been issued, several other
|
||||||
|
commands become possible, such as |:DenoteTag|. Some command are available
|
||||||
|
within any window, others only in denote notes, and yet other again only in
|
||||||
|
the location-list that lists denote entries.
|
||||||
|
|
||||||
|
|
||||||
|
*denote-universal-commands*
|
||||||
|
Universal commands~
|
||||||
|
*:DenoteDirectory*
|
||||||
|
*:DenoteDirectory!*
|
||||||
|
:DenoteDirectory[!] {path}
|
||||||
|
Set the provided {path} as the denote directory that will be used by
|
||||||
|
all following commands. The {path} argument is autocompleted. With the
|
||||||
|
bang, the autocompletion works for all directories available on your
|
||||||
|
system. Without the bang, only directories listed in the
|
||||||
|
|g:denote_directories| variable are autocompleted.
|
||||||
|
|
||||||
|
After the denote directory has been specified, the following commands become
|
||||||
|
available. They all operate on that specified directory.
|
||||||
|
|
||||||
|
*:Denote*
|
||||||
|
:Denote [{keyword ..}]
|
||||||
|
Populate the location list of the current window with the denote
|
||||||
|
entries present in the specified directory. This command may be
|
||||||
|
supplemented with any number of arguments that filter the entries
|
||||||
|
according to the appearance of the keywords in the file name.
|
||||||
|
|
||||||
|
*:DenoteByTag*
|
||||||
|
:DenoteByTag {tag}
|
||||||
|
This command takes as argument a tag, and populates the location list
|
||||||
|
with all denote entries of that are tagged accordingly. The tags are
|
||||||
|
autocompleted (see, |c_<Tab>|). Also fuzzy matching is possible when
|
||||||
|
"fuzzy" is contained in 'wildoptions'.
|
||||||
|
|
||||||
*:DenoteGrep*
|
*:DenoteGrep*
|
||||||
This command is a wrapper around |:lvimgrep| to search for a pattern in the
|
:DenoteGrep /{pattern}/[g][j][f]
|
||||||
denote entries. The required argument is a pattern as required by |:vimgrep|,
|
This command is a wrapper around |:lvimgrep| to search for a pattern
|
||||||
i.e., /{pattern}/[g][j][f].
|
in the denote entries. The required argument is a pattern as required
|
||||||
|
by |:vimgrep|, i.e., /{pattern}/[g][j][f].
|
||||||
|
|
||||||
*:DenoteNew*
|
*:DenoteNew*
|
||||||
This command takes as argument a note title, and generates a new denote entry
|
:DenoteNew {title}
|
||||||
with the specified title. The entry file type is controlled by the setting
|
This command takes as argument a note title, and generates a new
|
||||||
|g:denote_new_ft|.
|
denote entry with the specified title. The entry file type is
|
||||||
|
controlled by the setting |g:denote_new_ft|.
|
||||||
|
|
||||||
|
*:DenoteCopy*
|
||||||
|
:DenoteCopy {file}
|
||||||
|
With this, the specified file is copied into the denote directory. The
|
||||||
|
file name is taken as the title, and the identifier is freshly
|
||||||
|
generated. Any file, i.e., not only those specified using
|
||||||
|
|g:denote_note_file_extension| may be chosen.
|
||||||
|
|
||||||
|
|
||||||
|
*denote-note-command*
|
||||||
|
Note command~
|
||||||
|
|
||||||
|
This is the only command exclusive to the windows that hold denote note
|
||||||
|
entries, i.e., files with an extension in |g:denote_note_file_extension|.
|
||||||
|
|
||||||
*:DenoteBackReferences*
|
*:DenoteBackReferences*
|
||||||
When called from an opened denote entry, this command populates the location
|
:DenoteBackReferences
|
||||||
list with all references to the current note.
|
This command populates the location list with all references to the
|
||||||
|
current note. This command can only be called from an opened denote
|
||||||
|
note.
|
||||||
|
|
||||||
|
|
||||||
|
*denote-list-commands*
|
||||||
|
Denote-list commands~
|
||||||
|
|
||||||
|
The denote list may be opened using one of the commands |:Denote| or
|
||||||
|
|:DenoteByTag|. Also the commands |:DenoteGrep| and |:DenoteBackReferences|
|
||||||
|
open the location list, but not as a list of entries, but as a list of
|
||||||
|
matching patterns. The following commands are available in the denote list
|
||||||
|
(first case).
|
||||||
|
|
||||||
|
*:DenoteSetTitle*
|
||||||
|
:DenoteSetTitle {string}
|
||||||
|
The title of the selected entry is changed as specified.
|
||||||
|
|
||||||
|
*:DenoteTagAdd*
|
||||||
|
:DenoteTagAdd {tag}
|
||||||
|
With this, the provided tag is added to the list of tags of the
|
||||||
|
selected entry. The tag may be autocompleted. This command also
|
||||||
|
accepts a range, resulting in adding the tag to every entry within
|
||||||
|
that range.
|
||||||
|
|
||||||
|
*:DenoteTagRm*
|
||||||
|
:DenoteTagRm {tag}
|
||||||
|
Just as above, but for removing the specified tag.
|
||||||
|
|
||||||
|
*:DenoteDelete*
|
||||||
|
:DenoteDelete[!]
|
||||||
|
With this, the selected entry is deleted from the denote directory
|
||||||
|
(and from the disk). This command also accepts a range, to delete a
|
||||||
|
bunch of entries. After the deletion command has been invoked, the
|
||||||
|
user is asked to confirm the deletion. With the optional bang, no
|
||||||
|
confirmation will be asked.
|
||||||
|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
SETTINGS *denote-settings*
|
||||||
|
|
||||||
|
All settings described below are set to default values. For this package to
|
||||||
|
function, it is not necessary to specify a setting manually.
|
||||||
|
|
||||||
|
|
||||||
|
*g:denote_directories*
|
||||||
|
g:denote_directories list
|
||||||
|
With this option, may may specify a list of your denote directories.
|
||||||
|
This list is used for the autocompletion of the |:DenoteDirectory|
|
||||||
|
command. The default value is
|
||||||
|
>
|
||||||
|
let g:denote_directories = []
|
||||||
|
<
|
||||||
|
|
||||||
*denote-settings*
|
|
||||||
Settings ~
|
|
||||||
*g:denote_note_file_extension*
|
*g:denote_note_file_extension*
|
||||||
With this setting you may specify the file extensions of all denote entries
|
g:denote_note_file_extension list
|
||||||
within which |:DenoteGrep| will search for the provided pattern. If left
|
With this setting, you may specify the file extensions of all denote
|
||||||
unspecified, it is set to the following default value:
|
entries within which |:DenoteGrep| will search, and for which files
|
||||||
|
denote link completion and the |:DenoteBackReferences| command will be
|
||||||
|
available. If left unspecified, it is set to the following default
|
||||||
|
value:
|
||||||
>
|
>
|
||||||
g:denote_note_file_extension = ['md', 'org', 'txt']
|
let g:denote_note_file_extension = ['md', 'org', 'txt']
|
||||||
<
|
<
|
||||||
|
|
||||||
*g:denote_loc_title_columns*
|
*g:denote_loc_title_columns*
|
||||||
This integer specifies the number of columns used to display the titles of
|
g:denote_loc_title_columns number
|
||||||
denote entries. Per default, it is set to:
|
This integer specifies the number of columns used to display the
|
||||||
|
titles of denote entries. Per default, it is set to:
|
||||||
>
|
>
|
||||||
g:denote_loc_title_columns = 60
|
let g:denote_loc_title_columns = 60
|
||||||
<
|
<
|
||||||
|
|
||||||
*g:denote_new_ft*
|
*g:denote_new_ft*
|
||||||
Newly created notes are of this file type. Possible values are 'md', 'org', or
|
g:denote_new_ft string
|
||||||
'txt', with the following default:
|
Newly created notes are of this file type. Possible values are 'md',
|
||||||
|
'org', or 'txt', with the following default:
|
||||||
>
|
>
|
||||||
g:denote_new_ft = 'md'
|
let g:denote_new_ft = 'md'
|
||||||
<
|
<
|
||||||
|
|
||||||
*g:denote_fm_md_type*
|
*g:denote_fm_md_type*
|
||||||
The front matter of 'md' notes is given as 'yaml' or as 'toml'. By default,
|
g:denote_fm_md_type string
|
||||||
this package uses 'yaml':
|
The front matter of 'md' notes is given as 'yaml' or as 'toml'. By
|
||||||
|
default, this package uses 'yaml':
|
||||||
>
|
>
|
||||||
g:denote_fm_md_type = 'yaml'
|
let g:denote_fm_md_type = 'yaml'
|
||||||
<
|
<
|
||||||
*g:denote_identifier_fun*
|
|
||||||
Denote allows the use of custom identifiers. This variable, if set, points to
|
|
||||||
a function that generates identifiers for newly created notes. The function is
|
|
||||||
supposed to return a unique string.
|
|
||||||
|
|
||||||
*denote-mappings*
|
*g:Denote_identifier_fun*
|
||||||
Mappings ~
|
g:Denote_identifier_fun Funcref
|
||||||
|
Denote allows the use of custom identifiers. This variable, if set,
|
||||||
|
points to a function that generates identifiers for newly created
|
||||||
|
notes. The function is supposed to return a unique string. By default,
|
||||||
|
the variable set as
|
||||||
|
>
|
||||||
|
let g:Denote_identifier_fun = function('denote#meta#identifier_generate')
|
||||||
|
<
|
||||||
|
which calls |strftime('%Y%m%dT%H%M%S')| if |strftime()| is available,
|
||||||
|
and |rand()| otherwise. Another reasonable setting would be to use
|
||||||
|
some uuid generator and to specify, e.g.,
|
||||||
|
>
|
||||||
|
let g:Denote_identifier_fun = { -> system('uuidgen')
|
||||||
|
\ ->substitute('[^[:xdigit:]]', '', 'g') }
|
||||||
|
<
|
||||||
|
|
||||||
<Plug>DenoteList "Populate and open the location list with all
|
|
||||||
denote entries".
|
|
||||||
|
|
||||||
<Plug>DenoteBackReferences "Populate and open the location list with all
|
==============================================================================
|
||||||
denote entries that link to the currently opened one".
|
KEYS *denote-keys*
|
||||||
|
|
||||||
vim:tw=78:sw=4:ts=8:noet:ft=help:norl:
|
The location lists generated by the present package, e.g., through the command
|
||||||
|
|:DenoteGrep| or |:DenoteByTag|, have the following key key-bindings.
|
||||||
|
|
||||||
|
*denote-r*
|
||||||
|
r Reload the location list.
|
||||||
|
|
||||||
|
*denote-q*
|
||||||
|
q Close the location list.
|
||||||
|
|
||||||
|
|
||||||
|
In addition, denote lists (see |denote-list-commands|) come with the following
|
||||||
|
keys:
|
||||||
|
|
||||||
|
*denote-list-C*
|
||||||
|
C Change the title of the selected entry.
|
||||||
|
|
||||||
|
*denote-list-+*
|
||||||
|
+ Add a tag to the selected entries (also in visual mode).
|
||||||
|
|
||||||
|
*denote-list--*
|
||||||
|
- As |denote-list-+| but for removing tags.
|
||||||
|
|
||||||
|
*denote-list-dd*
|
||||||
|
dd Delete the selected entry.
|
||||||
|
{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:
|
||||||
|
|||||||
@@ -1,122 +1,119 @@
|
|||||||
" Global configurations {{{1
|
" Global configurations
|
||||||
|
if exists('g:loaded_denote')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
let g:loaded_denote = 1
|
||||||
|
|
||||||
" Restrict basic operations to these files:
|
" List of denote directories
|
||||||
|
if !exists('g:denote_directories')
|
||||||
|
let g:denote_directories = []
|
||||||
|
endif
|
||||||
|
call map(g:denote_directories, {_, d -> fnamemodify(d, ':p')})
|
||||||
|
|
||||||
|
" Restrict basic operations to these files
|
||||||
if !exists('g:denote_note_file_extensions')
|
if !exists('g:denote_note_file_extensions')
|
||||||
let g:denote_note_file_extensions=['md', 'org', 'txt']
|
let g:denote_note_file_extensions = ['md', 'org', 'txt']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" Number of columns used for the title in the location window.
|
" Number of columns used for the title in the location window
|
||||||
if !exists('g:denote_loc_title_columns')
|
if !exists('g:denote_loc_title_columns')
|
||||||
let g:denote_loc_title_columns=40
|
let g:denote_loc_title_columns = 40
|
||||||
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'
|
||||||
if !exists('g:denote_fm_md_type')
|
if !exists('g:denote_fm_md_type')
|
||||||
let g:denote_fm_md_type='yaml'
|
let g:denote_fm_md_type = 'yaml'
|
||||||
endif
|
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=''
|
let g:Denote_identifier_fun = function('libdenote#scheme_idgen')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" Local functions {{{1
|
" Transform full path into canonical form WITH trailing '/'
|
||||||
" Put all notes of the given tag to the location list. The tag argument is
|
function s:canonicalFullPath(path)
|
||||||
" mandatory.
|
let l:parts = split(a:path, '/')
|
||||||
function s:DenoteNotesByTag(tag)
|
let l:result = []
|
||||||
" Clear location list
|
for part in l:parts
|
||||||
call denote#loclist#clear()
|
if part == '.' || part == ''
|
||||||
" Find files
|
continue
|
||||||
let files = glob("*_" .. a:tag .. "*", 0, v:true)->filter('v:val =~ "_' .. a:tag .. '\\(==\\|@@\\|__\\|_\\|\\.\\)"')
|
elseif part == '..'
|
||||||
" Populate location list
|
if len(l:result) > 0
|
||||||
let locTitle="Denote notes: " .. a:tag
|
call remove(l:result, len(l:result)-1)
|
||||||
call setloclist(0, [], 'r',
|
endif
|
||||||
\ {'title': locTitle,
|
else
|
||||||
\ 'quickfixtextfunc' : 'denote#loclist#textNoteList'})
|
call add(l:result, part)
|
||||||
let notes=[]
|
endif
|
||||||
for f in files
|
|
||||||
call add(notes, {
|
|
||||||
\ 'filename' : f,
|
|
||||||
\ 'lnum' : 1
|
|
||||||
\ })
|
|
||||||
endfor
|
endfor
|
||||||
call setloclist(0, notes, 'a')
|
return empty(l:result) ? '/' : '/' .. join(l:result, '/') .. '/'
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Put all notes of the given tag to the location list. The search argument may be
|
" Compute the relative path from start to target. Both arguments are given as
|
||||||
" empty. For improving search, white spaces are replaced by the * |wildcard|.
|
" full paths.
|
||||||
function s:DenoteNotes(search)
|
function s:relativePath(start, target)
|
||||||
let s = substitute(" " .. a:search .. " ", " ", "*", "g")
|
let l:a = s:canonicalFullPath(a:start)
|
||||||
" Clear location list
|
let l:b = s:canonicalFullPath(a:target)
|
||||||
call denote#loclist#clear()
|
" Simple cases first: both paths are the same, or the target is l:a subpath
|
||||||
" Find files
|
" from the start.
|
||||||
let files = glob(s, 0, v:true)
|
if l:a == l:b[:strlen(l:a)-1]
|
||||||
" Populate location list
|
return l:b[strlen(l:a):]
|
||||||
let locTitle="Denote notes search:" .. a:search
|
endif
|
||||||
call setloclist(0, [], 'r',
|
" Now, we need to go back. If the following match fails, then we need to go
|
||||||
\ {'title': locTitle,
|
" back all the way
|
||||||
\ 'quickfixtextfunc' : 'denote#loclist#textNoteList'})
|
let l:l = matchstrpos(l:a .. l:b, '^\(/.*\)/\zs.*/\ze\1')
|
||||||
let notes=[]
|
return l:l[1] == -1
|
||||||
for f in files
|
\ ? substitute(l:a[1:-2], '[^/]\+', '..', 'g') .. l:b
|
||||||
call add(notes, {
|
\ : substitute(l:l[0], '[^/]\+', '..', 'g') .. l:b[l:l[1]:]
|
||||||
\ 'filename' : f,
|
endfunction
|
||||||
\ 'lnum' : 1
|
|
||||||
\ })
|
" Complete all paths to the denote directories. This functions completes the
|
||||||
|
" paths to the configured directories.
|
||||||
|
function s:denoteDirectoryCompletion(ArgLead, CmdLine, CursorPos)
|
||||||
|
let l:res = []
|
||||||
|
let l:bang = match(a:CmdLine, '^\S\+!') >= 0
|
||||||
|
let l:argleaddir = isdirectory(expand(a:ArgLead)) ? a:ArgLead : matchstr(a:ArgLead, '^.*/')
|
||||||
|
if strlen(l:argleaddir) == 0
|
||||||
|
let l:argleaddir = '~'
|
||||||
|
endif
|
||||||
|
if l:argleaddir !~ '/$'
|
||||||
|
let l:argleaddir = l:argleaddir .. '/'
|
||||||
|
endif
|
||||||
|
if l:bang
|
||||||
|
for ldir in (glob(expand(l:argleaddir) .. '/*', v:true, v:true)->filter('isdirectory(v:val)'))
|
||||||
|
call add(l:res, l:argleaddir .. fnamemodify(ldir, ':t'))
|
||||||
endfor
|
endfor
|
||||||
call setloclist(0, notes, 'a')
|
else
|
||||||
endfunction
|
let l:leaddir = s:canonicalFullPath(fnamemodify(l:argleaddir, ':p'))
|
||||||
|
for ldir in g:denote_directories
|
||||||
" This function implements the similar functionality of :vimgrep, but for
|
if l:leaddir == ldir[:strlen(l:leaddir)-1]
|
||||||
" denote notes.
|
call add(l:res, l:argleaddir .. s:relativePath(l:leaddir, ldir))
|
||||||
function s:DenoteGrep(search)
|
endif
|
||||||
" Clear location list
|
|
||||||
call denote#loclist#clear()
|
|
||||||
" Grep all greppable files
|
|
||||||
let fpat=map(copy(g:denote_note_file_extensions), {_, e -> "*." .. e})->join()
|
|
||||||
execute "lvimgrep " .. a:search .. " " .. fpat
|
|
||||||
" Adjust location list: set title and specify display function
|
|
||||||
call setloclist(0, [], 'r',
|
|
||||||
\ {'title': 'Denote grep: ' .. a:search,
|
|
||||||
\ 'quickfixtextfunc' : 'denote#loclist#textReferences'})
|
|
||||||
lclose
|
|
||||||
lopen
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" This function is used to autocomplete the tags in user commands.
|
|
||||||
function s:tagList(ArgLead, cmdLine, CursorPos)
|
|
||||||
let files=glob("*", 0, v:true)
|
|
||||||
let tags=[]
|
|
||||||
for f in files
|
|
||||||
let tags=extend(tags, denote#meta#noteTagsFromFile(f))
|
|
||||||
endfor
|
endfor
|
||||||
return uniq(sort(tags))->join("\n")
|
endif
|
||||||
|
return l:res->join("\n")
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" This creates a new denote entry with the given title and of the given
|
" Setup denote plugin, i.e.,
|
||||||
" filetype. The title may be empty.
|
" - set the denote directory
|
||||||
function s:DenoteNew(title, ft=g:denote_new_ft)
|
" - register user commands
|
||||||
let identifier=denote#meta#identifier_generate()
|
" - register auto commands
|
||||||
let fn=identifier .. '--' .. a:title
|
function s:setup(dir)
|
||||||
\ ->tolower()
|
" Set the denote directory
|
||||||
\ ->substitute('[^[:fname:]]\|/', '-', 'g')
|
let l:tmp = s:canonicalFullPath(fnamemodify(a:dir, ':p'))[:-2]
|
||||||
\ ->substitute('-\+', '-', 'g')
|
if !isdirectory(l:tmp)
|
||||||
\ ->trim('-') .. '.' .. a:ft
|
echohl WarningMsg
|
||||||
execute "edit " .. fn
|
echom "The specified argument is not a directory (" .. a:dir .. ")"
|
||||||
call setline(1, denote#frontmatter#new(a:ft, identifier, a:title))
|
return
|
||||||
|
endif
|
||||||
|
let g:denote_directory = l:tmp
|
||||||
|
" Register user commands and auto commands
|
||||||
|
call denote#commands#load()
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
" Public commands and key mappings {{{1
|
command -nargs=1 -bang -complete=custom,s:denoteDirectoryCompletion DenoteDirectory call s:setup(<f-args>)
|
||||||
command -nargs=* Denote :call <SID>DenoteNotes(<q-args>)
|
|
||||||
command -nargs=1 -complete=custom,<SID>tagList DenoteTag :call <SID>DenoteNotesByTag(<q-args>)
|
|
||||||
command -nargs=+ DenoteGrep :call <SID>DenoteGrep(<q-args>)
|
|
||||||
command -nargs=1 DenoteNew :call <SID>DenoteNew(<q-args>)
|
|
||||||
|
|
||||||
" Useful key mappings
|
|
||||||
nnoremap <silent> <Plug>DenoteList :Denote<CR>:lclose<CR>:lopen<CR>:resize 20<CR>
|
|
||||||
nnoremap <silent> <Plug>DenoteBackReferences :DenoteBackReferences<CR>:lclose<CR>:lopen<CR>:resize 20<CR>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user