ACE: самый функциональный редактор кода для веба (not only)

от автора

Здравствуйте, господа!

Я был достаточно приятно удивлен, когда узнал, что проект Ajax.org, именуемый Ace почти ни разу не упоминался на хабре. Ace — это веб-редактор исходного кода нового поколения. Он поддерживает уйму различных функций, среди которых: наличие режимов подсветки синтаксиса для более чем 60 языков программирования, сумасшедщего количества цветовых схем из различных поопулярный IDE, широкой кастомизации вида и функционала, syntax checkers для нескольких скриптовых языков. Так уж получилось, что эта статья скорее всего будет разносторонняя, т.е. содержать материал для веб-разработчиков и С++ программистов, которых я так успешно агитирую в сторону Qt. Итак, что вы можете прочитать в этой статье?

  • Быстрый старт с Ace. Где я могу использовать Ace? Почему?
  • Портирование Ace на Qt и обертка его API: How-To для создателей Qt5-based библиотек

Сейчас позволю себе показать пару скриншотов example-приложения, которое использует мою библиотеку Novile:


Что такое Ace?

Ace (англ. Ajax.org Cloud9 Editor) — онлайн-редактор исходного кода с подсветкой синтаксиса, темами, и горячими клавишами, написанный на Javascript, распространяющийся по лицензиям MPL/LGPL/GPL и легко встраиваемый в любую веб-страницу. Ace разработан в качестве основного редактора Cloud9 IDE является продолжением проекта Mozilla Skywriter (Bespin). Сейчас проек хостится на GitHub и активно развивается.

Ace может заинтересовать того, кому необходимо установить красивый, и главное — удобный редактор исходного кода на сайт или встроить в свое приложение. Из приемуществ редактора можно выделить такие:

  • Подсветка для более чем 60 языков (есть импорт файлов .tmlanguage)
  • Есть более 20 тем оформления (.tmtheme также импортируются)
  • Проверка синтаксиса в режиме реального времени (JavaScript/PHP/CSS/etc.)
  • Работает на больших документах (говорят, тянет 4 000 000 строчках кода)
  • Сворачивание кода, при наличии его языка программирования
  • Легко настраиваемые «горячие» клавиши и комбинации
  • Несколько курсоров и выделений
  • Отображение непечатных символов (что очень не маловажно)
  • Автоматическое выравнивание кода
  • Поиск и замена на регулярках
  • Режимы soft и hard табуляций

Это и делает Ace очень удобным и легко встраиваемым редактором!

API и документации

Присутствие документации определяет ее отсутсвие. Короче говоря, нормальной документации у Ace’a нету. На сайте таковое есть, но назвать его API Reference — это слишком громко сказать. Сейчас, давайте как-то интеративненько настроим этот редактор. Stey-by-step, так сказать.

Шаг 1. Элементарная настройка

Начнем с создания предпологаемой страницы с редактором. Создадим шаблон:

<!DOCTYPE html> <html lang="en">     <head>         <title>Ace Editor Demo</title>         <style type="text/css">             #editor {                  position: absolute;                 top: 0;                 right: 0;                 bottom: 0;                 left: 0;             }         </style>     </head>     <body>         <div id="editor"></div>         <script src="http://d1n0x3qji82z53.cloudfront.net/src-min-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>         <script>             var editor = ace.edit("editor"); // теперь обращаться к редактору будем через editor             // Далее весь экшон будет проходить тут!         </script>     </body> </html> 

Отлично! Теперь у нас есть простая страничка с простым редактором кода. Это уже что-то. Кстати, можно использовать другие источники Ace.js. Не говоря о том, что вам понадобятся другие файлы, лучше вообще собирать его самостоятельно (node-ом) или собирать по-кусочком из built-файлов с различным функционалом.

Шаг 2. Больше красок!

Сейчас настало время добавить красок нашему предпологаемому JavaScript коду. Это можно легко сделать путем нескольких нехитрых call-ов. Ну что, давайте допишем пару строчек:

editor.setTheme("ace/theme/monokai"); editor.getSession().setMode("ace/mode/javascript"); 

Что же мы сделали? Тема редактора задается строкой, содержащей путь формата ace/theme/<theme_name>. Важно отметить, что тема — это именно атрибут Editor. Далее мы задаем режим подсветки, подсветка — атрибут EditSession. Она задается аналогично теме, за исключением того, что задается не редактору на прямую, а его сессии. Теперь, давайте что-то памалякаем. Например, можете поупражняться в написании навороченого jquery-based AJAX-запроса 🙂

Шаг 3. Управляем текстом на API-level

Писать код — хорошо, но еще лучше уметь что-то с ним делать на программном уровне. На этом шаге я постараюсь разобраться в основных функциях редактора и их API. Как сказал Гагарин, Поехали!

