2024-09-03
Недавно выложил свою реализацию lisp-интерпретатора написанного на PHP. И, чтобы можно было хотя бы как-то посмотреть его работу ничего не запуская, решил прикрепить в readme скринкаст работы в REPL.
Сразу покажу результат:
В принципе, в win11, уже всё для этого есть, но вводить текст без запинок опечаток и с постоянной скоростью оказалось не очень-то и просто. "Нужно отдать это дело на откуп программе!" - первая мысль посетившая меня после нескольких неудачных попыток.
Я использую WSL c Ubuntu для разработки и, уж чего-чего, а в линуксе
100% есть или уже готовая программа или её можно собрать на коленке из
bash-скриптов и палок того что найдём в
/usr/bin.
Итак, мне нужно эмулировать ввод текста с клавиатуры. Недолгий поиск
привёл меня к xdotool. Есть только одна проблема:
xdotool --type "hello"
ничего не выводит, а если спросить
echo $? # 0
т.е. всё хорошо.
Выяснилось, что буква "x" в её названии не просто так, утилита работает только с x11-приложениями. Stack Overflow подсказал её решение:
sudo apt install xterm
Благо WSL2 позволяет без проблем работать с GUI-приложениями линукса.
Все дальнейшие эксперименты с xdotool, и сам скринкаст, я
проводил в xterm.
Одна проблема решена, теперь надо как-то сделать так чтобы на экране
появлялось много строк. xdotool позволяет написать для неё
последовательность команд и передать её на вход файлом или из stdin.
cat scenario.txt | xdotool -
xdotool scenario.txt
Мне больше импонирует первый вариант, потому, что так можно будет генерировать сценарий "на лету".
Итак, вручную я вводил в терминал что-то вроде этого:
$ make repl
?> ; First, let's see some help information.
?> :help
?> ; Let's write some code.
?> (defn sum (n a)
?> ..(cond (= n 0)
# …
?> ; Let's exit the REPL
?> :q
Видно, что нужно сделать две вещи:
Для запуска программ в xdotool предлагают использовать такой синтаксис:
exec program_name arg_1
Запуск программы занимает какое-то время, нужно подождать пока она
запустится и продолжить ввод, иначе xdotool продолжит ввод
не дожидаясь её готовности к работе:
sleep 1
Это заставит утилиту подождать 1 секунду.
Для ввода строк нам нужна такая команда:
type "some string"
Ещё нам нужен перевод на новую строку:
key Return
Таким образом, чтобы ввести команду в REPL нужно два вызова:
type "some string"
key Return
Также нужно учесть, что, по-умолчанию, задержка ввода символов 12 мс. Это очень мало, нужно чтобы было похоже на ввод человеком:
type --delay 200 "some string"
Ещё нужно дать время зрителю прочитать строку целиком:
key --delay 1000 Return
Итого получим:
type --delay 200 "some string"
key --delay 1000 Return
Отлично, теперь можно представить как будет выглядеть сценарий:
exec make repl
sleep 1
type --delay 200 "; First, let's see some help info"
key --delay 1000 Return
type --delay 200 ":help"
key --delay 1000 Return
type --delay 200 "; Let's write some code."
key --delay 1000 Return
type --delay 200 "(defn sum (n a)"
key --delay 1000 Return
type --delay 200 "(cond (= n 0)"
key --delay 1000 Return
…
Писать это всё вручную нет никакого желания, проще написать текст который нужно вводить, а сценарий сгенерировать программой. Т.е. исходный сценарий будет выглядеть как-то так:
exec make repl
sleep 1
; First, let's see some help info
:help
; Let's write some code.
(defn sum (n a)
(cond (= n 0)
…
Как видите, за исключением первых двух строк, заготовка ничем не отличается от того что я бы вводил руками.
Осталось написать генератор сценария для xdotool на
основе текста:
#!/bin/bash
FILE=$1
SPEED=${2:-100}
DELAY=${3:-1000}
while IFS= read -r line; do
if [[ $line == exec* ]] || [[ $line == sleep* ]]
then
echo $line
else
echo "type --delay $SPEED \"$line\""
echo "key --delay $DELAY Return"
fi
done < $FILE
Сам скрипт я закинул в gist. Предложения по улушению принимаются!
Помимо имени файла, я добавил два опциональных параметра:
EnterСмотрим результат:
$ ./gen.sh scenario.txt
exec make repl
sleep 1
type --delay 100 "; First, let's see some help information."
key --delay 1000 Return
type --delay 100 ":help"
key --delay 1000 Return
...
На первый взгляд всё хорошо. Попробуем запустить:
$ ./gen.sh scenario.txt | xdotool -
; docker compose run --rm --user “1000:1000” app ./repl
First, let's see some help infothe input device is not TTY
make: *** [Makefile:20: repl] Error 1
rmation.
:help
...
Хм, не сработало, чего-то не так с TTY у докера (как видно из вывода,
команда make repl запускает докер). Попробуем
по-другому:
$ ./gen.sh scenario.txt > scen.txt && xdotool scen.txt
docker compose run --rm --user "1000:1000" app ./repl
=====================================================
Наберите :help для просмотра списка доступных команд
=====================================================
?>; First, let's see some help information.
?>:help
...
Отлично! Правда мне не нравится необходимость создавать промежуточный файл, но работа выполняется, жить можно.
Осталось решить несколько проблем, с которыми, впрочем, можно жить:
xdotool не позволяет написать в консоль
make repl и продолжить ввод уже в его окно приглашения,
нужно именно запустить его, т.е. вызвать exec make repl.
Из-за этого первую строчку в скринкасте мне пришлось смонтировать (и это
большой плюс asciinema! Если бы я писал видео, то не знаю сколько бы сил
этот монтаж у меня отнял.)Enter более 1
секунды , то xdotool будет "нажимать" его несколько
разcat scenario.txt | xdotool -, быстрый поиск по проблеме мне
не помогЕсли Вы знаете как обойти какую-либо из этих проблем или как-то, по-своему, решаете проблему идеального ввода текста для скринкаста, ну или просто Вам есть что сказать, приглашаю в комментарии! Так же у меня есть в телеграм-канал.
Комментарии
Комментарии на GitHub