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, vimwiki and GTD

2009-02-17 23:39; Tags: ,

vimwiki-gtdI have just implemented “toggleable list items”. Now you can make “projects” which are vimwiki’s lists of what you should do to make a project done. Project is done when all it’s elements are done == checked.
Getting closer to emacs org-mode… :)

PS.
I wish i have implemented multiple wikies first.

Indenting Python with Vim 2

2009-02-15 23:23; Tags: ,

Not that long time ago I began exploring Python. As a Vim adept I write almost all my code using it. And I was really disappointed with the way vim72 indents python’s code. Consider the following snippet that is indented by built in indent/python.vim script:

for file in files:
    mkdir_copy(os.path.join(root, file), divider,
        os.path.join(BACKUP_DIR, dest_subdir))

The code layout should look like (according to PEP-8):

for file in files:
    mkdir_copy(os.path.join(root, file), divider,
               os.path.join(BACKUP_DIR, dest_subdir))

I googled up Indenting Python with VIM — it suggests to use Eric Mc Sween’s script to solve most of indenting “problems”. It is really nice… until you have a colon in a docstring or comment. And if you have it — gg=G will mess your python code right after it:

# TODO:
    # this is an example of bad indenting
    if this_is_an_issue:
        print("Issue message")

This is definitly not what you want. Although it could be fixed quite easily (and actually I have fixed it) I think builtin script is more robust, so…
I have fixed builtin indent/python.vim script too. Now it makes “sexy” braces indenting just like it should.
But!
Lack of “sexy” braces indenting in vim is not a big problem at all. Both — standard and suggested scripts — have indent error:

if fullscreen:
    self.win_main = pyglet.window.Window(fullscreen=True, visible=False)
else:
    self.win_main = pyglet.window.Window(width=config.width,
            height=config.height,
            visible=False,
            vsync=True)

self.win_main.set_caption("Belveder %s" % config.version)

Press gg=G :

if fullscreen:
    self.win_main = pyglet.window.Window(fullscreen=True, visible=False)
else:
    self.win_main = pyglet.window.Window(width=config.width,
            height=config.height,
            visible=False,
            vsync=True)

    self.win_main.set_caption("Belveder %s" % config.version)

The last line is indented. Code is broken!

I tried to address all mentioned issues in the fixed indent/python.vim.
Use it with caution! :)

vimwiki 0.6

2009-02-04 15:06; Tags:

Поправил некоторые ошибки, добавил возможность вставки в экспортируемые файлы шаблоны для верхней и нижней части HTML документа.

Загрузить vimwiki 0.6

Маленький баг в indent/python.vim

2009-02-03 12:29; Tags: ,

В vim, чтобы писать программы на питоне, для правильной расстановки отступов, советуют использовать следующий indent/python.vim (ver 0.3). Потому как, встроенный в редактор не соответстует PEP 8.

Однако есть там маленькая ошибка. Вот такой вот код:

# TODO:
# this is an example
if this_is_an_issue:
    print("Issue message")

будет отформатирован следующим образом:

# TODO:
    # this is an example of bad indenting
    if this_is_an_issue:
        print("Issue message")

Что, как видно, не верно.

Скрипт я для себя поправил, вечером отошлю исправления Eric Mc Sween’у.

Update.
Его email помер.
Тогда покажу, где и что на что поправить. В его indent/python.vim строчку под номером 179:

    if pline =~ ':\s*$'

поменять на:

    if pline =~ '^[^#]\+:\s*$'

Update 2.
В итоге, все равно пользуюсь стандартным файлом. :)

Пришлось, правда, его немного допилить. Чтобы после скобок ставил правильный «сдвиг» на следующих строках. Про это написал уже в Indenting Python with Vim 2

Powered by WordPress