たなしょのメモ

日々勉強していることをつらつらと

GW中にVimプラグインを作った

GW中にVimプラグインを作った

http://0xcc.net/unimag/1/ から影響を受けたメモツールを作成しました。
日々のメモや開発メモなどに活用してみてください!
https://github.com/jacoloves/vim-ChangeLog

動作概要

Vimで動作します!(NeoVimでの動作は確認中です。)
・以下の機能を作成しました。

  1. 新しいChangelog.txtファイルを作成します。
  2. Changelog.txtが作成されている場合、現在時刻と名前とメールアドレスを先頭の行に挿入します。
  3. メモを書いた日付を検索します。
  4. キーワードを検索します。(文頭に*が記載されてるものだけです)

使い方

ChangeLogOpen

新しいChangelog.txtファイルを作成します。
Changelog.txtが作成されている場合、現在時刻と名前とメールアドレスを先頭の行に挿入します。

この処理は初めに create_changelog()Changelog.txt の存在を確認してなければ作成する処理になります。
・create_changelog()のソースコード

function! s:create_changelog() abort
   if !filewritable(expand(glob(join([g:changelog_save_path, s:filename], s:sep))))
       execute "redir > " . join([g:changelog_save_path, s:filename], s:sep)
       execute "redir END"
       call s:first_write_date()
   endif
   return
endfunction

その後 check_date() で現在日付が存在するか確認し、存在しない場合は新規記載し、存在する場合はそのままChangelog.txtを開きます。
存在しない場合の新規記載はfirst_write_date()で処理します。
結合した日付ファイルに下記出しています。
・first_write_date()のソースコード

function! s:first_write_date() abort
    if !exists("g:user_full_name") || empty("g:user_full_name")
        let user_name = "anonymous"
    else
        let user_name = g:user_full_name
    endif

    if !exists("g:user_mail_address") || empty("g:user_mail_address")
        let user_mail_address = "anonymous@hogehoge"
    else
        let user_mail_address = g:user_mail_address
    endif

    let title_row = s:time . " " . user_name . " " . "<" . user_mail_address . ">"

    let lines = [title_row, "\t"] 

    call writefile(lines, expand(join([g:changelog_save_path, s:filename], s:sep)))

    return
endfunction

ファイルが作成されていてその続きにメモを記載する場合は、rewrite_date()で現在日付を文頭に挿入します。
first_write_date()と処理が似ていますが、一度配列にメモファイルの中身を取り出してその配列の先頭に新規日付を挿入しています。
rewrite_date()のソースコード一部

" Store all memo data in an array once. 
let write_lines = []
for line in readfile(expand(join([g:changelog_save_path, s:filename], s:sep)))
    call add(write_lines, line)
endfor

" Insert the date in the first row of the array and the tab in the second
" row.
call insert(write_lines, title_row, 0)
call insert(write_lines, "\t", 1)

SearchDatechangeLog

メモを記載した日付を検索します。エンターキーを押すと目的の日付の行にジャンプします。
qを押すとバッファが閉じます。

ChangeLog#searchDate() でメモから抽出した日付をバッファに表示します。
日付を選択すると ChangeLog#jump_date_row() を呼び出して対象の行にシャンプします。
date_searchdict()はパターン解析で日付がある行か確かめ配列に格納する。
・date_searchdict()のソースコード

unction! s:date_searchdict() abort
    let date_lines = []

    let line_cnt = 1 
    for line in readfile(expand(join([g:changelog_save_path, s:filename], s:sep)))
        if line =~ '[1-2][0-9][0-9][0-9]\-[0-1][0-9]\-[0-3][0-9]\s[0-9a-zA-Z]\+\s'
            let composite_str = line_cnt . ": " . line
            call add (date_lines, composite_str)
        endif
        let line_cnt = line_cnt + 1 
    endfor

    return date_lines 
endfunction

ChangeLog#searchDate()date_searchdictで取得した行をバッファに出力します。
qを押すとバッファを閉じて、エンターキー押すとChangeLog#jump_date_row()を実行します。
ChangeLog#searchDate()のソースコード

function! ChangeLog#searchDate() abort
    set nomodeline
    let search_list = s:date_searchdict()

    if empty(search_list)
        return
    endif
    
    if bufexists(s:date_search_list_buffer)
        let winid = bufwinid(s:date_search_list_buffer)
        if winid isnot# -1
            call win_gotoid(winid)
        else
            execute 'sbuffer' s:date_search_list_buffer
        endif
    else
        execute 'new' s:date_search_list_buffer
        set buftype=nofile

        " 1. Press 'q' on SEARCH_DATE_LIST to delete buffer
        " 2. Press 'Enter' to jump target date
        " Define two key mappings.
        nnoremap <silent> <buffer>
                    \ <Plug>(datesearch-session-close)
                    \ :<C-u>bwipeout!<CR>

        nnoremap <silent> <buffer>
                    \ <Plug>(jump-date)
                    \ :<C-u>call ChangeLog#jump_date_row(trim(getline('.')))<CR>

       " <Plug> map to key
       nmap <buffer> q <Plug>(datesearch-session-close)
       nmap <buffer> <CR> <Plug>(jump-date)
    endif

    " Delete all text in the temporary buffer and insert the retrieved date
    " search list into the buffer.
    %delete _
    call setline(1, search_list)
endfunction

ChangeLog#jump_date_rowは対象の行にジャンプして、日付を表示してるバッファを閉じます。
ChangeLog#jmp_date_rowのソースコード

function! ChangeLog#jump_date_row(target_date) abort
    let dates = split(a:target_date, ":")
    let date_row = dates[0]

    let changelog_path = join([g:changelog_save_path, s:filename], s:sep)
    if bufexists(changelog_path) 
        let winid = bufwinid(changelog_path)
        if winid isnot# -1
            call win_gotoid(winid)
        else
            execute 'buffer ' changelog_path
        endif
    else
        execute 'edit ' changelog_path
    endif
    execute date_row
    " delete SEARCH_DATE_LIST buffer 
    execute 'bwipeout!' s:date_search_list_buffer
    return
endfunction

SearchKeywordChangeLog

キーワードを検索します。(文頭に*が記載されてるものだけです)
エンターキーを押すと目的のキーワードの行にジャンプします。
qを押すとバッファが閉じます。

ChangeLog#searchKeyword() でメモから抽出したキーワードを表示します。 キーワードを選択すると ChangeLog#jump_keyword_row() を呼び出して対象の行にジャンプします。

keyword_searchlist()は検索してキーワードを検索して配列に格納します。

function! s:keyword_searchlist(keyword) abort
    let keyword_line_list = [] 
    let line_cnt = 1
    for line in readfile(expand(join([g:changelog_save_path, s:filename], s:sep)))
        if stridx(line, expand(a:keyword)) !=# -1
            let composite_str = line_cnt . ":" . line
            call add(keyword_line_list, composite_str)
        endif
        let line_cnt = line_cnt + 1
    endfor
    
    return keyword_line_list
endfunction

ChangeLog#searchKeyword()keyword_searchlistで取得した行をバッファに出力します。
ソースコードChangeLog#searchDate()と作りが同じ為割愛します。

ChangeLog#jump_keyword_rowは対象の行にジャンプして、キーワードを表示してるバッファを閉じます。
ソースコードChangeLog#jump_date_rowと作りが同じ為割愛します。

所感

Vimのバッファを利用することで便利なメモツールを作成することができました。
今回作成して学んだことを通してまた新しいVimプラグインを作成していきたいです。