6 марта 2010 в 21:36

Javascript для Notepad++

Здравствуй Храбрачеловек,

сегодня я решил поделиться с тобой Plugin'ом для Notepad++, который позволит тебе спомощью JavaScript автоматизировать некоторые действия над текстом и не только.

Рождение идеи


С тех пор как я открыл для себя Notepad++, прошло довольно таки много времени. Я использую его как дома так и на работе. Иногда приходится обрабатывать рутиным образом файлы и в большинстве случаев достаточно регулярных выражений. Но бывают случаи, когда хочется немного больше логики, чтобы одним махом произвести замену или что либо подсчитать. Для полного счастья не хватает VBA :-).
Поискав не долго я нашел Plugin под названием «Simple script». Он позволяет используя определенный набор функций последовательно обработать текст. Вообщем оказался слишком ПРОСТОЙ скрипт, чтобы удовлетворить мои в принцие на тот момент небольшие потребности. Дружба с «Simple script»
так и не сложилась.

По долгу службы я познакомился с Microsoft Windows Script, c помощью которого я тогда автоматизировал генерирование и обработку XML файлов. Однажды читая документацию к нему, я обнаружил, что его можно прикрутить и к своему приложению. Поискав по интернетам дальнейшую информацию и опыт внедрения в свои приложения я обнаружил законченный пример на RSDN.ru.

Мне было ясно, что я хочу полноценный JavaScript в Notepad++ и что это возможно.

Реализация


Многочисленные попытки начать дело потерпели неудачу. Отсутствие ATL на домашнем компьютере, а так же отсутствие желания и времени разбираться с этой библиотекой, создавали относительно большой порог для начала. Но однажды готовясь к очередному набегу я набрел на две ключевые статьи:СОМ без ATL и Использование Скриптинг. Спомощью этих двух статей был переработан пример с RSDN.ru без использования ATL. Моему восторгу не было предела, когда заработал первый прототип.

Довольно быстро я реализовал первоначальную идею — выполнение выделенного или скопированного в буфер обмена JavaScript кода. Потом захотелось повесить этот код на елементы меню. Поколдовав немного и подменив функцию окна, удалось вклиниться в главное меню Npp. Возможность работать с меню расширила область применения нового плагина (смотри ниже). С появлением меню захотелось сделать его контекстно зависимым. Чтобы например при переключении с файла на файл [де]активировать определенные елементы меню. Так появилась возможность навешивать обработчики событий.

Подготавливая примеры работы с Plugin'ом я заложил основы для чтения и сохранения настроек.

Использование


Ох и надоел я тебе со своими рассказами наверное! Переходим к практике.

В глобальной области видимости из JavaScript доступен обьект Editor. Доступ к его свойствам и методам возможен так же и без указания его имени.
/* Properties of Editor */
/* read only */
firstView; // a View object
currentView;// a View object
secondView;// a View object
clipBoard;
langs; // Array of language names
pluginConfigDir;
nppDir;

/* read write, bool */
tabBarHidden;
toolBarHidden;
menuHidden;
statusBarHidden;

/* Methods */
alert(/**String*/value);
saveAll();
open(/**String*/value);
addMenu(/**String*/ text); // returns a Menu object
decodeFrom(/** Number*/ codepage, /**String*/ value);
encodeTo(/** Number*/ codepage, /**String*/ value);
runMenuCmd(/** Number*/ cmd); // Runs a standart Menu command (see MenuCmds.js)
setListener(/** Object */ cfg); // see GlobalListener in start.js
addSystemHotKey(/** Object */ cfg); // adds system hotkey (see example in run.js)

Для работы с текстовыми редакторами Editor предоставляет свойства [firs|current|second]View.
/* Properties of View */
/* read write*/
text;
file; // number of current file
selection; // currently selected text
codepage; // Number of current codepage
lang; // Number of current language (see Editor.langs)
line; // Number of current line of text
pos; // Cursor position
column; // Cursor position from line begin
anchor; // Helps to set a selection. Selection is text in interval [anchor, pos]

/* read only */
files; // Array of strings

Чтобы добавить в главное меню необходимо вызвать Editor.addMenu(«Your Sub menu»). Прямое добавление в главное меню елементов не
предусмотренно.
/* Properties of Menu */
/* read write */
text;
checked;
disabled;
/* Methods */
addMenu(/*String*/ text); // adds and returns next submenu
addMenuItem(/*Object*/cfg); // adds and returns menu item

