Category: it

Category was added automatically. Read all entries about "it".

glider

Квазицитаты, метауровни и всякая всячина

В последнее время меня увлекли квазицитаты, поэтому я отложил сторонку допиливание макросов и начал разбираться с КЦ (кстати, это меня поражает в нашей лабе, и я, похоже, уже заразился этой привычкой - куча народу просто занимается тем, что в данный момент интересно, без особого плана или принуждения себя делать что-то конкретное). На всякий случай вот недавний коммит: https://github.com/scalamacros/kepler/commit/28be76ac3f2893a12898eabca139e27d2b166a8b, но сейчас я постараюсь рассказать человеческим языком.

С давних времен (2.8+) у нас в компиляторе поддерживается экспериментальный Code.lift, который превращает кодяру внутри единственного параметра в эквивалентный AST, который можно проинспектировать в рантайме (аля Expression Trees в сишарпе). С появлением reflection api, динамической кодогенерации и макросов настало время причесать лифтинг и добавить ему туда одну штучку, которая абсолютно необходима для удобной работы с деревьями. Ага, точно - я имею ввиду сплайсинг. Про него и про интересные эффекты, которые им порождаются, и будет сегодняшний пост.

***

Немного введения. Лично я лучше всего учусь на примерах, поэтому вместо тонны слов про то, что такое квазицитаты и сплайсы, вот небольшой сниппет, который заодно проиллюстрирует нашу реализацию. Итак, в моем бранче scalac можно писать вот так:
def two = lift{2}                                   // Constant(Literal(2))
def four = lift{splice{two} + splice{two}}          // Apply(Select(two, newTermName("$plus")), List(two))

val reporter = new ConsoleReporter(new Settings)    // немного бойлерплейта - мы пока не заморачивались над API
val toolbox = new ToolBox(reporter)                 // само собой, к релизу 2.10 все будет более приятно в использовании
                                                    
val ttree = toolbox.typeCheck(four.tree)            // тайпчекает дерево из four, после этого вызова можно 
                                                    // пробежаться по результату и узнать типы фрагментов
                                                    // а также увидеть, к каким именно внешним символам что прибиндилось
                                                    // к примеру, если бы в лифченном коде мы вызывали println, то
                                                    // sym.fullName для println после тайпчека показал бы scala.Predef.println

println(toolbox.runExpr(ttree))                     // запускаем компилятор, минуя первую фазу, parser,
                                                    // результаты тайпчека будут стерты нафиг, т.е. предыдущая строчка была необязательна
                                                    // на выходе будет сгенерирован in-memory байткод
                                                    // который будет подхвачен и исполнен специальным класслоадером
