あなたの天然記念物
ホーム更新雑談Perl鉄ゲタランドナーコースガイド自転車Linuxリンク経歴連絡先

Vimscirptでプラグインを作ってみた (2014.10.12)

きっかけ

こちらの本「Vim script テクニックバイブル ~Vim使いの魔法の杖」を読んで作りたくなりましたので。
しかも、ちまちまとプラグインを作っていると著者の方々が助けてくださいました(大歓喜)→Vimのプラグインを作りたい - Tabtter 2014.10.07 このページを添削していただきました♪プラグインのソースを一部修正しています。

機能

ホームページの作成、修正が楽にできるような機能を盛り込みました。 これでもうVimを開くだけで、ホームページの追加や修正ができるようになってしまいました(わーい♪)。 こーゆーのハイカラな言葉で何て言いましたっけ? ターンキーシステム(古!)…違った、ワンストップだ(←聞きかじった用語を使ってみたい)。
  1. メニューを表示して機能を選択(気分はMS-DOS)
  2. スクラッチから作成する場合、ファイル名の先頭2文字と拡張子を自動生成、定型ヘッダに作成日を埋め込み
  3. 自分独自のタグやよく使うタグ、開きタグや閉じタグを自動判定してユーザー補完
  4. 画像ファイルの最新10個のファイル名を埋め込んだimgタグをユーザー補完
  5. ファイルに書き出すとブラウザがファイルを開く
  6. コンパイル(ページ内容以外のヘッダやメニュー表示を統合)のバッチファイルを起動
  7. アップロードのバッチファイルを起動

ソース(1個目)

pluginの所に置くppmod.vimです。表示の都合で文字化け、脱字あります。
" ppmodのhtmlファイル作成を省力化します。
" Version: 1.0
" Author: yrntrlmnmnt <@yrntrlmnmnt>
" License: VIM LICENSE

if exists('g:loaded_ppmod')
	finish
endif
let g:loaded_ppmod = 1

let s:save_cpo = &cpo
set cpo&vim

:scriptencoding utf8

command! -bar Ppmod call ppmod#ppmod()

let &cpo = s:save_cpo
unlet s:save_cpo

ソース(2個目)

autoloadに置くppmod.vimです。表示の都合で文字化け、脱字あります。 2014.10.12 imgタグのユーザー補完について手を抜かない処理に改善しました。 デジカメから画像ファイルをコピーするとコピー日時で統一されるため手抜きの処理では上手く動作しませんでした。
" ppmodのhtmlファイル作成を省力化します。
" Version: 1.0
" Author: yrntrlmnmnt <@yrntrlmnmnt>
" License: VIM LICENSE

let s:save_cpo = &cpo
set cpo&vim

scriptencoding utf8

cd C:\?????\pp

let s:words_mid = []
let s:words_mid += ['<a href=""></a>']
let s:words_mid += ['<br />']

let s:words_image = []

function! ppmod#CompletePpmod(findstart, base)
	if a:findstart != 0
		"入力済みを無視
		return col('.')
	else
		"補完候補を準備
		let words = []

		" 日付(PpRemark用)
		if 1 < line('.') && '<pre ppmod="PpRemark">' == getline(line('.') - 1)
			let words += [strftime('%Y.%m.%d')]
		endif

		" 開きタグをチェック
		let tag_open = ''
		let line_num = line('.')
		while 6 <= line_num
			let linebuff = getline(line_num)
			if 0 == stridx(linebuff, '</')
				break
			elseif stridx(linebuff, '<li>') < stridx(linebuff, '</li>')
			elseif 0 <= stridx(linebuff, '<') && (-1 == stridx(linebuff, '/>') && -1 == stridx(linebuff, '</'))
				let tag_open = linebuff
				break
			endif

			let line_num -= 1
		endwhile

		if '' == tag_open
			let words += ['<h2>']
			let words += ['<pre ppmod="PpDownload">']
			let words += ['<pre ppmod="PpNiconico">']
			let words += ['<pre ppmod="PpRemark">']
			let words += ['<pre ppmod="PpSourceCode">']
			let words += ['<pre ppmod="PpGoogleMap">']
			let words += ['<ol>']
			let words += ['<ul>']
		elseif '<h2>' == tag_open
			let words += ['</h2>']
		elseif 0 == stridx(tag_open, '<pre')
			let words += ['</pre>']
		elseif '<ol>' == tag_open
			let words += ['<li>']
			let words += ['</ol>']
		elseif '<ul>' == tag_open
			let words += ['<li>']
			let words += ['</ul>']
		elseif 0 <= stridx(tag_open, '<li>')
			let words += ['</li>']
		endif

		if '' == tag_open && line('.') == line('$')
			let words += ['</p>']
		endif

		let words += s:words_mid

		let words += s:words_image

		return words
	endif
endfunction

"ホームページをコンパイル

function! Compile()
	silent execute '!start "C:\?????\HTMLをコンパイル.bat'
