diff --git a/packagedef b/packagedef index 597ddd9..a91c2d8 100644 --- a/packagedef +++ b/packagedef @@ -4,7 +4,7 @@ // Описание.Имя("cli") - .Версия("0.11.0") + .Версия("0.12.0") .Автор("Khorev Aleksey") .АдресАвтора("khorevaa@gmail.com") .Описание("Данный пакет облегчает создание консольных приложений на Oscript") @@ -15,7 +15,6 @@ //.ВключитьФайл("package-loader.os") //.ВключитьФайл("packagedef") .ЗависитОт("logos", "1.1.1") - .ЗависитОт("delegate", "0.2.0") .ЗависитОт("reflector", "0.5.1") .ЗависитОт("fluent", "0.6.0") .ЗависитОт("datetime", "0.1.0") @@ -25,4 +24,5 @@ .ОпределяетКласс("КонсольноеПриложение", "src/core/Классы/КонсольноеПриложение.os") .ОпределяетКласс("КомандаПриложения", "src/core/Классы/КомандаПриложения.os") .ОпределяетКласс("ПараметрКоманды", "src/core/Классы/ПараметрКоманды.os") + .ОпределяетКласс("КомандаДополнения", "src/core/Классы/КомандаДополнения.os") ; diff --git "a/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/internal/completion/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217Bash.os" "b/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/internal/completion/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217Bash.os" new file mode 100644 index 0000000..b091ad2 --- /dev/null +++ "b/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/internal/completion/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217Bash.os" @@ -0,0 +1,209 @@ +// Генератор (посетитель) скрипта автодополнения для GNU Bash. +// Реализует контракт ОбходчикКомандДополнения. + +Перем ИмяПриложенияГлоб; +Перем ИмяФункцииГлоб; + +Функция Оболочка() Экспорт + Возврат "bash"; +КонецФункции + +Функция СформироватьСкрипт(ИмяПриложения, КореньКоманд) Экспорт + + ИмяПриложенияГлоб = ИмяПриложения; + ИмяФункцииГлоб = "_" + БезопасноеИмяФункции(ИмяПриложения) + "_completions"; + + Буфер = Новый Массив; + Контекст = НовыйКонтекст(0, "", Буфер); + + Обходчик = Новый ОбходчикКомандДополнения(); + Обходчик.Обойти(КореньКоманд, ЭтотОбъект, Контекст); + + Возврат СтрСоединить(Буфер, Символы.ПС); + +КонецФункции + +Процедура НачатьКоманду(Команда, Контекст) Экспорт + + Если Контекст.Глубина = 0 Тогда + Б = Контекст.Буфер; + Б.Добавить("# " + ИмяПриложенияГлоб + " bash completions"); + Б.Добавить("# Добавьте строку ниже в ~/.bashrc для активации:"); + Б.Добавить("# source <(" + ИмяПриложенияГлоб + " completions --shell bash)"); + Б.Добавить(""); + Б.Добавить(ИмяФункцииГлоб + "() {"); + Б.Добавить(" local cur prev words cword"); + Б.Добавить(" _init_completion 2>/dev/null || {"); + Б.Добавить(" COMPREPLY=()"); + Б.Добавить(" cur=""${COMP_WORDS[COMP_CWORD]}"""); + Б.Добавить(" prev=""${COMP_WORDS[COMP_CWORD-1]}"""); + Б.Добавить(" words=(""${COMP_WORDS[@]}"")"); + Б.Добавить(" cword=$COMP_CWORD"); + Б.Добавить(" }"); + Иначе + Контекст.Буфер.Добавить(Контекст.Отступ + СтрСоединить(ПолучитьИменаКоманды(Команда), "|") + ")"); + КонецЕсли; + +КонецПроцедуры + +Процедура ПосетитьОпцию(СтрокаОпции, Контекст) Экспорт + + ЕстьЗначения = СтрокаОпции.ЗначенияДополнения.Количество() > 0; + Для Каждого ИмяОпции Из СтрокаОпции.НаименованияПараметров Цикл + Контекст.ИменаОпций.Добавить(ИмяОпции); + Если ЕстьЗначения Тогда + Контекст.ОпцииСоЗначениями.Вставить(ИмяОпции, СтрокаОпции.ЗначенияДополнения); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +Процедура ПосетитьАргумент(СтрокаАргумента, Контекст) Экспорт + + Для Каждого Значение Из СтрокаАргумента.ЗначенияДополнения Цикл + Контекст.ЗначенияАргументов.Добавить(Значение); + КонецЦикла; + +КонецПроцедуры + +Процедура ПередПодкомандами(Команда, Подкоманды, Контекст) Экспорт + + Б = Контекст.Буфер; + О = Контекст.Отступ; + Контекст.ЕстьПодкоманды = Подкоманды.Количество() > 0; + + Если Контекст.Глубина = 0 Тогда + Б.Добавить(""); + Б.Добавить(" local commands=""" + СтрСоединить(СобратьИменаВсех(Подкоманды), " ") + """"); + Б.Добавить(""); + Б.Добавить(" if [ $cword -eq 1 ]; then"); + Б.Добавить(" COMPREPLY=($(compgen -W ""$commands"" -- ""$cur""))"); + Б.Добавить(" return 0"); + Б.Добавить(" fi"); + Б.Добавить(""); + Б.Добавить(" local command=""${words[1]-}"""); + Б.Добавить(" case ""$command"" in"); + Возврат; + КонецЕсли; + + Для Каждого КлючЗначение Из Контекст.ОпцииСоЗначениями Цикл + Б.Добавить(О + " if [ ""$prev"" = """ + КлючЗначение.Ключ + """ ]; then"); + Б.Добавить(О + " COMPREPLY=($(compgen -W """ + СтрСоединить(КлючЗначение.Значение, " ") + """ -- ""$cur""))"); + Б.Добавить(О + " return 0"); + Б.Добавить(О + " fi"); + КонецЦикла; + + ИменаДляКомплита = Новый Массив; + ИменаДляКомплита.Добавить("--help"); + Для Каждого Имя Из Контекст.ИменаОпций Цикл + ИменаДляКомплита.Добавить(Имя); + КонецЦикла; + Б.Добавить(О + " if [[ ""$cur"" == -* ]]; then"); + Б.Добавить(О + " COMPREPLY=($(compgen -W """ + СтрСоединить(ИменаДляКомплита, " ") + """ -- ""$cur""))"); + Б.Добавить(О + " return 0"); + Б.Добавить(О + " fi"); + + Если Контекст.ЕстьПодкоманды Тогда + СледИндекс = Формат(Контекст.Глубина + 1, "ЧГ=0"); + Б.Добавить(О + " if [ $cword -eq " + СледИндекс + " ]; then"); + Б.Добавить(О + " COMPREPLY=($(compgen -W """ + СтрСоединить(СобратьИменаВсех(Подкоманды), " ") + """ -- ""$cur""))"); + Б.Добавить(О + " return 0"); + Б.Добавить(О + " fi"); + Б.Добавить(О + " local sub" + СледИндекс + "=""${words[" + СледИндекс + "]-}"""); + Б.Добавить(О + " case ""$sub" + СледИндекс + """ in"); + ИначеЕсли Контекст.ЗначенияАргументов.Количество() > 0 Тогда + Б.Добавить(О + " COMPREPLY=($(compgen -W """ + СтрСоединить(Контекст.ЗначенияАргументов, " ") + """ -- ""$cur""))"); + КонецЕсли; + +КонецПроцедуры + +Функция ОткрытьПодкоманду(Подкоманда, Контекст) Экспорт + + Возврат НовыйКонтекст(Контекст.Глубина + 1, Контекст.Отступ + " ", Контекст.Буфер); + +КонецФункции + +Процедура ЗакрытьПодкоманду(Подкоманда, ПодчинённыйКонтекст, Контекст) Экспорт + // Для bash дочерний узел сам завершает свою ветку case в ЗавершитьКоманду. +КонецПроцедуры + +Процедура ЗавершитьКоманду(Команда, Контекст) Экспорт + + Б = Контекст.Буфер; + О = Контекст.Отступ; + + Если Контекст.Глубина = 0 Тогда + Б.Добавить(" *)"); + Б.Добавить(" ;;"); + Б.Добавить(" esac"); + Б.Добавить(""); + Б.Добавить(" return 0"); + Б.Добавить("}"); + Б.Добавить(""); + Б.Добавить("complete -F " + ИмяФункцииГлоб + " " + ИмяПриложенияГлоб); + Возврат; + КонецЕсли; + + Если Контекст.ЕстьПодкоманды Тогда + Б.Добавить(О + " *)"); + Б.Добавить(О + " ;;"); + Б.Добавить(О + " esac"); + КонецЕсли; + Б.Добавить(О + " ;;"); + +КонецПроцедуры + +Функция НовыйКонтекст(Глубина, Отступ, Буфер) + + К = Новый Структура(); + К.Вставить("Глубина", Глубина); + К.Вставить("Отступ", Отступ); + К.Вставить("Буфер", Буфер); + К.Вставить("ИменаОпций", Новый Массив); + К.Вставить("ОпцииСоЗначениями", Новый Соответствие); + К.Вставить("ЗначенияАргументов", Новый Массив); + К.Вставить("ЕстьПодкоманды", Ложь); + Возврат К; + +КонецФункции + +Функция ПолучитьИменаКоманды(Команда) + + Имена = Новый Массив; + Имена.Добавить(Команда.ПолучитьИмяКоманды()); + Для Каждого Синоним Из Команда.ПолучитьСинонимы() Цикл + Если Синоним <> Команда.ПолучитьИмяКоманды() Тогда + Имена.Добавить(Синоним); + КонецЕсли; + КонецЦикла; + Возврат Имена; + +КонецФункции + +Функция СобратьИменаВсех(Подкоманды) + + Результат = Новый Массив; + Для Каждого Подкоманда Из Подкоманды Цикл + Результат.Добавить(Подкоманда.ПолучитьИмяКоманды()); + КонецЦикла; + Возврат Результат; + +КонецФункции + +Функция БезопасноеИмяФункции(Имя) + + Результат = ""; + Для Инд = 1 По СтрДлина(Имя) Цикл + Символ = Сред(Имя, Инд, 1); + Если (Символ >= "a" И Символ <= "z") + Или (Символ >= "A" И Символ <= "Z") + Или (Символ >= "0" И Символ <= "9") + Или Символ = "_" Тогда + Результат = Результат + Символ; + Иначе + Результат = Результат + "_"; + КонецЕсли; + КонецЦикла; + Возврат Результат; + +КонецФункции diff --git "a/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/internal/completion/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217Pwsh.os" "b/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/internal/completion/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217Pwsh.os" new file mode 100644 index 0000000..82cb940 --- /dev/null +++ "b/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/internal/completion/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217Pwsh.os" @@ -0,0 +1,263 @@ +// Генератор (посетитель) скрипта автодополнения для PowerShell. +// Эмитит дерево команд литералом-хэш-таблицей и небольшой обходчик +// токенов, что позволяет корректно работать при произвольной глубине +// подкоманд и при наличии опций/аргументов между родителем и подкомандой. +// Реализует контракт ОбходчикКомандДополнения. + +Перем ИмяПриложенияГлоб; + +Функция Оболочка() Экспорт + Возврат "pwsh"; +КонецФункции + +Функция СформироватьСкрипт(ИмяПриложения, КореньКоманд) Экспорт + + ИмяПриложенияГлоб = ИмяПриложения; + + Буфер = Новый Массив; + Контекст = НовыйКонтекст(0, " ", Буфер); + + Обходчик = Новый ОбходчикКомандДополнения(); + Обходчик.Обойти(КореньКоманд, ЭтотОбъект, Контекст); + + Возврат СтрСоединить(Буфер, Символы.ПС); + +КонецФункции + +Процедура НачатьКоманду(Команда, Контекст) Экспорт + // Узлы инициализируются в ОткрытьПодкоманду/СформироватьСкрипт. +КонецПроцедуры + +Процедура ПосетитьОпцию(СтрокаОпции, Контекст) Экспорт + + ЕстьЗначения = СтрокаОпции.ЗначенияДополнения.Количество() > 0; + Для Каждого ИмяОпции Из СтрокаОпции.НаименованияПараметров Цикл + Контекст.ИменаОпций.Добавить(ИмяОпции); + Если ЕстьЗначения Тогда + Контекст.ОпцииСоЗначениями.Вставить(ИмяОпции, СтрокаОпции.ЗначенияДополнения); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +Процедура ПосетитьАргумент(СтрокаАргумента, Контекст) Экспорт + + Для Каждого Значение Из СтрокаАргумента.ЗначенияДополнения Цикл + Контекст.ЗначенияАргументов.Добавить(Значение); + КонецЦикла; + +КонецПроцедуры + +Процедура ПередПодкомандами(Команда, Подкоманды, Контекст) Экспорт + // Никаких действий: дочерние узлы сериализуются в ЗакрытьПодкоманду. +КонецПроцедуры + +Функция ОткрытьПодкоманду(Подкоманда, Контекст) Экспорт + + Возврат НовыйКонтекст(Контекст.Глубина + 1, Контекст.Отступ + " ", Контекст.Буфер); + +КонецФункции + +Процедура ЗакрытьПодкоманду(Подкоманда, ПодчинённыйКонтекст, Контекст) Экспорт + + ИменаПодкоманды = ПолучитьИменаКоманды(Подкоманда); + ИмяКанон = ИменаПодкоманды[0]; + + Контекст.СериализованныеКоманды.Вставить(ИмяКанон, ПодчинённыйКонтекст.Сериализованное); + + Для Инд = 1 По ИменаПодкоманды.ВГраница() Цикл + Пара = Новый Структура("Алиас, Канон", ИменаПодкоманды[Инд], ИмяКанон); + Контекст.ПарыАлиасов.Добавить(Пара); + КонецЦикла; + +КонецПроцедуры + +Процедура ЗавершитьКоманду(Команда, Контекст) Экспорт + + Контекст.Сериализованное = СериализоватьУзел(Контекст); + + Если Контекст.Глубина = 0 Тогда + Б = Контекст.Буфер; + Б.Добавить("# " + ИмяПриложенияГлоб + " PowerShell completions"); + Б.Добавить("# Активируйте строкой в профиле PowerShell ($PROFILE):"); + Б.Добавить("# " + ИмяПриложенияГлоб + " completions --shell pwsh | Out-String | Invoke-Expression"); + Б.Добавить(""); + Б.Добавить("Register-ArgumentCompleter -Native -CommandName '" + ИмяПриложенияГлоб + "' -ScriptBlock {"); + Б.Добавить(" param($wordToComplete, $commandAst, $cursorPosition)"); + Б.Добавить(""); + Б.Добавить(" $__tree = " + Контекст.Сериализованное); + Б.Добавить(""); + Б.Добавить(" $tokens = @($commandAst.CommandElements | ForEach-Object { $_.Extent.Text })"); + Б.Добавить(" $lastIndex = $tokens.Count - 1"); + Б.Добавить(" $partial = -not [string]::IsNullOrEmpty($wordToComplete) -and $lastIndex -ge 1 -and $tokens[$lastIndex] -eq $wordToComplete"); + Б.Добавить(" if ($partial) { $endWalk = $lastIndex } else { $endWalk = $lastIndex + 1 }"); + Б.Добавить(""); + Б.Добавить(" $node = $__tree"); + Б.Добавить(" $i = 1"); + Б.Добавить(" while ($i -lt $endWalk) {"); + Б.Добавить(" $tok = $tokens[$i]"); + Б.Добавить(" if ($tok.StartsWith('-')) {"); + Б.Добавить(" if ($node.OptionValues.ContainsKey($tok) -and ($i + 1) -lt $endWalk) {"); + Б.Добавить(" $i += 2"); + Б.Добавить(" } else {"); + Б.Добавить(" $i += 1"); + Б.Добавить(" }"); + Б.Добавить(" } elseif ($node.Commands.ContainsKey($tok)) {"); + Б.Добавить(" $node = $node.Commands[$tok]"); + Б.Добавить(" $i += 1"); + Б.Добавить(" } elseif ($node.AliasMap.ContainsKey($tok)) {"); + Б.Добавить(" $node = $node.Commands[$node.AliasMap[$tok]]"); + Б.Добавить(" $i += 1"); + Б.Добавить(" } else {"); + Б.Добавить(" $i += 1"); + Б.Добавить(" }"); + Б.Добавить(" }"); + Б.Добавить(""); + Б.Добавить(" $prev = if ($endWalk -ge 2) { $tokens[$endWalk - 1] } else { '' }"); + Б.Добавить(""); + Б.Добавить(" if (-not [string]::IsNullOrEmpty($wordToComplete) -and $wordToComplete.StartsWith('-')) {"); + Б.Добавить(" return $node.OptionNames | Where-Object { $_ -like ""$wordToComplete*"" } | ForEach-Object {"); + Б.Добавить(" [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)"); + Б.Добавить(" }"); + Б.Добавить(" }"); + Б.Добавить(""); + Б.Добавить(" if ($node.OptionValues.ContainsKey($prev)) {"); + Б.Добавить(" return $node.OptionValues[$prev] | Where-Object { $_ -like ""$wordToComplete*"" } | ForEach-Object {"); + Б.Добавить(" [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)"); + Б.Добавить(" }"); + Б.Добавить(" }"); + Б.Добавить(""); + Б.Добавить(" $candidates = @()"); + Б.Добавить(" if ($node.Commands.Count -gt 0) {"); + Б.Добавить(" $candidates = @($node.Commands.Keys)"); + Б.Добавить(" } elseif ($node.ArgValues.Count -gt 0) {"); + Б.Добавить(" $candidates = $node.ArgValues"); + Б.Добавить(" }"); + Б.Добавить(""); + Б.Добавить(" return $candidates | Where-Object { $_ -like ""$wordToComplete*"" } | ForEach-Object {"); + Б.Добавить(" [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)"); + Б.Добавить(" }"); + Б.Добавить("}"); + КонецЕсли; + +КонецПроцедуры + +Функция СериализоватьУзел(Контекст) + + ВнутрОтступ = Контекст.Отступ + " "; + + ИменаОпцийДляКомплита = Новый Массив; + ИменаОпцийДляКомплита.Добавить("--help"); + Для Каждого Имя Из Контекст.ИменаОпций Цикл + ИменаОпцийДляКомплита.Добавить(Имя); + КонецЦикла; + + Элементы = Новый Массив; + Элементы.Добавить(ВнутрОтступ + "Commands = " + СериализоватьХешКоманд(Контекст.СериализованныеКоманды, ВнутрОтступ)); + Элементы.Добавить(ВнутрОтступ + "AliasMap = " + СериализоватьХешАлиасов(Контекст.ПарыАлиасов, ВнутрОтступ)); + Элементы.Добавить(ВнутрОтступ + "OptionNames = " + МассивЛитералом(ИменаОпцийДляКомплита)); + Элементы.Добавить(ВнутрОтступ + "OptionValues = " + СериализоватьХешЗначенийОпций(Контекст.ОпцииСоЗначениями, ВнутрОтступ)); + Элементы.Добавить(ВнутрОтступ + "ArgValues = " + МассивЛитералом(Контекст.ЗначенияАргументов)); + + Возврат "@{" + Символы.ПС + СтрСоединить(Элементы, Символы.ПС) + Символы.ПС + Контекст.Отступ + "}"; + +КонецФункции + +Функция СериализоватьХешКоманд(СериализованныеКоманды, Отступ) + + Если СериализованныеКоманды.Количество() = 0 Тогда + Возврат "@{}"; + КонецЕсли; + + ВнутрОтступ = Отступ + " "; + Пары = Новый Массив; + Для Каждого КлючЗначение Из СериализованныеКоманды Цикл + Пары.Добавить(ВнутрОтступ + ВКавычкахPS(КлючЗначение.Ключ) + " = " + КлючЗначение.Значение); + КонецЦикла; + + Возврат "@{" + Символы.ПС + СтрСоединить(Пары, Символы.ПС) + Символы.ПС + Отступ + "}"; + +КонецФункции + +Функция СериализоватьХешАлиасов(ПарыАлиасов, Отступ) + + Если ПарыАлиасов.Количество() = 0 Тогда + Возврат "@{}"; + КонецЕсли; + + ВнутрОтступ = Отступ + " "; + Строки = Новый Массив; + Для Каждого Пара Из ПарыАлиасов Цикл + Строки.Добавить(ВнутрОтступ + ВКавычкахPS(Пара.Алиас) + " = " + ВКавычкахPS(Пара.Канон)); + КонецЦикла; + + Возврат "@{" + Символы.ПС + СтрСоединить(Строки, Символы.ПС) + Символы.ПС + Отступ + "}"; + +КонецФункции + +Функция СериализоватьХешЗначенийОпций(ОпцииСоЗначениями, Отступ) + + Если ОпцииСоЗначениями.Количество() = 0 Тогда + Возврат "@{}"; + КонецЕсли; + + ВнутрОтступ = Отступ + " "; + Пары = Новый Массив; + Для Каждого КлючЗначение Из ОпцииСоЗначениями Цикл + Пары.Добавить(ВнутрОтступ + ВКавычкахPS(КлючЗначение.Ключ) + " = " + МассивЛитералом(КлючЗначение.Значение)); + КонецЦикла; + + Возврат "@{" + Символы.ПС + СтрСоединить(Пары, Символы.ПС) + Символы.ПС + Отступ + "}"; + +КонецФункции + +Функция МассивЛитералом(Значения) + + Если Значения.Количество() = 0 Тогда + Возврат "@()"; + КонецЕсли; + + Элементы = Новый Массив; + Для Каждого Значение Из Значения Цикл + Элементы.Добавить(ВКавычкахPS(Значение)); + КонецЦикла; + + Возврат "@(" + СтрСоединить(Элементы, ", ") + ")"; + +КонецФункции + +Функция ВКавычкахPS(Значение) + + Экранированное = СтрЗаменить(Значение, "'", "''"); + Возврат "'" + Экранированное + "'"; + +КонецФункции + +Функция НовыйКонтекст(Глубина, Отступ, Буфер) + + К = Новый Структура(); + К.Вставить("Глубина", Глубина); + К.Вставить("Отступ", Отступ); + К.Вставить("Буфер", Буфер); + К.Вставить("ИменаОпций", Новый Массив); + К.Вставить("ОпцииСоЗначениями", Новый Соответствие); + К.Вставить("ЗначенияАргументов", Новый Массив); + К.Вставить("СериализованныеКоманды", Новый Соответствие); + К.Вставить("ПарыАлиасов", Новый Массив); + К.Вставить("Сериализованное", ""); + Возврат К; + +КонецФункции + +Функция ПолучитьИменаКоманды(Команда) + + Имена = Новый Массив; + Имена.Добавить(Команда.ПолучитьИмяКоманды()); + Для Каждого Синоним Из Команда.ПолучитьСинонимы() Цикл + Если Синоним <> Команда.ПолучитьИмяКоманды() Тогда + Имена.Добавить(Синоним); + КонецЕсли; + КонецЦикла; + Возврат Имена; + +КонецФункции diff --git "a/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/internal/completion/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217Zsh.os" "b/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/internal/completion/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217Zsh.os" new file mode 100644 index 0000000..bed532e --- /dev/null +++ "b/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/internal/completion/\320\232\320\273\320\260\321\201\321\201\321\213/\320\223\320\265\320\275\320\265\321\200\320\260\321\202\320\276\321\200\320\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217Zsh.os" @@ -0,0 +1,209 @@ +// Генератор (посетитель) скрипта автодополнения для Zsh. +// Реализует контракт ОбходчикКомандДополнения. + +Перем ИмяПриложенияГлоб; +Перем ИмяФункцииГлоб; + +Функция Оболочка() Экспорт + Возврат "zsh"; +КонецФункции + +Функция СформироватьСкрипт(ИмяПриложения, КореньКоманд) Экспорт + + ИмяПриложенияГлоб = ИмяПриложения; + ИмяФункцииГлоб = "_" + БезопасноеИмяФункции(ИмяПриложения); + + Буфер = Новый Массив; + Контекст = НовыйКонтекст(0, "", Буфер); + + Обходчик = Новый ОбходчикКомандДополнения(); + Обходчик.Обойти(КореньКоманд, ЭтотОбъект, Контекст); + + Возврат СтрСоединить(Буфер, Символы.ПС); + +КонецФункции + +Процедура НачатьКоманду(Команда, Контекст) Экспорт + + Если Контекст.Глубина = 0 Тогда + Б = Контекст.Буфер; + Б.Добавить("#compdef " + ИмяПриложенияГлоб); + Б.Добавить("# " + ИмяПриложенияГлоб + " zsh completions"); + Б.Добавить("# Поместите файл в путь $fpath, например ~/.zsh/completions/_" + ИмяПриложенияГлоб + ","); + Б.Добавить("# либо активируйте через: source <(" + ИмяПриложенияГлоб + " completions --shell zsh)"); + Б.Добавить(""); + Б.Добавить(ИмяФункцииГлоб + "() {"); + Б.Добавить(" local -a commands"); + Б.Добавить(" local context curcontext=""$curcontext"" state line"); + Иначе + Контекст.Буфер.Добавить(Контекст.Отступ + СтрСоединить(ПолучитьИменаКоманды(Команда), "|") + ")"); + КонецЕсли; + +КонецПроцедуры + +Процедура ПосетитьОпцию(СтрокаОпции, Контекст) Экспорт + + ЕстьЗначения = СтрокаОпции.ЗначенияДополнения.Количество() > 0; + Для Каждого ИмяОпции Из СтрокаОпции.НаименованияПараметров Цикл + Контекст.ИменаОпций.Добавить(ИмяОпции); + Если ЕстьЗначения Тогда + Контекст.ОпцииСоЗначениями.Вставить(ИмяОпции, СтрокаОпции.ЗначенияДополнения); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +Процедура ПосетитьАргумент(СтрокаАргумента, Контекст) Экспорт + + Для Каждого Значение Из СтрокаАргумента.ЗначенияДополнения Цикл + Контекст.ЗначенияАргументов.Добавить(Значение); + КонецЦикла; + +КонецПроцедуры + +Процедура ПередПодкомандами(Команда, Подкоманды, Контекст) Экспорт + + Б = Контекст.Буфер; + О = Контекст.Отступ; + Контекст.ЕстьПодкоманды = Подкоманды.Количество() > 0; + + Если Контекст.Глубина = 0 Тогда + Б.Добавить(" commands=( " + СтрСоединить(СобратьИменаВсех(Подкоманды), " ") + " )"); + Б.Добавить(" _arguments -C \"); + Б.Добавить(" ""1: :->command"" \"); + Б.Добавить(" ""*:: :->args"""); + Б.Добавить(""); + Б.Добавить(" case $state in"); + Б.Добавить(" command)"); + Б.Добавить(" _values ""command"" $commands"); + Б.Добавить(" ;;"); + Б.Добавить(" args)"); + Б.Добавить(" case $words[1] in"); + Возврат; + КонецЕсли; + + Для Каждого КлючЗначение Из Контекст.ОпцииСоЗначениями Цикл + Б.Добавить(О + " if [[ $words[CURRENT-1] == """ + КлючЗначение.Ключ + """ ]]; then"); + Б.Добавить(О + " _values """ + КлючЗначение.Ключ + """ " + СтрСоединить(КлючЗначение.Значение, " ")); + Б.Добавить(О + " return"); + Б.Добавить(О + " fi"); + КонецЦикла; + + ИменаДляКомплита = Новый Массив; + ИменаДляКомплита.Добавить("--help"); + Для Каждого Имя Из Контекст.ИменаОпций Цикл + ИменаДляКомплита.Добавить(Имя); + КонецЦикла; + Б.Добавить(О + " if [[ $words[CURRENT] == -* ]]; then"); + Б.Добавить(О + " _values ""option"" " + СтрСоединить(ИменаДляКомплита, " ")); + Б.Добавить(О + " return"); + Б.Добавить(О + " fi"); + + Если Контекст.ЕстьПодкоманды Тогда + СледИндекс = Формат(Контекст.Глубина + 1, "ЧГ=0"); + Б.Добавить(О + " if (( CURRENT == " + СледИндекс + " )); then"); + Б.Добавить(О + " _values ""subcommand"" " + СтрСоединить(СобратьИменаВсех(Подкоманды), " ")); + Б.Добавить(О + " else"); + Б.Добавить(О + " case $words[" + СледИндекс + "] in"); + ИначеЕсли Контекст.ЗначенияАргументов.Количество() > 0 Тогда + Б.Добавить(О + " _values ""argument"" " + СтрСоединить(Контекст.ЗначенияАргументов, " ")); + КонецЕсли; + +КонецПроцедуры + +Функция ОткрытьПодкоманду(Подкоманда, Контекст) Экспорт + + // На верхнем уровне (Глубина=0) обёрнутый case state=args добавляет + // дополнительный уровень отступа по сравнению с bash. + Если Контекст.Глубина = 0 Тогда + ОтступПодчинённого = " "; + Иначе + ОтступПодчинённого = Контекст.Отступ + " "; + КонецЕсли; + Возврат НовыйКонтекст(Контекст.Глубина + 1, ОтступПодчинённого, Контекст.Буфер); + +КонецФункции + +Процедура ЗакрытьПодкоманду(Подкоманда, ПодчинённыйКонтекст, Контекст) Экспорт + // Ветка case подкоманды закрывается в её собственном ЗавершитьКоманду. +КонецПроцедуры + +Процедура ЗавершитьКоманду(Команда, Контекст) Экспорт + + Б = Контекст.Буфер; + О = Контекст.Отступ; + + Если Контекст.Глубина = 0 Тогда + Б.Добавить(" *) ;;"); + Б.Добавить(" esac"); + Б.Добавить(" ;;"); + Б.Добавить(" esac"); + Б.Добавить("}"); + Б.Добавить(""); + Б.Добавить("compdef " + ИмяФункцииГлоб + " " + ИмяПриложенияГлоб); + Возврат; + КонецЕсли; + + Если Контекст.ЕстьПодкоманды Тогда + Б.Добавить(О + " *) ;;"); + Б.Добавить(О + " esac"); + Б.Добавить(О + " fi"); + КонецЕсли; + Б.Добавить(О + " ;;"); + +КонецПроцедуры + +Функция НовыйКонтекст(Глубина, Отступ, Буфер) + + К = Новый Структура(); + К.Вставить("Глубина", Глубина); + К.Вставить("Отступ", Отступ); + К.Вставить("Буфер", Буфер); + К.Вставить("ИменаОпций", Новый Массив); + К.Вставить("ОпцииСоЗначениями", Новый Соответствие); + К.Вставить("ЗначенияАргументов", Новый Массив); + К.Вставить("ЕстьПодкоманды", Ложь); + Возврат К; + +КонецФункции + +Функция ПолучитьИменаКоманды(Команда) + + Имена = Новый Массив; + Имена.Добавить(Команда.ПолучитьИмяКоманды()); + Для Каждого Синоним Из Команда.ПолучитьСинонимы() Цикл + Если Синоним <> Команда.ПолучитьИмяКоманды() Тогда + Имена.Добавить(Синоним); + КонецЕсли; + КонецЦикла; + Возврат Имена; + +КонецФункции + +Функция СобратьИменаВсех(Подкоманды) + + Результат = Новый Массив; + Для Каждого Подкоманда Из Подкоманды Цикл + Результат.Добавить(Подкоманда.ПолучитьИмяКоманды()); + КонецЦикла; + Возврат Результат; + +КонецФункции + +Функция БезопасноеИмяФункции(Имя) + + Результат = ""; + Для Инд = 1 По СтрДлина(Имя) Цикл + Символ = Сред(Имя, Инд, 1); + Если (Символ >= "a" И Символ <= "z") + Или (Символ >= "A" И Символ <= "Z") + Или (Символ >= "0" И Символ <= "9") + Или Символ = "_" Тогда + Результат = Результат + Символ; + Иначе + Результат = Результат + "_"; + КонецЕсли; + КонецЦикла; + Возврат Результат; + +КонецФункции diff --git "a/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/internal/completion/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\261\321\205\320\276\320\264\321\207\320\270\320\272\320\232\320\276\320\274\320\260\320\275\320\264\320\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217.os" "b/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/internal/completion/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\261\321\205\320\276\320\264\321\207\320\270\320\272\320\232\320\276\320\274\320\260\320\275\320\264\320\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217.os" new file mode 100644 index 0000000..4b07832 --- /dev/null +++ "b/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/internal/completion/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\261\321\205\320\276\320\264\321\207\320\270\320\272\320\232\320\276\320\274\320\260\320\275\320\264\320\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217.os" @@ -0,0 +1,40 @@ +// Общий обходчик дерева команд для генераторов скриптов автодополнения. +// Генератор-посетитель должен реализовать следующий контракт: +// +// * НачатьКоманду(Команда, Контекст) +// * ПосетитьОпцию(СтрокаОпции, Контекст) +// * ПосетитьАргумент(СтрокаАргумента, Контекст) +// * ПередПодкомандами(Команда, Подкоманды, Контекст) +// * Функция ОткрытьПодкоманду(Подкоманда, Контекст) -> Контекст +// * ЗакрытьПодкоманду(Подкоманда, ПодчинённыйКонтекст, Контекст) +// * ЗавершитьКоманду(Команда, Контекст) +// +// Контекст - произвольная структура, зависящая от посетителя. Обходчик её +// не интерпретирует, а лишь передаёт между методами. ОткрытьПодкоманду +// возвращает новый контекст для подчинённого узла; ЗакрытьПодкоманду +// получает оба контекста, чтобы родитель мог собрать результат дочернего узла. + +Процедура Обойти(Команда, Посетитель, Контекст) Экспорт + + Посетитель.НачатьКоманду(Команда, Контекст); + + Для Каждого СтрокаОпции Из Команда.ПолучитьТаблицуОпций() Цикл + Посетитель.ПосетитьОпцию(СтрокаОпции, Контекст); + КонецЦикла; + + Для Каждого СтрокаАргумента Из Команда.ПолучитьТаблицуАргументов() Цикл + Посетитель.ПосетитьАргумент(СтрокаАргумента, Контекст); + КонецЦикла; + + Подкоманды = Команда.ПолучитьПодкоманды(); + Посетитель.ПередПодкомандами(Команда, Подкоманды, Контекст); + + Для Каждого Подкоманда Из Подкоманды Цикл + ПодчинённыйКонтекст = Посетитель.ОткрытьПодкоманду(Подкоманда, Контекст); + Обойти(Подкоманда, Посетитель, ПодчинённыйКонтекст); + Посетитель.ЗакрытьПодкоманду(Подкоманда, ПодчинённыйКонтекст, Контекст); + КонецЦикла; + + Посетитель.ЗавершитьКоманду(Команда, Контекст); + +КонецПроцедуры diff --git "a/src/core/\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\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217.os" "b/src/core/\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\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217.os" new file mode 100644 index 0000000..6560cef --- /dev/null +++ "b/src/core/\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\224\320\276\320\277\320\276\320\273\320\275\320\265\320\275\320\270\321\217.os" @@ -0,0 +1,59 @@ +// Реализация команды автодополнения командной оболочки. +// Автоматически регистрируется в КонсольноеПриложение как подкоманда "completions". + +#Использовать "./internal/completion" + +Перем ГенераторBash; +Перем ГенераторZsh; +Перем ГенераторPwsh; + +Функция ОписаниеКоманды(Команда) Экспорт + + Команда + .Опция("shell s", , "Командная оболочка, для которой генерируется скрипт") + .ТПеречисление() + .Обязательный() + .Перечисление("bash", "bash", "GNU Bash") + .Перечисление("zsh", "zsh", "Z Shell") + .Перечисление("pwsh", "pwsh", "PowerShell"); + + Возврат Команда; + +КонецФункции + +Процедура ВыполнитьКоманду(Команда) Экспорт + + ТипОболочки = Команда.ЗначениеОпции("shell"); + + ПриложениеCLI = Команда.Приложение; + КореньКоманд = ПриложениеCLI.ПолучитьКоманду(); + ИмяПриложения = КореньКоманд.ПолучитьИмяКоманды(); + + Генератор = ВыбратьГенератор(ТипОболочки); + Скрипт = Генератор.СформироватьСкрипт(ИмяПриложения, КореньКоманд); + + Сообщить(Скрипт); + +КонецПроцедуры + +Функция ВыбратьГенератор(ТипОболочки) + + Если ТипОболочки = "bash" Тогда + Возврат ГенераторBash; + ИначеЕсли ТипОболочки = "zsh" Тогда + Возврат ГенераторZsh; + ИначеЕсли ТипОболочки = "pwsh" Тогда + Возврат ГенераторPwsh; + КонецЕсли; + + ВызватьИсключение "Неизвестный тип оболочки: " + ТипОболочки; + +КонецФункции + +Процедура ПриСозданииОбъекта() + + ГенераторBash = Новый ГенераторДополненияBash(); + ГенераторZsh = Новый ГенераторДополненияZsh(); + ГенераторPwsh = Новый ГенераторДополненияPwsh(); + +КонецПроцедуры diff --git "a/src/core/\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\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" "b/src/core/\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\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" index 78be19d..a17cdd0 100644 --- "a/src/core/\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\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" +++ "b/src/core/\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\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" @@ -3,7 +3,6 @@ #Использовать "./internal/types" #Использовать "./internal/tools" #Использовать "./internal/path" -#Использовать delegate #Использовать logos #Использовать reflector #Использовать fluent @@ -628,7 +627,7 @@ ВызватьИсключение НоваяИнформацияОбОшибке("Ошибка установки действия <ВыполнитьКоманду>. Объект <%1> не содержит требуемого метода <%2>", ОбъектРеализации, ИмяПроцедуры); КонецЕсли; - ДелегатДействия = Делегаты.Создать(ОбъектРеализации, ИмяПроцедуры); + ДелегатДействия = Новый Действие(ОбъектРеализации, ИмяПроцедуры); ДобавитьВИндексДействиеКоманды("ВыполнитьКоманду", ДелегатДействия); КонецПроцедуры @@ -653,7 +652,7 @@ Лог.Отладка(" >> метод %2 у класс <%1> найден", ОбъектРеализации, ИмяПроцедуры); - ДелегатДействия = Делегаты.Создать(ОбъектРеализации, ИмяПроцедуры); + ДелегатДействия = Новый Действие(ОбъектРеализации, ИмяПроцедуры); ДобавитьВИндексДействиеКоманды("ПередВыполнениемКоманды", ДелегатДействия); КонецПроцедуры @@ -678,7 +677,7 @@ Лог.Отладка(" >> метод %2 у класс <%1> найден", ОбъектРеализации, ИмяПроцедуры); - ДелегатДействия = Делегаты.Создать(ОбъектРеализации, ИмяПроцедуры); + ДелегатДействия = Новый Действие(ОбъектРеализации, ИмяПроцедуры); ДобавитьВИндексДействиеКоманды("ПослеВыполненияКоманды", ДелегатДействия); КонецПроцедуры @@ -702,7 +701,7 @@ Лог.Отладка(" >> метод %2 у класс <%1> найден", ОбъектРеализации, ИмяПроцедуры); - ДелегатДействия = Делегаты.Создать(ОбъектРеализации, ИмяПроцедуры); + ДелегатДействия = Новый Действие(ОбъектРеализации, ИмяПроцедуры); ДобавитьВИндексДействиеКоманды("ВывестиСправку", ДелегатДействия); @@ -847,7 +846,7 @@ Возврат Ложь; КонецЕсли; - ДелегатДействия.Исполнить(ЭтотОбъект); + ДелегатДействия.Выполнить(ЭтотОбъект); Возврат Истина; @@ -896,6 +895,7 @@ Таблица.Колонки.Добавить("СкрытьЗначение"); Таблица.Колонки.Добавить("НаименованияПараметров"); Таблица.Колонки.Добавить("Значение"); + Таблица.Колонки.Добавить("ЗначенияДополнения"); Возврат Таблица; @@ -1209,22 +1209,22 @@ КонецЕсли; Если РеализованныеМетодыКоманды.ПередВыполнениемКоманды Тогда - ДелегатДействия = Делегаты.Создать(КлассРеализации, "ПередВыполнениемКоманды"); + ДелегатДействия = Новый Действие(КлассРеализации, "ПередВыполнениемКоманды"); ДобавитьВИндексДействиеКоманды("ПередВыполнениемКоманды", ДелегатДействия); КонецЕсли; Если РеализованныеМетодыКоманды.ВыполнитьКоманду Тогда - ДелегатДействия = Делегаты.Создать(КлассРеализации, "ВыполнитьКоманду"); + ДелегатДействия = Новый Действие(КлассРеализации, "ВыполнитьКоманду"); ДобавитьВИндексДействиеКоманды("ВыполнитьКоманду", ДелегатДействия); КонецЕсли; Если РеализованныеМетодыКоманды.ПослеВыполненияКоманды Тогда - ДелегатДействия = Делегаты.Создать(КлассРеализации, "ПослеВыполненияКоманды"); + ДелегатДействия = Новый Действие(КлассРеализации, "ПослеВыполненияКоманды"); ДобавитьВИндексДействиеКоманды("ПослеВыполненияКоманды", ДелегатДействия); КонецЕсли; Если РеализованныеМетодыКоманды.ВывестиСправку Тогда - ДелегатДействия = Делегаты.Создать(КлассРеализации, "ВывестиСправку"); + ДелегатДействия = Новый Действие(КлассРеализации, "ВывестиСправку"); ДобавитьВИндексДействиеКоманды("ВывестиСправку", ДелегатДействия); КонецЕсли; @@ -1262,6 +1262,7 @@ НоваяЗапись.ПеременнаяОкружения = ПараметрСправки.ПеременнаяОкружения; НоваяЗапись.СкрытьЗначение = ПараметрСправки.СкрытьЗначение; НоваяЗапись.НаименованияПараметров = ПараметрСправки.НаименованияПараметров; + НоваяЗапись.ЗначенияДополнения = ПараметрСправки.ПолучитьЗначенияДополнения(); Если НЕ ПараметрСправки.УстановленаИзПеременнойОкружения Тогда diff --git "a/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\265\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" "b/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\265\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" index 02a639b..04e3e65 100644 --- "a/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\265\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" +++ "b/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/\320\232\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\265\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" @@ -7,6 +7,8 @@ Перем НаименованиеПриложения; Перем ОписаниеПриложения; + + // Процедура добавляет версию приложения, // при вызове данной опции, показывается установленная версия и // завершается выполнение с кодом (0) @@ -208,4 +210,8 @@ Команда = Новый КомандаПриложения(Наименование, Описание, КлассРеализацииОсновныйКоманды, ЭтотОбъект); + Команда.ДобавитьПодкоманду("completions", + "Формирует скрипт автодополнения для командной оболочки", + Новый КомандаДополнения()); + КонецПроцедуры \ No newline at end of file diff --git "a/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\232\320\276\320\274\320\260\320\275\320\264\321\213.os" "b/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\232\320\276\320\274\320\260\320\275\320\264\321\213.os" index 0764c0c..6e9ccb5 100644 --- "a/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\232\320\276\320\274\320\260\320\275\320\264\321\213.os" +++ "b/src/core/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\232\320\276\320\274\320\260\320\275\320\264\321\213.os" @@ -56,6 +56,11 @@ Перем ТипЗначенияПараметра; // Произвольный класс реализуемые несколько обязательных методов Перем РазделительМассива; // Строка +// Объект-владелец метода, предоставляющего варианты автодополнения значений параметра +Перем ОбъектПоставщикаДополнения; // Произвольный +// Имя экспортного метода-функции объекта, возвращающего Массив<Строка> вариантов +Перем ИмяМетодаПоставщикаДополнения; // Строка + Перем Лог; Процедура ПриСозданииОбъекта(ВходящийТипПараметра, @@ -598,6 +603,65 @@ КонецФункции +// Регистрирует поставщик вариантов автодополнения значений параметра. +// Варианты используются командой `completions` для запекания в итоговый скрипт +// автодополнения командной оболочки. +// +// Параметры: +// ОбъектРеализации - Произвольный - объект-владелец метода-поставщика +// ИмяМетода - Строка - имя экспортной функции без параметров, +// возвращающей Массив<Строка> / ФиксированныйМассив +// +// Возвращаемое значение: +// ПараметрКоманды - значение из переменной ЭтотОбъект +// +Функция ПоставщикДополнения(Знач ОбъектРеализации, Знач ИмяМетода) Экспорт + + ОбъектПоставщикаДополнения = ОбъектРеализации; + ИмяМетодаПоставщикаДополнения = ИмяМетода; + + Возврат ЭтотОбъект; + +КонецФункции + +// Возвращает признак наличия поставщика вариантов автодополнения у параметра. +// +// Возвращаемое значение: +// Булево +// +Функция ЕстьПоставщикДополнения() Экспорт + + Возврат ОбъектПоставщикаДополнения <> Неопределено И Не ПустаяСтрока(ИмяМетодаПоставщикаДополнения); + +КонецФункции + +// Вызывает поставщик и возвращает массив вариантов автодополнения. +// При отсутствии поставщика возвращает пустой массив. +// При исключении внутри поставщика — записывает предупреждение в лог и +// возвращает пустой массив, чтобы генерация скрипта не прерывалась. +// +// Возвращаемое значение: +// Массив из Строка +// +Функция ПолучитьЗначенияДополнения() Экспорт + + Если Не ЕстьПоставщикДополнения() Тогда + Возврат Новый Массив; + КонецЕсли; + + Попытка + Действие = Новый Действие(ОбъектПоставщикаДополнения, ИмяМетодаПоставщикаДополнения); + Возврат Действие.Выполнить(); + Исключение + Лог.Предупреждение( + "Поставщик автодополнения ""%1"" завершился с ошибкой: %2", + ИмяМетодаПоставщикаДополнения, + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); + Возврат Новый Массив; + КонецПопытки; + +КонецФункции + #КонецОбласти Функция ВстроенныеТипЗначенийПараметров()