Как можно видеть, лифт преобразует кодяру в соответствующий AST, который можно проанализировать, тайпчекнуть и даже исполнить в рантайме. Более подробно про скаловский AST можно почитать у Мигеля Гарсиа (http://www.sts.tu-harburg.de/people/mi.garcia/ScalaCompilerCorner/UntanglingScalaASTs1ofN.pdf), а я лишь замечу то, что, в отличие от сишарпа, меня порадовало небольшое количество и гибкость стройматериалов. Например, нет разделения на Call и Invoke - есть Select, который достает мембер по имени (в том числе это работает и для методов), а есть Apply, который применяет функцию к аргументам (неважно, делегат это или метод).

Даже сам по себе лифтинг очень интересен. Его реализация в сишарпе весьма ограничена (лифтятся только лямбды + в процессе лифтинга теряется информация о переменных, захваченных из лексического скоупа), но все равно он стал очень популярен для создания type-safe апи. Однако, поработав с деревьями выражений сишарпа, довольно быстро сталкиваешься с необходимостью собирать деревья из динамических кусочков. К сожалению, лифтинг здесь не помогает (ибо он работает только с тем, что известно во время компиляции) и приходится вручную конструировать деревья.

Проблема композиции деревьев решается при помощи сплайсинга. В примере выше мы берем ранее залифченный код (переменную two) и вставляем его в квазицитату (выражение под вторым лифтом). В результате компилятор создаст ссылку на two, а также сгенерирует дерево, соответствующее шаблону, в который мы вставляем two. На самом деле, компилятор сделает еще больше - так как тип переменной two известен (он выводится как Code[Int]), то мы знаем, что сложение в four будет соответствовать сложению двух интов, т.е. обе квазицитаты в примере будут статически тайпчекнуты!

Получается все очень симпатично и концептуально просто так что я бы на этом и закончил, но самое интересное только начинается!

***

Во-первых, а что, если перед тем, как что-то сплайснуть, мы хотим это что-то обработать напильником? Каноничный пример - printf. Перед вставкой аргумента в принт мы, возможно, захотим его отформатировать, например, обернув в Apply(Select(arg, "format"), List(...)). Пока что ничего страшного, ибо спецификаторы формата задают тип аргумента, поэтому результирующее дерево все еще можно типизировать.

Но что, если напильник деформирует дерево так, что его родная мама не узнает мы не будем знать статический тип результата? Это не то, что бы совсем уж высосанное из пальца желание. Например, в нашем кусочке большого дерева мы можем захотеть сослаться на переменную, которая объявлена в другом кусочке дерева. Причем эта переменная может иметь тип, который генерируется динамически в третьем фрагменте дерева. Да, получается затык - наша строго типизированная идиллия в стиле MetaML рушится и надо что-то с этим делать.

Для спасения ситуации многие системы метапрограммирования вводят понятие нетипизированных квазицитат. К примеру, F#. Или вот Немерле, в котором макросы и квазицитаты по умолчанию нетипизированные (правда, с опциональными аннотациями типов). Более подробно об этом дизайн-решении написано в диссере одного из создателей Немерле: http://nazgul.omega.pl/macros.pdf (см. главу 8.1.1 "Static typing vs run-time").

Ту же самую штуку я добавил в Скалу, но возникло небольшое затруднение. Очень хочется типизировать все по макисмуму (например, если в кц есть типизируемые фрагменты, то есть желание их проверить), но для этого надо вводить в систему типов специальный магический тип (в слинкованном выше патче я так его и назвал - Magic). Этот тип, прикасаясь к чему угодно, преобразует это что угодно в Magic. Логично в принципе - если мы вызываем метод у результата нетипизированного сплайса, то мы не можем типизировать этот вызов и вынуждены отложить решение до рантайма. А пока что надо убедить компилятор отвязаться. Очень интересно, есть ли для этого формализация, а то пока что мой подход уж сильно ад-хок.

***

Во-вторых, в честь того, что мы сделали стейджинг крайне легким (вызов магической функции - что может быть легче) и сняли все тормоза (программист может вызвать лифт/сплайс откуда угодно), перед нами начинает маячить знаменитая темная башня метауровней (вот мой миррор статьи, оригинал вроде бы сдох: http://dl.dropbox.com/u/10497693/Library/Computer%20Science/Metaprogramming/Macros/Quasiquotations/Metalevels/The%20Dark%20Tower%20of%20Meta-levels.html):



Дело в том, что метауровни логически разделены между собой, а мы только что дали программисту элементарную возможность их смешать в кучу при помощи лексических скоупов. Смотрим еще один пример:
def y: Tree = ...
lift {
  y;                 // metalevel 1 refers to metalevel 0 => okay, but need a translation
                     // we will generate something like: Ident(newTermName("y"))

  splice { y };      // metalevel 0 refers to metalevel 0 => okay, no need of a translation
                     // we just insert a reference to y in the tree generated in LiftCode
                     // so that the generated code will look like: y (yep, as simple as that)

  def x: Tree = ...

  x;                 // metalevel 1 refers to metalevel 1 => okay, no need for a translation
                     // just Ident(newTermName("x"))

  splice { x };      // metalevel 0 refers to metalevel 1 => uh-oh, no translation will help us
                     // exact value of x will be known only during the run-time
                     // so we can only perform the splice during the run-time
                     // for the state of the art JVM it's more like science fiction
}
Итак мы только что убедились на практике, что: а) метауровни могут использовать переменные предыдущих метауровней, б) метауровни не могут ссылаться на переменные старших метауровней. Надо как-то закодировать это ограничение в компиляторе, и для этого мы снова воспользуемся типами (по крайней мере, на это настроен Адриаан, мнение Мартина пока что узнать не удалось).

Основная идея заключается в том, чтобы кодировать метауровень символов (символ = переменная, функция, класс - все, что угодно, что можно объявить) в аннотации к их типам. Т.е. в приведенном выше примере декларация x выглядела бы вот так: "def x: @ml(1) Tree" (само собой, компилятор вполне способен самостоятельно вывести и @ml и 1, поэтому явное указание аннотации здесь только для примера). Тогда функцию Code.splice мы могли бы объявить как "splice[A](tree: @ml(0) Code[A]): @ml(1) A" и все как бы чотко, но снова возникают проблемы.

Во-первых, метауровней не два и не три, а бесконечное число. Лифт, вложенный в лифт, переносит нас на метауровень 2 и так далее, причем вложенные лифты тоже надо тайпчекать, поэтому наша красивая декларация сплайса ломается и превращается в монстрилу вида "splice[A](tree: @ml(N) Code[A]): @ml(M) A where N < M and M = currentml" (синтаксис исключительно гипотетический).