Получаем и задаем содержимое:

editor.setValue("<source code>"); // задаем editor.getValue(); // -> String (получаем) 

Немного работы с выделением:

var selectionRange = editor.getSelectionRange(); // Range - название говорит само за себя var selectionText = editor.getSession().getTextRange(selectionRange); // -> String (текст выделения) 

А теперь немного поиграемся с курсором:

var pos = editor.getCursorPosition(); // Object {row: N, column: M} editor.insert("I know how to insert text"); // вставляем в точку, где находится курсор editor.gotoLine(lineNumber); // переходим на линию #lineNumber (нумерация с нуля) 

Что насчет расширенного управление кодингом?

var lines = editor.session.getLength(); // колличество строчек в документе editor.getSession().setUseSoftTabs(true); // использования "мягкого" выравнивания Tab-ами. document.getElementById('editor').style.fontSize='12px'; // достаточно только поменять размер шрифта #editor editor.getSession().setUseWrapMode(true); // включаем text wrapping editor.setShowPrintMargin(false); // такая полоска-граница (40, 80 или свободно число символов, считая слева) editor.setReadOnly(true); // нельзя редактировать, false - можно 

Кстати, если вдруг вам захочется поменять размер div#editor, не меняя размеров самого окна, то нужно выполнить

editor.resize() 
Шаг 4. Поиск и события (events)

К сожалению, о поиске я скажу только пару слов, так как почему-то нет желания сейчас сдесь описывать его работу. Вкраце, поддерживает регулярные выражения, чувствительность к регистру, и много других параметров. API сводится к

