vimwiki

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

commit 0df6adccc3d2edb6ef79e3695ef5574befa86841
parent c0b56d572b43d485e265f78d93c58855cc1a9965
Author: Maxim Kim <habamax@gmail.com>
Date:   Thu, 15 May 2008 00:00:00 +0000

Version 0.3

DONE: - Highlight non-existent WikiWords.
DONE: - delete current WikiWord (<Leader>wd)
DONE: - g:vimwiki_smartCR=2 => use vim comments (see :h comments :h formatoptions) feature to deal with list items. (thx - Dmitry Alexandrov)
DONE: Add highlighting to TODO:, DONE:, FIXED:.
DONE: Rename current WikiWord - be careful on Windows you cannot rename wikiword to WikiWord. After renaming update all links to that renamed WikiWord
FIXED: Bug - do not duplicate WikiWords in wiki history.
FIXED: after renaming [[wiki word]] twice buffers are not deleted
FIXED: when renaming from [[wiki word]] to WikiWord result is [[WikiWord]]
FIXED: more than one complex words on one line is bugging each other when try go to one of them. [[bla bla bla]] [[dodo dodo dodo]] becomes bla bla bla ]] [[dodo dodo dodo

Diffstat:
Mftplugin/vimwiki.vim | 209+++++++++----------------------------------------------------------------------
Aplugin/vimwiki.vim | 331+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msyntax/vimwiki.vim | 33++++++++++++++++++++++-----------
3 files changed, 376 insertions(+), 197 deletions(-)

diff --git a/ftplugin/vimwiki.vim b/ftplugin/vimwiki.vim @@ -1,11 +1,10 @@ " Vim filetype plugin file " Language: Wiki -" Maintainer: Maxim Kim (habamax at gmail dot com) +" Author: Maxim Kim (habamax at gmail dot com) " Home: http://code.google.com/p/vimwiki/ -" Author: Maxim Kim " Filenames: *.wiki -" Last Change: (07.05.2008 19:25) -" Version: 0.2.2 +" Last Change: (14.05.2008 17:25) +" Version: 0.3pre if exists("b:did_ftplugin") finish @@ -13,8 +12,12 @@ endif let b:did_ftplugin = 1 " Don't load another plugin for this buffer + +"" Defaults +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + " Reset the following options to undo this plugin. -let b:undo_ftplugin = "setl tw< wrap< lbr< fenc< ff< sua< isf< awa<" +let b:undo_ftplugin = "setl tw< wrap< lbr< fenc< ff< sua< isf< awa< com< fo<" setlocal textwidth=0 setlocal wrap @@ -23,183 +26,14 @@ setlocal fileencoding=utf-8 setlocal fileformat=unix setlocal autowriteall " for gf -setlocal suffixesadd=.wiki +execute 'setlocal suffixesadd='.g:vimwiki_ext setlocal isfname-=[,] - -"" Defaults -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -function! s:default(varname,value) - if !exists('g:vimwiki_'.a:varname) - let g:vimwiki_{a:varname} = a:value - endif -endfunction - -"" Could be redefined by users -call s:default('index',"") -call s:default('home',"") -call s:default('upper','A-ZА-Я') -call s:default('lower','a-zа-я') -call s:default('other','0-9_') -call s:default('ext','.wiki') -call s:default('smartCR',1) -call s:default('stripsym','_') - -call s:default('history',[]) - -let upp = g:vimwiki_upper -let low = g:vimwiki_lower -let oth = g:vimwiki_other -let nup = low.oth -let nlo = upp.oth -let any = upp.nup - -let g:vimwiki_word1 = '['.upp.']['.nlo.']*['.low.']['.nup.']*['.upp.']['.any.']*' -let g:vimwiki_word2 = '\[\[['.upp.low.oth.'[:punct:][:space:]]\+\]\]' - -let s:wiki_word = '\C\<'.g:vimwiki_word1.'\>\|'.g:vimwiki_word2 - - -"" Functions {{{ -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -function! s:SearchWord(wikiRx,cmd) - let hl = &hls - let lasts = @/ - let @/ = a:wikiRx - set nohls - try - :silent exe 'normal ' a:cmd - catch /Pattern not found/ - echoh WarningMsg - echo "No WikiWord found." - echoh None - endt - let @/ = lasts - let &hls = hl -endfunction - - -function! s:WikiNextWord() - call s:SearchWord(s:wiki_word, 'n') -endfunction - -function! s:WikiPrevWord() - call s:SearchWord(s:wiki_word, 'N') -endfunction - -function! s:WikiGetWordAtCursor(wikiRX) - let col = col('.') - 1 - let line = getline('.') - let ebeg = -1 - let cont = match(line, a:wikiRX, 0) - while (ebeg >= 0 || (0 <= cont) && (cont <= col)) - let contn = matchend(line, a:wikiRX, cont) - if (cont <= col) && (col < contn) - let ebeg = match(line, a:wikiRX, cont) - let elen = contn - ebeg - break - else - let cont = match(line, a:wikiRX, contn) - endif - endwh - if ebeg >= 0 - return strpart(line, ebeg, elen) - else - return "" - endif -endf - -function! s:WikiStripWord(word, sym) - function! s:WikiStripWordHelper(word, sym) - return substitute(a:word, '[<>|?*/\:"]', a:sym, 'g') - endfunction - - let result = a:word - if strpart(a:word, 0, 2) == "[[" - let result = s:WikiStripWordHelper(strpart(a:word, 2, strlen(a:word)-4), a:sym) - endif - return result -endfunction - - -" Check if word is link to a non-wiki file. -" The easiest way is to check if it has extension like .txt or .html -function! s:WikiLinkToNonWikiFile(word) - if a:word =~ '\..\{1,4}$' - return 1 - endif - return 0 -endfunction - -if !exists('*s:WikiFollowWord') - function! s:WikiFollowWord(split) - if a:split == "split" - let cmd = ":split " - elseif a:split == "vsplit" - let cmd = ":vsplit " - else - let cmd = ":e " - endif - let word = s:WikiStripWord(s:WikiGetWordAtCursor(s:wiki_word), g:vimwiki_stripsym) - " insert doesn't work properly inside :if. Check :help :if. - if word == "" - execute "normal! \n" - return - endif - if s:WikiLinkToNonWikiFile(word) - execute cmd.word - else - " history is [['WikiWord.wiki', 11], ['AnotherWikiWord', 3] ... etc] - " where numbers are column positions we should return when coming back. - call insert(g:vimwiki_history, [expand('%:p'), col('.')]) - execute cmd.g:vimwiki_home.word.g:vimwiki_ext - endif - endfunction - - function! s:WikiGoBackWord() - if len(g:vimwiki_history) > 0 - let word = remove(g:vimwiki_history, 0) - " go back to saved WikiWord - execute ":e ".get(word, 0) - call cursor(line('.'), get(word,1)) - endif - endfunction +if g:vimwiki_smartCR>=2 + setlocal comments=b:*,b:# + setlocal formatoptions=ctnqro endif -function! s:WikiNewLine() - function! WikiAutoListItemInsert(listSym) - let sym = escape(a:listSym, '*') - let prevline = getline(line('.')-1) - if prevline =~ '^\s*'.sym - let curline = substitute(getline('.'),'^\s\+',"","g") - if prevline =~ '^\s*'.sym.'\s*$' - " there should be easier way ... - execute 'normal kA '."\<ESC>".'"_dF'.a:listSym.'JX' - return 1 - endif - let ind = indent(line('.')-1) - call setline(line('.'), strpart(prevline, 0, ind).a:listSym.' '.curline) - call cursor(line('.'), ind+3) - return 1 - endif - return 0 - endfunction - - if WikiAutoListItemInsert('*') - return - endif - - if WikiAutoListItemInsert('#') - return - endif - - " delete <space> - execute 'normal x' -endfunction - - -" Functions }}} - "" Keybindings {{{ """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" nmap <buffer> <Up> gk @@ -215,15 +49,18 @@ vmap <buffer> j gj imap <buffer> <Down> <C-o>gj imap <buffer> <Up> <C-o>gk -nmap <buffer> <CR> :call <SID>WikiFollowWord('nosplit')<CR> -nmap <buffer> <S-CR> :call <SID>WikiFollowWord('split')<CR> -nmap <buffer> <C-CR> :call <SID>WikiFollowWord('vsplit')<CR> -nmap <buffer> <BS> :call <SID>WikiGoBackWord()<CR> +nmap <silent><buffer> <CR> :call WikiFollowWord('nosplit')<CR> +nmap <silent><buffer> <S-CR> :call WikiFollowWord('split')<CR> +nmap <silent><buffer> <C-CR> :call WikiFollowWord('vsplit')<CR> +nmap <silent><buffer> <BS> :call WikiGoBackWord()<CR> + +nmap <silent><buffer> <TAB> :call WikiNextWord()<CR> +nmap <silent><buffer> <S-TAB> :call WikiPrevWord()<CR> -nmap <buffer> <TAB> :call <SID>WikiNextWord()<CR> -nmap <buffer> <S-TAB> :call <SID>WikiPrevWord()<CR> +nmap <silent><buffer> <Leader>wd :call WikiDeleteWord()<CR> +nmap <silent><buffer> <Leader>wr :call WikiRenameWord()<CR> -if g:vimwiki_smartCR - inoremap <CR> <CR> <C-O>:call <SID>WikiNewLine()<CR> +if g:vimwiki_smartCR==1 + inoremap <silent><buffer><CR> <CR><Space><C-O>:call WikiNewLine()<CR> endif " Keybindings }}} diff --git a/plugin/vimwiki.vim b/plugin/vimwiki.vim @@ -0,0 +1,331 @@ +" VimWiki plugin file +" Language: Wiki +" Author: Maxim Kim (habamax at gmail dot com) +" Home: http://code.google.com/p/vimwiki/ +" Filenames: *.wiki +" Last Change: (14.05.2008 17:24) +" Version: 0.3 pre + + +if exists("loaded_vimwiki") || &cp + finish +endif +let loaded_vimwiki = 1 + +let s:save_cpo = &cpo +set cpo&vim + + +function! s:default(varname,value) + if !exists('g:vimwiki_'.a:varname) + let g:vimwiki_{a:varname} = a:value + endif +endfunction + +"" Could be redefined by users +call s:default('home',"") +call s:default('index',"index") +call s:default('ext','.wiki') +call s:default('upper','A-ZА-Я') +call s:default('lower','a-zа-я') +call s:default('maxhi','1') +call s:default('other','0-9_') +call s:default('smartCR',1) +call s:default('stripsym','_') + +call s:default('history',[]) + +let upp = g:vimwiki_upper +let low = g:vimwiki_lower +let oth = g:vimwiki_other +let nup = low.oth +let nlo = upp.oth +let any = upp.nup + +let g:vimwiki_word1 = '\C['.upp.']['.nlo.']*['.low.']['.nup.']*['.upp.']['.any.']*' +let g:vimwiki_word2 = '\[\[['.upp.low.oth.'[:punct:][:space:]]\{-}\]\]' + +let s:wiki_word = '\<'.g:vimwiki_word1.'\>\|'.g:vimwiki_word2 +let s:wiki_badsymbols = '[<>|?*/\:"]' + +execute 'autocmd! BufNewFile,BufReadPost,BufEnter *'.g:vimwiki_ext.' set ft=vimwiki' + + +"" Functions {{{ +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +function! s:msg(message)"{{{ + echohl WarningMsg + echomsg 'vimwiki: '.a:message + echohl None +endfunction"}}} + +function! s:SearchWord(wikiRx,cmd)"{{{ + let hl = &hls + let lasts = @/ + let @/ = a:wikiRx + set nohls + try + :silent exe 'normal ' a:cmd + catch /Pattern not found/ + call s:msg('WikiWord not found') + endt + let @/ = lasts + let &hls = hl +endfunction"}}} + +function! WikiNextWord()"{{{ + call s:SearchWord(s:wiki_word, 'n') +endfunction"}}} + +function! WikiPrevWord()"{{{ + call s:SearchWord(s:wiki_word, 'N') +endfunction"}}} + +function! s:WikiGetWordAtCursor(wikiRX) "{{{ + let col = col('.') - 1 + let line = getline('.') + let ebeg = -1 + let cont = match(line, a:wikiRX, 0) + while (ebeg >= 0 || (0 <= cont) && (cont <= col)) + let contn = matchend(line, a:wikiRX, cont) + if (cont <= col) && (col < contn) + let ebeg = match(line, a:wikiRX, cont) + let elen = contn - ebeg + break + else + let cont = match(line, a:wikiRX, contn) + endif + endwh + if ebeg >= 0 + return strpart(line, ebeg, elen) + else + return "" + endif +endf "}}} + +function! s:WikiStripWord(word, sym)"{{{ + function! s:WikiStripWordHelper(word, sym) + return substitute(a:word, s:wiki_badsymbols, a:sym, 'g') + endfunction + + let result = a:word + if strpart(a:word, 0, 2) == "[[" + let result = s:WikiStripWordHelper(strpart(a:word, 2, strlen(a:word)-4), a:sym) + endif + return result +endfunction"}}} + +" Check if word is link to a non-wiki file. +" The easiest way is to check if it has extension like .txt or .html +function! s:WikiIsLinkToNonWikiFile(word)"{{{ + if a:word =~ '\..\{1,4}$' + return 1 + endif + return 0 +endfunction"}}} + +" history is [['WikiWord.wiki', 11], ['AnotherWikiWord', 3] ... etc] +" where numbers are column positions we should return when coming back. +"" WikiWord history helper functions {{{2 +function! s:GetHistoryWord(historyItem) + return get(a:historyItem, 0) +endfunction +function! s:GetHistoryColumn(historyItem) + return get(a:historyItem, 1) +endfunction +"2}}} + +function! WikiFollowWord(split)"{{{ + if a:split == "split" + let cmd = ":split " + elseif a:split == "vsplit" + let cmd = ":vsplit " + else + let cmd = ":e " + endif + let word = s:WikiStripWord(s:WikiGetWordAtCursor(s:wiki_word), g:vimwiki_stripsym) + " insert doesn't work properly inside :if. Check :help :if. + if word == "" + execute "normal! \n" + return + endif + if s:WikiIsLinkToNonWikiFile(word) + execute cmd.word + else + call insert(g:vimwiki_history, [expand('%:p'), col('.')]) + execute cmd.g:vimwiki_home.word.g:vimwiki_ext + endif +endfunction"}}} + +function! WikiGoBackWord() "{{{ + if !empty(g:vimwiki_history) + let word = remove(g:vimwiki_history, 0) + " go back to saved WikiWord + execute ":e ".s:GetHistoryWord(word) + call cursor(line('.'), s:GetHistoryColumn(word)) + endif +endfunction "}}} + +function! WikiNewLine() "{{{ + function! s:WikiAutoListItemInsert(listSym) + let sym = escape(a:listSym, '*') + let prevline = getline(line('.')-1) + if prevline =~ '^\s\+'.sym + let curline = substitute(getline('.'),'^\s\+',"","g") + if prevline =~ '^\s*'.sym.'\s*$' + " there should be easier way ... + execute 'normal kA '."\<ESC>".'"_dF'.a:listSym.'JX' + return 1 + endif + let ind = indent(line('.')-1) + call setline(line('.'), strpart(prevline, 0, ind).a:listSym.' '.curline) + call cursor(line('.'), ind+3) + return 1 + endif + return 0 + endfunction + + if s:WikiAutoListItemInsert('*') + return + endif + + if s:WikiAutoListItemInsert('#') + return + endif + + " delete <space> + execute 'normal x' +endfunction "}}} + +"" file system funcs +"" Delete WikiWord you are in from filesystem +function! WikiDeleteWord()"{{{ + let val = input('Delete ['.expand('%').'] (y/n)? ', "") + if val!='y' + return + endif + let fname = expand('%:p') + " call WikiGoBackWord() + call delete(fname) + execute "bwipeout ".escape(fname, " ") + " delete from g:vimwiki_history list + call filter (g:vimwiki_history, 's:GetHistoryWord(v:val) != fname') + " as we got back to previous WikiWord - delete it from history - as much + " as possible + let hword = s:GetHistoryWord(remove(g:vimwiki_history, 0)) + while !empty(g:vimwiki_history) && hword == s:GetHistoryWord(g:vimwiki_history[0]) + let hword = s:GetHistoryWord(remove(g:vimwiki_history, 0)) + endwhile + + " reread buffer => deleted WikiWord should appear as non-existent + execute "e" +endfunction"}}} + +"" Rename WikiWord, update all links to renamed WikiWord +function! WikiRenameWord() "{{{ + let wwtorename = expand('%:r') + let isOldWordComplex = 0 + if wwtorename !~ g:vimwiki_word1 + let isOldWordComplex = 1 + endif + + " there is no file (new one maybe) + if glob(g:vimwiki_home.expand('%')) == '' + call s:msg('Cannot rename "'.expand('%').'". It does not exist!') + return + endif + + let val = input('Rename "'.expand('%:r').'" (y/n)? ', "") + if val!='y' + return + endif + let newWord = input('Enter new name: ', "") + " check newWord - it should be 'good', not empty + if substitute(newWord, '\s', '', 'g') == '' + call s:msg('Cannot rename to an empty filename!') + return + endif + if s:WikiIsLinkToNonWikiFile(newWord) + call s:msg('Cannot rename to a filename with extension (ie .txt .html)!') + return + endif + + if newWord !~ g:vimwiki_word1 + " if newWord is 'complex wiki word' then add [[]] + let newWord = '[['.newWord.']]' + endif + let newFileName = s:WikiStripWord(newWord, g:vimwiki_stripsym).g:vimwiki_ext + + " do not rename if word with such name exists + let fname = glob(g:vimwiki_home.newFileName) + if fname != '' + call s:msg('Cannot rename to "'.newFileName.'". File with that name exist!') + return + endif + " rename WikiWord file + try + call rename(expand('%'), newFileName) + bd + execute 'e '.newFileName + catch /.*/ + call s:msg('Cannot rename "'.expand('%:r').'" to "'.newFileName.'"') + return + endtry + + " save open buffers + let openbuffers = [] + let bcount = 1 + while bcount<=bufnr("$") + if bufexists(bcount) + call add(openbuffers, bufname(bcount)) + endif + let bcount = bcount + 1 + endwhile + + " update links + execute ':args '.g:vimwiki_home.'*'.g:vimwiki_ext + if isOldWordComplex + execute ':silent argdo %s/\[\['.wwtorename.'\]\]/'.newWord.'/geI | update' + else + execute ':silent argdo %s/\<'.wwtorename.'\>/'.newWord.'/geI | update' + endif + execute ':argd *'.g:vimwiki_ext + + " restore open buffers + let bcount = 1 + while bcount<=bufnr("$") + if bufexists(bcount) + if index(openbuffers, bufname(bcount)) == -1 + execute 'silent bwipeout '.escape(bufname(bcount), " ") + end + endif + let bcount = bcount + 1 + endwhile + + "" DONE: after renaming GUI caption is a bit corrupted? + "" FIXME: buffers menu is also not in the "normal" state, howto Refresh menu? + +endfunction "}}} + +function! WikiHighlightWords()"{{{ + let wikies = glob(g:vimwiki_home.'*') + let wikies = substitute(wikies, '\'.g:vimwiki_ext, "", "g") + let g:vimwiki_wikiwords = split(wikies, '\n') + call map(g:vimwiki_wikiwords, 'substitute(v:val, ''.*[/\\]'', "", "g")') + for word in g:vimwiki_wikiwords + if word =~ g:vimwiki_word1 && !s:WikiIsLinkToNonWikiFile(word) + execute 'syntax match wikiWord /\<'.word.'\>/' + else + execute 'syntax match wikiWord /\[\['.substitute(word, g:vimwiki_stripsym, s:wiki_badsymbols, "g").'\]\]/' + endif + endfor +endfunction "}}} + +function! WikiGoHome()"{{{ + execute ':e '.g:vimwiki_home.g:vimwiki_index.g:vimwiki_ext + let g:vimwiki_history = [] +endfunction"}}} + +" Functions }}} + +nmap <silent><unique> <Leader>ww :call WikiGoHome()<CR> diff --git a/syntax/vimwiki.vim b/syntax/vimwiki.vim @@ -1,12 +1,10 @@ " Vim syntax file " Language: Wiki -" Maintainer: Maxim Kim (habamax at gmail dot com) +" Author: Maxim Kim (habamax at gmail dot com) " Home: http://code.google.com/p/vimwiki/ -" Author: Maxim Kim " Filenames: *.wiki -" Last Change: (07.05.2008 19:25) -" Version: 0.2.2 -" Based on FlexWiki +" Last Change: (14.05.2008 17:25) +" Version: 0.3pre " Quit if syntax file is already loaded if version < 600 @@ -15,10 +13,20 @@ elseif exists("b:current_syntax") finish endif -" A WikiWord (unqualifiedWikiName) -execute 'syntax match wikiWord /'.g:vimwiki_word1.'/' -" A [bracketed wiki word] -execute 'syntax match wikiWord /'.g:vimwiki_word2.'/' +"" use max highlighting - could be quite slow if there are too many wikifiles +if g:vimwiki_maxhi + " Every WikiWord is nonexistent + execute 'syntax match wikiNoExistsWord /'.g:vimwiki_word1.'/' + execute 'syntax match wikiNoExistsWord /'.g:vimwiki_word2.'/' + " till we find them in g:vimwiki_home + call WikiHighlightWords() +else + " A WikiWord (unqualifiedWikiName) + execute 'syntax match wikiWord /'.g:vimwiki_word1.'/' + " A [[bracketed wiki word]] + execute 'syntax match wikiWord /'.g:vimwiki_word2.'/' +endif + " text: "this is a link (optional tooltip)":http://www.microsoft.com " TODO: check URL syntax against RFC @@ -69,9 +77,12 @@ syntax match wikiTable /||/ " highlight only bullets and digits. syntax match wikiList /^\s\+\(\*\|[1-9]\+0*\.\|#\)/ +syntax match wikiTodo /\(TODO:\|DONE:\|FIXME:\|FIXED:\)/ + " Treat all other lines that start with spaces as PRE-formatted text. syntax match wikiPre /^\s\+[^[:blank:]*#].*$/ +syntax region wikiPre start=/^{{{\s*$/ end=/^}}}\s*$/ " Link FlexWiki syntax items to colors hi def link wikiH1 Title @@ -87,6 +98,7 @@ hi def wikiItalic term=italic cterm=italic gui=italic hi def link wikiCode PreProc hi def link wikiWord Underlined +hi def link wikiNoExistsWord Error hi def link wikiEscape Todo hi def link wikiPre PreProc @@ -99,8 +111,7 @@ hi def link wikiInsText Constant hi def link wikiSuperScript Constant hi def link wikiSubScript Constant hi def link wikiCitation Constant - -hi def link wikiSingleLineProperty Identifier +hi def link wikiTodo Todo let b:current_syntax="vimwiki"