Во-вторых, снова возникает концепция протекания информации о типах типов через всю программу. Скажем, если мы складываем два @ml(0)-числа, то у нас должно получится @ml(0)-число. А вот если хотя бы одно из этих чисел - @ml(1), то тогда получается @ml(1). Опять же вопрос - есть ли для этого формализация? Реквестирую nponeccop.
glider

емакс, часть 4: ретроспектива

емакс, часть 1: первый взгляд
емакс, часть 2: восторг
емакс, часть 3: windows
емакс, часть 4: ретроспектива

Вдохновленный сегодняшним выступлением @alexott на митапе scala.by, я тоже решил поделиться наблюдениями из своего опыта. Экспы у меня не то чтобы много, но постараюсь быть максимально адекватным. Если я чего-то не догоняю, это не со зла - вы меня поправьте, ладно?

1) Емакс действительно крут. Главные его плюсы, на мой взгляд - неинтрузивность, программируемость и естественная интеграция с консолью. Например, недавно я соорудил наколенную билд-систему, с помощью которой застримлайнил свою работу над абсолютно разнородными проектами в универе. Она прекрасно заинтегрировалась в фар, и не менее замечательно - в емакс. Чтобы из емакса запустить какой-нибудь процесс и вбросить аутпут в буфер, нужны буквально пару телодвижений. Повесить на это все хоткеи и сделать гиперлинки на ошибки - еще немного работы. Пару обтачиваний и вуаля: myke-backend.el. Страшно представить, как что-то похожее сделать в Эклипсе.

2) Практически все можно пилить самому. Это прекрасно и очень вдохновляет (например, одним телодвижением можно посмотреть, на какой именно код забинджен тот или иной ключик), но есть и обратная сторона. Практически все придется допиливать самому. Даже банальную ширину таба нужно настраивать секретным образом (см. отдельную настройку для tab-stop-list), что уж говорить про такие вещи как копипасту, анду или прокрутку (кстати, у меня до сих пор через раз работает выделение мышкой). Это не то что бы уж очень плохо, но надо иметь ввиду, что первые пару недель емакс будет отнимать колоссальное количество времени.

3) Лисп не античеловечный, но и не простой в освоении. Довольно быстро я научился колбасить говнокод (что, наверняка, уже увидели уважаемые гуру емакса, пробежавшись по моему конфигу), но что-либо сложное я предпочитаю писать на чем-нибудь другом. Например, билд-система, упоминавшаяся выше, естественным образом выросла из ад-хок сниппетов на елиспе, но попытки превратить ее в что-то более-менее стройное успехом не увенчались, поэтому я по-быструхе переписал все с нуля на сишарпе. Наверняка, проблемы с удобством стандартной библиотеки и структур данных - всего лишь следствие моего несистемного подхода к изучению елиспа, но что вижу, то и пою. В любом случае, крайне помог бложек Стива Йегги, например, вот этот пост: Emergency Elisp.

4) Емакс - не панацея, что бы не писали в инете (по крайней мере для меня). Для разработки компилятора Скалы я юзаю Эклипс (контрол + клик на дефинишен и дебаг слишком важны, чтобы от них отказываться), для коммитов и истории я юзаю TortoiseGit (magit работает через раз + для чего-то нетривиального в VCS тупо нужен гуй). Вначале я думал, что это я такой нехардкорный, а потом увидел, что все в команде делают то же самое (только гуй к гиту другой, ибо никто не сидит на венде). Даже Мартин, который юзает емакс уже лет двадцать.

5) И все же я очень доволен емаксом. За денек я интегрировал в него греп по проектам с персональными свистелками, после чего выкинул поиск эклипса. Для сложных сессий репла Скалы я тоже юзаю емакс (идея консоли в буфере просто прелестна!). Да и домашки по алгоритмам в латеке я тоже фигачу в емаксе, ибо там подсветка синтаксиса и вручную прикрученный side-by-side превью.

Вот так и живем. Браузинг кода и дебаг в эклипсе, компиляция в фаре, текстовый поиск и реплы в емаксе. Use the right tools for the right job. Искренне ваш, кэп.
glider

29 октября в 12:00 в Минске расскажу про макросы в Скале

Эту неделю я буду в Минске, поэтому предложил ребятам из коммьюнити scala.by выступить с презентацией про макросы и обсудить потенциально интересные применения макросов на практике.

Спасибо большое Васе Ременюку - он оперативно организовал нашу встречу в эту субботу 29 октября в 12:00 на Купревича 1/1. Регистрация на ивент находится вот тут: http://scala.by/news/2011/10/24/meetup-6.html. Также, по поводу оргвопросов можно отписаться в гугл групсы: http://groups.google.com/group/scala-enthusiasts-belarus/browse_thread/thread/88e476cf1e52a9ff.

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

