Pull to refresh

Давайте быстрокодить как профессионалы

Reading time21 min
Views20K

Дайте мне рычаг, точку опоры, место для ног и армированный скотч



Даже попытавшись, нельзя лаконично обрисовать, насколько бездонная кроличья нора вас поджидает. Здесь один из тех редкостных случаев, когда, чтобы осознать, о чём будет идти речь, надо выслушать речь до самого финала. Изучив по шагам настоящее руководство, каждый обнаружит для себя что-то своё: эзотерический «текстовый» редактор Leo Editor всей своей сутью призывает применить его самым изумительным образом.




Содержание


1.  Пролог...................................2
2.  Установка Leo Editor.....................2
3.  Настройка................................4
4.  Знакомимся с интерфейсом.................7
5.  Создание внешних файлов.................14
6.  Использование именованных секций........18
7.  Жадное включение........................21
8.  Простое волшебство......................24
9.  Обратная сторона оборотня...............30
10. Визуализируй это........................33
11. Содержание и форма......................36
12. Сам себе IDE построю....................39
13. Свобода мысли...........................49
14. Ура, конец..............................58
15. UPD. Примеры применения.................58




Пролог


Ко­гда пи­шешь на каком-нибудь язы­ке про­грам­ми­ро­ва­ния, вечно ощу­ща­ет­ся ост­рая не­хват­ка брау­зе­ра клас­сов от Smalltalk, без конца свер­бит досадное чувство, буд­то ру­ки свя­за­ны, а но­гам промозгло. А ещё случается, зачастую выискиваешь в интернете од­но, а обнаруживаешь со­всем иное, но в такой степени пре­крас­ное, что при­чи­на начала розысков утрачивается на фо­не раз­вер­нув­ших­ся го­ри­зон­тов. По­иск по фра­зе «python class browser» вы­да­ёт тон­ну белиберды, но в этой го­ре ле­жит не­ог­ра­нён­ный ал­маз, смутно по­бле­ски­вая, не притягивая ши­ро­ко­го интереса, дожидаясь по­ка вни­ма­тель­ный глаз и пыт­ли­вый ум, приметят и под­бе­рут его.



Установка Leo Editor


Проект кроссплатформенный, процесс установки приводится для платформы Windows. Для запуска редактора необходимы Python и библиотека Qt. Описываемый вариант установки является наиболее бесхитростным для неготового к страданиям пользователя, профессионалы могут действовать по своему усмотрению.

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

Со странички загрузки скачиваем инсталлятор Python 3.7 Miniconda3 Windows 64-bit. Устанавливаем, когда возникнет вопрос про галочки, активируем обе две.

Следом запускаем командную строку (клавиши [Win + R], «cmd», [Enter]). Набираем:

conda

верни картинку взад

Ошибки нет, прямой доступ к conda есть. Проверяем наличие нужной версии выполнятора языка:

python -V

верни картинку взад

На месте.

Смотрим, какие версии редактора доступны для установки:

pip install leo==

Отдаём предпочтение последней версии без литер в номере:

pip install leo==6.1

После окончания скачивания, распаковки и установки, испытываем нашу удачу: запускаем интерпретатор python, подсоединяемся к компонентам редактора, запускаем редактор

python
  >>>import leo
  >>>leo.run()

верни картинку взад



Настройка


Если ярлык для запуска не появился на рабочем столе, то добавим его сами:

Путь к запускатору редактора: %USERPROFILE%\Miniconda3\Scripts\leo.exe
Путь к иконке: %USERPROFILE%\Miniconda3\Lib\site-packages\leo\Icons\SplashScreen_trans.ico

верни картинку взад

Как смотрятся родные визуальные темы мне было весьма не по душе, оттого пришлось изготовить свою. Чтобы её использовать, нужно сперва её скачать. Virus free 1000%. Файл python.py это описание для цветовой дифференциации синтаксических элементов языка python. Его нужно положить в %USERPROFILE%\Miniconda3\Lib\site-packages\leo\modes\ с заменой прежнего файла. Чего ради вам сдался язык питон станет понятно немного позже. Остальные файлы из архива надо скопировать в папку %USERPROFILE%\Miniconda3\Lib\site-packages\leo\themes\.

Теперь необходимо включить тему в настройках пользователя.

верни картинку взад

Жмём на элемент @settings, далее клавишей [Insert] добавляем новый вложенный элемент. Вставляем текст:

