Всякие разные штуки сомнительной полезности сделанные в свободное от работы время.
JavaScript, все не так плохо
(На картинке - jslint в шоке от юзерскрипа который обращается к всяким неизвестным ему сущностям типа key, hook, command и т.п.)
Не так давно я стал задумываться, а есть ли жизнь после смерти, на Марсе, и в других местах, где Флеша нету. Одной из промежуточных целей было найти средства вменяемой разработки используя JavaScript. Я как-то слышал хорошие отзывы о Visual Studio, но проверить их не удалось. Попробовал Аптану, но как-то не понравилось, какая-то она "сырая" что ли. Да и вообще, Эклипс...
Вобщем, чего я вас буду вводить в заблуждение, конечно же я искал возможности как бы сделать Эмакс по-удобнее для разработки. И, честно говоря, результат превзошел ожидания! Но давайте сначала и по-порядку.
Эмакс без никаких добавок предлагает javascript-mode. Это умеренно-терпимый мод для редактирования, сами догадываетесь чего. Кроме раскраски и автоматического форматирования в нем практически ничего и нет, ну только немного традиционной навигации от элемента к элементу, к началу функции, концу и т.д. Конечно, для полноценной работы этого не достаточно. Отправился я на поиски, и вот что нашел: http://blog.deadpansincerity.com/201...un-and-profit/ Собственно, тут уже все расписано в деталях, но я добавлю немного от себя. И подведу коротенький итог:
Нужно будет установить Node.js сервер. Этот сервер нужно устанавливать самому (это не сложно, но несколько непривычно, т.как в закромах Debian он не обнаружился). Для справки, что такое Node.js и зачем он нужен: это сервер написаный на С++ который может выполнять JavaScript. А нужен он нам будет для того, чтобы мы могли использовать fly-make (это младший мод в Эмаксе, ответсвенный за подсветку ошибок компиляции, и вообще ошибок синтаксиса), т.как мы будем его использовать в комплекте с jslint'ом - программой написанной Крокфордом (начальником JavaScript отдела в Yahoo!) специально предназначенной для обнаружения ошибок (разного плана, начиная от форматирования и заканчивая ошибками несовпадения типов) в JavaScrip'е. Кроме того, он нам понадобится для того, чтобы общаться с интерпретатором JavaScript'а. (Все ссылки с описанием приведены ниже).
Кроме Node.js и jslint нам понадобится js-comint - это, собственно, и есть интерпретатор, который позволяет нам интерактивно добавлять или изменять уже написанные функции, рассматривать содержание объектов и т.д. К сожалению, такой JavaScript выполняется отдельно от HTML страницы, в которой он будет находиться, что делает тестирование немного затруднительным, но об этом чуть позже.
В статье которую я цитирую говорится еще и о yasnippet (я его не устанавливал, и пока не вижу в нем критической необходимости, кроме того, в комментариях виднеют упоминания о его конфликтах с автоподстановкой, так что я бы пока не рекомендовал).
Автоподстановка, вопреки ожиданиям оказалась вполне сносной. Единственное, надо привыкнуть к тому, что ей нельзя на 100% доверять. Т.е. если автоподстановка не показывает возможное дополнение, это не значит, что его не существует. Но она "обучается по мере работы, ей так же можно скормить все файлы проекта на обработку, и тогда она будет "лучше соображать".
С другой стороны, есть и позитивный момент, т.как в JavaScript'е нет четких границ модулей, такая автоподстановка, основанная только на том, что загружено в данный момент может оказаться на руку, т.как не будет предлагать использовать функции из файлов, которые возможно, к делу отношения не имеют.
Немного дополнительной информации относящейся к тестированию: дя Firefox обнаружился очень занятный плагин, который, кроме того что имитирует горячие клавиши Эмакса, так еще и предоставляет возможность вызова пользовательских скриптов через такой привычный для Эмакса интерфейс: M-x function-name. Кроме того, он умеет общаться с Firebug и еще масса полезных плюшек, которые мне еще предстоит разобрать.
Полезность его заключается еще и в том, что он в интерактивном режиме позволяет нам общаться со скриптами на уровне хрома и на уровне страницы, а так же консолью - что делает отладку гораздо удобнее.
Ниже приводится пошаговое руководство к установке и настройке. Большую часть вы можете так же смело копировать с сайта deadpansincerity, т.как существенных изменений я не делал. Итак:
- Скачиваем Node.js http://nodejs.org/
- Распаковываем его куда-нибудь, но все-таки не в Downloads - нам эта папка еще пригодится.
- Запускаем
Код:
$ ./configure
-
Код:
$ make
-
Код:
# make install
Код:# apt-get install libssl-dev
- Скачиваем http://npmjs.org/install.sh с http://npmjs.org/ это установщик менеджера пакетов (на манер easy_install в Питоне или Quicklisp в CL).
- Запускаем его, опять же, с правами администратора.
- Далее, нам понадобятся следующие утилиты из пакетов npm:
Код:$ git clone https://github.com/davidmiller/lintnode.git $ cd lintnode $ npm install express connect-form haml underscore
- Скачиваем js-commint отсюда: http://js-comint-el.sourceforge.net/ и добавляем его на пути просматриваемые Эмаксом. (весь код нужный для подключения к Эмаксу приведен ниже.
- Автоподстановку можно скачать вот от сюда: http://cx4a.org/software/auto-complete/ она так же здорово облегчает жизнь при написании eLisp скриптов, но собственно, и для Java и для C++ может выступать как подспорье.
Ее желательно скомпилировать, если собираетесь использовать. http://cx4a.org/software/auto-comple...llation_Script тут описано как это сделать. -
Код:
; this is optional, but nice to have autocomplete library (add-to-list 'load-path "~/.emacs.d/") (require 'auto-complete-config) (add-to-list 'ac-dictionary-directories "~/.emacs.d/ac-dict") (ac-config-default) (setq-default ac-sources (add-to-list 'ac-sources 'ac-source-dictionary)) (global-auto-complete-mode t) ; Start auto-completion after 2 characters of a word (setq ac-auto-start 2) ; case sensitivity is important when finding matches (setq ac-ignore-case nil) ; lintnode has the flymake implementation to highlight JavaScript ; errors, so we need to load it in order to incorporate it with flymake (add-to-list 'load-path "~/projects/lintnode") (require 'flymake-jslint) ;; Make sure we can find the lintnode executable (setq lintnode-location "~/projects/lintnode") ;; JSLint can be... opinionated (this is the original comment, I'm ;; yet to discover what do eny of these do, but keep them for now) (setq lintnode-jslint-excludes (list 'nomen 'undef 'plusplus 'onevar 'white)) (add-hook 'js-mode-hook (lambda () ;; Start the server when we first open a js file and start checking (lintnode-hook) ;; Scan the file for nested code blocks. Not very useful, but for ;; niciety will do (imenu-add-menubar-index) ;; Activate the folding mode, again, this isn't mandatory, but ;; nice to have, read the original post to see what exactly it does ;;;; todo: these key bindings might be useful later. ;; (global-set-key (kbd "") 'hs-show-block) ;; (global-set-key (kbd "") 'hs-show-all) ;; (global-set-key (kbd "") 'hs-hide-block) ;; (global-set-key (kbd "") 'hs-hide-all) (hs-minor-mode t))) ;; this is the location of js-comint .el files ;; we need them for the JavaScript REPL (add-to-list 'load-path "~/projects/js-comint/") (require 'js-comint) ;; Use node as our repl (setq inferior-js-program-command "node") ;; various stuff to launch when javascript-mode starts. (setq inferior-js-mode-hook (lambda () ;; We like nice colors (ansi-color-for-comint-mode-on) ;; Deal with some prompt nonsense (add-to-list 'comint-preoutput-filter-functions (lambda (output) ;; ">" (replace-regexp-in-string ".*1G\.\.\..*5G" "..." (replace-regexp-in-string ".*1G.*3G" "* " output))))))
- Ну и последнее, https://github.com/mooz/keysnail/wiki/ keysnail очень полезный плагин к Firefox, который делает работу в браузере похожей на Эмакс. Инстуркция к установке прямо там же, по ссылке. Ниже пример добавления пользовательской функции, которую можно вызвать через M-x hello-world
Код:function hello_world() { alert('Hello world!'); } ext.add("hello-world", hello_world, M({ en: "This function shows Hello world alert", ru: "Эта функция показывает предупреждение Hello world"}));
И, совственно, первый практический пример применения. Оно еще немного сыровато, но все-равно приятно. Итак, пример:
Добавляем функцию в .keysnail.js. Эта функция будет зарегистрирована как M-x find-tab. Что делает: показывает окошко с возможностью выбрать закладку на которую нужно мы хотим перейти. Для меня это часто проблема т.как открыто пару десятков закладок и искать в них очень долго - хуже еще и то, что кнопка в Firefox которая показывает все закладки никак не нажимается с клавиатуры. Что мы собственно тут и исправим.
function find_tab() { var w = window.getBrowser(); var tabs = w.browsers; var s = []; for (var i = tabs.length - 1; i >= 0; i--) { if ('contentTitle' in tabs[i]) s.unshift(tabs[i].contentTitle); } window.openDialog("file:///home/wvxvw/xul/tabsearch-dialog.xul", "select tab", "select tab", s, w); } ext.add("find-tab", find_tab, M({ en: "Allows you to chose a browser tab to switch to", ru: "Позволяет перейти на выбранную закладку" }));
Код:
<?xml version="1.0"?> <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?> <dialog id="whatever" title="Select a tab to open" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" buttons="accept,cancel" buttonlabelcancel="Cancel" buttonlabelaccept="Save" ondialogaccept="return doOK();" ondialogcancel="return doCancel();"> <dialogheader title="Select tab"/> <menulist id="search-box" editable="true" oncommand="commandHandler(event)" onkeyup="keyUpHandler(event)"/> <script> var a = window.arguments[0]; var opener = window.arguments[1]; var menu = document.getElementById('search-box'); function doOK() { opener.selectTabAtIndex(a.indexOf(menu.value)); return true; } function doCancel(){ return true; } function commandHandler(event) { doOK(); window.close(); } function keyUpHandler(event) { var v = menu.value; menu.removeAllItems(); populate(a.filter(function (x, i) { if (x.toLowerCase() == v.toLowerCase()) opener.selectTabAtIndex(i); return x.toLowerCase().indexOf(v.toLowerCase()) > -1; })); } function populate(choices) { for (var i = choices.length - 1, s; i >= 0; i--) { s = choices[i]; menu.appendItem(s, s); } } menu.focus(); menu.select(); populate(a); // This doesn't seem to work, no idea why. menu.open = true; </script> </dialog>
Всего комментариев 0
Комментарии
Последние записи от wvxvw
- Dired - текстовый проводник по файловой системе (29.06.2013)
- Навигация по HTML с WASD (09.06.2012)
- JavaScript, все не так плохо (07.06.2012)
- Что такое tarball и чем его пакуют (11.04.2012)
- Критика Presentation Model (18.02.2012)