/* Properties of MenuItem */
/* read write */
text;
checked;
disabled;
/* Methods */
remove();


Для затравки я решил привести только небольшой пример (всего на 749байт):
var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
if (xmlHttp){
  // Создаю Меню
  var habrMenu = Editor.addMenu("Хабрахабр");
  xmlHttp.open('GET', 'http://habrahabr.ru/rss/1c9d5ed4f0953ded81510256ed34c9be/', true);
  xmlHttp.onreadystatechange = function () {
    if (xmlHttp.readyState == 4 && xmlHttp.responseXML) {
      var titles = xmlHttp.responseXML.selectNodes("/rss/channel/item/title");
      for(var i=0, c=titles.length; i<c; i++){
        // Создаю для каждой статьи в RSS свой пункт меню
        habrMenu.addItem({
          text: titles[i].text, // название пункта
          link: titles[i].selectSingleNode("../link").text, // сохраняю тут ссылку на статью
          cmd:function(){ // функция вызваемая по нажатию на пункт меню
            var shell = new ActiveXObject("WScript.Shell");
            if (shell && this.link){
              shell.run(this.link); // Открываю статью в Браузере
            }
        }});
      }
    }
  };
  xmlHttp.send(null);
}


Пример показывает возможности Plugin'а, а так же работу с XML и Shell используя ActiveX.
www.softwarecanoe.de/pic/nppscripting.habr.png

Дальнейшие возможности смотри в прилагаемых скриптах из папки includes.
  • run.js — добавляет меню для выполнения JavaScript,
  • clearcase.js — добавляет меню для работы с ClearCase,
  • decode.js — добавляет меню для декодирования текста (практично в не русской Windows),
  • gTranslate.js — добавляет меню для перевода текста с помощью Google Translate,
  • test.menu.js — добавляет меню с примерами и тестами,
  • dialog.js — позволяет, используя Internet Explorer, создавать диалоговые окна,
  • Zen Coding.js — Zen Coding от chikuyonok.

Пара ссылочек:
Страница проекта на Google Code,
Microsoft Windows Scripting

Happy Scripting!

UPD: Благодаря стараниям chikuyonok была обнаружена ошибочка, а так же адаптирован Zen Coding для Notepad++!!!
Ошибка уже исправлена.

UPD 2: Благодаря стараниям t0H была обнаружена ещё одна ошибочка. В скрытое главное меню не добавлялись новые подменю.
Ошибка уже исправлена.

UPD 3: Новая версия и API к ней. Пришлось переименовать plug-in из-за того что уже существовал с таким же именем для программирования на LUA. Так что не забудьте удалить предыдущую версию plug-in'a (NppScripting.dll и NppScripting папку).
sieukrem @sieukrem
карма
16,0
рейтинг 0,0

