diff --git a/README.md b/README.md index b6760a9..e3a230e 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,14 @@ ```sh d-examples -├── common Общего назначения -│ ├── isexists Проверяет наличие исполняемого файла в директориях,указанных в переменной окружения PATH -│ └── splittext Форматирует массив строк, разбивая их на строки указанной длины -├── ncurses Использование библиотеки ncurses -│ ├── menu Интерактивное консольное меню -│ └── password Консольное окно для ввода пароля -└── shell Запуск команд в shell - ├── pipe Чтение выходных данных на примере ip - └── spinner Эмуляция статуса выполнения процесса +├── common # Общего назначения +│ ├── isexists # Проверяет наличие исполняемого файла в директориях,указанных в переменной окружения PATH +│ └── splittext # Форматирует массив строк, разбивая их на строки указанной длины +├── ncurses # Использование библиотеки ncurses +│ ├── menu # Интерактивное консольное меню +│ └── password # Консольное окно для ввода пароля +└── shell # Запуск команд в shell + ├── pipe # Чтение выходных данных на примере ip + ├── spinner # Эмуляция статуса выполнения процесса + └── ospinner # Демонстрирует объектно-ориентированный подход к созданию анимации спиннера в консоли ``` diff --git a/source/app.d b/source/app.d index 7f8330b..82117e0 100644 --- a/source/app.d +++ b/source/app.d @@ -20,6 +20,8 @@ int main(string[] args) .add(new Command("shell", "Запуск команд в shell") .add(new Command("pipe", "Чтение выходных данных на примере ip")) .add(new Command("spinner", "Эмуляция статуса выполнения процесса")) + .add(new Command("ospinner", + "Демонстрирует объектно-ориентированный подход к созданию анимации спиннера в консоли")) ) .parse(args); @@ -34,7 +36,8 @@ int main(string[] args) }) .on("shell", (shell) { shell .on("pipe", (pipe) { pipeShell(); }) - .on("spinner", (loading) { spinnerShell(); }); + .on("spinner", (spinner) { spinnerShell(); }) + .on("ospinner", (ospinner) { oSpinnerShell(); }); }); return EXIT_SUCCESS; diff --git a/source/examples/shell/README.md b/source/examples/shell/README.md index 1b1aa94..d920848 100644 --- a/source/examples/shell/README.md +++ b/source/examples/shell/README.md @@ -7,3 +7,7 @@ ## spinner Функция `spinnerShell` создаёт анимацию спиннера в консоли, используя брайлевские символы для имитации процесса обработки. Устанавливает обработчик сигнала `Ctrl+C` для корректного завершения с восстановлением курсора. Выполняет цикл с задержкой 100 мс, отображая вращающийся символ, и завершает выполнение с выводом "Done!". Использует модули `std.stdio`, `core.thread`, `core.time` и функции C для работы с сигналами и выводом. + +## ospinner + +Функция `oSpinnerShell` демонстрирует объектно-ориентированный подход к созданию анимации спиннера в консоли. Использует абстрактный класс `Command` для выполнения задач с анимацией спиннера (брайлевские символы). Класс `LongRunningCommand` имитирует длительную задачу (5 секунд). Обработчик `Ctrl+C` завершает выполнение с восстановлением курсора. Анимация отображает имя команды и сообщение, завершаясь выводом "Done!". Использует модули `std.stdio`, `core.thread`, `core.time`, `core.stdc.signal`, `core.stdc.stdio`, `core.stdc.stdlib`. diff --git a/source/examples/shell/ospinner.d b/source/examples/shell/ospinner.d new file mode 100644 index 0000000..f73f577 --- /dev/null +++ b/source/examples/shell/ospinner.d @@ -0,0 +1,109 @@ +module examples.shell.ospinner; + +import std.stdio; +import core.thread; +import core.time; +import core.stdc.signal : signal, SIGINT; +import core.stdc.stdio : fprintf; +import core.stdc.stdlib : exit; + +// Обработчик сигнала Ctrl+C +extern (C) void handleCtrlC(int sig) nothrow @nogc +{ + // Используем fprintf для вывода в stderr + fprintf(core.stdc.stdio.stderr, "\033[?25h\r\033[KInterrupted!\n"); + exit(0); +} + +// Абстрактный базовый класс для команд +private abstract class Command +{ + private string message = "Processing..."; // Сообщение для спиннера + private string name = "Default command"; // Наименование команды + private immutable dchar[] spinner = [ + '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏' + ]; // Символы спиннера + + // Абстрактный метод, который должны реализовать наследники + protected abstract void execute(); + + this(string commandName) + { + name = commandName; + } + + // Метод для запуска команды с анимацией спиннера + final void run() + { + ulong i = 0; + bool taskCompleted = false; + + // Создаём поток для выполнения команды + auto worker = new Thread({ + try + { + execute(); // Выполняем логику команды + } + catch (Exception e) + { + stderr.writefln("Error: %s", e.msg); + } + taskCompleted = true; + }); + + // Скрываем курсор + write("\033[?25l"); + stdout.flush(); + + // Запускаем задачу + worker.start(); + + // Цикл анимации спиннера + while (!taskCompleted) + { + writef("\r%s: %s %c", name, message, spinner[i]); + stdout.flush(); + i = (i + 1) % spinner.length; + Thread.sleep(dur!("msecs")(100)); + } + + // Ждём завершения потока + worker.join(); + + // Восстанавливаем курсор и очищаем строку + writef("\033[?25h\r\033[K%s: Done!\n", name); + } + + // Метод для установки пользовательского сообщения + void setMessage(string msg) + { + message = msg; + } +} + +// Пример команды с выводом +private class LongRunningCommand : Command +{ + this(string commandName) + { + super(commandName); + } + + override void execute() + { + Thread.sleep(dur!("seconds")(5)); // Имитация работы + } +} + +void oSpinnerShell() +{ + // Устанавливаем обработчик для SIGINT (Ctrl+C) + signal(SIGINT, &handleCtrlC); + + // Создаём команду + auto cmd = new LongRunningCommand("Test"); + + cmd.setMessage("Working on task..."); + writeln("Running with spinner:"); + cmd.run(); +} diff --git a/source/examples/shell/package.d b/source/examples/shell/package.d index 3ea1e93..54a667a 100644 --- a/source/examples/shell/package.d +++ b/source/examples/shell/package.d @@ -2,3 +2,4 @@ module examples.shell; public import examples.shell.pipe; public import examples.shell.spinner; +public import examples.shell.ospinner; diff --git a/source/examples/version_.d b/source/examples/version_.d index 373c0e0..a6a7618 100644 --- a/source/examples/version_.d +++ b/source/examples/version_.d @@ -1,3 +1,3 @@ module examples.version_; -enum examplesVersion = "0.4.0"; +enum examplesVersion = "0.5.0";