diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d4918cf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+bdd-log.xml
+*.ospx
+*.orig
+exec.log
+ignore/**
+tests.xml
diff --git a/LICENSE b/LICENSE
index df96360..0753288 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,7 @@
-MIT License
+The MIT License (MIT)
-Copyright (c) 2019 orais / tools
+Copyright (c) 2016 Andrei Ovsiankin
+Copyright (c) 2019 BIA Technologies, LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1af6109
--- /dev/null
+++ b/README.md
@@ -0,0 +1,91 @@
+# Скрипт для работы с шаблонами кода
+
+- [Скрипт для работы с шаблонами кода](#%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82-%D0%B4%D0%BB%D1%8F-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B-%D1%81-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%B0%D0%BC%D0%B8-%D0%BA%D0%BE%D0%B4%D0%B0)
+ - [Установить приложение, алгоритм установки стандартный](#%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%B8%D1%82%D1%8C-%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC-%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B8-%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B9)
+ - [Использование](#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)
+ - [Конвертация шаблонов](#%D0%BA%D0%BE%D0%BD%D0%B2%D0%B5%D1%80%D1%82%D0%B0%D1%86%D0%B8%D1%8F-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2)
+ - [Объединение шаблонов](#%D0%BE%D0%B1%D1%8A%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2)
+ - [Разделение шаблонов](#%D1%80%D0%B0%D0%B7%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2)
+
+## Установить приложение, алгоритм установки стандартный
+
+- склонировать репозиторий или
+- распаковать в нужный каталог архив репозитория
+- для Windows запустить [installlocalhost.bat](/installlocalhost.bat)
+
+## Использование
+
+### Конвертация шаблонов
+
+1. Шаблоны конфигуратора в шаблоны VS Code
+2. Шаблоны конфигуратора в шаблоны EDT
+3. Шаблоны EDT в шаблоны конфигуратора
+
+Поддерживаемые расширения файлов
+
+- ".st" - шаблон конфигуратора
+- ".json" - шаблон языка VSCode
+- ".code-snippets" - глобальный шаблон VSCode
+- ".xml" - шаблон EDT
+
+Определение типа преобразования происходит на основании расширения файла.
+
+Для запуска преобразования используется команда:
+
+`snippet-transform convert Исходный-шаблон Новый-шаблон`
+
+Примеры:
+
+- `snippet-transform convert "Мой любимый шаблон.st" "bsl.code-snippets"`
+ Команда выполнить преобразование шаблона конфигуратор в глобальный шаблон VSCode
+
+- `snippet-transform convert "Мой любимый шаблон.xml" "bsl.st"`
+ Команда выполнить преобразование шаблона EDT в шаблон конфигуратора
+
+### Объединение шаблонов
+
+`snippet-transform join-files Изменяемый-шаблон Добавляемый-шаблон`
+
+- `Изменяемый-шаблон` - Имя файла шаблона, в который будут добавлены записи из второго файла
+- `Добавляемый-шаблон` - Имя файла, в котором содержатся добавляемые записи
+
+`snippet-transform join-path Каталог-шаблонов Результирующий-шаблон`
+
+- `Каталог-шаблонов` - Имя каталога, в котором лежат шаблоны, которые нужно соединить.
+- `Результирующий-шаблон` - Имя файла, в который будет сохранен результат
+
+Примеры:
+
+- `snippet-transform join-files "Мой любимый шаблон.xml" "Мой второй любимый шаблон.st"`
+ Команда выполнить объединение шаблонов EDT и конфигуратора и запишет результат в шаблон EDT c именем "Мой любимый шаблон.xml"
+
+- `snippet-transform join-path "Каталог любимый шаблонов" "Супер шаблон.code-snippets"`
+ Команда выполнить объединение всех поддерживаемых шаблонов каталога и запишет результат в новый шаблон
+
+### Разделение шаблонов
+
+`snippet-transform apportion Изменяемый-шаблон Выражение-поиска [Новый-шаблон] [-r]`
+
+Удаляет (переносит в новый файл) элементы шаблона, полное наименование которых совпадает с `Выражение-поиска`
+
+- `Изменяемый-шаблон` - Имя файла шаблона, из которого будет вырезана часть
+- `Выражение-поиска` - Регулярное выражение для проверки наименования элемента шаблона. Если выражение совпадает с наименованием, то такой элемент переносится в новый файл.
+- `Новый-шаблон` - Имя файла шаблона, в который будут помещены исключенные записи
+- `-r` Переносить элементы, у которых наименование не совпадает с шаблоном
+
+Примеры:
+
+- `snippet-transform apportion "Мой любимый шаблон.st" "алгоритм"`
+ Удалит из шаблона элементы, в наименовании которых есть слово "алгоритм"
+
+- `snippet-transform apportion "Мой любимый шаблон.st" "алгоритм" Алгоритмы.st`
+ Перенесет из шаблона "Мой любимый шаблон.st" в шаблон "Алгоритмы.st" элементы, в наименовании которых есть слово "алгоритм"
+
+- `snippet-transform apportion "Мой любимый шаблон.st" "оставить" -r`
+ Удалит из шаблона все элементы, в наименовании которых нет слова "оставить"
+
+- `snippet-transform apportion "Мой любимый шаблон.st" "^Супер группа\." -r`
+ Удалит из шаблона все элементы, кроме группы первого уровня "Супер группа"
+
+- `snippet-transform apportion "Мой любимый шаблон.st" "Плохая группа\."`
+ Удалит из шаблона группы "Плохая группа" и "очень плохая группа"
diff --git "a/features/step_definitions/\320\220\320\275\320\260\320\273\320\270\320\267\320\250\320\260\320\261\320\273\320\276\320\275\320\276\320\262.os" "b/features/step_definitions/\320\220\320\275\320\260\320\273\320\270\320\267\320\250\320\260\320\261\320\273\320\276\320\275\320\276\320\262.os"
new file mode 100644
index 0000000..f3872b9
--- /dev/null
+++ "b/features/step_definitions/\320\220\320\275\320\260\320\273\320\270\320\267\320\250\320\260\320\261\320\273\320\276\320\275\320\276\320\262.os"
@@ -0,0 +1,97 @@
+// Реализация шагов BDD-фич/сценариев c помощью фреймворка https://github.com/artbear/1bdd
+
+Перем БДД; //контекст фреймворка 1bdd
+
+// Метод выдает список шагов, реализованных в данном файле-шагов
+Функция ПолучитьСписокШагов(КонтекстФреймворкаBDD) Экспорт
+ БДД = КонтекстФреймворкаBDD;
+
+ ВсеШаги = Новый Массив;
+
+ ВсеШаги.Добавить("ФайлВРабочемКаталогеСодержитСтроки");
+ ВсеШаги.Добавить("ФайлВРабочемКаталогеНеСодержитСтроки");
+
+ Возврат ВсеШаги;
+КонецФункции
+
+// Реализация шагов
+
+// Процедура выполняется перед запуском каждого сценария
+Процедура ПередЗапускомСценария(Знач Узел) Экспорт
+
+КонецПроцедуры
+
+// Процедура выполняется после завершения каждого сценария
+Процедура ПослеЗапускаСценария(Знач Узел) Экспорт
+
+КонецПроцедуры
+
+//Файл "result/vscode1.code-snippets" в рабочем каталоге содержит строки
+//| "scope": "bsl" |
+//| "prefix": "Общий модуль" |
+//| "prefix": "DEPRECATED" |
+//| "prefix": "Инкремент" |
+Процедура ФайлВРабочемКаталогеСодержитСтроки(Знач ФайлРабочегоКаталога, Знач ТаблицаСтрок) Экспорт
+
+ ФайлРабочегоКаталога = БДД.ПолучитьПутьФайлаСУчетомПеременныхКонтекста(ФайлРабочегоКаталога);
+
+ Чтение = Новый ЧтениеТекста(ОбъединитьПути(БДД.ПолучитьИзКонтекста("РабочийКаталог"), ФайлРабочегоКаталога), КодировкаТекста.UTF8);
+ СтрокаГдеИщем = Чтение.Прочитать();
+ Чтение.Закрыть();
+
+ СтрокаРасхождений = "";
+ Для Каждого СтрТаблицы Из ТаблицаСтрок Цикл
+
+ СтрокаЧтоИщем = СтрТаблицы[0];
+ Если Найти(СтрокаГдеИщем, СтрокаЧтоИщем) = 0 Тогда
+ СтрокаРасхождений = СтрШаблон(
+ "%1
+ | Не найдена подстрока <%2>", СтрокаРасхождений, СтрокаЧтоИщем);
+ КонецЕсли;
+
+ КонецЦикла;
+ Если Не ПустаяСтрока(СтрокаРасхождений) Тогда
+ СтрокаРасхождений = СтрШаблон(
+ "Не нашли одну из подстрок таблицы:
+ |%2
+ |в строке:
+ |%1", СтрокаГдеИщем, СтрокаРасхождений);
+ Ожидаем.Что(Истина, СтрокаРасхождений).ЭтоЛожь();
+ КонецЕсли;
+
+КонецПроцедуры
+
+//Файл "result/vscode1.code-snippets" в рабочем каталоге не содержит строки
+//| "scope": "bsl" |
+//| "prefix": "Общий модуль" |
+//| "prefix": "DEPRECATED" |
+//| "prefix": "Инкремент" |
+Процедура ФайлВРабочемКаталогеНеСодержитСтроки(Знач ФайлРабочегоКаталога, Знач ТаблицаСтрок) Экспорт
+
+ ФайлРабочегоКаталога = БДД.ПолучитьПутьФайлаСУчетомПеременныхКонтекста(ФайлРабочегоКаталога);
+
+ Чтение = Новый ЧтениеТекста(ОбъединитьПути(БДД.ПолучитьИзКонтекста("РабочийКаталог"), ФайлРабочегоКаталога), КодировкаТекста.UTF8);
+ СтрокаГдеИщем = Чтение.Прочитать();
+ Чтение.Закрыть();
+
+ СтрокаРасхождений = "";
+ Для Каждого СтрТаблицы Из ТаблицаСтрок Цикл
+
+ СтрокаЧтоИщем = СтрТаблицы[0];
+ Если Найти(СтрокаГдеИщем, СтрокаЧтоИщем) <> 0 Тогда
+ СтрокаРасхождений = СтрШаблон(
+ "%1
+ | Найдена подстрока <%2>", СтрокаРасхождений, СтрокаЧтоИщем);
+ КонецЕсли;
+
+ КонецЦикла;
+ Если Не ПустаяСтрока(СтрокаРасхождений) Тогда
+ СтрокаРасхождений = СтрШаблон(
+ "Нашли одну из подстрок таблицы:
+ |%2
+ |в строке:
+ |%1", СтрокаГдеИщем, СтрокаРасхождений);
+ Ожидаем.Что(Истина, СтрокаРасхождений).ЭтоЛожь();
+ КонецЕсли;
+
+КонецПроцедуры
diff --git "a/features/\320\236\320\261\321\212\320\265\320\264\320\270\320\275\320\270\321\202\321\214-\320\264\320\262\320\260-\321\210\320\260\320\261\320\273\320\276\320\275\320\260.feature" "b/features/\320\236\320\261\321\212\320\265\320\264\320\270\320\275\320\270\321\202\321\214-\320\264\320\262\320\260-\321\210\320\260\320\261\320\273\320\276\320\275\320\260.feature"
new file mode 100644
index 0000000..fadbeae
--- /dev/null
+++ "b/features/\320\236\320\261\321\212\320\265\320\264\320\270\320\275\320\270\321\202\321\214-\320\264\320\262\320\260-\321\210\320\260\320\261\320\273\320\276\320\275\320\260.feature"
@@ -0,0 +1,29 @@
+#language: ru
+
+Функциональность: Объединение шаблонов кода
+
+Как разработчик
+Я хочу получить единый файл шаблона кода
+Чтоб проще распространять и подключать его
+
+Контекст:
+ Допустим Я очищаю параметры команды "oscript" в контексте
+ И я включаю отладку лога с именем "oscript.app.snippet-transform"
+ И я создаю временный каталог и сохраняю его в контекст
+ И я устанавливаю временный каталог как рабочий каталог
+ И я установил рабочий каталог как текущий каталог
+ И я создаю каталог "snippets" в рабочем каталоге
+ И я копирую файл "ШаблонКонфигуратора.st" из каталога "tests/fixtures//snippets" проекта в подкаталог "snippets" рабочего каталога
+ И я копирую файл "ШаблонEDT.xml" из каталога "tests/fixtures//snippets" проекта в подкаталог "snippets" рабочего каталога
+
+Сценарий: Объединение двух шаблонов
+ Когда я выполняю команду "oscript" с параметрами "<КаталогПроекта>/src/main.os join-files snippets/ШаблонКонфигуратора.st snippets/ШаблонEDT.xml"
+ Тогда Код возврата равен 0
+ И Файл "snippets/ШаблонКонфигуратора.st" в рабочем каталоге содержит
+ """
+ {"Общий модуль",0,0,"Модуль[Общий]","//⇗ ⇘ ⇙ ⇚ ⇛ ⇜ ⇝ ⇞ ⇟ ⇠ ⇡ ⇢ ⇣ ⇤ ⇥ ⇦ ⇧ ⇨ ⇩ ⇪ ⇫ ⇬ ⇭ ⇮ ⇯ ⇰ ⇱ ⇲ ⇳ ⇴ ⇵ ⇶ ⇷ ⇸ ⇹ ⇺ //
+ """
+ И Файл "snippets/ШаблонКонфигуратора.st" в рабочем каталоге содержит
+ """
+ ТекущаяДата = '"n1", ДатаВремя, ""ДФ=dd.MM.yyyy"">'
+ """
diff --git "a/features/\320\236\320\261\321\212\320\265\320\264\320\270\320\275\320\270\321\202\321\214-\321\210\320\260\320\261\320\273\320\276\320\275\321\213-\320\272\320\260\321\202\320\260\320\273\320\276\320\263\320\260.feature" "b/features/\320\236\320\261\321\212\320\265\320\264\320\270\320\275\320\270\321\202\321\214-\321\210\320\260\320\261\320\273\320\276\320\275\321\213-\320\272\320\260\321\202\320\260\320\273\320\276\320\263\320\260.feature"
new file mode 100644
index 0000000..51595d4
--- /dev/null
+++ "b/features/\320\236\320\261\321\212\320\265\320\264\320\270\320\275\320\270\321\202\321\214-\321\210\320\260\320\261\320\273\320\276\320\275\321\213-\320\272\320\260\321\202\320\260\320\273\320\276\320\263\320\260.feature"
@@ -0,0 +1,29 @@
+#language: ru
+
+Функциональность: Объединение шаблонов кода
+
+Как разработчик
+Я хочу получить единый файл шаблона кода
+Чтоб проще распространять и подключать его
+
+Контекст:
+ Допустим Я очищаю параметры команды "oscript" в контексте
+ И я включаю отладку лога с именем "oscript.app.snippet-transform"
+ И я создаю временный каталог и сохраняю его в контекст
+ И я устанавливаю временный каталог как рабочий каталог
+ И я установил рабочий каталог как текущий каталог
+ И я создаю каталог "snippets" в рабочем каталоге
+ И я копирую файл "ШаблонКонфигуратора.st" из каталога "tests/fixtures/snippets" проекта в подкаталог "snippets" рабочего каталога
+ И я копирую файл "ШаблонEDT.xml" из каталога "tests/fixtures/snippets" проекта в подкаталог "snippets" рабочего каталога
+
+Сценарий: Объединение шаблонов каталога
+ Когда я выполняю команду "oscript" с параметрами "<КаталогПроекта>/src/main.os join-path snippets result.st"
+ Тогда Код возврата равен 0
+ И Файл "result.st" в рабочем каталоге содержит
+ """
+ {"Общий модуль",0,0,"Модуль[Общий]","//⇗ ⇘ ⇙ ⇚ ⇛ ⇜ ⇝ ⇞ ⇟ ⇠ ⇡ ⇢ ⇣ ⇤ ⇥ ⇦ ⇧ ⇨ ⇩ ⇪ ⇫ ⇬ ⇭ ⇮ ⇯ ⇰ ⇱ ⇲ ⇳ ⇴ ⇵ ⇶ ⇷ ⇸ ⇹ ⇺ //
+ """
+ И Файл "result.st" в рабочем каталоге содержит
+ """
+ ТекущаяДата = '"n1", ДатаВремя, ""ДФ=dd.MM.yyyy"">'
+ """
diff --git "a/features/\320\237\321\200\320\265\320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\320\265-\321\210\320\260\320\261\320\273\320\276\320\275\320\276\320\262.feature" "b/features/\320\237\321\200\320\265\320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\320\265-\321\210\320\260\320\261\320\273\320\276\320\275\320\276\320\262.feature"
new file mode 100644
index 0000000..558c845
--- /dev/null
+++ "b/features/\320\237\321\200\320\265\320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\320\265-\321\210\320\260\320\261\320\273\320\276\320\275\320\276\320\262.feature"
@@ -0,0 +1,52 @@
+#language: ru
+
+Функциональность: Преобразование шаблонов
+
+Как разработчик я хочу иметь возможность конвертировать шаблоны в различные форматы
+Чтобы подключать их к различным IDE
+
+Контекст:
+ Допустим Я очищаю параметры команды "oscript" в контексте
+ И я включаю отладку лога с именем "oscript.app.snippet-transform"
+ И я создаю временный каталог и сохраняю его в контекст
+ И я устанавливаю временный каталог как рабочий каталог
+ И я установил рабочий каталог как текущий каталог
+ И Я копирую каталог "snippets" из каталога "tests/fixtures" проекта в рабочий каталог
+ И я создаю каталог "result" в рабочем каталоге
+
+Сценарий: Преобразование шаблона конфигуратора в шаблон VSCode
+ Когда я выполняю команду "oscript" с параметрами "<КаталогПроекта>/src/main.os convert snippets/ШаблонКонфигуратора.st result/vscode.code-snippets"
+ Тогда Код возврата равен 0
+ И Файл "result/vscode.code-snippets" в рабочем каталоге содержит строки
+ | "scope": "bsl" |
+ | "prefix": "МодульОбщий" |
+ | "prefix": "ЗапретитьИспользование" |
+ | "prefix": "++" |
+Сценарий: Преобразование шаблона конфигуратора в шаблон EDT
+ Когда я выполняю команду "oscript" с параметрами "<КаталогПроекта>/src/main.os convert snippets/ШаблонКонфигуратора.st result/edt.xml"
+ Тогда Код возврата равен 0
+ И Файл "result/edt.xml" в рабочем каталоге содержит строки
+ | name="МодульОбщий" |
+ | name="ЗапретитьИспользование" |
+ | name="++" |
+Сценарий: Преобразование шаблона конфигуратора с неподдерживаемыми типами в шаблон VSCode
+ Когда я выполняю команду "oscript" с параметрами "<КаталогПроекта>/src/main.os convert snippets/ШаблонКонфигуратораСНеподдерживаемымиТипами.st result/vscode.code-snippets"
+ Тогда Код возврата равен 0
+ И Файл "result/vscode.code-snippets" в рабочем каталоге содержит строки
+ | "scope": "bsl" |
+ | "prefix": "№Если" |
+ И Файл "result/vscode.code-snippets" в рабочем каталоге не содержит строки
+ | "prefix": "УстановитьЗначениеКонстанты" |
+ | "prefix": "Формат" |
+Сценарий: Преобразование шаблона конфигуратора с неподдерживаемыми в шаблон EDT
+ Когда я выполняю команду "oscript" с параметрами "<КаталогПроекта>/src/main.os convert snippets/ШаблонКонфигуратораСНеподдерживаемымиТипами.st result/edt.xml"
+ Тогда Код возврата равен 0
+ И Файл "result/edt.xml" в рабочем каталоге не содержит строки
+ | name="Формат" |
+ | name="УстановитьЗначениеКонстанты" |
+ | name="№Если" |
+ И Файл "result/edt.xml" в рабочем каталоге содержит
+ """
+
+
+ """
\ No newline at end of file
diff --git "a/features/\320\240\320\265\320\267\320\264\320\265\320\273\320\270\321\202\321\214-\321\210\320\260\320\261\320\273\320\276\320\275.feature" "b/features/\320\240\320\265\320\267\320\264\320\265\320\273\320\270\321\202\321\214-\321\210\320\260\320\261\320\273\320\276\320\275.feature"
new file mode 100644
index 0000000..5669f92
--- /dev/null
+++ "b/features/\320\240\320\265\320\267\320\264\320\265\320\273\320\270\321\202\321\214-\321\210\320\260\320\261\320\273\320\276\320\275.feature"
@@ -0,0 +1,33 @@
+#language: ru
+
+Функциональность: Разделение шаблона кода
+
+Как разработчик
+Я хочу получить разделить файл шаблона
+
+Контекст:
+ Допустим Я очищаю параметры команды "oscript" в контексте
+ И я включаю отладку лога с именем "oscript.app.snippet-transform"
+ И я создаю временный каталог и сохраняю его в контекст
+ И я устанавливаю временный каталог как рабочий каталог
+ И я установил рабочий каталог как текущий каталог
+ И я копирую файл "snippets/ШаблонКонфигуратора.st" из каталога "tests\fixtures" проекта в рабочий каталог
+
+Сценарий: Объединение двух шаблонов
+ Когда я выполняю команду "oscript" с параметрами
+ """
+ <КаталогПроекта>/src/main.os apportion ШаблонКонфигуратора.st "^Группа.*" result.st -r
+ """
+ Тогда Код возврата равен 0
+ И Файл "ШаблонКонфигуратора.st" в рабочем каталоге не содержит
+ """
+ {"Общий модуль",0,0,"Модуль[Общий]","//⇗ ⇘ ⇙ ⇚ ⇛ ⇜ ⇝ ⇞ ⇟ ⇠ ⇡ ⇢ ⇣ ⇤ ⇥ ⇦ ⇧ ⇨ ⇩ ⇪ ⇫ ⇬ ⇭ ⇮ ⇯ ⇰ ⇱ ⇲ ⇳ ⇴ ⇵ ⇶ ⇷ ⇸ ⇹ ⇺ //
+ """
+ И Файл "ШаблонКонфигуратора.st" в рабочем каталоге содержит
+ """
+ ""Операнд""> = ""Операнд""> + 1;
+ """
+ И Файл "result.st" в рабочем каталоге содержит
+ """
+ {"Общий модуль",0,0,"Модуль[Общий]","//⇗ ⇘ ⇙ ⇚ ⇛ ⇜ ⇝ ⇞ ⇟ ⇠ ⇡ ⇢ ⇣ ⇤ ⇥ ⇦ ⇧ ⇨ ⇩ ⇪ ⇫ ⇬ ⇭ ⇮ ⇯ ⇰ ⇱ ⇲ ⇳ ⇴ ⇵ ⇶ ⇷ ⇸ ⇹ ⇺ //
+ """
diff --git a/installlocalhost.bat b/installlocalhost.bat
new file mode 100644
index 0000000..f627dd6
--- /dev/null
+++ b/installlocalhost.bat
@@ -0,0 +1,13 @@
+@echo off
+call del "*.ospx"
+
+for /f %%i in ('"oscript -version"') do set result=%%i
+
+if %result%==1.0.19.105 (
+ call opm build . -mf ./packagedef -out .
+) else (
+ call opm build -m ./packagedef -o .
+)
+
+rem // TODO: наименование приложения и версия
+call opm install -f *.ospx
\ No newline at end of file
diff --git a/packagedef b/packagedef
new file mode 100644
index 0000000..715ee79
--- /dev/null
+++ b/packagedef
@@ -0,0 +1,14 @@
+ПутьКСценариюПараметров = ОбъединитьПути(ТекущийСценарий().Каталог, "src", "Модули", "ПараметрыПриложения.os");
+ПараметрыСистемы_ЛокальнаяВерсия = ЗагрузитьСценарий(ПутьКСценариюПараметров);
+
+ИмяПродукта = НРег(ПараметрыСистемы_ЛокальнаяВерсия.ИмяПродукта());
+
+Описание.Имя(ИмяПродукта)
+ .ВерсияСреды("1.0.21")
+ .Версия(ПараметрыСистемы_ЛокальнаяВерсия.ВерсияПродукта())
+ .ЗависитОт("logos", "1.2")
+ .ЗависитОт("cmdline", "1.0")
+ .ВключитьФайл("src")
+ .ВключитьФайл("README.md")
+ .ВключитьФайл("LICENSE")
+ .ИсполняемыйФайл("src/main.os", ИмяПродукта);
diff --git a/src/main.os b/src/main.os
new file mode 100644
index 0000000..d2f4c00
--- /dev/null
+++ b/src/main.os
@@ -0,0 +1,49 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// CLI-интерфейс для oscript-app
+//
+//The MIT License (MIT)
+//
+// Copyright (c) 2016 Andrei Ovsiankin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Рекомендованная структура модуля точки входа приложения
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#Использовать "."
+
+///////////////////////////////////////////////////////////////////////////////
+
+Приложение = МенеджерПриложения.Инициализировать(ПараметрыПриложения);
+
+Попытка
+
+ Приложение.ЗавершитьРаботуПриложения(Приложение.ЗапуститьВыполнение());
+
+Исключение
+
+ Приложение.ЗавершитьРаботуПриложенияСОшибкой(ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
+
+КонецПопытки;
diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260Apportion.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260Apportion.os"
new file mode 100644
index 0000000..d077db4
--- /dev/null
+++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260Apportion.os"
@@ -0,0 +1,37 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Модуль команды разделения шаблона
+//
+///////////////////////////////////////////////////////////////////////////////
+
+Процедура НастроитьКоманду(Знач Команда, Знач Парсер) Экспорт
+
+ Парсер.ДобавитьПозиционныйПараметрКоманды(Команда, "ИзменяемыйШаблон", "Имя файла шаблона, который хотим разделить");
+ Парсер.ДобавитьПозиционныйПараметрКоманды(Команда, "ШаблонНаименования", "Регулярное выражение для проверки полного наименования шаблона (Группа.Шаблон)");
+ Парсер.ДобавитьПозиционныйПараметрКоманды(Команда, "НовыйШаблон", "Имя файла шаблона, в который будут записаны отделенные элементы");
+ Парсер.ДобавитьПараметрФлагКоманды(Команда, "-r", "Переносить элементы, у которых наименование не совпадает с шаблоном");
+
+КонецПроцедуры // НастроитьКоманду
+
+// Выполняет логику команды
+//
+// Параметры:
+// ПараметрыКоманды - Соответствие - Соответствие ключей командной строки и их значений
+// Приложение - Модуль - Модуль менеджера приложения
+//
+Функция ВыполнитьКоманду(Знач ПараметрыКоманды, Знач Приложение) Экспорт
+
+ Лог = Приложение.ПолучитьЛог();
+
+ ИзменяемыйШаблон = ПараметрыКоманды["ИзменяемыйШаблон"];
+ НовыйШаблон = ПараметрыКоманды["НовыйШаблон"];
+ ШаблонНаименования = ПараметрыКоманды["ШаблонНаименования"];
+ ПереноситьНесовпадения = ПараметрыКоманды["-r"] = Истина;
+
+ Конвертер.РазделитьШаблон(ИзменяемыйШаблон, ШаблонНаименования, ПереноситьНесовпадения, НовыйШаблон);
+
+ Лог.Отладка("Выполнено разделение шаблонов");
+
+ Возврат Приложение.РезультатыКоманд().Успех;
+
+КонецФункции // ВыполнитьКоманду
diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260Convert.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260Convert.os"
new file mode 100644
index 0000000..2eb214d
--- /dev/null
+++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260Convert.os"
@@ -0,0 +1,33 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Служебный модуль с реализацией работы команды help
+//
+///////////////////////////////////////////////////////////////////////////////
+
+Процедура НастроитьКоманду(Знач Команда, Знач Парсер) Экспорт
+
+ Парсер.ДобавитьПозиционныйПараметрКоманды(Команда, "ВходнойФайл", "Имя конвертируемого шаблона");
+ Парсер.ДобавитьПозиционныйПараметрКоманды(Команда, "ВыходнойФайл", "Имя файла нового шаблона, в который будут перенесены элементы из первого файла");
+
+КонецПроцедуры // НастроитьКоманду
+
+// Выполняет логику команды
+//
+// Параметры:
+// ПараметрыКоманды - Соответствие - Соответствие ключей командной строки и их значений
+// Приложение - Модуль - Модуль менеджера приложения
+//
+Функция ВыполнитьКоманду(Знач ПараметрыКоманды, Знач Приложение) Экспорт
+
+ Лог = Приложение.ПолучитьЛог();
+
+ ВходнойФайл = ПараметрыКоманды["ВходнойФайл"];
+ ВыходнойФайл = ПараметрыКоманды["ВыходнойФайл"];
+
+ Конвертер.ПреобразоватьШаблон(ВходнойФайл, ВыходнойФайл);
+
+ Лог.Информация("Преобразование выполнено. %1 ==> %2", ВходнойФайл, ВыходнойФайл);
+
+ Возврат Приложение.РезультатыКоманд().Успех;
+
+КонецФункции // ВыполнитьКоманду
diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260JoinFiles.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260JoinFiles.os"
new file mode 100644
index 0000000..8b5b58a
--- /dev/null
+++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260JoinFiles.os"
@@ -0,0 +1,37 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Модуль команды соединения двух файлов
+//
+///////////////////////////////////////////////////////////////////////////////
+
+Процедура НастроитьКоманду(Знач Команда, Знач Парсер) Экспорт
+
+ Парсер.ДобавитьПозиционныйПараметрКоманды(Команда, "ИзменяемыйШаблон", "Имя файла шаблона, в который будут добавлены элементы из второго файла");
+ Парсер.ДобавитьПозиционныйПараметрКоманды(Команда, "ДобавляемыйШаблон", "Имя файла шаблона, из которого будут добавлены элементы в первый файл");
+
+КонецПроцедуры // НастроитьКоманду
+
+// Выполняет логику команды
+//
+// Параметры:
+// ПараметрыКоманды - Соответствие - Соответствие ключей командной строки и их значений
+// Приложение - Модуль - Модуль менеджера приложения
+//
+Функция ВыполнитьКоманду(Знач ПараметрыКоманды, Знач Приложение) Экспорт
+
+ Лог = Приложение.ПолучитьЛог();
+
+ ИзменяемыйШаблон = ПараметрыКоманды["ИзменяемыйШаблон"];
+ ДобавляемыйШаблон = ПараметрыКоманды["ДобавляемыйШаблон"];
+
+ ВходныеФайлы = Новый Массив();
+ ВходныеФайлы.Добавить(Новый Файл(ИзменяемыйШаблон));
+ ВходныеФайлы.Добавить(Новый Файл(ДобавляемыйШаблон));
+
+ Конвертер.СоединитьШаблоны(ВходныеФайлы, ИзменяемыйШаблон);
+
+ Лог.Отладка("Файлы объединены");
+
+ Возврат Приложение.РезультатыКоманд().Успех;
+
+КонецФункции // ВыполнитьКоманду
diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260JoinPath.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260JoinPath.os"
new file mode 100644
index 0000000..a056816
--- /dev/null
+++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260JoinPath.os"
@@ -0,0 +1,33 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Модуль команды соединения каталога шаблонов
+//
+///////////////////////////////////////////////////////////////////////////////
+
+Процедура НастроитьКоманду(Знач Команда, Знач Парсер) Экспорт
+
+ Парсер.ДобавитьПозиционныйПараметрКоманды(Команда, "КаталогШаблонов", "Каталог содержащий шаблоны кода, которые необходимо объединить");
+ Парсер.ДобавитьПозиционныйПараметрКоманды(Команда, "РезультирующийШаблон", "Имя файла итогового шаблона");
+
+КонецПроцедуры // НастроитьКоманду
+
+// Выполняет логику команды
+//
+// Параметры:
+// ПараметрыКоманды - Соответствие - Соответствие ключей командной строки и их значений
+// Приложение - Модуль - Модуль менеджера приложения
+//
+Функция ВыполнитьКоманду(Знач ПараметрыКоманды, Знач Приложение) Экспорт
+
+ Лог = Приложение.ПолучитьЛог();
+
+ КаталогШаблонов = ПараметрыКоманды["КаталогШаблонов"];
+ РезультирующийШаблон = ПараметрыКоманды["РезультирующийШаблон"];
+
+ Конвертер.СоединитьШаблоны(НайтиФайлы(КаталогШаблонов, "*", Истина), РезультирующийШаблон);
+
+ Лог.Отладка("Шаблоны каталога объединены");
+
+ Возврат Приложение.РезультатыКоманд().Успех;
+
+КонецФункции // ВыполнитьКоманду
diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260Version.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260Version.os"
new file mode 100644
index 0000000..1a131c0
--- /dev/null
+++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260Version.os"
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Служебный модуль с реализацией работы команды version
+//
+///////////////////////////////////////////////////////////////////////////////
+
+Процедура НастроитьКоманду(Знач Команда, Знач Парсер) Экспорт
+
+КонецПроцедуры // НастроитьКоманду
+
+// Выполняет логику команды
+//
+// Параметры:
+// ПараметрыКоманды - Соответствие - Соответствие ключей командной строки и их значений
+// Приложение - Модуль - Модуль менеджера приложения
+//
+Функция ВыполнитьКоманду(Знач ПараметрыКоманды, Знач Приложение) Экспорт
+
+ Лог = Приложение.ПолучитьЛог();
+
+ Сообщить(Приложение.ВерсияПродукта());
+
+ Лог.Отладка("Вывод версии приложения");
+
+ Возврат Приложение.РезультатыКоманд().Успех;
+
+КонецФункции // ВыполнитьКоманду
diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\241\320\277\321\200\320\260\320\262\320\272\320\260\320\237\320\276\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\260\320\274.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\241\320\277\321\200\320\260\320\262\320\272\320\260\320\237\320\276\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\260\320\274.os"
new file mode 100644
index 0000000..e00d787
--- /dev/null
+++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\274\320\260\320\275\320\264\320\260\320\241\320\277\321\200\320\260\320\262\320\272\320\260\320\237\320\276\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\260\320\274.os"
@@ -0,0 +1,41 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Служебный модуль с реализацией работы команды help
+//
+///////////////////////////////////////////////////////////////////////////////
+
+Процедура НастроитьКоманду(Знач Команда, Знач Парсер) Экспорт
+
+ Парсер.ДобавитьПозиционныйПараметрКоманды(Команда, "Команда");
+
+КонецПроцедуры // НастроитьКоманду
+
+// Выполняет логику команды
+//
+// Параметры:
+// ПараметрыКоманды - Соответствие - Соответствие ключей командной строки и их значений
+// Приложение - Модуль - Модуль менеджера приложения
+//
+Функция ВыполнитьКоманду(Знач ПараметрыКоманды, Знач Приложение) Экспорт
+
+ Лог = Приложение.ПолучитьЛог();
+
+ КомандаДляСправки = ПараметрыКоманды["Команда"];
+
+ Если КомандаДляСправки = Неопределено Тогда
+
+ Приложение.ВывестиСправкуПоКомандам();
+
+ Лог.Отладка("Вывод справки по командам");
+
+ Иначе
+
+ Приложение.ВывестиСправкуПоКоманде(КомандаДляСправки);
+
+ Лог.Отладка(СтрШаблон("Вывод справки по команде %1", КомандаДляСправки));
+
+ КонецЕсли;
+
+ Возврат Приложение.РезультатыКоманд().Успех;
+
+КонецФункции // ВыполнитьКоманду
diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\247\321\202\320\265\320\275\320\270\320\265\320\222\320\275\321\203\321\202\321\200\320\265\320\275\320\275\320\270\320\271\320\244\320\276\321\200\320\274\320\260\321\2021\320\241.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\247\321\202\320\265\320\275\320\270\320\265\320\222\320\275\321\203\321\202\321\200\320\265\320\275\320\275\320\270\320\271\320\244\320\276\321\200\320\274\320\260\321\2021\320\241.os"
new file mode 100644
index 0000000..8177c2a
--- /dev/null
+++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\247\321\202\320\265\320\275\320\270\320\265\320\222\320\275\321\203\321\202\321\200\320\265\320\275\320\275\320\270\320\271\320\244\320\276\321\200\320\274\320\260\321\2021\320\241.os"
@@ -0,0 +1,297 @@
+///////////////////////////////////////////////////////////////////
+//
+// Чтение файлов во внутреннем формате 1с
+// За основу взята разработка https://github.com/arkuznetsov/yabr
+// (с) BIA Technologies, LLC
+//
+///////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////
+// Программный интерфейс
+///////////////////////////////////////////////////////////////////
+
+// Выполняет чтение файла во внутреннем формате 1с(скобочном)
+//
+// Параметры:
+// ПутьКФайлу - Строка - путь к файлу для чтения
+// НачальнаяСтрока - Число - номер начальной строки файла для чтения
+//
+// Возвращаемое значение:
+// Структура - Новый элемент
+// *Родитель - Структура - ссылка на элемент-родитель
+// *Уровень - Число - уровень иерархии элемента
+// *Индекс - Число - индекс элемента в массиве значений родителя
+// *НачСтрока - Число - номер первой строки из которой был прочитан элемент и его дочерние элементы
+// *КонСтрока - Число - номер последней строки из которой был прочитан элемент и его дочерние элементы
+// *Значения - Массив(Структура) - массив дочерних элементов
+//
+Функция ПрочитатьФайл(ПутьКФайлу, НачальнаяСтрока = 1) Экспорт
+
+ СтруктураЧтения = ИнициализироватьЭлемент(Неопределено);
+
+ Текст = Новый ЧтениеТекста(ПутьКФайлу, КодировкаТекста.UTF8NoBOM);
+
+ ДанныеСтроки = Текст.ПрочитатьСтроку();
+
+ Начало = ТекущаяУниверсальнаяДатаВМиллисекундах();
+ ТекНачало = Начало;
+ НачКоличество = 0;
+
+ НомерСтроки = 1;
+
+ Пока НЕ ДанныеСтроки = Неопределено Цикл
+
+ Если НомерСтроки < НачальнаяСтрока И НЕ НачальнаяСтрока < 1 Тогда
+ ДанныеСтроки = Текст.ПрочитатьСтроку();
+ НомерСтроки = НомерСтроки + 1;
+ Продолжить;
+ КонецЕсли;
+
+ СтрокаДляОбработки = "";
+ СтрокаДляОбработкиПрочитана = Ложь;
+ КавычкиОткрыты = Ложь;
+
+ // сборка "завершенной" строки, где кавычки закрыты и последний символ = "," или "}"
+ Пока НЕ (СтрокаДляОбработкиПрочитана ИЛИ ДанныеСтроки = Неопределено) Цикл
+
+ СтрокаДляОбработкиПрочитана = ДополнитьСтрокуДляОбработки(СтрокаДляОбработки, ДанныеСтроки, КавычкиОткрыты);
+
+ Если НЕ СтрокаДляОбработкиПрочитана Тогда
+
+ Если КавычкиОткрыты Тогда
+ СтрокаДляОбработки = СтрокаДляОбработки + Символы.ПС;
+ КонецЕсли;
+
+ ДанныеСтроки = Текст.ПрочитатьСтроку();
+ НомерСтроки = НомерСтроки + 1;
+
+ КонецЕсли;
+
+ КонецЦикла;
+
+ СчетчикСимволов = 1;
+
+ ПрочитатьДанныеСтроки(СтруктураЧтения, СтрокаДляОбработки, СчетчикСимволов);
+
+ ДанныеСтроки = Текст.ПрочитатьСтроку();
+
+ НомерСтроки = НомерСтроки + 1;
+
+ КонецЦикла;
+
+ Текст.Закрыть();
+
+ Если НЕ ПустаяСтрока(СтрокаДляОбработки) Тогда
+ ПрочитатьДанныеСтроки(СтруктураЧтения, СтрокаДляОбработки, СчетчикСимволов);
+ КонецЕсли;
+
+ НачальнаяСтрока = НомерСтроки;
+
+ // переход к корневому элементу структуры чтения
+ Пока НЕ СтруктураЧтения.Родитель = Неопределено Цикл
+ СтруктураЧтения = СтруктураЧтения.Родитель;
+ КонецЦикла;
+
+ Результат = СтруктураЧтения;
+
+ Возврат Результат;
+
+КонецФункции // ПрочитатьФайл()
+
+///////////////////////////////////////////////////////////////////
+// Служебный функционал
+///////////////////////////////////////////////////////////////////
+
+// Функция - добавляет строку к исходной и возвращает признак завершенности строки
+// исходя из закрытия кавычек и окончания строки на "," или "}"
+//
+// Параметры:
+// ДополняемаяСтрока - Строка - исходная строка
+// Дополнение - Строка - добавляемая строка
+// КавычкиОткрыты - Булево - Истина - кавычки открыты; Ложь - кавычки закрыты
+//
+// Возвращаемое значение:
+// Булево - Истина - строка завершена; Ложь - строка не завершена
+//
+Функция ДополнитьСтрокуДляОбработки(ДополняемаяСтрока, Дополнение, КавычкиОткрыты)
+
+ КоличествоКавычек = СтрЧислоВхождений(Дополнение, """");
+
+ Если КавычкиОткрыты Тогда
+ КавычкиОткрыты = (КоличествоКавычек % 2 = 0);
+ Иначе
+ КавычкиОткрыты = (КоличествоКавычек % 2 = 1);
+ КонецЕсли;
+
+ ДополняемаяСтрока = ДополняемаяСтрока + Дополнение;
+
+ ПоследнийСимвол = Сред(Дополнение, СтрДлина(Дополнение), 1);
+
+ // строка завершена если кавычки закрыты и последний символ = "," или "}"
+ Возврат (НЕ КавычкиОткрыты) И (ПоследнийСимвол = "}" ИЛИ ПоследнийСимвол = ",");
+
+КонецФункции // ДополнитьСтрокуДляОбработки()
+
+// Функция - создает структуру нового элемента
+//
+// Параметры:
+// Родитель - Структура - ссылка на элемент-родитель (для корневого элемента "Неопределено")
+//
+// Возвращаемое значение:
+// Структура - Новый элемент
+// *Родитель - Структура - ссылка на элемент-родитель
+// *Уровень - Число - уровень иерархии элемента
+// *Индекс - Число - индекс элемента в массиве значений родителя
+// *НачСтрока - Число - номер первой строки из которой был прочитан элемент и его дочерние элементы
+// *КонСтрока - Число - номер последней строки из которой был прочитан элемент и его дочерние элементы
+// *Значения - Массив(Структура) - массив дочерних элементов
+//
+Функция ИнициализироватьЭлемент(Знач Родитель)
+
+ Уровень = 0;
+ Если ТипЗнч(Родитель) = Тип("Структура") Тогда
+ Если Родитель.Свойство("Уровень") Тогда
+ Уровень = Родитель.Уровень + 1;
+ КонецЕсли;
+ КонецЕсли;
+
+ Индекс = 0;
+ Если ТипЗнч(Родитель) = Тип("Структура") Тогда
+ Если Родитель.Свойство("Значения") Тогда
+ Индекс = Родитель.Значения.ВГраница() + 1;
+ КонецЕсли;
+ КонецЕсли;
+
+ Результат = Новый Структура("Родитель,
+ |Уровень,
+ |Индекс,
+ |НачСтрока,
+ |КонСтрока,
+ |Значения",
+ Родитель,
+ Уровень,
+ Индекс,
+ 0,
+ 0,
+ Новый Массив());
+
+
+ Возврат Результат;
+
+КонецФункции // ИнициализироватьЭлемент()
+
+// Процедура - Читает, разбирает данные из переданной строки и добавляет результат в иерархию массива структур
+//
+// Параметры:
+// ЭлементДляЗаполнения - Структура - структура элемента
+// *Родитель - Структура - ссылка на элемент-родитель
+// *Уровень - Число - уровень иерархии элемента
+// *Индекс - Число - индекс элемента в массиве значений родителя
+// *НачСтрока - Число - номер первой строки из которой был прочитан элемент и его дочерние элементы
+// *КонСтрока - Число - номер последней строки из которой был прочитан элемент и его дочерние элементы
+// *Значения - Массив(Структура) - массив дочерних элементов
+// ДанныеСтроки - Строка - строка для разбора
+// СчетчикСимволов - Число - счетчик прочитанных символов переданной строки
+//
+Процедура ПрочитатьДанныеСтроки(ЭлементДляЗаполнения, ДанныеСтроки, СчетчикСимволов)
+
+ ТекСтрока = "";
+ КавычкиОткрыты = Ложь;
+ ПредСимвол = "";
+
+ ДлинаСтроки = СтрДлина(ДанныеСтроки);
+
+ // посимвольное чтение строки
+ Для НомерСимвола = СчетчикСимволов По ДлинаСтроки Цикл
+
+ ТекСимвол = Сред(ДанныеСтроки, НомерСимвола, 1);
+
+ Если КавычкиОткрыты Тогда // обработка строки внутри кавычек
+
+ Если ТекСимвол = """" Тогда
+
+ Если Сред(ДанныеСтроки, НомерСимвола, 2) = """""" Тогда // это экранированные кавычки внутри строки
+
+ ТекСтрока = ТекСтрока + Сред(ДанныеСтроки, НомерСимвола, 2);
+ НомерСимвола = НомерСимвола + 1;
+
+ Иначе // закрытие кавычек
+
+ ТекСтрока = ТекСтрока + ТекСимвол;
+ КавычкиОткрыты = Ложь;
+
+ КонецЕсли;
+
+ Иначе // любой символ добавляется к строке
+
+ ТекСтрока = ТекСтрока + ТекСимвол;
+
+ КонецЕсли;
+
+ ИначеЕсли ТекСимвол = """" Тогда // открытие кавычек
+
+ ТекСтрока = ТекСтрока + ТекСимвол;
+ КавычкиОткрыты = Истина;
+
+ ИначеЕсли ТекСимвол = "{" Тогда // открытие вложенного списка
+
+ Если ЭлементДляЗаполнения = Неопределено Тогда
+
+ ВремЭлементДляЗаполнения = ИнициализироватьЭлемент(Неопределено);
+ ЭлементДляЗаполнения = ВремЭлементДляЗаполнения;
+
+ Иначе
+
+ ВремЭлементДляЗаполнения = ИнициализироватьЭлемент(ЭлементДляЗаполнения);
+ ЭлементДляЗаполнения.Значения.Добавить(ВремЭлементДляЗаполнения);
+
+ КонецЕсли;
+
+ НомерСимвола = НомерСимвола + 1;
+
+ ПрочитатьДанныеСтроки(ВремЭлементДляЗаполнения, ДанныеСтроки, НомерСимвола);
+
+ Если НомерСимвола > СтрДлина(ДанныеСтроки) Тогда
+
+ ЭлементДляЗаполнения = ВремЭлементДляЗаполнения; // если строка закончилась, то "наверх" поднимается элемент текущего уровня
+ Возврат;
+
+ КонецЕсли;
+
+ ИначеЕсли ТекСимвол = "}" Тогда // закрытие вложенного списка
+
+ Если НЕ (ПредСимвол = "{" ИЛИ ПредСимвол = "}" ИЛИ ПредСимвол = "") Тогда
+
+ ЭлементДляЗаполнения.Значения.Добавить(ТекСтрока);
+ ТекСтрока = "";
+
+ КонецЕсли;
+
+ ЭлементДляЗаполнения = ЭлементДляЗаполнения.Родитель;
+
+ СчетчикСимволов = НомерСимвола + 1;
+ Возврат;
+
+ ИначеЕсли ТекСимвол = "," Тогда // добавление элемента текущего списка
+
+ Если НЕ (ПредСимвол = "}" ИЛИ ПредСимвол = "") Тогда
+
+ ЭлементДляЗаполнения.Значения.Добавить(ТекСтрока);
+ ТекСтрока = "";
+
+ КонецЕсли;
+
+ Иначе
+
+ ТекСтрока = ТекСтрока + ТекСимвол;
+
+ КонецЕсли;
+
+ ПредСимвол = ТекСимвол;
+
+ КонецЦикла;
+
+ СчетчикСимволов = НомерСимвола;
+
+КонецПроцедуры // ПрочитатьДанныеСтроки()
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\320\262\320\265\321\200\321\202\320\265\321\200.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\320\262\320\265\321\200\321\202\320\265\321\200.os"
new file mode 100644
index 0000000..ed6070a
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\232\320\276\320\275\320\262\320\265\321\200\321\202\320\265\321\200.os"
@@ -0,0 +1,236 @@
+///////////////////////////////////////////////////////////////////
+//
+// Методы конвертации шаблонов кода
+//
+// (с) BIA Technologies, LLC
+//
+///////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////
+// Программный интерфейс
+///////////////////////////////////////////////////////////////////
+
+// Метод преобразования формата шаблона
+//
+// Параметры:
+// ИмяВходногоФайла - Строка - Имя файла базового шаблона
+// ИмяВыходногоФайла - Строка - Имя файла нового шаблона
+//
+Процедура ПреобразоватьШаблон(ИмяВходногоФайла, ИмяВыходногоФайла) Экспорт
+
+ МодульЧтение = ПолучитьМодульРаботыСШаблоном(ИмяВходногоФайла);
+
+ ДанныеШаблона = МодульЧтение.ПрочитатьШаблон(ИмяВходногоФайла);
+
+ ЗаписатьСПроверкойДоступныхТипов(ДанныеШаблона, ИмяВыходногоФайла);
+
+КонецПроцедуры
+
+// Метода объединения нескольких шаблонов в один
+//
+// Параметры:
+// МассивВходныхФайлов - Массив - Массив файлов (тип:Файл) шаблонов, которые необходимо объединить
+// ИмяВыходногоФайла - Строка - Имя файла нового шаблона
+//
+Процедура СоединитьШаблоны(МассивВходныхФайлов, ИмяВыходногоФайла) Экспорт
+
+ Лог = МенеджерПриложения.ПолучитьЛог();
+
+ Читатели = Новый Соответствие();
+
+ Шаблон = Неопределено;
+
+ Для Каждого Файл Из МассивВходныхФайлов Цикл
+
+ Если НЕ Файл.ЭтоФайл() Тогда
+
+ Продолжить;
+
+ КонецЕсли;
+
+ Если Читатели[Файл.Расширение] = Неопределено Тогда
+
+ Читатель = ПолучитьМодульРаботыСШаблоном(Файл.ПолноеИмя);
+
+ Если Читатель = Неопределено Тогда
+
+ Лог.Предупреждение("Формат шаблона не поддерживается. Файл пропущен %1", Файл.Имя);
+ Продолжить;
+
+ КонецЕсли;
+
+ Читатели.Вставить(Файл.Расширение, Читатель);
+
+ КонецЕсли;
+
+ ШаблонФайла = Читатели[Файл.Расширение].ПрочитатьШаблон(Файл.ПолноеИмя);
+
+ Если Шаблон = Неопределено Тогда // Первый шаблон будет основным, необходимо для сохранения имени шаблона конфигуратора, при объединении двух шаблонов
+
+ Шаблон = ШаблонФайла;
+
+ Иначе
+
+ Для Каждого Элемент Из ШаблонФайла.Элементы Цикл // Последующие шаблоны будут закидываться в основной
+
+ Шаблон.Элементы.Добавить(Элемент);
+
+ КонецЦикла;
+
+ КонецЕсли;
+
+ КонецЦикла;
+
+ ЗаписатьСПроверкойДоступныхТипов(Шаблон, ИмяВыходногоФайла);
+
+КонецПроцедуры
+
+// Метод для переноса части элементов шаблона в отдельный файл
+// Анализ необходимости переноса выполняется по полному наименованию(включая иерархию)
+// на соответствие регулярному выражению
+//
+// Параметры:
+// ИзменяемыйШаблон - Строку - Имя файла анализируемого шаблона
+// ШаблонНаименования - Строка - Шаблон регулярного для проверки наименования элемента
+// РежимОбработкиНаименования - Строка - Способ обработки элементов
+// * equal - совпадающий элемент переносится в новый файл
+// * notequal - не совпадающий элемент переносится в новый файл
+// УдаляемыеДанныеПоложитьВ - Строка - Имя файла, в который происходит перенос
+//
+Процедура РазделитьШаблон(ИзменяемыйШаблон, ШаблонНаименования, ПереносПриНеСовпадении, УдаляемыеДанныеПоложитьВ = Неопределено) Экспорт
+
+ Модуль = ПолучитьМодульРаботыСШаблоном(ИзменяемыйШаблон);
+ Шаблон = Модуль.ПрочитатьШаблон(ИзменяемыйШаблон);
+
+ НовыйШаблон = ШаблоныБазовый.КорневойЭлемент();
+ РегулярноеВыражение = Новый РегулярноеВыражение(ШаблонНаименования);
+
+ РазделитьШаблонПоРегулярномуВыражению(Шаблон, РегулярноеВыражение, НовыйШаблон, НЕ ПереносПриНеСовпадении, "");
+
+ Модуль.ЗаписатьШаблон(Шаблон, ИзменяемыйШаблон);
+
+ Если УдаляемыеДанныеПоложитьВ <> Неопределено Тогда
+
+ ЗаписатьСПроверкойДоступныхТипов(НовыйШаблон, УдаляемыеДанныеПоложитьВ);
+
+ КонецЕсли;
+
+КонецПроцедуры
+
+///////////////////////////////////////////////////////////////////
+// Программный интерфейс
+///////////////////////////////////////////////////////////////////
+
+Процедура ЗаписатьСПроверкойДоступныхТипов(Шаблон, ИмяФайла, МодульЗаписи = Неопределено)
+
+ Если МодульЗаписи = Неопределено Тогда
+
+ МодульЗаписи = ПолучитьМодульРаботыСШаблоном(ИмяФайла);
+
+ КонецЕсли;
+
+ ДоступныеТипыПодстановок = МодульЗаписи.ДоступныеТипыПодстановок();
+ ФлагиТипов = Утилиты.СоответствиеФлагов(ДоступныеТипыПодстановок);
+ УдалитьНедоступныеШаблоны(Шаблон, ФлагиТипов);
+
+ МодульЗаписи.ЗаписатьШаблон(Шаблон, ИмяФайла);
+
+КонецПроцедуры
+
+Процедура УдалитьНедоступныеШаблоны(ДанныеШаблона, ДоступныеТипыПодстановок)
+
+ Лог = МенеджерПриложения.ПолучитьЛог();
+
+ Количество = ДанныеШаблона.Элементы.Количество();
+
+ Для Инд = 1 По Количество Цикл
+
+ Элемент = ДанныеШаблона.Элементы[Количество - Инд];
+
+ Если Элемент.Тип = "Элемент" Тогда
+
+ Для Каждого ЭлементШаблона Из Элемент.Шаблон Цикл
+
+ Если ТипЗнч(ЭлементШаблона) = Тип("Структура") И ДоступныеТипыПодстановок[ЭлементШаблона.Тип] = Неопределено Тогда
+
+ Лог.Предупреждение("Шаблон замены ""%1"" пропущен, так имеет неподдерживаемый тип ""%2""", Элемент.Наименование, ЭлементШаблона.Тип);
+ ДанныеШаблона.Элементы.Удалить(Количество - Инд);
+ Прервать;
+
+ КонецЕсли;
+
+ КонецЦикла;
+
+ ИначеЕсли Элемент.Тип = "Группа" Тогда
+
+ УдалитьНедоступныеШаблоны(Элемент, ДоступныеТипыПодстановок);
+
+ КонецЕсли;
+
+ КонецЦикла;
+
+КонецПроцедуры
+
+Функция ПолучитьМодульРаботыСШаблоном(ИмяФайла)
+
+ РасширениеФайла = (Новый Файл(ИмяФайла)).Расширение;
+
+ Если РасширениеФайла = ".st" Тогда
+
+ Возврат ШаблоныКонфигуратора;
+
+ ИначеЕсли РасширениеФайла = ".json" ИЛИ РасширениеФайла = ".code-snippets" Тогда
+
+ Возврат ШаблоныVSCode;
+
+ ИначеЕсли РасширениеФайла = ".xml" Тогда
+
+ Возврат ШаблоныEDT;
+
+ Иначе
+
+ МенеджерПриложения.ПолучитьЛог().Ошибка("Не поддерживаемый формат файла: %1" + РасширениеФайла);
+
+ КонецЕсли;
+
+КонецФункции
+
+Функция РазделитьШаблонПоРегулярномуВыражению(Шаблон, РегулярноеВыражение, НовыйШаблон, ПереносПриСовпадении, ПрефиксИмени)
+
+ КУдалению = Новый Массив();
+ Лог = МенеджерПриложения.ПолучитьЛог();
+
+ Для Каждого Элемент Из Шаблон.Элементы Цикл
+
+ Наименование = ПрефиксИмени + ?(Элемент.Тип = "Группа", Элемент.Наименование + ".", Элемент.Наименование);
+ НаименованиеСовпадаетСШаблоном = РегулярноеВыражение.Совпадает(Наименование);
+
+ Если (ПереносПриСовпадении И НаименованиеСовпадаетСШаблоном) ИЛИ (НЕ ПереносПриСовпадении И НЕ НаименованиеСовпадаетСШаблоном) Тогда
+
+ НовыйШаблон.Элементы.Добавить(Элемент);
+ КУдалению.Добавить(Элемент);
+ Лог.Информация("Элемент шаблона ""%1%2"" перенесен в другой файл", ПрефиксИмени, Элемент.Наименование)
+
+ ИначеЕсли Элемент.Тип = "Группа" Тогда
+
+ НоваяГруппа = ШаблоныБазовый.Группа();
+
+ Если РазделитьШаблонПоРегулярномуВыражению(Элемент, РегулярноеВыражение, НоваяГруппа, ПереносПриСовпадении, Наименование) Тогда
+
+ НовыйШаблон.Элементы.Добавить(НоваяГруппа);
+
+ КонецЕсли;
+
+ КонецЕсли;
+
+ КонецЦикла;
+
+ Для Каждого Элемент Из КУдалению Цикл
+
+ Шаблон.Элементы.Удалить(Шаблон.Элементы.Найти(Элемент));
+
+ КонецЦикла;
+
+ Возврат КУдалению.Количество();
+
+КонецФункции
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os"
new file mode 100644
index 0000000..3be5b05
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os"
@@ -0,0 +1,296 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Служебный модуль с набором методов работы с командами приложения
+//
+// В большинстве проектов изменять данный модуль не требуется
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#Использовать logos
+#Использовать cmdline
+
+///////////////////////////////////////////////////////////////////////////////
+
+Перем Лог;
+
+Перем ПарсерКоманд;
+Перем ИсполнителиКоманд;
+Перем ОбъектНастроек;
+
+///////////////////////////////////////////////////////////////////////////////
+// СЛУЖЕБНЫЙ ОТКРЫТЫЙ ПРОГРАММНЫЙ ИНТЕРФЕЙС
+///////////////////////////////////////////////////////////////////////////////
+
+// Инициализирует и настраивает приложение
+//
+// Параметры:
+// Настройка - Модуль - Модуль, в котором определены настройки приложения
+//
+// Возвращаемое значение:
+// Модуль - Модуль менеджера приложения
+//
+Функция Инициализировать(Знач МенеджерНастроек) Экспорт
+
+ // Служебные переменные
+ ПарсерКоманд = Новый ПарсерАргументовКоманднойСтроки();
+ ИсполнителиКоманд = Новый Соответствие;
+ ОбъектНастроек = МенеджерНастроек;
+
+ // Логирование
+ Лог = Логирование.ПолучитьЛог(ОбъектНастроек.ИмяЛогаСистемы());
+ Лог.УстановитьРаскладку(ОбъектНастроек);
+
+ // Инициализация команд
+ ОбъектНастроек.НастроитьКомандыПриложения(ЭтотОбъект);
+
+ Возврат ЭтотОбъект;
+
+КонецФункции
+
+// Добавляет команду в приложение
+//
+// Параметры:
+// ИмяКоманды - Строка - Имя команды
+// КлассРеализации - Строка - Имя файла класса, в котором реализована команда
+// ОписаниеКоманды - Строка - краткое описание назначения команды
+//
+Процедура ДобавитьКоманду(Знач ИмяКоманды, Знач КлассРеализации, Знач ОписаниеКоманды) Экспорт
+
+ Попытка
+ РеализацияКоманды = Новый(КлассРеализации);
+
+ Команда = ПарсерКоманд.ОписаниеКоманды(ИмяКоманды, ОписаниеКоманды);
+ ПарсерКоманд.ДобавитьКоманду(Команда);
+
+ РеализацияКоманды.НастроитьКоманду(Команда, ПарсерКоманд);
+
+ ИсполнителиКоманд.Вставить(ИмяКоманды, РеализацияКоманды);
+ Исключение
+ ЗавершитьРаботуПриложенияСОшибкой(СтрШаблон("Не удалось инициализировать команду '%1' для класса '%2' по причине:
+ |%3", ИмяКоманды, КлассРеализации, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
+ КонецПопытки;
+
+КонецПроцедуры
+
+// Аварийно завершает работу приложения с ошибкой
+//
+// Параметры:
+// Сообщение - Строка - Сообщение, которое будет выведено пользователю перед завершением
+// КодВозврата (не обязательный) - Число - Код возврата с которым будет закрыто приложение
+// Значение по умолчанию: "ОшибкаВремениВыполнения" -- 1
+//
+Процедура ЗавершитьРаботуПриложенияСОшибкой(Знач Сообщение, Знач КодВозврата = Неопределено) Экспорт
+
+ Если КодВозврата = Неопределено Тогда
+ КодВозврата = РезультатыКоманд().ОшибкаВремениВыполнения;
+ КонецЕсли;
+
+ Лог.КритичнаяОшибка(Сообщение);
+
+ ЗавершитьРаботу(КодВозврата);
+
+КонецПроцедуры
+
+// Завершает работу приложения
+//
+// Параметры:
+// КодВозврата (не обязательный) - Число - Код возврата с которым будет закрыто приложение
+// Значение по умолчанию: "Успех" -- 0
+//
+Процедура ЗавершитьРаботуПриложения(Знач КодВозврата = Неопределено) Экспорт
+
+ Если КодВозврата = Неопределено Тогда
+ КодВозврата = РезультатыКоманд().Успех;
+ КонецЕсли;
+
+ ЗавершитьРаботу(КодВозврата);
+
+КонецПроцедуры
+
+// Осуществляет запуск приложения на выполнение
+//
+// Возвращаемое значение:
+// Число - Код возврата выполнения команды приложения
+//
+Функция ЗапуститьВыполнение() Экспорт
+
+ Попытка
+ ПараметрыЗапуска = ПарсерКоманд.Разобрать(АргументыКоманднойСтроки);
+ Исключение
+ Лог.Отладка(ОписаниеОшибки());
+
+ Лог.Ошибка("Не удалось определить требуемое действие.");
+ ВывестиСправкуПоКомандам();
+
+ Возврат РезультатыКоманд().НеверныеПараметры;
+ КонецПопытки;
+
+ Команда = "";
+ ЗначенияПараметров = Неопределено;
+
+ Если ПараметрыЗапуска = Неопределено ИЛИ ПараметрыЗапуска.Количество() = 0 Тогда
+
+ ВывестиВерсию();
+ ВывестиСправкуПоКомандам();
+
+ Возврат РезультатыКоманд().НеверныеПараметры;
+
+ ИначеЕсли ТипЗнч(ПараметрыЗапуска) = Тип("Структура") Тогда
+
+ // это команда
+ Команда = ПараметрыЗапуска.Команда;
+ ЗначенияПараметров = ПараметрыЗапуска.ЗначенияПараметров;
+ Лог.Отладка("Выполняю команду продукта %1", Команда);
+
+ ИначеЕсли ЗначениеЗаполнено(ОбъектНастроек.ИмяКомандыПоУмолчанию()) Тогда
+
+ // это команда по-умолчанию
+ Команда = ОбъектНастроек.ИмяКомандыПоУмолчанию();
+ ЗначенияПараметров = ПараметрыЗапуска;
+ Лог.Отладка("Выполняю команду продукта по умолчанию %1", Команда);
+
+ Иначе
+
+ Возврат НекорректныеПараметры();
+
+ КонецЕсли;
+
+ Если Команда <> ОбъектНастроек.ИмяКомандыВерсия() Тогда
+
+ ВывестиВерсию();
+
+ КонецЕсли;
+
+ Возврат ВыполнитьКоманду(Команда, ЗначенияПараметров);
+
+КонецФункции // ЗапуститьВыполнение()
+
+// Осуществляет запуск на выполнение указанной команды приложения
+//
+// Параметры:
+// ИмяКоманды - Строка - Имя команды, которую необходимо запустить
+// ПараметрыКоманды - Соответствие - Соответствие ключей командной строки и их значений
+//
+Функция ВыполнитьКоманду(Знач ИмяКоманды, Знач ПараметрыКоманды) Экспорт
+
+ Команда = ПолучитьКоманду(ИмяКоманды);
+ КодВозврата = Команда.ВыполнитьКоманду(ПараметрыКоманды, ЭтотОбъект);
+
+ Если КодВозврата = Неопределено Тогда
+ КодВозврата = РезультатыКоманд().Успех;
+ КонецЕсли;
+
+ Возврат КодВозврата;
+
+КонецФункции // ВыполнитьКоманду
+
+///////////////////////////////////////////////////////////////////////////////
+// ПРОГРАММНЫЙ ИНТЕРФЕЙС
+///////////////////////////////////////////////////////////////////////////////
+
+// Возвращает лог приложения
+Функция ПолучитьЛог() Экспорт
+
+ Возврат Лог;
+
+КонецФункции // ПолучитьЛог
+
+// Возвращает версию продукта
+Функция ВерсияПродукта() Экспорт
+
+ Возврат ОбъектНастроек.ВерсияПродукта();
+
+КонецФункции // ВерсияПродукта
+
+// Возвращает имя продукта
+Функция ИмяПродукта() Экспорт
+
+ Возврат ОбъектНастроек.ИмяПродукта();
+
+КонецФункции // ИмяПродукта
+
+// Возвращает путь к исполняемому файлу
+Функция ПутьКИсполняемомуФайлу() Экспорт
+
+ Возврат ОбъектНастроек.ПутьКИсполняемомуФайлу();
+
+КонецФункции // ПутьКИсполняемомуФайлу
+
+// Возвращает путь к каталогу основного скрипта
+Функция ПутьКРодительскомуКаталогу() Экспорт
+
+ Возврат ОбъектНастроек.ПутьКРодительскомуКаталогу();
+
+КонецФункции // ПутьКРодительскомуКаталогу
+
+// Возвращает путь к каталогу сценариев
+Функция КаталогСценариев() Экспорт
+
+ Возврат ОбъектНастроек.КаталогСценариев();
+
+КонецФункции // КаталогСценариев
+
+// Выводит справку по всем командам приложения
+Процедура ВывестиСправкуПоКомандам() Экспорт
+
+ ПарсерКоманд.ВывестиСправкуПоКомандам();
+
+КонецПроцедуры // ВывестиСправкуПоКомандам
+
+// Выводит справку по указанной команде приложения.
+Процедура ВывестиСправкуПоКоманде(Знач ИмяКоманды) Экспорт
+
+ ПарсерКоманд.ВывестиСправкуПоКоманде(ИмяКоманды);
+
+КонецПроцедуры // ВывестиСправкуПоКоманде
+
+///////////////////////////////////////////////////////////////////////////////
+// ПЕРЕЧИСЛЕНИЯ
+///////////////////////////////////////////////////////////////////////////////
+
+// Возвращает стандартные коды возврата приложения
+Функция РезультатыКоманд() Экспорт
+
+ РезультатыКоманд = Новый Структура;
+ РезультатыКоманд.Вставить("Успех", 0);
+ РезультатыКоманд.Вставить("НеверныеПараметры", 5);
+ РезультатыКоманд.Вставить("ОшибкаВремениВыполнения", 1);
+
+ Возврат РезультатыКоманд;
+
+КонецФункции // РезультатыКоманд
+
+///////////////////////////////////////////////////////////////////////////////
+// СЛУЖЕБНЫЕ ПРОЦЕДУРЫ И ФУНКЦИИ
+///////////////////////////////////////////////////////////////////////////////
+
+// Получает объект класса с реализацией указанной команды
+Функция ПолучитьКоманду(Знач ИмяКоманды)
+
+ КлассРеализации = ИсполнителиКоманд[ИмяКоманды];
+ Если КлассРеализации = Неопределено Тогда
+
+ ВызватьИсключение СтрШаблон("Неверная операция. Команда '%1' не предусмотрена.", ИмяКоманды);
+
+ КонецЕсли;
+
+ Возврат КлассРеализации;
+
+КонецФункции // ПолучитьКоманду
+
+// Осуществляет вывод полной версии продукта
+Процедура ВывестиВерсию()
+
+ Сообщить(СтрШаблон("%1 v%2", ИмяПродукта(), ВерсияПродукта()));
+
+КонецПроцедуры // ВывестиВерсию
+
+// Вывод ошибки и справки по параметрам
+Функция НекорректныеПараметры()
+
+ Лог.Ошибка("Некорректные аргументы командной строки");
+ ВывестиСправкуПоКомандам();
+
+ Возврат РезультатыКоманд().НеверныеПараметры;
+
+КонецФункции // НекорректныеПараметры()
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os"
new file mode 100644
index 0000000..59b2da8
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\321\213\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os"
@@ -0,0 +1,156 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Служебный модуль с набором служебных параметров приложения
+//
+// При создании нового приложения обязательно внести изменение
+// в ф-ии ИмяПродукта, указав имя вашего приложения.
+//
+// При выпуске новой версии обязательно изменить ее значение
+// в ф-ии ВерсияПродукта
+//
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// СВОЙСТВА ПРОДУКТА
+///////////////////////////////////////////////////////////////////////////////
+
+// ВерсияПродукта
+// Возвращает текущую версию продукта
+//
+// Возвращаемое значение:
+// Строка - Значение текущей версии продукта
+//
+Функция ВерсияПродукта() Экспорт
+
+ Возврат "1.0.1";
+
+КонецФункции // ВерсияПродукта
+
+// ИмяПродукта
+// Возвращает имя продукта
+//
+// Возвращаемое значение:
+// Строка - Значение имени продукта
+//
+Функция ИмяПродукта() Экспорт
+
+ Возврат "snippet-transform";
+
+КонецФункции // ИмяПродукта
+
+// ПутьКИсполняемомуФайлу
+// Возвращает путь к исполняемому файлу
+//
+// Возвращаемое значение:
+// Строка - Путь к исполняемому файлу скрипта
+//
+Функция ПутьКИсполняемомуФайлу() Экспорт
+
+ Возврат ОбъединитьПути(ПутьКРодительскомуКаталогу(), "src", "main.os");
+
+КонецФункции // ПутьКИсполняемомуФайлу
+
+// ПутьКРодительскомуКаталогу
+// Возвращает путь к каталогу основного скрипта
+//
+// Возвращаемое значение:
+// Строка - Путь к каталогу основного скрипта
+//
+Функция ПутьКРодительскомуКаталогу() Экспорт
+
+ Файл = Новый Файл(ОбъединитьПути(ТекущийСценарий().Каталог, "..", ".."));
+ Возврат Файл.ПолноеИмя;
+
+КонецФункции // ПутьКРодительскомуКаталогу
+
+// КаталогСценариев
+// Возвращает путь к каталогу сценариев
+//
+// Возвращаемое значение:
+// Строка - Путь к каталогу сценариев
+//
+Функция КаталогСценариев() Экспорт
+
+ Возврат ОбъединитьПути(ПутьКРодительскомуКаталогу(), "src", "СценарииОбработки");
+
+КонецФункции // КаталогСценариев
+
+///////////////////////////////////////////////////////////////////////////////
+// ЛОГИРОВАНИЕ
+///////////////////////////////////////////////////////////////////////////////
+
+// Форматирование логов
+// См. описание метода "УстановитьРаскладку" библиотеки logos
+//
+Функция Форматировать(Знач Уровень, Знач Сообщение) Экспорт
+
+ Возврат СтрШаблон("%1: %2 - %3", ТекущаяДата(), УровниЛога.НаименованиеУровня(Уровень), Сообщение);
+
+КонецФункции
+
+// ИмяЛогаСистемы
+// Возвращает идентификатор лога приложения
+//
+// Возвращаемое значение:
+// Строка - Значение идентификатора лога приложения
+//
+Функция ИмяЛогаСистемы() Экспорт
+
+ Возврат "oscript.app." + ИмяПродукта();
+
+КонецФункции // ИмяЛогаСистемы
+
+///////////////////////////////////////////////////////////////////////////////
+// НАСТРОЙКА КОМАНД
+///////////////////////////////////////////////////////////////////////////////
+
+// Возвращает имя команды "version" (ключ командной строки)
+//
+// Возвращаемое значение:
+// Строка - имя команды
+//
+Функция ИмяКомандыВерсия() Экспорт
+
+ Возврат "version";
+
+КонецФункции // ИмяКомандыВерсия
+
+// Возвращает имя команды "help" (ключ командной строки)
+//
+// Возвращаемое значение:
+// Строка - имя команды
+//
+Функция ИмяКомандыПомощь() Экспорт
+
+ Возврат "help";
+
+КонецФункции // ИмяКомандыПомощь()
+
+// ИмяКомандыПоУмолчанию
+// Одна из команд может вызываться неявно, без указания команды.
+// Иными словами, здесь указывается какой обработчик надо вызывать, если приложение запущено без какой-либо команды
+// myapp /home/user/somefile.txt будет аналогично myapp default-action /home/user/somefile.txt
+//
+// Возвращаемое значение:
+// Строка - имя команды по умолчанию
+Функция ИмяКомандыПоУмолчанию() Экспорт
+
+ Возврат "convert";
+
+КонецФункции // ИмяКомандыПоУмолчанию
+
+// НастроитьКомандыПриложения
+// Регистрирует классы обрабатывающие команды приложения
+//
+// Параметры:
+// Приложение - Модуль - Модуль менеджера приложения
+Процедура НастроитьКомандыПриложения(Знач Приложение) Экспорт
+
+ Приложение.ДобавитьКоманду(ИмяКомандыПомощь(), "КомандаСправкаПоПараметрам", "Выводит справку по командам");
+ Приложение.ДобавитьКоманду(ИмяКомандыВерсия(), "КомандаVersion", "Выводит версию приложения");
+ Приложение.ДобавитьКоманду("convert", "КомандаConvert", "Преобразование шаблона кода, с автоматическим определением форматов на основании расширения");
+ Приложение.ДобавитьКоманду("join-files", "КомандаJoinFiles", "Выполняет объединение двух файлов шаблонов");
+ Приложение.ДобавитьКоманду("join-path", "КомандаJoinPath", "Выполняет объединение каталога файлов шаблонов");
+ Приложение.ДобавитьКоманду("apportion", "КомандаApportion", "Выполняет разделение шаблона, на основании регулярного выражения");
+
+КонецПроцедуры // ПриРегистрацииКомандПриложения
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\320\237\320\276\320\264\321\201\321\202\320\260\320\275\320\276\320\262\320\272\320\270.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\320\237\320\276\320\264\321\201\321\202\320\260\320\275\320\276\320\262\320\272\320\270.os"
new file mode 100644
index 0000000..71f8183
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\242\320\270\320\277\320\237\320\276\320\264\321\201\321\202\320\260\320\275\320\276\320\262\320\272\320\270.os"
@@ -0,0 +1,41 @@
+///////////////////////////////////////////////////////////////////
+//
+// Модуль-перечисления, типы блоков подставновки шаблонов
+//
+// (с) BIA Technologies, LLC
+//
+///////////////////////////////////////////////////////////////////
+
+Перем Неизвестный Экспорт;
+Перем УстановкаКурсора Экспорт;
+Перем ВыборВарианта Экспорт;
+Перем ДатаВремя Экспорт;
+
+///////////////////////////////////////////////////////////////////
+// Программный интерфейс
+///////////////////////////////////////////////////////////////////
+
+// Возвращает список всех доступных типов, тип "Неизвестный" не включен
+//
+// Возвращаемое значение:
+// Массив - Коллекция строк-идентификаторов доступных типов
+//
+Функция ВсеТипы() Экспорт
+
+ ТипыШаблонов = Новый Массив();
+
+ ТипыШаблонов.Добавить(УстановкаКурсора);
+ ТипыШаблонов.Добавить(ВыборВарианта);
+ ТипыШаблонов.Добавить(ДатаВремя);
+
+ Возврат ТипыШаблонов;
+
+КонецФункции
+
+///////////////////////////////////////////////////////////////////
+
+Неизвестный = "Неизвестный";
+УстановкаКурсора = "Установка курсора";
+ВыборВарианта = "Выбор варианта";
+ДатаВремя = "Дата время";
+
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\243\321\202\320\270\320\273\320\270\321\202\321\213.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\243\321\202\320\270\320\273\320\270\321\202\321\213.os"
new file mode 100644
index 0000000..e01975c
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\243\321\202\320\270\320\273\320\270\321\202\321\213.os"
@@ -0,0 +1,185 @@
+///////////////////////////////////////////////////////////////////
+//
+// Модуль-перечисления, типы блоков подставновки шаблонов
+//
+// (с) BIA Technologies, LLC
+//
+///////////////////////////////////////////////////////////////////
+
+Перем Кэш;
+
+///////////////////////////////////////////////////////////////////
+// Программный интерфейс
+///////////////////////////////////////////////////////////////////
+
+// Проверяет, является ли строка числом
+//
+// Параметры:
+// Строка - Строка - Проверяемая строка
+//
+// Возвращаемое значение:
+// Булево - Истина - число, Ложь - нет
+//
+Функция ЭтоЧисло(Строка) Экспорт
+
+ Возврат Кэш["ПроверкаЧисло"].Совпадает(Строка);
+
+КонецФункции
+
+// Удаляет последовательности символов в начале и конце строки
+//
+// Параметры:
+// Текст - Строка - Анализируемый текст
+// Символы - Строка - Строка удаляемых символов
+//
+// Возвращаемое значение:
+// Строка - Строка с удаленными символами
+//
+Функция УдалитьСимволыВНачалеИКонце(Знач Текст, Символы) Экспорт
+
+ Ключ = "УдалитьСимволыВНачалеИКонце-" + Символы;
+
+ Если Кэш[Ключ] = Неопределено Тогда
+
+ Шаблон = СтрШаблон("^[%1]*(.*?)[%1]*$", ЭкранироватьСлужебныеСимволыRegExp(Символы));
+
+ Кэш.Вставить(Ключ, Новый РегулярноеВыражение(Шаблон));
+
+ КонецЕсли;
+
+ Возврат Кэш[Ключ].Заменить(Текст, "$1");
+
+КонецФункции
+
+// Удаляет из строки символы
+//
+// Параметры:
+// Текст - Строка - Анализируемый текст
+// Символы - Строка - Строка удаляемых символов
+//
+// Возвращаемое значение:
+// Строка - Строка с удаленными символами
+//
+Функция УдалитьСимволы(Знач Текст, УдаляемыеСимволы) Экспорт
+
+ // Не корректно работает СтрРазделить https://github.com/EvilBeaver/OneScript/pull/851/commits
+ // Должно заработать на следующем релизе oscript 1.0.22
+ // Части = СтрРазделить(Текст, УдаляемыеСимволы);
+
+ // Возврат СтрСоединить(Части, "");
+
+ Ключ = "УдалитьСимволы" + УдаляемыеСимволы;
+ Если Кэш[Ключ] = Неопределено Тогда
+
+ Шаблон = СтрШаблон("[%1]", ЭкранироватьСлужебныеСимволыRegExp(УдаляемыеСимволы));
+
+ Кэш.Вставить(Ключ, Новый РегулярноеВыражение(Шаблон));
+
+ КонецЕсли;
+
+ Возврат Кэш[Ключ].Заменить(Текст, "");
+
+КонецФункции
+
+// На основании массива значений формирует соответствие, в качестве значения используется "ЗначениеФлага"
+//
+// Параметры:
+// Массив - Массив - Коллекция произвольных значений
+// ЗначениеФлага - Произвольный - Значение соответствия
+//
+// Возвращаемое значение:
+// Соответствие - Соответствие флагов
+//
+Функция СоответствиеФлагов(Массив, ЗначениеФлага = Истина) Экспорт
+
+ Результат = Новый Соответствие();
+
+ Для Каждого Элемент Из Массив Цикл
+
+ Результат.Вставить(Элемент, ЗначениеФлага);
+
+ КонецЦикла;
+
+ Возврат Результат;
+
+КонецФункции
+
+// Формирует имя переменной в формате CamelCase
+//
+// Параметры:
+// Текст - Строка - Текст на основании, которого будет сформировано имя переменной
+//
+// Возвращаемое значение:
+// Строка - Имя переменной
+//
+Функция СформироватьИдентификатор(Текст) Экспорт
+
+ Строка = "";
+
+ Для Каждого Совпадение Из Кэш["Слова"].НайтиСовпадения(Текст) Цикл
+
+ Строка = Строка + ВРег(Лев(Совпадение.Значение, 1)) + Сред(Совпадение.Значение, 2);
+
+ КонецЦикла;
+
+ Возврат Строка;
+
+КонецФункции
+
+// Выделяет из текста слова
+//
+// Параметры:
+// Строка - Строка - Анализируемый тест
+// ВернутьТакжеПозицию - Булево - Истина - формирует массив структур, содержащих инф о положении слова в тексте
+//
+// Возвращаемое значение:
+// Массив - Массив слов
+//
+Функция ПолучитьСлова(Строка, ВернутьТакжеПозицию = Ложь) Экспорт
+
+ Слова = Новый Массив();
+
+ Для Каждого Совпадение Из Кэш["Слова"].НайтиСовпадения(Строка) Цикл
+
+ Если ВернутьТакжеПозицию Тогда
+ Слова.Добавить(Новый Структура("Слово, Начало, Окончание", Совпадение.Значение, Совпадение.Индекс, Совпадение.Индекс + Совпадение.Длина));
+ Иначе
+ Слова.Добавить(Совпадение.Значение);
+ КонецЕсли;
+
+ КонецЦикла;
+
+ Возврат Слова;
+
+КонецФункции
+
+Функция ЭкранироватьСлужебныеСимволыRegExp(Символы)
+
+ СлужебныеСимволыРегулярногоВыражения = "^$.[]\";
+
+ Результат = "";
+
+ Для Инд = 1 По СтрДлина(Символы) Цикл
+
+ Символ = Сред(Символы, Инд, 1);
+
+ Если СтрНайти(СлужебныеСимволыРегулярногоВыражения, Символ) Тогда
+
+ Результат = СтрШаблон("%1\%2", Результат, Символ);
+
+ Иначе
+
+ Результат = Результат + Символ;
+
+ КонецЕсли;
+
+ КонецЦикла;
+
+ Возврат Результат;
+
+КонецФункции
+
+Кэш = Новый Соответствие();
+Кэш.Вставить("ПроверкаЧисло", Новый РегулярноеВыражение("\d+"));
+Кэш.Вставить("ФиксТекстЗамены", Новый РегулярноеВыражение("[\[\]]"));
+Кэш.Вставить("Слова", Новый РегулярноеВыражение("[\w\dА-Яа-я]+"));
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\250\320\260\320\261\320\273\320\276\320\275\321\213EDT.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\250\320\260\320\261\320\273\320\276\320\275\321\213EDT.os"
new file mode 100644
index 0000000..2868b43
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\250\320\260\320\261\320\273\320\276\320\275\321\213EDT.os"
@@ -0,0 +1,324 @@
+///////////////////////////////////////////////////////////////////
+//
+// Методы работы с шаблонами EDT
+//
+// (с) BIA Technologies, LLC
+//
+///////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////
+// Программный интерфейс
+///////////////////////////////////////////////////////////////////
+
+// Считывает шаблон кода в структуру
+//
+// Параметры:
+// ИмяФайлаШаблона - Строка - Имя файла шаблона
+// РазбиратьБлокиПодстановки - Булево - Выполнять ли разбор текста шаблона
+// Если выполняется объединение/разделение без изменения типа шаблона, то рекомендуется не выполнять анализ текста шаблона
+//
+// Возвращаемое значение:
+// Структура - Данные шаблона
+// Тип - ТИп узла шаблона
+// Наименование - имя узла
+// Значения - подчиненные узлы
+//
+Функция ПрочитатьШаблон(ИмяФайлаШаблона, РазбиратьБлокиПодстановки = Истина) Экспорт
+
+ Чтение = Новый ЧтениеXML;
+ Чтение.ОткрытьФайл(ИмяФайлаШаблона);
+
+ ДанныеШаблона = ШаблоныБазовый.КорневойЭлемент();
+
+ Пока Чтение.Прочитать() Цикл
+
+ Если Чтение.Имя = "template" И Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
+
+ Если Чтение.ЗначениеАтрибута("deleted") <> "false" ИЛИ Чтение.ЗначениеАтрибута("enabled") <> "true" Тогда
+
+ Продолжить;
+
+ КонецЕсли;
+
+ Элемент = ШаблоныБазовый.Элемент();
+ Элемент.Наименование = Чтение.ЗначениеАтрибута("description");
+ Элемент.ТекстЗамены = Чтение.ЗначениеАтрибута("name");
+ Элемент.Наименование = Чтение.ЗначениеАтрибута("description");
+
+ Чтение.Прочитать();
+
+ Если РазбиратьБлокиПодстановки Тогда
+ Элемент.Шаблон = ПрочитатьСтруктуруТекстаШаблона(Чтение.Значение, 1, Ложь);
+ Иначе
+ Элемент.Шаблон = Чтение.Значение;
+ КонецЕсли;
+
+ ДанныеШаблона.Элементы.Добавить(Элемент);
+
+ КонецЕсли;
+
+ КонецЦикла;
+
+ Чтение.Закрыть();
+
+ Возврат ДанныеШаблона;
+
+КонецФункции
+
+// Сохраняет шаблон в файл
+//
+// Параметры:
+// Шаблон - Структура - Данные шаблона
+// ИмяФайла - Строка - Имя файла шаблона
+//
+Процедура ЗаписатьШаблон(Шаблон, ИмяФайла) Экспорт
+
+ Запись = Новый ЗаписьXML();
+ Запись.ОткрытьФайл(ИмяФайла);
+
+ Запись.ЗаписатьОбъявлениеXML();
+ Запись.ЗаписатьНачалоЭлемента("templates");
+
+ РекурсивнаяЗаписьДереваШаблонов(Шаблон, Запись);
+ Запись.ЗаписатьКонецЭлемента();
+ Запись.Закрыть();
+
+КонецПроцедуры
+
+// Возвращает список поддерживаемых типов блоков подстановки
+//
+// Возвращаемое значение:
+// Массив - Массив строка, элементов перечисления ТипПодстановки
+//
+Функция ДоступныеТипыПодстановок() Экспорт
+
+ ДоступныеТипыПодстановок = Новый Массив();
+
+ ДоступныеТипыПодстановок.Добавить(ТипПодстановки.УстановкаКурсора);
+ ДоступныеТипыПодстановок.Добавить(ТипПодстановки.ДатаВремя);
+
+ Возврат ДоступныеТипыПодстановок;
+
+КонецФункции
+
+///////////////////////////////////////////////////////////////////
+// Служебный функционал
+///////////////////////////////////////////////////////////////////
+
+// Чтение
+
+Функция ПрочитатьСтруктуруТекстаШаблона(Текст, Позиция, ЧитаемВложенныйЭлемент = Ложь)
+
+ ПараметрыЧтения = Новый Структура();
+ ПараметрыЧтения.Вставить("КавычкаОткрыта", Ложь);
+ ПараметрыЧтения.Вставить("БлокЗамены", ЧитаемВложенныйЭлемент);
+ ПредыдущийСимвол = "";
+
+ ТекущаяСтрока = "";
+
+ Данные = Новый Массив();
+
+ ДлиннаСтроки = СтрДлина(Текст);
+
+ Пока Позиция <= ДлиннаСтроки Цикл
+
+ Символ = Сред(Текст, Позиция, 1);
+ Позиция = Позиция + 1;
+
+ Если Символ = Неопределено Тогда
+ Прервать;
+ КонецЕсли;
+
+ СимволОбработан = Ложь;
+
+ Если Символ = "{" И ПредыдущийСимвол = "$" Тогда
+
+ ТекущаяСтрока = Лев(ТекущаяСтрока, СтрДлина(ТекущаяСтрока) - 1);
+ Данные.Добавить(?(ПараметрыЧтения.БлокЗамены, СокрЛП(ТекущаяСтрока), ТекущаяСтрока));
+ ТекущаяСтрока = "";
+
+ СимволОбработан = Истина;
+ ВложенныйЭлемент = ПрочитатьСтруктуруТекстаШаблона(Текст, Позиция, Истина);
+ Данные.Добавить(ВложенныйЭлемент);
+
+ ИначеЕсли Символ = "}" И ПараметрыЧтения.БлокЗамены Тогда
+
+ Если ЗначениеЗаполнено(ТекущаяСтрока) Тогда
+ Данные.Добавить(?(ПараметрыЧтения.БлокЗамены, СокрЛП(ТекущаяСтрока), ТекущаяСтрока));
+ КонецЕсли;
+
+ СимволОбработан = Истина;
+ ПараметрыУправляющейКонструкции1с = ПрочитатьПараметрыПодстановки(Данные);
+ Возврат ПараметрыУправляющейКонструкции1с;
+
+ ИначеЕсли Символ = "," И ПараметрыЧтения.БлокЗамены И НЕ ПараметрыЧтения.КавычкаОткрыта Тогда
+
+ Данные.Добавить(?(ПараметрыЧтения.БлокЗамены, СокрЛП(ТекущаяСтрока), ТекущаяСтрока));
+ ТекущаяСтрока = "";
+ СимволОбработан = Истина;
+
+ ИначеЕсли Символ = """" И ПредыдущийСимвол <> "\" Тогда
+
+ ПараметрыЧтения.КавычкаОткрыта = НЕ ПараметрыЧтения.КавычкаОткрыта;
+
+ КонецЕсли;
+
+ Если Не СимволОбработан Тогда
+
+ ТекущаяСтрока = ТекущаяСтрока + Символ;
+
+ КонецЕсли;
+
+ ПредыдущийСимвол = Символ;
+
+ КонецЦикла;
+
+ Если ЗначениеЗаполнено(ТекущаяСтрока) Тогда
+ Данные.Добавить(?(ПараметрыЧтения.БлокЗамены, СокрЛП(ТекущаяСтрока), ТекущаяСтрока));
+ КонецЕсли;
+
+ Возврат Данные;
+
+КонецФункции
+
+Функция ПрочитатьПараметрыПодстановки(Данные)
+
+ Параметры = Новый Структура("Тип", ТипПодстановки.Неизвестный);
+
+ Если Данные.Количество() = 0 Тогда
+
+ Возврат Параметры;
+
+ КонецЕсли;
+
+ ИмяТип = Данные[0];
+
+ СоответствиеТипов = Новый Соответствие();
+ СоответствиеТипов.Вставить("date", ТипПодстановки.ДатаВремя);
+
+ Если СтрНайти(ИмяТип, ":") Тогда
+
+ Слова = Утилиты.ПолучитьСлова(ИмяТип, Истина);
+
+ Имя = Слова[0].Слово;
+ Тип = Слова[1].Слово;
+
+ Если СоответствиеТипов[Тип] <> Неопределено Тогда
+ Тип = СоответствиеТипов[Тип];
+ КонецЕсли;
+
+ Параметры.Тип = Тип;
+ Параметры.Вставить("Подсказка", Имя);
+
+ Аргументы = Сред(ИмяТип, Слова[1].Окончание + 1);
+
+ Иначе
+
+ Тип = СоответствиеТипов[ИмяТип];
+
+ Если Тип = Неопределено Тогда
+
+ Параметры.Тип = ТипПодстановки.УстановкаКурсора;
+ Параметры.Вставить("Подсказка", ИмяТип);
+
+ Иначе
+
+ Параметры.Тип = Тип;
+
+ КонецЕсли;
+
+ Аргументы = "";
+
+ КонецЕсли;
+
+ Если Параметры.Тип = ТипПодстановки.ДатаВремя Тогда
+
+ Параметры.Вставить("Формат", Утилиты.УдалитьСимволыВНачалеИКонце(Аргументы, "()"));
+
+ КонецЕсли;
+
+ Возврат Параметры;
+
+КонецФункции
+
+// Запись
+
+Процедура РекурсивнаяЗаписьДереваШаблонов(Шаблон, Запись)
+
+ Для Каждого Элемент Из Шаблон.Элементы Цикл
+
+ Если Элемент.Тип = "Группа" Тогда
+
+ РекурсивнаяЗаписьДереваШаблонов(Элемент, Запись);
+ Продолжить;
+
+ КонецЕсли;
+
+ Запись.ЗаписатьНачалоЭлемента("template");
+ Запись.ЗаписатьАтрибут("autoinsert", "true");
+ Запись.ЗаписатьАтрибут("context", "com._1c.g5.v8.dt.bsl.Bsl.AddHandlerStatement");
+ Запись.ЗаписатьАтрибут("deleted", "false");
+ Запись.ЗаписатьАтрибут("description", Элемент.Наименование);
+ Запись.ЗаписатьАтрибут("enabled", "true");
+ Запись.ЗаписатьАтрибут("name", Элемент.ТекстЗамены);
+ Запись.ЗаписатьТекст(СобратьТекстШаблона(Элемент.Шаблон));
+
+ Запись.ЗаписатьКонецЭлемента();
+
+ КонецЦикла;
+
+КонецПроцедуры
+
+Функция СобратьТекстШаблона(ДанныеШаблона)
+
+ Если ТипЗнч(ДанныеШаблона) = Тип("Строка") Тогда
+
+ Возврат ДанныеШаблона;
+
+ КонецЕсли;
+
+ Вывод = Новый ЗаписьJSON();
+ Вывод.УстановитьСтроку();
+ НомерЭлемента = 1;
+
+ Для Каждого Элемент Из ДанныеШаблона Цикл
+
+ Если ТипЗнч(Элемент) = Тип("Строка") Тогда
+
+ Вывод.ЗаписатьБезОбработки(Элемент);
+ Продолжить;
+
+ ИначеЕсли Элемент.Тип = ТипПодстановки.УстановкаКурсора Тогда
+
+ Если Элемент.Свойство("Подсказка") Тогда
+
+ Вывод.ЗаписатьБезОбработки(СтрШаблон("${%1}", Утилиты.СформироватьИдентификатор(Элемент.Подсказка)));
+
+ Иначе
+
+ Вывод.ЗаписатьБезОбработки("${cursor}");
+
+ КонецЕсли;
+
+ ИначеЕсли Элемент.Тип = ТипПодстановки.ДатаВремя Тогда
+
+ Если Элемент.Свойство("Подсказка") Тогда
+
+ Вывод.ЗаписатьБезОбработки(СтрШаблон("${%1:date(%2)}", Утилиты.СформироватьИдентификатор(Элемент.Подсказка), Элемент.Формат));
+
+ Иначе
+
+ Вывод.ЗаписатьБезОбработки(СтрШаблон("${n%1:date(%2)}", НомерЭлемента, Элемент.Формат));
+
+ КонецЕсли;
+
+ КонецЕсли;
+
+ НомерЭлемента = НомерЭлемента + 1;
+
+ КонецЦикла;
+
+ Возврат Вывод.Закрыть();
+
+КонецФункции
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\250\320\260\320\261\320\273\320\276\320\275\321\213VSCode.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\250\320\260\320\261\320\273\320\276\320\275\321\213VSCode.os"
new file mode 100644
index 0000000..ba9d282
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\250\320\260\320\261\320\273\320\276\320\275\321\213VSCode.os"
@@ -0,0 +1,208 @@
+///////////////////////////////////////////////////////////////////
+//
+// Методы работы с шаблонами VS Code
+//
+// (с) BIA Technologies, LLC
+//
+///////////////////////////////////////////////////////////////////
+
+// Некоторые описание шаблонов VS code https://github.com/1c-syntax/vsc-language-1c-bsl/wiki/Динамические-шаблоны
+
+///////////////////////////////////////////////////////////////////
+// Программный интерфейс
+///////////////////////////////////////////////////////////////////
+
+// Считывает шаблон кода в структуру
+//
+// Параметры:
+// ИмяФайлаШаблона - Строка - Имя файла шаблона
+// РазбиратьБлокиПодстановки - Булево - Выполнять ли разбор текста шаблона
+// Если выполняется объединение/разделение без изменения типа шаблона, то рекомендуется не выполнять анализ текста шаблона
+//
+// Возвращаемое значение:
+// Структура - Данные шаблона
+// Тип - ТИп узла шаблона
+// Наименование - имя узла
+// Значения - подчиненные узлы
+//
+Функция ПрочитатьШаблон(ИмяФайла, РазбиратьБлокиПодстановки = Истина) Экспорт
+
+ ВызватьИсключение "Метод не поддерживается";
+
+КонецФункции
+
+// Сохраняет шаблон в файл
+//
+// Параметры:
+// Шаблон - Структура - Данные шаблона
+// ИмяФайла - Строка - Имя файла шаблона
+//
+Процедура ЗаписатьШаблон(Шаблон, ИмяФайла) Экспорт
+
+ ВставлятьИдентификаторЯзыка = (Новый Файл(ИмяФайла)).Расширение = ".code-snippets";
+
+ ДанныеДляЗаписи = СформироватьОбъектШаблона(Шаблон, ВставлятьИдентификаторЯзыка);
+
+ Запись = Новый ЗаписьJSON();
+ Запись.ОткрытьФайл(ИмяФайла);
+
+ ЗаписатьJSON(Запись, ДанныеДляЗаписи);
+
+ Запись.Закрыть();
+
+КонецПроцедуры
+
+// Возвращает список поддерживаемых типов блоков подстановки
+//
+// Возвращаемое значение:
+// Массив - Массив строка, элементов перечисления ТипПодстановки
+//
+Функция ДоступныеТипыПодстановок() Экспорт
+
+ ДоступныеТипыПодстановок = Новый Массив();
+
+ ДоступныеТипыПодстановок.Добавить(ТипПодстановки.УстановкаКурсора);
+ ДоступныеТипыПодстановок.Добавить(ТипПодстановки.ВыборВарианта);
+ ДоступныеТипыПодстановок.Добавить(ТипПодстановки.ДатаВремя);
+
+ Возврат ДоступныеТипыПодстановок;
+
+КонецФункции
+
+///////////////////////////////////////////////////////////////////
+// Служебный функционал
+///////////////////////////////////////////////////////////////////
+
+Функция СформироватьОбъектШаблона(Шаблон, ВставлятьИдентификаторЯзыка, ШаблонVSCode = Неопределено)
+
+ Если ШаблонVSCode = Неопределено Тогда
+
+ ШаблонVSCode = Новый Соответствие();
+
+ КонецЕсли;
+
+ Для Каждого Элемент Из Шаблон.Элементы Цикл
+
+ Если Элемент.Тип = "Группа" Тогда
+
+ СформироватьОбъектШаблона(Элемент, ВставлятьИдентификаторЯзыка, ШаблонVSCode);
+ Продолжить;
+
+ КонецЕсли;
+
+ ЭлементШаблона = Новый Структура();
+ ЭлементШаблона.Вставить("prefix", Элемент.ТекстЗамены);
+ ЭлементШаблона.Вставить("body", СобратьТекстШаблона(Элемент.Шаблон));
+ ЭлементШаблона.Вставить("description", Элемент.Наименование);
+
+ Если ВставлятьИдентификаторЯзыка Тогда
+
+ ЭлементШаблона.Вставить("scope", "bsl");
+
+ КонецЕсли;
+
+ ШаблонVSCode.Вставить(Элемент.Наименование, ЭлементШаблона);
+
+ КонецЦикла;
+
+ Возврат ШаблонVSCode;
+
+КонецФункции
+
+Функция СобратьТекстШаблона(ДанныеШаблона)
+
+ Параметры = Новый Структура("Номер", 1);
+
+ Вывод = Новый ЗаписьJSON();
+ Вывод.УстановитьСтроку();
+
+ Для Каждого Элемент Из ДанныеШаблона Цикл
+
+ Если ТипЗнч(Элемент) = Тип("Строка") Тогда
+
+ Вывод.ЗаписатьБезОбработки(Элемент);
+ Продолжить;
+
+ ИначеЕсли Элемент.Тип = ТипПодстановки.УстановкаКурсора Тогда
+
+ Если Элемент.Свойство("Подсказка") Тогда
+
+ Вывод.ЗаписатьБезОбработки(СтрШаблон("${%1:%2}", Параметры.Номер, ОбработатьКавычки(Элемент.Подсказка)));
+
+ Иначе
+
+ Вывод.ЗаписатьБезОбработки(СтрШаблон("$%1", Параметры.Номер));
+
+ КонецЕсли;
+
+ ИначеЕсли Элемент.Тип = ТипПодстановки.ВыборВарианта Тогда
+
+ Вывод.ЗаписатьБезОбработки(СтрШаблон("${%1|", Параметры.Номер));
+
+ Первый = Истина;
+ Для Каждого ЭлементВыбора Из Элемент.СписокВыбора Цикл
+
+ Если Первый Тогда
+ Вывод.ЗаписатьБезОбработки(ОбработатьКавычки(ЭлементВыбора.Значение));
+ Первый = Ложь;
+ Иначе
+ Вывод.ЗаписатьБезОбработки("," + ОбработатьКавычки(ЭлементВыбора.Значение));
+ КонецЕсли;
+
+ КонецЦикла;
+
+ Вывод.ЗаписатьБезОбработки("|}");
+
+ ИначеЕсли Элемент.Тип = ТипПодстановки.ДатаВремя Тогда
+
+ Вывод.ЗаписатьБезОбработки(ВыводТекущейДаты(Элемент.Формат));
+
+ КонецЕсли;
+
+ Параметры.Номер = Параметры.Номер + 1;
+
+ КонецЦикла;
+
+ Возврат Вывод.Закрыть();
+
+КонецФункции
+
+Функция ОбработатьКавычки(Знач Текст)
+
+ Текст = СтрЗаменить(Текст, "\""", """");
+
+ Если Лев(Текст, 1) = """" Тогда
+
+ Текст = Сред(Текст, 2, СтрДлина(Текст) - 1);
+
+ КонецЕсли;
+
+ Если Прав(Текст, 1) = """" Тогда
+
+ Текст = Сред(Текст, 1, СтрДлина(Текст) - 1);
+
+ КонецЕсли;
+
+ Возврат Текст;
+
+КонецФункции
+
+Функция ВыводТекущейДаты(Формат)
+
+ Результат = Формат;
+ Замены = Новый СписокЗначений();
+ Замены.Добавить("dd", "CURRENT_DATE");
+ Замены.Добавить("MM", "CURRENT_MONTH");
+ Замены.Добавить("yyyy", "CURRENT_YEAR");
+ Замены.Добавить("yyy", "CURRENT_YEAR");
+ Замены.Добавить("yy", "CURRENT_YEAR_SHORT");
+
+ Для Каждого Элемент Из Замены Цикл
+
+ Результат = СтрЗаменить(Результат, Элемент.Значение, "$" + Элемент.Представление);
+
+ КонецЦикла;
+
+ Возврат Результат;
+
+КонецФункции
\ No newline at end of file
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\250\320\260\320\261\320\273\320\276\320\275\321\213\320\221\320\260\320\267\320\276\320\262\321\213\320\271.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\250\320\260\320\261\320\273\320\276\320\275\321\213\320\221\320\260\320\267\320\276\320\262\321\213\320\271.os"
new file mode 100644
index 0000000..e06d49e
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\250\320\260\320\261\320\273\320\276\320\275\321\213\320\221\320\260\320\267\320\276\320\262\321\213\320\271.os"
@@ -0,0 +1,49 @@
+///////////////////////////////////////////////////////////////////
+//
+// Базовые методы для работы с шаблонами
+//
+// (с) BIA Technologies, LLC
+//
+///////////////////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////////////////
+// Программный интерфейс
+///////////////////////////////////////////////////////////////////
+
+// Инициализирует структуру корневого элемента шаблона
+//
+// Возвращаемое значение:
+// Структура - Описание корневого элемента
+//
+Функция КорневойЭлемент() Экспорт
+
+ Возврат Новый Структура("Тип, Наименование, Элементы", "Корень", "Корень", Новый Массив());
+
+КонецФункции
+
+// Инициализирует структуру группы шаблона
+//
+// Возвращаемое значение:
+// Структура - Описание группы шаблона
+//
+Функция Группа() Экспорт
+
+ Возврат Новый Структура("Тип, Наименование, Элементы", "Группа", "", Новый Массив());
+
+КонецФункции
+
+// Инициализирует структуру элемента шаблона
+//
+// Возвращаемое значение:
+// Структура - Описание элемента шаблона
+//
+Функция Элемент() Экспорт
+
+ Возврат Новый Структура("Тип, Наименование, ТекстЗамены, Шаблон", "Элемент");
+
+КонецФункции
+
+///////////////////////////////////////////////////////////////////
+// Служебный функционал
+///////////////////////////////////////////////////////////////////
\ No newline at end of file
diff --git "a/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\250\320\260\320\261\320\273\320\276\320\275\321\213\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\202\320\276\321\200\320\260.os" "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\250\320\260\320\261\320\273\320\276\320\275\321\213\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\202\320\276\321\200\320\260.os"
new file mode 100644
index 0000000..3d5d5af
--- /dev/null
+++ "b/src/\320\234\320\276\320\264\321\203\320\273\320\270/\320\250\320\260\320\261\320\273\320\276\320\275\321\213\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\202\320\276\321\200\320\260.os"
@@ -0,0 +1,469 @@
+///////////////////////////////////////////////////////////////////
+//
+// Методы работы с шаблонами конфигуратора
+//
+// (с) BIA Technologies, LLC
+//
+///////////////////////////////////////////////////////////////////
+
+#Использовать strings
+
+///////////////////////////////////////////////////////////////////
+// Программный интерфейс
+///////////////////////////////////////////////////////////////////
+
+// Считывает шаблон кода в структуру
+//
+// Параметры:
+// ИмяФайлаШаблона - Строка - Имя файла шаблона
+// РазбиратьБлокиПодстановки - Булево - Выполнять ли разбор текста шаблона
+// Если выполняется объединение/разделение без изменения типа шаблона, то рекомендуется не выполнять анализ текста шаблона
+//
+// Возвращаемое значение:
+// Структура - Данные шаблона
+// Тип - ТИп узла шаблона
+// Наименование - имя узла
+// Значения - подчиненные узлы
+//
+Функция ПрочитатьШаблон(ИмяФайлаШаблона, РазбиратьБлокиПодстановки = Истина) Экспорт
+
+ Читатель = Новый ЧтениеВнутреннийФормат1С();
+ Дерево = Читатель.ПрочитатьФайл(ИмяФайлаШаблона);
+
+ КорневойЭлемент = ШаблоныБазовый.КорневойЭлемент();
+ ПрочитатьУзелШаблона(Дерево.Значения[0], КорневойЭлемент, РазбиратьБлокиПодстановки);
+
+ Возврат КорневойЭлемент.Элементы[0];
+
+КонецФункции
+
+// Сохраняет шаблон в файл
+//
+// Параметры:
+// Шаблон - Структура - Данные шаблона
+// ИмяФайла - Строка - Имя файла шаблона
+//
+Процедура ЗаписатьШаблон(Шаблон, ИмяФайла) Экспорт
+
+ Запись = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
+ Запись.ЗаписатьСтроку("{1,");
+
+ ЗаписатьГруппуШаблона(Шаблон, Запись);
+
+ Запись.Записать(Символы.ПС + "}");
+
+ Запись.Закрыть();
+
+КонецПроцедуры
+
+// Возвращает список поддерживаемых типов блоков подстановки
+//
+// Возвращаемое значение:
+// Массив - Массив строка, элементов перечисления ТипПодстановки
+//
+Функция ДоступныеТипыПодстановок() Экспорт
+
+ ДоступныеТипыПодстановок = ТипПодстановки.ВсеТипы();
+
+ Возврат ДоступныеТипыПодстановок;
+
+КонецФункции
+
+///////////////////////////////////////////////////////////////////
+// Служебный функционал
+///////////////////////////////////////////////////////////////////
+
+// Чтение
+
+Функция ПрочитатьУзелШаблона(Знач Элемент, Знач Родитель, РазбиратьБлокиПодстановки)
+
+ КоллекцияЭлементов = Элемент.Значения;
+
+ ЭтоКоллекция = Утилиты.ЭтоЧисло(КоллекцияЭлементов[0]);
+ ЭтоГруппа = НЕ ЭтоКоллекция И КоллекцияЭлементов[1] = "1";
+ ЭтоЭлемент = НЕ ЭтоКоллекция И КоллекцияЭлементов[1] = "0";
+
+ Если ЭтоГруппа Тогда
+
+ ОписаниеЭлемента = ШаблоныБазовый.Группа();
+ ОписаниеЭлемента.Вставить("Наименование", ОбработатьКавычкиПриЧтении(КоллекцияЭлементов[0]));
+ Родитель.Элементы.Добавить(ОписаниеЭлемента);
+
+ Возврат ОписаниеЭлемента;
+
+ ИначеЕсли ЭтоЭлемент Тогда
+
+ ОписаниеЭлемента = ШаблоныБазовый.Элемент();
+ ОписаниеЭлемента.Наименование = ОбработатьКавычкиПриЧтении(КоллекцияЭлементов[0]);
+ ОписаниеЭлемента.ТекстЗамены = Утилиты.УдалитьСимволы(ОбработатьКавычкиПриЧтении(КоллекцияЭлементов[3]), "[]");
+ ОписаниеЭлемента.Вставить("ТекстЗаменыБазовый", ОбработатьКавычкиПриЧтении(КоллекцияЭлементов[3]));
+
+ Если РазбиратьБлокиПодстановки Тогда
+ ОписаниеЭлемента.Шаблон = ПрочитатьСтруктуруТекстаШаблона(ОбработатьКавычкиПриЧтении(КоллекцияЭлементов[4]), 1);
+ Иначе
+ ОписаниеЭлемента.Шаблон = ОбработатьКавычкиПриЧтении(КоллекцияЭлементов[4]);
+ КонецЕсли;
+
+ Родитель.Элементы.Добавить(ОписаниеЭлемента);
+
+ Возврат ОписаниеЭлемента;
+
+ ИначеЕсли ЭтоКоллекция Тогда
+
+ Для Инд = 1 По КоллекцияЭлементов.ВГраница() Цикл
+
+ Элемент = ПрочитатьУзелШаблона(КоллекцияЭлементов[Инд], Родитель, РазбиратьБлокиПодстановки);
+
+ Если Элемент <> Неопределено И Элемент.Тип = "Группа" Тогда
+
+ Родитель = Элемент;
+
+ КонецЕсли;
+
+ КонецЦикла;
+
+ КонецЕсли;
+
+КонецФункции
+
+Функция ПрочитатьСтруктуруТекстаШаблона(Текст, Позиция, ЧитаемВложенныйЭлемент = Ложь)
+
+ ПараметрыЧтения = Новый Структура();
+ ПараметрыЧтения.Вставить("КавычкаОткрыта", Ложь);
+ ПараметрыЧтения.Вставить("БлокЗамены", ЧитаемВложенныйЭлемент);
+ ПараметрыЧтения.Вставить("ПредыдущийСимвол", "");
+
+ ТекущаяСтрока = "";
+
+ ДанныеТекстаШаблона = Новый Массив();
+ ДлиннаСтроки = СтрДлина(Текст);
+
+ Пока Позиция <= ДлиннаСтроки Цикл
+
+ Символ = Сред(Текст, Позиция, 1);
+
+ Позиция = Позиция + 1;
+
+ ПараметрыСимвола = ПолучитьПараметрыСимвола(Символ, ПараметрыЧтения);
+
+ Если ПараметрыСимвола.ФиксацияТекущейСтроки.Фиксировать Тогда
+
+ Если ПараметрыСимвола.ФиксацияТекущейСтроки.УдалитьПрошлыйСимвол Тогда
+
+ СтроковыеФункции.УдалитьПоследнийСимволВСтроке(ТекущаяСтрока);
+
+ КонецЕсли;
+
+ Если НЕ ПараметрыСимвола.ФиксацияТекущейСтроки.ПроверятьЗаполненность ИЛИ ЗначениеЗаполнено(ТекущаяСтрока) Тогда
+
+ ДобавитьЭлементТекстаШаблон(ДанныеТекстаШаблона, ТекущаяСтрока, ПараметрыЧтения); // Фиксируем то, что было до блока
+
+ КонецЕсли;
+
+ ТекущаяСтрока = "";
+
+ КонецЕсли;
+
+ Если ПараметрыСимвола.Тип = "НачалоБлокаПодстановки" Тогда
+
+ ВложенныйЭлемент = ПрочитатьСтруктуруТекстаШаблона(Текст, Позиция, Истина);
+ ДобавитьЭлементТекстаШаблон(ДанныеТекстаШаблона, ВложенныйЭлемент, ПараметрыЧтения);
+
+ ИначеЕсли ПараметрыСимвола.Тип = "ОкончаниеБлокаПодстановки" Тогда
+
+ ПараметрыПодстановки = РазобратьПараметрыПодстановки(ДанныеТекстаШаблона);
+ Возврат ПараметрыПодстановки;
+
+ ИначеЕсли ПараметрыСимвола.Тип = "РазделительПараметровБлока" Тогда
+
+ ИначеЕсли ПараметрыСимвола.Тип = "Кавычка" Тогда
+
+ ПараметрыЧтения.КавычкаОткрыта = НЕ ПараметрыЧтения.КавычкаОткрыта;
+
+ ИначеЕсли НЕ ПараметрыСимвола.Тип = "Неизвестный" Тогда
+
+ ВызватьИсключение "Неизвестный тип символа";
+
+ КонецЕсли;
+
+ Если ПараметрыСимвола.ЗаписатьВПоток Тогда
+
+ ТекущаяСтрока = ТекущаяСтрока + Символ;
+
+ КонецЕсли;
+
+ ПараметрыЧтения.ПредыдущийСимвол = Символ;
+
+ КонецЦикла;
+
+ Если ЗначениеЗаполнено(ТекущаяСтрока) Тогда // Фиксируем последний блок текста
+
+ ДобавитьЭлементТекстаШаблон(ДанныеТекстаШаблона, ТекущаяСтрока, ПараметрыЧтения);
+
+ КонецЕсли;
+
+ Возврат ДанныеТекстаШаблона;
+
+КонецФункции
+
+Функция ПолучитьПараметрыСимвола(Символ, ПараметрыЧтения)
+
+ Параметры = Новый Структура("Тип, ЗаписатьВПоток", "Неизвестный", Истина);
+ Параметры.Вставить("ФиксацияТекущейСтроки", Новый Структура("Фиксировать, ПроверятьЗаполненность, УдалитьПрошлыйСимвол", Ложь, Истина, Ложь));
+
+ Если Символ = "?" И ПараметрыЧтения.ПредыдущийСимвол = "<" Тогда
+
+ Параметры.Тип = "НачалоБлокаПодстановки";
+ Параметры.ЗаписатьВПоток = Ложь;
+ Параметры.ФиксацияТекущейСтроки.Фиксировать = Истина;
+ Параметры.ФиксацияТекущейСтроки.УдалитьПрошлыйСимвол = Истина;
+
+ ИначеЕсли Символ = """" И ПараметрыЧтения.ПредыдущийСимвол <> "\" Тогда
+
+ Параметры.Тип = "Кавычка";
+
+ КонецЕсли;
+
+ Если ПараметрыЧтения.КавычкаОткрыта Тогда
+ Возврат Параметры;
+ КонецЕсли;
+
+ Если Символ = ">" И ПараметрыЧтения.БлокЗамены Тогда // Завершение блока замены
+
+ Параметры.Тип = "ОкончаниеБлокаПодстановки";
+ Параметры.ЗаписатьВПоток = Ложь;
+ Параметры.ФиксацияТекущейСтроки.Фиксировать = Истина;
+
+ ИначеЕсли Символ = "," И ПараметрыЧтения.БлокЗамены Тогда
+
+ Параметры.Тип = "РазделительПараметровБлока";
+ Параметры.ЗаписатьВПоток = Ложь;
+ Параметры.ФиксацияТекущейСтроки.Фиксировать = Истина;
+ Параметры.ФиксацияТекущейСтроки.ПроверятьЗаполненность = Ложь;
+
+ КонецЕсли;
+
+ Возврат Параметры;
+
+КонецФункции
+
+Процедура ДобавитьЭлементТекстаШаблон(ДанныеТекстаШаблона, Элемент, ПараметрыЧтения)
+
+ Если ТипЗнч(Элемент) = Тип("Структура") Тогда
+
+ ДанныеТекстаШаблона.Добавить(Элемент);
+
+ ИначеЕсли НЕ ПараметрыЧтения.БлокЗамены Тогда
+
+ ДанныеТекстаШаблона.Добавить(Элемент);
+
+ Иначе
+
+ ДанныеТекстаШаблона.Добавить(СокрЛП(Элемент));
+
+ КонецЕсли;
+
+КонецПроцедуры
+
+Функция РазобратьПараметрыПодстановки(Данные)
+
+ Параметры = Новый Структура("Тип", ТипПодстановки.Неизвестный);
+ КоличествоЭлементов = Данные.Количество();
+
+ Если КоличествоЭлементов = 0 Тогда // Пустой блок подстановки - установка курсора
+
+ Параметры.Тип = ТипПодстановки.УстановкаКурсора;
+ Возврат Параметры;
+
+ КонецЕсли;
+
+ Параметры.Вставить("Подсказка", Данные[0]);
+
+ Если КоличествоЭлементов = 1 Тогда
+
+ Параметры.Тип = ТипПодстановки.УстановкаКурсора;
+ Возврат Параметры;
+
+ КонецЕсли;
+
+ Тип = Данные[1];
+
+ Если Тип = "ВыборВарианта" Тогда
+
+ Параметры.Тип = ТипПодстановки.ВыборВарианта;
+
+ Параметры.Вставить("СписокВыбора", Новый СписокЗначений());
+ Для Инд = 2 По КоличествоЭлементов - 1 Цикл
+
+ Параметры.СписокВыбора.Добавить(Данные[Инд + 1], Данные[Инд]);
+ Инд = Инд + 1;
+
+ КонецЦикла;
+
+ ИначеЕсли Тип = "ДатаВремя" Тогда
+
+ Параметры.Тип = ТипПодстановки.ДатаВремя;
+ Формат = Данные[2];
+ ПозРавно = СтрНайти(Формат, "=");
+
+ Если ПозРавно Тогда
+ ПозТчкЗпт = СтрНайти(Формат, ";", , ПозРавно);
+ ПозТчкЗпт = ?(ПозТчкЗпт = 0, СтрДлина(Формат), ПозТчкЗпт);
+ Формат = Сред(Формат, ПозРавно + 1, ПозТчкЗпт - ПозРавно - 1);
+ КонецЕсли;
+
+ Параметры.Вставить("Формат", Формат);
+
+ Иначе
+
+ Параметры.Тип = Тип;
+
+ КонецЕсли;
+
+ Возврат Параметры;
+
+КонецФункции
+
+Функция ОбработатьКавычкиПриЧтении(Знач Текст)
+
+ Текст = СтрЗаменить(Текст, """""", """");
+
+ Если Лев(Текст, 1) = """" Тогда
+
+ Текст = Сред(Текст, 2, СтрДлина(Текст) - 1);
+
+ КонецЕсли;
+
+ Если Прав(Текст, 1) = """" Тогда
+
+ Текст = Сред(Текст, 1, СтрДлина(Текст) - 1);
+
+ КонецЕсли;
+
+ Возврат Текст;
+
+КонецФункции
+
+// Запись
+
+Процедура ЗаписатьГруппуШаблона(Данные, Запись)
+
+ // запишем начало блока + количество дочерних элементов
+ Запись.ЗаписатьСтроку(СтрШаблон(
+ "{%1,", Данные.Элементы.Количество()));
+
+ ЗаписатьЗаголовокГруппы(Данные, Запись); // Заголовок блока
+
+ Для Индекс = 0 По Данные.Элементы.ВГраница() Цикл
+
+ Элемент = Данные.Элементы[Индекс];
+
+ Запись.ЗаписатьСтроку(",");
+
+ Если Элемент.Тип = "Группа" Тогда
+
+ ЗаписатьГруппуШаблона(Элемент, Запись);
+
+ Иначе // Элемент
+
+ ЗаписатьЭлементШаблона(Элемент, Запись);
+
+ КонецЕсли;
+
+ КонецЦикла;
+
+ Запись.ЗаписатьСтроку("");
+ Запись.Записать("}"); // Конец блока
+
+КонецПроцедуры
+
+Процедура ЗаписатьЗаголовокГруппы(ОписаниеГруппы, Запись)
+
+ Запись.Записать(СтрШаблон("{""%1"",1,0,"""",""""}", ОписаниеГруппы.Наименование));
+
+КонецПроцедуры
+
+Процедура ЗаписатьЭлементШаблона(ОписаниеЭлемента, Запись)
+
+ Запись.ЗаписатьСтроку("{0,");
+
+ Если ОписаниеЭлемента.Свойство("ТекстЗаменыБазовый") И ЗначениеЗаполнено(ОписаниеЭлемента.ТекстЗаменыБазовый) Тогда
+ ТекстЗамены = ОписаниеЭлемента.ТекстЗаменыБазовый;
+ ИначеЕсли СтрНайти(ОписаниеЭлемента.ТекстЗамены, "[") Тогда
+ ТекстЗамены = ОписаниеЭлемента.ТекстЗамены;
+ Иначе
+ ТекстЗамены = СтрШаблон("%1[%2]", Лев(ОписаниеЭлемента.ТекстЗамены, 1), Сред(ОписаниеЭлемента.ТекстЗамены, 2));
+ КонецЕсли;
+
+ ТелоШаблон = СобратьТекстШаблона(ОписаниеЭлемента.Шаблон);
+
+ Запись.Записать(СтрШаблон("{""%1"",0,0,""%2"",""%3""}", ОписаниеЭлемента.Наименование, ТекстЗамены, ТелоШаблон));
+
+ Запись.ЗаписатьСтроку("");
+ Запись.Записать("}");
+
+КонецПроцедуры
+
+Функция СобратьТекстШаблона(ДанныеШаблона)
+
+ Если ТипЗнч(ДанныеШаблона) = Тип("Строка") Тогда
+
+ Возврат ОбработатьКавычкиПриЗаписи(ДанныеШаблона);
+
+ КонецЕсли;
+
+ Вывод = Новый ЗаписьJSON();
+ Вывод.УстановитьСтроку();
+
+ Для Каждого Элемент Из ДанныеШаблона Цикл
+
+ Если ТипЗнч(Элемент) = Тип("Строка") Тогда
+ Вывод.ЗаписатьБезОбработки(ОбработатьКавычкиПриЗаписи(Элемент));
+ Продолжить;
+ КонецЕсли;
+
+ Вывод.ЗаписатьБезОбработки("");
+ Если Элемент.Свойство("Подсказка") Тогда
+ Вывод.ЗаписатьБезОбработки(СтрШаблон("""%1""", Элемент.Подсказка));
+ КонецЕсли;
+
+ Если Элемент.Тип = ТипПодстановки.ВыборВарианта Тогда
+
+ Вывод.ЗаписатьБезОбработки(", ВыборВарианта");
+
+ Для Каждого ЭлементВыбора Из Элемент.СписокВыбора Цикл
+
+ Если ЗначениеЗаполнено(ЭлементВыбора.Представление) Тогда
+ Вывод.ЗаписатьБезОбработки(", " + ЭлементВыбора.Представление);
+ Иначе
+ Вывод.ЗаписатьБезОбработки(", " + ЭлементВыбора.Значение);
+ КонецЕсли;
+ Вывод.ЗаписатьБезОбработки(", " + ЭлементВыбора.Значение);
+
+ КонецЦикла;
+
+ ИначеЕсли Элемент.Тип = ТипПодстановки.ДатаВремя Тогда
+
+ Если Элемент.Свойство("Формат") Тогда
+ Вывод.ЗаписатьБезОбработки(СтрШаблон(", ДатаВремя, """"ДФ=%1""""", Элемент.Формат));
+ Иначе
+ Вывод.ЗаписатьБезОбработки(", ДатаВремя");
+ КонецЕсли;
+
+ КонецЕсли;
+
+ Вывод.ЗаписатьБезОбработки(">");
+
+ КонецЦикла;
+
+ Возврат Вывод.Закрыть();
+
+КонецФункции
+
+Функция ОбработатьКавычкиПриЗаписи(Текст)
+
+ Текст = СтрЗаменить(Текст, """", """""");
+
+ Возврат Текст;
+
+КонецФункции
diff --git a/tasks/test-feature.os b/tasks/test-feature.os
new file mode 100644
index 0000000..ece94e0
--- /dev/null
+++ b/tasks/test-feature.os
@@ -0,0 +1,18 @@
+#Использовать ".."
+#Использовать 1bdd
+
+КаталогФич = ОбъединитьПути(".", "features");
+ПутьФичи = ОбъединитьПути(".", "features", АргументыКоманднойСтроки[0]);
+Файл_КаталогФич = Новый Файл(КаталогФич);
+ФайлФичи = Новый Файл(ПутьФичи);
+
+ИсполнительБДД = Новый ИсполнительБДД;
+РезультатВыполнения = ИсполнительБДД.ВыполнитьФичу(ФайлФичи, Файл_КаталогФич);
+ИтоговыйРезультатВыполнения = ИсполнительБДД.ПолучитьИтоговыйСтатусВыполнения(РезультатВыполнения);
+
+Сообщить(ИтоговыйРезультатВыполнения);
+Если ИтоговыйРезультатВыполнения = ИсполнительБДД.ВозможныеСтатусыВыполнения().Сломался Тогда
+
+ ВызватьИсключение 1;
+
+КонецЕсли;
diff --git a/tasks/test.os b/tasks/test.os
new file mode 100644
index 0000000..0576ba5
--- /dev/null
+++ b/tasks/test.os
@@ -0,0 +1,82 @@
+#Использовать "../src"
+#Использовать 1bdd
+#Использовать 1testrunner
+
+Функция ПрогнатьТесты()
+
+ Тестер = Новый Тестер;
+
+ ПутьКТестам = ОбъединитьПути(ТекущийСценарий().Каталог, "..", "tests");
+ ПутьКОтчетуJUnit = ОбъединитьПути(ТекущийСценарий().Каталог, "..");
+
+ КаталогТестов = Новый Файл(ПутьКТестам);
+ Если Не КаталогТестов.Существует() Тогда
+ Сообщить(СтрШаблон("Не найден каталог тестов %1", ПутьКТестам));
+ Возврат Истина;
+ КонецЕсли;
+
+ РезультатТестирования = Тестер.ТестироватьКаталог(
+ КаталогТестов,
+ Новый Файл(ПутьКОтчетуJUnit)
+ );
+
+ Успешно = РезультатТестирования = 0;
+
+ Возврат Успешно;
+КонецФункции // ПрогнатьТесты()
+
+Функция ПрогнатьФичи()
+
+ ПутьОтчетаJUnit = "./bdd-log.xml";
+
+ КаталогФич = ОбъединитьПути(".", "features");
+
+ Файл_КаталогФич = Новый Файл(КаталогФич);
+ Если Не Файл_КаталогФич.Существует() Тогда
+ Сообщить(СтрШаблон("Не найден каталог фич %1", КаталогФич));
+ Возврат Истина;
+ КонецЕсли;
+
+ ИсполнительБДД = Новый ИсполнительБДД;
+ РезультатыВыполнения = ИсполнительБДД.ВыполнитьФичу(Файл_КаталогФич, Файл_КаталогФич);
+ ИтоговыйРезультатВыполнения = ИсполнительБДД.ПолучитьИтоговыйСтатусВыполнения(РезультатыВыполнения);
+
+ СтатусВыполнения = ИсполнительБДД.ВозможныеСтатусыВыполнения().НеВыполнялся;
+ Если РезультатыВыполнения.Строки.Количество() > 0 Тогда
+
+ СтатусВыполнения = ИсполнительБДД.ПолучитьИтоговыйСтатусВыполнения(РезультатыВыполнения);
+
+ КонецЕсли;
+
+ ГенераторОтчетаJUnit = Новый ГенераторОтчетаJUnit;
+ ГенераторОтчетаJUnit.Сформировать(РезультатыВыполнения, СтатусВыполнения, ПутьОтчетаJUnit);
+
+ Сообщить(СтрШаблон("Результат прогона фич <%1>
+ |", ИтоговыйРезультатВыполнения));
+
+ Возврат ИтоговыйРезультатВыполнения <> ИсполнительБДД.ВозможныеСтатусыВыполнения().Сломался;
+КонецФункции // ПрогнатьФичи()
+
+Попытка
+ ТестыПрошли = ПрогнатьТесты();
+
+Исключение
+ ТестыПрошли = Ложь;
+ Сообщить(СтрШаблон("Тесты через 1testrunner выполнены неудачно
+ |%1", ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
+КонецПопытки;
+
+Попытка
+ ФичиПрошли = ПрогнатьФичи();
+Исключение
+ ФичиПрошли = Ложь;
+ Сообщить(СтрШаблон("Тесты поведения через 1bdd выполнены неудачно
+ |%1", ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
+КонецПопытки;
+
+Если Не ТестыПрошли Или Не ФичиПрошли Тогда
+ ВызватьИсключение "Тестирование завершилось неудачно!";
+Иначе
+ Сообщить(СтрШаблон("Результат прогона тестов <%1>
+ |", ТестыПрошли));
+КонецЕсли;
diff --git "a/tests/fixtures/snippets/\320\250\320\260\320\261\320\273\320\276\320\275EDT.xml" "b/tests/fixtures/snippets/\320\250\320\260\320\261\320\273\320\276\320\275EDT.xml"
new file mode 100644
index 0000000..a2424aa
--- /dev/null
+++ "b/tests/fixtures/snippets/\320\250\320\260\320\261\320\273\320\276\320\275EDT.xml"
@@ -0,0 +1,14 @@
+
+
+ #Если НЕ ВебКлиент Тогда
+ Выполнить(СервисныйОбщегоНазначенияПовтИсп.ЗапретитьИспользованиеФункционала(
+ "${ЗапрещенныйФункционалМетод}", // Запрещенный функционал, метод
+ "${ФункционалДляЗаменыНеобязательно}", // Функционал для замены
+ "${КомментарийПояснениеНеобязательно}", // Комментарий / пояснение
+ ${ДатаЗапретаВТестовойНеобязательноВидДатаГГГГММДД}, // Дата запрета в тестовой
+ ${ДатаЗапретаВРабочейНеобязательноВидДатаГГГГММДД}) // Дата запрета в рабочей
+ );
+#КонецЕсли
+ ${Операнд} = ${Операнд} + 1;
+ ТекущаяДата = '${n1:date(dd.MM.yyyy)}';
+
\ No newline at end of file
diff --git "a/tests/fixtures/snippets/\320\250\320\260\320\261\320\273\320\276\320\275\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\202\320\276\321\200\320\260.st" "b/tests/fixtures/snippets/\320\250\320\260\320\261\320\273\320\276\320\275\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\202\320\276\321\200\320\260.st"
new file mode 100644
index 0000000..1d87256
--- /dev/null
+++ "b/tests/fixtures/snippets/\320\250\320\260\320\261\320\273\320\276\320\275\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\202\320\276\321\200\320\260.st"
@@ -0,0 +1,85 @@
+{1,
+{3,
+{"Тест",1,0,"",""},
+{0,
+{"Общий модуль",0,0,"Модуль[Общий]","//⇗ ⇘ ⇙ ⇚ ⇛ ⇜ ⇝ ⇞ ⇟ ⇠ ⇡ ⇢ ⇣ ⇤ ⇥ ⇦ ⇧ ⇨ ⇩ ⇪ ⇫ ⇬ ⇭ ⇮ ⇯ ⇰ ⇱ ⇲ ⇳ ⇴ ⇵ ⇶ ⇷ ⇸ ⇹ ⇺ //
+//
+// © ООО ""Моя компания"" (My company). 1234-5678.
+// Все права защищены.
+//
+// Все торговые марки являются собственностью их правообладателей.
+//
+// Настоящий результат интеллектуальной деятельности является собственностью
+// ООО ""Моя компания"" (UID 337c95d2-d846-4822-8cb4-79abc804dd95), и только
+// ее, а не кого-то иного.
+//
+// Любые действия (бездействие, наплевательского отношение, порча имущества),
+// направленные на использование (неиспользование, отрицание) настоящего
+// результата интеллектуальной (и не очень) деятельности, включая
+// (но не ограничиваясь) изучение, исследование, курение, медитацию, поиск кошек
+// в темной комнате, испытание его функционирования; воспроизводство
+// и преобразование объектного кода в исходный текст (это так юридически
+// зовется декомпилирование); смотрение и использование; еще какой-то бред;
+// результата интеллектуальной деятельности с иным программным обеспечением,
+// возможны только с предварительного согласия правообладателя (побожиться).
+//
+// Нарушение прав ООО ""Моя компания"" на данный результат интеллектуальной
+// деятельности будет преследоваться и пресекаться правообладателем
+// в соответствии с законом, а если не получится, то караться в соответствии с
+// моральными принципами и устоями конкретного безумца.
+//
+//ℋ ℌ ℍ ℎ ℏ ℐ ℑ ℒ ℓ ℔ ℕ № ℗ ℘ ℙ ℚ ℛ ℜ ℝ ℞ ℟ ℠ ℡ ™ ℣ ℤ ℥ Ω ℧ ℨ ℩ K Å ℬ ℭ ℮ ℯ ℰ ℱ//
+
+/////////////////////////////////////////////////////////////////////////////////
+// ""Заголовок модуля: краткое описание и условия применения модуля.>"">
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////
+// Экспортные процедуры и функции, предназначенные для использования другими
+// объектами конфигурации или другими программами
+/////////////////////////////////////////////////////////////////////////////////
+
+#Область ПрограммныйИнтерфейс
+
+#КонецОбласти
+
+/////////////////////////////////////////////////////////////////////////////////
+// Экспортные процедуры и функции для служебного использования внутри подсистемы
+/////////////////////////////////////////////////////////////////////////////////
+
+#Область СлужебныйПрограммныйИнтерфейс
+
+#КонецОбласти
+
+/////////////////////////////////////////////////////////////////////////////////
+// Процедуры и функции, составляющие внутреннюю реализацию модуля
+/////////////////////////////////////////////////////////////////////////////////
+
+#Область СлужебныеПроцедурыИФункции
+
+#КонецОбласти
+ "}
+},
+{2,
+{"Группа",1,0,"",""},
+{0,
+{"DEPRECATED",0,0,"Запре[титьИспользование]","#Если НЕ ВебКлиент Тогда
+ Выполнить(СервисныйОбщегоНазначенияПовтИсп.ЗапретитьИспользованиеФункционала(
+ """"Запрещенный функционал, метод"">"", // Запрещенный функционал, метод
+ """"Функционал для замены (необязательно)"">"", // Функционал для замены
+ """"Комментарий / пояснение (необязательно)"">"", // Комментарий / пояснение
+ ""Дата запрета в тестовой (необязательно, вид Дата(ГГГГ, ММ, ДД))"">, // Дата запрета в тестовой
+ ""Дата запрета в рабочей (необязательно, вид Дата(ГГГГ, ММ, ДД))"">) // Дата запрета в рабочей
+ );
+#КонецЕсли "}
+},
+{0,
+{"Инкремент",0,0,"++","""Операнд""> = ""Операнд""> + 1;"}
+}
+},
+{0,
+{"Пустая группа",1,0,"",""}
+}
+}
+}
\ No newline at end of file
diff --git "a/tests/fixtures/snippets/\320\250\320\260\320\261\320\273\320\276\320\275\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\202\320\276\321\200\320\260\320\241\320\235\320\265\320\277\320\276\320\264\320\264\320\265\321\200\320\266\320\270\320\262\320\260\320\265\320\274\321\213\320\274\320\270\320\242\320\270\320\277\320\260\320\274\320\270.st" "b/tests/fixtures/snippets/\320\250\320\260\320\261\320\273\320\276\320\275\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\202\320\276\321\200\320\260\320\241\320\235\320\265\320\277\320\276\320\264\320\264\320\265\321\200\320\266\320\270\320\262\320\260\320\265\320\274\321\213\320\274\320\270\320\242\320\270\320\277\320\260\320\274\320\270.st"
new file mode 100644
index 0000000..9e89a49
--- /dev/null
+++ "b/tests/fixtures/snippets/\320\250\320\260\320\261\320\273\320\276\320\275\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\202\320\276\321\200\320\260\320\241\320\235\320\265\320\277\320\276\320\264\320\264\320\265\321\200\320\266\320\270\320\262\320\260\320\265\320\274\321\213\320\274\320\270\320\242\320\270\320\277\320\260\320\274\320\270.st"
@@ -0,0 +1,18 @@
+{1,
+{3,
+{"ЧастичноПоддерживаемыйФункционал",1,0,"",""},
+{0,
+{"#Если",0,0,"№Ес[ли]","#Если """", ВыборВарианта, ""Клиент"", ""Клиент"", ""Сервер"", ""Сервер"", ""ВнешнееСоединение"", ""ВнешнееСоединение"" ,""ТолстыйКлиентОбычноеПриложение"", ""ТолстыйКлиентОбычноеПриложение"", ""ТолстыйКлиентУправляемоеПриложение"",""ТолстыйКлиентУправляемоеПриложение"", ""ТонкийКлиент"", ""ТонкийКлиент"", ""ВебКлиент"", ""ВебКлиент""> Тогда
+
+ >
+
+#КонецЕсли"}
+},
+{0,
+{"Формат",0,0,"Формат","Формат(>, "", ФорматнаяСтрока>"")"}
+},
+{0,
+{"УстановитьЗначениеКонстанты",0,0,"УстановитьЗнач[ениеКонстанты]","ОбщегоНазначенияСервер.УстановитьЗначениеКонстанты(""""Выберите константу"", Константа>"", >);"}
+}
+}
+}
\ No newline at end of file
diff --git "a/tests/\320\242\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260\320\250\320\260\320\261\320\273\320\276\320\275\320\276\320\262\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\202\320\276\321\200\320\260.os" "b/tests/\320\242\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260\320\250\320\260\320\261\320\273\320\276\320\275\320\276\320\262\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\202\320\276\321\200\320\260.os"
new file mode 100644
index 0000000..196c94d
--- /dev/null
+++ "b/tests/\320\242\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260\320\250\320\260\320\261\320\273\320\276\320\275\320\276\320\262\320\232\320\276\320\275\321\204\320\270\320\263\321\203\321\200\320\260\321\202\320\276\321\200\320\260.os"
@@ -0,0 +1,131 @@
+///////////////////////////////////////////////////////////////////
+//
+// Тестирование основной функциональности пакета
+// Проверка на соответствие выгрузки эталону
+//
+// (с) BIA Technologies, LLC
+//
+///////////////////////////////////////////////////////////////////
+
+#Использовать asserts
+#Использовать tempfiles
+
+///////////////////////////////////////////////////////////////////
+
+Перем МенеджерВременныхФайлов;
+
+///////////////////////////////////////////////////////////////////
+// Программный интерфейс
+///////////////////////////////////////////////////////////////////
+
+Функция ПолучитьСписокТестов(Знач ЮнитТестирование) Экспорт
+
+ МассивТестов = Новый Массив;
+ МассивТестов.Добавить("ТестПрочитатьШаблон");
+ МассивТестов.Добавить("ТестЗаписатьШаблон");
+ МассивТестов.Добавить("ТестПрочитатьИЗаписатьШаблон");
+
+ Возврат МассивТестов;
+
+КонецФункции
+
+Процедура ПередЗапускомТеста() Экспорт
+
+ МенеджерВременныхФайлов = Новый МенеджерВременныхФайлов;
+
+КонецПроцедуры
+
+Процедура ПослеЗапускаТеста() Экспорт
+
+ МенеджерВременныхФайлов.Удалить();
+
+КонецПроцедуры
+
+///////////////////////////////////////////////////////////////////
+// Шаги
+///////////////////////////////////////////////////////////////////
+
+Процедура ТестПрочитатьШаблон() Экспорт
+
+ Шаблон = ШаблоныКонфигуратора.ПрочитатьШаблон(ОбъединитьПути(КаталогФикстур(), "snippets", "ШаблонКонфигуратора.st"));
+
+ Утверждения.ПроверитьРавенство(Шаблон.Элементы.Количество(), 3, "Количество элементов шаблона равно 3");
+
+КонецПроцедуры
+
+Процедура ТестЗаписатьШаблон() Экспорт
+
+ Шаблон = ШаблоныБазовый.КорневойЭлемент();
+
+ Группа = ШаблоныБазовый.Группа();
+ Группа.Наименование = "Группа";
+ Шаблон.Элементы.Добавить(Группа);
+
+ Элемент = ШаблоныБазовый.Элемент();
+ Элемент.Наименование = "Сообщить";
+ Элемент.ТекстЗамены = "Соо[бщить]";
+ Элемент.Шаблон = "Сообщить();";
+ Шаблон.Элементы.Добавить(Элемент);
+
+ Элемент = ШаблоныБазовый.Элемент();
+ Элемент.Наименование = "Сообщить2";
+ Элемент.ТекстЗамены = "Соо[бщить2]";
+ Элемент.Шаблон = "Сообщить(2);";
+ Группа.Элементы.Добавить(Элемент);
+
+ ИмяФайла = МенеджерВременныхФайлов.НовоеИмяФайла("st");
+ ШаблоныКонфигуратора.ЗаписатьШаблон(Шаблон, ИмяФайла);
+
+ ТекстФайла = ПрочитатьФайл(ИмяФайла);
+
+ Эталон =
+ "{1,
+ |{2,
+ |{""Корень"",1,0,"""",""""},
+ |{1,
+ |{""Группа"",1,0,"""",""""},
+ |{0,
+ |{""Сообщить2"",0,0,""Соо[бщить2]"",""Сообщить(2);""}
+ |}
+ |},
+ |{0,
+ |{""Сообщить"",0,0,""Соо[бщить]"",""Сообщить();""}
+ |}
+ |}
+ |}";
+ Утверждения.ПроверитьРавенство(ТекстФайла, Эталон, "Текст шаблона не соответствует ожидаемому");
+
+КонецПроцедуры
+
+Процедура ТестПрочитатьИЗаписатьШаблон() Экспорт
+
+ ИмяБазовогоШаблона = ОбъединитьПути(КаталогФикстур(), "snippets", "ШаблонКонфигуратора.st");
+ ИмяНовогоШаблона = МенеджерВременныхФайлов.НовоеИмяФайла("st");
+
+ Шаблон = ШаблоныКонфигуратора.ПрочитатьШаблон(ИмяБазовогоШаблона);
+
+ ШаблоныКонфигуратора.ЗаписатьШаблон(Шаблон, ИмяНовогоШаблона);
+
+ Утверждения.ПроверитьРавенство(ПрочитатьФайл(ИмяБазовогоШаблона), ПрочитатьФайл(ИмяНовогоШаблона), "Текст шаблона не должен измениться");
+
+КонецПроцедуры
+
+///////////////////////////////////////////////////////////////////
+// Служебный функционал
+///////////////////////////////////////////////////////////////////
+
+Функция КаталогФикстур()
+
+ Возврат ОбъединитьПути(ТекущийСценарий().Каталог, "..", "tests", "fixtures");
+
+КонецФункции
+
+Функция ПрочитатьФайл(Файл)
+
+ Чтение = Новый ЧтениеТекста(Файл, КодировкаТекста.UTF8NoBOM);
+ Текст = Чтение.Прочитать();
+ Чтение.Закрыть();
+
+ Возврат Текст;
+
+КонецФункции
diff --git "a/\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265\320\250\320\260\320\261\320\273\320\276\320\275\320\276\320\262.md" "b/\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265\320\250\320\260\320\261\320\273\320\276\320\275\320\276\320\262.md"
new file mode 100644
index 0000000..aaa1574
--- /dev/null
+++ "b/\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265\320\250\320\260\320\261\320\273\320\276\320\275\320\276\320\262.md"
@@ -0,0 +1,76 @@
+# Инструкция по подключению шаблонов кода
+
+## Подключение к VS Code
+
+Есть несколько вариантов подключения шаблонов(фрагментов) кода к VS Code
+
+1. Редактирования файла шаблонов конкретного языка, для 1c это файл bsl.json
+ Для этого необходимо выполнить команду (нажав Ctrl+P) "Настроить пользовательские фрагменты кода" и выбрав в списке языков "BSL"
+
+2. Создание глобальных файлов шаблонов, которые могут в себя включать различные языки.
+ Для этого необходимо выполнить команду (нажав Ctrl+P) "Настроить пользовательские фрагменты кода" и выбрать "Новый файл с глобальным фрагментом кода"
+
+3. Можно руками создавать файлы с расширением "code-snippets" в каталоге "%appdata%\Code\User\snippets", это эквивалентно второму варианту.
+
+Основное отличие первого и второго вариантов в том, что по первому варианту может быть только один файл. Для второго - множество, но в нем придется указывать язык для каждого шаблона замены для какого он языка.
+Третий - тоже самое, что и второй, но руками.
+
+### Как писать шаблоны VSCode
+
+Шаблон - это JSON файл.
+Он не поддерживает иерархии и групп.
+Все шаблоны - это свойства корневого элемента.
+
+* Имя свойства - имя шаблона, должно быть уникальным.
+* prefix - заменяемая строка
+* body - тело шаблона
+* description - описание шаблона, отображается если заполнено и не равно имени
+
+```json
+{
+ "DEPRECATED": {
+ "prefix": "ЗапретитьИспользование",
+ "body": "#Если НЕ ВебКлиент Тогда\n\tВыполнить(СервисныйОбщегоНазначенияПовтИсп.ЗапретитьИспользованиеФункционала(\n\t\t\"${1:Запрещенный функционал, метод}\", \/\/ Запрещенный функционал, метод\n\t\t\"${2:Функционал для замены (необязательно)}\", \/\/ Функционал для замены\n\t\t\"${3:Комментарий \/ пояснение (необязательно)}\", \/\/ Комментарий \/ пояснение\n\t\t${4:Дата запрета в тестовой (необязательно, вид Дата(ГГГГ, ММ, ДД))}, \/\/ Дата запрета в тестовой\n\t\t${5:Дата запрета в рабочей (необязательно, вид Дата(ГГГГ, ММ, ДД))}) \/\/ Дата запрета в рабочей\n\t\t);\n#КонецЕсли ",
+ "description": "DEPRECATED"
+ },
+ "Инкремент": {
+ "prefix": "++",
+ "body": "${1:Операнд} = ${2:Операнд} + 1;",
+ "description": "Инкремент"
+ }
+}
+```
+
+В поле `body` (тело шаблона) можно использовать подстановочные символы
+
+* $1, $2... - места остановки для ввода текста
+* $0 - установка курсора по окончании ввода шаблона
+* ${1:Операнд} - места остановки для ввода текста со значением по умолчанию
+
+Например `Сообщить("${1:Тест сообщения}");`
+Для ввода многострочного шаблона необходимо использовать спецсимволы `\n`, либо оформлять тело как массив строк.
+
+Также можно использовать шаблон выбора и различные переменные, подробнее [здесь](https://code.visualstudio.com/docs/editor/userdefinedsnippets)
+
+## Подключение шаблонов EDT
+
+Заходим в настройки шаблонов:
+
+1. Меню → Окно → Параметры → V8 → Встроенный язык → Макеты
+2. Быстрый доступ (Ctrl+3), набираем "параметры макеты"
+
+Откроется окно работы с шаблонами. В нем есть возможность создавать новые, редактировать существующие и импортировать шаблоны
+
+### Создание
+
+1. Нажимаем создать
+2. Не меняем поле контекст!
+3. Указываем имя, оно будет использоваться для поиска шаблона
+4. Заполняем описание
+5. Заполняем поле шаблон
+
+В тексте шаблона можно использовать подстановочные символы
+
+* ${} - места остановки для ввода текста
+* ${имя_переменной} - места остановки для ввода текста, имя переменной является значение по-умолчанию, также если в шаблоне переменная используется несколько раз, то значение будет установлено для всех мест
+* ${cursor} - установка курсора по окончании ввода шаблона