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

Эксперимент с ней выглядит интересным и полезным, а разработку облегчат прекрасные объектные биндинги GtkD, всё-таки не с gap-буферами возиться. Из коробки биндинги уже есть в субпакете gtk-d:sv, но завязаны они на 4 версию библиотеки, а она есть не во всех дистрибутивах, что понижает портабельность, так что экспериментировать пришлось с 3. Поговаривают, что часть ошибок в ней исправили, в списке изменений есть исправление утечек памяти, api различаются незначительно (но местами всё-таки различаются). Практически всю общую логику можно реиспользовать из предыдущего эксперимента с RSS-ридером, что также сэкономит время на разработку, синхронизируя архитектуры программ, позволив их сопровождать с меньшей болью.

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

Любые требования к программе нужно с чем-то сравнивать, поэтому я выберу основным эталоном Geany, посматривая одним глазом на Notepad++, PSPad, а также на уже существующие редакторы (Gedit, Xed и т.д.) с GtkSourceView на борту. На самом деле основной функционал более-менее везде одинаков, различаясь в зависимости от специализации редактора.

В первую очередь логично обосновать выбор GtkD для данной программы, ведь текстовый редактор можно построить на любом более-менее популярном тулките. Для Swing есть RSyntaxTextArea, которую я испытывал в эксперименте с русскоязычным DSL, для JavaFX - RichTextFX. С последней эксперименты были очень поверхностными, но с простыми задачами она вроде как справляется, хотя потестировать серьёзнее её бы не помешало.

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

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

Теоретически, такой редактор с GtkSourceView вполне можно было бы сделать даже на Dart, учитывая недавний эксперимент с GTK, поскольку Flutter проявил свою специализацию на мобайле, а данная задача требует десктопной специализации. Но из-за отсутствия готовых биндингов затея выглядит сомнительной, ибо в намного более высокоуровневом Dart резко осложняется взаимодействие с низкоуровневым кодом через ffi.

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

Functionality (Функциональные требования): из-за наличия готовой библиотеки, развитого std у D и возможности использования системных библиотек выглядит возможным повторить большую часть функционала.

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

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

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

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

Reliability (Надёжность): с одной стороны, часть отказов подстраховано исключениями. Но в архитектуре разделения приложения на контроллеры в самом простом случае есть большое количество мест взаимодействия делегатами-коллбэками, которые вполне могут быть null, в случае неаккуратного с ним обращения будет беда. Хотя и есть некоторые способы подстраховок, но обращение к таким коллбэкам вполне контролируемо, поэтому можно начать без nullable-обёрток.

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

Ещё одним риском может быть поведение D для символических ссылок. Симлинк может успешно пройти std.file.exists на следующей проверке std.file.isFile и isDir выбросится исключение, как и при любом доступе к такому файлу, что может сделать редактор более хрупким и есть смысл лишний раз протестировать открытие симлинков с отсутствующим файлом.

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

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

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

Supportability (Поддержка): если использовать инжекцию контролов через метапрограммирование в поля контроллеров, то архитектура начинает приближаться к более высокоуровневым тулкитам.

Можно проанализировать как влияет тулкит на некоторые отдельные характеристики поддержки.

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

Гибкость, модифицируемость: тоже высокая из-за разделения кода и выноса вью в xml с Glade. Может быть проблемой перезапутывание логики взаимодействия между разными контроллерами и слоями приложения, но появление её ситуативно.

Модульность, расширяемость: возможна в разных вариантах, например, посредством плагинов и Lua-биндингов, как и других встраиваемых языков или систем (например, Libpeas). В данном случае есть полный доступ к кодовой базе, а значит проще внести изменения в сам код, чем использовать какие-то плагины и модули.

Локализация: это уже интереснее. Можно попробовать что-то такое через gettext, однако это не выглядит удобным. Собственное решение выглядит более универсальным, но потребует переустановки всех текстов во вью, что вполне реализуемо, однако по затратам времени в рамках эксперимента выглядит одинаково сомнительно.

Кроссплатформенность: GTK предполагает определённую кроссплатформенность, однако из-за части системозависимого кода и библиотек портативность может осложняться в зависимости от функционала самого редактора.

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

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

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

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

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

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

Однако код можно не только читать, но и запускать, что намекает на терминал и ещё одну панель снизу. Это отражает промежуточное положение между редактором и IDE, позволяя заниматься скриптописью, например, на Bash. Со сниппетами, быстрым запуском скрипта в терминале это выглядит удобным.

Для меня появляется ещё одно важное требование - поддержка Markdown. У Markdown не слишком много конкурентов, даже статьи этого блога оформляются в нём, достаточно странно, чтобы редактор его не поддерживал, однако это предполагает и встраивание браузера для проверки результата. Этот же браузер можно использовать для просмотра документации, как языка так и сервисов вроде devdocs.io.

