lib/soywiki.vim in soywiki-0.0.1 vs lib/soywiki.vim in soywiki-0.0.2

- old
+ new

@@ -1,18 +1,19 @@ " Vim script that turns Vim into a personal wiki " Maintainer: Daniel Choi <dhchoi@gmail.com> " License: MIT License (c) 2011 Daniel Choi -" this matched namedspaced WikiWords, top-level WikiWords, and relative .WikiWords in a -" namespace -let s:wiki_link_pattern = '\C\<\([a-z]\+\.\)\?[A-Z][a-z]\+[A-Z]\w*\>\|\.[A-Z][a-z]\+[A-Z]\w*\>' +" This regex matches namedspaced WikiWords, top-level WikiWords, and relative +" .WikiWords in a namespace +let s:wiki_link_pattern = '\C\<\([a-z][[:alnum:]_]\+\.\)\?[A-Z][a-z]\+[A-Z]\w*\>\|\.[A-Z][a-z]\+[A-Z]\w*\>' let s:rename_links_command = 'soywiki-rename ' let s:find_pages_linking_in_command = 'soywiki-pages-linking-in ' +let s:expand_command = 'soywiki-expand ' +let s:ls_command = 'soywiki-ls-t ' let s:search_for_link = "" - func! s:trimString(string) let string = substitute(a:string, '\s\+$', '', '') return substitute(string, '^\s\+', '', '') endfunc @@ -32,33 +33,46 @@ else return a:page_title endif endfunc +func! s:namespace_of_title(page_title) + if len(split(a:page_title, '\.')) == 2 + return get(split(a:page_title, '\.'), 0) + else + "" + endif +endfunc + + func! s:is_wiki_page() - let title_line = getline(1) - return (match(title_line, s:wiki_link_pattern) == 0) + return (match(getline(1), s:wiki_link_pattern) == 0) endfunc -func! s:save_page() -" write + +func! s:page_title2file(page) + return substitute(a:page, '\.', '/', 'g') endfunc +func! s:filename2pagetitle(page) + return substitute(a:page, '/', '.', 'g') +endfunc + func! s:list_pages() let s:search_for_link = "" call s:get_page_list() call s:page_list_window("CompletePageInSelectionWindow", "Select page: ") endfunc func! s:link_under_cursor() let link = expand("<cWORD>") + " strip off non-letters at the end (e.g., a comma) let link = substitute(link, '[^[:alnum:]]*$', '', '') - " see if he have a namespaced link + " see if we have a link relative to the namespace if (match(link, '^\.')) == 0 " find the namespace from the page title - let link = s:page_namespace() . link + let link = s:page_namespace() . link " this link already has a period at the beginning endif - let link = substitute(link, '^[^\.[:alnum:]]', '', '') " link may begin with period return link endfunc " follows a camel case link to a new page @@ -87,41 +101,58 @@ end return s:link_under_cursor() endfunc func! s:load_page(page, split) - let page = a:page if (s:is_wiki_page()) write endif - if (!filereadable(page)) + + let file = s:page_title2file(a:page) + + if (!filereadable(file)) " create the file - call writefile([a:page, '', ''], page) + let namespace = s:namespace_of_title(a:page) + if len(namespace) > 0 + call system("mkdir -p " . namespace) + endif + call writefile([a:page, '', ''], file) endif if (a:split == 2) - exec "vsplit ". page + exec "vsplit ". file else - exec "split ". page + exec "split ". file endif if (a:split == 0) wincmd p close endif + + if len(s:search_for_link) > 0 + let res = search(s:search_for_link, 'cw') + let s:search_for_link = '' + endif endfunc +func! s:load_most_recently_modified_page() + let pages = split(system(s:ls_command), "\n") + let start_page = len(pages) > 0 ? get(pages, 0) : "HomePage" + call s:load_page(start_page, 0) +endfunc + func! s:delete_page() let file = bufname('%') let bufnr = bufnr('%') call delete(file) call system("git commit " . bufname('%') . " -m 'deletion'") " go to most recently saved - " call feedkeys("\<C-o>") - let target = s:trimString(system("ls -t | head -1")) + let target = s:trimString(system(s:ls_command . " | head -1")) exec "e " . target exec "bdelete " . bufnr redraw echom "Deleted " . file + call s:load_most_recently_modified_page() endfunc func! s:prompt_for_wiki_word(prompt, default) let input = s:trimString(input(a:prompt, a:default)) while match(input, s:wiki_link_pattern) == -1 @@ -129,33 +160,38 @@ endwhile return input endfunc func! s:rename_page() - let file = bufname('%') - let newname = s:prompt_for_wiki_word("Rename file: ", l:file) - if (filereadable(newname)) - exe "echom '" . newname . " already exists!'" + let oldfile = bufname('%') + let newfile = s:page_title2file( s:prompt_for_wiki_word("Rename oldfile: ", l:oldfile) ) + if (oldfile == newfile) + echo "Canceled" return endif - call system("git mv " . l:file . " " . newname) - exec "e ". newname + if (filereadable(newfile)) + exe "echom '" . newfile . " already exists!'" + return + endif + call system("git mv " . l:oldfile . " " . newfile) + exec "e ". newfile " replace all existing inbound links " TODO replace this with a ruby script - call system(s:rename_links_command . file . " " . newname) + exec "! " . s:rename_links_command . oldfile . " " . newfile call system("git commit -am 'rename wiki page'") e! endfunc func! s:create_page() - let newname = s:prompt_for_wiki_word("New page title: ", "") - if (filereadable(newname)) - exe "echom '" . newname . " already exists!'" + let title = s:prompt_for_wiki_word("New page title: ", "") + let newfile = s:page_title2file(title) + if (filereadable(newfile)) + exe "echom '" . newfile . " already exists!'" return endif - call writefile([newname, '', ''], newname) - exec "e ". newname + call writefile([s:filename2pagetitle(title), '', ''], newfile) + exec "e ". newfile endfunc func! s:save_revision() call system("git add " . bufname('%')) call system("git commit " . bufname('%') . " -m 'edit'") @@ -169,22 +205,22 @@ exec ":!git log --color-words -p " . bufname('%') end endfunc func! s:show_blame() - exec ":!git blame " . bufname('%') + exec ":! git blame --date=relative " . bufname('%') endfunc " ------------------------------------------------------------------------------- " select Page func! s:get_page_list() if len(bufname('%')) == 0 - let s:page_list = split(system("ls -t"), "\n") + let s:page_list = split(system(s:ls_command), "\n") else - let s:page_list = split(system("ls -t | grep -vF '" . bufname('%') . "'" ), "\n") + let s:page_list = split(system(s:ls_command . " | grep -vF '" . bufname('%') . "'" ), "\n") endif endfunction func! s:pages_in_this_namespace(pages) let namespace = s:page_namespace() @@ -214,18 +250,21 @@ return endif endfunc function! s:page_list_window(complete_function, prompt) + " remember the original window + let s:return_to_winnr = winnr() topleft split page-list-buffer setlocal buftype=nofile setlocal noswapfile setlocal modifiable resize 1 inoremap <silent> <buffer> <cr> <Esc>:call <SID>select_page()<CR> inoremap <buffer> <Tab> <Esc>:call <SID>reduce_matches()<cr> noremap <buffer> q <Esc>:close<cr> + inoremap <buffer> <Esc> <Esc>:close<cr> exec "setlocal completefunc=" . a:complete_function " c-p clears the line call setline(1, a:prompt) normal $ call feedkeys("a\<c-x>\<c-u>\<c-p>", 't') @@ -290,25 +329,21 @@ endfun function! s:select_page() let page = s:trimString( get(split(getline(line('.')), ": "), 1) ) close + exe s:return_to_winnr . "wincmd w" if (page == '0' || page == '') " no selection return end let match = "" for item in s:matching_pages if (item == page) call s:load_page(page, 0) - break end endfor - echo s:search_for_link - if len(s:search_for_link) > 0 - call search('\<' . s:search_for_link . '\>') - endif endfunction "------------------------------------------------------------------------ " PAGES LINKING IN " @@ -317,15 +352,11 @@ func! s:list_pages_linking_in() let s:pages_linking_in = split(system(s:find_pages_linking_in_command . s:page_title()), "\n") let s:search_for_link = s:title_without_namespace( s:page_title()) if len(s:pages_linking_in) == 1 - let file = get(s:pages_linking_in, 0) - write - exec "e " . file - " not perfectly targeted but OK for now - call search(s:search_for_link) + call s:load_page(get(s:pages_linking_in, 0), 0) elseif len(s:pages_linking_in) == 0 echom "No pages link to " . s:page_title() . "!" else call s:page_list_window("CompletePagesLinkingIn_InSelectionWindow", "Pages that link to " . s:page_title() . ": ") endif @@ -357,20 +388,104 @@ endif endif endfun "------------------------------------------------------------------------ +" This appends the selected text (use visual-mode) to the page selected +" in the page selection window. +func! s:extract(...) range + if a:0 != 3 + return s:error("Incorrect number of arguments") + endif + + let first = a:firstline + let last = a:lastline + let file = a:1 + + if match(file, s:wiki_link_pattern) == -1 + echom "Target page must be a WikiWord!" + return + endif + + let mode = a:2 " append or insert + let link = a:3 " replace with link ? + let range = first.",".last + silent exe range."yank" + if link + let replacement = s:filename2pagetitle(file) + silent exe "norm! :".first.",".last."change\<CR>".replacement."\<CR>.\<CR>" + else + " this one just deletes the line + silent exe "norm! :".first.",".last."change\<CR>.\<CR>" + endif + if bufnr(file) == -1 || bufwinnr(bufnr(file)) == -1 + if !filereadable(file) + " create the file + let page_title = s:filename2pagetitle(file) + let namespace = s:namespace_of_title(page_title) + if len(namespace) > 0 + call system("mkdir -p " . namespace) + endif + call writefile([page_title, '', ''], file) + endif + exec "split ".file + else + let targetWindow = bufwinnr(bufnr(file)) + exe targetWindow."wincmd w" + end + if mode == 'append' + normal G + silent put + silent put= '' + elseif mode == 'insert' + call cursor(2, 0) + silent put + end + write! +endfunc + + +func! s:error(str) + echohl ErrorMsg + echomsg a:str + echohl None +endfunction + +func! s:insert_divider() + let divider = '------------------------------------------------------------------------' + silent put! =divider + silent put='' +endfunc +"------------------------------------------------------------------------ +" SEARCH +func! s:wiki_search(pattern) + + let pattern = (empty(a:pattern) ? @/ : a:pattern) + execute printf('vimgrep/%s/ %s', pattern, "**/*") +endfunc + +"------------------------------------------------------------------------ " This opens a new buffer with all the lines with just WikiLinks on them " expanded (recursively). This is not a wiki buffer but a text buffer -func! s:unfurl() - let res = system("soywiki-unfurl " . bufname('%')) +func! s:expand(seamless) + if a:seamless == 1 + " seamful, the default + echom "Expanding seamfully. Please wait." + let res = system(s:expand_command . " seamless " . bufname('%')) + else " seamless + echom "Expanding seamlessly. Please wait." + let res = system(s:expand_command . " seamful " . bufname('%')) + endif vertical botright new setlocal buftype=nofile "scratch buffer for viewing; user can write - put =res - 1delete - normal 1G + silent! put =res + silent! 1delete + silent! normal 1G + redraw + echom "Expanded " . (a:seamless == 0 ? 'seamfully' : 'seamlessly') . "." + endfunc "------------------------------------------------------------------------ func! s:open_href() @@ -386,10 +501,17 @@ func! s:global_mappings() noremap <leader>m :call <SID>list_pages()<CR> noremap <leader>M :call <SID>list_pages_linking_in()<CR> noremap <silent> <leader>o :call <SID>open_href()<cr> + + command! -bar -nargs=1 -range -complete=file SWAppend :<line1>,<line2>call s:extract(<f-args>, 'append', 0) + command! -bar -nargs=1 -range -complete=file SWInsert :<line1>,<line2>call s:extract(<f-args>, 'insert', 0) + command! -bar -nargs=1 -range -complete=file SWLinkAppend :<line1>,<line2>call s:extract(<f-args>, 'append', 1) + command! -bar -nargs=1 -range -complete=file SWLinkInsert :<line1>,<line2>call s:extract(<f-args>, 'insert', 1) + + command! -bar -nargs=1 SWSearch :call s:wiki_search(<f-args>) endfunc " this checks if the buffer is a SoyWiki file (from firstline) " and then turns on syntax coloring and mappings as necessary func! s:prep_buffer() @@ -397,20 +519,31 @@ set textwidth=72 nnoremap <buffer> <cr> :call <SID>follow_link_under_cursor(0)<cr> nnoremap <buffer> - :call <SID>follow_link_under_cursor(1)<cr> nnoremap <buffer> \| :call <SID>follow_link_under_cursor(2)<cr> noremap <buffer> <leader>f :call <SID>follow_link(0)<CR> - noremap <buffer> <leader>n :call <SID>find_next_wiki_link(0)<CR> - noremap <buffer> <leader>p :call <SID>find_next_wiki_link(1)<CR> + noremap <buffer> <c-n> :call <SID>find_next_wiki_link(0)<CR> + noremap <buffer> <c-p> :call <SID>find_next_wiki_link(1)<CR> + noremap <leader>c :call <SID>create_page()<CR> - command! -buffer SWDelete :call s:delete_page() command! -buffer SWRename :call s:rename_page() + + noremap <buffer> <leader>r :call <SID>rename_page()<CR> + command! -buffer SWDelete :call s:delete_page() + noremap <buffer> <leader># :call <SID>delete_page()<CR> + command! -buffer SWLog :call s:show_revision_history(0) noremap <buffer> <leader>l :call <SID>show_revision_history(0)<CR> command! -buffer SWLogStat :call s:show_revision_history(1) command! -buffer SWBlame :call s:show_blame() - noremap <buffer> <leader>x :call <SID>unfurl()<CR> + noremap <buffer> <leader>b :call <SID>show_blame()<CR> + + + + noremap <buffer> <leader>x :call <SID>expand(0)<CR> + noremap <buffer> <leader>X :call <SID>expand(1)<CR> + set nu setlocal completefunc=CompletePage augroup <buffer> au! autocmd BufWritePost <buffer> call s:save_revision() @@ -426,18 +559,13 @@ endif endfunc call s:global_mappings() -autocmd WinEnter * call s:highlight_wikiwords() +autocmd BufReadPost,BufNewFile,WinEnter * call s:highlight_wikiwords() autocmd BufEnter * call s:prep_buffer() -" load most recent page -let pages = split(system("ls -t" ), "\n") -let start_page = len(pages) > 0 ? get(pages, 0) : "HomePage" -call s:load_page(start_page, 0) - if (!isdirectory(".git")) call system("git init") echom "Created .git repository to store revisions" endif @@ -451,5 +579,14 @@ if !exists("g:SoyWiki#browser_command") echom "Can't find the to open your web browser." endif endif +if len(bufname("%")) == 0 + call s:load_most_recently_modified_page() +else + call s:load_page(bufname("%"), 0) +endif + +call s:get_page_list() +syntax on +let mapleader = ','