Vim, strlen и «Мама мыла раму»

2010-02-07 13:04; Tags:

Несмотря на то, что внутреннее представление строк в виме — UTF-8, функция strlen результат выдает в байтах. И, чтобы подсчитать длину строки «Мама мыла раму», нужно вот такое злобное колдунство:

let str = "Мама мыла раму"
let len = strlen(substitute(str, ".", "x", "g"))

Тупо, каждый символ меняем на однобайтовый "x" (вот substitute замечательно работает с UTF-8) и только после этого считаем длину строки.

«Очень продуманно!»

Run vimscript, run!

2009-03-20 14:01; Tags: ,
:h :@

This is the command every Vim plugin developer should be aware of. I wish I knew about it earlier.

" eval selected vimscript
vmap <Leader>r "vy:@v<CR>
" eval vimscript line
nmap <Leader>r "vyy:@v<CR>

Now with this screwdriver in my hands I can tinker at variables and functions of my plugin/script/colorscheme easily. That’s convenient. :)

The only drawback is that it can’t eval vimscript’s longlines. Those with `\` in the beginning:

" remove trailing spaces
map <F4> m`:silent! %s/\(\s\+$\)\\|\(\r$\)//g<CR>``
      \:echo "Remove trailing spaces and ^Ms ..."<CR>

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-09-08 11:07; Tags: ,

Так случилось, что мне необходимо в некоторых файлах записывать дату их изменения (вот как здесь, например). До недавних пор использовал:

nmap <Leader>Id i<C-R>=strftime("%d.%m.%Y %H:%M")<CR><ESC>
nmap <Leader>id a<C-R>=strftime("%d.%m.%Y %H:%M")<CR><ESC>
vmap <Leader>id di<C-R>=strftime("%d.%m.%Y %H:%M")<CR><ESC>

Я находил старую дату — обычно где-то в самом начале файла — удалял ее и вставлял новую.
Делал так достаточно долго, хоть это было и не очень удобно. Пока не надоело:

function! LastChangeUpdate(...)
    if a:0 > 0
        let prefix = a:1
    else
        let prefix = ""
    endif
    let linenr = 1
    while linenr <= 10
        if getline(linenr)=~ "Last Change"
            call setline(linenr, prefix.'Last Change: '.strftime("%d.%m.%Y %H:%M"))
            break
        endif
        let linenr += 1
    endwhile
endfunction
"" Before _vimrc is saved, update 'Last Change' time if it is exists.
autocmd! bufwritepre $MYVIMRC call LastChangeUpdate('" ')
autocmd bufwritepre *.vim call LastChangeUpdate('" ')

Функция LastChangeUpdate тупо смотрит на первые 10 строк файла. Если находит ту, в которой есть Last Change, то заменяет ее на нужное нам — Last Change: текущая дата и время. Если в параметрах функции задана строка, то она подставляется перед Last Change, чтобы оформить как комментарий, например.
Ну и автокоманды — для vimrc и для всех vim-файлов перед записью вызывается наша функция и делает описанное выше.

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