Пожалуйста, заходите к нам на огонек, ибо мне крайне важно узнать ваше мнение. Для чего в ваших проектах могут быть применены макросы? Есть ли такие задачи, для которых вы плачете, колетесь, но пишете бойлерплейт? Сейчас я всего лишь пишу спеку, поэтому оригинальную идею можно легко подпилить в ту или иную сторону. Не стесняйтесь - и макросы в Скале будут полезны лично для вас и ваших юз-кейсов.

upd. Большое спасибо всем, кто был сегодня на встрече! Ребята, это большая честь рассказать о том, что я делаю, такой заинтересованной аудитории. Также крайне порадовало то, что было столько вопросов буквально с первой минуты презентации. По факту мы обсудили раза в три больше вопросов, чем я заранее планировал =) Слайды лежат на гитхабе: https://raw.github.com/xeno-by/kepler/master/papers/2011-10-29-RuProjectKepler.pdf. Скринкаст будет выложен на днях, об этом я отпишусь отдельно.
glider

github: как в форкнутом репозитории смержиться с апстримом

Я подозревал, что такое возможно, а сегодня, как понадобилось - научился:
* http://help.github.com/fork-a-repo/
* http://stackoverflow.com/questions/849308/pull-push-from-multiple-remote-locations

Заодно догнал, зачем нужно магическое заклинание "git remote add origin git://github.com/username/newproject" для того, чтобы инициализировать только что созданный проект на гитхабе. В принципе, логично, хотя в меркуриале было совсем по-другому.
glider

файловые менеджеры

Сегодня по пути в универ прочитал статью Мигеля де Икасы Learning Unix. Как раз то, что я хотел найти в посте ищу книжку про юникс/линукс. В сжатом виде аффтар описывает свое видение unix way. Субъективно, opinionated - то, что надо, жаль мало. Пусть даже с непонятно откуда взявшейся рекламой платного курса по слепой печати. Впрочем, сегодняшний пост не об этом.

Когда я читал фрагмент статьи, в котором идет речь про mc (кстати, Мигель де Икаса, оказывается, является автором mc, омг!), у меня что-то щелкнуло в голове, и я, наконец, нашел для себя смысл в посте ребе vp про Total Commander. Напомню краткое содержание: "А вот у нас на работе эта программа запрещена. Если кто-то из работников будет замечен за ее использованием - сразу увольнение. Основная идея файлового менеджера - ускорение работы с файлами, с перенаправлением вывода, с выводом на консоль, с подстановкой параметров в командную строку и т.п. Ни одной задачи эта софтина не решает, а мозг людям, кто ею пользуется."

Сразу признаюсь - основной программой у меня на компе долгое время был тотал.

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

Народ, который юзает фар, всегда вызывал у меня искреннее недоумение - вроде бы то же самое, только с уродливым шрифтом и без закладок. Зачем мучиться? А разгадка крайне проста! (сорри, что сейчас буду играть в кэпа, но, если бы кто-нибудь пару лет назад провел сеанс кэпства для меня, я был бы искренне благодарен)

***

Консоль - мощный и удобный способ организации рабочего окружения. Для себя я это понял примерно через день знакомства с линуксом, но это тема для отдельной лекции К.О., на пока что примем сабж за аксиому. Раз консоль так крута, возникает желание юзать ее все время. Но у меня это желание разбилось о неразрешимую проблему - как же держать в голове список файлов, с которым я в данный момент работаю. На эту тему я слышал много разных ответов, в том числе и стандартный ответ линуксоида: "а нафига это нужно, зато вона что мы умеем".

Вначале я думал, что дело в том, что я не понимаю дзен линуксизма и что надо тренировать моск удовлетворяться аутпутом команды ls или, на худой конец, ls -l. Ессно, моску весьма часто этого не хватает, да и держать все в памяти он не может - ну, по крайней мере, мой. Ну, или, думал я, может, вообще не нужно ручками выбирать файлы-параметры для команд (например, если я хочу скопировать часть файлов из одной папки в другую), у нас же есть вайлдкарды и греп. Ессно, и это не панацея - если бы автоматика могла полностью заменить ручной труд, мы бы уже жили в раю.