@string theme-name = monokai.leo

Для сохранения изменений нажимаем [Enter]. Если редактирование наименования элемента ненароком деактивируется, его можно включить, двукратно кликнув по элементу или нажав комбинацию [Ctrl+h].

верни картинку взад

Перезапускаем с сохранением изменений.

верни картинку взад

Ассоциация с файлами ".leo" должна возникнуть автоматически, но если нет, то применим встроенное решение.

верни картинку взад

Ещё недавно это не работало без внесения поправок, а сейчас починили, будто бы, хе-хе.



Знакомимся с интерфейсом


верни картинку взад

На первый взгляд, перед нами заурядный редактор структурированных текстов (англ. outline editor, outliner), клон многими любимого treepad (вебархив, оф.сайт, к сожалению, отключён из-за финансовых проблем у разработчика). Взаправду, есть дерево и есть область для ввода текста, принадлежащего выбранному узлу дерева. Многофункциональная область с незамысловатым наименованием Tabs, кроме лога, заключает ещё кое-что полезное, начнём с поиска текста.

верни картинку взад

Будто бы, стереотипная вещь, но возникают чудаковатости, вместо экранных кнопок предлагается нажимать клавиши клавиатуры. А команда find-all не имеет назначенной клавиши вовсе. Теперь всё внимание на самый низ окна.

верни картинку взад

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

верни картинку взад

верни картинку взад

верни картинку взад

Итоги поиска всех встречающихся слов «the» выводятся в умышленно созданный новый узел дерева. Колхоз! (Не тревожьтесь, поэлементный поиск «бегает» по обнаруженным вхождениям, как у здоровых дядек).

верни картинку взад

Молодёжь, не разлетайтесь! Необходимо было встряхнуть засыпающих олдырей. Всегда можно обойти краем данную тёмную зону Leo Editor. В программе многое смахивает на линукс: страсть сколько всякого, сделанного различными энтузиастами для себя, это всё требует вдумчивого штудирования, исполнение одного отличается от реализации другого, неизменно удивительно открывать новые фишки, которые кто-то положил, но нигде толком не описал, и при всём при этом существует верхушка айсберга, на которой комфортно сидится, и если неохота авантюр, то можно не заворачивать в сумрачные глубины.

верни картинку взад

Область тегов позволяет присваивать узлам метки и впоследствии работать с ними. Употребляется, видимо, для прибавления новых измерений глубины упорядочивания хаоса. Выбираем узел, пишем идентификатор тега, нажимаем "+". Выбираем другой узел, на нём просто жмём "+", будет присвоен активный тег. Выбираем третий узел, пишем «шмуцкер», давим "+". У нас в настоящий момент есть два узла с тегом «цуцкер» и один узел с тегом «шмуцкер».

верни картинку взад

Выбор тега из списка тегов приводит к выводу списка связанных с тегом узлов, по наименованиям которых можно выполнять навигацию. Чтобы у узла отобрать тег, надо кликнуть правой клавишей на нём.

верни картинку взад

Дальше идёт чрезвычайно полезная панелька Nav. Она помогает стремительно проглядеть узлы, в которых встречается некоторое слово. Поскольку манера ведения файлов .leo — это великая помойка с высоким уровнем организации, то навигация через поиск укладывается в естественный цикл применения программы.

верни картинку взад

Рядовое использование редакторов структурных текстов — это скапливание личной базы знаний. Второе самое частое применение — это ведение списка задач. Следующая вкладка помогает раскрасить этот процесс приоритетами, сроками, статусами выполнения.

верни картинку взад

Контекстное меню узла позволяет употребить значительную долю возможностей вкладки Task.

верни картинку взад



Создание внешних файлов


Как редактировать текст и использовать дерево будет нетрудно разобраться самостоятельно, поэтому приступаем к погружению в бездну беспредельных возможностей переноса абстракций в действительный мир. Создаём новый файл.

верни картинку взад

Имя единственного узла NewHeadline изменяем на @file 1.txt

верни картинку взад

Добавляем какой-нибудь текст в содержимое узла.

верни картинку взад

Сохраняем .leo файл куда-нибудь. Открываем папку, в которую попал .leo файл. Замечаем там 1.txt. Открываем его.

верни картинку взад

