Nvim-gdb перенесено на Moonscript
Nvim-gdb запитує місця зупинки у налагоджувача через сторонній канал. Для цього створюється локальне гніздо, яке з’єднується зі стороннім каналом. І виконувалося це через сторонній процес Пітону. Однак я нещодавно зрозумів, що в Neovim є вбудований інтерпретатор повноцінної мови програмування Lua. Чому було б не спробувати? Виявилося, що зусилля були не марними і вилилися у цілковиту переробку програми розширення.
Огляд
По-перше, з Lua легко почати. Навіть якщо в її стаднартна бібліотека не справляє враження, все ж її можливості легко розширити з допомогою Luarocks. Так у проекту з’явився власний сценарій розгортання install.sh. Він встановлює спочатку власне luarocks у місцеву теку, потім кілька модулів, які знадобляться для роботи з регулярними виразами і POSIX. Нарешті, готує компілятор Moonscript.
По-друге, особисто мені не до вподоби багатослівність Lua, тому й Moonscript. Він не потребує постійного друкування ключових слів, зате код виходить компактний і виразний водночас. Більше того, він набагато зручніший, коли справа доходить до об’єктно-орієнтованого програмування.
Тож я почав поступово замінювати скрипт за скриптом Vim модулями Lua, написаними мовою Moonscript. Зусилля не виявилися марними, і тепер більшість коду перенесено.
Деталі
Читальність коду
Moonscript — це звичайна і виразна мова програмування. Порівняймо один і той
самий шмат коду до та після перенесення. Можна відразу помітити, що більше немає
безглуздих let
, щоб присвоїти змінну, call
, щоб викликати функцію,
ніякого більше сміття при визначенні функції function!
і endfunction
тощо.
Доступ до API
Деякі обхідні шляхи зараз зовсім не потрібні завдяки Neovim API. Наприклад, є спосіб ідентифікувати вікна, вкладки і буфери. Їхні ідентифікатори можна запам’ятовувати, і більше не стрибати туди-сюди аби зорієнтуватися (це я про прибраний шматок у попередній ілюстрації).
Об’єктна орієнтовність
Moonscript дозволяє скористатися перевагами інкапсуляції, успадкування і поліморфізму. Наприклад, специфіки різних налагоджувачів успадковуються від базового. Обробники станів спільні, переходи між станами автомату у кожного відмінні.
class PdbScm extends BaseScm
new: (...) =>
super select(2, ...)
@addTrans(@paused, r([[(?<!-)> ([^(]+)\((\d+)\)[^(]+\(\)]]), m, @jump)
@addTrans(@paused, r([[^\(Pdb\) ]]), m, @query)
@state = @paused
Розділення коду
Перероблення коду — це хороша нагода переглянути взаємодію об’єктів. Щоб переконатися,
що вони взаємодіють чисто і прямолінійно. В якості ілюстрації, розгляньмо, як
запускається сеанс налагодження. Самостійні об’єкти @client
, @cursor
ініціюються першими,
потім ті, які їх потребують для функціонування, такі як @breakpoint
і @win
.
Залежні класи використовують свої залежності тільки через відкриті інтерфейси
контрольованим чином.
class App
new: (backendStr, proxyCmd, clientCmd) =>
-- Створити нову вкладку для налагодження і розбити горизонтально
V.exe "tabnew | sp"
-- Перерахувати вікна, що вийшли.
wins = V.list_wins!
table.sort wins
wcli, wjump = unpack(wins)
@backend = require "gdb.backend." .. backendStr
-- Перейти до іншого вікна і запустити клієнт налагоджувача
@client = Client(wcli, proxyCmd, clientCmd)
-- Підготувати слідкування за активним рядком
@cursor = Cursor()
-- Підготувати слідкування за місцями зупинки
@breakpoint = Breakpoint(@client\getProxyAddr!)
-- Підготувати віконну підсистему
@win = Win(wjump, @client, @cursor, @breakpoint)
-- Підготувати автомат
@scm = @backend\initScm(@cursor, @win)
-- Автомат вже має бути готовий, запустити налагоджувач!
@client\start!
Набір тестів
Саме перенесення було можливе завдяки набору тестів. Разом з цим, так само покращилися й тести: час виконання зменшився удвічі, надійність збільшилася, коли прибралися кілька видів гонок.
Висновки і плани
-
Взятися за переробляння — хороша нагода вивчити і покращити базу коду.
-
З оновленим розділеним кодом має бути тепер легше і підтримувати і додавати нові можливості, наприклад, delve.
-
Теоретично можливо обійтися без окремого інтерпретатора lua5.1 і використати сам Neovim як інтерпретатор Lua для початкового розгортання.