LISP: Balance unmatched parentheses in Vim

2009-02-25 15:58; Tags: , ,

If you a vim guy hacking lisp or scheme the next vimscript could be useful for you. It closes unmatched parentheses on the current line, i.e.:

(define (fact n)
  (if (= n 0) 1
    (* n (fact (- n 1   ; cursor is on the line

Pressing \) while on the last line will close unbalanced parentheses on that line:

(define (fact n)
  (if (= n 0) 1
    (* n (fact (- n 1)))))   ; cursor is on the line

Here is the vimscript, just put it into your .vimrc:

function! s:rtrim(line) "{{{
  return substitute(a:line, '\s*$', '', '')
endfunction "}}}

function! s:find_rside_commentpos(lnum) "{{{
  let line = getline(a:lnum)
  let col = stridx(line, ';')
  while col != -1 &&
        \ synIDattr(synID(a:lnum, col, 1), "name") =~ "String"
    let col = stridx(line, ';', col + 1)
  endwhile
  return col
endfunction "}}}

function! s:LISP_close_parens(lnum) "{{{
  let save_cursor = getpos(".")

  call cursor(a:lnum, col('$'))
  let unbalanced = searchpair('(', '', ')', 'rmbcW',
        \ "synIDattr(synID(line('.'), col('.'), 0), 'name') =~? ".
        \ "'\\(Comment\\|String\\)'")
  if unbalanced > 0
    let line = getline(a:lnum)
    let unbalanced_str = repeat(')', unbalanced)
    let col = s:find_rside_commentpos(a:lnum)
    if col != -1
      let before_comment = strpart(line, 0, col)
      let wsp_cnt = strlen(before_comment) - strlen(s:rtrim(before_comment))
      let wsp_str = repeat(' ', wsp_cnt)
      let comment = strpart(line, col)
      call setline(a:lnum,
            \ s:rtrim(before_comment).unbalanced_str.wsp_str.comment)
    else
      let line = s:rtrim(line).unbalanced_str
      call setline(a:lnum, line)
    endif
  endif

  call setpos(".", save_cursor)
endfunction "}}}

command! LISPCloseParens call <SID>LISP_close_parens(line('.'))
map <Leader>) :LISPCloseParens<CR>
map <Leader>( :LISPCloseParens<CR>

This is a way better version of my previous attempt (russian) , which is to be frank just bad.

Vim — закрыть открытые скобки

2008-08-01 11:41; Tags: , ,

Тем кто пишет на Лиспе (Схеме) в Виме может быть интересен скрипт, закрывающий открытые скобки (unbalanced parens). Ничего особенного в нем нет — со своей работой справляется. Однако функция s:isInLispExpression() тупая как пробка, ее нужно еще тюнить и тюнить. :)

" Lisp stuff {{{

"" Close parens
function! s:isInLispExpression(linenr) " {{{
    let result = 1
    if a:linenr < 0
        let result = 0
    else
        let line = getline(a:linenr)
        if line == ""
            let result = 0
        endif
    endif

    return result
endfunction " }}}

function! s:LispCountOpenedParens(line) "{{{
    let unbalanced = 0
    let idx = 0
    while idx < len(a:line)
        if a:line[idx] == '('
            let unbalanced += 1
        elseif a:line[idx] == ')'
            let unbalanced -= 1
        endif
        let idx += 1
    endwhile
    return unbalanced
endfunction "}}}

function! s:LispCloseParens(linenr) "{{{
    let unbalanced = 0
    let lineidx = a:linenr
    while s:isInLispExpression(lineidx)
        let line = getline(lineidx)
        let unbalanced += s:LispCountOpenedParens(line)
        let lineidx -= 1
    endwhile
    if unbalanced > 0
        execute "normal ".unbalanced."A)\<ESC>"
    endif
endfunction "}}}

command! LISPCloseParens call <SID>LispCloseParens(line('.'))
map <Leader>) :LISPCloseParens<CR>

"" }}}

Upd.
Написал улучшенный вариант “балансировки” скобок.

Powered by WordPress