LoginSignup
0
1

More than 5 years have passed since last update.

PlantUML のコードをインデント略記から生成する Vim プラグイン(雑)

Posted at

多用するのでプラグイン作ってみた。
classって書いたりpackage ... {って括弧書いたり面倒だよね。

超適当配布なので VimScript 1ファイル製。

仕様

変換ルール

記法 変換 備考
. foo package foo html の class 属性のイメージで . にした
# foo namespace foo html の id 属性のイメージで # にした
+ Foo class Foo
- Foo enum Foo
* Foo interface Foo
空行 捨てられる 実装辛くてどーでも良くなってしまった
それ以外 そのまま 線とかコメントとか

HTML のリスト記法のイメージなので、

. foo
  + FooId
  # FooType

package foo {
  class FooId
  enum FooType
}

になるってこと。

ソース

command! PlantVim call PlantVim()

function! PlantVim()
    call s:init(getline(1, '$'))

    let node = s:subs(0)

    execute 'normal ggdG'

    call s:put('@startuml')
    call s:put('')
    call s:indentingSetLine(node, '')
    call s:put('')
    call s:put('@enduml')

    execute 'normal Gddgg0'
endfunction

function! s:init(input)
    let g:n = 0
    let g:input = filter(a:input, 'v:val != ""')
    let g:max = len(g:input) - 1
endfunction

function! s:subs(depth)
    let xs = []
    while g:n <= g:max && s:depth(g:input[g:n]) >= a:depth
        let g:n = g:n + 1

        if s:depth(g:input[g:n - 1]) == a:depth
            if s:needParse(g:input[g:n - 1]) == 'true'
                let parsed = s:parse(g:input[g:n - 1])
                let parsed['subs'] = s:subs(a:depth + 1)
                let xs = xs + [parsed]
            else
                let xs = xs + [{'line': g:input[g:n - 1], 'output': 'raw', 'subs': []}]
            endif
        endif
    endwhile
    return xs
endfunction

function! s:depth(line)
    let x = 0
    for c in split(a:line, '\zs')
        if c == ' '
            let x = x + 1
        else
            break
        endif
    endfor
    return x / 2
endfunction

function! s:parse(line)
    let type = {'.': 'package', '#': 'namespace', '+': 'class', '-': 'enum', '*': 'interface'}[split(a:line, '^ ')[0][0]]
    let containable = get({'package': 'containable', 'namespace': 'containable'}, type, 'no_contains')
    let content = split(a:line, ' ')[1]

    return {'line': type . ' ' . content, 'output': containable}
endfunction

function! s:needParse(line)
    return (a:line =~ '\.\|#\|+\|- \|\*') == 1 ? 'true' : 'false'
endfunction

function! s:indentingSetLine(node, pad)
    for elm in a:node
        if elm['output'] == 'containable'
            call s:put(a:pad . elm['line'] . ' {')
            call s:indentingSetLine(elm['subs'], a:pad . '  ')
            call s:put(a:pad . '}')
        elseif elm['output'] == 'no_contains'
            call s:put(a:pad . elm['line'])
        else
            call s:put(elm['line'])
        endif
    endfor
endfunction

function! s:put(line)
    call append(line('$') - 1, a:line)
endfunction

導入

上のファイルをplant.vimという名前で保存して、vi を起動して:so ~/Downloads/plant.vimをする。(パスは読み替えて)

インデント略記が書き終わったら:PlantVimとすると変換される。

デモ

アニメ

こうなる
model.png

おしまい

whileとかグローバル変数と添字アクセスとか数年ぶりに書いた。ちょー辛い、もう二度とやりたくない。

本当は改行を保ちたいとか不可逆だしファイルを書き換えちゃうのでやり直しが効かないとか対応したかったけど、これ以上を VimScript 1ファイルでやるのはもう無理。

気に入って、かつ機能追加したくなったらメインロジックは全部 haskell か何かに移して VimScript はすっかすかにする。

ノシ

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1