commit 89d28a72c5b444a28d0bca52ae8faa5a46bc67df
parent 13271541a64629942f13704ae98dd4d580fe0e33
Author: Michael F. Schönitzer <michael@schoenitzer.de>
Date: Wed, 4 Apr 2018 02:27:27 +0200
Merge branch 'beta' into dev
Diffstat:
3 files changed, 1664 insertions(+), 1600 deletions(-)
diff --git a/autoload/vimwiki/html.vim b/autoload/vimwiki/html.vim
@@ -1457,7 +1457,11 @@ function! s:convert_file(path_html, wikifile) "{{{
endif
" prepare regexps for lists
- let s:bullets = '[*-]'
+ if exists("g:vimwiki_additional_bullet_types")
+ let s:bullets = '[*-'. join(keys(g:vimwiki_additional_bullet_types), '') . ']'
+ else
+ let s:bullets = '[*-]'
+ endif
let s:numbers =
\'\C\%(#\|\d\+)\|\d\+\.\|[ivxlcdm]\+)\|[IVXLCDM]\+)\|\l\{1,2})\|\u\{1,2})\)'
diff --git a/autoload/vimwiki/lst.vim b/autoload/vimwiki/lst.vim
@@ -1,1600 +1,1656 @@
-" vim:tabstop=2:shiftwidth=2:expandtab:foldmethod=marker:textwidth=99
-" Vimwiki autoload plugin file
-" Desc: Everything concerning lists and checkboxes
-" Home: https://github.com/vimwiki/vimwiki/
-
-if exists("g:loaded_vimwiki_list_auto") || &cp
- finish
-endif
-let g:loaded_vimwiki_list_auto = 1
-
-"incrementation functions for the various kinds of numbers {{{
-
-function! s:increment_1(value) "{{{
- return eval(a:value) + 1
-endfunction "}}}
-
-function! s:increment_A(value) "{{{
- let list_of_chars = split(a:value, '.\zs')
- let done = 0
- for idx in reverse(range(len(list_of_chars)))
- let cur_num = char2nr(list_of_chars[idx])
- if cur_num < 90
- let list_of_chars[idx] = nr2char(cur_num + 1)
- let done = 1
- break
- else
- let list_of_chars[idx] = 'A'
- endif
- endfor
- if !done
- call insert(list_of_chars, 'A')
- endif
- return join(list_of_chars, '')
-endfunction "}}}
-
-function! s:increment_a(value) "{{{
- let list_of_chars = split(a:value, '.\zs')
- let done = 0
- for idx in reverse(range(len(list_of_chars)))
- let cur_num = char2nr(list_of_chars[idx])
- if cur_num < 122
- let list_of_chars[idx] = nr2char(cur_num + 1)
- let done = 1
- break
- else
- let list_of_chars[idx] = 'a'
- endif
- endfor
- if !done
- call insert(list_of_chars, 'a')
- endif
- return join(list_of_chars, '')
-endfunction "}}}
-
-function! s:increment_I(value) "{{{
- let subst_list = [ ['XLVIII$', 'IL'], ['VIII$', 'IX'], ['III$', 'IV'],
- \ ['DCCCXCIX$', 'CM'], ['CCCXCIX$', 'CD'], ['LXXXIX$', 'XC'],
- \ ['XXXIX$', 'XL'], ['\(I\{1,2\}\)$', '\1I'], ['CDXCIX$', 'D'],
- \ ['CMXCIX$', 'M'], ['XCIX$', 'C'], ['I\([VXLCDM]\)$', '\1'],
- \ ['\([VXLCDM]\)$', '\1I'] ]
- for [regex, subst] in subst_list
- if a:value =~# regex
- return substitute(a:value, regex, subst, '')
- endif
- endfor
- return ''
-endfunction "}}}
-
-function! s:increment_i(value) "{{{
- let subst_list = [ ['xlviii$', 'il'], ['viii$', 'ix'], ['iii$', 'iv'],
- \ ['dcccxcix$', 'cm'], ['cccxcix$', 'cd'], ['lxxxix$', 'xc'],
- \ ['xxxix$', 'xl'], ['\(i\{1,2\}\)$', '\1i'], ['cdxcix$', 'd'],
- \ ['cmxcix$', 'm'], ['xcix$', 'c'], ['i\([vxlcdm]\)$', '\1'],
- \ ['\([vxlcdm]\)$', '\1i'] ]
- for [regex, subst] in subst_list
- if a:value =~# regex
- return substitute(a:value, regex, subst, '')
- endif
- endfor
- return ''
-endfunction "}}}
-
-"incrementation functions for the various kinds of numbers }}}
-
-"utility functions {{{
-
-function! s:substitute_rx_in_line(lnum, pattern, new_string) "{{{
- call setline(a:lnum, substitute(getline(a:lnum), a:pattern, a:new_string,
- \ ''))
-endfunction "}}}
-
-function! s:substitute_string_in_line(lnum, old_string, new_string) "{{{
- call s:substitute_rx_in_line(a:lnum, vimwiki#u#escape(a:old_string),
- \ a:new_string)
-endfunction "}}}
-
-function! s:first_char(string) "{{{
- return matchstr(a:string, '^.')
-endfunction "}}}
-
-if exists("*strdisplaywidth") "{{{
- function! s:string_length(str)
- return strdisplaywidth(a:str)
- endfunction
-else
- function! s:string_length(str)
- return strlen(substitute(a:str, '.', 'x', 'g'))
- endfunction
-endif "}}}
-
-function! vimwiki#lst#default_symbol() "{{{
- return vimwiki#vars#get_syntaxlocal('list_markers')[0]
-endfunction "}}}
-
-function! vimwiki#lst#get_list_margin() "{{{
- let list_margin = vimwiki#vars#get_wikilocal('list_margin')
- if list_margin < 0
- return &sw
- else
- return list_margin
- endif
-endfunction "}}}
-
-"Returns: the column where the text of a line starts (possible list item
-"markers and checkboxes are skipped)
-function! s:text_begin(lnum) "{{{
- return s:string_length(matchstr(getline(a:lnum), vimwiki#vars#get_syntaxlocal('rxListItem')))
-endfunction "}}}
-
-"Returns: 2 if there is a marker and text
-" 1 for a marker and no text
-" 0 for no marker at all (empty line or only text)
-function! s:line_has_marker(lnum) "{{{
- if getline(a:lnum) =~# vimwiki#vars#get_syntaxlocal('rxListItem').'\s*$'
- return 1
- elseif getline(a:lnum) =~# vimwiki#vars#get_syntaxlocal('rxListItem').'\s*\S'
- return 2
- else
- return 0
- endif
-endfunction "}}}
-
-"utility functions }}}
-
-"get properties of an item {{{
-
-"Returns: the mainly used data structure in this file
-"An item represents a single list item and is a dictionary with the keys
-"lnum - the line number of the list item
-"type - 1 for bulleted item, 2 for numbered item, 0 for a regular line
-"mrkr - the concrete marker, e.g. '**' or 'b)'
-"cb - the char in the checkbox or '' if there is no checkbox
-function! s:get_item(lnum) "{{{
- let item = {'lnum': a:lnum}
- if a:lnum == 0 || a:lnum > line('$')
- let item.type = 0
- return item
- endif
-
- let matches = matchlist(getline(a:lnum), vimwiki#vars#get_syntaxlocal('rxListItem'))
- if matches == [] ||
- \ (matches[1] == '' && matches[2] == '') ||
- \ (matches[1] != '' && matches[2] != '')
- let item.type = 0
- return item
- endif
-
- let item.cb = matches[3]
-
- if matches[1] != ''
- let item.type = 1
- let item.mrkr = matches[1]
- else
- let item.type = 2
- let item.mrkr = matches[2]
- endif
-
- return item
-endfunction "}}}
-
-function! s:empty_item() "{{{
- return {'type': 0}
-endfunction "}}}
-
-"Returns: level of the line
-"0 is the 'highest' level
-function! s:get_level(lnum) "{{{
- if getline(a:lnum) =~# '^\s*$'
- return 0
- endif
- if !vimwiki#vars#get_syntaxlocal('recurring_bullets')
- let level = indent(a:lnum)
- else
- let level = s:string_length(matchstr(getline(a:lnum), vimwiki#vars#get_syntaxlocal(rx_bullet_chars)))-1
- if level < 0
- let level = (indent(a:lnum) == 0) ? 0 : 9999
- endif
- endif
- return level
-endfunction "}}}
-
-"Returns: 1, a, i, A, I or ''
-"If in doubt if alphanumeric character or romanian
-"numeral, peek in the previous line
-function! s:guess_kind_of_numbered_item(item) "{{{
- if a:item.type != 2 | return '' | endif
- let number_chars = a:item.mrkr[:-2]
- let divisor = a:item.mrkr[-1:]
-
- let number_kinds = vimwiki#vars#get_syntaxlocal('number_kinds')
-
- if number_chars =~# '\d\+'
- return '1'
- endif
- if number_chars =~# '\l\+'
- if number_chars !~# '^[ivxlcdm]\+' || index(number_kinds, 'i') == -1
- return 'a'
- else
-
- let item_above = s:get_prev_list_item(a:item, 0)
- if item_above.type != 0
- if index(number_kinds, 'a') == -1 ||
- \ (item_above.mrkr[-1:] !=# divisor && number_chars =~# 'i\+') ||
- \ s:increment_i(item_above.mrkr[:-2]) ==# number_chars
- return 'i'
- else
- return 'a'
- endif
- else
- if number_chars =~# 'i\+' || index(number_kinds, 'a') == -1
- return 'i'
- else
- return 'a'
- endif
- endif
-
- endif
- endif
- if number_chars =~# '\u\+'
- if number_chars !~# '^[IVXLCDM]\+' || index(number_kinds, 'I') == -1
- return 'A'
- else
-
- let item_above = s:get_prev_list_item(a:item, 0)
- if item_above.type != 0
- if index(number_kinds, 'A') == -1 ||
- \ (item_above.mrkr[-1:] !=# divisor && number_chars =~# 'I\+') ||
- \ s:increment_I(item_above.mrkr[:-2]) ==# number_chars
- return 'I'
- else
- return 'A'
- endif
- else
- if number_chars =~# 'I\+' || index(number_kinds, 'A') == -1
- return 'I'
- else
- return 'A'
- endif
- endif
-
- endif
- endif
-endfunction "}}}
-
-function! s:regexp_of_marker(item) "{{{
- if a:item.type == 1
- return vimwiki#u#escape(a:item.mrkr)
- elseif a:item.type == 2
- let number_divisors = vimwiki#vars#get_syntaxlocal('number_divisors')
- for ki in ['d', 'u', 'l']
- let match = matchstr(a:item.mrkr, '\'.ki.'\+['.number_divisors.']')
- if match != ''
- return '\'.ki.'\+'.vimwiki#u#escape(match[-1:])
- endif
- endfor
- else
- return ''
- endif
-endfunction "}}}
-
-"get properties of an item }}}
-
-"functions for navigating between items {{{
-
-"Returns: the list item after a:item or an empty item
-"If a:ignore_kind is 1, the markers can differ
-function! s:get_next_list_item(item, ignore_kind) "{{{
- let org_lvl = s:get_level(a:item.lnum)
- if !a:ignore_kind
- let org_regex = s:regexp_of_marker(a:item)
- endif
-
- let cur_ln = s:get_next_line(a:item.lnum)
- while cur_ln <= line('$')
- let cur_lvl = s:get_level(cur_ln)
- if cur_lvl <= org_lvl
- if a:ignore_kind
- return s:get_any_item_of_level(cur_ln, cur_lvl, org_lvl)
- else
- return s:get_item_of_level(cur_ln, cur_lvl, org_lvl, org_regex)
- endif
- endif
- let cur_ln = s:get_next_line(cur_ln)
- endwhile
- return s:empty_item()
-endfunction "}}}
-
-"Returns: the list item before a:item or an empty item
-"If a:ignore_kind is 1, the markers can differ
-function! s:get_prev_list_item(item, ignore_kind) "{{{
- let org_lvl = s:get_level(a:item.lnum)
- if !a:ignore_kind
- let org_regex = s:regexp_of_marker(a:item)
- endif
-
- let cur_ln = s:get_prev_line(a:item.lnum)
- while cur_ln >= 1
- let cur_lvl = s:get_level(cur_ln)
- if cur_lvl <= org_lvl
- if a:ignore_kind
- return s:get_any_item_of_level(cur_ln, cur_lvl, org_lvl)
- else
- return s:get_item_of_level(cur_ln, cur_lvl, org_lvl, org_regex)
- endif
- endif
- let cur_ln = s:get_prev_line(cur_ln)
- endwhile
- return s:empty_item()
-endfunction "}}}
-
-function! s:get_item_of_level(cur_ln, cur_lvl, org_lvl, org_regex) "{{{
- let cur_linecontent = getline(a:cur_ln)
- if a:cur_lvl == a:org_lvl
- if cur_linecontent =~# '^\s*'.a:org_regex.'\s'
- return s:get_item(a:cur_ln)
- else
- return s:empty_item()
- endif
- elseif a:cur_lvl < a:org_lvl
- return s:empty_item()
- endif
-endfunction "}}}
-
-function! s:get_any_item_of_level(cur_ln, cur_lvl, org_lvl) "{{{
- if a:cur_lvl == a:org_lvl
- return s:get_item(a:cur_ln)
- elseif a:cur_lvl < a:org_lvl
- return s:empty_item()
- endif
-endfunction "}}}
-
-function! s:get_first_item_in_list(item, ignore_kind) "{{{
- let cur_item = a:item
- while 1
- let prev_item = s:get_prev_list_item(cur_item, a:ignore_kind)
- if prev_item.type == 0
- break
- else
- let cur_item = prev_item
- endif
- endwhile
- return cur_item
-endfunction "}}}
-
-function! s:get_last_item_in_list(item, ignore_kind) "{{{
- let cur_item = a:item
- while 1
- let next_item = s:get_next_list_item(cur_item, a:ignore_kind)
- if next_item.type == 0
- break
- else
- let cur_item = next_item
- endif
- endwhile
- return cur_item
-endfunction "}}}
-
-"Returns: lnum+1 in most cases, but skips blank lines and preformatted text,
-"0 in case of nonvalid line.
-"If there is no second argument, 0 is returned at a header, otherwise the
-"header is skipped
-function! s:get_next_line(lnum, ...) "{{{
- if getline(a:lnum) =~# vimwiki#vars#get_syntaxlocal('rxPreStart')
- let cur_ln = a:lnum + 1
- while cur_ln <= line('$') &&
- \ getline(cur_ln) !~# vimwiki#vars#get_syntaxlocal('rxPreEnd')
- let cur_ln += 1
- endwhile
- let next_line = cur_ln
- else
- let next_line = nextnonblank(a:lnum+1)
- endif
-
- if a:0 > 0 && getline(next_line) =~# vimwiki#vars#get_syntaxlocal('rxHeader')
- let next_line = s:get_next_line(next_line, 1)
- endif
-
- if next_line < 0 || next_line > line('$') ||
- \ (getline(next_line) =~# vimwiki#vars#get_syntaxlocal('rxHeader') && a:0 == 0)
- return 0
- endif
-
- return next_line
-endfunction "}}}
-
-"Returns: lnum-1 in most cases, but skips blank lines and preformatted text
-"0 in case of nonvalid line and a header, because a header ends every list
-function! s:get_prev_line(lnum) "{{{
- let prev_line = prevnonblank(a:lnum-1)
-
- if getline(prev_line) =~# vimwiki#vars#get_syntaxlocal('rxPreEnd')
- let cur_ln = a:lnum - 1
- while 1
- if cur_ln == 0 || getline(cur_ln) =~# vimwiki#vars#get_syntaxlocal('rxPreStart')
- break
- endif
- let cur_ln -= 1
- endwhile
- let prev_line = cur_ln
- endif
-
- if prev_line < 0 || prev_line > line('$') ||
- \ getline(prev_line) =~# vimwiki#vars#get_syntaxlocal('rxHeader')
- return 0
- endif
-
- return prev_line
-endfunction "}}}
-
-function! s:get_first_child(item) "{{{
- if a:item.lnum >= line('$')
- return s:empty_item()
- endif
- let org_lvl = s:get_level(a:item.lnum)
- let cur_item = s:get_item(s:get_next_line(a:item.lnum))
- while 1
- if cur_item.type != 0 && s:get_level(cur_item.lnum) > org_lvl
- return cur_item
- endif
- if cur_item.lnum > line('$') || cur_item.lnum <= 0 ||
- \ s:get_level(cur_item.lnum) <= org_lvl
- return s:empty_item()
- endif
- let cur_item = s:get_item(s:get_next_line(cur_item.lnum))
- endwhile
-endfunction "}}}
-
-
-"Returns: the next sibling of a:child, given the parent item
-"Used for iterating over children
-"Note: child items do not necessarily have the same indent, i.e. level
-function! s:get_next_child_item(parent, child) "{{{
- if a:parent.type == 0 | return s:empty_item() | endif
- let parent_lvl = s:get_level(a:parent.lnum)
- let cur_ln = s:get_last_line_of_item_incl_children(a:child)
- while 1
- let next_line = s:get_next_line(cur_ln)
- if next_line == 0 || s:get_level(next_line) <= parent_lvl
- break
- endif
- let cur_ln = next_line
- let cur_item = s:get_item(cur_ln)
- if cur_item.type > 0
- return cur_item
- endif
- endwhile
- return s:empty_item()
-endfunction "}}}
-
-function! s:get_parent(item) "{{{
- let parent_line = 0
-
- let cur_ln = prevnonblank(a:item.lnum)
- let child_lvl = s:get_level(cur_ln)
- if child_lvl == 0
- return s:empty_item()
- endif
-
- while 1
- let cur_ln = s:get_prev_line(cur_ln)
- if cur_ln == 0 | break | endif
- let cur_lvl = s:get_level(cur_ln)
- if cur_lvl < child_lvl
- let cur_item = s:get_item(cur_ln)
- if cur_item.type == 0
- let child_lvl = cur_lvl
- continue
- endif
- let parent_line = cur_ln
- break
- endif
- endwhile
- return s:get_item(parent_line)
-endfunction "}}}
-
-"Returns: the item above or the item below or an empty item
-function! s:get_a_neighbor_item(item) "{{{
- let prev_item = s:get_prev_list_item(a:item, 1)
- if prev_item.type != 0
- return prev_item
- else
- let next_item = s:get_next_list_item(a:item, 1)
- if next_item.type != 0
- return next_item
- endif
- endif
- return s:empty_item()
-endfunction "}}}
-
-function! s:get_a_neighbor_item_in_column(lnum, column) "{{{
- let cur_ln = s:get_prev_line(a:lnum)
- while cur_ln >= 1
- if s:get_level(cur_ln) <= a:column
- return s:get_corresponding_item(cur_ln)
- endif
- let cur_ln = s:get_prev_line(cur_ln)
- endwhile
- return s:empty_item()
-endfunction "}}}
-
-"Returns: the item if there is one in a:lnum
-"else the multiline item a:lnum belongs to
-function! s:get_corresponding_item(lnum) "{{{
- let item = s:get_item(a:lnum)
- if item.type != 0
- return item
- endif
- let org_lvl = s:get_level(a:lnum)
- let cur_ln = a:lnum
- while cur_ln > 0
- let cur_lvl = s:get_level(cur_ln)
- let cur_item = s:get_item(cur_ln)
- if cur_lvl < org_lvl && cur_item.type != 0
- return cur_item
- endif
- if cur_lvl < org_lvl
- let org_lvl = cur_lvl
- endif
- let cur_ln = s:get_prev_line(cur_ln)
- endwhile
- return s:empty_item()
-endfunction "}}}
-
-"Returns: the last line of a (possibly multiline) item, including all children
-function! s:get_last_line_of_item_incl_children(item) "{{{
- let cur_ln = a:item.lnum
- let org_lvl = s:get_level(a:item.lnum)
- while 1
- let next_line = s:get_next_line(cur_ln)
- if next_line == 0 || s:get_level(next_line) <= org_lvl
- return cur_ln
- endif
- let cur_ln = next_line
- endwhile
-endfunction "}}}
-
-"Returns: the last line of a (possibly multiline) item
-"Note: there can be other list items between the first and last line
-function! s:get_last_line_of_item(item) "{{{
- if a:item.type == 0 | return 0 | endif
- let org_lvl = s:get_level(a:item.lnum)
- let last_corresponding_line = a:item.lnum
-
- let cur_ln = s:get_next_line(a:item.lnum)
- while 1
- if cur_ln == 0 || s:get_level(cur_ln) <= org_lvl
- break
- endif
- let cur_item = s:get_item(cur_ln)
- if cur_item.type == 0
- let last_corresponding_line = cur_ln
- let cur_ln = s:get_next_line(cur_ln)
- else
- let cur_ln = s:get_next_line(
- \ s:get_last_line_of_item_incl_children(cur_item))
- endif
- endwhile
-
- return last_corresponding_line
-endfunction "}}}
-
-"functions for navigating between items }}}
-
-"renumber list items {{{
-"Renumbers the current list from a:item on downwards
-"Returns: the last item that was adjusted
-function! s:adjust_numbered_list_below(item, recursive) "{{{
- if !(a:item.type == 2 || (a:item.type == 1 && a:recursive))
- return a:item
- endif
-
- let kind = s:guess_kind_of_numbered_item(a:item)
-
- let cur_item = a:item
- while 1
- if a:recursive
- call s:adjust_items_recursively(cur_item)
- endif
-
- let next_item = s:get_next_list_item(cur_item, 0)
- if next_item.type == 0
- break
- endif
-
- if cur_item.type == 2
- let new_val = s:increment_{kind}(cur_item.mrkr[:-2]) . cur_item.mrkr[-1:]
- call s:substitute_string_in_line(next_item.lnum, next_item.mrkr, new_val)
- let next_item.mrkr = new_val
- endif
-
- let cur_item = next_item
- endwhile
- return cur_item
-endfunction "}}}
-
-function! s:adjust_items_recursively(parent) "{{{
- if a:parent.type == 0
- return s:empty_item()
- end
-
- let child_item = s:get_first_child(a:parent)
- if child_item.type == 0
- return child_item
- endif
- while 1
- let last_item = s:adjust_numbered_list(child_item, 1, 1)
-
- let child_item = s:get_next_child_item(a:parent, last_item)
- if child_item.type == 0
- return last_item
- endif
- endwhile
-endfunction "}}}
-
-"Renumbers the list a:item is in.
-"If a:ignore_kind == 0, only the items which have the same kind of marker as
-"a:item are considered, otherwise all items.
-"Returns: the last item that was adjusted
-function! s:adjust_numbered_list(item, ignore_kind, recursive) "{{{
- if !(a:item.type == 2 || (a:item.type == 1 && (a:ignore_kind || a:recursive)))
- return s:empty_item()
- end
-
- let first_item = s:get_first_item_in_list(a:item, a:ignore_kind)
-
- while 1
- if first_item.type == 2
- let new_mrkr = s:guess_kind_of_numbered_item(first_item) .
- \ first_item.mrkr[-1:]
- call s:substitute_string_in_line(first_item.lnum, first_item.mrkr,
- \ new_mrkr)
- let first_item.mrkr = new_mrkr
- endif
-
- let last_item = s:adjust_numbered_list_below(first_item, a:recursive)
-
- let next_first_item = s:get_next_list_item(last_item, 1)
- if a:ignore_kind == 0 || next_first_item.type == 0
- return last_item
- endif
- let first_item = next_first_item
- endwhile
-endfunction "}}}
-
-"Renumbers the list the cursor is in
-"also update its parents checkbox state
-function! vimwiki#lst#adjust_numbered_list() "{{{
- let cur_item = s:get_corresponding_item(line('.'))
- if cur_item.type == 0 | return | endif
- call s:adjust_numbered_list(cur_item, 1, 0)
- call s:update_state(s:get_parent(cur_item))
-endfunction "}}}
-
-"Renumbers all lists of the buffer
-"of course, this might take some seconds
-function! vimwiki#lst#adjust_whole_buffer() "{{{
- let cur_ln = 1
- while 1
- let cur_item = s:get_item(cur_ln)
- if cur_item.type != 0
- let cur_item = s:adjust_numbered_list(cur_item, 0, 1)
- endif
- let cur_ln = s:get_next_line(cur_item.lnum, 1)
- if cur_ln <= 0 || cur_ln > line('$')
- return
- endif
- endwhile
-endfunction "}}}
-
-"renumber list items }}}
-
-"checkbox stuff {{{
-
-"Returns: the rate of checkboxed list item in percent
-function! s:get_rate(item) "{{{
- if a:item.type == 0 || a:item.cb == ''
- return -1
- endif
- let state = a:item.cb
- if state == vimwiki#vars#get_global('listsym_rejected')
- return -1
- endif
- let n = len(vimwiki#vars#get_syntaxlocal('listsyms_list'))
- return index(vimwiki#vars#get_syntaxlocal('listsyms_list'), state) * 100/(n-1)
-endfunction "}}}
-
-"Set state of the list item to [ ] or [o] or whatever
-"Returns: 1 if the state changed, 0 otherwise
-function! s:set_state(item, new_rate) "{{{
- let new_state = s:rate_to_state(a:new_rate)
- let old_state = s:rate_to_state(s:get_rate(a:item))
- if new_state !=# old_state
- call s:substitute_rx_in_line(a:item.lnum, '\[.]', '['.new_state.']')
- return 1
- else
- return 0
- endif
-endfunction "}}}
-
-"Set state of the list item to [ ] or [o] or whatever
-"Updates the states of its child items
-function! s:set_state_plus_children(item, new_rate) "{{{
- call s:set_state(a:item, a:new_rate)
-
- let child_item = s:get_first_child(a:item)
- while 1
- if child_item.type == 0
- break
- endif
- if child_item.cb != ''
- call s:set_state_plus_children(child_item, a:new_rate)
- endif
- let child_item = s:get_next_child_item(a:item, child_item)
- endwhile
-endfunction "}}}
-
-"Returns: the appropriate symbol for a given percent rate
-function! s:rate_to_state(rate) "{{{
- let listsyms_list = vimwiki#vars#get_syntaxlocal('listsyms_list')
- let state = ''
- let n = len(listsyms_list)
- if a:rate == 100
- let state = listsyms_list[n-1]
- elseif a:rate == 0
- let state = listsyms_list[0]
- elseif a:rate == -1
- let state = vimwiki#vars#get_global('listsym_rejected')
- else
- let index = float2nr(ceil(a:rate/100.0*(n-2)))
- let state = listsyms_list[index]
- endif
- return state
-endfunction "}}}
-
-"updates the symbol of a checkboxed item according to the symbols of its
-"children
-function! s:update_state(item) "{{{
- if a:item.type == 0 || a:item.cb == ''
- return
- endif
-
- let sum_children_rate = 0
- let count_children_with_cb = 0
-
- let child_item = s:get_first_child(a:item)
-
- while 1
- if child_item.type == 0
- break
- endif
- if child_item.cb != ''
- let rate = s:get_rate(child_item)
- if rate != -1
- let count_children_with_cb += 1
- let sum_children_rate += rate
- endif
- endif
- let child_item = s:get_next_child_item(a:item, child_item)
- endwhile
-
- if count_children_with_cb > 0
- let new_rate = sum_children_rate / count_children_with_cb
- call s:set_state_recursively(a:item, new_rate)
- else
- let rate = s:get_rate(a:item)
- if rate > 0 && rate < 100
- call s:set_state_recursively(a:item, 0)
- endif
- endif
-endfunction "}}}
-
-function! s:set_state_recursively(item, new_rate) "{{{
- let state_changed = s:set_state(a:item, a:new_rate)
- if state_changed
- call s:update_state(s:get_parent(a:item))
- endif
-endfunction "}}}
-
-"Creates checkbox in a list item.
-"Returns: 1 if successful
-function! s:create_cb(item) "{{{
- if a:item.type == 0 || a:item.cb != ''
- return 0
- endif
-
- let new_item = a:item
- let new_item.cb = vimwiki#vars#get_syntaxlocal('listsyms_list')[0]
- call s:substitute_rx_in_line(new_item.lnum,
- \ vimwiki#u#escape(new_item.mrkr) . '\zs\ze', ' [' . new_item.cb . ']')
-
- call s:update_state(new_item)
- return 1
-endfunction "}}}
-
-function! s:remove_cb(item) "{{{
- let item = a:item
- if item.type != 0 && item.cb != ''
- let item.cb = ''
- call s:substitute_rx_in_line(item.lnum, '\s\+\[.\]', '')
- endif
- return item
-endfunction "}}}
-
-"Change state of checkbox
-"in the lines of the given range
-function! s:change_cb(from_line, to_line, new_rate) "{{{
- let from_item = s:get_corresponding_item(a:from_line)
- if from_item.type == 0
- return
- endif
-
- let parent_items_of_lines = []
-
- for cur_ln in range(from_item.lnum, a:to_line)
- let cur_item = s:get_item(cur_ln)
- if cur_item.type != 0 && cur_item.cb != ''
- call s:set_state_plus_children(cur_item, a:new_rate)
- let cur_parent_item = s:get_parent(cur_item)
- if index(parent_items_of_lines, cur_parent_item) == -1
- call insert(parent_items_of_lines, cur_parent_item)
- endif
- endif
- endfor
-
- for parent_item in parent_items_of_lines
- call s:update_state(parent_item)
- endfor
-
-endfunction "}}}
-
-"Toggles checkbox between two states in the lines of the given range,
-"creates chceckboxes if there aren't any.
-function! s:toggle_create_cb(from_line, to_line, state1, state2) "{{{
- let from_item = s:get_corresponding_item(a:from_line)
- if from_item.type == 0
- return
- endif
-
- if from_item.cb == ''
-
- "if from_line has no CB, make a CB in every selected line
- let parent_items_of_lines = []
- for cur_ln in range(from_item.lnum, a:to_line)
- let cur_item = s:get_item(cur_ln)
- let success = s:create_cb(cur_item)
-
- if success
- let cur_parent_item = s:get_parent(cur_item)
- if index(parent_items_of_lines, cur_parent_item) == -1
- call insert(parent_items_of_lines, cur_parent_item)
- endif
- endif
- endfor
-
- for parent_item in parent_items_of_lines
- call s:update_state(parent_item)
- endfor
-
- else
-
- "if from_line has CB, toggle it and set all siblings to the same new state
- let rate_first_line = s:get_rate(from_item)
- let new_rate = rate_first_line == a:state1 ? a:state2 : a:state1
-
- call s:change_cb(a:from_line, a:to_line, new_rate)
-
- endif
-
-endfunction "}}}
-
-"Decrement checkbox between [ ] and [X]
-"in the lines of the given range
-function! vimwiki#lst#decrement_cb(from_line, to_line) "{{{
- let from_item = s:get_corresponding_item(a:from_line)
- if from_item.type == 0
- return
- endif
-
- "if from_line has CB, decrement it and set all siblings to the same new state
- let rate_first_line = s:get_rate(from_item)
- let n = len(vimwiki#vars#get_syntaxlocal('listsyms_list'))
- let new_rate = max([rate_first_line - 100/(n-1)-1, 0])
-
- call s:change_cb(a:from_line, a:to_line, new_rate)
-
-endfunction "}}}
-
-"Increment checkbox between [ ] and [X]
-"in the lines of the given range
-function! vimwiki#lst#increment_cb(from_line, to_line) "{{{
- let from_item = s:get_corresponding_item(a:from_line)
- if from_item.type == 0
- return
- endif
-
- "if from_line has CB, increment it and set all siblings to the same new state
- let rate_first_line = s:get_rate(from_item)
- let n = len(vimwiki#vars#get_syntaxlocal('listsyms_list'))
- let new_rate = min([rate_first_line + 100/(n-1)+1, 100])
-
- call s:change_cb(a:from_line, a:to_line, new_rate)
-
-endfunction "}}}
-
-"Toggles checkbox between [ ] and [X] or creates one
-"in the lines of the given range
-function! vimwiki#lst#toggle_cb(from_line, to_line) "{{{
- return s:toggle_create_cb(a:from_line, a:to_line, 100, 0)
-endfunction "}}}
-
-"Toggles checkbox between [ ] and [-] or creates one
-"in the lines of the given range
-function! vimwiki#lst#toggle_rejected_cb(from_line, to_line) "{{{
- return s:toggle_create_cb(a:from_line, a:to_line, -1, 0)
-endfunction "}}}
-
-"Increment checkbox between [ ] and [X]
-"in the lines of the given range
-function! vimwiki#lst#increment_cb(from_line, to_line) "{{{
- let from_item = s:get_corresponding_item(a:from_line)
- if from_item.type == 0
- return
- endif
-
- "if from_line has CB, increment it and set all siblings to the same new state
- let rate_first_line = s:get_rate(from_item)
- let n = len(vimwiki#vars#get_syntaxlocal('listsyms_list'))
- let new_rate = min([rate_first_line + 100/(n-1)+1, 100])
-
- call s:change_cb(a:from_line, a:to_line, new_rate)
-
-endfunction "}}}
-
-"Toggles checkbox between [ ] and [X] or creates one
-"in the lines of the given range
-function! vimwiki#lst#toggle_cb(from_line, to_line) "{{{
- return s:toggle_create_cb(a:from_line, a:to_line, 100, 0)
-endfunction "}}}
-
-"Toggles checkbox between [ ] and [-] or creates one
-"in the lines of the given range
-function! vimwiki#lst#toggle_rejected_cb(from_line, to_line) "{{{
- return s:toggle_create_cb(a:from_line, a:to_line, -1, 0)
-endfunction "}}}
-
-function! vimwiki#lst#remove_cb(first_line, last_line) "{{{
- let first_item = s:get_corresponding_item(a:first_line)
- let last_item = s:get_corresponding_item(a:last_line)
-
- if first_item.type == 0 || last_item.type == 0
- return
- endif
-
- let parent_items_of_lines = []
- let cur_ln = first_item.lnum
- while 1
- if cur_ln <= 0 || cur_ln > last_item.lnum | break | endif
- let cur_item = s:get_item(cur_ln)
- if cur_item.type != 0
- let cur_item = s:remove_cb(cur_item)
- let cur_parent_item = s:get_parent(cur_item)
- if index(parent_items_of_lines, cur_parent_item) == -1
- call insert(parent_items_of_lines, cur_parent_item)
- endif
- endif
- let cur_ln = s:get_next_line(cur_ln)
- endwhile
- for parent_item in parent_items_of_lines
- call s:update_state(parent_item)
- endfor
-endfunction "}}}
-
-function! vimwiki#lst#remove_cb_in_list() "{{{
- let first_item = s:get_first_item_in_list(
- \ s:get_corresponding_item(line('.')), 0)
-
- let cur_item = first_item
- while 1
- let next_item = s:get_next_list_item(cur_item, 0)
- let cur_item = s:remove_cb(cur_item)
- if next_item.type == 0
- break
- else
- let cur_item = next_item
- endif
- endwhile
-
- call s:update_state(s:get_parent(first_item))
-endfunction "}}}
-
-"checkbox stuff }}}
-
-"change the level of list items {{{
-
-function! s:set_indent(lnum, new_indent) "{{{
- if &expandtab
- let indentstring = repeat(' ', a:new_indent)
- else
- let indentstring = repeat('\t', a:new_indent / &tabstop) .
- \ repeat(' ', a:new_indent % &tabstop)
- endif
- call s:substitute_rx_in_line(a:lnum, '^\s*', indentstring)
-endfunction "}}}
-
-function! s:decrease_level(item) "{{{
- let removed_indent = 0
- if vimwiki#vars#get_syntaxlocal('recurring_bullets') && a:item.type == 1 &&
- \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), s:first_char(a:item.mrkr)) > -1
- if s:string_length(a:item.mrkr) >= 2
- call s:substitute_string_in_line(a:item.lnum,
- \ s:first_char(a:item.mrkr), '')
- let removed_indent = -1
- endif
- else
- let old_indent = indent(a:item.lnum)
- if &shiftround
- let new_indent = (old_indent - 1) / vimwiki#u#sw() * vimwiki#u#sw()
- else
- let new_indent = old_indent - vimwiki#u#sw()
- endif
- call s:set_indent(a:item.lnum, new_indent)
- let removed_indent = new_indent - old_indent
- endif
- return removed_indent
-endfunction "}}}
-
-function! s:increase_level(item) "{{{
- let additional_indent = 0
- if vimwiki#vars#get_syntaxlocal('recurring_bullets') && a:item.type == 1 &&
- \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), s:first_char(a:item.mrkr)) > -1
- call s:substitute_string_in_line(a:item.lnum, a:item.mrkr, a:item.mrkr .
- \ s:first_char(a:item.mrkr))
- let additional_indent = 1
- else
- let old_indent = indent(a:item.lnum)
- if &shiftround
- let new_indent = (old_indent / vimwiki#u#sw() + 1) * vimwiki#u#sw()
- else
- let new_indent = old_indent + vimwiki#u#sw()
- endif
- call s:set_indent(a:item.lnum, new_indent)
- let additional_indent = new_indent - old_indent
- endif
- return additional_indent
-endfunction "}}}
-
-"adds a:indent_by to the current indent
-"a:indent_by can be negative
-function! s:indent_line_by(lnum, indent_by) "{{{
- let item = s:get_item(a:lnum)
- if vimwiki#vars#get_syntaxlocal('recurring_bullets') && item.type == 1 &&
- \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), s:first_char(item.mrkr)) > -1
- if a:indent_by > 0
- call s:substitute_string_in_line(a:lnum, item.mrkr,
- \ item.mrkr . s:first_char(item.mrkr))
- elseif a:indent_by < 0
- call s:substitute_string_in_line(a:lnum, s:first_char(item.mrkr), '')
- endif
- else
- call s:set_indent(a:lnum, indent(a:lnum) + a:indent_by)
- endif
-endfunction "}}}
-
-"changes lvl of lines in selection
-function! s:change_level(from_line, to_line, direction, plus_children) "{{{
- let from_item = s:get_corresponding_item(a:from_line)
- if from_item.type == 0
- if a:direction ==# 'increase' && a:from_line == a:to_line &&
- \ empty(getline(a:from_line))
- "that's because :> doesn't work on an empty line
- normal! gi
- else
- execute a:from_line.','.a:to_line.(a:direction ==# 'increase' ? '>' : '<')
- endif
- return
- endif
-
- if a:direction ==# 'decrease' && s:get_level(from_item.lnum) == 0
- return
- endif
-
- if a:from_line == a:to_line
- if a:plus_children
- let to_line = s:get_last_line_of_item_incl_children(from_item)
- else
- let to_line = s:get_last_line_of_item(from_item)
- endif
- else
- let to_item = s:get_corresponding_item(a:to_line)
- if to_item.type == 0
- let to_line = a:to_line
- else
- if a:plus_children
- let to_line = s:get_last_line_of_item_incl_children(to_item)
- else
- let to_line = s:get_last_line_of_item(to_item)
- endif
- endif
- endif
-
- if to_line == 0
- return
- endif
-
- let to_be_adjusted = s:get_a_neighbor_item(from_item)
- let old_parent = s:get_parent(from_item)
- let first_line_level = s:get_level(from_item.lnum)
- let more_than_one_level_concerned = 0
-
- let first_line_indented_by =
- \ (a:direction ==# 'increase') ?
- \ s:increase_level(from_item) : s:decrease_level(from_item)
-
- let cur_ln = s:get_next_line(from_item.lnum)
- while cur_ln > 0 && cur_ln <= to_line
- if !more_than_one_level_concerned &&
- \ s:get_level(cur_ln) != first_line_level &&
- \ s:get_item(cur_ln).type != 0
- let more_than_one_level_concerned = 1
- endif
- call s:indent_line_by(cur_ln, first_line_indented_by)
- let cur_ln = s:get_next_line(cur_ln, 1)
- endwhile
-
- if a:from_line == a:to_line
- call s:adjust_mrkr(from_item)
- endif
- call s:update_state(old_parent)
- let from_item = s:get_item(from_item.lnum)
- if from_item.cb != ''
- call s:update_state(from_item)
- call s:update_state(s:get_parent(from_item))
- endif
-
- if more_than_one_level_concerned
- call vimwiki#lst#adjust_whole_buffer()
- else
- call s:adjust_numbered_list(from_item, 0, 0)
- call s:adjust_numbered_list(to_be_adjusted, 0, 0)
- endif
-endfunction "}}}
-
-function! vimwiki#lst#change_level(from_line, to_line, direction, plus_children) "{{{
- let cur_col = col('$') - col('.')
- call s:change_level(a:from_line, a:to_line, a:direction, a:plus_children)
- call cursor('.', col('$') - cur_col)
-endfunction "}}}
-
-"indent line a:lnum to be the continuation of a:prev_item
-function! s:indent_multiline(prev_item, lnum) "{{{
- if a:prev_item.type != 0
- call s:set_indent(a:lnum, s:text_begin(a:prev_item.lnum))
- endif
-endfunction "}}}
-
-"change the level of list items }}}
-
-"change markers of list items {{{
-"Returns: the position of a marker in g:vimwiki_list_markers
-function! s:get_idx_list_markers(item) "{{{
- if a:item.type == 1
- let m = s:first_char(a:item.mrkr)
- else
- let m = s:guess_kind_of_numbered_item(a:item) . a:item.mrkr[-1:]
- endif
- return index(vimwiki#vars#get_syntaxlocal('list_markers'), m)
-endfunction "}}}
-
-"changes the marker of the given item to the next in g:vimwiki_list_markers
-function! s:get_next_mrkr(item) "{{{
- let markers = vimwiki#vars#get_syntaxlocal('list_markers')
- if a:item.type == 0
- let new_mrkr = markers[0]
- else
- let idx = s:get_idx_list_markers(a:item)
- let new_mrkr = markers[(idx+1) % len(markers)]
- endif
- return new_mrkr
-endfunction "}}}
-
-"changes the marker of the given item to the previous in g:vimwiki_list_markers
-function! s:get_prev_mrkr(item) "{{{
- let markers = vimwiki#vars#get_syntaxlocal('list_markers')
- if a:item.type == 0
- return markers[-1]
- endif
- let idx = s:get_idx_list_markers(a:item)
- if idx == -1
- return markers[-1]
- else
- return markers[(idx - 1 + len(markers)) %
- \ len(markers)]
- endif
-endfunction "}}}
-
-function! s:set_new_mrkr(item, new_mrkr) "{{{
- if a:item.type == 0
- call s:substitute_rx_in_line(a:item.lnum, '^\s*\zs\ze', a:new_mrkr.' ')
- if indent(a:item.lnum) == 0 && !vimwiki#vars#get_syntaxlocal('recurring_bullets')
- call s:set_indent(a:item.lnum, vimwiki#lst#get_list_margin())
- endif
- else
- call s:substitute_string_in_line(a:item.lnum, a:item.mrkr, a:new_mrkr)
- endif
-endfunction "}}}
-
-function! vimwiki#lst#change_marker(from_line, to_line, new_mrkr, mode) "{{{
- let cur_col_from_eol = col("$") - (a:mode ==# "i" ? col("'^") : col('.'))
- let new_mrkr = a:new_mrkr
- let cur_ln = a:from_line
- while 1
- let cur_item = s:get_item(cur_ln)
-
- if new_mrkr ==# "next"
- let new_mrkr = s:get_next_mrkr(cur_item)
- elseif new_mrkr ==# "prev"
- let new_mrkr = s:get_prev_mrkr(cur_item)
- endif
-
- "handle markers like ***
- if index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), s:first_char(new_mrkr)) > -1
- "use *** if the item above has *** too
- let item_above = s:get_prev_list_item(cur_item, 1)
- if item_above.type == 1 &&
- \ s:first_char(item_above.mrkr) ==# s:first_char(new_mrkr)
- let new_mrkr = item_above.mrkr
- else
- "use *** if the item below has *** too
- let item_below = s:get_next_list_item(cur_item, 1)
- if item_below.type == 1 &&
- \ s:first_char(item_below.mrkr) ==# s:first_char(new_mrkr)
- let new_mrkr = item_below.mrkr
- else
- "if the old is ### and the new is * use ***
- if cur_item.type == 1 &&
- \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), s:first_char(cur_item.mrkr))>-1
- let new_mrkr = repeat(new_mrkr, s:string_length(cur_item.mrkr))
- else
- "use *** if the parent item has **
- let parent_item = s:get_parent(cur_item)
- if parent_item.type == 1 &&
- \ s:first_char(parent_item.mrkr) ==# s:first_char(new_mrkr)
- let new_mrkr = repeat(s:first_char(parent_item.mrkr),
- \ s:string_length(parent_item.mrkr)+1)
- endif
- endif
- endif
- endif
-
- endif
-
- call s:set_new_mrkr(cur_item, new_mrkr)
- call s:adjust_numbered_list(s:get_item(cur_ln), 1, 0)
-
- if cur_ln >= a:to_line | break | endif
- let cur_ln = s:get_next_line(cur_ln, 1)
- endwhile
-
- call cursor('.', col('$') - cur_col_from_eol)
-endfunction "}}}
-
-function! vimwiki#lst#change_marker_in_list(new_mrkr) "{{{
- let cur_item = s:get_corresponding_item(line('.'))
- let first_item = s:get_first_item_in_list(cur_item, 0)
- let last_item = s:get_last_item_in_list(cur_item, 0)
- if first_item.type == 0 || last_item.type == 0 | return | endif
- let first_item_line = first_item.lnum
-
- let cur_item = first_item
- while cur_item.type != 0 && cur_item.lnum <= last_item.lnum
- call s:set_new_mrkr(cur_item, a:new_mrkr)
- let cur_item = s:get_next_list_item(cur_item, 1)
- endwhile
-
- call s:adjust_numbered_list(s:get_item(first_item_line), 0, 0)
-endfunction "}}}
-
-"sets kind of the item depending on neighbor items and the parent item
-function! s:adjust_mrkr(item) "{{{
- if a:item.type == 0 || vimwiki#vars#get_syntaxlocal('recurring_bullets')
- return
- endif
-
- let new_mrkr = a:item.mrkr
- let neighbor_item = s:get_a_neighbor_item(a:item)
- if neighbor_item.type != 0
- let new_mrkr = neighbor_item.mrkr
- endif
-
- "if possible, set e.g. *** if parent has ** as marker
- if neighbor_item.type == 0 && a:item.type == 1 &&
- \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), s:first_char(a:item.mrkr)) > -1
- let parent_item = s:get_parent(a:item)
- if parent_item.type == 1 &&
- \ s:first_char(parent_item.mrkr) ==# s:first_char(a:item.mrkr)
- let new_mrkr = repeat(s:first_char(parent_item.mrkr),
- \ s:string_length(parent_item.mrkr)+1)
- endif
- endif
-
- call s:substitute_string_in_line(a:item.lnum, a:item.mrkr, new_mrkr)
- call s:adjust_numbered_list(a:item, 0, 1)
-endfunction "}}}
-
-function! s:clone_marker_from_to(from, to) "{{{
- let item_from = s:get_item(a:from)
- if item_from.type == 0 | return | endif
- let new_mrkr = item_from.mrkr . ' '
- call s:substitute_rx_in_line(a:to, '^\s*', new_mrkr)
- let new_indent = ( vimwiki#vars#get_syntaxlocal('recurring_bullets') ? 0 : indent(a:from) )
- call s:set_indent(a:to, new_indent)
- if item_from.cb != ''
- call s:create_cb(s:get_item(a:to))
- call s:update_state(s:get_parent(s:get_item(a:to)))
- endif
- if item_from.type == 2
- let adjust_from = ( a:from < a:to ? a:from : a:to )
- call s:adjust_numbered_list_below(s:get_item(adjust_from), 0)
- endif
-endfunction "}}}
-
-function! s:remove_mrkr(item) "{{{
- let item = a:item
- if item.cb != ''
- let item = s:remove_cb(item)
- let parent_item = s:get_parent(item)
- else
- let parent_item = s:empty_item()
- endif
- call s:substitute_rx_in_line(item.lnum, vimwiki#u#escape(item.mrkr).'\s*', '')
- call remove(item, 'mrkr')
- call remove(item, 'cb')
- let item.type = 0
- call s:update_state(parent_item)
- return item
-endfunction "}}}
-
-function! s:create_marker(lnum) "{{{
- let new_sibling = s:get_corresponding_item(a:lnum)
- if new_sibling.type == 0
- let new_sibling = s:get_a_neighbor_item_in_column(a:lnum, virtcol('.'))
- endif
- if new_sibling.type != 0
- call s:clone_marker_from_to(new_sibling.lnum, a:lnum)
- else
- let cur_item = s:get_item(a:lnum)
- call s:set_new_mrkr(cur_item, vimwiki#vars#get_syntaxlocal('list_markers')[0])
- call s:adjust_numbered_list(cur_item, 0, 0)
- endif
-endfunction "}}}
-
-"change markers of list items }}}
-
-"handle keys {{{
-function! vimwiki#lst#kbd_o() "{{{
- let fold_end = foldclosedend('.')
- let lnum = (fold_end == -1) ? line('.') : fold_end
- let cur_item = s:get_item(lnum)
- "inserting and deleting the x is necessary
- "because otherwise the indent is lost
- normal! ox
- if cur_item.lnum < s:get_last_line_of_item(cur_item)
- call s:indent_multiline(cur_item, cur_item.lnum+1)
- else
- call s:clone_marker_from_to(cur_item.lnum, cur_item.lnum+1)
- endif
- startinsert!
-endfunction "}}}
-
-function! vimwiki#lst#kbd_O() "{{{
- normal! Ox
- let cur_ln = line('.')
- if getline(cur_ln+1) !~# '^\s*$'
- call s:clone_marker_from_to(cur_ln+1, cur_ln)
- else
- call s:clone_marker_from_to(cur_ln-1, cur_ln)
- endif
- startinsert!
-endfunction "}}}
-
-function! s:cr_on_empty_list_item(lnum, behavior) "{{{
- if a:behavior == 1
- "just make a new list item
- normal! gi
- call s:clone_marker_from_to(a:lnum, a:lnum+1)
- startinsert!
- return
- elseif a:behavior == 2
- "insert new marker but remove marker in old line
- call append(a:lnum-1, '')
- startinsert!
- return
- elseif a:behavior == 3
- "list is finished, but cursor stays in current line
- let item = s:get_item(a:lnum)
- let neighbor_item = s:get_a_neighbor_item(item)
- let child_item = s:get_first_child(item)
- let parent_item = (item.cb != '') ? s:get_parent(item) : s:empty_item()
- normal! "_cc
- call s:adjust_numbered_list(neighbor_item, 0, 0)
- call s:adjust_numbered_list(child_item, 0, 0)
- call s:update_state(parent_item)
- startinsert
- return
- elseif a:behavior == 4
- "list is finished, but cursor goes to next line
- let item = s:get_item(a:lnum)
- let neighbor_item = s:get_a_neighbor_item(item)
- let child_item = s:get_first_child(item)
- let parent_item = (item.cb != '') ? s:get_parent(item) : s:empty_item()
+" vim:tabstop=2:shiftwidth=2:expandtab:foldmethod=marker:textwidth=99
+" Vimwiki autoload plugin file
+" Desc: Everything concerning lists and checkboxes
+" Home: https://github.com/vimwiki/vimwiki/
+
+if exists("g:loaded_vimwiki_list_auto") || &cp
+ finish
+endif
+let g:loaded_vimwiki_list_auto = 1
+
+"incrementation functions for the various kinds of numbers {{{
+
+function! s:increment_1(value) "{{{
+ return eval(a:value) + 1
+endfunction "}}}
+
+function! s:increment_A(value) "{{{
+ let list_of_chars = split(a:value, '.\zs')
+ let done = 0
+ for idx in reverse(range(len(list_of_chars)))
+ let cur_num = char2nr(list_of_chars[idx])
+ if cur_num < 90
+ let list_of_chars[idx] = nr2char(cur_num + 1)
+ let done = 1
+ break
+ else
+ let list_of_chars[idx] = 'A'
+ endif
+ endfor
+ if !done
+ call insert(list_of_chars, 'A')
+ endif
+ return join(list_of_chars, '')
+endfunction "}}}
+
+function! s:increment_a(value) "{{{
+ let list_of_chars = split(a:value, '.\zs')
+ let done = 0
+ for idx in reverse(range(len(list_of_chars)))
+ let cur_num = char2nr(list_of_chars[idx])
+ if cur_num < 122
+ let list_of_chars[idx] = nr2char(cur_num + 1)
+ let done = 1
+ break
+ else
+ let list_of_chars[idx] = 'a'
+ endif
+ endfor
+ if !done
+ call insert(list_of_chars, 'a')
+ endif
+ return join(list_of_chars, '')
+endfunction "}}}
+
+function! s:increment_I(value) "{{{
+ let subst_list = [ ['XLVIII$', 'IL'], ['VIII$', 'IX'], ['III$', 'IV'],
+ \ ['DCCCXCIX$', 'CM'], ['CCCXCIX$', 'CD'], ['LXXXIX$', 'XC'],
+ \ ['XXXIX$', 'XL'], ['\(I\{1,2\}\)$', '\1I'], ['CDXCIX$', 'D'],
+ \ ['CMXCIX$', 'M'], ['XCIX$', 'C'], ['I\([VXLCDM]\)$', '\1'],
+ \ ['\([VXLCDM]\)$', '\1I'] ]
+ for [regex, subst] in subst_list
+ if a:value =~# regex
+ return substitute(a:value, regex, subst, '')
+ endif
+ endfor
+ return ''
+endfunction "}}}
+
+function! s:increment_i(value) "{{{
+ let subst_list = [ ['xlviii$', 'il'], ['viii$', 'ix'], ['iii$', 'iv'],
+ \ ['dcccxcix$', 'cm'], ['cccxcix$', 'cd'], ['lxxxix$', 'xc'],
+ \ ['xxxix$', 'xl'], ['\(i\{1,2\}\)$', '\1i'], ['cdxcix$', 'd'],
+ \ ['cmxcix$', 'm'], ['xcix$', 'c'], ['i\([vxlcdm]\)$', '\1'],
+ \ ['\([vxlcdm]\)$', '\1i'] ]
+ for [regex, subst] in subst_list
+ if a:value =~# regex
+ return substitute(a:value, regex, subst, '')
+ endif
+ endfor
+ return ''
+endfunction "}}}
+
+"incrementation functions for the various kinds of numbers }}}
+
+"utility functions {{{
+
+function! s:substitute_rx_in_line(lnum, pattern, new_string) "{{{
+ call setline(a:lnum, substitute(getline(a:lnum), a:pattern, a:new_string,
+ \ ''))
+endfunction "}}}
+
+function! s:substitute_string_in_line(lnum, old_string, new_string) "{{{
+ call s:substitute_rx_in_line(a:lnum, vimwiki#u#escape(a:old_string),
+ \ a:new_string)
+endfunction "}}}
+
+function! s:first_char(string) "{{{
+ return matchstr(a:string, '^.')
+endfunction "}}}
+
+if exists("*strdisplaywidth") "{{{
+ function! s:string_length(str)
+ return strdisplaywidth(a:str)
+ endfunction
+else
+ function! s:string_length(str)
+ return strlen(substitute(a:str, '.', 'x', 'g'))
+ endfunction
+endif "}}}
+
+function! vimwiki#lst#default_symbol() "{{{
+ return vimwiki#vars#get_syntaxlocal('list_markers')[0]
+endfunction "}}}
+
+function! vimwiki#lst#get_list_margin() "{{{
+ let list_margin = vimwiki#vars#get_wikilocal('list_margin')
+ if list_margin < 0
+ return &sw
+ else
+ return list_margin
+ endif
+endfunction "}}}
+
+"Returns: the column where the text of a line starts (possible list item
+"markers and checkboxes are skipped)
+function! s:text_begin(lnum) "{{{
+ return s:string_length(matchstr(getline(a:lnum), vimwiki#vars#get_syntaxlocal('rxListItem')))
+endfunction "}}}
+
+"Returns: 2 if there is a marker and text
+" 1 for a marker and no text
+" 0 for no marker at all (empty line or only text)
+function! s:line_has_marker(lnum) "{{{
+ if getline(a:lnum) =~# vimwiki#vars#get_syntaxlocal('rxListItem').'\s*$'
+ return 1
+ elseif getline(a:lnum) =~# vimwiki#vars#get_syntaxlocal('rxListItem').'\s*\S'
+ return 2
+ else
+ return 0
+ endif
+endfunction "}}}
+
+"utility functions }}}
+
+"get properties of an item {{{
+
+"Returns: the mainly used data structure in this file
+"An item represents a single list item and is a dictionary with the keys
+"lnum - the line number of the list item
+"type - 1 for bulleted item, 2 for numbered item, 0 for a regular line
+"mrkr - the concrete marker, e.g. '**' or 'b)'
+"cb - the char in the checkbox or '' if there is no checkbox
+function! s:get_item(lnum) "{{{
+ let item = {'lnum': a:lnum}
+ if a:lnum == 0 || a:lnum > line('$')
+ let item.type = 0
+ return item
+ endif
+
+ let matches = matchlist(getline(a:lnum), vimwiki#vars#get_syntaxlocal('rxListItem'))
+ if matches == [] ||
+ \ (matches[1] == '' && matches[2] == '') ||
+ \ (matches[1] != '' && matches[2] != '')
+ let item.type = 0
+ return item
+ endif
+
+ let item.cb = matches[3]
+
+ if matches[1] != ''
+ let item.type = 1
+ let item.mrkr = matches[1]
+ else
+ let item.type = 2
+ let item.mrkr = matches[2]
+ endif
+
+ return item
+endfunction "}}}
+
+function! s:empty_item() "{{{
+ return {'type': 0}
+endfunction "}}}
+
+"Returns: level of the line
+"0 is the 'highest' level
+function! s:get_level(lnum) "{{{
+ if getline(a:lnum) =~# '^\s*$'
+ return 0
+ endif
+ if !vimwiki#vars#get_syntaxlocal('recurring_bullets')
+ let level = indent(a:lnum)
+ else
+ let level = s:string_length(matchstr(getline(a:lnum), vimwiki#vars#get_syntaxlocal(rx_bullet_chars)))-1
+ if level < 0
+ let level = (indent(a:lnum) == 0) ? 0 : 9999
+ endif
+ endif
+ return level
+endfunction "}}}
+
+"Returns: 1, a, i, A, I or ''
+"If in doubt if alphanumeric character or romanian
+"numeral, peek in the previous line
+function! s:guess_kind_of_numbered_item(item) "{{{
+ if a:item.type != 2 | return '' | endif
+ let number_chars = a:item.mrkr[:-2]
+ let divisor = a:item.mrkr[-1:]
+
+ let number_kinds = vimwiki#vars#get_syntaxlocal('number_kinds')
+
+ if number_chars =~# '\d\+'
+ return '1'
+ endif
+ if number_chars =~# '\l\+'
+ if number_chars !~# '^[ivxlcdm]\+' || index(number_kinds, 'i') == -1
+ return 'a'
+ else
+
+ let item_above = s:get_prev_list_item(a:item, 0)
+ if item_above.type != 0
+ if index(number_kinds, 'a') == -1 ||
+ \ (item_above.mrkr[-1:] !=# divisor && number_chars =~# 'i\+') ||
+ \ s:increment_i(item_above.mrkr[:-2]) ==# number_chars
+ return 'i'
+ else
+ return 'a'
+ endif
+ else
+ if number_chars =~# 'i\+' || index(number_kinds, 'a') == -1
+ return 'i'
+ else
+ return 'a'
+ endif
+ endif
+
+ endif
+ endif
+ if number_chars =~# '\u\+'
+ if number_chars !~# '^[IVXLCDM]\+' || index(number_kinds, 'I') == -1
+ return 'A'
+ else
+
+ let item_above = s:get_prev_list_item(a:item, 0)
+ if item_above.type != 0
+ if index(number_kinds, 'A') == -1 ||
+ \ (item_above.mrkr[-1:] !=# divisor && number_chars =~# 'I\+') ||
+ \ s:increment_I(item_above.mrkr[:-2]) ==# number_chars
+ return 'I'
+ else
+ return 'A'
+ endif
+ else
+ if number_chars =~# 'I\+' || index(number_kinds, 'A') == -1
+ return 'I'
+ else
+ return 'A'
+ endif
+ endif
+
+ endif
+ endif
+endfunction "}}}
+
+function! s:regexp_of_marker(item) "{{{
+ if a:item.type == 1
+ return vimwiki#u#escape(a:item.mrkr)
+ elseif a:item.type == 2
+ let number_divisors = vimwiki#vars#get_syntaxlocal('number_divisors')
+ for ki in ['d', 'u', 'l']
+ let match = matchstr(a:item.mrkr, '\'.ki.'\+['.number_divisors.']')
+ if match != ''
+ return '\'.ki.'\+'.vimwiki#u#escape(match[-1:])
+ endif
+ endfor
+ else
+ return ''
+ endif
+endfunction "}}}
+
+"get properties of an item }}}
+
+"functions for navigating between items {{{
+
+"Returns: the list item after a:item or an empty item
+"If a:ignore_kind is 1, the markers can differ
+function! s:get_next_list_item(item, ignore_kind) "{{{
+ let org_lvl = s:get_level(a:item.lnum)
+ if !a:ignore_kind
+ let org_regex = s:regexp_of_marker(a:item)
+ endif
+
+ let cur_ln = s:get_next_line(a:item.lnum)
+ while cur_ln <= line('$')
+ let cur_lvl = s:get_level(cur_ln)
+ if cur_lvl <= org_lvl
+ if a:ignore_kind
+ return s:get_any_item_of_level(cur_ln, cur_lvl, org_lvl)
+ else
+ return s:get_item_of_level(cur_ln, cur_lvl, org_lvl, org_regex)
+ endif
+ endif
+ let cur_ln = s:get_next_line(cur_ln)
+ endwhile
+ return s:empty_item()
+endfunction "}}}
+
+"Returns: the list item before a:item or an empty item
+"If a:ignore_kind is 1, the markers can differ
+function! s:get_prev_list_item(item, ignore_kind) "{{{
+ let org_lvl = s:get_level(a:item.lnum)
+ if !a:ignore_kind
+ let org_regex = s:regexp_of_marker(a:item)
+ endif
+
+ let cur_ln = s:get_prev_line(a:item.lnum)
+ while cur_ln >= 1
+ let cur_lvl = s:get_level(cur_ln)
+ if cur_lvl <= org_lvl
+ if a:ignore_kind
+ return s:get_any_item_of_level(cur_ln, cur_lvl, org_lvl)
+ else
+ return s:get_item_of_level(cur_ln, cur_lvl, org_lvl, org_regex)
+ endif
+ endif
+ let cur_ln = s:get_prev_line(cur_ln)
+ endwhile
+ return s:empty_item()
+endfunction "}}}
+
+function! s:get_item_of_level(cur_ln, cur_lvl, org_lvl, org_regex) "{{{
+ let cur_linecontent = getline(a:cur_ln)
+ if a:cur_lvl == a:org_lvl
+ if cur_linecontent =~# '^\s*'.a:org_regex.'\s'
+ return s:get_item(a:cur_ln)
+ else
+ return s:empty_item()
+ endif
+ elseif a:cur_lvl < a:org_lvl
+ return s:empty_item()
+ endif
+endfunction "}}}
+
+function! s:get_any_item_of_level(cur_ln, cur_lvl, org_lvl) "{{{
+ if a:cur_lvl == a:org_lvl
+ return s:get_item(a:cur_ln)
+ elseif a:cur_lvl < a:org_lvl
+ return s:empty_item()
+ endif
+endfunction "}}}
+
+function! s:get_first_item_in_list(item, ignore_kind) "{{{
+ let cur_item = a:item
+ while 1
+ let prev_item = s:get_prev_list_item(cur_item, a:ignore_kind)
+ if prev_item.type == 0
+ break
+ else
+ let cur_item = prev_item
+ endif
+ endwhile
+ return cur_item
+endfunction "}}}
+
+function! s:get_last_item_in_list(item, ignore_kind) "{{{
+ let cur_item = a:item
+ while 1
+ let next_item = s:get_next_list_item(cur_item, a:ignore_kind)
+ if next_item.type == 0
+ break
+ else
+ let cur_item = next_item
+ endif
+ endwhile
+ return cur_item
+endfunction "}}}
+
+"Returns: lnum+1 in most cases, but skips blank lines and preformatted text,
+"0 in case of nonvalid line.
+"If there is no second argument, 0 is returned at a header, otherwise the
+"header is skipped
+function! s:get_next_line(lnum, ...) "{{{
+ if getline(a:lnum) =~# vimwiki#vars#get_syntaxlocal('rxPreStart')
+ let cur_ln = a:lnum + 1
+ while cur_ln <= line('$') &&
+ \ getline(cur_ln) !~# vimwiki#vars#get_syntaxlocal('rxPreEnd')
+ let cur_ln += 1
+ endwhile
+ let next_line = cur_ln
+ else
+ let next_line = nextnonblank(a:lnum+1)
+ endif
+
+ if a:0 > 0 && getline(next_line) =~# vimwiki#vars#get_syntaxlocal('rxHeader')
+ let next_line = s:get_next_line(next_line, 1)
+ endif
+
+ if next_line < 0 || next_line > line('$') ||
+ \ (getline(next_line) =~# vimwiki#vars#get_syntaxlocal('rxHeader') && a:0 == 0)
+ return 0
+ endif
+
+ return next_line
+endfunction "}}}
+
+"Returns: lnum-1 in most cases, but skips blank lines and preformatted text
+"0 in case of nonvalid line and a header, because a header ends every list
+function! s:get_prev_line(lnum) "{{{
+ let prev_line = prevnonblank(a:lnum-1)
+
+ if getline(prev_line) =~# vimwiki#vars#get_syntaxlocal('rxPreEnd')
+ let cur_ln = a:lnum - 1
+ while 1
+ if cur_ln == 0 || getline(cur_ln) =~# vimwiki#vars#get_syntaxlocal('rxPreStart')
+ break
+ endif
+ let cur_ln -= 1
+ endwhile
+ let prev_line = cur_ln
+ endif
+
+ if prev_line < 0 || prev_line > line('$') ||
+ \ getline(prev_line) =~# vimwiki#vars#get_syntaxlocal('rxHeader')
+ return 0
+ endif
+
+ return prev_line
+endfunction "}}}
+
+function! s:get_first_child(item) "{{{
+ if a:item.lnum >= line('$')
+ return s:empty_item()
+ endif
+ let org_lvl = s:get_level(a:item.lnum)
+ let cur_item = s:get_item(s:get_next_line(a:item.lnum))
+ while 1
+ if cur_item.type != 0 && s:get_level(cur_item.lnum) > org_lvl
+ return cur_item
+ endif
+ if cur_item.lnum > line('$') || cur_item.lnum <= 0 ||
+ \ s:get_level(cur_item.lnum) <= org_lvl
+ return s:empty_item()
+ endif
+ let cur_item = s:get_item(s:get_next_line(cur_item.lnum))
+ endwhile
+endfunction "}}}
+
+
+"Returns: the next sibling of a:child, given the parent item
+"Used for iterating over children
+"Note: child items do not necessarily have the same indent, i.e. level
+function! s:get_next_child_item(parent, child) "{{{
+ if a:parent.type == 0 | return s:empty_item() | endif
+ let parent_lvl = s:get_level(a:parent.lnum)
+ let cur_ln = s:get_last_line_of_item_incl_children(a:child)
+ while 1
+ let next_line = s:get_next_line(cur_ln)
+ if next_line == 0 || s:get_level(next_line) <= parent_lvl
+ break
+ endif
+ let cur_ln = next_line
+ let cur_item = s:get_item(cur_ln)
+ if cur_item.type > 0
+ return cur_item
+ endif
+ endwhile
+ return s:empty_item()
+endfunction "}}}
+
+function! s:get_parent(item) "{{{
+ let parent_line = 0
+
+ let cur_ln = prevnonblank(a:item.lnum)
+ let child_lvl = s:get_level(cur_ln)
+ if child_lvl == 0
+ return s:empty_item()
+ endif
+
+ while 1
+ let cur_ln = s:get_prev_line(cur_ln)
+ if cur_ln == 0 | break | endif
+ let cur_lvl = s:get_level(cur_ln)
+ if cur_lvl < child_lvl
+ let cur_item = s:get_item(cur_ln)
+ if cur_item.type == 0
+ let child_lvl = cur_lvl
+ continue
+ endif
+ let parent_line = cur_ln
+ break
+ endif
+ endwhile
+ return s:get_item(parent_line)
+endfunction "}}}
+
+"Returns: the item above or the item below or an empty item
+function! s:get_a_neighbor_item(item) "{{{
+ let prev_item = s:get_prev_list_item(a:item, 1)
+ if prev_item.type != 0
+ return prev_item
+ else
+ let next_item = s:get_next_list_item(a:item, 1)
+ if next_item.type != 0
+ return next_item
+ endif
+ endif
+ return s:empty_item()
+endfunction "}}}
+
+function! s:get_a_neighbor_item_in_column(lnum, column) "{{{
+ let cur_ln = s:get_prev_line(a:lnum)
+ while cur_ln >= 1
+ if s:get_level(cur_ln) <= a:column
+ return s:get_corresponding_item(cur_ln)
+ endif
+ let cur_ln = s:get_prev_line(cur_ln)
+ endwhile
+ return s:empty_item()
+endfunction "}}}
+
+"Returns: the item if there is one in a:lnum
+"else the multiline item a:lnum belongs to
+function! s:get_corresponding_item(lnum) "{{{
+ let item = s:get_item(a:lnum)
+ if item.type != 0
+ return item
+ endif
+ let org_lvl = s:get_level(a:lnum)
+ let cur_ln = a:lnum
+ while cur_ln > 0
+ let cur_lvl = s:get_level(cur_ln)
+ let cur_item = s:get_item(cur_ln)
+ if cur_lvl < org_lvl && cur_item.type != 0
+ return cur_item
+ endif
+ if cur_lvl < org_lvl
+ let org_lvl = cur_lvl
+ endif
+ let cur_ln = s:get_prev_line(cur_ln)
+ endwhile
+ return s:empty_item()
+endfunction "}}}
+
+"Returns: the last line of a (possibly multiline) item, including all children
+function! s:get_last_line_of_item_incl_children(item) "{{{
+ let cur_ln = a:item.lnum
+ let org_lvl = s:get_level(a:item.lnum)
+ while 1
+ let next_line = s:get_next_line(cur_ln)
+ if next_line == 0 || s:get_level(next_line) <= org_lvl
+ return cur_ln
+ endif
+ let cur_ln = next_line
+ endwhile
+endfunction "}}}
+
+"Returns: the last line of a (possibly multiline) item
+"Note: there can be other list items between the first and last line
+function! s:get_last_line_of_item(item) "{{{
+ if a:item.type == 0 | return 0 | endif
+ let org_lvl = s:get_level(a:item.lnum)
+ let last_corresponding_line = a:item.lnum
+
+ let cur_ln = s:get_next_line(a:item.lnum)
+ while 1
+ if cur_ln == 0 || s:get_level(cur_ln) <= org_lvl
+ break
+ endif
+ let cur_item = s:get_item(cur_ln)
+ if cur_item.type == 0
+ let last_corresponding_line = cur_ln
+ let cur_ln = s:get_next_line(cur_ln)
+ else
+ let cur_ln = s:get_next_line(
+ \ s:get_last_line_of_item_incl_children(cur_item))
+ endif
+ endwhile
+
+ return last_corresponding_line
+endfunction "}}}
+
+"functions for navigating between items }}}
+
+"renumber list items {{{
+"Renumbers the current list from a:item on downwards
+"Returns: the last item that was adjusted
+function! s:adjust_numbered_list_below(item, recursive) "{{{
+ if !(a:item.type == 2 || (a:item.type == 1 && a:recursive))
+ return a:item
+ endif
+
+ let kind = s:guess_kind_of_numbered_item(a:item)
+
+ let cur_item = a:item
+ while 1
+ if a:recursive
+ call s:adjust_items_recursively(cur_item)
+ endif
+
+ let next_item = s:get_next_list_item(cur_item, 0)
+ if next_item.type == 0
+ break
+ endif
+
+ if cur_item.type == 2
+ let new_val = s:increment_{kind}(cur_item.mrkr[:-2]) . cur_item.mrkr[-1:]
+ call s:substitute_string_in_line(next_item.lnum, next_item.mrkr, new_val)
+ let next_item.mrkr = new_val
+ endif
+
+ let cur_item = next_item
+ endwhile
+ return cur_item
+endfunction "}}}
+
+function! s:adjust_items_recursively(parent) "{{{
+ if a:parent.type == 0
+ return s:empty_item()
+ end
+
+ let child_item = s:get_first_child(a:parent)
+ if child_item.type == 0
+ return child_item
+ endif
+ while 1
+ let last_item = s:adjust_numbered_list(child_item, 1, 1)
+
+ let child_item = s:get_next_child_item(a:parent, last_item)
+ if child_item.type == 0
+ return last_item
+ endif
+ endwhile
+endfunction "}}}
+
+"Renumbers the list a:item is in.
+"If a:ignore_kind == 0, only the items which have the same kind of marker as
+"a:item are considered, otherwise all items.
+"Returns: the last item that was adjusted
+function! s:adjust_numbered_list(item, ignore_kind, recursive) "{{{
+ if !(a:item.type == 2 || (a:item.type == 1 && (a:ignore_kind || a:recursive)))
+ return s:empty_item()
+ end
+
+ let first_item = s:get_first_item_in_list(a:item, a:ignore_kind)
+
+ while 1
+ if first_item.type == 2
+ let new_mrkr = s:guess_kind_of_numbered_item(first_item) .
+ \ first_item.mrkr[-1:]
+ call s:substitute_string_in_line(first_item.lnum, first_item.mrkr,
+ \ new_mrkr)
+ let first_item.mrkr = new_mrkr
+ endif
+
+ let last_item = s:adjust_numbered_list_below(first_item, a:recursive)
+
+ let next_first_item = s:get_next_list_item(last_item, 1)
+ if a:ignore_kind == 0 || next_first_item.type == 0
+ return last_item
+ endif
+ let first_item = next_first_item
+ endwhile
+endfunction "}}}
+
+"Renumbers the list the cursor is in
+"also update its parents checkbox state
+function! vimwiki#lst#adjust_numbered_list() "{{{
+ let cur_item = s:get_corresponding_item(line('.'))
+ if cur_item.type == 0 | return | endif
+ call s:adjust_numbered_list(cur_item, 1, 0)
+ call s:update_state(s:get_parent(cur_item))
+endfunction "}}}
+
+"Renumbers all lists of the buffer
+"of course, this might take some seconds
+function! vimwiki#lst#adjust_whole_buffer() "{{{
+ let cur_ln = 1
+ while 1
+ let cur_item = s:get_item(cur_ln)
+ if cur_item.type != 0
+ let cur_item = s:adjust_numbered_list(cur_item, 0, 1)
+ endif
+ let cur_ln = s:get_next_line(cur_item.lnum, 1)
+ if cur_ln <= 0 || cur_ln > line('$')
+ return
+ endif
+ endwhile
+endfunction "}}}
+
+"renumber list items }}}
+
+"checkbox stuff {{{
+
+"Returns: the rate of checkboxed list item in percent
+function! s:get_rate(item) "{{{
+ if a:item.type == 0 || a:item.cb == ''
+ return -1
+ endif
+ let state = a:item.cb
+ if state == vimwiki#vars#get_global('listsym_rejected')
+ return -1
+ endif
+ let n = len(vimwiki#vars#get_syntaxlocal('listsyms_list'))
+ return index(vimwiki#vars#get_syntaxlocal('listsyms_list'), state) * 100/(n-1)
+endfunction "}}}
+
+"Set state of the list item to [ ] or [o] or whatever
+"Returns: 1 if the state changed, 0 otherwise
+function! s:set_state(item, new_rate) "{{{
+ let new_state = s:rate_to_state(a:new_rate)
+ let old_state = s:rate_to_state(s:get_rate(a:item))
+ if new_state !=# old_state
+ call s:substitute_rx_in_line(a:item.lnum, '\[.]', '['.new_state.']')
+ return 1
+ else
+ return 0
+ endif
+endfunction "}}}
+
+"Set state of the list item to [ ] or [o] or whatever
+"Updates the states of its child items
+function! s:set_state_plus_children(item, new_rate) "{{{
+ call s:set_state(a:item, a:new_rate)
+
+ let child_item = s:get_first_child(a:item)
+ while 1
+ if child_item.type == 0
+ break
+ endif
+ if child_item.cb != ''
+ call s:set_state_plus_children(child_item, a:new_rate)
+ endif
+ let child_item = s:get_next_child_item(a:item, child_item)
+ endwhile
+endfunction "}}}
+
+"Returns: the appropriate symbol for a given percent rate
+function! s:rate_to_state(rate) "{{{
+ let listsyms_list = vimwiki#vars#get_syntaxlocal('listsyms_list')
+ let state = ''
+ let n = len(listsyms_list)
+ if a:rate == 100
+ let state = listsyms_list[n-1]
+ elseif a:rate == 0
+ let state = listsyms_list[0]
+ elseif a:rate == -1
+ let state = vimwiki#vars#get_global('listsym_rejected')
+ else
+ let index = float2nr(ceil(a:rate/100.0*(n-2)))
+ let state = listsyms_list[index]
+ endif
+ return state
+endfunction "}}}
+
+"updates the symbol of a checkboxed item according to the symbols of its
+"children
+function! s:update_state(item) "{{{
+ if a:item.type == 0 || a:item.cb == ''
+ return
+ endif
+
+ let sum_children_rate = 0
+ let count_children_with_cb = 0
+
+ let child_item = s:get_first_child(a:item)
+
+ while 1
+ if child_item.type == 0
+ break
+ endif
+ if child_item.cb != ''
+ let rate = s:get_rate(child_item)
+ if rate != -1
+ let count_children_with_cb += 1
+ let sum_children_rate += rate
+ endif
+ endif
+ let child_item = s:get_next_child_item(a:item, child_item)
+ endwhile
+
+ if count_children_with_cb > 0
+ let new_rate = sum_children_rate / count_children_with_cb
+ call s:set_state_recursively(a:item, new_rate)
+ else
+ let rate = s:get_rate(a:item)
+ if rate > 0 && rate < 100
+ call s:set_state_recursively(a:item, 0)
+ endif
+ endif
+endfunction "}}}
+
+function! s:set_state_recursively(item, new_rate) "{{{
+ let state_changed = s:set_state(a:item, a:new_rate)
+ if state_changed
+ call s:update_state(s:get_parent(a:item))
+ endif
+endfunction "}}}
+
+"Creates checkbox in a list item.
+"Returns: 1 if successful
+function! s:create_cb(item) "{{{
+ if a:item.type == 0 || a:item.cb != ''
+ return 0
+ endif
+
+ let new_item = a:item
+ let new_item.cb = vimwiki#vars#get_syntaxlocal('listsyms_list')[0]
+ call s:substitute_rx_in_line(new_item.lnum,
+ \ vimwiki#u#escape(new_item.mrkr) . '\zs\ze', ' [' . new_item.cb . ']')
+
+ call s:update_state(new_item)
+ return 1
+endfunction "}}}
+
+function! s:remove_cb(item) "{{{
+ let item = a:item
+ if item.type != 0 && item.cb != ''
+ let item.cb = ''
+ call s:substitute_rx_in_line(item.lnum, '\s\+\[.\]', '')
+ endif
+ return item
+endfunction "}}}
+
+"Change state of checkbox
+"in the lines of the given range
+function! s:change_cb(from_line, to_line, new_rate) "{{{
+ let from_item = s:get_corresponding_item(a:from_line)
+ if from_item.type == 0
+ return
+ endif
+
+ let parent_items_of_lines = []
+
+ for cur_ln in range(from_item.lnum, a:to_line)
+ let cur_item = s:get_item(cur_ln)
+ if cur_item.type != 0 && cur_item.cb != ''
+ call s:set_state_plus_children(cur_item, a:new_rate)
+ let cur_parent_item = s:get_parent(cur_item)
+ if index(parent_items_of_lines, cur_parent_item) == -1
+ call insert(parent_items_of_lines, cur_parent_item)
+ endif
+ endif
+ endfor
+
+ for parent_item in parent_items_of_lines
+ call s:update_state(parent_item)
+ endfor
+
+endfunction "}}}
+
+"Toggles checkbox between two states in the lines of the given range,
+"creates chceckboxes if there aren't any.
+function! s:toggle_create_cb(from_line, to_line, state1, state2) "{{{
+ let from_item = s:get_corresponding_item(a:from_line)
+ if from_item.type == 0
+ return
+ endif
+
+ if from_item.cb == ''
+
+ "if from_line has no CB, make a CB in every selected line
+ let parent_items_of_lines = []
+ for cur_ln in range(from_item.lnum, a:to_line)
+ let cur_item = s:get_item(cur_ln)
+ let success = s:create_cb(cur_item)
+
+ if success
+ let cur_parent_item = s:get_parent(cur_item)
+ if index(parent_items_of_lines, cur_parent_item) == -1
+ call insert(parent_items_of_lines, cur_parent_item)
+ endif
+ endif
+ endfor
+
+ for parent_item in parent_items_of_lines
+ call s:update_state(parent_item)
+ endfor
+
+ else
+
+ "if from_line has CB, toggle it and set all siblings to the same new state
+ let rate_first_line = s:get_rate(from_item)
+ let new_rate = rate_first_line == a:state1 ? a:state2 : a:state1
+
+ call s:change_cb(a:from_line, a:to_line, new_rate)
+
+ endif
+
+endfunction "}}}
+
+"Decrement checkbox between [ ] and [X]
+"in the lines of the given range
+function! vimwiki#lst#decrement_cb(from_line, to_line) "{{{
+ let from_item = s:get_corresponding_item(a:from_line)
+ if from_item.type == 0
+ return
+ endif
+
+ "if from_line has CB, decrement it and set all siblings to the same new state
+ let rate_first_line = s:get_rate(from_item)
+ let n = len(vimwiki#vars#get_syntaxlocal('listsyms_list'))
+ let new_rate = max([rate_first_line - 100/(n-1)-1, 0])
+
+ call s:change_cb(a:from_line, a:to_line, new_rate)
+
+endfunction "}}}
+
+"Increment checkbox between [ ] and [X]
+"in the lines of the given range
+function! vimwiki#lst#increment_cb(from_line, to_line) "{{{
+ let from_item = s:get_corresponding_item(a:from_line)
+ if from_item.type == 0
+ return
+ endif
+
+ "if from_line has CB, increment it and set all siblings to the same new state
+ let rate_first_line = s:get_rate(from_item)
+ let n = len(vimwiki#vars#get_syntaxlocal('listsyms_list'))
+ let new_rate = min([rate_first_line + 100/(n-1)+1, 100])
+
+ call s:change_cb(a:from_line, a:to_line, new_rate)
+
+endfunction "}}}
+
+"Toggles checkbox between [ ] and [X] or creates one
+"in the lines of the given range
+function! vimwiki#lst#toggle_cb(from_line, to_line) "{{{
+ return s:toggle_create_cb(a:from_line, a:to_line, 100, 0)
+endfunction "}}}
+
+"Toggles checkbox between [ ] and [-] or creates one
+"in the lines of the given range
+function! vimwiki#lst#toggle_rejected_cb(from_line, to_line) "{{{
+ return s:toggle_create_cb(a:from_line, a:to_line, -1, 0)
+endfunction "}}}
+
+"Increment checkbox between [ ] and [X]
+"in the lines of the given range
+function! vimwiki#lst#increment_cb(from_line, to_line) "{{{
+ let from_item = s:get_corresponding_item(a:from_line)
+ if from_item.type == 0
+ return
+ endif
+
+ "if from_line has CB, increment it and set all siblings to the same new state
+ let rate_first_line = s:get_rate(from_item)
+ let n = len(vimwiki#vars#get_syntaxlocal('listsyms_list'))
+ let new_rate = min([rate_first_line + 100/(n-1)+1, 100])
+
+ call s:change_cb(a:from_line, a:to_line, new_rate)
+
+endfunction "}}}
+
+"Toggles checkbox between [ ] and [X] or creates one
+"in the lines of the given range
+function! vimwiki#lst#toggle_cb(from_line, to_line) "{{{
+ return s:toggle_create_cb(a:from_line, a:to_line, 100, 0)
+endfunction "}}}
+
+"Toggles checkbox between [ ] and [-] or creates one
+"in the lines of the given range
+function! vimwiki#lst#toggle_rejected_cb(from_line, to_line) "{{{
+ return s:toggle_create_cb(a:from_line, a:to_line, -1, 0)
+endfunction "}}}
+
+function! vimwiki#lst#remove_cb(first_line, last_line) "{{{
+ let first_item = s:get_corresponding_item(a:first_line)
+ let last_item = s:get_corresponding_item(a:last_line)
+
+ if first_item.type == 0 || last_item.type == 0
+ return
+ endif
+
+ let parent_items_of_lines = []
+ let cur_ln = first_item.lnum
+ while 1
+ if cur_ln <= 0 || cur_ln > last_item.lnum | break | endif
+ let cur_item = s:get_item(cur_ln)
+ if cur_item.type != 0
+ let cur_item = s:remove_cb(cur_item)
+ let cur_parent_item = s:get_parent(cur_item)
+ if index(parent_items_of_lines, cur_parent_item) == -1
+ call insert(parent_items_of_lines, cur_parent_item)
+ endif
+ endif
+ let cur_ln = s:get_next_line(cur_ln)
+ endwhile
+ for parent_item in parent_items_of_lines
+ call s:update_state(parent_item)
+ endfor
+endfunction "}}}
+
+function! vimwiki#lst#remove_cb_in_list() "{{{
+ let first_item = s:get_first_item_in_list(
+ \ s:get_corresponding_item(line('.')), 0)
+
+ let cur_item = first_item
+ while 1
+ let next_item = s:get_next_list_item(cur_item, 0)
+ let cur_item = s:remove_cb(cur_item)
+ if next_item.type == 0
+ break
+ else
+ let cur_item = next_item
+ endif
+ endwhile
+
+ call s:update_state(s:get_parent(first_item))
+endfunction "}}}
+
+"checkbox stuff }}}
+
+"change the level of list items {{{
+
+function! s:set_indent(lnum, new_indent) "{{{
+ if &expandtab
+ let indentstring = repeat(' ', a:new_indent)
+ else
+ let indentstring = repeat('\t', a:new_indent / &tabstop) .
+ \ repeat(' ', a:new_indent % &tabstop)
+ endif
+ call s:substitute_rx_in_line(a:lnum, '^\s*', indentstring)
+endfunction "}}}
+
+function! s:decrease_level(item) "{{{
+ let removed_indent = 0
+ if vimwiki#vars#get_syntaxlocal('recurring_bullets') && a:item.type == 1 &&
+ \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), s:first_char(a:item.mrkr)) > -1
+ if s:string_length(a:item.mrkr) >= 2
+ call s:substitute_string_in_line(a:item.lnum,
+ \ s:first_char(a:item.mrkr), '')
+ let removed_indent = -1
+ endif
+ else
+ let old_indent = indent(a:item.lnum)
+ if &shiftround
+ let new_indent = (old_indent - 1) / vimwiki#u#sw() * vimwiki#u#sw()
+ else
+ let new_indent = old_indent - vimwiki#u#sw()
+ endif
+ call s:set_indent(a:item.lnum, new_indent)
+ let removed_indent = new_indent - old_indent
+ endif
+ return removed_indent
+endfunction "}}}
+
+function! s:increase_level(item) "{{{
+ let additional_indent = 0
+ if vimwiki#vars#get_syntaxlocal('recurring_bullets') && a:item.type == 1 &&
+ \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), s:first_char(a:item.mrkr)) > -1
+ call s:substitute_string_in_line(a:item.lnum, a:item.mrkr, a:item.mrkr .
+ \ s:first_char(a:item.mrkr))
+ let additional_indent = 1
+ else
+ let old_indent = indent(a:item.lnum)
+ if &shiftround
+ let new_indent = (old_indent / vimwiki#u#sw() + 1) * vimwiki#u#sw()
+ else
+ let new_indent = old_indent + vimwiki#u#sw()
+ endif
+ call s:set_indent(a:item.lnum, new_indent)
+ let additional_indent = new_indent - old_indent
+ endif
+ return additional_indent
+endfunction "}}}
+
+"adds a:indent_by to the current indent
+"a:indent_by can be negative
+function! s:indent_line_by(lnum, indent_by) "{{{
+ let item = s:get_item(a:lnum)
+ if vimwiki#vars#get_syntaxlocal('recurring_bullets') && item.type == 1 &&
+ \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), s:first_char(item.mrkr)) > -1
+ if a:indent_by > 0
+ call s:substitute_string_in_line(a:lnum, item.mrkr,
+ \ item.mrkr . s:first_char(item.mrkr))
+ elseif a:indent_by < 0
+ call s:substitute_string_in_line(a:lnum, s:first_char(item.mrkr), '')
+ endif
+ else
+ call s:set_indent(a:lnum, indent(a:lnum) + a:indent_by)
+ endif
+endfunction "}}}
+
+"changes lvl of lines in selection
+function! s:change_level(from_line, to_line, direction, plus_children) "{{{
+ let from_item = s:get_corresponding_item(a:from_line)
+ if from_item.type == 0
+ if a:direction ==# 'increase' && a:from_line == a:to_line &&
+ \ empty(getline(a:from_line))
+ "that's because :> doesn't work on an empty line
+ normal! gi
+ else
+ execute a:from_line.','.a:to_line.(a:direction ==# 'increase' ? '>' : '<')
+ endif
+ return
+ endif
+
+ if a:direction ==# 'decrease' && s:get_level(from_item.lnum) == 0
+ return
+ endif
+
+ if a:from_line == a:to_line
+ if a:plus_children
+ let to_line = s:get_last_line_of_item_incl_children(from_item)
+ else
+ let to_line = s:get_last_line_of_item(from_item)
+ endif
+ else
+ let to_item = s:get_corresponding_item(a:to_line)
+ if to_item.type == 0
+ let to_line = a:to_line
+ else
+ if a:plus_children
+ let to_line = s:get_last_line_of_item_incl_children(to_item)
+ else
+ let to_line = s:get_last_line_of_item(to_item)
+ endif
+ endif
+ endif
+
+ if to_line == 0
+ return
+ endif
+
+ let to_be_adjusted = s:get_a_neighbor_item(from_item)
+ let old_parent = s:get_parent(from_item)
+ let first_line_level = s:get_level(from_item.lnum)
+ let more_than_one_level_concerned = 0
+
+ let first_line_indented_by =
+ \ (a:direction ==# 'increase') ?
+ \ s:increase_level(from_item) : s:decrease_level(from_item)
+
+ let cur_ln = s:get_next_line(from_item.lnum)
+ while cur_ln > 0 && cur_ln <= to_line
+ if !more_than_one_level_concerned &&
+ \ s:get_level(cur_ln) != first_line_level &&
+ \ s:get_item(cur_ln).type != 0
+ let more_than_one_level_concerned = 1
+ endif
+ call s:indent_line_by(cur_ln, first_line_indented_by)
+ let cur_ln = s:get_next_line(cur_ln, 1)
+ endwhile
+
+ if a:from_line == a:to_line
+ call s:adjust_mrkr(from_item)
+ endif
+ call s:update_state(old_parent)
+ let from_item = s:get_item(from_item.lnum)
+ if from_item.cb != ''
+ call s:update_state(from_item)
+ call s:update_state(s:get_parent(from_item))
+ endif
+
+ if more_than_one_level_concerned
+ call vimwiki#lst#adjust_whole_buffer()
+ else
+ call s:adjust_numbered_list(from_item, 0, 0)
+ call s:adjust_numbered_list(to_be_adjusted, 0, 0)
+ endif
+endfunction "}}}
+
+function! vimwiki#lst#change_level(from_line, to_line, direction, plus_children) "{{{
+ let cur_col = col('$') - col('.')
+ call s:change_level(a:from_line, a:to_line, a:direction, a:plus_children)
+ call cursor('.', col('$') - cur_col)
+endfunction "}}}
+
+"indent line a:lnum to be the continuation of a:prev_item
+function! s:indent_multiline(prev_item, lnum) "{{{
+ if a:prev_item.type != 0
+ call s:set_indent(a:lnum, s:text_begin(a:prev_item.lnum))
+ endif
+endfunction "}}}
+
+"change the level of list items }}}
+
+"change markers of list items {{{
+"Returns: the position of a marker in g:vimwiki_list_markers
+function! s:get_idx_list_markers(item) "{{{
+ if a:item.type == 1
+ let m = s:first_char(a:item.mrkr)
+ else
+ let m = s:guess_kind_of_numbered_item(a:item) . a:item.mrkr[-1:]
+ endif
+ return index(vimwiki#vars#get_syntaxlocal('list_markers'), m)
+endfunction "}}}
+
+"changes the marker of the given item to the next in g:vimwiki_list_markers
+function! s:get_next_mrkr(item) "{{{
+ let markers = vimwiki#vars#get_syntaxlocal('list_markers')
+ if a:item.type == 0
+ let new_mrkr = markers[0]
+ else
+ let idx = s:get_idx_list_markers(a:item)
+ let new_mrkr = markers[(idx+1) % len(markers)]
+ endif
+ return new_mrkr
+endfunction "}}}
+
+"changes the marker of the given item to the previous in g:vimwiki_list_markers
+function! s:get_prev_mrkr(item) "{{{
+ let markers = vimwiki#vars#get_syntaxlocal('list_markers')
+ if a:item.type == 0
+ return markers[-1]
+ endif
+ let idx = s:get_idx_list_markers(a:item)
+ if idx == -1
+ return markers[-1]
+ else
+ return markers[(idx - 1 + len(markers)) %
+ \ len(markers)]
+ endif
+endfunction "}}}
+
+function! s:set_new_mrkr(item, new_mrkr) "{{{
+ if a:item.type == 0
+ call s:substitute_rx_in_line(a:item.lnum, '^\s*\zs\ze', a:new_mrkr.' ')
+ if indent(a:item.lnum) == 0 && !vimwiki#vars#get_syntaxlocal('recurring_bullets')
+ call s:set_indent(a:item.lnum, vimwiki#lst#get_list_margin())
+ endif
+ else
+ call s:substitute_string_in_line(a:item.lnum, a:item.mrkr, a:new_mrkr)
+ endif
+endfunction "}}}
+
+function! vimwiki#lst#change_marker(from_line, to_line, new_mrkr, mode) "{{{
+ let cur_col_from_eol = col("$") - (a:mode ==# "i" ? col("'^") : col('.'))
+ let new_mrkr = a:new_mrkr
+ let cur_ln = a:from_line
+ while 1
+ let cur_item = s:get_item(cur_ln)
+
+ if new_mrkr ==# "next"
+ let new_mrkr = s:get_next_mrkr(cur_item)
+ elseif new_mrkr ==# "prev"
+ let new_mrkr = s:get_prev_mrkr(cur_item)
+ endif
+
+ "handle markers like ***
+ if index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), s:first_char(new_mrkr)) > -1
+ "use *** if the item above has *** too
+ let item_above = s:get_prev_list_item(cur_item, 1)
+ if item_above.type == 1 &&
+ \ s:first_char(item_above.mrkr) ==# s:first_char(new_mrkr)
+ let new_mrkr = item_above.mrkr
+ else
+ "use *** if the item below has *** too
+ let item_below = s:get_next_list_item(cur_item, 1)
+ if item_below.type == 1 &&
+ \ s:first_char(item_below.mrkr) ==# s:first_char(new_mrkr)
+ let new_mrkr = item_below.mrkr
+ else
+ "if the old is ### and the new is * use ***
+ if cur_item.type == 1 &&
+ \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), s:first_char(cur_item.mrkr))>-1
+ let new_mrkr = repeat(new_mrkr, s:string_length(cur_item.mrkr))
+ else
+ "use *** if the parent item has **
+ let parent_item = s:get_parent(cur_item)
+ if parent_item.type == 1 &&
+ \ s:first_char(parent_item.mrkr) ==# s:first_char(new_mrkr)
+ let new_mrkr = repeat(s:first_char(parent_item.mrkr),
+ \ s:string_length(parent_item.mrkr)+1)
+ endif
+ endif
+ endif
+ endif
+
+ endif
+
+ call s:set_new_mrkr(cur_item, new_mrkr)
+ call s:adjust_numbered_list(s:get_item(cur_ln), 1, 0)
+
+ if cur_ln >= a:to_line | break | endif
+ let cur_ln = s:get_next_line(cur_ln, 1)
+ endwhile
+
+ call cursor('.', col('$') - cur_col_from_eol)
+endfunction "}}}
+
+function! vimwiki#lst#change_marker_in_list(new_mrkr) "{{{
+ let cur_item = s:get_corresponding_item(line('.'))
+ let first_item = s:get_first_item_in_list(cur_item, 0)
+ let last_item = s:get_last_item_in_list(cur_item, 0)
+ if first_item.type == 0 || last_item.type == 0 | return | endif
+ let first_item_line = first_item.lnum
+
+ let cur_item = first_item
+ while cur_item.type != 0 && cur_item.lnum <= last_item.lnum
+ call s:set_new_mrkr(cur_item, a:new_mrkr)
+ let cur_item = s:get_next_list_item(cur_item, 1)
+ endwhile
+
+ call s:adjust_numbered_list(s:get_item(first_item_line), 0, 0)
+endfunction "}}}
+
+"sets kind of the item depending on neighbor items and the parent item
+function! s:adjust_mrkr(item) "{{{
+ if a:item.type == 0 || vimwiki#vars#get_syntaxlocal('recurring_bullets')
+ return
+ endif
+
+ let new_mrkr = a:item.mrkr
+ let neighbor_item = s:get_a_neighbor_item(a:item)
+ if neighbor_item.type != 0
+ let new_mrkr = neighbor_item.mrkr
+ endif
+
+ "if possible, set e.g. *** if parent has ** as marker
+ if neighbor_item.type == 0 && a:item.type == 1 &&
+ \ index(vimwiki#vars#get_syntaxlocal('multiple_bullet_chars'), s:first_char(a:item.mrkr)) > -1
+ let parent_item = s:get_parent(a:item)
+ if parent_item.type == 1 &&
+ \ s:first_char(parent_item.mrkr) ==# s:first_char(a:item.mrkr)
+ let new_mrkr = repeat(s:first_char(parent_item.mrkr),
+ \ s:string_length(parent_item.mrkr)+1)
+ endif
+ endif
+
+ call s:substitute_string_in_line(a:item.lnum, a:item.mrkr, new_mrkr)
+ call s:adjust_numbered_list(a:item, 0, 1)
+endfunction "}}}
+
+function! s:clone_marker_from_to(from, to) "{{{
+ let item_from = s:get_item(a:from)
+ if item_from.type == 0 | return | endif
+ let new_mrkr = item_from.mrkr . ' '
+ call s:substitute_rx_in_line(a:to, '^\s*', new_mrkr)
+ let new_indent = ( vimwiki#vars#get_syntaxlocal('recurring_bullets') ? 0 : indent(a:from) )
+ call s:set_indent(a:to, new_indent)
+ if item_from.cb != ''
+ call s:create_cb(s:get_item(a:to))
+ call s:update_state(s:get_parent(s:get_item(a:to)))
+ endif
+ if item_from.type == 2
+ let adjust_from = ( a:from < a:to ? a:from : a:to )
+ call s:adjust_numbered_list_below(s:get_item(adjust_from), 0)
+ endif
+endfunction "}}}
+
+function! s:remove_mrkr(item) "{{{
+ let item = a:item
+ if item.cb != ''
+ let item = s:remove_cb(item)
+ let parent_item = s:get_parent(item)
+ else
+ let parent_item = s:empty_item()
+ endif
+ call s:substitute_rx_in_line(item.lnum, vimwiki#u#escape(item.mrkr).'\s*', '')
+ call remove(item, 'mrkr')
+ call remove(item, 'cb')
+ let item.type = 0
+ call s:update_state(parent_item)
+ return item
+endfunction "}}}
+
+function! s:create_marker(lnum) "{{{
+ let new_sibling = s:get_corresponding_item(a:lnum)
+ if new_sibling.type == 0
+ let new_sibling = s:get_a_neighbor_item_in_column(a:lnum, virtcol('.'))
+ endif
+ if new_sibling.type != 0
+ call s:clone_marker_from_to(new_sibling.lnum, a:lnum)
+ else
+ let cur_item = s:get_item(a:lnum)
+ call s:set_new_mrkr(cur_item, vimwiki#vars#get_syntaxlocal('list_markers')[0])
+ call s:adjust_numbered_list(cur_item, 0, 0)
+ endif
+endfunction "}}}
+
+"change markers of list items }}}
+
+"handle keys {{{
+function! vimwiki#lst#kbd_o() "{{{
+ let fold_end = foldclosedend('.')
+ let lnum = (fold_end == -1) ? line('.') : fold_end
+ let cur_item = s:get_item(lnum)
+ "inserting and deleting the x is necessary
+ "because otherwise the indent is lost
+ normal! ox
+ if cur_item.lnum < s:get_last_line_of_item(cur_item)
+ call s:indent_multiline(cur_item, cur_item.lnum+1)
+ else
+ call s:clone_marker_from_to(cur_item.lnum, cur_item.lnum+1)
+ endif
+ startinsert!
+endfunction "}}}
+
+function! vimwiki#lst#kbd_O() "{{{
+ normal! Ox
+ let cur_ln = line('.')
+ if getline(cur_ln+1) !~# '^\s*$'
+ call s:clone_marker_from_to(cur_ln+1, cur_ln)
+ else
+ call s:clone_marker_from_to(cur_ln-1, cur_ln)
+ endif
+ startinsert!
+endfunction "}}}
+
+function! s:cr_on_empty_list_item(lnum, behavior) "{{{
+ if a:behavior == 1
+ "just make a new list item
+ normal! gi
+
+ call s:clone_marker_from_to(a:lnum, a:lnum+1)
+ startinsert!
+ return
+ elseif a:behavior == 2
+ "insert new marker but remove marker in old line
+ call append(a:lnum-1, '')
+ startinsert!
+ return
+ elseif a:behavior == 3
+ "list is finished, but cursor stays in current line
+ let item = s:get_item(a:lnum)
+ let neighbor_item = s:get_a_neighbor_item(item)
+ let child_item = s:get_first_child(item)
+ let parent_item = (item.cb != '') ? s:get_parent(item) : s:empty_item()
normal! "_cc
- call s:adjust_numbered_list(neighbor_item, 0, 0)
- call s:adjust_numbered_list(child_item, 0, 0)
- call s:update_state(parent_item)
- startinsert
- return
- elseif a:behavior == 5
- "successively decrease level
- if s:get_level(a:lnum) > 0
- call s:change_level(a:lnum, a:lnum, 'decrease', 0)
- startinsert!
- else
- let item = s:get_item(a:lnum)
- let neighbor_item = s:get_a_neighbor_item(item)
- let child_item = s:get_first_child(item)
- let parent_item = (item.cb != '') ? s:get_parent(item) : s:empty_item()
- normal! "_cc
- call s:adjust_numbered_list(neighbor_item, 0, 0)
- call s:adjust_numbered_list(child_item, 0, 0)
- call s:update_state(parent_item)
- startinsert
- endif
- return
- endif
-endfunction "}}}
-
-function! s:cr_on_empty_line(lnum, behavior) "{{{
- "inserting and deleting the x is necessary
- "because otherwise the indent is lost
- normal! gix
- if a:behavior == 2 || a:behavior == 3
- call s:create_marker(a:lnum+1)
- endif
-endfunction "}}}
-
-function! s:cr_on_list_item(lnum, insert_new_marker, not_at_eol) "{{{
- if a:insert_new_marker
- "the ultimate feature of this script: make new marker on <CR>
- normal! gi
- call s:clone_marker_from_to(a:lnum, a:lnum+1)
- "tiny sweet extra feature: indent next line if current line ends with :
- if !a:not_at_eol && getline(a:lnum) =~# ':$'
- call s:change_level(a:lnum+1, a:lnum+1, 'increase', 0)
- endif
- else
- " || (cur_item.lnum < s:get_last_line_of_item(cur_item))
- "indent this line so that it becomes the continuation of the line above
- normal! gi
- let prev_line = s:get_corresponding_item(s:get_prev_line(a:lnum+1))
- call s:indent_multiline(prev_line, a:lnum+1)
- endif
-endfunction "}}}
-
-function! vimwiki#lst#kbd_cr(normal, just_mrkr) "{{{
- let lnum = line('.')
- let has_bp = s:line_has_marker(lnum)
-
- if has_bp != 0 && virtcol('.') < s:text_begin(lnum)
- call append(lnum-1, '')
- startinsert!
- return
- endif
-
- if has_bp == 1
- call s:cr_on_empty_list_item(lnum, a:just_mrkr)
- return
- endif
-
- let insert_new_marker = (a:normal == 1 || a:normal == 3)
- if getline('.')[col("'^")-1:] =~# '^\s\+$'
- let cur_col = 0
- else
- let cur_col = col("$") - col("'^")
- if getline('.')[col("'^")-1] =~# '\s' && exists("*strdisplaywidth")
- let ws_behind_cursor =
- \ strdisplaywidth(matchstr(getline('.')[col("'^")-1:], '\s\+'),
- \ virtcol("'^")-1)
- let cur_col -= ws_behind_cursor
- endif
- if insert_new_marker && cur_col == 0 && getline(lnum) =~# '\s$'
- let insert_new_marker = 0
- endif
- endif
-
- if has_bp == 0
- call s:cr_on_empty_line(lnum, a:normal)
- endif
-
- if has_bp == 2
- call s:cr_on_list_item(lnum, insert_new_marker, cur_col)
- endif
-
- call cursor(lnum+1, col("$") - cur_col)
- if cur_col == 0
- startinsert!
- else
- startinsert
- endif
-
-endfunction "}}}
-
-"creates a list item in the current line or removes it
-function! vimwiki#lst#toggle_list_item() "{{{
- let cur_col_from_eol = col("$") - col("'^")
- let cur_item = s:get_item(line('.'))
-
- if cur_item.type == 0
- call s:create_marker(cur_item.lnum)
- else
- let prev_item = s:get_prev_list_item(cur_item, 1)
- if prev_item.type == 0
- let prev_item = s:get_corresponding_item(s:get_prev_line(cur_item.lnum))
- endif
- let cur_item = s:remove_mrkr(cur_item)
- let adjust_prev_item = (prev_item.type == 2 &&
- \ s:get_level(cur_item.lnum) <= s:get_level(prev_item.lnum)) ? 1 : 0
- call s:indent_multiline(prev_item, cur_item.lnum)
- if adjust_prev_item
- call s:adjust_numbered_list_below(prev_item, 0)
- endif
- endif
-
- "set cursor position s.t. it's on the same char as before
- let new_cur_col = col("$") - cur_col_from_eol
- call cursor(cur_item.lnum, new_cur_col >= 1 ? new_cur_col : 1)
-
- if cur_col_from_eol == 0 || getline(cur_item.lnum) =~# '^\s*$'
- startinsert!
- else
- startinsert
- endif
-endfunction "}}}
-
-"handle keys }}}
-
-"misc stuff {{{
-function! vimwiki#lst#TO_list_item(inner, visual) "{{{
- let lnum = prevnonblank('.')
- let item = s:get_corresponding_item(lnum)
- if item.type == 0
- return
- endif
- let from_line = item.lnum
- if a:inner
- let to_line = s:get_last_line_of_item(item)
- else
- let to_line = s:get_last_line_of_item_incl_children(item)
- endif
- normal! V
- call cursor(to_line, 0)
- normal! o
- call cursor(from_line, 0)
-endfunction "}}}
-
-fun! vimwiki#lst#fold_level(lnum) "{{{
- let cur_item = s:get_item(a:lnum)
- if cur_item.type != 0
- let parent_item = s:get_parent(cur_item)
- let child_item = s:get_first_child(cur_item)
- let next_item = s:get_next_child_item(parent_item, cur_item)
- if child_item.type != 0
- return 'a1'
- elseif next_item.type == 0
- return 's1'
- endif
- endif
- return '='
-endf "}}}
-
-"misc stuff }}}
+ call s:adjust_numbered_list(neighbor_item, 0, 0)
+ call s:adjust_numbered_list(child_item, 0, 0)
+ call s:update_state(parent_item)
+ startinsert
+ return
+ elseif a:behavior == 4
+ "list is finished, but cursor goes to next line
+ let item = s:get_item(a:lnum)
+ let neighbor_item = s:get_a_neighbor_item(item)
+ let child_item = s:get_first_child(item)
+ let parent_item = (item.cb != '') ? s:get_parent(item) : s:empty_item()
+ normal! "_cc
+ call s:adjust_numbered_list(neighbor_item, 0, 0)
+ call s:adjust_numbered_list(child_item, 0, 0)
+ call s:update_state(parent_item)
+ startinsert
+ return
+ elseif a:behavior == 5
+ "successively decrease level
+ if s:get_level(a:lnum) > 0
+ call s:change_level(a:lnum, a:lnum, 'decrease', 0)
+ startinsert!
+ else
+ let item = s:get_item(a:lnum)
+ let neighbor_item = s:get_a_neighbor_item(item)
+ let child_item = s:get_first_child(item)
+ let parent_item = (item.cb != '') ? s:get_parent(item) : s:empty_item()
+ normal! "_cc
+ call s:adjust_numbered_list(neighbor_item, 0, 0)
+ call s:adjust_numbered_list(child_item, 0, 0)
+ call s:update_state(parent_item)
+ startinsert
+ endif
+ return
+ endif
+endfunction "}}}
+
+function! s:cr_on_empty_line(lnum, behavior) "{{{
+ "inserting and deleting the x is necessary
+ "because otherwise the indent is lost
+ normal! gi
+x
+ if a:behavior == 2 || a:behavior == 3
+ call s:create_marker(a:lnum+1)
+ endif
+endfunction "}}}
+
+function! s:cr_on_list_item(lnum, insert_new_marker, not_at_eol) "{{{
+ if a:insert_new_marker
+ "the ultimate feature of this script: make new marker on <CR>
+ normal! gi
+
+ call s:clone_marker_from_to(a:lnum, a:lnum+1)
+ "tiny sweet extra feature: indent next line if current line ends with :
+ if !a:not_at_eol && getline(a:lnum) =~# ':$'
+ call s:change_level(a:lnum+1, a:lnum+1, 'increase', 0)
+ endif
+ else
+ " || (cur_item.lnum < s:get_last_line_of_item(cur_item))
+ "indent this line so that it becomes the continuation of the line above
+ normal! gi
+
+ let prev_line = s:get_corresponding_item(s:get_prev_line(a:lnum+1))
+ call s:indent_multiline(prev_line, a:lnum+1)
+ endif
+endfunction "}}}
+
+function! vimwiki#lst#kbd_cr(normal, just_mrkr) "{{{
+ let lnum = line('.')
+ let has_bp = s:line_has_marker(lnum)
+
+ if has_bp != 0 && virtcol('.') < s:text_begin(lnum)
+ call append(lnum-1, '')
+ startinsert!
+ return
+ endif
+
+ if has_bp == 1
+ call s:cr_on_empty_list_item(lnum, a:just_mrkr)
+ return
+ endif
+
+ let insert_new_marker = (a:normal == 1 || a:normal == 3)
+ if getline('.')[col("'^")-1:] =~# '^\s\+$'
+ let cur_col = 0
+ else
+ let cur_col = col("$") - col("'^")
+ if getline('.')[col("'^")-1] =~# '\s' && exists("*strdisplaywidth")
+ let ws_behind_cursor =
+ \ strdisplaywidth(matchstr(getline('.')[col("'^")-1:], '\s\+'),
+ \ virtcol("'^")-1)
+ let cur_col -= ws_behind_cursor
+ endif
+ if insert_new_marker && cur_col == 0 && getline(lnum) =~# '\s$'
+ let insert_new_marker = 0
+ endif
+ endif
+
+ if has_bp == 0
+ call s:cr_on_empty_line(lnum, a:normal)
+ endif
+
+ if has_bp == 2
+ call s:cr_on_list_item(lnum, insert_new_marker, cur_col)
+ endif
+
+ call cursor(lnum+1, col("$") - cur_col)
+ if cur_col == 0
+ startinsert!
+ else
+ startinsert
+ endif
+
+endfunction "}}}
+
+"creates a list item in the current line or removes it
+function! vimwiki#lst#toggle_list_item() "{{{
+ let cur_col_from_eol = col("$") - col("'^")
+ let cur_item = s:get_item(line('.'))
+
+ if cur_item.type == 0
+ call s:create_marker(cur_item.lnum)
+ else
+ let prev_item = s:get_prev_list_item(cur_item, 1)
+ if prev_item.type == 0
+ let prev_item = s:get_corresponding_item(s:get_prev_line(cur_item.lnum))
+ endif
+ let cur_item = s:remove_mrkr(cur_item)
+ let adjust_prev_item = (prev_item.type == 2 &&
+ \ s:get_level(cur_item.lnum) <= s:get_level(prev_item.lnum)) ? 1 : 0
+ call s:indent_multiline(prev_item, cur_item.lnum)
+ if adjust_prev_item
+ call s:adjust_numbered_list_below(prev_item, 0)
+ endif
+ endif
+
+ "set cursor position s.t. it's on the same char as before
+ let new_cur_col = col("$") - cur_col_from_eol
+ call cursor(cur_item.lnum, new_cur_col >= 1 ? new_cur_col : 1)
+
+ if cur_col_from_eol == 0 || getline(cur_item.lnum) =~# '^\s*$'
+ startinsert!
+ else
+ startinsert
+ endif
+endfunction "}}}
+
+"handle keys }}}
+
+"misc stuff {{{
+
+function! vimwiki#lst#setup_marker_infos() "{{{
+ let l:bullet_types=g:vimwiki_bullet_types
+ if exists("g:vimwiki_additional_bullet_types")
+ call extend(l:bullet_types, g:vimwiki_additional_bullet_types)
+ endif
+ let s:rx_bullet_chars = '['.join(keys(l:bullet_types), '').']\+'
+
+ let s:multiple_bullet_chars = []
+ for i in keys(l:bullet_types)
+ if l:bullet_types[i] == 1
+ call add(s:multiple_bullet_chars, i)
+ endif
+ endfor
+
+ let s:number_kinds = []
+ let s:number_divisors = ""
+ for i in g:vimwiki_number_types
+ call add(s:number_kinds, i[0])
+ let s:number_divisors .= vimwiki#u#escape(i[1])
+ endfor
+
+ let s:char_to_rx = {'1': '\d\+', 'i': '[ivxlcdm]\+', 'I': '[IVXLCDM]\+',
+ \ 'a': '\l\{1,2}', 'A': '\u\{1,2}'}
+
+ "create regexp for bulleted list items
+ let g:vimwiki_rxListBullet = join( map(keys(l:bullet_types),
+ \'vimwiki#u#escape(v:val).repeat("\\+", l:bullet_types[v:val])'
+ \ ) , '\|')
+
+ "create regex for numbered list items
+ if !empty(g:vimwiki_number_types)
+ let g:vimwiki_rxListNumber = '\C\%('
+ for type in g:vimwiki_number_types[:-2]
+ let g:vimwiki_rxListNumber .= s:char_to_rx[type[0]] .
+ \ vimwiki#u#escape(type[1]) . '\|'
+ endfor
+ let g:vimwiki_rxListNumber .= s:char_to_rx[g:vimwiki_number_types[-1][0]].
+ \ vimwiki#u#escape(g:vimwiki_number_types[-1][1]) . '\)'
+ else
+ "regex that matches nothing
+ let g:vimwiki_rxListNumber = '$^'
+ endif
+
+ "the user can set the listsyms as string, but vimwiki needs a list
+ let g:vimwiki_listsyms_list = split(g:vimwiki_listsyms, '\zs')
+
+ if match(g:vimwiki_listsyms, g:vimwiki_listsym_rejected) != -1
+ echomsg "Warning: g:vimwiki_listsyms and g:vimwiki_listsym_rejected overlap"
+ endif
+endfunction "}}}
+
+function! vimwiki#lst#TO_list_item(inner, visual) "{{{
+ let lnum = prevnonblank('.')
+ let item = s:get_corresponding_item(lnum)
+ if item.type == 0
+ return
+ endif
+ let from_line = item.lnum
+ if a:inner
+ let to_line = s:get_last_line_of_item(item)
+ else
+ let to_line = s:get_last_line_of_item_incl_children(item)
+ endif
+ normal! V
+ call cursor(to_line, 0)
+ normal! o
+ call cursor(from_line, 0)
+endfunction "}}}
+
+fun! vimwiki#lst#fold_level(lnum) "{{{
+ let cur_item = s:get_item(a:lnum)
+ if cur_item.type != 0
+ let parent_item = s:get_parent(cur_item)
+ let child_item = s:get_first_child(cur_item)
+ let next_item = s:get_next_child_item(parent_item, cur_item)
+ if child_item.type != 0
+ return 'a1'
+ elseif next_item.type == 0
+ return 's1'
+ endif
+ endif
+ return '='
+endf "}}}
+
+"misc stuff }}}
diff --git a/doc/vimwiki.txt b/doc/vimwiki.txt
@@ -1559,6 +1559,10 @@ after a list using letters or vice versa, Vimwiki will get confused because
it cannot distinguish which is which (at least if the types are both upper
case or both lower case).
+You can add additional list-types in your vimrc by setting the variable
+ let g:vimwiki_additional_bullet_types = { "→": 0}
+Corresponding mapings will not be set.
+
See |vimwiki_glstar|, |vimwiki_gl#| |vimwiki_gl-|, |vimwiki_gl-|,
|vimwiki_gl1|, |vimwiki_gla|, |vimwiki_glA|, |vimwiki_gli|, |vimwiki_glI|