Подведём небольшие итоги по концепту редактора и макета:

  • Панель с файловым браузером слева.
  • Панель инструментов справа.
  • Панель терминала снизу.

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

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

Можно подвести небольшие итоги по функционалу, используя MoSCoW метод, однако в рамках эксперимента перечисление всего возможного функционала потребовало бы огромных списков, ограничусь самым основным, например:

Must have (критичный функционал):

  • Открытие и закрытие файлов в табах.
  • Открытие файла перетаскиванием в окно программы.
  • Сохранение файла по сочетанию клавиш и через диалог, возможность перемещения курсора клавишами.
  • Поиск, подсветка и замена текста в т.ч. по регулярным выражениям.
  • Контекстное меню с основными действиями: вырезать, копировать, вставить и т.п.
  • Повтор и отмена, номера строк, перенос.
  • Подсветка синтаксиса.
  • Вывод информации о файле: кодировка, тип переноса строки, MIME-тип файла, количество строк и символов.

Should have (важный):

  • Создание файла из шаблонов (например, xdg-user-dirs)
  • Монитор открытого файла, перегрузка по изменениям.
  • Механизм сессий и восстановление открытых файлов.
  • Открытие новых файлов в том же окне уже работающей программы.
  • Анализ файла на безопасность (например, на Trojan Source с CVE-2021-42574).
  • Автодополнение.
  • Поддержка сниппетов.
  • Markdown.
  • Файловый менеджер.
  • Терминал.
  • Браузер.

Could have (желательный):

  • Быстрый переход вверх и вниз документа.
  • Настройка шрифтов и цветов.
  • Список недавно открытых файлов.
  • Проверка орфографии.
  • Печать.

Would to have (опциональный):

  • Разные дополнения и улучшения, перечислять которые в рамках эксперимента избыточно: вставка даты и времени, сортировка строк и т.п.

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

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

Из Geany особенно удобны кнопки создания нового файла и список недавно открытых файлов. Рядом с ними было решено добавить ещё две полезные кнопки - навигация по документу вверх и вниз до конца, что иногда часто требуется и достаточно удобно. С сожалению, этот концепт нарушает когнитивную привычку искать пункт меню "Файл" на самом краю главного меню, поэтому пришлось их вынести в совсем другую сторону и подальше.

Функционал автосохранения хотя и полезен, но на любителя: привычка частого сохранения хоткеями выработалась годами, а вот автосохранение способно сохранить то, что не нужно. Встраивание SSH в рамках эксперимента тоже выглядит специализированным, как и удалённое открытие документов и прочее, его я не рассматриваю. Разноцветные табы смотрятся красиво, но привыкание к одноцветным табам разных IDE и браузеров скорее также делает этот функционал специфическим.

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

Прототип получился каким-то таким:

GtkD with GtkSourceView text editor

Бегло пробегусь по некоторым моментам реализации.

Табы можно легко реализовать через gtk.Notebook. Основные грабли скорее в закрытии таба, где есть шанс получить утечки, не разрушив все зависимые виджеты (можно предположить, что вызова removePage по индексу может быть достаточно, но это не так).

Для сниппетов выделена отдельная вкладка на правой панели, сами сниппеты в простых текстовых файлах, наверное больше всего полезны они для Bash, учитывая большое количество его граблей. Механизм сессий, как и список недавних файлов также самый простой обычными текстовыми файлами, всё по Unix-way.

В Gtk есть DnD (Drag and Drop), поэтому открытие файла перетаскиванием тоже не проблема.

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

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

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

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

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

В сохранении есть случай - отсутствие свободного места на диске. У D есть функция std.file.getAvailableDiskSpace, её название может вводить в заблуждение, но на Posix системах она внутри использует вызов statvfs (для FreeBSD там немножко по-своему), а он возвращает информацию о смонтированной файловой системе.

Открытие новых файлов в запущенном приложении уже предусмотрено в Gtk, возможно через регистрацию делегата в методе Application.addOnOpen (приложению должен быть передан и флаг GApplicationFlags.HANDLES_OPEN), различать разные копии може специальным апи (например, getIsRemote и т.п.). При открытии бывают проблемы с долгим сохранением иконки загрузки на курсоре, но после тестов такое поведение оказалось и у других редакторов, возможно, тут влияет версия библиотек, дистрибутив и т.п. факторы. Также здесь появляется риск из-за каким-то образом оставшейся без открытого окна программы: любой новый открывающийся файл будет пытаться открываться в ней, блокируя запуск всех других копий, что без убийства основного процесса сделает программу неработоспособной в системе.

Терминал через библиотеку vte, готовые биндинги есть в субпакете gtk-d:vte, с которой могут возникнуть проблемы под Windows, хотя, теоретически, её наверное можно найти во всяких MSYS2 и Cygwin. Для терминала имеет большое значение оформление, которое может отличаться от системного терминала и требовать либо какого-то отслеживания дефолтной темы, либо настройки. Я просто добавил кнопку переключения фона, поскольку разные задачи терминала удобно решать разными фонами.