Погрустил я на эту тему и забил. Нашел для линукса какой-то тоталоподобный файловый менеджер и стал юзать его вместе с консолью. Если сказать честно, нихрена это не удобно. Смотришь на список файлов в этом самом файловом менеджере и действительно быстро понимаешь: "оба-на, зафигачу-ка я команду delitec для вот этих двух scala-файликов из двадцати лежащих в папке". Набираешь в строке ввода менеджера "delitec file1 file2", нажимаешь ENTER - окошко появилось на секунду и пропало. Что происходит - неизвестно. Брр. Бесишься про себя, в строке ввода набираешь "$TERM", который стартует в текущей директории, а там уже вбиваешь, что надо. Лишние телодвижения, но что поделать. Как вариант, можно скачать плагинчик, который по отдельной просьбе будет открывать $TERM за тебя, но и с этим есть косяки. Что, если внезапно хочется посмотреть список файлов в консоли? Еще один плагинчик искать?

Как же решить все эти проблемы? Просто забить - поставленных проблем не существует, ибо есть программы, которые сочетают в себе и консоль, и файловый менеджер. Да, в общем-то и файловый менеджер как отдельная концепция нифига не нужен. Тотал настолько извратил мое мировосприятие, что я просто не представлял, как такое может быть.



Что видит на картинке ученик класса по информатике? Меню, две панели с файлами, какую-то строчку ввода и кнопки. Ессно, основной фокус внимания на файлы - сознание автоматически воспринимает их как главное, что есть на экране. Ну причем здесь строчка ввода, да и нафига она вообще? А еще тема, можно нажать Ctrl+O и появится какая-то черная хрень на весь экран. Во смеху-то будет, если сделать так челу за соседним компом.

Что на самом деле находится на картинке? Шелл, командная строка которого находится внизу, а основное полотно (предыдущие команды и их вывод) спрятано. Кроме того, на экране также находятся два дополнительных виджета: список файлов текущей папки шелла и список файлов какой-то другой папки.

В такой ментальной модели вся сложность взаимодействия консоли и файлового менеджера, описанная выше, пропадает. Это, на самом деле, одна и та же программа, просто к собственно консоли добавились еще несколько вспомогательных визуальных элементов. Несколько примеров.

1) Основной киллер-фичей тотала для меня было наличие закладок. По сравнению с эксплорером тотал значительно выигрывает в скорости навигации по файловой системе, но без дополнительных средств он не сильно-то и круче в плане одновременной работы с несколькими папками, а то и хуже вообще - обычно, тотал открывают только один, а эксплореров пачку. Блин, фигово. Надо придумывать дополнительную концепцию - закладки (табы ли, букмарки ли, это детали реализации). Вот она, сложность родимая.

А на деле ведь переход в папку описывается простой командой cd. Нравится какая-то папка - не вопрос. Сделай алиас для соответствующего cd и юзай на здоровье. Часто бываешь в папке Downloads - нафигачь алиас dl для "cd /foo/bar/very/long/path/Downloads" и набирай dl, чтобы быстро попасть, куда надо. Набираешь dl в шелле, а, в честь перехода в новую папку, соответствующий виджет автоматически обновляет список файлов. Всяко быстрее, чем тыркать мышкой, и не хуже, чем нажимать C-d <номер закладки>. Но что главное - логичнее.

2) Скажем, файловую систему мы набраузили и теперь надо искать файлы по имени. В модели номер 1 нужно реализовать логику поиска, сваять уи, реализовать концепцию виртуального списка файлов, который не соответствует никакой реально папке в файловой системе. Я специально упоминаю детали реализации в посте про юзабилити потому, что эти детали влияют не только на эффорты программиста, но и на мысленную картину, которую для себя строит пользователь.

В модели номер 2 нужно всего лишь ввести концепцию виртуального виджета, ибо find у нас уже есть (в виде консольной программы), а уи нам не нужен - вместо использования поля ввода юзер просто вобьет имя или вайлдкард в составе команды консоли. Кроме того, такой подход неплохо скейлится на будущие требования, если нам понадобится искать по другим критериям. Скажем, если нужно искать вхождение подстрок в содержимом файлов, нужно лишь заменить вызов find вызовом find + xargs + grep. Я идеализирую, конечно, для некоторых тасков специализированный уи будет удобнее, но идея понятна.

3) Часто бывает необходимо не только посмотреть аутпут какой-то команды, но также и свериться с результатом выполнения некоторой программы в прошлом. В рамках модели номер 2 для этого достаточно нажать тот самый хоткей Ctrl+O и вся история консоли перед глазами.

В модели номер 1 пользователь должен сам заботиться о сохранении аутпута важных программ. Особенно доставляют такому пользователю "нехорошие" программы, которые выполняются в консольном режиме и автоматически закрываются по окончанию работы. Для них надо ручками открывать окошки консолей, добавлять pause в бат-файлы или readline в программы. Чего только не придумаешь для борьбы с ветряными мельницами.

***

