From 84aa3ac849ae57be6ce5bcb9e7a79616b86ab95f Mon Sep 17 00:00:00 2001 From: Nikita Fedkin Date: Thu, 27 Aug 2026 18:29:17 +0200 Subject: [PATCH 1/5] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=B3=D1=80=D0=B5=D1=81?= =?UTF-8?q?=D1=81-=D0=B1=D0=B0=D1=80=20=D0=BD=D0=B5=20=D0=BF=D0=B0=D0=B4?= =?UTF-8?q?=D0=B0=D0=B5=D1=82=20=D0=BD=D0=B0=20Linux=20=D0=B8=20macOS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Консоль.ВидимостьКурсора возвращает прежнее значение курсора и для этого читает Console.CursorVisible - свойство, чтение которого поддерживается только на Windows. На остальных платформах вызов выбрасывает PlatformNotSupportedException, поэтому прогресс-бар падал на первом же СделатьШаг. Теперь видимость курсора устанавливается там, где это поддерживается, а где нет - курсор просто остаётся видимым, и бар работает как обычно. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01PpvuJYLbttUBC1ufRmU1JN --- packagedef | 2 +- ...21\201\321\201\320\221\320\260\321\200.os" | 42 +++++++++++++++++-- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/packagedef b/packagedef index db70ebb..462b80c 100644 --- a/packagedef +++ b/packagedef @@ -1,6 +1,6 @@  Описание.Имя("progbar") - .Версия("1.3") + .Версия("1.4") .ВключитьФайл("src") .ВключитьФайл("LICENSE") .ВключитьФайл("lib.config") diff --git "a/src/\320\237\321\200\320\276\320\263\321\200\320\265\321\201\321\201\320\221\320\260\321\200.os" "b/src/\320\237\321\200\320\276\320\263\321\200\320\265\321\201\321\201\320\221\320\260\321\200.os" index 275aeb4..39f8f14 100644 --- "a/src/\320\237\321\200\320\276\320\263\321\200\320\265\321\201\321\201\320\221\320\260\321\200.os" +++ "b/src/\320\237\321\200\320\276\320\263\321\200\320\265\321\201\321\201\320\221\320\260\321\200.os" @@ -21,6 +21,8 @@ Перем СтрокаЗаполненногоБара; Перем ЦветБара; +Перем КурсорУправляем; + /////////////////////////////////////////////////////////////////////////////// // Начать @@ -95,7 +97,7 @@ КонецЕсли; - Консоль.ВидимостьКурсора(Ложь); + СкрытьКурсор(Ложь); Консоль.КурсорЛево = 0; Для Ит = 1 По Консоль.Ширина - 1 Цикл @@ -149,9 +151,9 @@ КонецЕсли; - Консоль.ВидимостьКурсора(Истина); + СкрытьКурсор(Истина); Консоль.ЦветТекста = ЦветТекстаКонсоли; - + КонецПроцедуры // СделатьШаг // Завершить @@ -161,7 +163,7 @@ Инициализирован = Ложь; Длительность = ТекущаяДата() - ДатаНачала; - Консоль.ВидимостьКурсора(Истина); + СкрытьКурсор(Истина); Консоль.ЦветТекста = ЦветТекстаКонсоли; Консоль.ВывестиСтроку(""); @@ -248,6 +250,37 @@ КонецФункции // ВремяВСтроку() +// СкрытьКурсор +// Управляет видимостью курсора там, где это поддерживается. +// +// Консоль.ВидимостьКурсора возвращает прежнее значение курсора, а для этого читает +// Console.CursorVisible - свойство, чтение которого существует только на Windows. +// На Linux и macOS вызов выбрасывает PlatformNotSupportedException, и прогресс-бар +// падал на первом же шаге. Курсор там просто остаётся видимым. +// +// Параметры: +// Видимость - Булево - Истина, если курсор должен быть виден +// +Процедура СкрытьКурсор(Знач Видимость) + + Если Не КурсорУправляем Тогда + + Возврат; + + КонецЕсли; + + Попытка + + Консоль.ВидимостьКурсора(Видимость); + + Исключение + + КурсорУправляем = Ложь; + + КонецПопытки; + +КонецПроцедуры // СкрытьКурсор() + Функция ЗаполнитьБар(СимволШаблона, Длина = 50); МассивСимволов = Новый Массив; @@ -263,5 +296,6 @@ Инициализирован = ЛОЖЬ; Длительность = 0; +КурсорУправляем = ИСТИНА; ЦветБара = ЦветКонсоли.Magenta; УстановитьСимволыБара(); From aa919a2e247779dc04be8313e7d21a3cb1c86a2e Mon Sep 17 00:00:00 2001 From: Nikita Fedkin Date: Thu, 27 Aug 2026 18:39:17 +0200 Subject: [PATCH 2/5] =?UTF-8?q?=D0=A2=D0=B5=D1=81=D1=82=D1=8B=20=D0=B8=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=87=D0=B8=D0=B5=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=86=D0=B5=D1=81=D1=81=D1=8B=20=D1=81=D0=B1=D0=BE=D1=80=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Тесты на OneUnit проверяют поведение до инициализации, длительность выполнения и то, что бар доходит до конца - на этом падала прежняя версия вне Windows. Тестовый рабочий процесс гоняет их на трёх операционных системах и на stable и dev движка, релизный публикует пакет на хаб по выпуску релиза. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01PpvuJYLbttUBC1ufRmU1JN --- .github/workflows/release.yml | 16 ++++ .github/workflows/test.yml | 19 +++++ .gitignore | 1 + packagedef | 2 + ...21\201\321\201\320\221\320\260\321\200.os" | 85 +++++++++++++++++++ 5 files changed, 123 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/test.yml create mode 100644 "tests/\320\237\321\200\320\276\320\263\321\200\320\265\321\201\321\201\320\221\320\260\321\200.os" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..423cfbf --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,16 @@ +name: Публикация релиза + +on: + release: + types: + - published + workflow_dispatch: + +jobs: + release: + uses: autumn-library/workflows/.github/workflows/release.yml@v1 + with: + oscript_version: stable + package_mask: "progbar-*.ospx" + secrets: + PUSH_TOKEN: ${{ secrets.PUSH_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..55aeeb8 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,19 @@ +name: Тестирование + +on: + push: + pull_request: + workflow_dispatch: + +jobs: + test: + strategy: + fail-fast: false + matrix: + oscript_version: ['stable', 'dev'] + uses: autumn-library/workflows/.github/workflows/test.yml@v1 + with: + oscript_version: ${{ matrix.oscript_version }} + test_engine: oneunit + test_dir_paths: tests + build_package: true diff --git a/.gitignore b/.gitignore index 305913c..562f619 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.ospx +oscript_modules diff --git a/packagedef b/packagedef index 462b80c..7284b2a 100644 --- a/packagedef +++ b/packagedef @@ -5,3 +5,5 @@ .ВключитьФайл("LICENSE") .ВключитьФайл("lib.config") .ВключитьФайл("readme.md") + + .РазработкаЗависитОт("asserts", "1.6.2") diff --git "a/tests/\320\237\321\200\320\276\320\263\321\200\320\265\321\201\321\201\320\221\320\260\321\200.os" "b/tests/\320\237\321\200\320\276\320\263\321\200\320\265\321\201\321\201\320\221\320\260\321\200.os" new file mode 100644 index 0000000..45a0701 --- /dev/null +++ "b/tests/\320\237\321\200\320\276\320\263\321\200\320\265\321\201\321\201\320\221\320\260\321\200.os" @@ -0,0 +1,85 @@ +#Использовать asserts +#Использовать ".." + +// Тесты прогресс-бара. +// +// Рисование проверяется наравне с остальным: в сборке вывод перенаправлен в файл, +// и бар должен переживать это на любой операционной системе. + +Функция Бар() + Возврат Новый ПрогрессБар(); +КонецФункции + +&Тест +Процедура ШагБезИнициализацииВыбрасываетИсключение() Экспорт + + Попытка + Бар().СделатьШаг(); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + КонецПопытки; + + Ожидаем.Что(ИнформацияОбОшибке).Не_().ЭтоНеопределено(); + Ожидаем.Что(СтрНайти(ИнформацияОбОшибке.Описание, "не инициализирован")).Больше(0); + +КонецПроцедуры + +&Тест +Процедура ОтрицательноеЧислоШаговВыбрасываетИсключение() Экспорт + + Попытка + Бар().Начать(-1); + Исключение + ИнформацияОбОшибке = ИнформацияОбОшибке(); + КонецПопытки; + + Ожидаем.Что(ИнформацияОбОшибке).Не_().ЭтоНеопределено(); + +КонецПроцедуры + +&Тест +Процедура ДлительностьВыполненияЧитаетсяВЧисленномВиде() Экспорт + + Ожидаем.Что(Бар().ДлительностьВыполнения()).Равно(0); + +КонецПроцедуры + +&Тест +Процедура ДлительностьВыполненияЧитаетсяВПредставлении() Экспорт + + Ожидаем.Что(Бар().ДлительностьВыполнения(Истина)).Равно("0с"); + +КонецПроцедуры + +&Тест +Процедура ШагиДоходятДоКонцаБара() Экспорт + + // Регрессия: на Linux и macOS первый же шаг падал с PlatformNotSupportedException - + // видимость курсора там прочитать нельзя + + ПрогрессБар = Бар(); + ПрогрессБар.Начать(3, "Проба"); + + Для Сч = 1 По 3 Цикл + ПрогрессБар.СделатьШаг(); + КонецЦикла; + + ПрогрессБар.Завершить(); + + Ожидаем.Что(ПрогрессБар.ДлительностьВыполнения()).БольшеИлиРавно(0); + +КонецПроцедуры + +&Тест +Процедура СимволыИЦветБараНастраиваются() Экспорт + + ПрогрессБар = Бар(); + ПрогрессБар.УстановитьСимволыБара(".", "#"); + ПрогрессБар.УстановитьЦветБара(ЦветКонсоли.Blue); + ПрогрессБар.Начать(2, "Проба"); + ПрогрессБар.СделатьШаг(); + ПрогрессБар.Завершить(); + + Ожидаем.Что(ПрогрессБар.ДлительностьВыполнения()).БольшеИлиРавно(0); + +КонецПроцедуры From fb1497424000fdedcf61729fb9e6e5143f0ec4f9 Mon Sep 17 00:00:00 2001 From: Nikita Fedkin Date: Thu, 27 Aug 2026 18:42:44 +0200 Subject: [PATCH 3/5] =?UTF-8?q?=D0=97=D0=B0=D0=B2=D0=B8=D1=81=D0=B8=D0=BC?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B8=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82?= =?UTF-8?q?=D0=B0=20=D0=B2=D0=B8=D0=B4=D0=BD=D1=8B=20=D0=B4=D0=BE=D1=87?= =?UTF-8?q?=D0=B5=D1=80=D0=BD=D0=B5=D0=BC=D1=83=20=D0=BF=D1=80=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=D0=BD=D1=83=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OneUnit порождает прогон отдельным процессом и собирает ему конфигурацию из oscript.cfg проекта. Без него дочерний процесс не видел локальный каталог библиотек и падал на поиске annotations. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01PpvuJYLbttUBC1ufRmU1JN --- oscript.cfg | 1 + 1 file changed, 1 insertion(+) create mode 100644 oscript.cfg diff --git a/oscript.cfg b/oscript.cfg new file mode 100644 index 0000000..39e1188 --- /dev/null +++ b/oscript.cfg @@ -0,0 +1 @@ +lib.additional=./oscript_modules From 5fa73c14d625b56ac7f72cf488b3aefbdf3b5aee Mon Sep 17 00:00:00 2001 From: Nikita Fedkin Date: Thu, 27 Aug 2026 18:44:07 +0200 Subject: [PATCH 4/5] =?UTF-8?q?=D0=9A=D0=B0=D1=82=D0=B0=D0=BB=D0=BE=D0=B3?= =?UTF-8?q?=20=D0=B1=D0=B8=D0=B1=D0=BB=D0=B8=D0=BE=D1=82=D0=B5=D0=BA=20?= =?UTF-8?q?=D1=83=D0=BA=D0=B0=D0=B7=D1=8B=D0=B2=D0=B0=D0=B5=D1=82=D1=81?= =?UTF-8?q?=D1=8F=20=D0=B2=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=D1=83?= =?UTF-8?q?=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D1=82=D0=B5=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Корневой oscript.cfg для этого не нужен: OneUnit собирает конфигурацию дочернего прогона из каталогов тестов, туда её и кладём. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01PpvuJYLbttUBC1ufRmU1JN --- oscript.cfg | 1 - tests/oscript.cfg | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 oscript.cfg create mode 100644 tests/oscript.cfg diff --git a/oscript.cfg b/oscript.cfg deleted file mode 100644 index 39e1188..0000000 --- a/oscript.cfg +++ /dev/null @@ -1 +0,0 @@ -lib.additional=./oscript_modules diff --git a/tests/oscript.cfg b/tests/oscript.cfg new file mode 100644 index 0000000..4101683 --- /dev/null +++ b/tests/oscript.cfg @@ -0,0 +1 @@ +lib.additional=../oscript_modules From 35d25fc91dc377eff6ce3973298db78240215379 Mon Sep 17 00:00:00 2001 From: Nikita Fedkin Date: Thu, 27 Aug 2026 18:49:55 +0200 Subject: [PATCH 5/5] =?UTF-8?q?=D0=91=D0=B0=D1=80=20=D0=BC=D0=BE=D0=BB?= =?UTF-8?q?=D1=87=D0=B8=D1=82=20=D1=82=D0=B0=D0=BC,=20=D0=B3=D0=B4=D0=B5?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BD=D1=81=D0=BE=D0=BB=D0=B8=20=D0=BD=D0=B5?= =?UTF-8?q?=D1=82,=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20=D0=BF=D0=B0?= =?UTF-8?q?=D0=B4=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Управление курсором работает только в живой консоли: при перенаправленном выводе позиция курсора недоступна (на Windows - "The handle is invalid"), а в сборке окна нет вовсе и его ширина равна нулю - установка позиции падает с выходом за границы. Прогресс-бар - украшение, и работа из-за него падать не должна: если рисовать нельзя, бар замолкает до конца прогона, а шаги и длительность продолжают считаться. Версия среды поднята до 2.0.0. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01PpvuJYLbttUBC1ufRmU1JN --- packagedef | 1 + ...21\201\321\201\320\221\320\260\321\200.os" | 96 +++++++++++++++---- 2 files changed, 80 insertions(+), 17 deletions(-) diff --git a/packagedef b/packagedef index 7284b2a..b5a5a02 100644 --- a/packagedef +++ b/packagedef @@ -1,6 +1,7 @@  Описание.Имя("progbar") .Версия("1.4") + .ВерсияСреды("2.0.0") .ВключитьФайл("src") .ВключитьФайл("LICENSE") .ВключитьФайл("lib.config") diff --git "a/src/\320\237\321\200\320\276\320\263\321\200\320\265\321\201\321\201\320\221\320\260\321\200.os" "b/src/\320\237\321\200\320\276\320\263\321\200\320\265\321\201\321\201\320\221\320\260\321\200.os" index 39f8f14..c51bbad 100644 --- "a/src/\320\237\321\200\320\276\320\263\321\200\320\265\321\201\321\201\320\221\320\260\321\200.os" +++ "b/src/\320\237\321\200\320\276\320\263\321\200\320\265\321\201\321\201\320\221\320\260\321\200.os" @@ -22,6 +22,7 @@ Перем ЦветБара; Перем КурсорУправляем; +Перем ВыводВозможен; /////////////////////////////////////////////////////////////////////////////// @@ -38,7 +39,17 @@ Процедура Начать(КоличествоШагов, Подсказка = "", ВыводитьПроценты = ИСТИНА, ВыводитьНомерИКоличество = ИСТИНА, ВыводитьВремя = ИСТИНА) Экспорт - ЦветТекстаКонсоли = Консоль.ЦветТекста; + Попытка + + ЦветТекстаКонсоли = Консоль.ЦветТекста; + + Исключение + + // цвет текста недоступен там же, где и остальная консоль: рисовать будет нечем + ЦветТекстаКонсоли = ЦветКонсоли.White; + ВыводВозможен = Ложь; + + КонецПопытки; ТекстПодсказки = Подсказка; НадоВыводитьПроценты = ВыводитьПроценты; НадоВыводитьНомерИКоличество = ВыводитьНомерИКоличество; @@ -92,11 +103,48 @@ КонецЕсли; Если Подсказка <> Неопределено Тогда - + ТекстПодсказки = Подсказка; - + КонецЕсли; - + + Длительность = ТекущаяДата() - ДатаНачала; + + Нарисовать(); + +КонецПроцедуры // СделатьШаг + +// Нарисовать +// Рисует строку прогресса, если консоль это позволяет. +// +// Управление курсором работает только в живой консоли: при перенаправленном выводе +// позиция курсора недоступна (на Windows - "The handle is invalid"), а в сборке окна +// нет вовсе и его ширина равна нулю. Прогресс-бар - украшение, и из-за него работа +// падать не должна: если рисовать нельзя, бар молча замолкает до конца прогона, +// а счётчик шагов и длительность продолжают считаться. +// +Процедура Нарисовать() + + Если Не ВыводВозможен Тогда + + Возврат; + + КонецЕсли; + + Попытка + + НарисоватьСтроку(); + + Исключение + + ВыводВозможен = Ложь; + + КонецПопытки; + +КонецПроцедуры // Нарисовать() + +Процедура НарисоватьСтроку() + СкрытьКурсор(Ложь); Консоль.КурсорЛево = 0; Для Ит = 1 По Консоль.Ширина - 1 Цикл @@ -105,7 +153,7 @@ КонецЦикла; Консоль.КурсорЛево = 0; - + Если ЗначениеЗаполнено(ТекстПодсказки) Тогда Консоль.ЦветТекста = ЦветКонсоли.Green; @@ -129,17 +177,15 @@ СтрокаНеЗаполненногоПрогресса = Сред(СтрокаПустогоБара, Позиция); Консоль.Вывести(СтрШаблон("%1 |%2%3| ", Значек, СтрокаЗаполненногоПрогресса, СтрокаНеЗаполненногоПрогресса)); - + Если НадоВыводитьПроценты Тогда - + Консоль.ЦветТекста = ЦветКонсоли.Yellow; Консоль.Вывести("" + Цел(ПоследнийШаг / КоличествоШаговПрогресса * 100) + "% "); - + КонецЕсли; - - Длительность = ТекущаяДата() - ДатаНачала; - Если НадоВыводитьВремя Тогда + Если НадоВыводитьВремя Тогда ДлительностьСтрока = ВремяВСтроку(Длительность); Прогноз = (Длительность * КоличествоШаговПрогресса) / ПоследнийШаг - Длительность; @@ -154,19 +200,34 @@ СкрытьКурсор(Истина); Консоль.ЦветТекста = ЦветТекстаКонсоли; -КонецПроцедуры // СделатьШаг +КонецПроцедуры // НарисоватьСтроку() // Завершить // Завершает вывод строки прогресс бара // Процедура Завершить() Экспорт - + Инициализирован = Ложь; Длительность = ТекущаяДата() - ДатаНачала; - СкрытьКурсор(Истина); - Консоль.ЦветТекста = ЦветТекстаКонсоли; - Консоль.ВывестиСтроку(""); - + + Если Не ВыводВозможен Тогда + + Возврат; + + КонецЕсли; + + Попытка + + СкрытьКурсор(Истина); + Консоль.ЦветТекста = ЦветТекстаКонсоли; + Консоль.ВывестиСтроку(""); + + Исключение + + ВыводВозможен = Ложь; + + КонецПопытки; + КонецПроцедуры // Завершить // ДлительностьВыполнения @@ -297,5 +358,6 @@ Инициализирован = ЛОЖЬ; Длительность = 0; КурсорУправляем = ИСТИНА; +ВыводВозможен = ИСТИНА; ЦветБара = ЦветКонсоли.Magenta; УстановитьСимволыБара();