mirror of
https://github.com/gryf/.vim.git
synced 2025-12-17 11:30:29 +01:00
Removed ACP plugin. Found it annoying after a while. Reorganized rst2blogger plugin. Added documentation for it.
This commit is contained in:
@@ -9,7 +9,6 @@ ScriptID SourceID Filename
|
|||||||
2666 13424 Mark
|
2666 13424 Mark
|
||||||
2262 8944 occur.vim
|
2262 8944 occur.vim
|
||||||
910 14349 pydoc.vim
|
910 14349 pydoc.vim
|
||||||
1879 11894 AutoComplPop
|
|
||||||
#2421 9423 pysmell.vim
|
#2421 9423 pysmell.vim
|
||||||
152 3342 showmarks.vim
|
152 3342 showmarks.vim
|
||||||
2540 11006 snipMate.vim
|
2540 11006 snipMate.vim
|
||||||
|
|||||||
431
autoload/acp.vim
431
autoload/acp.vim
@@ -1,431 +0,0 @@
|
|||||||
"=============================================================================
|
|
||||||
" Copyright (c) 2007-2009 Takeshi NISHIDA
|
|
||||||
"
|
|
||||||
"=============================================================================
|
|
||||||
" LOAD GUARD {{{1
|
|
||||||
|
|
||||||
if exists('g:loaded_autoload_acp') || v:version < 702
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let g:loaded_autoload_acp = 1
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
"=============================================================================
|
|
||||||
" GLOBAL FUNCTIONS: {{{1
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#enable()
|
|
||||||
call acp#disable()
|
|
||||||
|
|
||||||
augroup AcpGlobalAutoCommand
|
|
||||||
autocmd!
|
|
||||||
autocmd InsertEnter * unlet! s:posLast s:lastUncompletable
|
|
||||||
autocmd InsertLeave * call s:finishPopup(1)
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
if g:acp_mappingDriven
|
|
||||||
call s:mapForMappingDriven()
|
|
||||||
else
|
|
||||||
autocmd AcpGlobalAutoCommand CursorMovedI * call s:feedPopup()
|
|
||||||
endif
|
|
||||||
|
|
||||||
nnoremap <silent> i i<C-r>=<SID>feedPopup()<CR>
|
|
||||||
nnoremap <silent> a a<C-r>=<SID>feedPopup()<CR>
|
|
||||||
nnoremap <silent> R R<C-r>=<SID>feedPopup()<CR>
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#disable()
|
|
||||||
call s:unmapForMappingDriven()
|
|
||||||
augroup AcpGlobalAutoCommand
|
|
||||||
autocmd!
|
|
||||||
augroup END
|
|
||||||
nnoremap i <Nop> | nunmap i
|
|
||||||
nnoremap a <Nop> | nunmap a
|
|
||||||
nnoremap R <Nop> | nunmap R
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#lock()
|
|
||||||
let s:lockCount += 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#unlock()
|
|
||||||
let s:lockCount -= 1
|
|
||||||
if s:lockCount < 0
|
|
||||||
let s:lockCount = 0
|
|
||||||
throw "AutoComplPop: not locked"
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#meetsForSnipmate(context)
|
|
||||||
if g:acp_behaviorSnipmateLength < 0
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
let matches = matchlist(a:context, '\(^\|\s\|\<\)\(\u\{' .
|
|
||||||
\ g:acp_behaviorSnipmateLength . ',}\)$')
|
|
||||||
return !empty(matches) && !empty(s:getMatchingSnipItems(matches[2]))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#meetsForKeyword(context)
|
|
||||||
if g:acp_behaviorKeywordLength < 0
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
let matches = matchlist(a:context, '\(\k\{' . g:acp_behaviorKeywordLength . ',}\)$')
|
|
||||||
if empty(matches)
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
for ignore in g:acp_behaviorKeywordIgnores
|
|
||||||
if stridx(ignore, matches[1]) == 0
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#meetsForFile(context)
|
|
||||||
if g:acp_behaviorFileLength < 0
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
if has('win32') || has('win64')
|
|
||||||
let separator = '[/\\]'
|
|
||||||
else
|
|
||||||
let separator = '\/'
|
|
||||||
endif
|
|
||||||
if a:context !~ '\f' . separator . '\f\{' . g:acp_behaviorFileLength . ',}$'
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
return a:context !~ '[*/\\][/\\]\f*$\|[^[:print:]]\f*$'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#meetsForRubyOmni(context)
|
|
||||||
if !has('ruby')
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
if g:acp_behaviorRubyOmniMethodLength >= 0 &&
|
|
||||||
\ a:context =~ '[^. \t]\(\.\|::\)\k\{' .
|
|
||||||
\ g:acp_behaviorRubyOmniMethodLength . ',}$'
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
if g:acp_behaviorRubyOmniSymbolLength >= 0 &&
|
|
||||||
\ a:context =~ '\(^\|[^:]\):\k\{' .
|
|
||||||
\ g:acp_behaviorRubyOmniSymbolLength . ',}$'
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#meetsForPythonOmni(context)
|
|
||||||
return has('python') && g:acp_behaviorPythonOmniLength >= 0 &&
|
|
||||||
\ a:context =~ '\k\.\k\{' . g:acp_behaviorPythonOmniLength . ',}$'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#meetsForPerlOmni(context)
|
|
||||||
return g:acp_behaviorPerlOmniLength >= 0 &&
|
|
||||||
\ a:context =~ '\w->\k\{' . g:acp_behaviorPerlOmniLength . ',}$'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#meetsForXmlOmni(context)
|
|
||||||
return g:acp_behaviorXmlOmniLength >= 0 &&
|
|
||||||
\ a:context =~ '\(<\|<\/\|<[^>]\+ \|<[^>]\+=\"\)\k\{' .
|
|
||||||
\ g:acp_behaviorXmlOmniLength . ',}$'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#meetsForHtmlOmni(context)
|
|
||||||
return g:acp_behaviorHtmlOmniLength >= 0 &&
|
|
||||||
\ a:context =~ '\(<\|<\/\|<[^>]\+ \|<[^>]\+=\"\)\k\{' .
|
|
||||||
\ g:acp_behaviorHtmlOmniLength . ',}$'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#meetsForCssOmni(context)
|
|
||||||
if g:acp_behaviorCssOmniPropertyLength >= 0 &&
|
|
||||||
\ a:context =~ '\(^\s\|[;{]\)\s*\k\{' .
|
|
||||||
\ g:acp_behaviorCssOmniPropertyLength . ',}$'
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
if g:acp_behaviorCssOmniValueLength >= 0 &&
|
|
||||||
\ a:context =~ '[:@!]\s*\k\{' .
|
|
||||||
\ g:acp_behaviorCssOmniValueLength . ',}$'
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#completeSnipmate(findstart, base)
|
|
||||||
if a:findstart
|
|
||||||
let s:posSnipmateCompletion = len(matchstr(s:getCurrentText(), '.*\U'))
|
|
||||||
return s:posSnipmateCompletion
|
|
||||||
endif
|
|
||||||
let lenBase = len(a:base)
|
|
||||||
let items = filter(GetSnipsInCurrentScope(),
|
|
||||||
\ 'strpart(v:key, 0, lenBase) ==? a:base')
|
|
||||||
return map(sort(items(items)), 's:makeSnipmateItem(v:val[0], v:val[1])')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#onPopupCloseSnipmate()
|
|
||||||
let word = s:getCurrentText()[s:posSnipmateCompletion :]
|
|
||||||
for trigger in keys(GetSnipsInCurrentScope())
|
|
||||||
if word ==# trigger
|
|
||||||
call feedkeys("\<C-r>=TriggerSnippet()\<CR>", "n")
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#onPopupPost()
|
|
||||||
" to clear <C-r>= expression on command-line
|
|
||||||
echo ''
|
|
||||||
if pumvisible()
|
|
||||||
inoremap <silent> <expr> <C-h> acp#onBs()
|
|
||||||
inoremap <silent> <expr> <BS> acp#onBs()
|
|
||||||
" a command to restore to original text and select the first match
|
|
||||||
return (s:behavsCurrent[s:iBehavs].command =~# "\<C-p>" ? "\<C-n>\<Up>"
|
|
||||||
\ : "\<C-p>\<Down>")
|
|
||||||
endif
|
|
||||||
let s:iBehavs += 1
|
|
||||||
if len(s:behavsCurrent) > s:iBehavs
|
|
||||||
call s:setCompletefunc()
|
|
||||||
return printf("\<C-e>%s\<C-r>=acp#onPopupPost()\<CR>",
|
|
||||||
\ s:behavsCurrent[s:iBehavs].command)
|
|
||||||
else
|
|
||||||
let s:lastUncompletable = {
|
|
||||||
\ 'word': s:getCurrentWord(),
|
|
||||||
\ 'commands': map(copy(s:behavsCurrent), 'v:val.command')[1:],
|
|
||||||
\ }
|
|
||||||
call s:finishPopup(0)
|
|
||||||
return "\<C-e>"
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function acp#onBs()
|
|
||||||
" using "matchstr" and not "strpart" in order to handle multi-byte
|
|
||||||
" characters
|
|
||||||
if call(s:behavsCurrent[s:iBehavs].meets,
|
|
||||||
\ [matchstr(s:getCurrentText(), '.*\ze.')])
|
|
||||||
return "\<BS>"
|
|
||||||
endif
|
|
||||||
return "\<C-e>\<BS>"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
"=============================================================================
|
|
||||||
" LOCAL FUNCTIONS: {{{1
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:mapForMappingDriven()
|
|
||||||
call s:unmapForMappingDriven()
|
|
||||||
let s:keysMappingDriven = [
|
|
||||||
\ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
|
||||||
\ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
|
||||||
\ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
|
||||||
\ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
|
||||||
\ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
|
||||||
\ '-', '_', '~', '^', '.', ',', ':', '!', '#', '=', '%', '$', '@', '<', '>', '/', '\',
|
|
||||||
\ '<Space>', '<C-h>', '<BS>', ]
|
|
||||||
for key in s:keysMappingDriven
|
|
||||||
execute printf('inoremap <silent> %s %s<C-r>=<SID>feedPopup()<CR>',
|
|
||||||
\ key, key)
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:unmapForMappingDriven()
|
|
||||||
if !exists('s:keysMappingDriven')
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
for key in s:keysMappingDriven
|
|
||||||
execute 'iunmap ' . key
|
|
||||||
endfor
|
|
||||||
let s:keysMappingDriven = []
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:setTempOption(group, name, value)
|
|
||||||
call extend(s:tempOptionSet[a:group], { a:name : eval('&' . a:name) }, 'keep')
|
|
||||||
execute printf('let &%s = a:value', a:name)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:restoreTempOptions(group)
|
|
||||||
for [name, value] in items(s:tempOptionSet[a:group])
|
|
||||||
execute printf('let &%s = value', name)
|
|
||||||
endfor
|
|
||||||
let s:tempOptionSet[a:group] = {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:getCurrentWord()
|
|
||||||
return matchstr(s:getCurrentText(), '\k*$')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:getCurrentText()
|
|
||||||
return strpart(getline('.'), 0, col('.') - 1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:getPostText()
|
|
||||||
return strpart(getline('.'), col('.') - 1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:isModifiedSinceLastCall()
|
|
||||||
if exists('s:posLast')
|
|
||||||
let posPrev = s:posLast
|
|
||||||
let nLinesPrev = s:nLinesLast
|
|
||||||
let textPrev = s:textLast
|
|
||||||
endif
|
|
||||||
let s:posLast = getpos('.')
|
|
||||||
let s:nLinesLast = line('$')
|
|
||||||
let s:textLast = getline('.')
|
|
||||||
if !exists('posPrev')
|
|
||||||
return 1
|
|
||||||
elseif posPrev[1] != s:posLast[1] || nLinesPrev != s:nLinesLast
|
|
||||||
return (posPrev[1] - s:posLast[1] == nLinesPrev - s:nLinesLast)
|
|
||||||
elseif textPrev ==# s:textLast
|
|
||||||
return 0
|
|
||||||
elseif posPrev[2] > s:posLast[2]
|
|
||||||
return 1
|
|
||||||
elseif has('gui_running') && has('multi_byte')
|
|
||||||
" NOTE: auto-popup causes a strange behavior when IME/XIM is working
|
|
||||||
return posPrev[2] + 1 == s:posLast[2]
|
|
||||||
endif
|
|
||||||
return posPrev[2] != s:posLast[2]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:makeCurrentBehaviorSet()
|
|
||||||
let modified = s:isModifiedSinceLastCall()
|
|
||||||
if exists('s:behavsCurrent[s:iBehavs].repeat') && s:behavsCurrent[s:iBehavs].repeat
|
|
||||||
let behavs = [ s:behavsCurrent[s:iBehavs] ]
|
|
||||||
elseif exists('s:behavsCurrent[s:iBehavs]')
|
|
||||||
return []
|
|
||||||
elseif modified
|
|
||||||
let behavs = copy(exists('g:acp_behavior[&filetype]')
|
|
||||||
\ ? g:acp_behavior[&filetype]
|
|
||||||
\ : g:acp_behavior['*'])
|
|
||||||
else
|
|
||||||
return []
|
|
||||||
endif
|
|
||||||
let text = s:getCurrentText()
|
|
||||||
call filter(behavs, 'call(v:val.meets, [text])')
|
|
||||||
let s:iBehavs = 0
|
|
||||||
if exists('s:lastUncompletable') &&
|
|
||||||
\ stridx(s:getCurrentWord(), s:lastUncompletable.word) == 0 &&
|
|
||||||
\ map(copy(behavs), 'v:val.command') ==# s:lastUncompletable.commands
|
|
||||||
let behavs = []
|
|
||||||
else
|
|
||||||
unlet! s:lastUncompletable
|
|
||||||
endif
|
|
||||||
return behavs
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:feedPopup()
|
|
||||||
" NOTE: CursorMovedI is not triggered while the popup menu is visible. And
|
|
||||||
" it will be triggered when popup menu is disappeared.
|
|
||||||
if s:lockCount > 0 || pumvisible() || &paste
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
if exists('s:behavsCurrent[s:iBehavs].onPopupClose')
|
|
||||||
if !call(s:behavsCurrent[s:iBehavs].onPopupClose, [])
|
|
||||||
call s:finishPopup(1)
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let s:behavsCurrent = s:makeCurrentBehaviorSet()
|
|
||||||
if empty(s:behavsCurrent)
|
|
||||||
call s:finishPopup(1)
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
" In case of dividing words by symbols (e.g. "for(int", "ab==cd") while a
|
|
||||||
" popup menu is visible, another popup is not available unless input <C-e>
|
|
||||||
" or try popup once. So first completion is duplicated.
|
|
||||||
call insert(s:behavsCurrent, s:behavsCurrent[s:iBehavs])
|
|
||||||
call s:setTempOption(s:GROUP0, 'spell', 0)
|
|
||||||
call s:setTempOption(s:GROUP0, 'completeopt', 'menuone' . (g:acp_completeoptPreview ? ',preview' : ''))
|
|
||||||
call s:setTempOption(s:GROUP0, 'complete', g:acp_completeOption)
|
|
||||||
call s:setTempOption(s:GROUP0, 'ignorecase', g:acp_ignorecaseOption)
|
|
||||||
" NOTE: With CursorMovedI driven, Set 'lazyredraw' to avoid flickering.
|
|
||||||
" With Mapping driven, set 'nolazyredraw' to make a popup menu visible.
|
|
||||||
call s:setTempOption(s:GROUP0, 'lazyredraw', !g:acp_mappingDriven)
|
|
||||||
" NOTE: 'textwidth' must be restored after <C-e>.
|
|
||||||
call s:setTempOption(s:GROUP1, 'textwidth', 0)
|
|
||||||
call s:setCompletefunc()
|
|
||||||
call feedkeys(s:behavsCurrent[s:iBehavs].command . "\<C-r>=acp#onPopupPost()\<CR>", 'n')
|
|
||||||
return '' " this function is called by <C-r>=
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:finishPopup(fGroup1)
|
|
||||||
inoremap <C-h> <Nop> | iunmap <C-h>
|
|
||||||
inoremap <BS> <Nop> | iunmap <BS>
|
|
||||||
let s:behavsCurrent = []
|
|
||||||
call s:restoreTempOptions(s:GROUP0)
|
|
||||||
if a:fGroup1
|
|
||||||
call s:restoreTempOptions(s:GROUP1)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:setCompletefunc()
|
|
||||||
if exists('s:behavsCurrent[s:iBehavs].completefunc')
|
|
||||||
call s:setTempOption(0, 'completefunc', s:behavsCurrent[s:iBehavs].completefunc)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:makeSnipmateItem(key, snip)
|
|
||||||
if type(a:snip) == type([])
|
|
||||||
let descriptions = map(copy(a:snip), 'v:val[0]')
|
|
||||||
let snipFormatted = '[MULTI] ' . join(descriptions, ', ')
|
|
||||||
else
|
|
||||||
let snipFormatted = substitute(a:snip, '\(\n\|\s\)\+', ' ', 'g')
|
|
||||||
endif
|
|
||||||
return {
|
|
||||||
\ 'word': a:key,
|
|
||||||
\ 'menu': strpart(snipFormatted, 0, 80),
|
|
||||||
\ }
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:getMatchingSnipItems(base)
|
|
||||||
let key = a:base . "\n"
|
|
||||||
if !exists('s:snipItems[key]')
|
|
||||||
let s:snipItems[key] = items(GetSnipsInCurrentScope())
|
|
||||||
call filter(s:snipItems[key], 'strpart(v:val[0], 0, len(a:base)) ==? a:base')
|
|
||||||
call map(s:snipItems[key], 's:makeSnipmateItem(v:val[0], v:val[1])')
|
|
||||||
endif
|
|
||||||
return s:snipItems[key]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
"=============================================================================
|
|
||||||
" INITIALIZATION {{{1
|
|
||||||
|
|
||||||
let s:GROUP0 = 0
|
|
||||||
let s:GROUP1 = 1
|
|
||||||
let s:lockCount = 0
|
|
||||||
let s:behavsCurrent = []
|
|
||||||
let s:iBehavs = 0
|
|
||||||
let s:tempOptionSet = [{}, {}]
|
|
||||||
let s:snipItems = {}
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
"=============================================================================
|
|
||||||
" vim: set fdm=marker:
|
|
||||||
512
doc/acp.txt
512
doc/acp.txt
@@ -1,512 +0,0 @@
|
|||||||
*acp.txt* Automatically opens popup menu for completions.
|
|
||||||
|
|
||||||
Copyright (c) 2007-2009 Takeshi NISHIDA
|
|
||||||
|
|
||||||
AutoComplPop *autocomplpop* *acp*
|
|
||||||
|
|
||||||
INTRODUCTION |acp-introduction|
|
|
||||||
INSTALLATION |acp-installation|
|
|
||||||
USAGE |acp-usage|
|
|
||||||
COMMANDS |acp-commands|
|
|
||||||
OPTIONS |acp-options|
|
|
||||||
SPECIAL THANKS |acp-thanks|
|
|
||||||
CHANGELOG |acp-changelog|
|
|
||||||
ABOUT |acp-about|
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INTRODUCTION *acp-introduction*
|
|
||||||
|
|
||||||
With this plugin, your vim comes to automatically opens popup menu for
|
|
||||||
completions when you enter characters or move the cursor in Insert mode. It
|
|
||||||
won't prevent you continuing entering characters.
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INSTALLATION *acp-installation*
|
|
||||||
|
|
||||||
Put all files into your runtime directory. If you have the zip file, extract
|
|
||||||
it to your runtime directory.
|
|
||||||
|
|
||||||
You should place the files as follows:
|
|
||||||
>
|
|
||||||
<your runtime directory>/plugin/acp.vim
|
|
||||||
<your runtime directory>/doc/acp.txt
|
|
||||||
...
|
|
||||||
<
|
|
||||||
If you disgust to jumble up this plugin and other plugins in your runtime
|
|
||||||
directory, put the files into new directory and just add the directory path to
|
|
||||||
'runtimepath'. It's easy to uninstall the plugin.
|
|
||||||
|
|
||||||
And then update your help tags files to enable fuzzyfinder help. See
|
|
||||||
|add-local-help| for details.
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
USAGE *acp-usage*
|
|
||||||
|
|
||||||
Once this plugin is installed, auto-popup is enabled at startup by default.
|
|
||||||
|
|
||||||
Which completion method is used depends on the text before the cursor. The
|
|
||||||
default behavior is as follows:
|
|
||||||
|
|
||||||
kind filetype text before the cursor ~
|
|
||||||
Keyword * two keyword characters
|
|
||||||
Filename * a filename character + a path separator
|
|
||||||
+ 0 or more filename character
|
|
||||||
Omni ruby ".", "::" or non-word character + ":"
|
|
||||||
(|+ruby| required.)
|
|
||||||
Omni python "." (|+python| required.)
|
|
||||||
Omni xml "<", "</" or ("<" + non-">" characters + " ")
|
|
||||||
Omni html/xhtml "<", "</" or ("<" + non-">" characters + " ")
|
|
||||||
Omni css (":", ";", "{", "^", "@", or "!")
|
|
||||||
+ 0 or 1 space
|
|
||||||
|
|
||||||
Also, you can make user-defined completion and snipMate's trigger completion
|
|
||||||
(|acp-snipMate|) auto-popup if the options are set.
|
|
||||||
|
|
||||||
These behavior are customizable.
|
|
||||||
|
|
||||||
*acp-snipMate*
|
|
||||||
snipMate's Trigger Completion ~
|
|
||||||
|
|
||||||
snipMate's trigger completion enables you to complete a snippet trigger
|
|
||||||
provided by snipMate plugin
|
|
||||||
(http://www.vim.org/scripts/script.php?script_id=2540) and expand it.
|
|
||||||
|
|
||||||
|
|
||||||
To enable auto-popup for this completion, add following function to
|
|
||||||
plugin/snipMate.vim:
|
|
||||||
>
|
|
||||||
fun! GetSnipsInCurrentScope()
|
|
||||||
let snips = {}
|
|
||||||
for scope in [bufnr('%')] + split(&ft, '\.') + ['_']
|
|
||||||
call extend(snips, get(s:snippets, scope, {}), 'keep')
|
|
||||||
call extend(snips, get(s:multi_snips, scope, {}), 'keep')
|
|
||||||
endfor
|
|
||||||
return snips
|
|
||||||
endf
|
|
||||||
<
|
|
||||||
And set |g:acp_behaviorSnipmateLength| option to 1.
|
|
||||||
|
|
||||||
There is the restriction on this auto-popup, that the word before cursor must
|
|
||||||
consist only of uppercase characters.
|
|
||||||
|
|
||||||
*acp-perl-omni*
|
|
||||||
Perl Omni-Completion ~
|
|
||||||
|
|
||||||
AutoComplPop supports perl-completion.vim
|
|
||||||
(http://www.vim.org/scripts/script.php?script_id=2852).
|
|
||||||
|
|
||||||
To enable auto-popup for this completion, set |g:acp_behaviorPerlOmniLength|
|
|
||||||
option to 0 or more.
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
COMMANDS *acp-commands*
|
|
||||||
|
|
||||||
*:AcpEnable*
|
|
||||||
:AcpEnable
|
|
||||||
enables auto-popup.
|
|
||||||
|
|
||||||
*:AcpDisable*
|
|
||||||
:AcpDisable
|
|
||||||
disables auto-popup.
|
|
||||||
|
|
||||||
*:AcpLock*
|
|
||||||
:AcpLock
|
|
||||||
suspends auto-popup temporarily.
|
|
||||||
|
|
||||||
For the purpose of avoiding interruption to another script, it is
|
|
||||||
recommended to insert this command and |:AcpUnlock| than |:AcpDisable|
|
|
||||||
and |:AcpEnable| .
|
|
||||||
|
|
||||||
*:AcpUnlock*
|
|
||||||
:AcpUnlock
|
|
||||||
resumes auto-popup suspended by |:AcpLock| .
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
OPTIONS *acp-options*
|
|
||||||
|
|
||||||
*g:acp_enableAtStartup* >
|
|
||||||
let g:acp_enableAtStartup = 1
|
|
||||||
<
|
|
||||||
If non-zero, auto-popup is enabled at startup.
|
|
||||||
|
|
||||||
*g:acp_mappingDriven* >
|
|
||||||
let g:acp_mappingDriven = 0
|
|
||||||
<
|
|
||||||
If non-zero, auto-popup is triggered by key mappings instead of
|
|
||||||
|CursorMovedI| event. This is useful to avoid auto-popup by moving
|
|
||||||
cursor in Insert mode.
|
|
||||||
|
|
||||||
*g:acp_ignorecaseOption* >
|
|
||||||
let g:acp_ignorecaseOption = 1
|
|
||||||
<
|
|
||||||
Value set to 'ignorecase' temporarily when auto-popup.
|
|
||||||
|
|
||||||
*g:acp_completeOption* >
|
|
||||||
let g:acp_completeOption = '.,w,b,k'
|
|
||||||
<
|
|
||||||
Value set to 'complete' temporarily when auto-popup.
|
|
||||||
|
|
||||||
*g:acp_completeoptPreview* >
|
|
||||||
let g:acp_completeoptPreview = 0
|
|
||||||
<
|
|
||||||
If non-zero, "preview" is added to 'completeopt' when auto-popup.
|
|
||||||
|
|
||||||
*g:acp_behaviorUserDefinedFunction* >
|
|
||||||
let g:acp_behaviorUserDefinedFunction = ''
|
|
||||||
<
|
|
||||||
|g:acp_behavior-completefunc| for user-defined completion. If empty,
|
|
||||||
this completion will be never attempted.
|
|
||||||
|
|
||||||
*g:acp_behaviorUserDefinedMeets* >
|
|
||||||
let g:acp_behaviorUserDefinedMeets = ''
|
|
||||||
<
|
|
||||||
|g:acp_behavior-meets| for user-defined completion. If empty, this
|
|
||||||
completion will be never attempted.
|
|
||||||
|
|
||||||
*g:acp_behaviorSnipmateLength* >
|
|
||||||
let g:acp_behaviorSnipmateLength = -1
|
|
||||||
<
|
|
||||||
Pattern before the cursor, which are needed to attempt
|
|
||||||
snipMate-trigger completion.
|
|
||||||
|
|
||||||
*g:acp_behaviorKeywordCommand* >
|
|
||||||
let g:acp_behaviorKeywordCommand = "\<C-n>"
|
|
||||||
<
|
|
||||||
Command for keyword completion. This option is usually set "\<C-n>" or
|
|
||||||
"\<C-p>".
|
|
||||||
|
|
||||||
*g:acp_behaviorKeywordLength* >
|
|
||||||
let g:acp_behaviorKeywordLength = 2
|
|
||||||
<
|
|
||||||
Length of keyword characters before the cursor, which are needed to
|
|
||||||
attempt keyword completion. If negative value, this completion will be
|
|
||||||
never attempted.
|
|
||||||
|
|
||||||
*g:acp_behaviorKeywordIgnores* >
|
|
||||||
let g:acp_behaviorKeywordIgnores = []
|
|
||||||
<
|
|
||||||
List of string. If a word before the cursor matches to the front part
|
|
||||||
of one of them, keyword completion won't be attempted.
|
|
||||||
|
|
||||||
E.g., when there are too many keywords beginning with "get" for the
|
|
||||||
completion and auto-popup by entering "g", "ge", or "get" causes
|
|
||||||
response degradation, set ["get"] to this option and avoid it.
|
|
||||||
|
|
||||||
*g:acp_behaviorFileLength* >
|
|
||||||
let g:acp_behaviorFileLength = 0
|
|
||||||
<
|
|
||||||
Length of filename characters before the cursor, which are needed to
|
|
||||||
attempt filename completion. If negative value, this completion will
|
|
||||||
be never attempted.
|
|
||||||
|
|
||||||
*g:acp_behaviorRubyOmniMethodLength* >
|
|
||||||
let g:acp_behaviorRubyOmniMethodLength = 0
|
|
||||||
<
|
|
||||||
Length of keyword characters before the cursor, which are needed to
|
|
||||||
attempt ruby omni-completion for methods. If negative value, this
|
|
||||||
completion will be never attempted.
|
|
||||||
|
|
||||||
*g:acp_behaviorRubyOmniSymbolLength* >
|
|
||||||
let g:acp_behaviorRubyOmniSymbolLength = 1
|
|
||||||
<
|
|
||||||
Length of keyword characters before the cursor, which are needed to
|
|
||||||
attempt ruby omni-completion for symbols. If negative value, this
|
|
||||||
completion will be never attempted.
|
|
||||||
|
|
||||||
*g:acp_behaviorPythonOmniLength* >
|
|
||||||
let g:acp_behaviorPythonOmniLength = 0
|
|
||||||
<
|
|
||||||
Length of keyword characters before the cursor, which are needed to
|
|
||||||
attempt python omni-completion. If negative value, this completion
|
|
||||||
will be never attempted.
|
|
||||||
|
|
||||||
*g:acp_behaviorPerlOmniLength* >
|
|
||||||
let g:acp_behaviorPerlOmniLength = -1
|
|
||||||
<
|
|
||||||
Length of keyword characters before the cursor, which are needed to
|
|
||||||
attempt perl omni-completion. If negative value, this completion will
|
|
||||||
be never attempted.
|
|
||||||
|
|
||||||
See also: |acp-perl-omni|
|
|
||||||
|
|
||||||
*g:acp_behaviorXmlOmniLength* >
|
|
||||||
let g:acp_behaviorXmlOmniLength = 0
|
|
||||||
<
|
|
||||||
Length of keyword characters before the cursor, which are needed to
|
|
||||||
attempt XML omni-completion. If negative value, this completion will
|
|
||||||
be never attempted.
|
|
||||||
|
|
||||||
*g:acp_behaviorHtmlOmniLength* >
|
|
||||||
let g:acp_behaviorHtmlOmniLength = 0
|
|
||||||
<
|
|
||||||
Length of keyword characters before the cursor, which are needed to
|
|
||||||
attempt HTML omni-completion. If negative value, this completion will
|
|
||||||
be never attempted.
|
|
||||||
|
|
||||||
*g:acp_behaviorCssOmniPropertyLength* >
|
|
||||||
let g:acp_behaviorCssOmniPropertyLength = 1
|
|
||||||
<
|
|
||||||
Length of keyword characters before the cursor, which are needed to
|
|
||||||
attempt CSS omni-completion for properties. If negative value, this
|
|
||||||
completion will be never attempted.
|
|
||||||
|
|
||||||
*g:acp_behaviorCssOmniValueLength* >
|
|
||||||
let g:acp_behaviorCssOmniValueLength = 0
|
|
||||||
<
|
|
||||||
Length of keyword characters before the cursor, which are needed to
|
|
||||||
attempt CSS omni-completion for values. If negative value, this
|
|
||||||
completion will be never attempted.
|
|
||||||
|
|
||||||
*g:acp_behavior* >
|
|
||||||
let g:acp_behavior = {}
|
|
||||||
<
|
|
||||||
This option is for advanced users. This setting overrides other
|
|
||||||
behavior options. This is a |Dictionary|. Each key corresponds to a
|
|
||||||
filetype. '*' is default. Each value is a list. These are attempted in
|
|
||||||
sequence until completion item is found. Each element is a
|
|
||||||
|Dictionary| which has following items:
|
|
||||||
|
|
||||||
"command": *g:acp_behavior-command*
|
|
||||||
Command to be fed to open popup menu for completions.
|
|
||||||
|
|
||||||
"completefunc": *g:acp_behavior-completefunc*
|
|
||||||
'completefunc' will be set to this user-provided function during the
|
|
||||||
completion. Only makes sense when "command" is "<C-x><C-u>".
|
|
||||||
|
|
||||||
"meets": *g:acp_behavior-meets*
|
|
||||||
Name of the function which dicides whether or not to attempt this
|
|
||||||
completion. It will be attempted if this function returns non-zero.
|
|
||||||
This function takes a text before the cursor.
|
|
||||||
|
|
||||||
"onPopupClose": *g:acp_behavior-onPopupClose*
|
|
||||||
Name of the function which is called when popup menu for this
|
|
||||||
completion is closed. Following completions will be suppressed if
|
|
||||||
this function returns zero.
|
|
||||||
|
|
||||||
"repeat": *g:acp_behavior-repeat*
|
|
||||||
If non-zero, the last completion is automatically repeated.
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
SPECIAL THANKS *acp-thanks*
|
|
||||||
|
|
||||||
- Daniel Schierbeck
|
|
||||||
- Ingo Karkat
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
CHANGELOG *acp-changelog*
|
|
||||||
|
|
||||||
2.14.1
|
|
||||||
- Changed the way of auto-popup for avoiding an issue about filename
|
|
||||||
completion.
|
|
||||||
- Fixed a bug that popup menu was opened twice when auto-popup was done.
|
|
||||||
|
|
||||||
2.14
|
|
||||||
- Added the support for perl-completion.vim.
|
|
||||||
|
|
||||||
2.13
|
|
||||||
- Changed to sort snipMate's triggers.
|
|
||||||
- Fixed a bug that a wasted character was inserted after snipMate's trigger
|
|
||||||
completion.
|
|
||||||
|
|
||||||
2.12.1
|
|
||||||
- Changed to avoid a strange behavior with Microsoft IME.
|
|
||||||
|
|
||||||
2.12
|
|
||||||
- Added g:acp_behaviorKeywordIgnores option.
|
|
||||||
- Added g:acp_behaviorUserDefinedMeets option and removed
|
|
||||||
g:acp_behaviorUserDefinedPattern.
|
|
||||||
- Changed to do auto-popup only when a buffer is modified.
|
|
||||||
- Changed the structure of g:acp_behavior option.
|
|
||||||
- Changed to reflect a change of behavior options (named g:acp_behavior*)
|
|
||||||
any time it is done.
|
|
||||||
- Fixed a bug that completions after omni completions or snipMate's trigger
|
|
||||||
completion were never attempted when no candidate for the former
|
|
||||||
completions was found.
|
|
||||||
|
|
||||||
2.11.1
|
|
||||||
- Fixed a bug that a snipMate's trigger could not be expanded when it was
|
|
||||||
completed.
|
|
||||||
|
|
||||||
2.11
|
|
||||||
- Implemented experimental feature which is snipMate's trigger completion.
|
|
||||||
|
|
||||||
2.10
|
|
||||||
- Improved the response by changing not to attempt any completion when
|
|
||||||
keyword characters are entered after a word which has been found that it
|
|
||||||
has no completion candidate at the last attempt of completions.
|
|
||||||
- Improved the response by changing to close popup menu when <BS> was
|
|
||||||
pressed and the text before the cursor would not match with the pattern of
|
|
||||||
current behavior.
|
|
||||||
|
|
||||||
2.9
|
|
||||||
- Changed default behavior to support XML omni completion.
|
|
||||||
- Changed default value of g:acp_behaviorKeywordCommand option.
|
|
||||||
The option with "\<C-p>" cause a problem which inserts a match without
|
|
||||||
<CR> when 'dictionary' has been set and keyword completion is done.
|
|
||||||
- Changed to show error message when incompatible with a installed vim.
|
|
||||||
|
|
||||||
2.8.1
|
|
||||||
- Fixed a bug which inserted a selected match to the next line when
|
|
||||||
auto-wrapping (enabled with 'formatoptions') was performed.
|
|
||||||
|
|
||||||
2.8
|
|
||||||
- Added g:acp_behaviorUserDefinedFunction option and
|
|
||||||
g:acp_behaviorUserDefinedPattern option for users who want to make custom
|
|
||||||
completion auto-popup.
|
|
||||||
- Fixed a bug that setting 'spell' on a new buffer made typing go crazy.
|
|
||||||
|
|
||||||
2.7
|
|
||||||
- Changed naming conventions for filenames, functions, commands, and options
|
|
||||||
and thus renamed them.
|
|
||||||
- Added g:acp_behaviorKeywordCommand option. If you prefer the previous
|
|
||||||
behavior for keyword completion, set this option "\<C-n>".
|
|
||||||
- Changed default value of g:acp_ignorecaseOption option.
|
|
||||||
|
|
||||||
The following were done by Ingo Karkat:
|
|
||||||
|
|
||||||
- ENH: Added support for setting a user-provided 'completefunc' during the
|
|
||||||
completion, configurable via g:acp_behavior.
|
|
||||||
- BUG: When the configured completion is <C-p> or <C-x><C-p>, the command to
|
|
||||||
restore the original text (in on_popup_post()) must be reverted, too.
|
|
||||||
- BUG: When using a custom completion function (<C-x><C-u>) that also uses
|
|
||||||
an s:...() function name, the s:GetSidPrefix() function dynamically
|
|
||||||
determines the wrong SID. Now calling s:DetermineSidPrefix() once during
|
|
||||||
sourcing and caching the value in s:SID.
|
|
||||||
- BUG: Should not use custom defined <C-X><C-...> completion mappings. Now
|
|
||||||
consistently using unmapped completion commands everywhere. (Beforehand,
|
|
||||||
s:PopupFeeder.feed() used mappings via feedkeys(..., 'm'), but
|
|
||||||
s:PopupFeeder.on_popup_post() did not due to its invocation via
|
|
||||||
:map-expr.)
|
|
||||||
|
|
||||||
2.6:
|
|
||||||
- Improved the behavior of omni completion for HTML/XHTML.
|
|
||||||
|
|
||||||
2.5:
|
|
||||||
- Added some options to customize behavior easily:
|
|
||||||
g:AutoComplPop_BehaviorKeywordLength
|
|
||||||
g:AutoComplPop_BehaviorFileLength
|
|
||||||
g:AutoComplPop_BehaviorRubyOmniMethodLength
|
|
||||||
g:AutoComplPop_BehaviorRubyOmniSymbolLength
|
|
||||||
g:AutoComplPop_BehaviorPythonOmniLength
|
|
||||||
g:AutoComplPop_BehaviorHtmlOmniLength
|
|
||||||
g:AutoComplPop_BehaviorCssOmniPropertyLength
|
|
||||||
g:AutoComplPop_BehaviorCssOmniValueLength
|
|
||||||
|
|
||||||
2.4:
|
|
||||||
- Added g:AutoComplPop_MappingDriven option.
|
|
||||||
|
|
||||||
2.3.1:
|
|
||||||
- Changed to set 'lazyredraw' while a popup menu is visible to avoid
|
|
||||||
flickering.
|
|
||||||
- Changed a behavior for CSS.
|
|
||||||
- Added support for GetLatestVimScripts.
|
|
||||||
|
|
||||||
2.3:
|
|
||||||
- Added a behavior for Python to support omni completion.
|
|
||||||
- Added a behavior for CSS to support omni completion.
|
|
||||||
|
|
||||||
2.2:
|
|
||||||
- Changed not to work when 'paste' option is set.
|
|
||||||
- Fixed AutoComplPopEnable command and AutoComplPopDisable command to
|
|
||||||
map/unmap "i" and "R".
|
|
||||||
|
|
||||||
2.1:
|
|
||||||
- Fixed the problem caused by "." command in Normal mode.
|
|
||||||
- Changed to map "i" and "R" to feed completion command after starting
|
|
||||||
Insert mode.
|
|
||||||
- Avoided the problem caused by Windows IME.
|
|
||||||
|
|
||||||
2.0:
|
|
||||||
- Changed to use CursorMovedI event to feed a completion command instead of
|
|
||||||
key mapping. Now the auto-popup is triggered by moving the cursor.
|
|
||||||
- Changed to feed completion command after starting Insert mode.
|
|
||||||
- Removed g:AutoComplPop_MapList option.
|
|
||||||
|
|
||||||
1.7:
|
|
||||||
- Added behaviors for HTML/XHTML. Now supports the omni completion for
|
|
||||||
HTML/XHTML.
|
|
||||||
- Changed not to show expressions for CTRL-R =.
|
|
||||||
- Changed not to set 'nolazyredraw' while a popup menu is visible.
|
|
||||||
|
|
||||||
1.6.1:
|
|
||||||
- Changed not to trigger the filename completion by a text which has
|
|
||||||
multi-byte characters.
|
|
||||||
|
|
||||||
1.6:
|
|
||||||
- Redesigned g:AutoComplPop_Behavior option.
|
|
||||||
- Changed default value of g:AutoComplPop_CompleteOption option.
|
|
||||||
- Changed default value of g:AutoComplPop_MapList option.
|
|
||||||
|
|
||||||
1.5:
|
|
||||||
- Implemented continuous-completion for the filename completion. And added
|
|
||||||
new option to g:AutoComplPop_Behavior.
|
|
||||||
|
|
||||||
1.4:
|
|
||||||
- Fixed the bug that the auto-popup was not suspended in fuzzyfinder.
|
|
||||||
- Fixed the bug that an error has occurred with Ruby-omni-completion unless
|
|
||||||
Ruby interface.
|
|
||||||
|
|
||||||
1.3:
|
|
||||||
- Supported Ruby-omni-completion by default.
|
|
||||||
- Supported filename completion by default.
|
|
||||||
- Added g:AutoComplPop_Behavior option.
|
|
||||||
- Added g:AutoComplPop_CompleteoptPreview option.
|
|
||||||
- Removed g:AutoComplPop_MinLength option.
|
|
||||||
- Removed g:AutoComplPop_MaxLength option.
|
|
||||||
- Removed g:AutoComplPop_PopupCmd option.
|
|
||||||
|
|
||||||
1.2:
|
|
||||||
- Fixed bugs related to 'completeopt'.
|
|
||||||
|
|
||||||
1.1:
|
|
||||||
- Added g:AutoComplPop_IgnoreCaseOption option.
|
|
||||||
- Added g:AutoComplPop_NotEnableAtStartup option.
|
|
||||||
- Removed g:AutoComplPop_LoadAndEnable option.
|
|
||||||
1.0:
|
|
||||||
- g:AutoComplPop_LoadAndEnable option for a startup activation is added.
|
|
||||||
- AutoComplPopLock command and AutoComplPopUnlock command are added to
|
|
||||||
suspend and resume.
|
|
||||||
- 'completeopt' and 'complete' options are changed temporarily while
|
|
||||||
completing by this script.
|
|
||||||
|
|
||||||
0.4:
|
|
||||||
- The first match are selected when the popup menu is Opened. You can insert
|
|
||||||
the first match with CTRL-Y.
|
|
||||||
|
|
||||||
0.3:
|
|
||||||
- Fixed the problem that the original text is not restored if 'longest' is
|
|
||||||
not set in 'completeopt'. Now the plugin works whether or not 'longest' is
|
|
||||||
set in 'completeopt', and also 'menuone'.
|
|
||||||
|
|
||||||
0.2:
|
|
||||||
- When completion matches are not found, insert CTRL-E to stop completion.
|
|
||||||
- Clear the echo area.
|
|
||||||
- Fixed the problem in case of dividing words by symbols, popup menu is
|
|
||||||
not opened.
|
|
||||||
|
|
||||||
0.1:
|
|
||||||
- First release.
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
ABOUT *acp-about* *acp-contact* *acp-author*
|
|
||||||
|
|
||||||
Author: Takeshi NISHIDA <ns9tks@DELETE-ME.gmail.com>
|
|
||||||
Licence: MIT Licence
|
|
||||||
URL: http://www.vim.org/scripts/script.php?script_id=1879
|
|
||||||
http://bitbucket.org/ns9tks/vim-autocomplpop/
|
|
||||||
|
|
||||||
Bugs/Issues/Suggestions/Improvements ~
|
|
||||||
|
|
||||||
Please submit to http://bitbucket.org/ns9tks/vim-autocomplpop/issues/ .
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
vim:tw=78:ts=8:ft=help:norl:
|
|
||||||
|
|
||||||
710
doc/project.txt
710
doc/project.txt
@@ -1,710 +0,0 @@
|
|||||||
*project.txt* Plugin for managing multiple projects with multiple sources
|
|
||||||
For Vim version 6.x and Vim version 7.x.
|
|
||||||
Last Change: Fri 13 Oct 2006 10:20:13 AM EDT
|
|
||||||
|
|
||||||
|
|
||||||
By Aric Blumer
|
|
||||||
aricvim email-at-sign charter.net
|
|
||||||
|
|
||||||
*project* *project-plugin*
|
|
||||||
Contents:
|
|
||||||
|
|
||||||
Commands...................|project-invoking|
|
|
||||||
Inheritance.............|project-inheritance|
|
|
||||||
Mappings...................|project-mappings|
|
|
||||||
Adding Mappings.....|project-adding-mappings|
|
|
||||||
Settings...................|project-settings|
|
|
||||||
Example File................|project-example|
|
|
||||||
Tips...........................|project-tips|
|
|
||||||
|
|
||||||
|
|
||||||
You can use this plugin's basic functionality to set up a list of
|
|
||||||
frequently-accessed files for easy navigation. The list of files will be
|
|
||||||
displayed in a window on the left side of the Vim window, and you can press
|
|
||||||
<Return> or double-click on filenames in the list to open the files. I find
|
|
||||||
this easier to use than having to navigate a directory hierarchy with the
|
|
||||||
|file-explorer|.
|
|
||||||
|
|
||||||
You can also instruct the Plugin to change to a directory and to run Vim
|
|
||||||
scripts when you select a file. These scripts can, for example, modify the
|
|
||||||
environment to include compilers in $PATH. This makes it very easy to use
|
|
||||||
quickfix with multiple projects that use different environments.
|
|
||||||
|
|
||||||
Other features include:
|
|
||||||
o Loading/Unloading all the files in a Project (\l, \L, \w, and \W)
|
|
||||||
o Grepping all the files in a Project (\g and \G)
|
|
||||||
o Running a user-specified script on a file (can be used to launch an
|
|
||||||
external program on the file) (\1 through \9)
|
|
||||||
o Running a user-specified script on all the files in a Project
|
|
||||||
(\f1-\f9 and \F1-\F9)
|
|
||||||
o High degree of user-configurability
|
|
||||||
o Also works with |netrw| using the XXXX://... notation where XXXX is
|
|
||||||
ftp, rcp, scp, or http.
|
|
||||||
|
|
||||||
All of this is specified within a simple text file and a few global variables
|
|
||||||
in your vimrc file.
|
|
||||||
|
|
||||||
You must set 'nocompatible' in your |vimrc| file to use this plugin. You can
|
|
||||||
stop the plugin from being loaded by setting the "loaded_project" variable: >
|
|
||||||
:let loaded_project = 1
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
COMMANDS *project-invoking*
|
|
||||||
|
|
||||||
You can use the plugin by placing it in your plugin directory (e.g.,
|
|
||||||
~/.vim/plugin). See |add-global-plugin|. When you start vim the next time, you
|
|
||||||
then enter the command >
|
|
||||||
:Project
|
|
||||||
or >
|
|
||||||
:Project {file}
|
|
||||||
|
|
||||||
If you do not specify the filename, $HOME/.vimprojects is used.
|
|
||||||
|
|
||||||
To have Vim come up with the Project Window enabled automatically (say, from a
|
|
||||||
GUI launcher), run Vim like this: [g]vim +Project
|
|
||||||
|
|
||||||
Note that you can invoke :Project on only one file at a time. If you wish to
|
|
||||||
change the Project File, do a :bwipe in the Project Buffer, then re-invoke the
|
|
||||||
Plugin as described above.
|
|
||||||
|
|
||||||
Several Projects can be kept and displayed in the same file, each in a fold
|
|
||||||
delimited by { and } (see |fold.txt|). There can be any number of nested
|
|
||||||
folds to provide you with a Project hierarchy. Any line without a { or a } in
|
|
||||||
the file is considered to be a filename. Blank lines are ignored, and any
|
|
||||||
text after a # is ignored.
|
|
||||||
|
|
||||||
Because the plugin uses standard Vim folds, you can use any of the
|
|
||||||
|fold-commands|. You can double-click on the first line of a fold to open and
|
|
||||||
close it. You can select a file to open by putting the cursor on its name and
|
|
||||||
pressing <Return> or by double-clicking on it. The plugin will create a new
|
|
||||||
window to the right or use the |CTRL-W_p| equivalent if it exists.
|
|
||||||
|
|
||||||
*project-syntax*
|
|
||||||
Each Project Entry has this form:
|
|
||||||
|
|
||||||
project_entry ::=
|
|
||||||
<Description>={projpath} [{options}] {
|
|
||||||
[ filename ]
|
|
||||||
[ project_entry ]
|
|
||||||
}
|
|
||||||
|
|
||||||
{options} is one or more of the following (on the same line):
|
|
||||||
CD={path}
|
|
||||||
in={filename}
|
|
||||||
out={filename}
|
|
||||||
filter="{pat}"
|
|
||||||
flags={flag}
|
|
||||||
|
|
||||||
Note that a project_entry can reside within a project_entry. This allows you
|
|
||||||
to set up a hierarchy within your Project.
|
|
||||||
|
|
||||||
The <Description> will be displayed in the foldtext and cannot contain "=".
|
|
||||||
There can be no space character directly on either side of the =.
|
|
||||||
|
|
||||||
The {projpath} is the path in which the files listed in the Project's fold
|
|
||||||
will be found, and it may contain environment variables. If the path is a
|
|
||||||
relative path, then the plugin constructs the whole path from the Project's
|
|
||||||
parent, grandparent, etc., all the way up the hierarchy. An outermost
|
|
||||||
project_entry must have an absolute path. See the |project-inheritance|
|
|
||||||
example below. {projpath} may contain spaces, but they must be escaped like
|
|
||||||
normal Vim escapes. Here are two examples of the same directory:
|
|
||||||
>
|
|
||||||
Example=/my/directory/with\ spaces {
|
|
||||||
}
|
|
||||||
Example="/my/directory/with spaces" {
|
|
||||||
}
|
|
||||||
|
|
||||||
I recommend this for Windows<77>: >
|
|
||||||
|
|
||||||
Example="c:\My Documents" {
|
|
||||||
}
|
|
||||||
|
|
||||||
But Vim is smart enough to do this, too: >
|
|
||||||
|
|
||||||
Example=c:\My\ Documents {
|
|
||||||
}
|
|
||||||
|
|
||||||
CD= provides the directory that Vim will change to when you select a file in
|
|
||||||
that fold (using |:cd|). This allows you, for example, to enter |:make| to use
|
|
||||||
the local Makefile. A CD=. means that Vim will make {projpath} or its
|
|
||||||
inherited equivalent the current working directory. When CD is omitted, the
|
|
||||||
directory is not changed. There can be no space on either side of the =. The
|
|
||||||
value of CD can also be a relative path from a parent's CD. See the
|
|
||||||
|project-inheritance| example below. This directive is ignored for |netrw|
|
|
||||||
projects. Spaces are allowed in the path as for {projpath}.
|
|
||||||
|
|
||||||
in= and out= provide the means to run arbitrary Vim scripts whenever you enter
|
|
||||||
or leave a file's buffer (see the |BufEnter| and |BufLeave| autocommand
|
|
||||||
events). The idea is to have a Vim script that sets up or tears down the
|
|
||||||
environment for the Project like this:
|
|
||||||
|
|
||||||
in.vim: >
|
|
||||||
let $PROJECT_HOME='~/my_project'
|
|
||||||
" Put the compiler in $PATH
|
|
||||||
if $PATH !~ '/path/to/my/compiler'
|
|
||||||
let $PATH=$PATH.':/path/to/my/compiler'
|
|
||||||
endif
|
|
||||||
|
|
||||||
out.vim: >
|
|
||||||
" Remove compiler from $PATH
|
|
||||||
if $PATH =~ '/path/to/my/compiler'
|
|
||||||
let $PATH=substitute($PATH, ':/path/to/my/compiler', '', 'g')
|
|
||||||
endif
|
|
||||||
|
|
||||||
Then you can use :make with the proper environment depending on what file you
|
|
||||||
are currently editing. If the path to the script is relative, then it is
|
|
||||||
relative from {projpath}. These directives are inherited by Subprojects
|
|
||||||
unless the Subproject specifies its own. For use with |netrw| projects, the
|
|
||||||
paths specified for in= and out= must be absolute and local.
|
|
||||||
|
|
||||||
filter= specifies a |glob()| file pattern. It is used to regenerate the list
|
|
||||||
of files in a Project fold when using the \r (<LocalLeader>r) map in the
|
|
||||||
Project Window. The filter value must be in quotes because it can contain
|
|
||||||
multiple file patterns. If filter is omitted, then the * pattern is used.
|
|
||||||
There can be no space on either side of the =. A Subproject will inherit the
|
|
||||||
filter of its parent unless it specifies its own filter.
|
|
||||||
|
|
||||||
flags= provides the means to enable/disable features for a particular fold.
|
|
||||||
The general mnemonic scheme is for lower case to turn something off and upper
|
|
||||||
case to turn something on. {flag} can contain any of the following
|
|
||||||
characters:
|
|
||||||
|
|
||||||
flag Description ~
|
|
||||||
|
|
||||||
l Turn off recursion for this fold for \L. Subfolds are also
|
|
||||||
blocked from the recursion.
|
|
||||||
|
|
||||||
r Turn off refresh. When present, do not refresh this fold when
|
|
||||||
\r or \R is used. This does not affect subfold recursion.
|
|
||||||
|
|
||||||
S Turn on sorting for refresh and create.
|
|
||||||
|
|
||||||
s Turn off sorting for refresh and create.
|
|
||||||
|
|
||||||
T Turn on top gravity. Forces folds to the top of the current
|
|
||||||
fold when refreshing. It has the same affect as the 'T' flag
|
|
||||||
in g:proj_flags, but controls the feature on a per-fold basis.
|
|
||||||
|
|
||||||
t Turn off top gravity. Forces folds to the bottom of the
|
|
||||||
current fold when refreshing.
|
|
||||||
|
|
||||||
w Turn off recursion for this fold for \W. Subfolds are also
|
|
||||||
blocked from the recursion.
|
|
||||||
|
|
||||||
|
|
||||||
Flags are not inherited by Subprojects.
|
|
||||||
|
|
||||||
Any text outside a fold is ignored.
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INHERITANCE *project-inheritance*
|
|
||||||
|
|
||||||
It's best to show inheritance by comparing these two Project Files:
|
|
||||||
>
|
|
||||||
Parent=~/my_project CD=. filter="Make* *.mk" flags=r {
|
|
||||||
Child1=c_code {
|
|
||||||
}
|
|
||||||
Child2=include CD=. filter="*.h" {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Child1's path is "~/my_project/c_code" because ~/my_project is inherited. It
|
|
||||||
also inherits the CD from Parent. Since Parent has CD=., the Parent's cwd is
|
|
||||||
"~/my_project". Child1 therefore inherits a CD of "~/my_project". Finally,
|
|
||||||
Child1 inherits the filter from Parent. The flags are not inherited.
|
|
||||||
|
|
||||||
Child2 only inherits the "~/my_project" from Parent.
|
|
||||||
|
|
||||||
Thus, the example above is exactly equivalent to this:
|
|
||||||
>
|
|
||||||
Parent=~/my_project CD=. filter="Make* *.mk" flags=r {
|
|
||||||
Child1=~/my_project/c_code CD=~/my_project filter="Make* *.mk" {
|
|
||||||
}
|
|
||||||
Child2=~/my_project/include CD=~/my_project/include filter="*.h" {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(For a real Project, Child1 would not want to inherit its parent's filter, but
|
|
||||||
this example shows the concept.) You can always enter \i to display what the
|
|
||||||
cursor's project inherits.
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
MAPPINGS *project-mappings*
|
|
||||||
|
|
||||||
Map Action ~
|
|
||||||
|
|
||||||
\r Refreshes the Project fold that the cursor is in by placing in the
|
|
||||||
fold all the files that match the filter. The Project is refreshed
|
|
||||||
using an indent of one space for every foldlevel in the hierarchy.
|
|
||||||
|
|
||||||
You may place a "# pragma keep" (without the quotes) at the end of a
|
|
||||||
line, and the file entry on that line will not be removed when you
|
|
||||||
refresh. This is useful, for example, when you have . as an entry so
|
|
||||||
you can easily browse the directory.
|
|
||||||
|
|
||||||
Note that this mapping is actually <LocalLeader>r, and the default of
|
|
||||||
|<LocalLeader>| is \.
|
|
||||||
|
|
||||||
This does not work for Projects using |netrw|.
|
|
||||||
|
|
||||||
\R Executes \r recursively in the current fold and all folds below.
|
|
||||||
This does not work for Projects using |netrw|.
|
|
||||||
|
|
||||||
\c Creates a Project fold entry. It asks for the description, the path
|
|
||||||
to the files, the CD parameter, and the filename |glob()| pattern.
|
|
||||||
From this information, it will create the Project Entry below the
|
|
||||||
cursor.
|
|
||||||
|
|
||||||
This does not work for Projects using |netrw|.
|
|
||||||
|
|
||||||
\C Creates a Project fold entry like \c, but recursively includes all the
|
|
||||||
subdirectories.
|
|
||||||
|
|
||||||
<Return>
|
|
||||||
Select a file to open in the |CTRL-W_p| window or in a new window. If
|
|
||||||
the cursor is on a fold, open or close it.
|
|
||||||
|
|
||||||
<S-Return>
|
|
||||||
\s
|
|
||||||
Same as <Return> but horizontally split the target window.
|
|
||||||
<LocalLeader>s is provided for those terminals that don't recognize
|
|
||||||
<S-Return>.
|
|
||||||
|
|
||||||
\S
|
|
||||||
Load all files in a project by doing horizontal splits.
|
|
||||||
|
|
||||||
<C-Return>
|
|
||||||
\o
|
|
||||||
Same as <Return> but ensure that the opened file is the only other
|
|
||||||
window. <LocalLeader>o is provided for those terminals that don't
|
|
||||||
recognize <C-Return>.
|
|
||||||
|
|
||||||
<M-Return>
|
|
||||||
\v
|
|
||||||
Same as <Return> but only display the file--the cursor stays in the
|
|
||||||
Project Window.
|
|
||||||
|
|
||||||
<2-LeftMouse>
|
|
||||||
(Double-click) If on a closed fold, open it. If on an open fold
|
|
||||||
boundary, close it. If on a filename, open the file in the |CTRL-W_p|
|
|
||||||
window or in a new window.
|
|
||||||
|
|
||||||
<S-2-LeftMouse>
|
|
||||||
Same as <S-Return>.
|
|
||||||
|
|
||||||
<C-2-LeftMouse>
|
|
||||||
Same as <C-Return>.
|
|
||||||
|
|
||||||
<RightMouse>
|
|
||||||
Increase the width of the Project Window by g:proj_window_increment or
|
|
||||||
toggle between a width of
|
|
||||||
g:proj_window_width + g:proj_window_increment
|
|
||||||
and
|
|
||||||
g:proj_window_width.
|
|
||||||
|
|
||||||
Whether you toggle or monotonically increase the width is determined
|
|
||||||
by the 't' flag of the g:proj_flags variable (see |project-flags|).
|
|
||||||
|
|
||||||
Note that a Right Mouse click will not automatically place the cursor
|
|
||||||
in the Project Window if it is in a different window. The window will
|
|
||||||
go back to the g:proj_window_width width when you leave the window.
|
|
||||||
|
|
||||||
<space> Same as <RightMouse>
|
|
||||||
|
|
||||||
<CTRL-Up>
|
|
||||||
\<Up>
|
|
||||||
Move the text or fold under the cursor up one row. This may not work
|
|
||||||
in a terminal because the terminal is unaware of this key combination.
|
|
||||||
<LocalLeader><Up> is provided for those terminals that don't recognize
|
|
||||||
<C-Up>.
|
|
||||||
|
|
||||||
|
|
||||||
<CTRL-Down>
|
|
||||||
\<Down>
|
|
||||||
Move the text or fold under the cursor down one row. This may not work
|
|
||||||
in a terminal because the terminal is unaware of this key combination.
|
|
||||||
<LocalLeader><Down> is provided for those terminals that don't
|
|
||||||
recognize <C-Down>.
|
|
||||||
|
|
||||||
\i Show in the status line the completely resolved and inherited
|
|
||||||
parameters for the fold the cursor is in. This is intended for
|
|
||||||
debugging your relative path and inherited parameters for manually
|
|
||||||
entered Projects.
|
|
||||||
|
|
||||||
\I Show in the status line the completely resolved filename. Uses the
|
|
||||||
Project_GetFname(line('.')) function.
|
|
||||||
|
|
||||||
\1 - \9
|
|
||||||
Run the command specified in g:proj_run{x} where {x} is the number
|
|
||||||
of the key. See the documentation of g:proj_run1 below.
|
|
||||||
|
|
||||||
\f1-\f9
|
|
||||||
Run the command specified in g:proj_run_fold{x} where {x} is the
|
|
||||||
number of the key. The command is run on the files at the current
|
|
||||||
Project level. See the |project-settings| below.
|
|
||||||
|
|
||||||
\F1-\F9
|
|
||||||
Run the command specified in g:proj_run_fold{x} where {x} is the
|
|
||||||
number of the key. The command is run on the files at the current
|
|
||||||
Project level and all Subprojects. See the |project-settings| below.
|
|
||||||
|
|
||||||
\0 Display the commands that are defined for \1 through \9.
|
|
||||||
|
|
||||||
\f0 Display the commands that are defined for \f1 through \f9 and \F1
|
|
||||||
through \F0. Same as \F0.
|
|
||||||
|
|
||||||
\l Load all the files in the current Project level into Vim. While files
|
|
||||||
are being loaded, you may press any key to stop.
|
|
||||||
|
|
||||||
\L Load all the files in the current Project and all Subprojects into
|
|
||||||
Vim. Use this mapping with caution--I wouldn't suggest using \L to
|
|
||||||
load a Project with thousands of files. (BTW, my Project file has more
|
|
||||||
than 5,300 files in it!) While files are being loaded, you may press
|
|
||||||
any key to stop.
|
|
||||||
|
|
||||||
\w Wipe all the files in the current Project level from Vim. (If files
|
|
||||||
are modified, they will be saved first.) While files are being wiped,
|
|
||||||
you may press any key to stop.
|
|
||||||
|
|
||||||
\W Wipe all the files in the current Project and all Subprojects from
|
|
||||||
Vim. (If files are modified, they will be saved first.) While files
|
|
||||||
are being wiped, you may press any key to stop.
|
|
||||||
|
|
||||||
\g Grep all the files in the current Project level.
|
|
||||||
|
|
||||||
\G Grep all the files in the current Project level and all Subprojects.
|
|
||||||
|
|
||||||
\e Set up the Environment for the Project File as though you had selected
|
|
||||||
it with <Return>. This allows you to do a \e and a :make without
|
|
||||||
having to open any files in the project.
|
|
||||||
|
|
||||||
\E Explore (using |file-explorer|) the directory of the project the
|
|
||||||
cursor is in. Does not work with netrw.
|
|
||||||
|
|
||||||
<F12> When the 'g' flag is present in g:proj_flags (see |project-flags|)
|
|
||||||
this key toggles the Project Window open and closed. You may remap
|
|
||||||
this toggle function by putting the following in your vimrc and
|
|
||||||
replacing <Leader>P with whatever key combination you wish:
|
|
||||||
|
|
||||||
nmap <silent> <Leader>P <Plug>ToggleProject
|
|
||||||
|
|
||||||
Note that the Project Plugin remaps :help because the Help Window and the
|
|
||||||
Project Window get into a fight over placement. The mapping avoids the
|
|
||||||
problem.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
ADDING MAPPINGS *project-adding-mappings*
|
|
||||||
|
|
||||||
You can add your own mappings or change the mappings of the plugin by placing
|
|
||||||
them in the file $HOME/.vimproject_mappings. This file, if it exists, will be
|
|
||||||
sourced when the plugin in loaded. Here is an example that will count the
|
|
||||||
number of entries in a project when you press \K (Kount, C is taken :-): >
|
|
||||||
|
|
||||||
function! s:Wc()
|
|
||||||
let b:loadcount=0
|
|
||||||
function! SpawnExec(infoline, fname, lineno, data)
|
|
||||||
let b:loadcount = b:loadcount + 1
|
|
||||||
if getchar(0) != 0 | let b:stop_everything=1 | endif
|
|
||||||
endfunction
|
|
||||||
call Project_ForEach(1, line('.'), "*SpawnExec", 0, '')
|
|
||||||
delfunction SpawnExec
|
|
||||||
echon b:loadcount." Files\r"
|
|
||||||
unlet b:loadcount
|
|
||||||
if exists("b:stop_everything")
|
|
||||||
unlet b:stop_everything
|
|
||||||
echon "Aborted.\r"
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
nnoremap <buffer> <silent> <LocalLeader>K :call <SID>Wc()<CR>
|
|
||||||
|
|
||||||
Here's another example of how I integrated the use of perforce with the plugin
|
|
||||||
in my $HOME/.vimproject_mappings:
|
|
||||||
>
|
|
||||||
function! s:DoP4(cmd)
|
|
||||||
let name=Project_GetFname(line('.'))
|
|
||||||
let dir=substitute(name, '\(.*\)/.*', '\1', 'g')
|
|
||||||
exec 'cd '.dir
|
|
||||||
exec "!".a:cmd.' '.Project_GetFname(line('.'))
|
|
||||||
cd -
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
nmap <buffer> <silent> \pa :call <SID>DoP4("p4add")<CR>
|
|
||||||
nmap <buffer> <silent> \pe :call <SID>DoP4("p4edit")<CR>
|
|
||||||
<
|
|
||||||
(Note that I CD to the directory the file is in so I can pick of the $P4CONFIG
|
|
||||||
file. See the perforce documentation.)
|
|
||||||
|
|
||||||
This creates the mappings \pe to check out the file for edit and \pa to add
|
|
||||||
the file to the depot.
|
|
||||||
|
|
||||||
Here is another example where I remap the <Return> mapping to use an external
|
|
||||||
program to launch a special kind of file (in this case, it launches ee to view
|
|
||||||
a jpg file). It is a bit contrived, but it works.
|
|
||||||
>
|
|
||||||
let s:sid = substitute(maparg('<Return>', 'n'), '.*\(<SNR>.\{-}\)_.*', '\1', '')
|
|
||||||
function! s:LaunchOrWhat()
|
|
||||||
let fname=Project_GetFname(line('.'))
|
|
||||||
if fname =~ '\.jpg$'
|
|
||||||
exec 'silent! !ee "'.fname.'"&'
|
|
||||||
else
|
|
||||||
call {s:sid}_DoFoldOrOpenEntry('', 'e')
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
nnoremap <buffer> <silent> <Return> \|:call <SID>LaunchOrWhat()<CR>
|
|
||||||
<
|
|
||||||
If the file ends in .jpg, the external program is launched, otherwise the
|
|
||||||
original mapping of <Return> is run.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
SETTINGS *project-settings*
|
|
||||||
|
|
||||||
You can set these variables in your vimrc file before the plugin is loaded to
|
|
||||||
change its default behavior
|
|
||||||
|
|
||||||
g:proj_window_width
|
|
||||||
The width of the Project Window that the plugin attempts to maintain.
|
|
||||||
Default: 24
|
|
||||||
|
|
||||||
The Project Plugin is not always successful in keeping the window
|
|
||||||
where I want it with the size specified here, but it does a decent
|
|
||||||
job.
|
|
||||||
|
|
||||||
g:proj_window_increment
|
|
||||||
The increment by which to increase the width of the Project Window
|
|
||||||
when pressing <space> or clicking the <LeftMouse>. Default: 100
|
|
||||||
(See |project-mappings|.)
|
|
||||||
|
|
||||||
*project-flags*
|
|
||||||
g:proj_flags
|
|
||||||
Default: "imst"
|
|
||||||
Various flags to control the behavior of the Project Plugin. This
|
|
||||||
variable can contain any of the following character flags.
|
|
||||||
|
|
||||||
flag Description ~
|
|
||||||
|
|
||||||
b When present, use the |browse()| when selecting directories
|
|
||||||
for \c and \C. This is off by default for Windows, because
|
|
||||||
the windows browser does not allow you to select directories.
|
|
||||||
|
|
||||||
c When present, the Project Window will automatically close when
|
|
||||||
you select a file.
|
|
||||||
|
|
||||||
F Float the Project Window. That is, turn off automatic
|
|
||||||
resizing and placement. This allows placement between other
|
|
||||||
windows that wish to share similar placement at the side of
|
|
||||||
the screen. It is also particularly helpful for external
|
|
||||||
window managers.
|
|
||||||
|
|
||||||
g When present, the mapping for <F12> will be created to toggle
|
|
||||||
the Project Window open and closed.
|
|
||||||
|
|
||||||
i When present, display the filename and the current working
|
|
||||||
directory in the command line when a file is selected for
|
|
||||||
opening.
|
|
||||||
|
|
||||||
l When present, the Project Plugin will use the |:lcd| command
|
|
||||||
rather than |:cd| to change directories when you select a file
|
|
||||||
to open. This flag is really obsolete and not of much use
|
|
||||||
because of L below.
|
|
||||||
|
|
||||||
L Similar to l, but install a BufEnter/Leave |:autocommand| to
|
|
||||||
ensure that the current working directory is changed to the
|
|
||||||
one specified in the fold CD specification whenever that
|
|
||||||
buffer is active. (|:lcd| only changes the CWD for a window,
|
|
||||||
not a buffer.)
|
|
||||||
|
|
||||||
m Turn on mapping of the |CTRL-W_o| and |CTRL-W_CTRL_O| normal
|
|
||||||
mode commands to make the current buffer the only visible
|
|
||||||
buffer, but keep the Project Window visible, too.
|
|
||||||
|
|
||||||
n When present, numbers will be turned on for the project
|
|
||||||
window.
|
|
||||||
|
|
||||||
s When present, the Project Plugin will use syntax highlighting
|
|
||||||
in the Project Window.
|
|
||||||
|
|
||||||
S Turn on sorting for refresh and create.
|
|
||||||
|
|
||||||
t When present, toggle the size of the window rather than just
|
|
||||||
increase the size when pressing <space> or right-clicking.
|
|
||||||
See the entry for <RightMouse> in |project-mappings|.
|
|
||||||
|
|
||||||
T When present, put Subproject folds at the top of the fold when
|
|
||||||
refreshing.
|
|
||||||
|
|
||||||
v When present, use :vimgrep rather than :grep when using \G.
|
|
||||||
|
|
||||||
g:proj_run1 ... g:proj_run9
|
|
||||||
Contains a Vim command to execute on the file. See the
|
|
||||||
mappings of \1 to \9 above.
|
|
||||||
|
|
||||||
%f is replaced with the full path and filename
|
|
||||||
%F is replaced with the full path and filename with spaces
|
|
||||||
quoted
|
|
||||||
%n is replaced with the filename alone
|
|
||||||
%N is replaced with the filename alone with spaces quoted
|
|
||||||
%h is replaced with the home directory
|
|
||||||
%H is replaced with the home directory with spaces quoted
|
|
||||||
%r is replaced with the directory relative to the CD path
|
|
||||||
%R is replaced with the directory relative to the CD path
|
|
||||||
with spaces quoted
|
|
||||||
%d is replaced with the CD directory.
|
|
||||||
%D is replaced with the CD directory.with spaces quoted
|
|
||||||
%% is replaced with a single % that is not used in
|
|
||||||
expansion.
|
|
||||||
|
|
||||||
(Deprecated: %s is also replaced with the full path and
|
|
||||||
filename for backward compatibility.)
|
|
||||||
|
|
||||||
For example, gvim will be launched on the file under the
|
|
||||||
cursor when you enter \3 if the following is in your vimrc
|
|
||||||
file: >
|
|
||||||
let g:proj_run3='silent !gvim %f'
|
|
||||||
< Here are a few other examples: >
|
|
||||||
let g:proj_run1='!p4 edit %f'
|
|
||||||
let g:proj_run2='!p4 add %f'
|
|
||||||
let g:proj_run4="echo 'Viewing %f'|sil !xterm -e less %f &"
|
|
||||||
<
|
|
||||||
On Windows systems you will want to put the %f, %h, and %d in
|
|
||||||
single quotes to avoid \ escaping.
|
|
||||||
|
|
||||||
g:proj_run_fold1 ... g:proj_run_fold9
|
|
||||||
Contains a Vim command to execute on the files in a fold. See
|
|
||||||
the mappings of \f1 to \f9 and \F1 to \F9 above.
|
|
||||||
|
|
||||||
%f is the filename, %h is replaced with the project home
|
|
||||||
directory, and %d is replaced with the CD directory. Multiple
|
|
||||||
filenames can be handled in two ways:
|
|
||||||
|
|
||||||
The first (default) way is to have %f replaced with all the
|
|
||||||
absolute filenames, and the command is run once. The second
|
|
||||||
is to have the command run for each of the non-absolute
|
|
||||||
filenames (%f is replaced with one filename at a time). To
|
|
||||||
select the second behavior, put an '*' character at the
|
|
||||||
beginning of the g:proj_run_fold{x} variable. (The '*' is
|
|
||||||
stripped before the command is run.)
|
|
||||||
|
|
||||||
For example, note the difference between the following: >
|
|
||||||
let g:proj_run_fold3="*echo '%h/%f'"
|
|
||||||
let g:proj_run_fold4="echo '%f'"
|
|
||||||
<
|
|
||||||
Note that on Windows systems, you will want the %f, %h, and %c
|
|
||||||
within single quotes, or the \ in the paths will cause
|
|
||||||
problems. The alternative is to put them in |escape()|.
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
PROJECT EXAMPLE FILE *project-example*
|
|
||||||
|
|
||||||
Here is an example ~/.vimprojects file: >
|
|
||||||
|
|
||||||
1 My Project=~/c/project CD=. in=in.vim out=out.vim flags=r {
|
|
||||||
2 Makefile
|
|
||||||
3 in.vim
|
|
||||||
4 out.vim
|
|
||||||
5 GUI Files=. filter="gui*.c gui*.h" {
|
|
||||||
6 gui_window.c
|
|
||||||
7 gui_dialog.c
|
|
||||||
8 gui_list.c
|
|
||||||
9 gui.h # Header file
|
|
||||||
10 }
|
|
||||||
11 Database Files=. filter="data*.c data*.h" {
|
|
||||||
12 data_read.c
|
|
||||||
13 data_write.c
|
|
||||||
14 data.h
|
|
||||||
15 }
|
|
||||||
16 OS-Specific Files {
|
|
||||||
17 Win32=. filter="os_win32*.c os_win32*.h" {
|
|
||||||
18 os_win32_gui.c
|
|
||||||
19 os_win32_io.c
|
|
||||||
20 }
|
|
||||||
21 Unix=. filter="os_unix*.c os_unix*.h" {
|
|
||||||
22 os_unix_gui.c
|
|
||||||
23 os_unix_io.c
|
|
||||||
24 }
|
|
||||||
25 }
|
|
||||||
26 }
|
|
||||||
|
|
||||||
(Don't type in the line numbers, of course.)
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
TIPS ON USING PROJECT PLUGIN *project-tips*
|
|
||||||
|
|
||||||
1. You can create a Project Entry by entering this: >
|
|
||||||
|
|
||||||
Label=~/wherever CD=. filter="*.c *.h" {
|
|
||||||
}
|
|
||||||
<
|
|
||||||
Then you can put the cursor in the fold and press \r. The script will fill
|
|
||||||
in the files (C files in this case) from this directory for you. This is
|
|
||||||
equivalent to \c without any dialogs.
|
|
||||||
|
|
||||||
2. You can edit the Project File at any time to add, remove, or reorder files
|
|
||||||
in the Project list.
|
|
||||||
|
|
||||||
3. If the Project Window ever gets closed, you can just enter >
|
|
||||||
:Project
|
|
||||||
< to bring it back again. (You don't need to give it the filename; the
|
|
||||||
plugin remembers.)
|
|
||||||
|
|
||||||
If you have the 'm' flag set in g:proj_flags, then you get the Project
|
|
||||||
Window to show up again by pressing |CTRL-W_o|. This, of course, will
|
|
||||||
close any other windows that may be open that the cursor is not in.
|
|
||||||
|
|
||||||
4. Adding files to a Project is very easy. To add, for example, the 'more.c'
|
|
||||||
file to the Project, just insert the filename in the Project Entry then
|
|
||||||
hit <Return> on it.
|
|
||||||
|
|
||||||
5. When |quickfix| loads files, it is not equivalent to pressing <Return> on
|
|
||||||
a filename, so the directory will not be changed and the scripts will not
|
|
||||||
be run. (If I could make this otherwise, I would.) The solution is to use
|
|
||||||
the \L key to load all of the files in the Project before running
|
|
||||||
quickfix.
|
|
||||||
|
|
||||||
6. If the Project window gets a bit cluttered with folds partially
|
|
||||||
open/closed, you can press |zM| to close everything and tidy it up.
|
|
||||||
|
|
||||||
7. For advanced users, I am exporting the function Project_GetAllFnames()
|
|
||||||
which returns all the filenames within a fold and optionally all its
|
|
||||||
Subprojects. Also, I export Project_ForEach() for running a function for
|
|
||||||
each filename in the project. See the code for examples on how to use
|
|
||||||
these. Finally, I export Project_GetFname(line_number) so that you can
|
|
||||||
write your own mappings and get the filename for it.
|
|
||||||
|
|
||||||
8. Some people have asked how to do a global mapping to take the cursor to
|
|
||||||
the Project window. One of my goals for the plugin is for it to be as
|
|
||||||
self-contained as possible, so I'm not going to add it by default. But you
|
|
||||||
can put this in your vimrc:
|
|
||||||
>
|
|
||||||
nmap <silent> <Leader>P :Project<CR>
|
|
||||||
|
|
||||||
<
|
|
||||||
9. You can put the . entry in a project, and it will launch the
|
|
||||||
|file-explorer| plugin on the directory. To avoid removal when you
|
|
||||||
refresh, make the entry look like this:
|
|
||||||
>
|
|
||||||
. # pragma keep
|
|
||||||
<
|
|
||||||
==============================================================================
|
|
||||||
THANKS
|
|
||||||
|
|
||||||
The following people have sent me patches to help with the Project
|
|
||||||
Plugin development:
|
|
||||||
|
|
||||||
Tomas Zellerin
|
|
||||||
Lawrence Kesteloot
|
|
||||||
Dave Eggum
|
|
||||||
A Harrison
|
|
||||||
Thomas Link
|
|
||||||
Richard Bair
|
|
||||||
Eric Arnold
|
|
||||||
Peter Jones
|
|
||||||
Eric Van Dewoestine
|
|
||||||
|
|
||||||
|
|
||||||
vim:ts=8 sw=8 noexpandtab tw=78 ft=help:
|
|
||||||
198
doc/vimblogger_ft.txt
Normal file
198
doc/vimblogger_ft.txt
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
*vimblogger_ft.txt* reStructuredText to Blogger Interface
|
||||||
|
Author: Roman Dobosz, gryf73 at gmail com
|
||||||
|
|
||||||
|
Simple interface to create blog articles in rsST format. It provides
|
||||||
|
commands for preview in browser, post and delete articles.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Requirements~
|
||||||
|
|
||||||
|
Module for communication was written in Python. So, VIm has to be
|
||||||
|
compiled with +python.
|
||||||
|
|
||||||
|
Other requirements:
|
||||||
|
|
||||||
|
- Python (tested with version 2.6, should work also in others)
|
||||||
|
- gdata http://code.google.com/p/gdata-python-client
|
||||||
|
- docutils http://docutils.sourceforge.net
|
||||||
|
- pygments http://pygments.org
|
||||||
|
- Blogger account
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Install~
|
||||||
|
|
||||||
|
Extract zip file into your ~/.vim.
|
||||||
|
|
||||||
|
========================================================================
|
||||||
|
Usage~
|
||||||
|
|
||||||
|
This plugin is targeting for people, who has blogger account, want to
|
||||||
|
use vim for creating blog articles and don't really likes to manually do
|
||||||
|
this in html.
|
||||||
|
|
||||||
|
Unfortunately it has several limitations, like you cannot use multiple
|
||||||
|
blogs or edit existing articles without reST source files. You have to
|
||||||
|
somehow convert it reStructuredText, add *Id* and then update it.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Options~
|
||||||
|
*g:blogger_browser*
|
||||||
|
g:blogger_browser (default: 0)
|
||||||
|
|
||||||
|
If set to 1 output file from :PreviewBlogArticle will be opened in
|
||||||
|
browser (used webbrowser Python module)
|
||||||
|
|
||||||
|
*g:blogger_name*
|
||||||
|
g:blogger_name (default: "")
|
||||||
|
|
||||||
|
This is blog name, which is part of the URL, and you was obligated
|
||||||
|
to enter it during blog creation. If you don't remember it, just
|
||||||
|
check first part od the URL of your blog, just after 'http://'.
|
||||||
|
Don't be confused with the blog title.
|
||||||
|
|
||||||
|
*g:blogger_login*
|
||||||
|
g:blogger_login (default: "")
|
||||||
|
|
||||||
|
Google login name, usually gmail address.
|
||||||
|
*g:blogger_pass*
|
||||||
|
g:blogger_pass (default: "")
|
||||||
|
|
||||||
|
Password. If set to empty string, You'll be asked for it every time
|
||||||
|
you do any blogger activity.
|
||||||
|
*g:blogger_draft*
|
||||||
|
g:blogger_draft (default: 1)
|
||||||
|
|
||||||
|
By default, don't publish articles immediately, just save it on the
|
||||||
|
service. If set to 0, article will be published.
|
||||||
|
|
||||||
|
*g:blogger_maxarticles*
|
||||||
|
g:blogger_maxarticles (default: 0)
|
||||||
|
|
||||||
|
Number of displayed articles during deletion. 0 means all. Any
|
||||||
|
positive number will display only that numbers of articles on list.
|
||||||
|
|
||||||
|
*g:blogger_confirm_del*
|
||||||
|
g:blogger_confirm_del (default: 1)
|
||||||
|
|
||||||
|
Confirm every deletion. If set to 0, suppress the confirmation.
|
||||||
|
|
||||||
|
*g:blogger_stylesheets*
|
||||||
|
g:blogger_stylesheets (default: [])
|
||||||
|
|
||||||
|
List of relative paths (relative to generated HTML document) of CSS
|
||||||
|
stylesheets, used only for article preview in HTML document. Usually
|
||||||
|
one wanted to save stylesheets from his own blog, so that article
|
||||||
|
can be displayed almost in the same way as in blog.
|
||||||
|
|
||||||
|
========================================================================
|
||||||
|
Commands~
|
||||||
|
|
||||||
|
*:PreviewBlogArticle*
|
||||||
|
|
||||||
|
Generate article in HTML format, save it to the file with te same
|
||||||
|
name as a reST source with .html extension in the same directory,
|
||||||
|
and optionally opens it in browser. No connection to the blogger is
|
||||||
|
performed.
|
||||||
|
|
||||||
|
*:SendBlogArticle*
|
||||||
|
|
||||||
|
Generate partial HTML document, which holds article, from current
|
||||||
|
reST buffer and send it to the blog.
|
||||||
|
|
||||||
|
See reST document structure below for further description.
|
||||||
|
|
||||||
|
*:DeleteBlogArticle*
|
||||||
|
|
||||||
|
Display list of articles, and lets user choose one (or none) of them
|
||||||
|
to perform deletions.
|
||||||
|
|
||||||
|
========================================================================
|
||||||
|
reST document structure~
|
||||||
|
|
||||||
|
It is assumed, that following template will be used:
|
||||||
|
|
||||||
|
-----8<-----
|
||||||
|
:Id:
|
||||||
|
:Title: Title for the blog
|
||||||
|
:Date:
|
||||||
|
:Modified:
|
||||||
|
:Tags: some, tags
|
||||||
|
|
||||||
|
Penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla
|
||||||
|
facilisis massa ut massa. Sed nisi purus, malesuada eu, porta vulputate,
|
||||||
|
suscipit auctor, nunc. Vestibulum convallis, augue eu luctus malesuada,
|
||||||
|
mi ante mattis odio, ac venenatis neque sem vitae nisi.
|
||||||
|
|
||||||
|
.. more
|
||||||
|
|
||||||
|
|
||||||
|
heading
|
||||||
|
-------
|
||||||
|
|
||||||
|
**Congue** mi, quis posuere augue nulla a augue. Pellentesque sed est.
|
||||||
|
Mauris cursus urna id lectus. Integer dignissim feugiat eros. Sed tempor
|
||||||
|
volutpat dolor. Vestibulum vel lectus nec mauris semper adipiscing.
|
||||||
|
|
||||||
|
Aliquam tincidunt enim sit amet tellus. Sed mauris nulla, semper
|
||||||
|
tincidunt, luctus a, sodales eget, leo. Sed ligula augue, cursus et.
|
||||||
|
----->8-----
|
||||||
|
|
||||||
|
reST document (optionally) starts with *docinfo* section (first several
|
||||||
|
lines, that are starting from *:* character) separaded from other
|
||||||
|
content with one empty line.
|
||||||
|
|
||||||
|
Docinfo items holds article attributes, and are updated automatically
|
||||||
|
every each of upload to blogger, which is triggered by
|
||||||
|
*:SendBlogArticle* command.
|
||||||
|
|
||||||
|
*:Id:*
|
||||||
|
Holds article id on blogger side. If not defined, new article will
|
||||||
|
be created (even if there is already existing one with the very same
|
||||||
|
content). If wrong id is entered (or an Id of deleted article),
|
||||||
|
exception will be raised, and no action on blogger side will be
|
||||||
|
performed.
|
||||||
|
|
||||||
|
*:Title:*
|
||||||
|
Holds article title. Can be changed when *:Id:* is obtained.
|
||||||
|
|
||||||
|
*:Date:*
|
||||||
|
This is published date in RFC 3339
|
||||||
|
http://www.ietf.org/rfc/rfc3339.txt format. If empty on first
|
||||||
|
upload, it will be set to current date. Can be set/changed to
|
||||||
|
desired date.
|
||||||
|
|
||||||
|
*:Modified:*
|
||||||
|
This is read-only item, which store modification date which happens
|
||||||
|
on blogger side.
|
||||||
|
|
||||||
|
*:Tags:*
|
||||||
|
Comma separated list of tags (Labels). Can be empty.
|
||||||
|
|
||||||
|
All other items are ignored.
|
||||||
|
|
||||||
|
After docinfo block, article body should be placed using markup for
|
||||||
|
reStructuredText.
|
||||||
|
|
||||||
|
Additionally, there is sourcecode directive, simple syntax highlighter
|
||||||
|
using Pygments module. Very simple usage could be as follows:
|
||||||
|
|
||||||
|
-----8<-----
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
import vim
|
||||||
|
print vim.current.buffer.name
|
||||||
|
|
||||||
|
----->8-----
|
||||||
|
|
||||||
|
Note: All headings for generated HTML by *:SendBlogArticle* will be
|
||||||
|
shifted by 3, so the first heading will become <h3>, second <h4> and so
|
||||||
|
on, to fit into blogger template (well, most of them). Remember, that
|
||||||
|
HTML allow up to 6 level of headings, while reST doesn't have this
|
||||||
|
limitation.
|
||||||
|
|
||||||
|
========================================================================
|
||||||
|
Changelog~
|
||||||
|
|
||||||
|
0.1 First release
|
||||||
|
|
||||||
|
vim:tw=72:fo=tcq2:isk=!-~,^*,^|,^":ts=8:ft=help:norl:
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
" Blogger vim interface.
|
|
||||||
" Provide some convinient functions for creating preview from the reST file
|
|
||||||
" and to send articles to blog.
|
|
||||||
|
|
||||||
if exists("b:did_rst_plugin")
|
|
||||||
finish " load only once
|
|
||||||
else
|
|
||||||
let b:did_rst_plugin = 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists("g:blogger_browser")
|
|
||||||
let g:blogger_browser = 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists("g:blogger_name")
|
|
||||||
let g:blogger_name = ""
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists("g:blogger_login")
|
|
||||||
let g:blogger_login= ""
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists("g:blogger_pass")
|
|
||||||
let g:blogger_pass = ""
|
|
||||||
endif
|
|
||||||
|
|
||||||
map <F6> :call <SID>Restify()<cr>
|
|
||||||
map <F7> :call <SID>Rst2Blogger()<cr>
|
|
||||||
|
|
||||||
if !exists('*s:Restify')
|
|
||||||
python << EOF
|
|
||||||
#{{{
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import webbrowser
|
|
||||||
|
|
||||||
import vim
|
|
||||||
|
|
||||||
scriptdir = os.path.dirname(vim.eval('expand("<sfile>")'))
|
|
||||||
sys.path.insert(0, scriptdir)
|
|
||||||
try:
|
|
||||||
from vimblogger.rest import blogPreview, blogArticleString
|
|
||||||
from vimblogger.blogger import VimBlogger
|
|
||||||
except ImportError:
|
|
||||||
print "Plugin blogger cannot be loaded, due to lack of required modules"
|
|
||||||
#}}}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
" Translate reSt text into html fragment suitable for preview in browser.
|
|
||||||
fun <SID>Restify()
|
|
||||||
python << EOF
|
|
||||||
# {{{
|
|
||||||
bufcontent = "\n".join(vim.current.buffer)
|
|
||||||
name = vim.current.buffer.name
|
|
||||||
|
|
||||||
name = name[:-4] + ".html"
|
|
||||||
html = blogPreview(bufcontent)
|
|
||||||
output_file = open(name, "w")
|
|
||||||
output_file.write(html)
|
|
||||||
output_file.close()
|
|
||||||
if vim.eval("g:blogger_browser"):
|
|
||||||
webbrowser.open(name)
|
|
||||||
print "Generated HTML has been opened in browser"
|
|
||||||
else:
|
|
||||||
print "Generated HTML has been written to %s" % name
|
|
||||||
#}}}
|
|
||||||
EOF
|
|
||||||
endfun
|
|
||||||
|
|
||||||
" Generate headless html, gather title, dates and tags from filed list and
|
|
||||||
" then send it to blog.
|
|
||||||
fun <SID>Rst2Blogger()
|
|
||||||
python << EOF
|
|
||||||
#{{{
|
|
||||||
bufcontent = "\n".join(vim.current.buffer)
|
|
||||||
name = vim.current.buffer.name
|
|
||||||
html, attrs = blogArticleString(bufcontent)
|
|
||||||
|
|
||||||
login = vim.eval("g:blogger_login")
|
|
||||||
password = vim.eval("g:blogger_pass")
|
|
||||||
blogname = vim.eval("g:blogger_name")
|
|
||||||
|
|
||||||
if not password:
|
|
||||||
password = vim.eval('inputsecret("Enter your gmail password: ")')
|
|
||||||
|
|
||||||
title = 'title' in attrs and attrs['title'] or None
|
|
||||||
date = 'date' in attrs and attrs['date'] or None
|
|
||||||
tags = 'tags' in attrs and attrs['tags'] or ""
|
|
||||||
tags = [tag.strip() for tag in tags.split(',')]
|
|
||||||
modified = 'modified' in attrs and attrs['modified'] or None
|
|
||||||
|
|
||||||
blog = VimBlogger(blogname, login, password)
|
|
||||||
print blog.create_article(title, html, tags=tags)
|
|
||||||
|
|
||||||
#}}}
|
|
||||||
EOF
|
|
||||||
endfun
|
|
||||||
endif
|
|
||||||
@@ -9,3 +9,7 @@ setlocal formatoptions=tcq "set VIms default
|
|||||||
let g:blogger_login="gryf73"
|
let g:blogger_login="gryf73"
|
||||||
let g:blogger_name="rdobosz"
|
let g:blogger_name="rdobosz"
|
||||||
let g:blogger_browser=1
|
let g:blogger_browser=1
|
||||||
|
let g:blogger_stylesheets=["css/widget_css_2_bundle.css", "css/style_custom.css", "css/style_blogger.css"]
|
||||||
|
|
||||||
|
map <F6> :PreviewBlogArticle<cr>
|
||||||
|
map <F7> :SendBlogArticle<cr>
|
||||||
|
|||||||
1
ftplugin/rst/rst2blogger/__init__.py
Normal file
1
ftplugin/rst/rst2blogger/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# module vimblogger
|
||||||
258
ftplugin/rst/rst2blogger/blogger.py
Normal file
258
ftplugin/rst/rst2blogger/blogger.py
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
# vim: fileencoding=utf8
|
||||||
|
#
|
||||||
|
# Blogger interface to make easy way to create/update articles for specified
|
||||||
|
# blog.
|
||||||
|
#
|
||||||
|
# It is assumed one way communication only, so you may create or update an
|
||||||
|
# article from reST source files. There is no way to recreate article from
|
||||||
|
# html to reST format.
|
||||||
|
#
|
||||||
|
# requirements:
|
||||||
|
#
|
||||||
|
# - Vim compiled with +python
|
||||||
|
# - python 2.x (tested with 2.6)
|
||||||
|
# - modules
|
||||||
|
# - gdata (http://code.google.com/p/gdata-python-client)
|
||||||
|
# - docutils (http://docutils.sourceforge.net)
|
||||||
|
#
|
||||||
|
# USE CASES:
|
||||||
|
# 1. Create new post
|
||||||
|
#
|
||||||
|
# use reST template:
|
||||||
|
# ===8<---
|
||||||
|
# :Title: Blog post title
|
||||||
|
# :Date: optional publish date (for example: 2010-11-28 18:47:05),
|
||||||
|
# default: now()
|
||||||
|
# :Modified: optional, default: None
|
||||||
|
# :Tags: comma separated blog tags
|
||||||
|
#
|
||||||
|
# .. more
|
||||||
|
#
|
||||||
|
# --->8===
|
||||||
|
#
|
||||||
|
# All four docinfo are optional, however it is nice to give at least a title
|
||||||
|
# to the article :)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# which is provided under templates directory or as a
|
||||||
|
# snipMate shoortcut (see .vim/snippets/rst.snippets)
|
||||||
|
#
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
import datetime
|
||||||
|
import re
|
||||||
|
|
||||||
|
import atom
|
||||||
|
from gdata.blogger.client import BloggerClient, BLOG_POST_URL
|
||||||
|
from gdata.blogger.data import BlogPost
|
||||||
|
|
||||||
|
|
||||||
|
class VimBlogger(object):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
DATE_PATTERN = re.compile(r"^(\d{4}-\d{2}-\d{2})"
|
||||||
|
"T(\d{2}:\d{2}:\d{2})(\.\d{3})?[+-]"
|
||||||
|
"(\d{2}:\d{2})$")
|
||||||
|
DATE_FORMAT = "%Y-%m-%d"
|
||||||
|
TIME_FORMAT = "%H:%M:%S"
|
||||||
|
TZ_FORMAT = "%H:%M"
|
||||||
|
|
||||||
|
# TODO: dodać usuwanie artykułów (prosta lista, wybieramy art,
|
||||||
|
# potwierdzamy)
|
||||||
|
# TODO: Dokumentacja jako vimdoc!
|
||||||
|
|
||||||
|
def __init__(self, blogname, login, password):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
self.draft = True
|
||||||
|
self.blog_id = None
|
||||||
|
self.blog = None
|
||||||
|
self.client = BloggerClient()
|
||||||
|
self._authorize(login, password)
|
||||||
|
|
||||||
|
self.feed = self.client.get_blogs()
|
||||||
|
self._set_blog(blogname)
|
||||||
|
|
||||||
|
def get_articles(self, maxarticles=0):
|
||||||
|
"""
|
||||||
|
Return list of articles
|
||||||
|
"""
|
||||||
|
|
||||||
|
feed = self.client.get_posts(self.blog_id)
|
||||||
|
posts = []
|
||||||
|
|
||||||
|
for index, entry in enumerate(feed.entry):
|
||||||
|
if maxarticles and index >= maxarticles:
|
||||||
|
break
|
||||||
|
posts.append((entry.get_post_id(),
|
||||||
|
entry.title.text,
|
||||||
|
self._extract_date(entry.published.text)))
|
||||||
|
return posts
|
||||||
|
|
||||||
|
|
||||||
|
def create_article(self, html_doc, attrs=None):
|
||||||
|
"""
|
||||||
|
Create new article
|
||||||
|
html_doc is content of the article in HTML format, without headers,
|
||||||
|
preamble, doctype and body tags.
|
||||||
|
attrs is a dictionary that should hold title, date and tags.
|
||||||
|
return BlogPost object
|
||||||
|
"""
|
||||||
|
if not attrs:
|
||||||
|
attrs = {}
|
||||||
|
|
||||||
|
title = 'title' in attrs and attrs['title'] or ""
|
||||||
|
title = atom.data.Title(text=title, type="text")
|
||||||
|
html_doc = atom.data.Content(text=html_doc, type="html")
|
||||||
|
|
||||||
|
new_post = BlogPost(title=title, content=html_doc)
|
||||||
|
|
||||||
|
if 'tags' in attrs and attrs['tags']:
|
||||||
|
for tag in attrs['tags'].split(','):
|
||||||
|
new_post.add_label(tag.strip())
|
||||||
|
|
||||||
|
if 'date' in attrs and attrs['date'] and \
|
||||||
|
self._check_date(attrs['date']):
|
||||||
|
new_post.published = atom.data.Published(text=attrs['date'])
|
||||||
|
|
||||||
|
if self.draft:
|
||||||
|
new_post.control = atom.data.Control(\
|
||||||
|
draft=atom.data.Draft(text='yes'))
|
||||||
|
|
||||||
|
return self.client.post(new_post, BLOG_POST_URL % self.blog_id)
|
||||||
|
|
||||||
|
def update_article(self, html_doc, attrs):
|
||||||
|
"""
|
||||||
|
Update article.
|
||||||
|
html_doc is content of the article in HTML format, without headers,
|
||||||
|
preamble, doctype and body tags.
|
||||||
|
attrs is a dictionary that should hold title, date and tags.
|
||||||
|
return BlogPost object
|
||||||
|
"""
|
||||||
|
if "id" not in attrs:
|
||||||
|
raise Exception("Post Id not found in attributes!")
|
||||||
|
|
||||||
|
post = self._get_post(attrs['id'])
|
||||||
|
post.content = atom.data.Content(text=html_doc, type="html")
|
||||||
|
|
||||||
|
# update publish date
|
||||||
|
if 'date' in attrs and attrs['date'] and \
|
||||||
|
self._check_date(attrs['date']):
|
||||||
|
post.published = atom.data.Published(text=attrs['date'])
|
||||||
|
|
||||||
|
if 'title' in attrs and attrs['title']:
|
||||||
|
post.title = atom.data.Title(text=attrs['title'], type="text")
|
||||||
|
#
|
||||||
|
# update tag list
|
||||||
|
if 'tags' in attrs:
|
||||||
|
tags = [tag.strip() for tag in attrs['tags'].split(',')]
|
||||||
|
for index, label in enumerate(post.category):
|
||||||
|
if label.term not in tags:
|
||||||
|
del(post.category[index])
|
||||||
|
|
||||||
|
for tag in tags:
|
||||||
|
self._add_tag(post, tag.strip())
|
||||||
|
|
||||||
|
return self.client.update(post)
|
||||||
|
|
||||||
|
def delete_article(self, post_id):
|
||||||
|
"""
|
||||||
|
Delete selected article
|
||||||
|
"""
|
||||||
|
if not post_id:
|
||||||
|
return "No article id provided"
|
||||||
|
|
||||||
|
post = self._get_post(post_id)
|
||||||
|
self.client.delete(post)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _get_post(self, post_id):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
post_href = self.blog.get_post_link().href
|
||||||
|
return self.client.get_feed(post_href + "/%s" % post_id,
|
||||||
|
desired_class=BlogPost)
|
||||||
|
|
||||||
|
def _add_tag(self, post, tag):
|
||||||
|
"""
|
||||||
|
post - BlogPost object
|
||||||
|
tag - string with tag/label to add
|
||||||
|
"""
|
||||||
|
for label in post.category:
|
||||||
|
if label.term == tag:
|
||||||
|
return
|
||||||
|
|
||||||
|
post.add_label(tag)
|
||||||
|
|
||||||
|
def _extract_date(self, date_string, time=False):
|
||||||
|
"""
|
||||||
|
Extract date from the string and optionally time
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not self.DATE_PATTERN.match(date_string):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not time:
|
||||||
|
return self.DATE_PATTERN.match(date_string).groups()[0]
|
||||||
|
|
||||||
|
groups = self.DATE_PATTERN.match(date_string).groups()
|
||||||
|
return groups[0] + " " + groups[1]
|
||||||
|
|
||||||
|
def _check_date(self, date):
|
||||||
|
"""
|
||||||
|
Parse date as RFC 3339 format, for example:
|
||||||
|
2010-11-30T21:06:48.678+01:00
|
||||||
|
or
|
||||||
|
2010-11-30T21:06:48+01:00
|
||||||
|
|
||||||
|
Returns true, if date is acceptable, false otherwise
|
||||||
|
"""
|
||||||
|
if not self.DATE_PATTERN.match(date):
|
||||||
|
return False
|
||||||
|
|
||||||
|
groups = self.DATE_PATTERN.match(date).groups()
|
||||||
|
_date = groups[0]
|
||||||
|
_time = groups[1]
|
||||||
|
_tz = len(groups) == 3 and groups[2] or groups[3]
|
||||||
|
|
||||||
|
try:
|
||||||
|
datetime.datetime.strptime(_date, self.DATE_FORMAT)
|
||||||
|
datetime.datetime.strptime(_time, self.TIME_FORMAT)
|
||||||
|
datetime.datetime.strptime(_tz, self.TZ_FORMAT)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _update_date(self, post, attrs):
|
||||||
|
"""
|
||||||
|
Update articles published date
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _authorize(self, login, password):
|
||||||
|
"""
|
||||||
|
Try to authorize in Google service.
|
||||||
|
Authorization is kept in client object. In case of wrong credentials,
|
||||||
|
exception is thrown.
|
||||||
|
"""
|
||||||
|
source = 'Blogger_Python_Sample-2.0'
|
||||||
|
service = 'blogger'
|
||||||
|
|
||||||
|
self.client.client_login(login,
|
||||||
|
password,
|
||||||
|
source=source,
|
||||||
|
service=service)
|
||||||
|
|
||||||
|
def _set_blog(self, blogname):
|
||||||
|
"""
|
||||||
|
Set correct blog, as defined in blogname
|
||||||
|
"""
|
||||||
|
for blog in self.feed.entry:
|
||||||
|
if blog.get_blog_name() == blogname:
|
||||||
|
self.blog_id = blog.get_blog_id()
|
||||||
|
self.blog = blog
|
||||||
|
break
|
||||||
|
|
||||||
197
ftplugin/rst/rst2blogger/main.py
Normal file
197
ftplugin/rst/rst2blogger/main.py
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
# vim: fileencoding=utf8
|
||||||
|
import webbrowser
|
||||||
|
from xml.dom import minidom
|
||||||
|
from xml.parsers.expat import ExpatError
|
||||||
|
|
||||||
|
import vim
|
||||||
|
|
||||||
|
from rst2blogger.rest import blogPreview, blogArticleString
|
||||||
|
from rst2blogger.blogger import VimBlogger
|
||||||
|
|
||||||
|
|
||||||
|
class Rst2Blogger(object):
|
||||||
|
"""
|
||||||
|
Provide convenient way to communicate between vim and blogger through reST
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
vim.command('call setqflist([])')
|
||||||
|
|
||||||
|
self.buff = vim.current.buffer
|
||||||
|
self.docinfo_len = 0
|
||||||
|
self._set_docinfo_len()
|
||||||
|
self.login = vim.eval("g:blogger_login")
|
||||||
|
self.password = vim.eval("g:blogger_pass")
|
||||||
|
self.blogname = vim.eval("g:blogger_name")
|
||||||
|
self.buffer_encoding = vim.eval("&fileencoding")
|
||||||
|
self.vim_encoding = vim.eval("&encoding")
|
||||||
|
self.draft = int(vim.eval("g:blogger_draft"))
|
||||||
|
self.maxarticles = int(vim.eval("g:blogger_maxarticles"))
|
||||||
|
self.confirm_del = int(vim.eval("g:blogger_confirm_del"))
|
||||||
|
self.stylesheets = vim.eval("g:blogger_stylesheets")
|
||||||
|
|
||||||
|
def preview(self):
|
||||||
|
"""
|
||||||
|
Generate HTML Blogger article preview and (optionally) display it in
|
||||||
|
systems' web browser
|
||||||
|
"""
|
||||||
|
bufcontent = "\n".join(self.buff)
|
||||||
|
name = vim.current.buffer.name
|
||||||
|
|
||||||
|
name = name[:-4] + ".html"
|
||||||
|
html = blogPreview(bufcontent, self.stylesheets)
|
||||||
|
self._open_qf(self._check_html(html))
|
||||||
|
|
||||||
|
output_file = open(name, "w")
|
||||||
|
output_file.write(html)
|
||||||
|
output_file.close()
|
||||||
|
if vim.eval("g:blogger_browser"):
|
||||||
|
webbrowser.open(name)
|
||||||
|
return "Generated HTML has been opened in browser"
|
||||||
|
else:
|
||||||
|
return "Generated HTML has been written to %s" % name
|
||||||
|
|
||||||
|
def post(self):
|
||||||
|
bufcontent = "\n".join(vim.current.buffer)
|
||||||
|
html, attrs = blogArticleString(bufcontent)
|
||||||
|
|
||||||
|
parse_msg = self._check_html(html, True)
|
||||||
|
if parse_msg:
|
||||||
|
self._open_qf(parse_msg)
|
||||||
|
return "There are errors in generated document"
|
||||||
|
|
||||||
|
if not self.password:
|
||||||
|
self.password = vim.eval('inputsecret("Enter your gmail password: ")')
|
||||||
|
|
||||||
|
blog = VimBlogger(self.blogname, self.login, self.password)
|
||||||
|
blog.draft = self.draft > 0
|
||||||
|
|
||||||
|
if 'id' in attrs and attrs['id']:
|
||||||
|
post = blog.update_article(html, attrs=attrs)
|
||||||
|
msg = unicode("Article '%s' has been updated" % post.title.text)
|
||||||
|
msg = msg.encode(self.vim_encoding)
|
||||||
|
else:
|
||||||
|
post = blog.create_article(html, attrs=attrs)
|
||||||
|
msg = "New article with id %s has been created" % \
|
||||||
|
post.get_post_id()
|
||||||
|
|
||||||
|
if not post:
|
||||||
|
return "There is something fishy with creating new article."
|
||||||
|
|
||||||
|
for item, value in (('id', post.get_post_id()),
|
||||||
|
('date', post.published.text),
|
||||||
|
('title', post.title.text),
|
||||||
|
('modified', post.updated.text),
|
||||||
|
('tags',
|
||||||
|
", ".join([cat.term for cat in post.category]))):
|
||||||
|
self._update_docinfo(item, value)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
"""
|
||||||
|
Get list of articles, display it to the user, make him choose one and
|
||||||
|
delete
|
||||||
|
"""
|
||||||
|
if not self.password:
|
||||||
|
self.password = vim.eval('inputsecret("Enter your gmail password: ")')
|
||||||
|
blog = VimBlogger(self.blogname, self.login, self.password)
|
||||||
|
|
||||||
|
posts = blog.get_articles(self.maxarticles)
|
||||||
|
|
||||||
|
msg = u"inputlist(["
|
||||||
|
for index, entries in enumerate(posts):
|
||||||
|
line = "%2d %s %s" % (index+1,
|
||||||
|
entries[1],
|
||||||
|
entries[2])
|
||||||
|
msg += u'"' + line.replace('"', '\\"') + u'",'
|
||||||
|
msg = msg[:-1]
|
||||||
|
msg += u"])"
|
||||||
|
msg = unicode(msg).encode(self.vim_encoding)
|
||||||
|
|
||||||
|
choice = int(vim.eval(msg))
|
||||||
|
if choice:
|
||||||
|
art = posts[choice-1]
|
||||||
|
msg = 'confirm("You are about to delete article \'%s\'. Are you sure?"'
|
||||||
|
msg = unicode(msg % art[1]).encode(self.vim_encoding)
|
||||||
|
msg += ', "&No\n&Yes")'
|
||||||
|
|
||||||
|
if self.confirm_del:
|
||||||
|
choice = int(vim.eval(msg))
|
||||||
|
else:
|
||||||
|
choice = 2
|
||||||
|
|
||||||
|
if choice == 2:
|
||||||
|
result = blog.delete_article(art[0])
|
||||||
|
if result is None:
|
||||||
|
return "Article deleted"
|
||||||
|
else:
|
||||||
|
return result
|
||||||
|
return "No articles deleted"
|
||||||
|
|
||||||
|
|
||||||
|
def _update_docinfo(self, attr, val):
|
||||||
|
"""
|
||||||
|
Update current buffer with attributes value
|
||||||
|
"""
|
||||||
|
|
||||||
|
val = unicode(":%s: %s" % (attr.capitalize(), val))
|
||||||
|
val = val.encode(self.buffer_encoding)
|
||||||
|
|
||||||
|
if not self.docinfo_len:
|
||||||
|
self.buff.append(val, 0)
|
||||||
|
return
|
||||||
|
|
||||||
|
for num, line in enumerate(self.buff[:self.docinfo_len]):
|
||||||
|
if ':%s:' % attr in line.lower() and line.startswith(":"):
|
||||||
|
self.buff[num] = val
|
||||||
|
return
|
||||||
|
|
||||||
|
self.buff.append(val, 0)
|
||||||
|
self.docinfo_len += 1
|
||||||
|
|
||||||
|
def _set_docinfo_len(self):
|
||||||
|
"""
|
||||||
|
Set docinfo_len, which means number of lines from the beginning of the
|
||||||
|
buffer to the first empty line.
|
||||||
|
"""
|
||||||
|
for num, line in enumerate(self.buff):
|
||||||
|
if line and line.startswith(':'):
|
||||||
|
continue
|
||||||
|
elif not line:
|
||||||
|
self.docinfo_len = num
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.docinfo_len = 0
|
||||||
|
break
|
||||||
|
|
||||||
|
def _open_qf(self, msg):
|
||||||
|
"""
|
||||||
|
Open VIm QuickFix window with message, if argument msg is non empty
|
||||||
|
string.
|
||||||
|
"""
|
||||||
|
if msg:
|
||||||
|
msg1 = "There are problems reported by XML parser:"
|
||||||
|
msg2 = "Check generated html for errors."
|
||||||
|
vim.command('call setqflist([{"text": "%s"}, {"text": "%s"}, '
|
||||||
|
'{"text": "%s"}])' % (msg1, msg, msg2))
|
||||||
|
vim.command('copen')
|
||||||
|
|
||||||
|
def _check_html(self, html, add_container=False):
|
||||||
|
"""
|
||||||
|
Check HTML generated document, by simply use minidom parser
|
||||||
|
If add_container is set to True, entire document is wrapped inside
|
||||||
|
additional div
|
||||||
|
returns empty string if parses succeed, else exception message.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if add_container:
|
||||||
|
html = "<div>" + html + "</div>"
|
||||||
|
|
||||||
|
message = ""
|
||||||
|
try:
|
||||||
|
minidom.parseString(html)
|
||||||
|
except ExpatError as ex:
|
||||||
|
message = str(ex)
|
||||||
|
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ class Attrs(object):
|
|||||||
|
|
||||||
class Pygments(Directive):
|
class Pygments(Directive):
|
||||||
"""
|
"""
|
||||||
Source code syntax hightlighting.
|
Source code syntax highlighting.
|
||||||
"""
|
"""
|
||||||
required_arguments = 1
|
required_arguments = 1
|
||||||
optional_arguments = 0
|
optional_arguments = 0
|
||||||
@@ -72,7 +72,7 @@ class CustomHTMLTranslator(HTMLTranslator):
|
|||||||
|
|
||||||
def depart_docinfo(self, node):
|
def depart_docinfo(self, node):
|
||||||
"""
|
"""
|
||||||
Reset body, remove unnecesairy content.
|
Reset body, remove unnecessary content.
|
||||||
"""
|
"""
|
||||||
self.body = []
|
self.body = []
|
||||||
|
|
||||||
@@ -165,8 +165,7 @@ class NoHeaderHTMLTranslator(CustomHTMLTranslator):
|
|||||||
Harvest docinfo fields and store it in global dictionary.
|
Harvest docinfo fields and store it in global dictionary.
|
||||||
"""
|
"""
|
||||||
key, val = [n.astext() for n in node]
|
key, val = [n.astext() for n in node]
|
||||||
key = key.lower()
|
Attrs.ATTRS[key.lower()] = val.strip()
|
||||||
Attrs.ATTRS[key] = val
|
|
||||||
|
|
||||||
def visit_date(self, node):
|
def visit_date(self, node):
|
||||||
"""
|
"""
|
||||||
@@ -176,8 +175,9 @@ class NoHeaderHTMLTranslator(CustomHTMLTranslator):
|
|||||||
|
|
||||||
class PreviewHTMLTranslator(CustomHTMLTranslator):
|
class PreviewHTMLTranslator(CustomHTMLTranslator):
|
||||||
"""
|
"""
|
||||||
Class for dislpay article in the browser as a preview.
|
Class for display article in the browser as a preview.
|
||||||
"""
|
"""
|
||||||
|
CSS = []
|
||||||
def __init__(self, document):
|
def __init__(self, document):
|
||||||
"""
|
"""
|
||||||
Alter levels for the heading tags, define custom, blog specific
|
Alter levels for the heading tags, define custom, blog specific
|
||||||
@@ -188,9 +188,7 @@ class PreviewHTMLTranslator(CustomHTMLTranslator):
|
|||||||
self.initial_header_level = 1
|
self.initial_header_level = 1
|
||||||
self.section_level = 1
|
self.section_level = 1
|
||||||
# order of css files is important
|
# order of css files is important
|
||||||
self.default_stylesheets = ["css/widget_css_2_bundle.css",
|
self.default_stylesheets = PreviewHTMLTranslator.CSS
|
||||||
"css/style_custom.css",
|
|
||||||
"css/style_blogger.css"]
|
|
||||||
self.stylesheet = [self.stylesheet_link % self.encode(css) \
|
self.stylesheet = [self.stylesheet_link % self.encode(css) \
|
||||||
for css in self.default_stylesheets]
|
for css in self.default_stylesheets]
|
||||||
self.body_ = []
|
self.body_ = []
|
||||||
@@ -230,21 +228,27 @@ class BlogPreviewWriter(Writer):
|
|||||||
"""
|
"""
|
||||||
Custom Writer class for generating full HTML of the article
|
Custom Writer class for generating full HTML of the article
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self, stylesheets=None):
|
||||||
Writer.__init__(self)
|
Writer.__init__(self)
|
||||||
|
if not stylesheets:
|
||||||
|
stylesheets = []
|
||||||
self.translator_class = PreviewHTMLTranslator
|
self.translator_class = PreviewHTMLTranslator
|
||||||
|
self.translator_class.CSS = stylesheets
|
||||||
|
|
||||||
def translate(self):
|
def translate(self):
|
||||||
self.document.settings.output_encoding = "utf-8"
|
self.document.settings.output_encoding = "utf-8"
|
||||||
Writer.translate(self)
|
Writer.translate(self)
|
||||||
|
|
||||||
|
|
||||||
def blogPreview(string):
|
def blogPreview(string, stylesheets=None):
|
||||||
"""
|
"""
|
||||||
Returns partial HTML of the article, and attribute dictionary
|
Returns full HTML of the article.
|
||||||
string argument is an article in reST
|
string argument is an article in reST
|
||||||
"""
|
"""
|
||||||
html_output = core.publish_string(string, writer=BlogPreviewWriter())
|
if not stylesheets:
|
||||||
|
stylesheets = []
|
||||||
|
html_output = core.publish_string(string,
|
||||||
|
writer=BlogPreviewWriter(stylesheets))
|
||||||
html_output = html_output.strip()
|
html_output = html_output.strip()
|
||||||
html_output = html_output.replace("<!-- more -->", "\n<!-- more -->\n")
|
html_output = html_output.replace("<!-- more -->", "\n<!-- more -->\n")
|
||||||
return html_output
|
return html_output
|
||||||
@@ -259,5 +263,10 @@ def blogArticleString(string):
|
|||||||
html_output = core.publish_string(string, writer=BlogBodyWriter())
|
html_output = core.publish_string(string, writer=BlogBodyWriter())
|
||||||
html_output = html_output.strip()
|
html_output = html_output.strip()
|
||||||
html_output = html_output.replace("<!-- more -->", "\n<!-- more -->\n")
|
html_output = html_output.replace("<!-- more -->", "\n<!-- more -->\n")
|
||||||
return html_output, Attrs.ATTRS
|
attrs = {}
|
||||||
|
for key in Attrs.ATTRS:
|
||||||
|
if Attrs.ATTRS[key]:
|
||||||
|
attrs[key] = Attrs.ATTRS[key]
|
||||||
|
|
||||||
|
return html_output, attrs
|
||||||
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
# vim: fileencoding=utf8
|
|
||||||
#
|
|
||||||
# Blogger interface to make easy way to create/update articles for specified
|
|
||||||
# blog.
|
|
||||||
#
|
|
||||||
# It is assumed one way communication only, so you may create or update an
|
|
||||||
# article from reST source files. There is no way to recreate article from
|
|
||||||
# html to reST format.
|
|
||||||
#
|
|
||||||
# requirements:
|
|
||||||
#
|
|
||||||
# - Vim compiled with +python
|
|
||||||
# - python 2.x (tested with 2.6)
|
|
||||||
# - modules
|
|
||||||
# - gdata (http://code.google.com/p/gdata-python-client)
|
|
||||||
# - docutils (http://docutils.sourceforge.net)
|
|
||||||
# - pytz (http://pytz.sourceforge.net)
|
|
||||||
#
|
|
||||||
# USE CASES:
|
|
||||||
# 1. Create new post
|
|
||||||
#
|
|
||||||
# use reST template:
|
|
||||||
# ===8<---
|
|
||||||
# :Title: Blog post title
|
|
||||||
# :Date: optional publish date (for example: 2010-11-28 18:47:05),
|
|
||||||
# default: now()
|
|
||||||
# :Modified: optional, default: None
|
|
||||||
# :Tags: comma separated blog tags
|
|
||||||
#
|
|
||||||
# .. more
|
|
||||||
#
|
|
||||||
# --->8===
|
|
||||||
#
|
|
||||||
# All four docinfo are optional, however it is nice to give at least a title
|
|
||||||
# to the article :)
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# which is provided under templates directory or as a
|
|
||||||
# snipMate shoortcut (see .vim/snippets/rst.snippets)
|
|
||||||
#
|
|
||||||
|
|
||||||
# vim.eval('inputsecret("Password: ")')
|
|
||||||
# echomsg expand("%:p")
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
import getpass # TODO: remove
|
|
||||||
import time
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
import pytz
|
|
||||||
import atom
|
|
||||||
from gdata.blogger.client import BloggerClient
|
|
||||||
|
|
||||||
|
|
||||||
class VimBlogger(object):
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, blogname, login, password):
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
self.blog = None
|
|
||||||
self.client = BloggerClient()
|
|
||||||
self._authorize(login, password)
|
|
||||||
|
|
||||||
self.feed = self.client.get_blogs()
|
|
||||||
self._set_blog(blogname)
|
|
||||||
#self._get_arts(blogname)
|
|
||||||
|
|
||||||
def _set_blog(self, blogname):
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
for blog in self.feed.entry:
|
|
||||||
if blog.get_blog_name() == blogname:
|
|
||||||
self.blog = blog
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
def _get_arts(self, blogname):
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
feed = self.client.get_posts(self.blog.get_blog_id())
|
|
||||||
for entry in feed.entry:
|
|
||||||
print entry.title.text
|
|
||||||
#
|
|
||||||
import ipdb; ipdb.set_trace()
|
|
||||||
#
|
|
||||||
# entry.content obiekt zawiera ciało artykułu (entry.content.text
|
|
||||||
# posiada czystą formę która mnie interesuje najbardziej, do której
|
|
||||||
# można pisać
|
|
||||||
#
|
|
||||||
# entry.category - lista wszystkich kategorii (blogowych tagów), które
|
|
||||||
# post posiada. Są to elementy klasy atom.data.Category, które
|
|
||||||
# łatwiutko stworzyć i dodać do posta:
|
|
||||||
# import atom
|
|
||||||
# cat1 = atom.data.Category()
|
|
||||||
# cat1.term = "nowy tag dla bloggera"
|
|
||||||
# entry.category.append(cat1)
|
|
||||||
#
|
|
||||||
# entry.title przechowuje tytuł posta
|
|
||||||
|
|
||||||
def _authorize(self, login, password):
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
source = 'Blogger_Python_Sample-2.0'
|
|
||||||
service = 'blogger'
|
|
||||||
|
|
||||||
self.client.client_login(login,
|
|
||||||
password,
|
|
||||||
source=source,
|
|
||||||
service=service)
|
|
||||||
def create_article(self, title, html_doc, tags=None):
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
|
|
||||||
blog_id = self.blog.get_blog_id()
|
|
||||||
if tags is None:
|
|
||||||
tags = []
|
|
||||||
return self.client.add_post(blog_id, title, html_doc, labels=tags,
|
|
||||||
draft=True)
|
|
||||||
|
|
||||||
def update_article(self, title, html_doc, tags=None):
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
p = getpass.getpass("Password: ")
|
|
||||||
b = VimBlogger("rdobosz", "gryf73@gmail.com", p)
|
|
||||||
72
ftplugin/rst/vimblogger_ft.vim
Normal file
72
ftplugin/rst/vimblogger_ft.vim
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
" reST to blogger vim interface.
|
||||||
|
" Provide some convinient commands for creating preview from the reST file
|
||||||
|
" and to send articles to blog.
|
||||||
|
|
||||||
|
if exists("b:did_rst_plugin")
|
||||||
|
finish " load only once
|
||||||
|
else
|
||||||
|
let b:did_blogger_plugin = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
if exists(':PreviewBlogArticle')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists("g:blogger_browser")
|
||||||
|
let g:blogger_browser = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists("g:blogger_name")
|
||||||
|
let g:blogger_name = ""
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists("g:blogger_login")
|
||||||
|
let g:blogger_login= ""
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists("g:blogger_pass")
|
||||||
|
let g:blogger_pass = "Kurcz4czek"
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists("g:blogger_draft")
|
||||||
|
let g:blogger_draft = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists("g:blogger_maxarticles")
|
||||||
|
let g:blogger_maxarticles = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists("g:blogger_confirm_del")
|
||||||
|
let g:blogger_confirm_del = 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists("g:blogger_stylesheets")
|
||||||
|
let g:blogger_stylesheets = []
|
||||||
|
endif
|
||||||
|
|
||||||
|
python << EOF
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import vim
|
||||||
|
|
||||||
|
scriptdir = os.path.dirname(vim.eval('expand("<sfile>")'))
|
||||||
|
sys.path.insert(0, scriptdir)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from rst2blogger.main import Rst2Blogger
|
||||||
|
except ImportError:
|
||||||
|
print "Plugin vimblogger cannot be loaded, due to lack of required modules"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if !exists(":PreviewBlogArticle")
|
||||||
|
command PreviewBlogArticle py print Rst2Blogger().preview()
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists(":SendBlogArticle")
|
||||||
|
command SendBlogArticle py print Rst2Blogger().post()
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists(":DeleteBlogArticle")
|
||||||
|
command DeleteBlogArticle py print Rst2Blogger().delete()
|
||||||
|
endif
|
||||||
170
plugin/acp.vim
170
plugin/acp.vim
@@ -1,170 +0,0 @@
|
|||||||
"=============================================================================
|
|
||||||
" Copyright (c) 2007-2009 Takeshi NISHIDA
|
|
||||||
"
|
|
||||||
" GetLatestVimScripts: 1879 1 :AutoInstall: AutoComplPop
|
|
||||||
"=============================================================================
|
|
||||||
" LOAD GUARD {{{1
|
|
||||||
|
|
||||||
if exists('g:loaded_acp')
|
|
||||||
finish
|
|
||||||
elseif v:version < 702
|
|
||||||
echoerr 'AutoComplPop does not support this version of vim (' . v:version . ').'
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let g:loaded_acp = 1
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
"=============================================================================
|
|
||||||
" FUNCTION: {{{1
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:defineOption(name, default)
|
|
||||||
if !exists(a:name)
|
|
||||||
let {a:name} = a:default
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
function s:makeDefaultBehavior()
|
|
||||||
let behavs = {
|
|
||||||
\ '*' : [],
|
|
||||||
\ 'ruby' : [],
|
|
||||||
\ 'python' : [],
|
|
||||||
\ 'perl' : [],
|
|
||||||
\ 'xml' : [],
|
|
||||||
\ 'html' : [],
|
|
||||||
\ 'xhtml' : [],
|
|
||||||
\ 'css' : [],
|
|
||||||
\ }
|
|
||||||
"---------------------------------------------------------------------------
|
|
||||||
if !empty(g:acp_behaviorUserDefinedFunction) &&
|
|
||||||
\ !empty(g:acp_behaviorUserDefinedMeets)
|
|
||||||
for key in keys(behavs)
|
|
||||||
call add(behavs[key], {
|
|
||||||
\ 'command' : "\<C-x>\<C-u>",
|
|
||||||
\ 'completefunc' : g:acp_behaviorUserDefinedFunction,
|
|
||||||
\ 'meets' : g:acp_behaviorUserDefinedMeets,
|
|
||||||
\ 'repeat' : 0,
|
|
||||||
\ })
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
"---------------------------------------------------------------------------
|
|
||||||
for key in keys(behavs)
|
|
||||||
call add(behavs[key], {
|
|
||||||
\ 'command' : "\<C-x>\<C-u>",
|
|
||||||
\ 'completefunc' : 'acp#completeSnipmate',
|
|
||||||
\ 'meets' : 'acp#meetsForSnipmate',
|
|
||||||
\ 'onPopupClose' : 'acp#onPopupCloseSnipmate',
|
|
||||||
\ 'repeat' : 0,
|
|
||||||
\ })
|
|
||||||
endfor
|
|
||||||
"---------------------------------------------------------------------------
|
|
||||||
for key in keys(behavs)
|
|
||||||
call add(behavs[key], {
|
|
||||||
\ 'command' : g:acp_behaviorKeywordCommand,
|
|
||||||
\ 'meets' : 'acp#meetsForKeyword',
|
|
||||||
\ 'repeat' : 0,
|
|
||||||
\ })
|
|
||||||
endfor
|
|
||||||
"---------------------------------------------------------------------------
|
|
||||||
for key in keys(behavs)
|
|
||||||
call add(behavs[key], {
|
|
||||||
\ 'command' : "\<C-x>\<C-f>",
|
|
||||||
\ 'meets' : 'acp#meetsForFile',
|
|
||||||
\ 'repeat' : 1,
|
|
||||||
\ })
|
|
||||||
endfor
|
|
||||||
"---------------------------------------------------------------------------
|
|
||||||
call add(behavs.ruby, {
|
|
||||||
\ 'command' : "\<C-x>\<C-o>",
|
|
||||||
\ 'meets' : 'acp#meetsForRubyOmni',
|
|
||||||
\ 'repeat' : 0,
|
|
||||||
\ })
|
|
||||||
"---------------------------------------------------------------------------
|
|
||||||
call add(behavs.python, {
|
|
||||||
\ 'command' : "\<C-x>\<C-o>",
|
|
||||||
\ 'meets' : 'acp#meetsForPythonOmni',
|
|
||||||
\ 'repeat' : 0,
|
|
||||||
\ })
|
|
||||||
"---------------------------------------------------------------------------
|
|
||||||
call add(behavs.perl, {
|
|
||||||
\ 'command' : "\<C-x>\<C-o>",
|
|
||||||
\ 'meets' : 'acp#meetsForPerlOmni',
|
|
||||||
\ 'repeat' : 0,
|
|
||||||
\ })
|
|
||||||
"---------------------------------------------------------------------------
|
|
||||||
call add(behavs.xml, {
|
|
||||||
\ 'command' : "\<C-x>\<C-o>",
|
|
||||||
\ 'meets' : 'acp#meetsForXmlOmni',
|
|
||||||
\ 'repeat' : 1,
|
|
||||||
\ })
|
|
||||||
"---------------------------------------------------------------------------
|
|
||||||
call add(behavs.html, {
|
|
||||||
\ 'command' : "\<C-x>\<C-o>",
|
|
||||||
\ 'meets' : 'acp#meetsForHtmlOmni',
|
|
||||||
\ 'repeat' : 1,
|
|
||||||
\ })
|
|
||||||
"---------------------------------------------------------------------------
|
|
||||||
call add(behavs.xhtml, {
|
|
||||||
\ 'command' : "\<C-x>\<C-o>",
|
|
||||||
\ 'meets' : 'acp#meetsForHtmlOmni',
|
|
||||||
\ 'repeat' : 1,
|
|
||||||
\ })
|
|
||||||
"---------------------------------------------------------------------------
|
|
||||||
call add(behavs.css, {
|
|
||||||
\ 'command' : "\<C-x>\<C-o>",
|
|
||||||
\ 'meets' : 'acp#meetsForCssOmni',
|
|
||||||
\ 'repeat' : 0,
|
|
||||||
\ })
|
|
||||||
"---------------------------------------------------------------------------
|
|
||||||
return behavs
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
"=============================================================================
|
|
||||||
" INITIALIZATION {{{1
|
|
||||||
|
|
||||||
"-----------------------------------------------------------------------------
|
|
||||||
call s:defineOption('g:acp_enableAtStartup', 1)
|
|
||||||
call s:defineOption('g:acp_mappingDriven', 0)
|
|
||||||
call s:defineOption('g:acp_ignorecaseOption', 1)
|
|
||||||
call s:defineOption('g:acp_completeOption', '.,w,b,k')
|
|
||||||
call s:defineOption('g:acp_completeoptPreview', 0)
|
|
||||||
call s:defineOption('g:acp_behaviorUserDefinedFunction', '')
|
|
||||||
call s:defineOption('g:acp_behaviorUserDefinedMeets', '')
|
|
||||||
call s:defineOption('g:acp_behaviorSnipmateLength', -1)
|
|
||||||
call s:defineOption('g:acp_behaviorKeywordCommand', "\<C-n>")
|
|
||||||
call s:defineOption('g:acp_behaviorKeywordLength', 2)
|
|
||||||
call s:defineOption('g:acp_behaviorKeywordIgnores', [])
|
|
||||||
call s:defineOption('g:acp_behaviorFileLength', 0)
|
|
||||||
call s:defineOption('g:acp_behaviorRubyOmniMethodLength', 0)
|
|
||||||
call s:defineOption('g:acp_behaviorRubyOmniSymbolLength', 1)
|
|
||||||
call s:defineOption('g:acp_behaviorPythonOmniLength', 0)
|
|
||||||
call s:defineOption('g:acp_behaviorPerlOmniLength', -1)
|
|
||||||
call s:defineOption('g:acp_behaviorXmlOmniLength', 0)
|
|
||||||
call s:defineOption('g:acp_behaviorHtmlOmniLength', 0)
|
|
||||||
call s:defineOption('g:acp_behaviorCssOmniPropertyLength', 1)
|
|
||||||
call s:defineOption('g:acp_behaviorCssOmniValueLength', 0)
|
|
||||||
call s:defineOption('g:acp_behavior', {})
|
|
||||||
"-----------------------------------------------------------------------------
|
|
||||||
call extend(g:acp_behavior, s:makeDefaultBehavior(), 'keep')
|
|
||||||
"-----------------------------------------------------------------------------
|
|
||||||
command! -bar -narg=0 AcpEnable call acp#enable()
|
|
||||||
command! -bar -narg=0 AcpDisable call acp#disable()
|
|
||||||
command! -bar -narg=0 AcpLock call acp#lock()
|
|
||||||
command! -bar -narg=0 AcpUnlock call acp#unlock()
|
|
||||||
"-----------------------------------------------------------------------------
|
|
||||||
" legacy commands
|
|
||||||
command! -bar -narg=0 AutoComplPopEnable AcpEnable
|
|
||||||
command! -bar -narg=0 AutoComplPopDisable AcpDisable
|
|
||||||
command! -bar -narg=0 AutoComplPopLock AcpLock
|
|
||||||
command! -bar -narg=0 AutoComplPopUnlock AcpUnlock
|
|
||||||
"-----------------------------------------------------------------------------
|
|
||||||
if g:acp_enableAtStartup
|
|
||||||
AcpEnable
|
|
||||||
endif
|
|
||||||
"-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
"=============================================================================
|
|
||||||
" vim: set fdm=marker:
|
|
||||||
@@ -106,3 +106,11 @@ snippet docmodule
|
|||||||
"""
|
"""
|
||||||
snippet debug
|
snippet debug
|
||||||
LOG.debug(self.${1:method_name}.__doc__.strip())
|
LOG.debug(self.${1:method_name}.__doc__.strip())
|
||||||
|
snippet edbg
|
||||||
|
import sys
|
||||||
|
pydevdPath = r"/mnt/data/IDE/eclipse/plugins/org.python.pydev.debug_1.6.3.2010100513/pysrc"
|
||||||
|
if not pydevdPath in sys.path:
|
||||||
|
sys.path.append(pydevdPath)
|
||||||
|
import pydevd
|
||||||
|
pydevd.settrace()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user