c2rust-refactor 0.15.0

C2Rust refactoring tool implementation

let s:job = 0
let s:channel = 0
let s:active = 0

let s:last_kind = "any"
let s:last_label = "target"

let s:hl_map = {}

function! s:ModeBegin()
    if s:active
        echo "already refactoring"
        return
    end

    let s:job = job_start("./run-interact.sh",
                \ {"out_cb": "RefactorOutputHandler",
                \  "err_cb": "RefactorErrorHandler",
                \
                \  "out_io": "buffer",
                \  "out_name": "<stdout>",
                \  "out_modifiable": 0,
                \  "out_msg": 1,
                \
                \  "err_io": "buffer",
                \  "err_name": "<stderr>",
                \  "err_modifiable": 0,
                \  "err_msg": 1,
                \  })
    let s:channel = job_getchannel(s:job)
    let s:active = 1
    echo "opened" s:channel
endfunction

function! s:ModeEnd()
    echo "mode end!"
    if !s:active
        return
    endif
    call job_stop(s:job)
    call s:ClearHighlights()

    let s:job = 0
    let s:channel = 0
    let s:active = 0
endfunction


nnoremap <Leader>r :call <SID>ModeBegin()<CR>
nnoremap <Leader>q :call <SID>ModeEnd()<CR>
nnoremap <Leader>m :call <SID>DoMark()<CR>
nnoremap <Leader>M :call <SID>DoMarkNamed()<CR>
nnoremap <Leader>c :call <SID>DoCommand()<CR>
nnoremap <Leader>f :call <SID>DoFormat()<CR>
nnoremap <Leader>h :call <SID>RefreshHighlights()<CR>
nnoremap <Leader>s :source %<CR>

function! s:Send(json)
    if !s:active
        echo "not refactoring"
        return
    end

    let msg = json_encode(a:json)
    call ch_sendraw(s:channel, msg . "\n")
endfunction

function! s:Mark(kind, label)
    call s:SendAvailableBuffers()
    call s:Send({
                \ "msg": "add-mark",
                \ "file": expand("%"),
                \ "line": line("."),
                \ "col": col(".") - 1,
                \ "kind": a:kind,
                \ "label": a:label,
                \ })
endfunction


function! s:DoMark()
    call s:Mark("any", "target")
endfunction

function! s:DoMarkNamed()
    let kind = input("Node kind? ", s:last_kind)
    let label = input("Label? ", s:last_label)
    call s:Mark(kind, label)

    let s:last_kind = kind
    let s:last_label = label
endfunction

function! s:DoCommand()
    let cmd = input("Command: ")
    let parts = split(cmd)

    call s:SendAvailableBuffers()
    call s:Send({
                \ "msg": "run-command",
                \ "name": parts[0],
                \ "args": parts[1:],
                \ })
endfunction

function! s:DoFormat()
    let cur_line = line(".")
    %!./run-fmt.sh
    exec cur_line
endfunction


function! s:SendAvailableBuffers()
    let buf_files = []
    for info in getbufinfo()
        call add(buf_files, info["name"])
    endfor

    call s:Send({
                \ "msg": "set-buffers-available",
                \ "files": buf_files,
                \ })
endfunction

function! s:SetMark(mark, file, line, col)
    let nr = bufnr(a:file)
    if nr == -1
        return
    endif
    call setpos(a:mark, [nr, a:line, a:col, a:col])
endfunction

function! RefactorOutputHandler(channel, msg)
    let json = json_decode(a:msg)
    if json["msg"] == "mark"
        call s:HighlightMark(json["info"])
        echo "Marked node as " . join(json["info"]["labels"], ", ")
    elseif json["msg"] == "mark-list"
        call s:ClearHighlights()
        for info in json["infos"]
            call s:HighlightMark(info)
        endfor
    elseif json["msg"] == "get-buffer-text"
        let nr = bufnr(json["file"])
        let lines = getbufline(nr, 1, "$")
        call s:Send({
                    \ "msg": "buffer-text",
                    \ "file": json["file"],
                    \ "content": join(lines, "\n"),
                    \ })
    elseif json["msg"] == "new-buffer-text"
        let nr = bufnr(json["file"])
        let lines = split(json["content"], "\n")
        let cur_nr = bufnr("%")
        let cur_line = line(".")

        if nr != -1
            if nr != cur_nr
                exec 'buffer ' . nr
            endif
            %delete _
            call append(0, lines)
            if nr != cur_nr
                exec 'buffer ' . cur_nr
            else
                exec cur_line
            endif
        endif
    elseif json["msg"] == "error"
        redraw
        echohl ErrorMsg
        echom json["text"]
        echohl None
    else
        echo "unrecognized message type" json["msg"]
    endif
endfunction

function! RefactorErrorHandler(channel, msg)
    "echohl WarningMsg
    "echom a:msg
    "echohl None
endfunction


hi default RefactorMarkedNode ctermbg=52

function! s:HighlightMark(json)
    call s:SetMark("'<", a:json["file"], a:json["start_line"], a:json["start_col"] + 1)
    call s:SetMark("'>", a:json["file"], a:json["end_line"], a:json["end_col"] + 1)
    "normal gv
    let nr = bufnr(a:json["file"])
    if nr != -1
        call s:Highlight(nr,
                    \ a:json["start_line"], a:json["start_col"] + 1,
                    \ a:json["end_line"], a:json["end_col"] + 1)
    endif
endfunction

function! s:Highlight(nr, line1, col1, line2, col2)
    if !has_key(s:hl_map, a:nr)
        let s:hl_map[a:nr] = []
    endif

    let pat = '\%' . a:line1 . 'l\%' . a:col1 . 'c\_.*' .
                \ '\%' . a:line2 . 'l\%' . a:col2 . 'c'
    let hl = {
                \ 'group': 'RefactorMarkedNode',
                \ 'pattern': pat,
                \ 'priority': 10,
                \ 'id': len(s:hl_map[a:nr]) + 4
                \ }
    call add(s:hl_map[a:nr], hl)

    if a:nr == bufnr('%')
        call setmatches(s:hl_map[a:nr])
    endif
endfunction

function! s:ClearHighlights()
    let s:hl_map = {}
    call clearmatches()
endfunction

function! s:RefreshHighlights()
    let nr = bufnr('%')
    if has_key(s:hl_map, nr)
        call setmatches(s:hl_map[nr])
    else
        call clearmatches()
    endif
endfunction