Признаком хороших абстракций может быть то, что они позволяют быстро создавать новые полезные абстракции. Это подчеркивается ощущением, что ваша среда программирования работает на вас, а не против вас. Ситуация, когда вы ограничены только своими мыслями и воображением, а не тем, что компьютер позволяет вам делать. Это ощущение, которое я редко улавливаю без использования Emacs. Часто шутят, что Emacs - отличная операционная система - ей просто не хватает приличного текстового редактора. Обычно это используется не по назначению, но я всегда считал это сильной стороной. Emacs никогда не говорит мне «Нет», что одновременно является большой опасностью и невероятным преимуществом. В этом духе развития мне нравится подталкивать Emacs к новым пределам, чтобы увидеть, на что он способен… который, как вы сейчас прочитаете, включает ClojureScript.

Самая сильная сторона Emacs - это, как правило, самый большой источник критики со стороны непользователей, заключающийся в том, что он контролируется языком под названием Emacs Lisp (elisp). elisp - отличный язык, но очень посредственный Лисп. Пользователи Emacs давно искали альтернативу. Emacs-ng - это вилка emacs, которая интегрирует среду выполнения Deno посредством набора дополнительных изменений в нативный уровень. Это обеспечивает полный контроль над сценарием редактора с использованием JavaScript / TypeScript, сохраняя при этом возможность чистого слияния патчей из восходящего потока. Этот выбор был… спорным, мягко говоря. Ряд опытных пользователей Emacs считают, что Emacs IS lisp, и большое количество пользователей JavaScript прекрасно справляются с такими решениями, как VSCode. Что, если бы существовал способ дать каждому желание, которое они хотят?

Пользователи давно хотели включить в Emacs другие шепелявые. Clojure - это диалект Лиспа, работающий на JVM. Обычное обсуждение интеграции чего-то вроде Clojure в Emacs сосредоточено на необходимых изменениях в сборщике мусора и среде выполнения elisp. Обе эти системы тесно связаны в Emacs, и изменить их будет очень сложно. Для этого потребуется кто-то мотивированный, который хорошо разбирается в существующей кодовой базе C и низкоуровневом программировании в целом, а также понимает Clojure. Люди с таким набором навыков встречаются редко. Я знаю, что лично я не подхожу к этому счету ... но почему я вообще должен проходить через всю эту работу? Clojure - динамический язык, elisp - динамический язык, почему компьютер не может просто понять, как они могут разговаривать друг с другом? Чтобы связать это с началом, нам просто не хватает правильной абстракции. На самом деле я должен сказать, что нам не хватало правильной абстракции. Кому-то пришло в голову, что было бы здорово, если бы Clojure запускался в браузере, скомпилировав Clojure в JavaScript и назвав его ClojureScript. Поскольку теперь у нас есть возможность запускать JavaScript в emacs-ng, означает ли это, что мы можем запускать ClojureScript в Emacs?

Сначала я думал, что это будет невозможно из-за того, что ClojureScript не поддерживает Deno в качестве цели первого класса, но оказалось, что пользователь GitHub jobez на самом деле получил MVP, работающий, который я разветвился, чтобы поиграть с . Первоначальный MVP очень прост: просто скомпилируйте ClojureScript как модуль ES6 и импортируйте его. Однако Джобез предложил нам кое-что более интересное - мы можем настроить компилятор файлового наблюдателя, чтобы мы генерировали результат при сохранении. Затем нам просто нужно оценить наш буфер JavaScript для запуска наших функций. Я добавил немного логики, чтобы обойти отсутствие у Deno перезагрузки горячего модуля, но конечный результат довольно прост:

Это может быть неясно, поскольку у нас на экране очень много языков, но мы вызываем функции elisp из ClojureScript и вызываем функции ClojureScript из JavaScript. Этот .message js/lisp на самом деле вызывает функцию сообщения elisp - и в этом нет ничего особенного. Мы можем вызвать практически ЛЮБУЮ функцию elisp из JavaScript, и поэтому мы можем сделать то же самое практически для любой функции elisp. Все это происходит от замечательного объекта lisp в JavaScript, который позволяет нам легко преобразовывать наши объекты JavaScript в объекты elisp и обрабатывать преобразование наоборот. Благодаря этой единственной возможности мы получили совершенно другой язык в нескольких строках кода. Барьеры на пути «чего я хочу» исчезают, когда компьютер работает на меня, а не против меня. С очень небольшими усилиями мы можем экспортировать это как правильную функцию elisp и вызвать ее * с нуля *

Самым большим ограничением этого подхода является то, что, поскольку Deno и nodejs имеют разные API для доступа к файлам, для определенных операций, таких как доступ к файлам, потребуется специальный код, то есть вам нужно будет использовать js/Deno readTextFile вместо использования стандартной библиотеки ClojureScript и полагаться на перевод ClojureScript компилятор предоставляет.

Выполнение базового теста Фибоначчи дает нам следующее (ClojureScript вверху)

Для fib (40) выводится в миллисекундах. Этот тест не очень подробный, и я уверен, что смогу контролировать его и дальше, но он очень многообещающий.

Для этого проекта еще многое предстоит изучить, но я очень рад этому. Я надеюсь, что в будущем люди будут использовать JavaScript / TypeScript и ClojureScript для создания замечательных приложений elisp на emacs-ng.