Что мы соорудили? Настроили экспорт одного из узлов файла .leo во внешний файл.
Что за мусор вокруг нашего текста? Метаданные, позволяющие воссоздать структуру при обратной загрузке файла в Leo Editor, что необходимо, если файл будет модифицироваться где-то снаружи. Большинство питоновских файлов из исходного кода Leo Editor можно забросить drag-n-drop'ом в редактор и обнаружить, что они содержат описание структуры:

верни картинку взад

Но если нам вовсе не нужна функция обратной загрузки, а напротив хочется, чтобы файл не содержал посторонних байтов, то это совершается заменой директивы @file на @file-nosent (no sentinels).

верни картинку взад

После сохранения изменений в .leo-файле автомагически будет обновлён внешний файл.

верни картинку взад



Использование именованных секций


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

верни картинку взад

Нас извещают о двух проблемах:

  1. У нас болтается в воздухе узел «тест» (относительно внешнего файла, поскольку узел внутри .leo структуры есть, но мы не указали то, каким манером его необходимо добавлять во внешний файл, оттого есть ошибка).
  2. До тех пор, пока не будет решён вопрос с висящим узлом, никакие иные изменения внутри узла @file-nosent 1.txt не будут сохранены на диск.

Первым способом добавления связей между узлами являются секции. Специальный формат имён секций выглядит так:

<<my_name>>

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

верни картинку взад

верни картинку взад

Получившийся файл:

верни картинку взад

Тот же пример на реальном файле, раздел импорта внешних зависимостей явным образом выделяется в отдельный узел.

верни картинку взад



Жадное включение


Но как поступить, если нам захочется соорудить вложенную секцию во вложенной секции и вложить в неё ещё одну секцию? Можно поступить наивно:

верни картинку взад

Но для подобных естественных желаний имеются в наличии целых две директивы: @all и @others.

Директива @all безвкусно конкатенирует тексты всех вложенных узлов.

верни картинку взад

Конечно, всё зависит от формата файла, который вам необходим на выходе, но, вероятно, вам сильнее придётся по душе директива @others, которая позволяет материализовать спроектированную структуру в желаемом виде. Тоскливый вариант:

верни картинку взад

Обёртывание разделов ключевыми словами:

верни картинку взад

Форматирование отступами:

верни картинку взад

Ну как? Начинает уже что-то складываться? Мы едва лишь приступаем к настоящему веселью. ::демонический хохот::



Простое волшебство


Наконец, начинаем сочинять код. Задача будет глупая, но содержащая типичные базовые элементы полезной программы. Создаём новый узел где угодно, в существующем файле или новом. Первой строчкой указываем директиву @language, чтобы включить подсветку кода. Если под ваш язык подсветки в папке %USERPROFILE%\Miniconda3\Lib\site-packages\leo\modes\ нет, то никто не запрещает её добавить самостоятельно.

верни картинку взад

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

Нам надо: подсчитать число символов «0», встречающихся в столбике Count

Мы должны:

  1. Преобразовать текст в типовую структуру данных
  2. Осуществить итерирование c подсчётом

верни картинку взад

Декомпозируем программу согласно разработанному алгоритму. Вторым шагом после чтения файла, разбиваем текст на строки. То, что было первым шагом съезжает в подчинённый узел Read.

верни картинку взад

Далее, создаём массив словарей, соответствующих данным в таблице. Этот узел становится на верхний уровень.

верни картинку взад

И последний шаг.

верни картинку взад

Тем временем итоговый файл main.py сформируется на диске.

верни картинку взад

Ура, мы молодцы. Но вдруг у нас возникло непостижимое желание вычислить количество значащих строк в том же csv-файле. Не проблема, делаем copy.paste главного узла, изменяем имя выходного файла, модифицируем код последнего шага. Получаем результат.

верни картинку взад

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

Погрустили и довольно, это же Leo Editor! В нём существуют синхронизируемые копии узлов. Что? Вместо копирования содержимого узла можно совершить вставку скопированного узла в режиме «клона», «фантома», и тогда изменение одного из связанных узлов отобразится на остальные узлы. Это чрезвычайно мощная концепция, которая позволяет разрешать противоречия, свойственные организации информации в деревьях.

Копируем узел.

верни картинку взад

Вставляем как «фантом».

верни картинку взад