endfunction

"imgタグに最新10個の画像ファイル名を埋めてユーザー補完に追加

function! FileTimeCompare(i1, i2)
	if s:image2time[a:i1] < s:image2time[a:i2]
		return -1
	elseif s:image2time[a:i2] < s:image2time[a:i1]
		return 1
	endif

	return 0
endfunction

function! Image()
	let images = []
	let s:image2time = {}
	for image in glob('*.jpeg', 0, 1) + glob('*.jpg', 0, 1)
		let s:image2time[image] = getftime(image)
		let images += [image]
	endfor

	call sort(images, 'FileTimeCompare')
	call reverse(images)

	let s:words_image = []
	let i = 0
	for image in images
		let s:words_image += ['<img src="' . image . '" alt="" class="単独" />']
		let i += 1
		if 10 <= i
			break
		endif
	endfor
endfunction

"編集

function! Edit()
	" カテゴリを選択
	let category = browsedir('カテゴリを選択', getcwd())
	if '' != category
		execute 'cd! ' . category
	else
		return
	endif

	let s:html_file = browse(0, 'ページを選択', getcwd(), '*.html')
	if '' != s:html_file
		execute 'e! ' . s:html_file
	else
		return
	endif

	call Image()
endfunction

"新規作成

function! New()
	" スクラッチでHTMLファイルを作成

	" カテゴリを選択
	let category = browsedir('カテゴリを選択', getcwd())
	if '' != category
		execute 'cd! ' . category
	else
		return
	endif

	" 既存で最後のファイル名の接頭語から次の接頭語を生成
	let html = reverse(sort(glob('??_*.html', 0, 1)))
	let prefix_last = strpart(html[0], 0, 2)
	let digitalpha = '0123456789abcdefghijklmnopqrstuvwxyz'
	let prefix_1_idx = stridx(digitalpha, strpart(prefix_last, 0, 1))
	let prefix_2_idx = stridx(digitalpha, strpart(prefix_last, 1, 1))

	" 接頭語の順番は、01~99、a0~a9、aa~az、b0~zz
	if prefix_1_idx < 9 || prefix_2_idx < 9
		" 2桁の数字
		let prefix_new = printf('%02d', str2nr(prefix_last) + 1)
	elseif prefix_last == '99'
		" 99の後はa0
		let prefix_new = 'a0'
	else
		" a1~zz
		if prefix_2_idx < strchars(digitalpha) - 1
			let prefix_2_idx += 1
		else
			let prefix_2_idx = 0
			let prefix_1_idx += 1
		endif
		let prefix_new = strpart(digitalpha, prefix_1_idx, 1) . strpart(digitalpha, prefix_2_idx, 1)
	endif

	let newfile = prefix_new . '_' . input("作成するファイル名(接頭語と拡張子を除く)") . '.html'

	" ヘッダーの定型フォーマットに日付を埋める
	let today = strftime('%Y/%m/%d')
	let header = []
	let header += ['<!-- $VER: html code. 1.0, ' . today . ' () -->']
	let header += ['<p>']
	let header += ['<h1>']
	let header += ["\t"]
	let header += ['</h1>']
	let header += ['<h2>']
	let header += ["\t"]
	let header += ['</h2>']
	call append(0, header)

	" カーソルをタイトル位置に移動
	let posbuff = getpos('.')
	let posbuff[1] = 4
	let posbuff[2] = 2
	call setpos('.', posbuff)

	let s:isnew = 1
	execute 'w ' . newfile
	let s:isnew = 0

	call Image()
endfunction

"ファイル書き出しと同時にブラウザで開く

function! ppmod#OpenHtml()
	" 新規作成で書き出した場合は定型フォーマットだけなので開かない
	if 0 == s:isnew
		silent execute '!start "C:\Program Files (x86)\Mozilla Firefox\firefox.exe" ' . expand("%:p")
	endif
endfunction

"ホームページをアップロード

function! Upload()
	silent execute '!start "C:\?????\プロバイダと自宅サーバにアップロード.bat'
endfunction

" メニュー

function! ppmod#Menu()
	let MenuSelected = inputlist(['PPMODメニュー', '1. ページを作成', '2. ページを編集', '3. コンパイル', '4. アップロード'])
	if 1 == MenuSelected
		call New()
	elseif 2 == MenuSelected
		call Edit()
	elseif 3 == MenuSelected
		call Compile()
	elseif 4 == MenuSelected
		call Upload()
	endif
endfunction

" プラグイン使用開始

function! ppmod#ppmod()
	set completefunc=ppmod#CompletePpmod
	set fileencoding=utf8
	set nobomb

	command! -bar PpmodMenu call ppmod#Menu()

	let s:isnew = 0
	augroup ppmod#Preview
		autocmd!
		autocmd BufWritePost *.html call ppmod#OpenHtml()
	augroup END
endfunction

let &cpo = s:save_cpo
unlet s:save_cpo