tl;dr. В сухом остатке остается вывод о том, что продуктивнее думать о файловом менеджере не как об отдельной программе, а как о надстройке над шеллом. Но, как только появляется такое видение, сразу становится заметно, что тотал и его клоны не очень-то и хорошо поддерживают эту парадигму использования. После этого выбор в пользу консольных файловых менеджеров становится самоочевиден.
glider

емакс, часть 3: windows

емакс, часть 1: первый взгляд
емакс, часть 2: восторг
емакс, часть 3: windows
емакс, часть 4: ретроспектива

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

Сразу после запуска емакс встретил меня сообщением об ошибке в скриптах инициализации и антиалиаснутым курьером. "Окей, в принципе никто и не предполагал, что сразу все заработает" - подумал я и нажал Alt+F4, чтобы перезапустить емакс в режиме отладки. В ответ последовало: "<M-f4> is undefined", что в переводе на русский обозначает, что Alt+F4 по умолчанию ни на что не забинджен. Да, поездочка будет долгой...

Сегодняшний пост будет содержать большое количество технических деталей, поэтому нетерпеливым читателям спешу сообщить, что все заработало (в том числе и шелл-скрипты с участием coreutils), но пришлось немного повозиться. Недоволен я остался лишь гитом - он и, как следствие, интеграция с ним работают раздражающе медленно, но, к счастью, общение с ними удалось свести к минимуму. В любом случае, все траблы, через которые пришлось пройти, перекрываются тем фактом, что под линухой и виндой у меня теперь практически идентичное окружение. А, благодаря дропбоксу, перезагрузка в другую операционку всего лишь меняет визуальную тему окошек, но не их содержимое.

upd. Также я столкнулся с проблемой тормозов. Часть из них была вызвана гитом (см. ниже по тексту), часть из них имела другие причины. Хорошая новость в том, что все удалось починить. Детали см. вот тут: http://xeno-by.livejournal.com/57626.html.

***

Первым делом я обдумал вопрос программного окружения. Так как емакс неслабо использует возможности стандартных юниксовых тулов (например, поиск по пачке файлов (читай, проекту) проще всего реализовать через find+grep), нужно было где-то достать эти самые тулы. Можно было просто вытащить греп и файнд из mingw, но отказываться от шелла тоже не хотелось, ибо писать дакт-тейп на елиспе - удовольствие ниже среднего. В итоге, остались два варианта: 1) запускать емакс из-под цигвина или чего-то подобного (к сожалению, я плохо разбираюсь в теме эмуляции юникса под виндой, поэтому не в курсе, как еще можно поступить в рамках этой опции), 2) юзать NT Emacs (т.е. емакс, скомпилированный в виде нативного виндового приложения), но при этом использовать bash и gnu utils от цигвина.

После чтения емакс-вики и статейки Стива Йегги я решил остановиться на второй возможности. Кроме общефилософского мнения о том, что предпочтительнее юзать нативную прилагу, немаловажным был тот фактор, что цигвин я видел первый раз в жизни, поэтому непонятно, какие косяки меня могли ожидать. В любом случае, и баш, и корные юниксовые утилиты доступны в обоих случаях, поэтому, выбрав NT Emacs, концептуально я ничего не терял. В итоге я поставил цигвин, добавил его bin в виндовый PATH, установил переменную окружения SHELL в c:\cygwin\bin\bash.exe (это все, что нужно для того, чтобы емакс проинтегрировался с цигвиновскими coreutils) и смело пошел навстречу граблям.

Самым первым делом я пофиксил шрифты. Если к сглаживанию как таковому я со временем привык, то сглаженный курьер меня продолжает удивлять и по сей день. Впрочем, оказалось, что установкой одной-единственной переменной можно сразу изменить шрифт для всего окна емакса. Для полноты картины отмечу два нюанса: 1) формат значений этой переменной нетривиален, 2) переменная локальна для фрейма, т.е. для новых окон нужно ее устанавливать заново. За деталями смотрим сюда.

Следующей на очереди была унификация формата сохраненной сессии емакса между виндой и линуксом. Винда успешно поддерживает симлинки, но никакими симлинками не превратить путь типа X:\ в путь типа /foo/bar. И это даже несмотря на то, что емакс прекрасно переваривает прямые слеши вместо обратных и наоборот. Проблема решилась при помощи цигвина. В папке c:\cygwin я воспроизвел структуру рабочего окружения линукса и забросил оттуда симлинки на папки с реальным контентом. А дальше всего лишь осталось заюзать библиотеку cygwin-mount, которая умеет маппить виртуальные юниксовые пути на реальные виндовые пути внутри папки цигвина.