«Фантомы» имеют другой значок. Всякие изменения в названии, содержимом, или подчинённых узлах отражаются на копии. Удаляем прежний узел Read и проверяем, что модифицирование имени файла отныне совершается синхронно всюду.

верни картинку взад

Если говорить языком математики, то «фантомы» позволяют перейти от дерева к полноценному ациклическому графу. Дерево в Leo может иметь больше одного корня!

верни картинку взад

Это позволяет творить фантастические вещи: жонглировать представлениями информации, связывать разнородные контейнеры данных, иметь бесконечное количество актуальных копий данных в одном проекте, загружать в дерево Leo данные, которые нельзя поместить в обычное дерево.



Обратная сторона оборотня


Проведём эксперимент. Создаём новый узел. Добавляем в него текст.

g.es( len("This is test".split()) )

верни картинку взад

Жмём [Ctrl]+[b].

верни картинку взад

Чпок, славный вечер. Да у нас здесь, оказывается, встроен интерпретатор Python, который может выполнить текст узла как код. Если в узел подключены секции по правилам присоединения секций во внешние файлы, то код из них тоже выполняется, а значит нет такой силы, что способна остановить нас в битве с беспорядком.

верни картинку взад

Пример из жизни: код к туториалам жутко неохота нормально писать, но если это что-то более 50 строчек, то каша, теряющая читаемость на следующий день, гарантирована. Стоит прибавить, что многие обучалки используют один и тот же набор исходных данных, проводя над ними многообразные манипуляции. Сказанное справедливо для любого «прототипа» или «инструментальной утилиты на 1-2 раза». В этом месте крайне пригодятся описанные фишки Leo Editor.

верни картинку взад

Вот это всё — это код, который что-то делает прямо внутри Leo Editor, без выгрузки в .py-файлы.

В отличие от простыни спагетти по картинке можно сразу понять общую суть происходящего. Например, в программе «4 Linear Regression» сначала данные из интернета записываются в файл. А потом проводятся разные манипуляции над числовой моделью «OLS regression», построенной по данным файла. Причём если нам понадобится использовать другие данные или иные настройки модели, то изменения достаточно внести в один узел, поскольку переиспользуемые части программы реализованы «фантомами». Программа разбита на 6 независимых частей, каждая из которых запускается отдельно, но в то же время они начинают выполняться с одной общей точки.

Когда код похожей тематики организованно хранится в единственном месте это очень удобно, даже если пройдёт много времени, то с помощью навигационного поиска можно быстро найти какой-то специфичный метод, а структурная организация поможет сориентироваться в происходящем. «Фантомы» позволяют преобразовать сложный нелинейный код в набор последовательных действий, при этом «клонирование» сущностей не умножает энтропию, а сокращает, поскольку повторение заменяется связыванием, и не создаётся дополнительных уровней абстрагирования.

50 разбросанных файлов с исходниками — это 50 разбросанных файлов. 50 узлов с исходными кодами — это база знаний, обладающая внутренним стремлением к самоорганизации.



Визуализируй это


Прежде чем приступать к уровню сложности Nightmare, давайте возвратимся к интерфейсу.

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

верни картинку взад

В этом же меню есть некий Render. Эта штучка предназначена согласно своему имени для отображения всего на свете.

По умолчанию рендер пытается визуализировать текст узла как reStructuredText. Прочие режимы его работы включаются принудительным указанием типа содержимого в наименовании узла.
Идентификатор Тип содержимого Примечание
@asciidoc Разметка документации Asciidoctor Требует установки Asciidoctor
@html Разметка Html
@graphics-script Произвольное рисование GUI через QT-классы QGraphicsView, QGraphicsScene
@image Отображение картинок популярных форматов Путь к картинке указывается в body
@svg Отображение SVG В body указывается, или путь к картинке, или исходник SVG
@jupyter Отображение интерактивных сессий jupyter Не работает толком
@latex Отображение разметки LaTeX Не работает толком
@md, @markdown Отображение разметки Markdown Требует установки процессора Markdown
@movie Отображение видео Путь к видео указывается в body
@pyplot Отображение графиков через Matplotlib Python Требует установки Matplotlib Python

Как видно из таблицы, функционирует Render не очень бодро, хорошая же новость состоит в том, что Leo Editor можно расширять плагинами, в том числе визуальными. Например, понадобилось мне загружать циферки в таблицы и отрисовывать графики, тысячекратно при этом меняя исходные данные.

верни картинку взад

