четверг, 24 ноября 2011 г.

Поиск по внешним исходникам в Vim

Я давно использую ctags в Vim, и более чем доволен, но одной вещи по-прежнему сильно не хватало. Редко когда нужен поиск только по кода внутри проекта. Часто хочется заглянуть ещё и в third-party код. Только вот мешать его с рабочим (чтобы ctags мог дотянуться) нет никакого желания.

Обычно я решал эту проблему, просто держа под рукой браузер с API или исходниками требуемого класса. Либо запускал отдельное окно Vim. Но постепенно эта ситуация стала надоедать, да и обида за любимый редактор взяла - неужто он хуже той же IDEA? Неужто не умеет брать ctags из нескольких источников?

Полез в документацию - и увидел, что всё у него с этим делом обстоит прекрасно. Проблему решает одна-единственная строчка в конфиге.

Сначала подготовим необходимые библиотеки: создаём папку ~/src и выкладываем туда исходники необходимых библиотек и фреймворков. Можно просто распаковать архивы с кодом, но более труёвый способ - склонировать нужную ветку или тег из репозитория библиотеки. Проще будет обновлять версию при необходимости.


После этого прогоняем ctags для всех исходников - заходим поочерёдно в папки и запускаем ctags:

$ cd ~/src
$ for dir in $(ls); do if [ -d $dir ]; then cd $dir; ctags -R; cd ..; fi; done

После чего добавляем одну строчку к конфигу:

set tags=./tags,./TAGS,tags,TAGS,~/src/*/tags

Теперь мы можем изменять состав библиотек, переключаться с одной версии на другую, и баловать как только можно. И Vim будет подхватывать все изменения. Надо лишь не забывать обновлять теги.

Поиск по тегам, кстати, работает на удивление быстро. Быстрее, чем в любой IDE.

Just FYI: Мой конфиг Vim живёт здесь, но я периодически подумываю перенести его на github.

четверг, 29 сентября 2011 г.

Useful bash macro: with

Here is a simple but quite nice bash macro that I use very often. Just added it into my ~/.bash_aliases:
function with () {
    # filter files list, leaving only files that has our key words
    xargs grep $@ | sed 's/:.*//' | uniq
}
Now my command line looks prettier:
$ cd project_dir
$ find . -name \*.java | wc -l # find all java files
over 9000
$ find . -name \*.java | with -i hitrin | wc -l # find all my java files
138
You can also use chaining:
find | with | with | ...
Exception: you can't use with with -v option of grep, because it displays rows in another format. Sad but true.

понедельник, 28 марта 2011 г.

Сделать после

Сегодня задался вопросом, как можно в шелле дождаться завершения какого-то процесса, и после этого сделать что-нибудь ещё. Порой такая возможность бывает совсем не лишней.

Например, когда ВНЕЗАПНО выясняется, что из-за медленного интернета процесс установки нового пакета (и пятнадцати библиотек, от которых он зависит :) затянется на четверть часа, глупо сидеть и пялиться в экран на ползунок apt-get. Лучше переключиться на другую деятельность, а к новому пакету вернуться только тогда, когда он будет готов. Конечно, можно прервать процесс и запустить заново с добавлением & notify-send "Job done, my Master!" после команды, но это же не Ъ-way!

Мне казалось, что в богатейшем списке утилит командной строки обязательно есть какая-нибудь штукенция, которая позволит решить эту проблему с помощью одной-единственной команды, но гуглёж показал, что магического слова всё же нет, и все используют связку while & wait. Но лень - страшная вещь, и писать каждый раз (даже примитивный) цикл дико ломает.

Поэтому на основе пары источников был создан следующий опус:

% cat doafter
#!/bin/sh

delay=2
pid=$1
shift
cmd=$@
usage=0

if [ "$pid" == "" ]
then
  usage=1
  echo "PID is required"
fi

if [ "$cmd" == "" ]
then
  usage=1
  echo "COMMAND is required"
fi

if [ "$usage" == "1" ]
then
  echo "Usage: doafter PID COMMAND"
  echo "where"
  echo "  PID = Process id to wait for"
  echo "  COMMAND = Command to be executed after it completes"
  exit
fi

while ps -p $pid >/dev/null; do sleep $delay; done
$cmd

Отныне, закинув этот скрипт в /usr/local/bin, я могу уведомлять сам себя о завершении длинного процесса хоть через notify-send, хоть через mpc play, хоть через что-угодно-ещё. Хотя, конечно, если бы существовала "магическая команда" для тех же целей, не пришлось бы и скриптованием заниматься.

В качестве дополнительного упражнения надо будет разобраться, как сделать так, чтобы можно было использовать автодополнение bash/zsh для завершения выполняемой команды. А то ввожу номер процесса, набиваю начало команды, жму таб - а шелл ничего не добавляет! Непорядок :(