vimwiki

Personal wiki for vim
git clone https://github.com/vimwiki/vimwiki.git
Log | Files | Refs | README | LICENSE

commit c9104fc2c171b3ec22f545830785d5acd4739bbf
parent 250fd3c47b0682b97ae4f0d943857f7d9c8310b9
Author: EinfachToll <istjanichtzufassen@googlemail.com>
Date:   Sun, 25 Dec 2016 21:35:56 +0100

Start refactoring the rest -- part 1

Ref #256

Diffstat:
Mautoload/vimwiki/base.vim | 19+++++++++----------
Mautoload/vimwiki/vars.vim | 46++++++++++++++++++++++++++++++----------------
Mplugin/vimwiki.vim | 318+++++++++++++++++++++++--------------------------------------------------------
3 files changed, 129 insertions(+), 254 deletions(-)

diff --git a/autoload/vimwiki/base.vim b/autoload/vimwiki/base.vim @@ -530,7 +530,7 @@ function! vimwiki#base#find_files(wiki_nr, directories_only) " if current wiki is temporary -- was added by an arbitrary wiki file then do " not search wiki files in subdirectories. Or it would hang the system if " wiki file was created in $HOME or C:/ dirs. - if VimwikiGet('temp', wiki_nr) + if vimwiki#vars#get_wikilocal('temp', wiki_nr) let pattern = '*'.ext else let pattern = '**/*'.ext @@ -1290,13 +1290,13 @@ endfunction " }}} " vimwiki#base#goto_index function! vimwiki#base#goto_index(wnum, ...) "{{{ - if a:wnum > len(g:vimwiki_list) - echomsg 'Vimwiki Error: Wiki '.a:wnum.' is not registered in g:vimwiki_list!' + if a:wnum > vimwiki#vars#number_of_wikis() + echomsg 'Vimwiki Error: Wiki '.a:wnum.' is not registered in your Vimwiki settings!' return endif " usually a:wnum is greater then 0 but with the following command it is == 0: - " vim -n -c "exe 'VimwikiIndex' | echo g:vimwiki_current_idx" + " vim -n -c ":VimwikiIndex" if a:wnum > 0 let idx = a:wnum - 1 else @@ -1309,12 +1309,11 @@ function! vimwiki#base#goto_index(wnum, ...) "{{{ let cmd = 'edit' endif - call Validate_wiki_options(idx) - call vimwiki#base#edit_file(cmd, - \ vimwiki#vars#get_wikilocal('path', idx).vimwiki#vars#get_wikilocal('index', idx). - \ vimwiki#vars#get_wikilocal('ext', idx), - \ '') - call vimwiki#base#setup_buffer_state(idx) + let index_file = vimwiki#vars#get_wikilocal('path', idx). + \ vimwiki#vars#get_wikilocal('index', idx). + \ vimwiki#vars#get_wikilocal('ext', idx) + + call vimwiki#base#edit_file(cmd, index_file, '') endfunction "}}} " vimwiki#base#delete_link diff --git a/autoload/vimwiki/vars.vim b/autoload/vimwiki/vars.vim @@ -125,17 +125,21 @@ function! s:populate_wikilocal_options() if exists('g:vimwiki_list') for users_options in g:vimwiki_list - let new_options_dict = {} + let new_wiki_settings = {} for key in keys(default_values) if has_key(users_options, key) - let new_options_dict[key] = users_options[key] + let new_wiki_settings[key] = users_options[key] elseif exists('g:vimwiki_'.key) - let new_options_dict[key] = g:vimwiki_{key} + let new_wiki_settings[key] = g:vimwiki_{key} else - let new_options_dict[key] = default_values[key] + let new_wiki_settings[key] = default_values[key] endif endfor - call add(g:vimwiki_wikilocal_vars, new_options_dict) + + " is it a temporary wiki? No, it's not. + let new_wiki_settings.temp = 0 + + call add(g:vimwiki_wikilocal_vars, new_wiki_settings) endfor endif @@ -148,26 +152,27 @@ function! s:populate_wikilocal_options() let temporary_options_dict[key] = default_values[key] endif endfor - call add(g:vimwiki_wikilocal_vars, default_values) + let temporary_options_dict.temp = 1 + call add(g:vimwiki_wikilocal_vars, temporary_options_dict) - call s:validate_options() + call s:validate_settings() endfunction -function! s:validate_options() - for options_dict in g:vimwiki_wikilocal_vars - let options_dict['path'] = s:normalize_path(options_dict['path']) +function! s:validate_settings() + for wiki_settings in g:vimwiki_wikilocal_vars + let wiki_settings['path'] = s:normalize_path(wiki_settings['path']) - let path_html = options_dict['path_html'] + let path_html = wiki_settings['path_html'] if !empty(path_html) - let options_dict['path_html'] = s:normalize_path(path_html) + let wiki_settings['path_html'] = s:normalize_path(path_html) else - let options_dict['path_html'] = s:normalize_path( - \ substitute(options_dict['path'], '[/\\]\+$', '', '').'_html/') + let wiki_settings['path_html'] = s:normalize_path( + \ substitute(wiki_settings['path'], '[/\\]\+$', '', '').'_html/') endif - let options_dict['template_path'] = s:normalize_path(options_dict['template_path']) - let options_dict['diary_rel_path'] = s:normalize_path(options_dict['diary_rel_path']) + let wiki_settings['template_path'] = s:normalize_path(wiki_settings['template_path']) + let wiki_settings['diary_rel_path'] = s:normalize_path(wiki_settings['diary_rel_path']) endfor endfunction @@ -241,6 +246,15 @@ function! vimwiki#vars#set_wikilocal(key, value, wiki_nr) endfunction +function! vimwiki#vars#add_temporary_wiki(settings) + let new_temp_wiki_settings = copy(g:vimwiki_wikilocal_vars[-1]) + for [key, value] in items(a:settings) + let new_temp_wiki_settings[key] = value + endfor + call insert(g:vimwiki_wikilocal_vars, new_temp_wiki_settings, -1) + call s:validate_settings() +endfunction + " number of registered wikis + temporary function! vimwiki#vars#number_of_wikis() return len(g:vimwiki_wikilocal_vars) - 1 diff --git a/plugin/vimwiki.vim b/plugin/vimwiki.vim @@ -12,127 +12,79 @@ let s:old_cpo = &cpo set cpo&vim -" HELPER functions {{{ -function! s:default(varname, value) "{{{ - if !exists('g:vimwiki_'.a:varname) - let g:vimwiki_{a:varname} = a:value +" this is called when the cursor leaves the buffer +function! s:setup_buffer_leave() "{{{ + " don't do anything if it's not managed by Vimwiki (that is, when it's not in + " a registered wiki and not a temporary wiki) + if vimwiki#vars#get_buffer_var('wiki_nr') == -1 + return endif -endfunction "}}} -function! s:path_html(idx) "{{{ - let path_html = vimwiki#vars#get_wikilocal('path_html', a:idx) - if !empty(path_html) - return path_html - else - let path = vimwiki#vars#get_wikilocal('path', a:idx) - return substitute(path, '[/\\]\+$', '', '').'_html/' - endif -endfunction "}}} + let &autowriteall = s:vimwiki_autowriteall_saved -function! s:normalize_path(path) "{{{ - " resolve doesn't work quite right with symlinks ended with / or \ - let path = substitute(a:path, '[/\\]\+$', '', '') - if path !~# '^scp:' - return resolve(expand(path)).'/' - else - return path.'/' + if vimwiki#vars#get_global('menu') != "" + exe 'nmenu disable '.vimwiki#vars#get_global('menu').'.Table' endif endfunction "}}} -function! Validate_wiki_options(idx) " {{{ - call vimwiki#vars#set_wikilocal('path', s:normalize_path(vimwiki#vars#get_wikilocal('path', a:idx)), a:idx) - call vimwiki#vars#set_wikilocal('path_html', s:normalize_path(s:path_html(a:idx)), a:idx) - call vimwiki#vars#set_wikilocal('template_path', - \ s:normalize_path(vimwiki#vars#get_wikilocal('template_path', a:idx)), a:idx) - call vimwiki#vars#set_wikilocal('diary_rel_path', - \ s:normalize_path(vimwiki#vars#get_wikilocal('diary_rel_path', a:idx)), a:idx) -endfunction " }}} -function! s:vimwiki_idx() " {{{ - if exists('b:vimwiki_idx') - return b:vimwiki_idx - else - return -1 - endif -endfunction " }}} +" create a new temporary wiki for the current buffer +function! s:create_temporary_wiki() + let path = expand('%:p:h') + let ext = '.'.expand('%:e') -function! s:setup_buffer_leave() "{{{ - if &filetype ==? 'vimwiki' - " cache global vars of current state XXX: SLOW!? - call vimwiki#base#cache_buffer_state() + let syntax_mapping = vimwiki#vars#get_global('ext2syntax') + if has_key(syntax_mapping, ext) + let syntax = syntax_mapping[ext] + else + let syntax = vimwiki#vars#get_wikilocal_default('syntax') endif - let &autowriteall = s:vimwiki_autowriteall + let new_temp_wiki_settings = {'path': path, + \ 'ext': ext, + \ 'syntax': syntax, + \ } - " Set up menu - if vimwiki#vars#get_global('menu') != "" - exe 'nmenu disable '.vimwiki#vars#get_global('menu').'.Table' - endif -endfunction "}}} + call vimwiki#vars#add_temporary_wiki(new_temp_wiki_settings) +endfunction -function! s:setup_filetype() "{{{ - " Find what wiki current buffer belongs to. - let path = expand('%:p:h') - let idx = vimwiki#base#find_wiki(path) - if idx == -1 && vimwiki#vars#get_global('global_ext') == 0 - return - endif - "XXX when idx = -1? (an orphan page has been detected) - - "TODO: refactor (same code in setup_buffer_enter) - " The buffer's file is not in the path and user *does* want his wiki - " extension(s) to be global -- Add new wiki. - if idx == -1 - let ext = '.'.expand('%:e') - " lookup syntax using g:vimwiki_ext2syntax - let syn = get(vimwiki#vars#get_global('ext2syntax'), ext, vimwiki#vars#get_wikilocal_default('syntax')) - call add(g:vimwiki_list, {'path': path, 'ext': ext, 'syntax': syn, 'temp': 1}) - let idx = len(g:vimwiki_list) - 1 - call Validate_wiki_options(idx) +" this is called when Vim opens a new buffer with a known wiki extension +function! s:setup_new_wiki_buffer() "{{{ + let wiki_nr = vimwiki#vars#get_bufferlocal('wiki_nr') + if wiki_nr == -1 " it's not in a known wiki directory + if vimwiki#vars#get_global('global_ext') + call s:create_temporary_wiki() + else + " the user does not want a temporary wiki, so do nothing + return + endif endif - " initialize and cache global vars of current state - call vimwiki#base#setup_buffer_state(idx) - unlet! b:vimwiki_fs_rescan + " this makes that ftplugin/vimwiki.vim is sourced set filetype=vimwiki -endfunction "}}} -function! s:setup_buffer_enter() "{{{ - if !vimwiki#base#recall_buffer_state() - " Find what wiki current buffer belongs to. - " If wiki does not exist in g:vimwiki_list -- add new wiki there with - " buffer's path and ext. - " Else set g:vimwiki_current_idx to that wiki index. - let path = expand('%:p:h') - let idx = vimwiki#base#find_wiki(path) - - " The buffer's file is not in the path and user *does NOT* want his wiki - " extension to be global -- Do not add new wiki. - if idx == -1 && vimwiki#vars#get_global('global_ext') == 0 - return - endif + " to force a rescan of the filesystem which may have changed + " and update VimwikiLinks syntax group that depends on it; + " b:vimwiki_fs_rescan indicates that setup_filetype() has not been run + if exists('b:vimwiki_fs_rescan') && vimwiki#vars#get_wikilocal('maxhi') + set syntax=vimwiki + endif + let b:vimwiki_fs_rescan = 1 +endfunction "}}} - "TODO: refactor (same code in setup_filetype) - " The buffer's file is not in the path and user *does* want his wiki - " extension(s) to be global -- Add new wiki. - if idx == -1 - let ext = '.'.expand('%:e') - " lookup syntax using g:vimwiki_ext2syntax - let syn = get(vimwiki#vars#get_global('ext2syntax'), ext, vimwiki#vars#get_wikilocal_default('syntax')) - call add(g:vimwiki_list, {'path': path, 'ext': ext, 'syntax': syn, 'temp': 1}) - let idx = len(g:vimwiki_list) - 1 - call Validate_wiki_options(idx) - endif - " initialize and cache global vars of current state - call vimwiki#base#setup_buffer_state(idx) +" this is called when the cursor enters the buffer +function! s:setup_buffer_enter() "{{{ + " don't do anything if it's not managed by Vimwiki (that is, when it's not in + " a registered wiki and not a temporary wiki) + if vimwiki#vars#get_buffer_var('wiki_nr') == -1 + return endif - " If you have - " au GUIEnter * VimwikiIndex - " Then change it to - " au GUIEnter * nested VimwikiIndex + let s:vimwiki_autowriteall_saved = &autowriteall + let &autowriteall = vimwiki#vars#get_global('autowriteall') + if &filetype == '' set filetype=vimwiki elseif &syntax ==? 'vimwiki' @@ -145,23 +97,23 @@ function! s:setup_buffer_enter() "{{{ let b:vimwiki_fs_rescan = 1 endif - " Settings foldmethod, foldexpr and foldtext are local to window. Thus in a - " new tab with the same buffer folding is reset to vim defaults. So we + " The settings foldmethod, foldexpr and foldtext are local to window. Thus in + " a new tab with the same buffer folding is reset to vim defaults. So we " insist vimwiki folding here. let foldmethod = vimwiki#vars#get_global('folding') if foldmethod ==? 'expr' - setlocal fdm=expr + setlocal foldmethod=expr setlocal foldexpr=VimwikiFoldLevel(v:lnum) setlocal foldtext=VimwikiFoldText() elseif foldmethod ==? 'list' || foldmethod ==? 'lists' - setlocal fdm=expr + setlocal foldmethod=expr setlocal foldexpr=VimwikiFoldListLevel(v:lnum) setlocal foldtext=VimwikiFoldText() elseif foldmethod ==? 'syntax' - setlocal fdm=syntax + setlocal foldmethod=syntax setlocal foldtext=VimwikiFoldText() else - setlocal fdm=manual + setlocal foldmethod=manual normal! zE endif @@ -170,21 +122,15 @@ function! s:setup_buffer_enter() "{{{ let &conceallevel = vimwiki#vars#get_global('conceallevel') endif - " Set up menu - if vimwiki#vars#get_global('menu') != "" - exe 'nmenu enable '.vimwiki#vars#get_global('menu').'.Table' + " lcd as well + if vimwiki#vars#get_global('auto_chdir') + exe 'lcd' vimwiki#vars#get_wikilocal('path') endif -endfunction "}}} -function! s:setup_buffer_reenter() "{{{ - if !vimwiki#base#recall_buffer_state() - " Do not repeat work of s:setup_buffer_enter() and s:setup_filetype() - " Once should be enough ... - endif - if !exists("s:vimwiki_autowriteall") - let s:vimwiki_autowriteall = &autowriteall + " Set up menu + if vimwiki#vars#get_global('menu') !=# '' + exe 'nmenu enable '.vimwiki#vars#get_global('menu').'.Table' endif - let &autowriteall = vimwiki#vars#get_global('autowriteall') endfunction "}}} function! s:setup_cleared_syntax() "{{{ highlight groups that get cleared @@ -200,76 +146,6 @@ function! s:setup_cleared_syntax() "{{{ highlight groups that get cleared endif endfunction "}}} -" OPTION get/set functions {{{ -" return complete list of options -function! VimwikiGetOptionNames() "{{{ - return keys(s:vimwiki_defaults) -endfunction "}}} - -function! VimwikiGetOptions(...) "{{{ - let idx = a:0 == 0 ? g:vimwiki_current_idx : a:1 - let option_dict = {} - for kk in keys(s:vimwiki_defaults) - let option_dict[kk] = VimwikiGet(kk, idx) - endfor - return option_dict -endfunction "}}} - -" Return value of option for current wiki or if second parameter exists for -" wiki with a given index. -" If the option is not found, it is assumed to have been previously cached in a -" buffer local dictionary, that acts as a cache. -" If the option is not found in the buffer local dictionary, an error is thrown -function! VimwikiGet(option, ...) "{{{ - let idx = a:0 == 0 ? g:vimwiki_current_idx : a:1 - - if has_key(g:vimwiki_list[idx], a:option) - let val = g:vimwiki_list[idx][a:option] - elseif has_key(s:vimwiki_defaults, a:option) - let val = s:vimwiki_defaults[a:option] - let g:vimwiki_list[idx][a:option] = val - else - let val = b:vimwiki_list[a:option] - endif - - " XXX no call to vimwiki#base here or else the whole autoload/base gets loaded! - return val -endfunction "}}} - -" Set option for current wiki or if third parameter exists for -" wiki with a given index. -" If the option is not found or recognized (i.e. does not exist in -" s:vimwiki_defaults), it is saved in a buffer local dictionary, that acts -" as a cache. -" If the option is not found in the buffer local dictionary, an error is thrown -function! VimwikiSet(option, value, ...) "{{{ - let idx = a:0 == 0 ? g:vimwiki_current_idx : a:1 - - if has_key(s:vimwiki_defaults, a:option) || - \ has_key(g:vimwiki_list[idx], a:option) - let g:vimwiki_list[idx][a:option] = a:value - elseif exists('b:vimwiki_list') - let b:vimwiki_list[a:option] = a:value - else - let b:vimwiki_list = {} - let b:vimwiki_list[a:option] = a:value - endif - -endfunction "}}} - -" Clear option for current wiki or if second parameter exists for -" wiki with a given index. -" Currently, only works if option was previously saved in the buffer local -" dictionary, that acts as a cache. -function! VimwikiClear(option, ...) "{{{ - let idx = a:0 == 0 ? g:vimwiki_current_idx : a:1 - - if exists('b:vimwiki_list') && has_key(b:vimwiki_list, a:option) - call remove(b:vimwiki_list, a:option) - endif - -endfunction "}}} -" }}} function! s:vimwiki_get_known_extensions() " {{{ " Getting all extensions that different wikis could have @@ -315,38 +191,24 @@ if !exists("*VimwikiWikiIncludeHandler") "{{{ endif "}}} " CALLBACK }}} -" DEFAULT wiki {{{ -let s:vimwiki_defaults = {} - -" is wiki temporary -- was added to g:vimwiki_list by opening arbitrary wiki -" file. -let s:vimwiki_defaults.temp = 0 -"}}} - -" DEFAULT options {{{ -call s:default('list', [s:vimwiki_defaults]) - -call s:default('current_idx', 0) - -for s:idx in range(len(g:vimwiki_list)) - call Validate_wiki_options(s:idx) -endfor -"}}} " AUTOCOMMANDS for all known wiki extensions {{{ -augroup filetypedetect - " clear FlexWiki's stuff - au! * *.wiki -augroup end +let s:known_extensions = s:vimwiki_get_known_extensions() + +if index(s:known_extensions, '.wiki') > -1 + augroup filetypedetect + " clear FlexWiki's stuff + au! * *.wiki + augroup end +endif augroup vimwiki autocmd! - for s:ext in s:vimwiki_get_known_extensions() - exe 'autocmd BufEnter *'.s:ext.' call s:setup_buffer_reenter()' - exe 'autocmd BufWinEnter *'.s:ext.' call s:setup_buffer_enter()' - exe 'autocmd BufLeave,BufHidden *'.s:ext.' call s:setup_buffer_leave()' - exe 'autocmd BufNewFile,BufRead, *'.s:ext.' call s:setup_filetype()' + for s:ext in s:known_extensions + exe 'autocmd BufEnter *'.s:ext.' call s:setup_buffer_enter()' + exe 'autocmd BufNewFile,BufRead *'.s:ext.' call s:setup_new_wiki_buffer()' + exe 'autocmd BufLeave *'.s:ext.' call s:setup_buffer_leave()' exe 'autocmd ColorScheme *'.s:ext.' call s:setup_cleared_syntax()' " Format tables when exit from insert mode. Do not use textwidth to " autowrap tables. @@ -381,44 +243,46 @@ command! VimwikiDiaryGenerateLinks "}}} " MAPPINGS {{{ +let s:map_prefix = vimwiki#vars#get_global('map_prefix') + if !hasmapto('<Plug>VimwikiIndex') - exe 'nmap <silent><unique> '.vimwiki#vars#get_global('map_prefix').'w <Plug>VimwikiIndex' + exe 'nmap <silent><unique> '.s:map_prefix.'w <Plug>VimwikiIndex' endif nnoremap <unique><script> <Plug>VimwikiIndex :VimwikiIndex<CR> if !hasmapto('<Plug>VimwikiTabIndex') - exe 'nmap <silent><unique> '.vimwiki#vars#get_global('map_prefix').'t <Plug>VimwikiTabIndex' + exe 'nmap <silent><unique> '.s:map_prefix.'t <Plug>VimwikiTabIndex' endif nnoremap <unique><script> <Plug>VimwikiTabIndex :VimwikiTabIndex<CR> if !hasmapto('<Plug>VimwikiUISelect') - exe 'nmap <silent><unique> '.vimwiki#vars#get_global('map_prefix').'s <Plug>VimwikiUISelect' + exe 'nmap <silent><unique> '.s:map_prefix.'s <Plug>VimwikiUISelect' endif nnoremap <unique><script> <Plug>VimwikiUISelect :VimwikiUISelect<CR> if !hasmapto('<Plug>VimwikiDiaryIndex') - exe 'nmap <silent><unique> '.vimwiki#vars#get_global('map_prefix').'i <Plug>VimwikiDiaryIndex' + exe 'nmap <silent><unique> '.s:map_prefix.'i <Plug>VimwikiDiaryIndex' endif nnoremap <unique><script> <Plug>VimwikiDiaryIndex :VimwikiDiaryIndex<CR> if !hasmapto('<Plug>VimwikiDiaryGenerateLinks') - exe 'nmap <silent><unique> '.vimwiki#vars#get_global('map_prefix').'<Leader>i <Plug>VimwikiDiaryGenerateLinks' + exe 'nmap <silent><unique> '.s:map_prefix.'<Leader>i <Plug>VimwikiDiaryGenerateLinks' endif nnoremap <unique><script> <Plug>VimwikiDiaryGenerateLinks :VimwikiDiaryGenerateLinks<CR> if !hasmapto('<Plug>VimwikiMakeDiaryNote') - exe 'nmap <silent><unique> '.vimwiki#vars#get_global('map_prefix').'<Leader>w <Plug>VimwikiMakeDiaryNote' + exe 'nmap <silent><unique> '.s:map_prefix.'<Leader>w <Plug>VimwikiMakeDiaryNote' endif nnoremap <unique><script> <Plug>VimwikiMakeDiaryNote :VimwikiMakeDiaryNote<CR> if !hasmapto('<Plug>VimwikiTabMakeDiaryNote') - exe 'nmap <silent><unique> '.vimwiki#vars#get_global('map_prefix').'<Leader>t <Plug>VimwikiTabMakeDiaryNote' + exe 'nmap <silent><unique> '.s:map_prefix.'<Leader>t <Plug>VimwikiTabMakeDiaryNote' endif nnoremap <unique><script> <Plug>VimwikiTabMakeDiaryNote \ :VimwikiTabMakeDiaryNote<CR> if !hasmapto('<Plug>VimwikiMakeYesterdayDiaryNote') - exe 'nmap <silent><unique> '.vimwiki#vars#get_global('map_prefix').'<Leader>y <Plug>VimwikiMakeYesterdayDiaryNote' + exe 'nmap <silent><unique> '.s:map_prefix.'<Leader>y <Plug>VimwikiMakeYesterdayDiaryNote' endif nnoremap <unique><script> <Plug>VimwikiMakeYesterdayDiaryNote \ :VimwikiMakeYesterdayDiaryNote<CR> @@ -427,16 +291,14 @@ nnoremap <unique><script> <Plug>VimwikiMakeYesterdayDiaryNote " MENU {{{ function! s:build_menu(topmenu) - let idx = 0 - while idx < len(g:vimwiki_list) + for idx in range(vimwiki#vars#number_of_wikis()) let norm_path = fnamemodify(vimwiki#vars#get_wikilocal('path', idx), ':h:t') let norm_path = escape(norm_path, '\ \.') execute 'menu '.a:topmenu.'.Open\ index.'.norm_path. - \ ' :call vimwiki#base#goto_index('.(idx + 1).')<CR>' + \ ' :call vimwiki#base#goto_index('.idx.')<CR>' execute 'menu '.a:topmenu.'.Open/Create\ diary\ note.'.norm_path. - \ ' :call vimwiki#diary#make_note('.(idx + 1).')<CR>' - let idx += 1 - endwhile + \ ' :call vimwiki#diary#make_note('.idx.')<CR>' + endfor endfunction function! s:build_table_menu(topmenu)