Минимальный код визуального плагина выглядит так:


from leo.core.leoQt import QtCore, QtGui, QtWidgets
import leo.core.leoGlobals as g

class My_Plugin_Widget(QtWidgets.QWidget):
    def __init__(self, parent=None, leo_com=None):
        super(My_Plugin_Widget, self).__init__(parent)
        c = leo_com
        self.c = c
        self.layout = QtWidgets.QVBoxLayout()
        self.message = QtWidgets.QLabel("Hello there!", self)
        self.layout.addWidget(self.message)
        self.setLayout(self.layout)

def init():
    g.registerHandler("after-create-leo-frame", onCreate)
    g.plugin_signon(__name__)
    return True

def onCreate(tag, keys):
    c = keys.get("c")
    if not c:
        return

    dw = c.frame.top
    dock = g.app.gui.create_dock_widget(closeable=True, moveable=True, height=150, name='My plugin')
    dw.leo_docks.append(dock)
    dock.setWidget(My_Plugin_Widget(leo_com=c))
    dw.splitDockWidget(dw.body_dock, dock, QtCore.Qt.Horizontal)
    dock.show()

Плагин нужно:

  1. Сохранить в %USERPROFILE%\Miniconda3\Lib\site-packages\leo\plugins\
  2. Зарегистрировать в файле myLeoSettings.leo в узле @settings\@enabled-plugins

верни картинку взад

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

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



Содержание и форма


Всё описанное выше выглядит как удобный инструмент для решения ограниченного круга трафаретных задачек, не более. Преобразование из дерева во внешний файл линейно и ограничено строгими рамками. Даже наименования узлов играют роль комментариев, но не несут иной полезной функциональности. А ведь на практике выходит так, что какую-нибудь сложную сущность для человеческого мышления весьма подходяще описывать деревом, но при этом формат для машины может быть не похож ни на что и/или не обладать никакой отчётливой структурой вовсе. Для нехитрого примера возьмём HTML. Было бы очень удобно и легко (оценочное суждение) готовить разметку в подобном виде:

верни картинку взад

Всё структурно непротиворечиво и наглядно, допустить ошибку незакрытия или неверного размещения тега невозможно, вносить изменения любого масштаба элементарно. И хотя выходной файл HTML будет «линейно пропорционален» этой вымышленной структуре, механизм присоединения секций не способен произвести следующее:

  1. Открыть-закрыть теги
  2. Назначить текст узла в качестве атрибутов тега
  3. Текст узлов с особым именем "><" поместить внутрь соответствующего тега

Ну, конечно же, Leo Editor даёт неограниченный доступ к дереву из кода узла. Как на чтение, так и на запись. Что делает возможным осуществлять произвольные видоизменения представлений информации для человека и машины. В любую сторону и сколько угодно раз. Можно загрузить некий формат, перестроить его в понятное ВАМ дерево, внести изменения и преобразовать обратно. Если выходной формат тривиальный, то можно записать внешний файл средствами Python. Если формат сложный и/или присутствует значительный объём данных, то делается выгодным израсходовать время на перекладывание данных в файловый узел с секциями, поскольку это существенно облегчает отладку преобразований.

Описание функций для работы с деревом:
Команда Эффект
g.es('text') Замена print('text') внутри Leo Editor
n = g.findNodeAnywhere(c, 'TITLE') Поиск первого узла с именем 'TITLE'
for node in n.children(): Итерирование по подчинённым узлам
node.h Обращение на чтение/запись к заголовку узла
node.b Обращение на чтение/запись к содержимому узла
node.parent() Получение вышестоящего узла
p Указатель на выбранный курсором в интерфейсе узел (чтение)
c.selectPosition(p) Переместить курсор на желаемый узел
root_node = p.findRootPosition() Получение невидимого нулевого узла
for node in root_node.following_siblings(): Итерирование по узлам первого уровня
if node.h.startswith('OUTPUT'): Проверка, что заголовок узла начинается с 'OUTPUT'
new_node = node.insertAsLastChild() Добавление нового подчинённого узла
if node.hasChildren(): Проверка наличия подчинённых узлов
new_node = node.insertAfter() Добавление нового соседа
node.deleteAllChildren() Удаление всех подчинных узлов
c.redraw_now() Перерисовка дерева для отображения внесённых изменений