editor.find('needle', { // ищем текст "needle"     backwards: false, // только спереди курсора     wrap: false, // циклируем по документу     caseSensitive: false, // все равно на регистр     wholeWord: false, // только слово целиком     regExp: false // без регулярок }); editor.findNext(); editor.findPrevious(); editor.replaceAll('pub'); 

Слушаем различные события:

// Что-то изменилось в сессии editor.getSession().on('change', function(e) {     // e.type, etc });  // Поменялось выделение editor.getSession().selection.on('changeSelection', function(e) {     // e.type, etc });  // Смена локации курсора editor.getSession().selection.on('changeCursor', function(e) {     // e.type, etc }); 

А теперь очень классное, «горячие» клавиши и сочетания:

editor.commands.addCommand({     name: 'myCommand', // название комманды     bindKey: {win: 'Ctrl-M',  mac: 'Command-M'}, // вызов на PC и Mac     exec: function(editor) { // судный час         // editor.*     },     readOnly: true // false, если мы не хотим чтобы в readOnly работало }); 

В теории, обладая этими знаниями (+ специфика из полного api reference) можно написать редактор, аналогичный редактору Cloud9 IDE. Конечно нужно очень сильно его extend-ить, но оно того стоит.

Novile Component for Qt

Сейчас речь пойдет о проекте Novile, проекте над которым я работал последнюю неделю. Смелые продолжат читать, а те, кому не особо оно-то и колышется, могут пролистать к Заключению. А джедаев я попрошу остаться. Я собираюсь рассказать о том, как использовать Novile, зачем он нужен, и главное, расскажу,

Кому оно надо?

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

Novile, в частности, created with Qt, created for Qt. Кто не знает, Qt — это фреймворк для разработки кросс-платформенного ПО на C++ (еще можно на Python, Java, но это не тот случай). Погуглив, можно понять что Qt — это нечто, что Qt — это Linux Mac Window Symbian Android iOS Embedded. Novile — это мост между низкоуровневым API редактора на JavaScript к высокоуровневому коду на С++ через QtWebKit.

Сборочная система

Не смотря на то, что Qt очень активно пропагандирует QMake, а уже скоро начнется QBS-мания, я считаю что для библиотек самый лучший вариант, одназначно CMake. Он дает тот уровень кастомизации зборки, который действительно нужен.

Сейчас для зборки и установки Novile с документацией, debug output и примером нужно выполнить (Linux):

cd path/to/novile mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=path -DVERBOSE_OUTPUT=Yes -DBUILD_DOCS=Yes -DBUILD_EXAMPLE=Yes .. make # можно пропустить make install 

Удобно, не так-ли? Сегодня я попробую научить вас делать такие библиотеки (в данном случае для Qt 5). Кстати, я не буду рассказывать как работает СMake, и как с ним работать, так как на хабре уже есть такая статья. Она отнимет у вас буквально пару минут. А сейчас, если вам неинтересен CMake, вы можете пролистать следующую статью.

Qt 5 в CMake 2.8.8+

Как же заставить CMake собирать Qt 5 проекты? Да очень просто. Читаем код и комментарии (кстати, приятно, что на хабре есть хайлайтер для CMake):

# .h файлы будут автоматически подвержены мета-объектному компилятору set(CMAKE_AUTOMOC ON) # будет добавлять текущую папку в инклюды автоматически # (не нужно будет везде писать include_directories(.) set(CMAKE_INCLUDE_CURRENT_DIR ON)  # ищем QtWebKitWidgets и находим (я надеюсь) # кстати, чтобы оно его нашло, cmake-файлы Qt должны быть в $PATH find_package(Qt5WebKitWidgets REQUIRED)  # я люблю записывть все .cpp файлы в такой манер set(NOVILE_SOURCES # .cpp     editor.cpp )  # аналогично set(NOVILE_HEADERS # .h     editor.h     novile_export.h     novile_debug.h     editor_p.h )  # QRC - файлы ресурсов Qt. Утилита uic собирает .qrc файлы в qrc_*.cpp файлы, которые # можна использовать для ресурсов. NOVUILE_RCC_SRC - готовые qrc_*.cpp файлы qt5_add_resources(NOVILE_RCC_SRC ../data/shared.qrc) # скармливаем файл ресурсов и получаем qrc_*.cpp файл add_library(novile SHARED ${NOVILE_SOURCES} # создаем shared-библиотеку                           ${NOVILE_HEADERS}                           ${NOVILE_RCC_SRC}                           ../data/shared.qrc # только чтобы этот файл отображался в дереве проекта IDE (.cbp файл) ) qt5_use_modules(novile WebKitWidgets) # linkуем к таргету модуль Qt 5  set_target_properties(novile PROPERTIES # свойства библиотеки     DEFINE_SYMBOL NOVILE_MAKEDLL # define для свитчера EXPORT/IMPORT     PUBLIC_HEADER "${NOVILE_HEADERS}" # хедеры для установки )  install(TARGETS novile     LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib     PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/include ) 

Если вы создаете свою библиотеку, то этого вам не избежать. Еще вам может понадобится собирать .ui файлы пользовательского интерфейса. Для этого есть специальный макрос:

# EXAMPLE_UIC_HDR - переменная со сгенерированными ui_*.h qt5_wrap_ui(EXAMPLE_UIC_HDR mainwindow.ui) 

Import/Export свитчеры

При работе с библиотекой, некоторые символы должны уйти в експорт, а потом, на этапе использования либы, быть импортироваными из нее, поэтому удобно использовать такую конструкцию:

#ifndef NOVILE_EXPORT # if defined(NOVILE_MAKEDLL) #  define NOVILE_EXPORT Q_DECL_EXPORT // кьютовый макрос экспорта # else #  define NOVILE_EXPORT Q_DECL_IMPORT // импорта # endif #endif  class NOVILE_EXPORT MyClass {     Q_OBJECT // ... 

Итак, теперь, во время зборки, нужно объявить -DNOVILE_MAKEDLL (помните, выше мы его установили в cmake). При использовании библиотеки, макроса не будет, и будет вызван экспорт.

Как пользоваться Novile?

Пример использования Novile классно описан в проекте из папки example, который хорошо собирается с ключем конфигурации -DBUILD_EXAMPLE=Yes, который сделает все за вас.

Но тут я готов привести маленький пример того, как же удобно это все делается из плюсов (С++11 + Qt 5)

#include <Novile/Editor>  using namespace std;  // somewhere in the code...  Editor *editor = new Editor; editor->setHighlightMode(Editor::ModePython); editor->setTheme(Editor::ThemeMonokai); editor->setFontSize(13); editor->setPrintMarginShown(false); connect(editor, &Editor::textChanged, [=]() { // код будет выполнен асинхронно на событии     const QString &text = editor->text();     doSmth(text); }); editor->show(); // показать его миру 

C++11, мощный Qt и дописанная Novile позволяют построить быструю и кросс-платформенную IDE со всем необходимым функционалом.

Заключение

Я надеюсь что эта статья действительно помогла и веб-разработчикам и программистам. Представить не могу, насколько удачно я сагитировал народ на Qt, но я старался. Честно. Хотелось бы сказать пару слов в сторону Novile. Признаться говоря, сейчас Novile не совсем хороший продукт, чтобы я про него не говорил. Сейчас она покрывает от силы 50% функционала Ace. Если есть кто-то заинтересованый, вы всегда можете помочь проекту на GitHub. Даже самый маленький pull request будет кстати.

Ссылочки

  1. ace.ajax.org
  2. github.com/tucnak/novile
  3. qt-project.org/

Спасибо за внимание,
namespace

ссылка на оригинал статьи http://habrahabr.ru/post/174987/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *