Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ Or use some other plugin manager:
* [neobundle](https://github.com/Shougo/neobundle.vim)
* [pathogen](https://github.com/tpope/vim-pathogen)

Note that some features require a recent version of Vim (>= 8.1) or
NeoVim (>= 0.5).

## Usage

This outlines the basic steps to get started:
Expand Down
4 changes: 4 additions & 0 deletions autoload/wiki/buffer.vim
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ function! s:init_buffer_commands() abort " {{{1
command! -buffer WikiTagReload call wiki#tags#reload()
command! -buffer -nargs=* WikiTagList call wiki#tags#list(<f-args>)
command! -buffer -nargs=* WikiTagSearch call wiki#tags#search(<f-args>)
command! -buffer -nargs=+ -complete=custom,wiki#tags#get_tag_names
\ WikiTagRename call wiki#tags#rename_ask(<f-args>)

command! -buffer WikiFzfToc call wiki#fzf#toc()

Expand Down Expand Up @@ -95,6 +97,7 @@ function! s:init_buffer_mappings() abort " {{{1
nnoremap <silent><buffer> <plug>(wiki-tag-list) :WikiTagList<cr>
nnoremap <silent><buffer> <plug>(wiki-tag-reload) :WikiTagReload<cr>
nnoremap <silent><buffer> <plug>(wiki-tag-search) :WikiTagSearch<cr>
nnoremap <silent><buffer> <plug>(wiki-tag-rename) :WikiTagRename<cr>

nnoremap <silent><buffer> <plug>(wiki-fzf-toc) :WikiFzfToc<cr>
inoremap <silent><buffer> <plug>(wiki-fzf-toc) <esc>:WikiFzfToc<cr>
Expand Down Expand Up @@ -145,6 +148,7 @@ function! s:init_buffer_mappings() abort " {{{1
\ '<plug>(wiki-tag-list)': '<leader>wsl',
\ '<plug>(wiki-tag-reload)': '<leader>wsr',
\ '<plug>(wiki-tag-search)': '<leader>wss',
\ '<plug>(wiki-tag-rename)': '<leader>wsn',
\ 'x_<plug>(wiki-link-toggle-visual)': '<cr>',
\ 'o_<plug>(wiki-au)': 'au',
\ 'x_<plug>(wiki-au)': 'au',
Expand Down
137 changes: 137 additions & 0 deletions autoload/wiki/tags.vim
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ function! wiki#tags#get_all() abort " {{{1
return s:tags.gather()
endfunction

" }}}1
function! wiki#tags#get_tag_names() abort " {{{1
return keys(wiki#tags#get_all())
endfunction

" }}}1
function! wiki#tags#complete_tag_names(...) abort " {{{1
" Returns tag names in newline separated string suitable for completion with
" the "custom" argument, see ":help :command-completion-custom". We could
" also have used "customlist", but with "custom", filtering is performed
" implicitly and may be more efficient (cf. documentation).
return join(map(wiki#tags#get_tag_names(), 'escape(v:val, " ")'), "\n")
endfunction

" }}}1
function! wiki#tags#search(...) abort " {{{1
let l:cfg = deepcopy(g:wiki_tag_search)
Expand Down Expand Up @@ -70,6 +84,41 @@ function! wiki#tags#reload() abort " {{{1
call s:tags.reload()
endfunction

" }}}1
function! wiki#tags#rename(old_tag, new_tag='', rename_to_existing=v:false) abort " {{{1
if a:new_tag ==# ''
call wiki#tags#rename_ask(a:old_tag)
else
call s:tags.rename(a:old_tag, a:new_tag, a:rename_to_existing)
endif
endfunction

" }}}1
function! wiki#tags#rename_ask(old_tag='', new_tag='', ...) abort " {{{1
let l:old_tag = a:old_tag ==# ''
\ ? input('Enter tag to rename (wihtout delimiters): ',
'', 'custom,wiki#tags#get_tag_names')
\ : a:old_tag
if l:old_tag ==# '' | return | endif

if input('Rename "' . l:old_tag . '"'
\ . (a:new_tag ==# '' ? '' : ' to "' . a:new_tag . '"')
\ . ' [y]es/[N]o? ') !~? '^y'
return
endif

" Get new tag name
redraw!
if a:new_tag ==# ''
call wiki#log#info('Enter new tag name (without tag delimiters):')
let l:new_tag = input('> ')
else
let l:new_tag = a:new_tag
endif

call wiki#tags#rename(l:old_tag, l:new_tag)
endfunction

" }}}1


Expand Down Expand Up @@ -331,7 +380,91 @@ function! s:tags.add(tag, ...) abort dict " {{{1
endfunction

" }}}1
function! s:tags.rename(old_tag, new_tag, rename_to_existing=v:false) abort dict " {{{1
redraw!
if !has_key(self.collection, a:old_tag)
call wiki#log#info('Old tag name "' . a:old_tag . '" not found in cache; reloading tags.')
call wiki#tags#reload()
if !has_key(self.collection, a:old_tag)
return wiki#log#warn('No tag named "' . a:old_tag . '", aborting rename.')
endif
endif

if has_key(self.collection, a:new_tag)
call wiki#log#warn('Tag "' . a:new_tag . '" already exists!')
if !a:rename_to_existing
if input('Rename anyway? [y]es/[N]o: ', 'N') ==? 'n'
return
endif
endif
endif

call wiki#log#info('Renaming tag "' . a:old_tag . '" to "' . a:new_tag . '".')

let l:tagpages = self.collection[a:old_tag]

let l:bufnr = bufnr('')
" Get list of open wiki buffers
let l:bufs =
\ map(
\ filter(
\ filter(range(1, bufnr('$')), 'buflisted(v:val)'),
\ '!empty(getbufvar(v:val, ''wiki''))'),
\ 'fnamemodify(bufname(v:val), '':p'')')

" Save other wiki buffers
for l:bufname in l:bufs
execute 'buffer' fnameescape(l:bufname)
update
endfor

let l:num_files = 0

" We already know where the tag is in the file, thanks to the cache
for [l:file, l:lnum] in l:tagpages
if s:update_tag_in_wiki(l:file, l:lnum, a:old_tag, a:new_tag)
call self.add(a:new_tag, l:file, l:lnum)
call remove(self.collection, a:old_tag)
let l:num_files += 1
endif
endfor

" Refresh other wiki buffers
for l:bufname in l:bufs
execute 'buffer' fnameescape(l:bufname)
edit
endfor

" Refresh tags
silent call wiki#tags#reload()

execute 'buffer' l:bufnr

call wiki#log#info(printf('Renamed tags in %d files', l:num_files))
endfunction

" }}}1
function! s:update_tag_in_wiki(path, lnum, old_tag, new_tag) abort
call wiki#log#info('Renaming tag in: ' . fnamemodify(a:path, ':t'))
let l:lines = readfile(a:path)
let l:tagline = l:lines[a:lnum-1]
for l:parser in g:wiki_tag_parsers
if l:parser.match(l:tagline)
let l:tags = l:parser.parse(l:tagline)
if index(l:tags, a:new_tag) >= 0
call filter(l:tags, {_, t -> t !=# a:old_tag})
else
call map(l:tags, {_, t -> t ==# a:old_tag ? a:new_tag : t})
endif
let l:lines[a:lnum-1] = l:parser.make(l:tags, l:tagline)
call writefile(l:lines, a:path)
return 1
endif
endfor
return wiki#log#error("Didn't match tagline " . a:path . ':' . a:lnum . ' with any parser')
endfunction

" }}}1
function! s:parse_tags_in_file(file) abort " {{{1
let l:tags = []
let l:lnum = 0
Expand Down Expand Up @@ -390,4 +523,8 @@ function! g:wiki#tags#default_parser.parse(line) dict abort
return l:tags
endfunction

function! g:wiki#tags#default_parser.make(taglist, curline='') dict abort
return empty(a:taglist) ? '' : join(map(a:taglist, '":" . v:val . ":"'))
endfunction

" }}}1
31 changes: 26 additions & 5 deletions doc/wiki.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,12 @@ Note: |wiki.vim| is `not` a filetype plugin. It is designed so that it may be us
REQUIREMENTS *wiki-intro-requirements*

This plugin is mainly developed on and for Linux. Some or most of the features
should still work on Windows and OSX, but currently there are no guaranties.
should still work on Windows and OSX, but currently there are no guarantees.
On Windows, it is assumed that users enable 'shellslash' to avoid issues with
backslashes versus forward slashes.

Some features require a recent version of Vim (>= 8.1) or NeoVim (>= 0.5).

The following is a list of external tools that are used for some of the
features:

Expand Down Expand Up @@ -682,6 +684,12 @@ OPTIONS *wiki-config-options*
A function (|FuncRef|) that takes a single argument, the current line.
It should return a list of the tags in the given line.

make~
A function (|FuncRef|) that takes two arguments: a list of tags, and the
current line. It should return a new line with the list of tags
formatted appropriately. This new line will replace the current line.
This function is used by |WikiTagRename|.

re_findstart~
`OPTIONAL`
A regular expression (|String|) that should match the start of the
Expand All @@ -694,7 +702,8 @@ OPTIONS *wiki-config-options*
let g:wiki_tag_parsers = [
\ g:wiki#tags#default_parser,
\ { 'match': {x -> x =~# '^tags: '},
\ 'parse': {x -> split(matchstr(x, '^tags:\zs.*'), '[ ,]\+')}}
\ 'parse': {x -> split(matchstr(x, '^tags:\zs.*'), '[ ,]\+')},
\ 'make': {t,x -> 'tags: ' . empty(t) ? '' : join(t, ', ')}}
\]
<
See |g:wiki#tags#default_parser| for details on the default tag parser.
Expand Down Expand Up @@ -1061,6 +1070,12 @@ the commands are also available as mappings of the form `<plug>(wiki-[name])`.
* `scratch` Add results to a scratch buffer
* `cursor` Insert result below cursor

*<plug>(wiki-tag-rename)*
*WikiTagRename* [old_tag] [new_tag]
Rename `old_tag` to `new_tag` in all pages. If zero or one arguments are
supplied, the command asks for input. This command uses the `make` function
of |g:wiki_tag_parsers|.

*CtrlPWiki*
Open |CtrlP| in find file mode for wiki files in current wiki or in the main
wiki defined by |g:wiki_root|.
Expand Down Expand Up @@ -1423,6 +1438,7 @@ Related commands:
- |WikiTagList|
- |WikiTagReload|
- |WikiTagSearch|
- |WikiTagRename|
- |WikiFzfTags|

Related settings:
Expand Down Expand Up @@ -1462,13 +1478,18 @@ for convenience: >
return l:tags
endfunction

One may customize the default parser by adjusting the `re_match` and
`re_findstart` strings. E.g., to instead recognize hashed tags like `#tag1`
and `#my-other-tag`, one could add the following in ones vimrc: >
function! g:wiki#tags#default_parser.make(taglist, curline='') dict abort
return empty(a:taglist) ? '' : join(map(a:taglist, '":" . v:val . ":"'))
endfunction

One may customize the default parser by adjusting `re_match`,
`re_findstart`, and `make`. E.g., to instead recognize hashed tags like `#tag1`
and `#my-other-tag`, one could add the following in one's vimrc: >

let s:tag_parser = deepcopy(g:wiki#tags#default_parser)
let s:tag_parser.re_match = '\v%(^|\s)#\zs[^# ]+'
let s:tag_parser.re_findstart = '\v%(^|\s)#\zs[^# ]+'
let s:tag_parser.make = {t,l -> empty(t) ? '' : join(map(t, '"#" . v:val))}

let g:wiki_tag_parsers = [s:tag_parser]

Expand Down
8 changes: 7 additions & 1 deletion test/test-tags/test-custom-yaml.vim
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@ let g:wiki_link_extension = '.md'
let g:wiki_tag_parsers = [
\ g:wiki#tags#default_parser,
\ { 'match': {x -> x =~# '^tags: '},
\ 'parse': {x -> split(matchstr(x, '^tags:\zs.*'), '[ ,]\+')}}
\ 'parse': {x -> split(matchstr(x, '^tags:\zs.*'), '[ ,]\+')},
\ 'make': {t,l -> empty(t) ? '' : 'tags: ' . join(t, ', ')}}
\]

silent edit ../wiki-markdown/index.md

let s:tags = wiki#tags#get_all()
call assert_equal(['drink', 'good', 'life', 'work'], sort(keys(s:tags)))

call wiki#tags#rename('drink', 'coffee', 1)
call wiki#tags#rename('work', 'coffee', 1)
call wiki#tags#rename('life', 'good', 1)
call assert_equal('tags: coffee, good', readfile('../wiki-markdown/yaml-tags.md')[2])

call wiki#test#finished()
11 changes: 10 additions & 1 deletion test/test-tags/test-defaults.vim
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,17 @@ let g:wiki_cache_persistent = 0
silent edit ../wiki-basic/index.wiki

let s:tags = wiki#tags#get_all()
call assert_equal(5, len(s:tags))
call assert_equal(8, len(s:tags))
call assert_equal(1, len(s:tags.tag1))
call assert_equal(2, len(s:tags.marked))

"Original line in tagged.wiki is:
":tag_six: :tag3: :tag4: :tag5: :tag6:
call wiki#tags#rename('tag4', 'tag_four', 1) "Basic renaming
call wiki#tags#rename('tag5', 'tag_four', 1) "Rename to an existing tag
call wiki#tags#rename('tag6', 'tag_six', 1) "Rename to an existing tag, keeping original ordering
call assert_equal(
\ ':tag_six: :tag3: :tag_four:',
\ readfile('../wiki-basic/tagged.wiki')[1])

call wiki#test#finished()
2 changes: 1 addition & 1 deletion test/wiki-basic/tagged.wiki
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Intro
:tag3: :tag4:
:tag_six: :tag3: :tag4: :tag5: :tag6:

This is a wiki.