Пришлось также неслабо поисследовать вопрос с хоткеями. В линуксе проблема гвоздями прибитых хоткеев отсутствует - и в метасити, и в компизе можно перебиндить что угодно, включая вещи вроде alt+tab. В винде все несколько грустнее. Во-первых, из коробки емакс не обрабатывал кнопки Win, отдавая их системе. Если в убунте я мог изображать любые сочетания клавиш с участием Win, то в винде эти штучки уже не работали. К счастью, нашлось простое решение. Для того, чтобы Win превратить в super (или во любой другой модификатор), нужно всего лишь установить парочку переменных.

Дальше - интереснее. Если проблемы с win+tab и win+цифры я ожидал, то увидеть занятыми ctrl+esc и даже win+= было удивительно. Вначале я пытался разрулить проблему, копаясь в реестре, но это были просто припарки - там заработало, тут отвалилось. Ситуацию переломил бесплатный тул AutoHotkey. С помощью несложного вида скриптов он позволяет перекрыть и обработать большой спектр хоткеев (я подозреваю, что все, что угодно, кроме ctrl+alt+del), а также даже скомпилировать свои скрипты в standalone икзешники. Кроме того, я перемаппил Caps Lock на Ctrl - это делается регедитом, без всяких тулов.

Конечно, мои изыскания не могли пройти мимо проблемы с разделителями строк. Вначале я подумал, что эту проблему удастся избежать, т.к. емакс достаточно смартовый редактор для того, чтобы автоматически понимать, где \n, а где \r\n. Но после того, как скрипт, отредактированный под виндой, отвалился в линуксе по причине лишнего символа \r, мне стало не до шуток. Была введена политика огораживания, по которой все новосозданные файлы, несмотря на текущую операционку, кодируются с разделителями в стиле юникса. Исключение - бат-файлы, которые без \r\n виндовый интерпретатор не съест. Интуитивно чувствую, что это решение слишком жестко, чтобы быть практичным, но будущее покажет.

Кстати, по концовке оказалось, что проблема была не в емаксе. Символы окончания строки испортил кое-кто другой. Некоторые из вас, вероятно, уже догадались. В честь этого все вместе передадим привет гиту и его core.autocrlf. Впрочем, тема гита на винде выходит за пределы и так уже большого поста.

Последняя грабля была связана снова с гитом. В интернетах много кто жалуется на неторопливость его виндового порта. Как я понял, это связано с тем, что гит юзает идиомы линукса, которые невозможно эффективно замаппить на виндовый апи, в честь чего и тормоза. На горьком опыте я выяснил, для дефолтного сетапа msysgit 1.7.2 операции вида git XXX выполняются минимум 0.3 секунды каждая (ssd, core i7, loads of ram). Все бы ничего, но при открытии каждого файла емаксовая инфраструктура сорс-контроля выполняет более 10 таких операций. Путем красноглазия удалось сократить время до 0.1 секунды на операцию, но это все равно баттхёрт! Пришлось отрубать, но, на счастье, получилось чисто - отключился только хук, но не остальной функционал вроде диффов.

***

tl;dr. Поставлено тулов: 1) Cygwin, 2) NT Emacs. Пришлось подпилить: 1) фонты, 2) имена файлов в сессиях, 3) системные хоткеи винды, 4) политику разделителей строк, 5) интеграцию с гитом. В результате под виндой: 1) gnu тулы из емакса работают, 2) шелл-скрипты из емакса (например, grep+find по проекту) работают, 3) сессии емакса, сохраненные в одной операционке, открываются в другой, 4) функциональность и хоткеи емакса в пределах моего воркфлова одинаковы - и в линухе, и в винде.
glider

емакс, часть 1: первый взгляд

емакс, часть 1: первый взгляд
емакс, часть 2: восторг
емакс, часть 3: windows
емакс, часть 4: ретроспектива

Наконец, переборол свой страх перед емаксом и заставил себя слезть с gedit. За сегодня узнал много чего нового - ecb, dired, tabbar, ну и так, по мелочи настроил .emacs.d. Попутно сгенерилась куча вопросов, вот несколько из них.

1. В чем тайный смысл длинных хоткеев для частых действий? Вот, например, C-x C-_ для redo: требует нажатия пяти клавиш для выполнения весьма распространенной процедуры. Это ведь банально неудобно! Наверное, я что-то упускаю, но что? upd. Просто замаппил redo на C-y при помощи UndoTree. Надеюсь, тайный смысл многокнопочных шорткатов пойму позже.