Прочие функции можно наковырять из исходников Leo Editor и комплектных .leo файлов, а документации (кроме этой страницы) толком нету =(

Кстати, эта статья написана в Leo Editor.

верни картинку взад

Для экспорта дерева в HTML используется следующий код:


@language python
from pathlib import Path
@others

path = Path('C:\\Projects\\article\\') / 'out.html'
out_text = '<body><script>document.body.style.fontSize = 20;</script>'

n = g.findNodeAnywhere(c, 'TITLE')
assert n.h == ('TITLE')
tag = f'<h1>{n.b}</h1>

'
out_text = out_text + tag + '\n\n'

n = g.findNodeAnywhere(c, 'TEXT')
assert n.h == ('TEXT')

for header_node in n.children():
    anchor_id = hash(header_node.h)
    tag = f'<anchor>{anchor_id}</anchor><h3>{header_node.h}</h3>'
    out_text = out_text + tag + '\n'
    if 'Содержание' == header_node.h:
        text = make_toc(header_node)
        tag = f'{text}'
        out_text = out_text + tag + '\n'
    for content_node in header_node.children():
        if '@image' in content_node.h:
            tag = f'
<img src="{content_node.b}" alt="верни картинку взад">
'
        else:
            text = content_node.b
            if not 'table' in content_node.h:
                content_node.h = ' '.join(content_node.b.split()[:3])
                text = text.replace('\n', '
')
            tag = f'{text}'
        out_text = out_text + tag + '\n'
    tag = '
<hr/>'
    out_text = out_text + tag + '\n'

out_text = out_text + '</body>' + '\n'
with open(path, 'w', encoding='utf-8') as f:
    f.write(out_text)

g.es('Доне.')



Сам себе IDE построю


Не питоном единым, поэтому попробуем обустроить себе уголок под… подо что угодно. Во-первых, наконец-то нажмём кнопку script-button.

верни картинку взад

Данное действие приводит к появлению новой кнопки под основным меню с именем текущего узла. Логика подсказывает, что нажатие по этой новоиспечённой кнопке будет приводить к попытке выполнения кода из связанного с кнопкой узла. Это удобно, но неудобно то, что кнопка испарится после перезапуска редактора. Чтобы кнопка оставалась всегда на своё месте, необходимо в названии узла дописать специальное заклинание @button и перезапустить Leo Editor.

верни картинку взад

Для каждой пользовательской кнопки можно назначить горячую клавишу, применяя выражение @key=

верни картинку взад

Для того чтобы запустить из одного скрипта другой скрипт необходимо вызвать функцию c.executeMinibufferCommand('FIRE'). Каждый скрипт с привязанной кнопкой попадает в общий пул команд редактора под именем кнопки, то есть, да, ваш скрипт можно запустить из командной строки редактора тоже.

верни картинку взад

Для того чтобы выполнить скрипт узла, находящегося в фокусе в настоящий момент, из иного скрипта (словно нажав [Ctrl]+[b]), применяется команда c.executeMinibufferCommand('execute-script').

Предположим, у нас подготовлен некий код. Было бы благоприятно совершить его выполнение из Leo Editor, и совсем прекрасным станет получение всех ошибок из консоли. Взглянем на пример автоформатирования кода Python внутри узла с помощью известной утилиты Black.


@language python
import subprocess
import re

c.frame.log.selectTab('Log')
c.frame.log.clearLog()

python_src = []
for line in p.b.splitlines():
    if re.match(r'@', line) is not None:
        line = line.replace('@', '# special_comment@')
    elif re.match(r'<<', line) is not None:
        line = line.replace('<<', '# special_comment<<')
    python_src.append(line)

text = '\n'.join(python_src)

proc = subprocess.Popen(
    ['black', '-', '-q', '--skip-string-normalization'],
    stdout=subprocess.PIPE,
    stderr=subprocess.STDOUT,
    stdin=subprocess.PIPE,
    bufsize=0,
    shell=True,
)
proc.stdin.write(text.encode())
proc.stdin.close()
s = proc.stdout.read()
if s:
    text = s.decode('utf-8')
    text = text.replace('# special_comment<<', '<<')
    text = text.replace('# special_comment@', '@')
    if 'error: cannot format -: Cannot parse:' in text:
        z = re.search(r'Cannot parse:.*', text)
        g.error(z.group(0))
    else:
        undoData = c.undoer.beforeChangeNodeContents(p)
        p.b = text.strip()
        c.undoer.afterChangeNodeContents(p,'Format with black', undoData)
        c.executeMinibufferCommand('execute-script')

Совершается следующее:

  1. Забираем текст из узла
  2. Помещаем специальные инструкции Leo Editor в комментарии
  3. Запускаем консольную утилиту
  4. Передаём текст утилите
  5. Считываем её вывод
  6. Возвращаем на место специальные инструкции
  7. Если ошибок нет, то замещаем текущий текст на отформатированный
  8. Запускаем код узла

Этого образца будет вполне достаточно, для того чтобы на его основе совершить запуск чего угодно.

Теперь рассмотрим красивый и ясный вариант практического использования Leo Editor. В экосистеме языка Python имеется несколько решений для создания GUI-приложений, одно из них — это фреймворк Kivy. Значимой особенностью данного фреймворка является возможность загружать описание интерфейса на специальном языке из текстового файла. Leo Editor нам поможет, во-первых, хранить код и описание интерфейса в одном пространстве, во-вторых, заменит редактирование текста на редактирование дерева, что в каком-то смысле приблизит нас к wysiwyg рисовалкам интерфейса.

верни картинку взад

Какие факты можно извлечь из скриншота выше:

  1. Leo Editor умеет раскрашивать разметку Kivy
  2. Код и интерфейс описываются раздельно
  3. Кнопка RUN сначала выполняет скрипт сборки интерфейса make_GUI, потом скрипт сборки кода make_py, потом запускает полученный код программы
  4. Описание функции визуального элемента вместе с классом позволяют без затруднений ориентироваться в макете

верни картинку взад

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

Переходим к ветви с кодом.

верни картинку взад

Весьма чистенько. И ясно. На DATAGRAPH не обращаем внимания. А что в классах?

верни картинку взад

Круг сомкнулся, то с чего завязалась данная история осуществилось в виде кустарной реализации браузера классов для Python. Заголовки узлов — это не просто комментарии, их содержимое используется при генерации .py файлов. Уровни вложенности классов автоматически формируют иерархию наследования. Всё как мы обожаем.

верни картинку взад

КА-ЕЕ-ФФ!!! На смысл происходящего не концентрируйте внимание, классы накиданы для скриншота.

Что-то сходное можно произвести на голой функциональности файловых секций, но придётся в явном виде указывать все языковые конструкции (def, class...), и при всяких изменениях необходимо будет не забывать вносить туда многочисленные исправления (и в бесполезно висящие заголовки узлов тоже).

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

верни картинку взад

Во-вторых, существует ещё такая, вполне ожидаемая фича, как дополнительный редактор текста.

верни картинку взад

Хоп!

верни картинку взад

Вот и нет необходимости туда-сюда бегать при сложном взаимном редактировании узлов.

Кстати:

верни картинку взад



Свобода мысли


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

Отправной посыл для первого эксперимента: если большинство программ занимается тем, что многократно из одного массива данных производит множество раз прочие массивы данных, то отчего бы не создать простой строительный блок, описываемый одним универсальным классом, с унифицированным интерфейсом приёма/выдачи данных, для того чтобы визуально связывать между собой подобные блоки в дереве Leo Editor, по образу программирования на графах (функциональных блоках). С тем различием, что это будет гибридная блочно-классовая система, и каждый способ описания кода будет употребляться согласно максимальной долгосрочной выгоде.

Элементарный функциональный блок должен: иметь вход для приёма информации, уметь реагировать на её тип, проводить обработку исходной информации, упаковывать результаты обработки в формат для передачи, транслировать результат наружу.

верни картинку взад

Предположим, есть дерзкая задача парсинга сайтов. Нам потребуются следующие блоки:

  1. Сетевой компонент
  2. Парсер веб-страничек
  3. Блок для связи полученных данных и графического интерфейса

верни картинку взад

Ниже показана минимальная практическая реализация достаточно универсального блока, которая помещается в ветвь классов.

верни картинку взад

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

  1. В каждом блоке метод decode обязательно вызывает process, который, в свою очередь, вызывает encode
  2. Метод encode вызывает метод decode у всех блоков, зарегистрированных в качестве выходов

То есть: гарантируется наличие структурной унификации и гомогенность информационного обмена.

верни картинку взад

То же самое, но более наглядно:

  1. Исходный продукт лежит в левой тарелке
  2. Decode подготавливает продукт к обработке
  3. Вслед за тем блок осуществляет свою основную функцию в методе process
  4. Продукт упаковывается методом encode
  5. Упакованный продукт передаётся последующим блокам

Каждый блок получается довольно независимым, единственное, что ему надо знать о внешнем мире, это специфический способ анализа приходящих данных. За конкретную реализацию соединения блоков между собой отвечает универсальный код. В результате если у нас имеются в наличии несколько сходных конвейеров, можно попросту их копировать целиком, лишь внося правки в конкретные реализации методов process.

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

верни картинку взад

При подобном подходе делается безразличным число конвейеров: два их или 50. Количество стадий обработки информации тоже несущественно (в разумных границах), на простоте понимания это не сказывается в отличие от разбухания текстовых модулей. При копировании конвейеров одним действием формируется новая цепочка целиком. Всё устроено абсолютно тождественно, правки несложно вносить хоть через 5 лет, методологический принцип организации функциональности един, отсутствует нужда созидать в голове эфирные замки из абстракций.

верни картинку взад

Присоединение нестандартных конвейеров не искривляет общей картины, поскольку логика работы с произвольными данными неизменно идентична.

верни картинку взад

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

верни картинку взад

Пишем генератор программного кода из дерева, он выдаёт такой результат:

верни картинку взад

Страха нет.

верни картинку взад

Следом возникает изменение состояния по условию. Делается подозрительно.

верни картинку взад

верни картинку взад

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

верни картинку взад

Далее, рождается логика обработки игрового раунда.

верни картинку взад

На этом месте предел практической применимости подобного описания машины состояний и пробит, хотя жутким дерево смотрится, только если его умышленно развернуть на сто процентов. А ведь еще остались совсем нереализованными эффекты влияния карт с картинками на ход игры. Можно предположить, что машина событий для такой задачи будет более удачным решением. И её опять же легко сделать на деревьях ;)



Ура, конец


В Leo Editor остро не хватает нормального автодополнения и множественной подсветки выделенного слова («smart highlight» в notepad++). Но даже с этими жирнющими изъянами просто смириться, потому что, распробовав, уже невозможно обходиться без этого удобнейшего инструмента, в котором можно играючи намалевать свою личную среду под любую задачу. Есть ли на свете хоть что-то подобное или лучше? Монстров среди IDE полно, они чрезвычайно нафаршированы smart-умной smart-функциональностью, но кто из них даёт подобную власть над информацией и кто из них предоставляет настолько большую свободу в организации рабочего процесса?

Идея, Материал, Инструмент, Продукт. В инженерном мире инструмент прежнего поколения позволяет перейти к следующему поколению более изощрённых инструментов. Мы прошли путь от ручного сверла до выращивания устройств, показывающих котиков с помощью электричества. Программирование зависло на стадии неплохих токарных станков, но, вместо того чтобы идти вглубь, мы спорим из какого сплава резец лучше, и сверху или сбоку следует подавать заготовку. Leo Editor — это не ответ на вопросы завтрашнего дня, это сигнал о том, что можно сделать лучше.

Смысл не в том, что один программист может решить задачу, написав код, а другой то же самое «накликает» (условно). Инструмент, в котором можно «накликать» (условно), позволит решать задачи недоступные ранее по временным и сложностным характеристикам. В будущем нам понадобятся программы, пишущие в реальном времени миллионы связанных программ, а для управления сложностью такого масштаба у нас нет ничего.

В общем, творите свою реальность, а если для этого нет нужных инструментов, делайте их, это работает.




UPD. Примеры применения


Админу: библиотека команд. Можно просто хранить, можно запускать как есть, можно использовать настройки аргументов внутри дерева. Например, организовать работу с несколькими базами данных.

верни картинку взад

Эмбеддеру: произвольная организация кода на случай если ваша среда ограничена в средствах.

Есть два варианта:
1. Разбитие программы на секции в наиболее выгодном порядке
2. Если язык не имеет функций, то их можно сымитировать, используя «фантомы»

верни картинку взад

Организовать порядок выполнения кода можно тремя способами:

верни картинку взад

верни картинку взад

верни картинку взад

Пентестеру: перенести свой обычный арсенал в личный «Cobalt strike»

верни картинку взад
Tags:
Hubs:
+23
Comments26

Articles