初めてのVimスクリプトをPythonで書いたが、
ほとんどVimの機能を呼び出しているだけになってしまった...
しかし楽しい。
環境は gVim7 + WinXP + Python2.5 + BeautifulSoup。
:PyBookmarkAdd でカレントバッファのファイルをブックマーク。
:PyBookmarkList でブックマークの一覧表示。Enterでファイルを開く。
以下の2ファイルをpluginsフォルダに配置する。
pybookmarks.vim
if has('win32') let s:vim_encoding = "shift_jis" else let s:vim_encoding = "utf-8" endif if !exists('g:pybookmarks_file') let g:pybookmarks_file = $HOME . "\\pybookmarks.xml" endif if !exists("g:pybookmarks_loaded_python_file") pyfile <sfile>:p:h/pybookmarks.py python pybookmarks = PyBookmarks() let g:pybookmarks_loaded_python_file=1 endif command! PyBookmarkList python pybookmarks.list_bookmark() command! PyBookmarkAdd python pybookmarks.add_bookmark() function! s:OpenSearchLine() python pybookmarks.open_search_line() endfunction
pybookmarks.py
# vim:set fileencoding=utf-8: # ファイルブックマーク Vimスクリプト # # XML形式のファイルにブックマークを保存 # BeautifulSoupを使って解析、編集 import vim import sys import codecs import os import re import datetime from BeautifulSoup import * class PyBookmarks(): def __init__(self): self.vim_encoding = vim.eval("s:vim_encoding") self._xml_file = None self._soup = None def list_bookmark(self): bname = "__PYBOOKMARKS__" winnum = vim.eval('bufwinnr("%s")' % (bname,)) if vim.eval("winnr()") != winnum: if winnum != "-1": vim.command("exe %swincmd w" % (winnum,)) self._open_window(bname) vim.command("setlocal bt=nofile bh=delete noswf") # Enter時にOpenSearchLineコマンドを呼び出す vim.command("nnoremap <silent> <buffer> <CR> :call <SID>OpenSearchLine()<CR>") b = vim.current.buffer vim.command("redraw!") vim.command("setlocal modifiable") line_format = "%s | %s | %s" # バッファにXMLファイルの内容を一覧表示 idx = 1 soup = self._get_soup() for bookmark in soup('bookmark'): bookmark_href = re.escape(bookmark['href']) self._enc_command('let b:file{%d} = "%s"' % (idx, bookmark_href)) line = line_format % (bookmark['title'], bookmark_href, bookmark['create_date']) if vim.eval('line("$")') != "1" or vim.eval('getline("1")') != '': self._enc_command('call append("$", "%s")' % (line,)) else: self._enc_command('call setline("1", "%s")' % (line,)) idx = idx + 1 vim.command("setlocal nomodifiable") vim.command("redraw!") def add_bookmark(self): path = vim.current.buffer.name if path is not None: path = path.decode(self.vim_encoding) input = 'input("%s", "%s")' % (u'タイトル:', os.path.basename(path)) title = self._enc_eval(input) if title is not None: soup = self._get_soup() title = title.decode(self.vim_encoding) if title == "": title = u"無名ブックマーク" bookmark = Tag(soup, "bookmark") bookmark['title'] = title #bookmark.append(title) bookmark['href'] = path bookmark['create_date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M") soup.bookmarks.append(bookmark) self._overwrite_xml(soup.prettify()) print u"ブックマークを追加しました".encode(self.vim_encoding) else: print u"ファイルまたはディレクトリが開かれていません".encode(self.vim_encoding) def open_search_line(self): line_num = vim.eval('line(".")') bookmark_href = vim.eval('b:file{%s}' % (line_num,)) bookmark_href = re.escape(bookmark_href) self._eliminate_window(vim.eval('bufname("%")')) self._open_window(bookmark_href) def _get_xml_path(self): if self._xml_file == None: self._xml_file = vim.eval("g:pybookmarks_file") return self._xml_file def _get_soup(self): if self._soup == None: xml_file = self._get_xml_path() if os.path.exists(xml_file): f = open(xml_file) bxml = f.read() f.close() self._soup = BeautifulStoneSoup(bxml, fromEncoding="UTF-8", selfClosingTags='bookmark') else: self._soup = BeautifulStoneSoup('<?xml version="1.0" encoding="UTF-8"?>\n<bookmarks></bookmarks>', selfClosingTags='bookmark') return self._soup def _overwrite_xml(self, contents): xml_file = self._get_xml_path() f = open(xml_file, "w") f.write(contents) f.close() def _enc_command(self, command): vim.command(command.encode(self.vim_encoding)) def _enc_eval(self, command): return vim.eval(command.encode(self.vim_encoding)) def _open_window(self, filepath): self._eliminate_window(filepath) cmd = "new" if vim.eval('expand("%:p") == "" && &modified == 0 && !has("vim_starting")') == "1": cmd = "edit" #vim.command('silent exe "%s ++enc=%s ++ff=&ff %s"' % (cmd, "utf-8", filepath)) self._enc_command('silent exe "%s %s"' % (cmd, filepath)) def _eliminate_window(self, name): """指定したバッファ名のウィンドウをすべて閉じる""" nr = vim.eval('bufwinnr("%s")' % (name,)) while nr != "-1": vim.command('%swincmd w' % (nr,)) if self._safe_close() == 0: break nr = vim.eval('bufwinnr("%s")' % (name,)) def _safe_close(self): retval = 0 if vim.eval('&modified') != "-1": vim.command('silent! enew') if self._get_win_num() > 1: vim.command("close") retval = 1 return retval def _get_win_num(self): winnum = 1 nr = vim.eval('winnr()') vim.command('silent! exe "wincmd \\<C-w>"') while nr != vim.eval('winnr()'): winnum = winnum + 1 vim.command('silent! exe "wincmd \\<C-w>"') return winnum
下記のサイトのVimスクリプトを参考にさせていただきました。
http://sworddancer.funkyboy.jp/howm_vim/
http://www.vim.org/scripts/script.php?script_id=165