Комментарии (59)

  • +1
    Я рад, что для моего любимого EmEditor'a не нужно изобретать ничего подобного — он из коробки поддерживает макросы на Javascript/VBscript (более того, поддерживается запись таких макросов). Больше я не видел текстовых редакторов (кроме офиса со своим VBA) с подобным функционалом. Думаю за ваши старания поклонники Notepad++ тоже скажут вам спасибо.
    • 0
      До вашего коментария не слышал о EmEditor'a :-). Посмотрел, действительно мощьно, правда за деньги и ещё нет поддержики для ClearCase ;-)
  • 0
    А у этого плагина есть возможность заменить фрагмент текста в редакторе? Например, заменить выделенный текст на что-нибудь другое?
    • +1
      это была та самая первая идея.
      // заменим в выделении все пробелы на плюсики
      currentView.selection = currentView.selection.replace(/\s/,'+');


      * This source code was highlighted with Source Code Highlighter.
  • +2
    мне почему то казалось что подобная статья получить больший ажиотаж ;) я как яркий поклонник Notepad++ искренне благодарен вам за проделанную роботу =) единственное, хотелось бы пожелать дальнейшего развития плагина!..
    p.s. очень хочется возможности обработки открытия \ закрытия файла…
    • 0
      Прощу прощения, недосмотрел) Оказывается, прямо сейчас уже можно вешать обработчики. Ещё раз спасибо…
    • 0
      Вы правы, это ожиотаж. Я вообще-то называю это «зараженный человек». Если я от чего-то в восторге, я готов бежать и со всеми делиться. Такое поведение наверное неправильно, тк не все это понимают :-)
  • 0
    Полезная штука. Всё думаю вернуться к notepad++ от textmate. Textmate хвалят-хвалят, а много чего не хватает…
  • +2
    Я сейчас делаю один плагин для Notepad++ на основе вашего, столкнулся с такой проблемой: WSH наотрез отказывается импортирвать JS-файлы, размер которых больше 20 КБ (примерно). При этом программа падает, ссылаясь на другой плагин.

    В качестве решения своей проблемы я вставляю кода плагина прямиком в start.js, что, конечно, не очень хорошо. Может, есть вариант вместо start.js использовать .wsf файл, чтобы можно было подключать файлы более «нативным» способом?
    • 0
      И ещё вдогонку вопрос: как вызвать диалоговое окно с полем для ввода? Стандартный prompt() не работает.
      • 0
        Вы правы, функции нет! Я хотел сразу мощьный инструмент для построения диалогов предоставить. Посмотрите пример «Show Dialog» в меню «Tests» (реализован в tests.menu.js). Используется ИЕ, а это значит что вы можете доволно таки сложные диалоги строить, как для ввода данных так и для управления редактором. Если предполагается частое использование такого диалога, то совет создавать его один раз и по закрытию скрывать, экономите инициализацию ИЕ.
        Скажу сразу, сам я еще ничего толкового, кроме примера, таким способом не сделал. Уверен prompt() с эмулировать можно :-)
    • 0
      хммм!
      Сохраните ваш плагин в UTF-8!
      WSF это уже программа от MS, которая использует то же Windows scripting. Про такой же подход для подключения новых скриптов я тоже думал, но это уже другая история.
      • +1
        Не помогает. Вот такую ошибку вижу:


        Причём если я беру свой плагин и сокращаю количество кода в нём, скажем, до 15 КБ, то всё работает (верее, ничего не падает).
        • 0
          Хочется надеяться, что ошибку я исправил не наделав новых. Проблема была в том что я освобождал память которую не выделял :-). Zen Coding я выделил в новый файл и добавил в обновленный архив, если вы не против.
        • 0
          Внезапно тоже выскочила эта ошибка. Оказывается касперский что-то похерил. Исправил перерегистрацией библиотек — forum.oszone.net/post-1482725.html
  • +4
    Вот, собственно, и результат: Zen Coding for Notepad++. Могу сказать, что вы осчастливили многих пользователей этого редактора :)

    Вы не против того, что я ваш плагин поставляю вместе со своим? Там в readme.txt ваше авторство указано + я удалил все тестовые скрипты.
    • +1
      Конечно же я не против! Я рад что плагин находит применение, не смотря на присутствие ошибок. Я предалагаю «Zen Coding for Notepad++» включить в стандартный набор скриптов!
    • 0
      Очень оперативно! Спасибо за проделанную работу.
    • 0
      Спасибо!
      Очень приятно использовать!
      По сравнению с E — просто летает)
  • 0
    Спасибо!
  • 0
    Спасибо, что реализовали то, что я в свое время не смогла сделать.
  • +1
    Спасибо большое действительно удобно…
    только есть небольшой баг (
    если меню скрыто и показывается только по нажатию Alt, то новые пункты не добавляются((
    я из за этого уже два раза обновил программу и кучу всего перепробовал(((
    • +1
      Cпасибо за найденую ошибку. Не продумал такой пример использования.
      Уже поправил, в обновленном архиве лежит новая версия Dll.
    • 0
      Возможно не нашел «обновленного» архива, но у меня все равно работает только так:

      var mh = Editor.menuHidden;
      Editor.menuHidden = 0;

      var testMenu = Editor.addMenu(«Tests»);

      Editor.menuHidden = mh;

      NPP 5.6.8 UNICODE
      Nppscripting.dll 0.1.1.0

      Может исходники на google code? Ошибки сами собой находиться будут (не знаю, как выразить смущение)

      P.S. Спасибо за плагин.
      • 0
        Вы немного не туда написали)
        а вообще архив действительно обновлен уже…
      • 0
        По ссылке в топике уже Nppscripting.dll 0.1.2.0.
        Я использовал что то подобное, но только на CPP, чтобы получить хендл меню от нпп. Иначе к сожалению никак.
        • 0
          Вот по этой: www.softwarecanoe.de/data/nppscripting.zip — 0.1.1 (только что проверил). Есть еще какая-то?
          • 0
            Заставте браузер скачать новый zip!
  • 0
    У меня при нажатии CTRL+E выскакивает ENQ.
    • 0
      Скорее всего CTRL+E было зарезервировано другим приложением. Попробуйте дургую комбинацию.
      • 0
        Как изменить комбинацию? Например, хочется ctrl+пробел
        • 0
          Будет! Но только это все глобально, так что перестанет работать в других приложениях и будет вызывать ваш обработчик в Нпп даже если он не активен!
          • 0
            Эм… Т.е. эта возомжность будет в скором?
            • 0
              Давайте попорядку! Опишите что вы и как делаете!

              Где вы это обнаружили: сами пишете или используете сторонний яваскрипт?
              Какую версию Nppscriptingю.dll вы используете?
              Что вы хотите добиться?
  • 0
    По порядку:
    1. есть чистый notepad++ последней версии 5.6.8
    2. Ставлю Zen.Coding-Notepad++.v0.6.zip
    3. Версия Nppscripting.dll
    clip2net.com/clip/m5759/1270197580-clip-7kb.png
    4. открываю notepad++, ввеожу «div», нажимаю ctrl+e получаю символ ENQ (как на скриншоте). Если же выбрать пункт меню «Expand Abbreviation», то все разворачивается
    • 0
      А какая раскладка по умолчанию? Попробуйте английскую поставить по умолчанию и перезапустить Npp! Я думаю заработает :-) Решение проблемы я думаю вы уже понимаете.

      1. Если вы используете оригинал Zen Coding то открываете start.js
      2. Меняете комбинации в самом внизу файла на другие (русские буковки)
      3. Перезапускаете Нпп.

      Комбинации клавиш срабатывают глобально в системе. Это значит, что обработчик вызывается даже если Нпп не активен. Такое поведение конечно плохо, т.к перестают работать горячие клавиши в других приложениях, но пока что другой (правильный) вариант из-за ограничений Нпп не возможен. И как я понимаю еще долго не будет решен, не смотря на то что патч я уже заслал. Возможно решают другие проблемы. :-(

      А еще я советую вам скачать плагин по ссылке в этой статье. Так как были устранены некоторые ошибки, а Zen Coding выделен в отдельный файл.
      • 0
        А можно ссылку на issue, где описывается проблема глобальных hotkey'ев? Спасибо
        • 0
          Я так понимаю, ребята более важной работой завалены. Поэтому каждый интегрирует сам.
          • 0
            Подозреваю, что из тикета просто не понятен смысл проблемы, из-за этого он наверное и не в приоритете.
            • 0
              Вы правы.

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

              Долго ждать у меня не было желания и я решил это ограничение установив хук на очередь сообщений приложения.

              Так что, кто хочет интегрирует, а терпеливые ждут новую версию плагина!

              ;-)
    • 0
      Если это из-за того, что CTRL+E занято, то поменять можно так:

      в файле Zen Coding.js найдите
      строку
      addMenuItem('Expand Abbreviation', 'expand_abbreviation', 'Ctrl+E');
      и замените CTRL+E на любую удобную вам комбинацию (из клавиш ALT,CTRL,SHIFT и одного символа).
      Если вы хотите CTRL+пробел, то нужно чуть-больше поменять:
      addMenuItem('Expand Abbreviation', 'expand_abbreviation', 'Ctrl+Space');
      • 0
        Нечаянно отправил ответ, не дописав его.
        Выше, в функции function addMenuItem(name, action, keystroke) {
        после строки:
        for (var i = 0, il = keys.length; i < il; i++) {
        var key = keys[i].toLowerCase();
        нужно добавить:
        if (key=='space') key=' ';

        Тогда у вас сработает CTRL+пробел.
  • 0
    Это же просто пи… ец! Это нереально удобно! Сегодня только узнал про зен кодинг и сразу плагин для нотпада. Теперь-то я с него точно никогда не слезу. Огромное спасибо!
    • 0
      Это очень удобно! Я вчера узнал про Zen Coding и нашел плагин для npp сразу 0.7-й версии! Только один вопрос меня мучает — как добавить свои снипеты?
      Я в качестве шаблонизатора в некоторых проектах использую смарти и хотелось бы некоторые его конструкции добавить.

      Добавляю в plugins\NppScripting\includes\Zen Coding.js — 675-й строкой

      'foreach': '{ foreach }\r\n\r\n{ /foreach }',

      Перезагружаюсь
      В результате получаю закрытый тег foreach
  • 0
    Кажется разобрался, добавляю в zen_settings секцию

    Copy Source | Copy HTML«php»: {
      «filters»: «tpl,php,html»,
      «extends»: «html,css»,
      «snippets»: {
        «foreach»: "{ foreach }\n\n{ /foreach }\n",
        «foreachelse»: "{ foreach }\n\n{ foreachelse }\n\n{ /foreach }\n"
      }
    },

    при этом у меня в настройках стилей для php назначено пользовательское расширение php, все работает!
    Еще раз спасибо Автору.
  • 0
    Что-то у меня Editor.currentView.column возвращает то же, что Editor.currentView.pos. :(
    • +1
      А не поделитесь примером!?
      • +1
        Editor.addMenu("Example").addItem({
        	text: "Example",
        	cmd: function() {
        		alert(Editor.currentView.column - Editor.currentView.pos);
        	}
        });


        В любом файле на любой строке при выполнении этой команды выводится 0.
        • 0
          Буг :(
          • 0
            Южный? :) Кстати. открытие исходников не предвидится?
        • 0
          Спасибо за подсказку. Ошибка была уже давно исправлена возможно даже я и не заметил ее. Вот с публикацией новой версии я затянул. Дом-работа-семья.

          Версия для желающих выявить ошибки и нестыковки со скриптами написанными для предыдущей версии. Крохи API документации.
      • 0
        Notepad++ 5.9.3 Unicode
  • 0
    Заинтересовал плагин. В процессе написания своего JS плагина под ваше решение столкнулся с некоторыми трудностями:

    Поскольку работает мы уже не в браузере, и вместо стандартного браузерного объекта window, у нас объект Editor, то где искать методы типа setInterval, SetTimout?

    И вообще интересует каким образом сделан этот плагин, в плане движка, вряд ли в плагине реализован собственный движок, ведь так?
    Я спрашиваю это для того что обратиться к его мануалам и посмотреть какое АПИ доступно кроме описанного вами.
    • 0
      Снимаю часть своего вопроса: setTimeout нашел в вашем Api.
      Но вот как реализован JS все равно интересно. Я так понимаю что задействован Windows Host Script, но я попытался использовать его встроенные объекты и у меня ничего не вышло.
      Я не слишком силен в этой специфике, основное направление разработки всегда было WEB…
      • 0
        Используется Scripting Engine. Microsoft предлагает VB и JScript реализованные на ее базисе. Доступны только те объекты, которые видны из javascript и те что вы нашли в Api плагина.

        WHS это совершенно отдельное приложение, которое добавляет свои объекты для облегчения работы с Windows из скрипта. Части WHS реализованны ввиде ActiveX и могут быть использованны в ваших скриптах для Npp.
        Как например
        // объект для работы с файловой системой
        var fso = new ActiveXObject(«Scripting.FileSystemObject»);
        или
        // объект для чтения файла с возможностью указания кодировки
        // советую обратить на него внимание
        var stream = new ActiveXObject(«ADODB.Stream»);

        А тут и тут можно глянуть как работать с базой данных.

        Например так можно новую создать БД
        var cat = new ActiveXObject(«ADOX.Catalog»);
        cat.Create(«Provider='Microsoft.Jet.OLEDB.4.0';Data Source='h:\\new1.mdb'»);

        Успехов!
  • 0
    Кто-нибудь в курсе, как в NPP настроить всплывающие подсказки по функциям JS, с параметрами функций?
    например, вот так:
    image

    Пробовал настроить плагин Language Help с разными справочниками *.CHM, всплывающих подсказок нет (не путать с автодополнением)… Но для других языков народ как-то ухитряется настроить, для PHP и т.п.

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.