Да!
Дайте мне рычаг, точку опоры, место для ног и армированный скотч
Даже попытавшись, нельзя лаконично обрисовать, насколько бездонная кроличья нора вас поджидает. Здесь один из тех редкостных случаев, когда, чтобы осознать, о чём будет идти речь, надо выслушать речь до самого финала. Изучив по шагам настоящее руководство, каждый обнаружит для себя что-то своё: эзотерический «текстовый» редактор Leo Editor всей своей сутью призывает применить его самым изумительным образом.
Словарь терминов
Слово | Значение |
---|---|
Быдлокод | Прототип |
Проектирование | Избегание подвигов |
Тестирование | Растрата ресурсов |
Документирование | Имитация работы |
Содержание
1. Да!.....................................1
2. Словарь терминов........................2
3. Содержание..............................2
4. Пролог..................................2
5. Установка Leo Editor....................2
6. Важное примечание!......................3
7. Завершаем установку редактора...........4
8. Настройка...............................4
9. Знакомимся с интерфейсом................7
10. Создание внешних файлов.................14
11. Использование именованных секций........18
12. Жадное включение........................21
13. Простое волшебство......................24
14. Обратная сторона оборотня...............30
15. Визуализируй это........................33
16. Содержание и форма......................36
17. Сам себе IDE построю....................39
18. Свобода мысли...........................49
19. Ура, конец..............................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
На месте.
Важное примечание!
Верное употребление conda — это явственное сотворение отдельных рабочих зон под задачи. Например:
conda create -n my_environment_for_py_37 python=3.7
Данная команда создаёт исчерпывающую имитацию отдельной установки выбранной версии интерпретатора python, которая именуется терминами «среда» или «виртуальная среда». При активировании одной из этих пользовательских сред, установка сторонних модулей и выполнение программ осуществляется лишь в рамках текущей среды.
conda env list
Таким образом мы выясняем полный список созданных пользователем сред.
conda activate my_environment_for_py_37
А вот так мы переключаем активную среду, при этом в командной строке показывается её наименование.
Если установить какой-нибудь модуль, например, так:
conda install pytorch==1.0.1 torchvision==0.2.2 cudatoolkit=10.0 -c pytorch
То pytorch будет доступен, только если руками была предварительно активирована среда my_environment_for_py_37.
Если мы доустанавливаемся до того, что всё перепутается и перестанет работать, то к чёрту всё:
conda env remove -n my_environment_for_py_37
Удаляем испорченное окружение, при этом остальные окружения продолжают работать. Теперь можно создавать окружение заново и продолжать с чистого листа.
К чему всё это было? К тому, что для редактора очень общего назначения будет неразумно создавать отдельное окружение, поэтому мы его поставим прямо в базовое окружение. Активирование пользовательской среды происходит только в рамках текущей сессии командной строки, вне этой командной строки продолжает работать базовое окружение. Не запускаем командную строку: работает базовое окружение, запустили командную строку: внутри работает базовое окружение, выбрали в командной строке окружение: перешли в это окружение, в других сессиях командной строки и системе в целом при этом работает базовое окружение python. Переключать среду перед запуском редактора сильно неудобно по массе причин. Тогда зачем мы ставили miniconda, если не будем пользоваться средами? Для экономии времени.
Да, на сайте редактора Leo Editor есть в наличии готовый win-инсталлятор, но будет весьма опрометчиво ступать по этой немудрёной тропинке, ведущей к букету вопросов. От души не рекомендую.
Завершаем установку редактора
Если вы озорничали командами выше, то нужно возвратиться в базовое окружение.
conda deactivate
Взглянем, какие версии редактора доступны для установки:
pip install leo==
Отдаём предпочтение последней версии без литер в номере:
pip install leo==6.1
После окончания скачивания, распаковки и установки, испытываем нашу удачу: запускаем интерпретатор python, подсоединяемся к компонентам редактора, запускаем редактор
python
>>>import leo
>>>leo.run()
Настройка
Если ярлык для запуска не появился на рабочем столе, то добавим его сами:
Путь к запускатору редактора: %USERPROFILE%Miniconda3Scriptsleo.exe
Путь к иконке: %USERPROFILE%Miniconda3Libsite-packagesleoIconsSplashScreen_trans.ico
Как смотрятся родные визуальные темы мне было весьма не по душе, оттого пришлось изготовить свою. Чтобы её использовать, нужно сперва её скачать. Virus free 1000%. Файл python.py это описание для цветовой дифференциации синтаксических элементов языка python. Его нужно положить в %USERPROFILE%Miniconda3Libsite-packagesleomodes с заменой прежнего файла. Чего ради вам сдался язык питон станет понятно немного позже. Остальные файлы из архива надо скопировать в папку %USERPROFILE%Miniconda3Libsite-packagesleothemes.
Теперь необходимо включить тему в настройках пользователя.
Жмём на элемент @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-файле автомагически будет обновлён внешний файл.
Использование именованных секций
Всякий узел является отдельной самостоятельной сущностью, которая по умолчанию не располагает сведениями о своих соседях. Если мы попробуем добавить новую структуру в узел, привязанный к внешнему файлу, и нажмём сохранить, то случится ошибка.
Нас извещают о двух проблемах:
- У нас болтается в воздухе узел «тест» (относительно внешнего файла, поскольку узел внутри .leo структуры есть, но мы не указали то, каким манером его необходимо добавлять во внешний файл, оттого есть ошибка).
- До тех пор, пока не будет решён вопрос с висящим узлом, никакие иные изменения внутри узла
@file-nosent 1.txt
не будут сохранены на диск.
Первым способом добавления связей между узлами являются секции. Специальный формат имён секций выглядит так:
<<my_name>>
Это позволяет провозгласить вложенный узел именованной секцией, это же самое имя необходимо указать в том месте наружного узла, в которое следует поместить содержимое подчинённого узла.
Получившийся файл:
Тот же пример на реальном файле, раздел импорта внешних зависимостей явным образом выделяется в отдельный узел.
Жадное включение
Но как поступить, если нам захочется соорудить вложенную секцию во вложенной секции и вложить в неё ещё одну секцию? Можно поступить наивно:
Но для подобных естественных желаний имеются в наличии целых две директивы: @all
и @others
.
Директива @all
безвкусно конкатенирует тексты всех вложенных узлов.
Конечно, всё зависит от формата файла, который вам необходим на выходе, но, вероятно, вам сильнее придётся по душе директива @others
, которая позволяет материализовать спроектированную структуру в желаемом виде. Тоскливый вариант:
Обёртывание разделов ключевыми словами:
Форматирование отступами:
Ну как? Начинает уже что-то складываться? Мы едва лишь приступаем к настоящему веселью. ::демонический хохот::
Простое волшебство
Наконец, начинаем сочинять код. Задача будет глупая, но содержащая типичные базовые элементы полезной программы. Создаём новый узел где угодно, в существующем файле или новом. Первой строчкой указываем директиву @language
, чтобы включить подсветку кода. Если под ваш язык подсветки в папке %USERPROFILE%Miniconda3Libsite-packagesleomodes нет, то никто не запрещает её добавить самостоятельно.
Предположим, информация, которую мы будем обрабатывать хранится табличкой в csv-файле.
Нам надо: подсчитать число символов «0», встречающихся в столбике Count
Мы должны:
- Преобразовать текст в типовую структуру данных
- Осуществить итерирование c подсчётом
Декомпозируем программу согласно разработанному алгоритму. Вторым шагом после чтения файла, разбиваем текст на строки. То, что было первым шагом съезжает в подчинённый узел Read.
Далее, создаём массив словарей, соответствующих данным в таблице. Этот узел становится на верхний уровень.
И последний шаг.
Тем временем итоговый файл main.py сформируется на диске.
Ура, мы молодцы. Но вдруг у нас возникло непостижимое желание вычислить количество значащих строк в том же csv-файле. Не проблема, делаем copy.paste главного узла, изменяем имя выходного файла, модифицируем код последнего шага. Получаем результат.
И тут наша радость сменяется печалью, потому что название CSV-файла может стать другим, а значит, если мы откорректируем его в одной программе, то во второй точно выпустим это из виду и тем самым обесценим радость от переиспользования кода.
Погрустили и довольно, это же Leo Editor! В нём существуют синхронизируемые копии узлов. Что? Вместо копирования содержимого узла можно совершить вставку скопированного узла в режиме «клона», «фантома», и тогда изменение одного из связанных узлов отобразится на остальные узлы. Это чрезвычайно мощная концепция, которая позволяет разрешать противоречия, свойственные организации информации в деревьях.
Копируем узел.
Вставляем как «фантом».
«Фантомы» имеют другой значок. Всякие изменения в названии, содержимом, или подчинённых узлах отражаются на копии. Удаляем прежний узел Read и проверяем, что модифицирование имени файла отныне совершается синхронно всюду.
Обратная сторона оборотня
Проведём эксперимент. Создаём новый узел. Добавляем в него текст.
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()
Плагин нужно:
- Сохранить в
%USERPROFILE%Miniconda3Libsite-packagesleoplugins
- Зарегистрировать в файле myLeoSettings.leo в узле
@settings@enabled-plugins
Прочесть про то, как делать плагины можно здесь, если приспичит получить побольше информации, то один-единственный путь — это самостоятельно штудировать плагин viewrendered.py.
К чему это всё? Снова же к безграничным возможностям. Полный доступ к QT позволяет как воспроизводить информацию произвольным образом, так и вводить её самым неожиданным способом.
Содержание и форма
Всё описанное выше выглядит как удобный инструмент для решения ограниченного круга трафаретных задачек, не более. Преобразование из дерева во внешний файл линейно и ограничено строгими рамками. Даже наименования узлов играют роль комментариев, но не несут иной полезной функциональности. А ведь на практике выходит так, что какую-нибудь сложную сущность для человеческого
Всё структурно непротиворечиво и наглядно, допустить ошибку незакрытия или неверного размещения тега невозможно, вносить изменения любого масштаба элементарно. И хотя выходной файл HTML будет «линейно пропорционален» этой вымышленной структуре, механизм присоединения секций не способен произвести следующее:
- Открыть-закрыть теги
- Назначить текст узла в качестве атрибутов тега
- Текст узлов с особым именем "><" поместить внутрь соответствующего тега
Ну, конечно же, 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 |
Указатель на выбранный курсором в интерфейсе узел (чтение/запись) |
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 + 'nn'
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')
Совершается следующее:
- Забираем текст из узла
- Помещаем специальные инструкции Leo Editor в комментарии
- Запускаем консольную утилиту
- Передаём текст утилите
- Считываем её вывод
- Возвращаем на место специальные инструкции
- Если ошибок нет, то замещаем текущий текст на отформатированный
- Запускаем код узла
Этого образца будет вполне достаточно, для того чтобы на его основе совершить запуск чего угодно.
Теперь рассмотрим красивый и ясный вариант практического использования Leo Editor. В экосистеме языка Python имеется несколько решений для создания GUI-приложений, одно из них — это фреймворк Kivy. Значимой особенностью данного фреймворка является возможность загружать описание интерфейса на специальном языке из текстового файла. Leo Editor нам поможет, во-первых, хранить код и описание интерфейса в одном пространстве, во-вторых, заменит редактирование текста на редактирование дерева, что в каком-то смысле приблизит нас к wysiwyg рисовалкам интерфейса.
Какие факты можно извлечь из скриншота выше:
- Leo Editor умеет раскрашивать разметку Kivy
- Код и интерфейс описываются раздельно
- Кнопка RUN сначала выполняет скрипт сборки интерфейса make_GUI, потом скрипт сборки кода make_py, потом запускает полученный код программы
- Описание функции визуального элемента вместе с классом позволяют без затруднений ориентироваться в макете
Выше можно взглянуть на то, как выглядит описание интерфейса в собранном виде. Возможно, это вкусовщина, но более управляемым и промышленным решением представляется колхоз слева. Правый вариант так и просит наделать в нём опечаток пятничным вечерком.
Переходим к ветви с кодом.
Весьма чистенько. И ясно. На DATAGRAPH не обращаем внимания. А что в классах?
Круг сомкнулся, то с чего завязалась данная история осуществилось в виде кустарной реализации браузера классов для Python. Заголовки узлов — это не просто комментарии, их содержимое используется при генерации .py файлов. Уровни вложенности классов автоматически формируют иерархию наследования. Всё как мы обожаем.
КА-ЕЕ-ФФ!!! На смысл происходящего не концентрируйте внимание, классы накиданы для скриншота.
Что-то сходное можно произвести на голой функциональности файловых секций, но придётся в явном виде указывать все языковые конструкции (def, class...), и при всяких изменениях необходимо будет не забывать вносить туда многочисленные исправления (и в бесполезно висящие заголовки узлов тоже).
И опять-таки про единое пространство кода и интерфейса. Во-первых, вспоминаем про навигационный поиск, позволяющий проворно разыскивать обработчики кода для визуальных элементов и визуальные элементы из кода.
Во-вторых, существует ещё такая, вполне ожидаемая фича, как дополнительный редактор текста.
Хоп!
Вот и нет необходимости туда-сюда бегать при сложном взаимном редактировании узлов.
Кстати:
Свобода мысли
Под конец будет чуточку противоестественного. Всё описываемое ниже не стоит воспринимать как демонстрацию хороших инженерных практик, это всего-навсего затравка для кристаллизации ваших личных идей.
Отправной посыл для первого эксперимента: если большинство программ занимается тем, что многократно из одного массива данных производит множество раз прочие массивы данных, то отчего бы не создать простой строительный блок, описываемый одним универсальным классом, с унифицированным интерфейсом приёма/выдачи данных, для того чтобы визуально связывать между собой подобные блоки в дереве Leo Editor, по образу программирования на графах (функциональных блоках). С тем различием, что это будет гибридная блочно-классовая система, и каждый способ описания кода будет употребляться согласно максимальной долгосрочной выгоде.
Элементарный функциональный блок должен: иметь вход для приёма информации, уметь реагировать на её тип, проводить обработку исходной информации, упаковывать результаты обработки в формат для передачи, транслировать результат наружу.
Предположим, есть дерзкая задача парсинга сайтов. Нам потребуются следующие блоки:
- Сетевой компонент
- Парсер веб-страничек
- Блок для связи полученных данных и графического интерфейса
Ниже показана минимальная практическая реализация достаточно универсального блока, которая помещается в ветвь классов.
Само собой, всякий конкретный блок может перезагружать типовые методы своими, если неукоснительно соблюдаются два правила:
- В каждом блоке метод decode обязательно вызывает process, который, в свою очередь, вызывает encode
- Метод encode вызывает метод decode у всех блоков, зарегистрированных в качестве выходов
То есть: гарантируется наличие структурной унификации и гомогенность информационного обмена.
То же самое, но более наглядно:
- Исходный продукт лежит в левой тарелке
- Decode подготавливает продукт к обработке
- Вслед за тем блок осуществляет свою основную функцию в методе process
- Продукт упаковывается методом encode
- Упакованный продукт передаётся последующим блокам
Каждый блок получается довольно независимым, единственное, что ему надо знать о внешнем мире, это специфический способ анализа приходящих данных. За конкретную реализацию соединения блоков между собой отвечает универсальный код. В результате если у нас имеются в наличии несколько сходных конвейеров, можно попросту их копировать целиком, лишь внося правки в конкретные реализации методов process.
На следующей картинке можно наблюдать что-то крайне похожее на описанную в предшествующем разделе работу с классами. Разница состоит в том, что вложенность узлов устанавливает не отношение родитель-наследник, а связь вход-выход соответствующих блоков. Для организации обмена данными с несмежными блоками применяется костыль в виде явного объявления выходов, что оправдано малочисленностью подобных случаев.
При подобном подходе делается безразличным число конвейеров: два их или 50. Количество стадий обработки информации тоже несущественно (в разумных границах), на простоте понимания это не сказывается в отличие от разбухания текстовых модулей. При копировании конвейеров одним действием формируется новая цепочка целиком. Всё устроено абсолютно тождественно, правки несложно вносить хоть через 5 лет, методологический принцип организации функциональности един, отсутствует нужда созидать в голове эфирные замки из абстракций.
Присоединение нестандартных конвейеров не искривляет общей картины, поскольку логика работы с произвольными данными неизменно идентична.
Вторая абсурдная история. Потребовалось мне сделать игру Kvent (прямой аналог широко известной игры внутри ещё более широко известной игры, для игры в которую используются стандартные игральные карты). Существует немало различных подходов к организации игрового цикла, один из наивных вариантов — это машина состояний. С машиной состояний всё ладно и просто в теории, на практике поддерживать больше 7 состояний в сколько-нибудь настоящей программе постепенно становится уныло без добавления пары слоёв абстракций. В этом месте-то мне и подумалось, что визуальное ведение машины состояний в виде дерева — это занятный вариант.
Пишем генератор программного кода из дерева, он выдаёт такой результат:
Страха нет.
Следом возникает изменение состояния по условию. Делается подозрительно.
Это была всего лишь раздача карт с заменой пары произвольных. Ok, разделяем единую машину на несколько подмашин.
Далее, рождается логика обработки игрового раунда.
На этом месте предел практической применимости подобного описания машины состояний и пробит, хотя жутким дерево смотрится, только если его умышленно развернуть на сто процентов. А ведь еще остались совсем нереализованными эффекты влияния карт с картинками на ход игры. Можно предположить, что машина событий для такой задачи будет более удачным решением. И её опять же легко сделать на деревьях ;)
Ура, конец
В Leo Editor остро не хватает нормального автодополнения и множественной подсветки выделенного слова («smart highlight» в notepad++). Но даже с этими жирнющими изъянами просто смириться, потому что, распробовав, уже невозможно обходиться без этого удобнейшего инструмента, в котором можно играючи намалевать свою личную среду под любую задачу. Есть ли на свете хоть что-то подобное или лучше? Монстров среди IDE полно, они чрезвычайно нафаршированы smart-умной smart-функциональностью, но кто из них даёт подобную власть над информацией и кто из них предоставляет настолько большую свободу в организации рабочего процесса?
Идея, Материал, Инструмент, Продукт. В инженерном мире инструмент прежнего поколения позволяет перейти к следующему поколению более изощрённых инструментов. Мы прошли путь от ручного сверла до выращивания устройств, показывающих котиков с помощью электричества. Программирование зависло на стадии неплохих токарных станков, но, вместо того чтобы идти вглубь, мы спорим из какого сплава резец лучше, и сверху или сбоку следует подавать заготовку. Leo Editor — это не ответ на вопросы завтрашнего дня, это сигнал о том, что можно сделать лучше.
Смысл не в том, что один программист может решить задачу, написав код, а другой то же самое «накликает» (условно). Инструмент, в котором можно «накликать» (условно), позволит решать задачи недоступные ранее по временным и сложностным характеристикам. В будущем нам понадобятся программы, пишущие в реальном времени миллионы связанных программ, а для управления сложностью такого масштаба у нас нет ничего.
В общем, творите свою реальность, а если для этого нет нужных инструментов, делайте их, это работает.
Автор: putinBog