Здесь есть нюанс в настройке оформления vte, с толку может сбить сообщение об ошибке цвета: можно подумать, что его значение невалидно, однако ориентироваться нужно не по нему, а по ассерту о проверке цветов в палитре 0,8,16 и т.п., если размер неправильный, то оно и работать не будет. Неудобство здесь может быть из-за сброса стиля курсора, текста и прочего при изменении фона, но для простого случая не особенно критично.

Проверка орфографии через hunspell, биндинги там достаточно простые и легко реализуются вручную. Само окно проверки вынес в правую панель, поскольку поэтапная проверка орфографии в диалоге меня лично всегда раздражала в редакторах. Туда же была добавлена и отдельная проверка через yaspeller, проще всего запустить его через cli.

Что касается безопасности Trojan Source, то списки опасных символов можно найти в разных местах, однако лучше сверять детектирование с другими популярными IDE и редакторами, например, тут отсутствует \u200b.

Также частным случаем могут быть невалидные символы в имени файла на разных системах, такое предупреждение реализуется весьма просто и выглядит полезным, особенно на Linux: много раз сталкивался с проблемами копирования файлов на носители с устаревшими и менее продвинутыми файловыми системами. Раз речь зашла о валидации имени, то концепт табов чувствителен к максимальной длине имени, Geany в случае превышения обрезает имя, что выглядит логичным, а, например, vscode - нет.

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

Из коробки через std.encoding поддерживается перекодирование UTF-8\16\32, ASCII, ISO-8859-1 и 2, WINDOWS-1250\1251\1252 через функцию transcode. Не слишком много для редактора, но учитывая его задачи выглядит достаточным (так-то есть ещё iconv, конечно же), а для неизвестной кодировки проще вывести предупреждение или вопрос в диалоге, поскольку gtk тоже проверяет текст (вызывает Glib.utf8_validate и в буфер SourceBuffer его просто так не вставит). Вызовом функции getBOM можно определить маркер последовательности байтов. С учётом его опасности для скриптов есть смысл выводить предупреждение в случае его наличия.

Здесь также нужно учитывать логику чтения файла до перекодирования. Если будет вызов функции, которая делает какую-то валидацию текста, например, std.file.readText, то будут проблемы.

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

Поскольку кодировка и тип перевода строки может не совпадать с таковыми в редакторе, то в информационном тулбаре разделение их тоже показалось более удобным, да и проще определить, сработал ли автодетект кодировки и символа переноса строки, как сработал и т.д.

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

Браузер через webkit2gtk. Часть тулкитов переходит на Blink, но люди пишут, что биндинки к Webkit намного проще и стабильнее, да и подключить их намного легче. Для D можно найти пакеты, но в моём простом случае достаточно и самописных, расширенного функционала не требуется. Браузер создаёт определённые риски для безопасности, уязвимости всплывают периодически, что намекает на осторожное использование этого функционала.

Возможность работы с ресурсами навроде DevDocs поднимает вопрос портабельности программы: данные, которые сохраняет сайт для оффлайн-работы должны переноситься вместе с программой. Перенастроить директории можно с помощью WebKitWebsiteDataManager, однако если взять какой-нибудь пакет, например, webkit2gtkd, то в нём только пустой конструктор, когда как настроить директории можно через вариативную функцию webkit_website_data_manager_new, передавая ей ключи и пути, да null последним.

Файловый менеджер самый простой с минимально необходимой навигацией и историей. Здесь в будущем может потребоваться вынос рутовой директории в отдельную вкладку, с другой стороны, возможны какие-то вкладки с проектом, навигацией по символам или что-то такое более полезное, а вот навигатор с множеством табов-директорий может быть избыточным. Набор файловых иконок free-file-icons. Здесь основной вопрос с файловыми мониторами, без которых любой файловый менеджер сильно теряет в своей полезности, я использовал всё тот же gio.FileMonitor.

Для облегчения печати есть SourcePrintCompositor, однако документ упорно не хотел печататься в PDF и за примерами апи пришлось лезть в Xed, после портирования логики всё заработало.

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

Какие итоги можно подвести. Несмотря на определённые проблемы и потери времени на борьбу с библиотекой, эксперимент можно признать успешным. Часть api не особенно интуитивна, но за счёт объектности биндингов в общем случае можно прийти к решению банальным перебором методов и разных их комбинаций, сообщения со стороны GTK также помогают сориентироваться, а решение проблем можно подсмотреть и в кодовой базе других редакторов, построенных на GtkSourceView. Так что было достаточно весело (в хорошем смысле этого слова) и мне этот эксперимент определённо понравился.