2. С созданием хоткеев я в целом разобрался, но остался нерешенный момент. Как забиндить C-1? Когда я в init.el пишу (global-set-key (kbd "C-1") 'blah-blah), то хоткей тупо не применяется. Если в этой же строчке заменить С-1, например, на C-=, то все ок. upd. Выяснилось, что C-цифры замаплены на некий digit-argument, но я без понятия что это, поэтому просто заюзал другую комбинацию клавиш.

3. Что по концовке будет удобнее: CUA или стандартный подход емакса к копипасту? upd. Врубил CUA, ибо решил вначале добиться минимально необходимого/привычного набора фич, а потом уже играться с емаксом по ходу работы.

4. Как я понимаю, dired - выбор редакции для всех операций, которые касаются нескольких файлов одновременно? Например, поиск некоторого текста во всех файлах папки или замена чего-либо рекурсивно для всех файлов проекта. Или же есть какой-то более удобный тул для этой цели, про который, например, в силу юного возраста еще не написали в бложеках?

5. Как можно удобно сделать инкрементальный поиск по всем файлам проекта? Я нагуглил вариант с запуском диреда с флажком -R и инкрементальным поиском по окошку диреда. Есть ли альтернативные опции с автокомплитом, например, в минибуфере? Как я понял, и ido, и icicles поддерживают только поиск файла в текущей папке. Какие есть еще варианты? (задал вопрос на stackoverflow)

6. Под виндой я привык, что tortoise* регистрирует кастомные оверлеи на иконках файлов, лежащих под сорс-контролем. Файл не менялся после последнего коммита - зелененький, менялся - красненький, ну и в таком духе. Особенная прелесть такого подхода заключается в том, что иконки рекурсивно применяются к папкам, т.о. можно быстро увидеть что закоммитал, а что забыл. Есть ли что-то похожее в емаксе? Я видел, что ECB рисует иконки файлов с учетом их статуса в VCS. Но умеет ли он отображать статус папок? upd. Забил - вообще отключил иконки ECB. Во-первых, они часто глючат, а, во-вторых, магита хватает за глаза - одной кнопкой можно посмотреть статус репозитория, что, в общем-то, и нужно было от иконок.

7. Про какие мастхэв модули я должен знать? Я нашел интересный пост на SO: The single most useful emacs feature - но там больше про мелочи.
glider

Макось

Зачел пост "Опыт перехода с Linux на Mac OS X" с хабра (основной интерес для меня составили каменты, ибо области деятельности афтара - работа со звуком. Встретил высказывание уважаемого sorhed на тему того, что макось лучшая в мире операционка, не считая QNX.

Дискашен попал в точку, ибо мое первое знакомство с макосью состоялось буквально пару дней назад, когда я портировал скрипты с линукса на винду и мак. Я не так уж и много общался с макосью - в основном, сидел в консоли, но мне операционка не показалась откровением + много вещей, к которым надо привыкать (начнем, например, с замещения контрола мак-кнопкой или, вот, вспоминается свистопляска с home/end/pgup/pgdn). Чего я не понял?
glider

Про перл

С перлом меня познакомил Стив Йегги.
Потом я сел почитать книжку Learning Perl, но быстро заскучал и забил разбираться.

Спустя год после знакомства с юниксом я снова начал эксперименты.
Немного освоив bash, решил продвигаться дальше и стал разбираться с юниксовым тулчейном.
Нашел клевую штучку про awk: Idiomatic Awk, параллельно немного научился пинать sed.
Дальше - больше: Awk One-Liners Explained, Sed One-Liners Explained.
С авком еще туда-сюда, но текст про сед я не осилил и до половины.

Посмотрел на питон, почитал секретные техники шелл-скриптинга.
К счастью, вспомнил про перл.
Оказывается, он умеет эмулировать сед и авк: http://perldoc.perl.org/perlrun.html.

Зашел на stackoverflow поискать книжки по перлу.
Смотрю, все говорят про какой-то camel book.
Открываю Learning Perl, которую читал год назад - вроде бы на обложке какой-то верблюд.
Думаю: ну что они в этой книге нашли, скукотища ведь.
Присмотрелся - а там на самом деле лама.
Вот блин, оказывается тогда я читал неправильную книжку.
Правильная книжка называется Programming Perl.

Чо, сел читать правильную литературу.
Вначале был срыв мозга: http://stackoverflow.com/questions/6698041/how-do-parentheses-work-in-perl-5.
Потом перл мне показался весьма милым: http://pastie.org/2243606.
Потом снова срыв мозга: http://perldoc.perl.org/perlref.html.
А потом мне вштырило: http://perldoc.perl.org/perlobj.html.

Перл все-таки прикольный. "0+" - отличное название для оператора каста к числу.
И книжка Programming Perl очень хорошая. Если бы не она, навряд ли бы меня так затянуло.