Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
fde0258
[MOB-59261] Удаляет плагины hh-carnival и hh-garcon
PStrelchenko Apr 18, 2026
310a5f4
[MOB-59261] Переносит контент всех shared-модулей в main sourceSet пл…
PStrelchenko Apr 18, 2026
fe9324e
[MOB-59261] Удаляет остатки shared-модулей из проекта
PStrelchenko Apr 18, 2026
6a20232
[MOB-59261] Переносит исходники плагина Geminio в корень проекта, так…
PStrelchenko Apr 19, 2026
e7b647f
[MOB-59261] Переносит документацию Geminio ближе к корню проекта
PStrelchenko Apr 19, 2026
6115bbd
[MOB-59261] Обновляет версию Gradle до 9.4.1
PStrelchenko Apr 19, 2026
489217a
[MOB-59261] Переносит настройку плагина в settings.gradle и корневой …
PStrelchenko Apr 19, 2026
03d9227
[MOB-59261] Переносит оставшийся скрипт git-hook в новую папку
PStrelchenko Apr 19, 2026
499511c
[MOB-59261] Немного уточняет .gitignore
PStrelchenko Apr 19, 2026
d8b94b2
[MOB-59261] Исправляет работу detekt и формирует актуальный baseline
PStrelchenko Apr 19, 2026
0f54bf8
[MOB-59261] Исправляет GitHub worflow после упрощения конфигурации
PStrelchenko Apr 19, 2026
7387fda
[MOB-59261] И ещё раз немного уточняет .gitignore
PStrelchenko Apr 19, 2026
d3234de
[MOB-59261] -- Обновляет версию Detekt в GitHub Action
PStrelchenko Apr 19, 2026
7d3280d
[MOB-59261] -- Исправляет id плагина
PStrelchenko Apr 19, 2026
f7f185e
[MOB-59318] Добавляет несколько тестов на текущее поведение плагина (…
PStrelchenko Apr 19, 2026
fc07972
[MOB-59318] Добавляет runtime для работы UI-формы, отвязанный от внут…
PStrelchenko Apr 19, 2026
e60b100
[MOB-59318] Мигрирует построение UI шаблона Geminio на кастомный диал…
PStrelchenko Apr 19, 2026
a186fde
[MOB-59318] Мигрирует построение UI шаблона модулей Geminio на кастом…
PStrelchenko Apr 19, 2026
fef7e2c
[MOB-59318] Убирает ненужные фабрики диалогов после перехода на касто…
PStrelchenko Apr 19, 2026
3dc8036
[MOB-59318] Добавляет новый кастомный runtime для выполнения geminio-…
PStrelchenko Apr 20, 2026
c3b81d8
[MOB-59318] Добавляет механику Undo для создания модулей и создания ф…
PStrelchenko Apr 20, 2026
f349215
[MOB-59318] Убирает версию runtime, завязанную на шаблоны Android Stu…
PStrelchenko Apr 20, 2026
e90cfa3
[MOB-59318] Убирает вызовы TemplateUtils
PStrelchenko Apr 20, 2026
4cb262e
[MOB-59318] Убирает вызовы android-плагина (TemplateUtils и ReformatU…
PStrelchenko Apr 20, 2026
841e007
[MOB-59318] Переносит adapter-слой вокруг android-плагина в отдельный…
PStrelchenko Apr 20, 2026
ad72a12
[MOB-59318] Поднимает версию плагина
PStrelchenko Apr 20, 2026
051e81f
[MOB-59318] Исправляет замечания detekt в тестах
PStrelchenko Apr 20, 2026
09896f6
[MOB-59318] Исправляет замечания detekt в kts-скриптах
PStrelchenko Apr 20, 2026
82acf1c
[MOB-59319] Добавляет поддержку suggest-параметров
PStrelchenko Apr 20, 2026
ee4a347
[MOB-59319] Исправляет ссылку в одном из файлов документации
PStrelchenko Apr 20, 2026
8708778
[MOB-59319] Дописывает изменения в CHANGELOG
PStrelchenko Apr 20, 2026
739aacd
[MOB-59261] Исправляет замечание от ИИ — исправляет документацию по о…
PStrelchenko Apr 25, 2026
6a81c27
[MOB-59261] Исправляет замечание от ИИ — добавляет проверку на сущест…
PStrelchenko Apr 25, 2026
bcf6d72
[MOB-59318] Merge branch 'MOB-59261__simplify_geminio_project_setup' …
PStrelchenko Apr 25, 2026
4e7b79d
[MOB-59318] Исправляет замечания от ИИ — возвращает поддержку валидац…
PStrelchenko Apr 25, 2026
6abeb7d
[MOB-59318] Исправляет замечания от ИИ — возвращает обработку Freemar…
PStrelchenko Apr 25, 2026
e4b807c
[MOB-59318] Убирает константу String.EMPTY
PStrelchenko Apr 25, 2026
f3a03ee
[MOB-59318] Исправляет замечание от ИИ — исправляет формирование путе…
PStrelchenko Apr 25, 2026
62fd6fe
[MOB-59319] Merge branch 'MOB-59318__custom_geminio_ui_and_executor' …
PStrelchenko Apr 25, 2026
a39b32b
[MOB-59319] Исправляет ошибки после merge предыдущей задачи
PStrelchenko Apr 25, 2026
781b0c3
[MOB-59319] Исправляет замечания ИИ — добавляет защиту от дублировани…
PStrelchenko Apr 25, 2026
03fa95f
[MOB-59319] Merge branch 'master' into MOB-59319__enum_parameters_for…
PStrelchenko Apr 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

## [2.0.0]

### Added

- `suggestParameter` — a searchable string-backed parameter with optional `sealed` mode, inline options and `options.source` CSV support.
- Support `==` and `!=` operators for string-backed parameters in boolean expressions such as `visibility` and `availability`.
- Undo support for recipe execution actions.

### Changed

- Rewrites runtime and UI of plugin to avoid Android Studio dependencies as much as possible.
- Rewrite Geminio runtime, UI and execution pipeline to reduce Android Studio-specific dependencies as much as possible.

## [1.15.0]

Expand Down
13 changes: 10 additions & 3 deletions docs/en/EXPRESSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Examples of expressions for the `widgets` section:
suggest: fragment_${className.classToResource().underscoreToCamelCase()}
visibility: ${includeModule}
availability: true
# visibility: ${uiFramework} == compose
# availability: ${uiFramework} != views
```

The text inside `${}` is considered the «dynamic» part of the expression, which needs to be
Expand All @@ -28,9 +30,14 @@ Additional extension functions can be used for text parameters:
- `layoutToFragment`;
- `underscoreToCamelCase`.

There are special values for boolean expressions - `true` / `false`
Boolean expressions currently support:

+ you can use only boolean-parameters inside ${} for them
- `true` / `false`;
- `${booleanParameter}`;
- `${stringOrSuggestParameter} == value`;
- `${stringOrSuggestParameter} != value`.

Logical `&&` / `||` are not supported right now.

Examples of expressions for the recipe section:

Expand Down Expand Up @@ -62,4 +69,4 @@ In the `recipe` section, we add several additional parameters for string values:

---

[Return to MoC](../../README_EN.md)
[Return to MoC](../../README_EN.md)
28 changes: 27 additions & 1 deletion docs/en/RECIPE_CONTENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@ widgets:
help: Generate fragment Toothpick Module for easy instantiation
default: true

- suggestParameter:
id: uiFramework
name: UI framework
help: Which UI stack should be generated
default: compose
sealed: true
options:
- value: compose
label: Compose
- value: views
label: Views

- suggestParameter:
id: targetModule
name: Target module
help: Module for integration
sealed: true
options:
source: options/modules.csv

- stringParameter:
id: moduleName
name: Fragment Toothpick Module
Expand All @@ -79,6 +99,12 @@ widgets:
visibility: ${includeModule}
suggest: ${className.classToResource().underscoreToCamelCase()}Module

- stringParameter:
id: composePackage
name: Compose package
default: ru.hh.feature.compose
visibility: ${uiFramework} == compose

globals:
- stringParameter:
id: reducerClassName
Expand Down Expand Up @@ -144,7 +170,7 @@ The recipe consists of 6 sections:
- `optionalParams` — optional parameters;
- `predefinedFeatures` - a set of predefined features in Geminio, which can add new widgets to the template, supplement
the functionality.
- `widgets` — description of template parameters; only string and boolean parameters are available for use;
- `widgets` — description of template parameters; string, boolean and suggest parameters are available for use;
- `globals` - description of invisible parameters for templates, some "global" variables.
- `recipe` — a set of instructions that should be executed.

Expand Down
50 changes: 48 additions & 2 deletions docs/en/recipe_content/WIDGETS.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
### `widgets` section

The `widget` section is a user's parameter list for your template. For now, we support only string and boolean
parameters. Each parameter supports [expression](../EXPRESSIONS.md) evaluation.
The `widget` section is a user's parameter list for your template. For now, we support string,
boolean and searchable suggest parameters. Each parameter supports
[expression](../EXPRESSIONS.md) evaluation.

#### `stringParameter`

Expand Down Expand Up @@ -65,6 +66,51 @@ a module, some additional method, and so on). Will be converted to a checkbox on

Has exactly the same parameters as `stringParameter`, but `booleanParameter` has no `suggest`.

#### `suggestParameter`

`suggestParameter` — description of a string-backed parameter rendered as a searchable completion field.

Has the same base parameters as `stringParameter`, including `suggest`, `visibility` and `availability`,
plus the following fields:

- `sealed` — optional boolean flag. Defaults to `false`.
When `sealed: true`, the final value should match one of the declared options.
- `options` — required source of suggested values. Can be declared in one of two forms:

* inline list:

```yaml
options:
- value: compose
label: Compose
- value: views
```

* external CSV file relative to `recipe.yaml`:

```yaml
options:
source: options/ui_frameworks.csv
```

Inline options and CSV rows support:

- `value` — the actual value exposed to expressions and FreeMarker templates;
- `label` — optional text shown in the UI. If omitted, Geminio uses `value`. Labels should be
unique within one `suggestParameter`.

CSV files are read as UTF-8 and support either `value` or `value,label` rows. The optional
`value,label` header is ignored automatically.

Additional notes:

- `default` should match one of `options.value` only when `sealed: true`;
- `suggest` is evaluated in terms of stored values, not labels;
- for `sealed: true`, if `suggest` returns a value that is not present in `options`, Geminio does
not apply it. Instead, it keeps the current value when it is still valid; otherwise it uses
`default`, and if `default` is also missing or invalid, it falls back to the first option;
- for `sealed: false`, any entered string is accepted, while `options` only power completion.

---

[Back to `recipe.yaml` content](../RECIPE_CONTENT.md)
13 changes: 10 additions & 3 deletions docs/ru/EXPRESSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
suggest: fragment_${className.classToResource().underscoreToCamelCase()}
visibility: ${includeModule}
availability: true
# visibility: ${uiFramework} == compose
# availability: ${uiFramework} != views
```

Текст внутри `${}` считается за "динамическую" часть выражения, которую требуется вычислять в зависимости от содержания,
Expand All @@ -27,9 +29,14 @@ availability: true
- `layoutToFragment`
- `underscoreToCamelCase`

Для булевских выражений есть специальные значения - `true` / `false`
Для булевских выражений сейчас поддерживаются:

+ для них возможно использование только boolean-параметров
- `true` / `false`
- `${booleanParameter}`
- `${stringOrSuggestParameter} == value`
- `${stringOrSuggestParameter} != value`

Логические `&&` / `||` пока не поддерживаются.

Примеры выражений для секции `recipe`:

Expand Down Expand Up @@ -64,4 +71,4 @@ availability: true

---

[Обратно к содержанию](../../plugins/hh-geminio/README.md#Содержание)
[Обратно к содержанию](../../README.md#Содержание)
28 changes: 27 additions & 1 deletion docs/ru/RECIPE_CONTENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@ widgets:
help: Generate fragment Toothpick Module for easy instantiation
default: true

- suggestParameter:
id: uiFramework
name: UI framework
help: Which UI stack should be generated
default: compose
sealed: true
options:
- value: compose
label: Compose
- value: views
label: Views

- suggestParameter:
id: targetModule
name: Target module
help: Module for integration
sealed: true
options:
source: options/modules.csv

- stringParameter:
id: moduleName
name: Fragment Toothpick Module
Expand All @@ -79,6 +99,12 @@ widgets:
visibility: ${includeModule}
suggest: ${className.classToResource().underscoreToCamelCase()}Module

- stringParameter:
id: composePackage
name: Compose package
default: ru.hh.feature.compose
visibility: ${uiFramework} == compose

globals:
- stringParameter:
id: reducerClassName
Expand Down Expand Up @@ -143,7 +169,7 @@ recipe:
- `requiredParams` - обязательные параметры для вашего шаблона
- `optionalParams` - соответственно, необязательные параметры
- `predefinedFeatures` - набор заранее предопределённых фич в Geminio, которые могут добавлять новые виджеты в шаблон, дополнять функционал.
- `widgets` - описание параметров шаблона - для использования доступны строковые и булевские параметры
- `widgets` - описание параметров шаблона - для использования доступны строковые, булевские и suggest-параметры
- `globals` - описание невидимых параметров для шаблонов, некие "глобальные" переменные.
- `recipe` - сам рецепт, набор инструкций, которые нужно выполнить

Expand Down
48 changes: 47 additions & 1 deletion docs/ru/recipe_content/WIDGETS.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
### Секция `widgets`

Секция виджетов - это список параметров вашего шаблона, которые зависят от пользователя.
В данный момент поддерживаются строковые и булевские параметры.
На данный момент секция поддерживает строковые, булевские и suggest-параметры с поиском.
Параметры поддерживают вычисление [выражений](../EXPRESSIONS.md).

#### `stringParameter`
Expand Down Expand Up @@ -67,6 +67,52 @@

Имеет ровно такие же параметры, как и `stringParamter`, только у `booleanParameter` нет `suggest`.

#### `suggestParameter`

`suggestParameter` - описание строкового параметра, который на UI отображается как поле с поиском
и completion-подсказками.

Имеет те же базовые параметры, что и `stringParameter`, включая `suggest`, `visibility` и
`availability`, а также следующие поля:

- `sealed` - необязательный флаг. По умолчанию `false`.
При `sealed: true` итоговое значение должно совпадать с одним из объявленных option.
- `options` - обязательный источник значений для подсказок. Можно задать в одном из двух видов:

* прямо в recipe:

```yaml
options:
- value: compose
label: Compose
- value: views
```

* через внешний CSV-файл относительно `recipe.yaml`:

```yaml
options:
source: options/ui_frameworks.csv
```

И inline-значения, и строки CSV поддерживают:

- `value` - фактическое значение, которое попадёт в выражения и FreeMarker-шаблоны
- `label` - необязательный текст, который будет показан пользователю на UI. Если его не задать,
Geminio использует `value`. Значения `label` должны быть уникальными внутри одного `suggestParameter`

CSV-файлы читаются как UTF-8 и поддерживают строки вида `value` или `value,label`. Необязательный
заголовок `value,label` будет автоматически проигнорирован.

Дополнительно:

- `default` должен совпадать с одним из `options.value` только при `sealed: true`
- `suggest` вычисляется в терминах сохраняемого значения, а не `label`
- при `sealed: true`, если `suggest` вернул значение, которого нет в `options`, Geminio не будет
применять его. Вместо этого он оставит текущее значение, если оно всё ещё валидно; иначе
возьмёт `default`, а если и `default` отсутствует или невалиден - откатится к первому option
- при `sealed: false` можно ввести любую строку, а `options` используются только для completion.

---

[Обратно к устройству "рецептов"](../RECIPE_CONTENT.md)
38 changes: 38 additions & 0 deletions src/main/kotlin/ru/hh/plugins/geminio/sdk/form/GeminioForm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,44 @@ internal sealed class GeminioFormField {
val defaultValue: Boolean? = null,
val initialValueEvaluator: GeminioFormBooleanEvaluator? = null,
) : GeminioFormField()

/**
* Searchable completion field with optional closed-set validation.
*/
data class SuggestField(
override val id: String,
override val name: String,
override val help: String?,
override val origin: GeminioFormFieldOrigin,
override val visibilityEvaluator: GeminioFormBooleanEvaluator? = null,
override val availabilityEvaluator: GeminioFormBooleanEvaluator? = null,
val defaultValue: String? = null,
val isSealed: Boolean = false,
val initialValueEvaluator: GeminioFormStringEvaluator? = null,
val suggestEvaluator: GeminioFormStringEvaluator? = null,
val options: List<GeminioFormSuggestOption>,
) : GeminioFormField() {

init {
require(options.isNotEmpty()) {
"Suggest field '$id' should contain at least one option."
}
}

fun containsValue(value: String?): Boolean {
return value != null && options.any { option -> option.value == value }
}

fun findOption(textOrValue: String?): GeminioFormSuggestOption? {
return options.firstOrNull { option ->
option.value == textOrValue || option.label == textOrValue
}
}

fun resolveStoredValue(input: String?): String? {
return findOption(input)?.value ?: input
}
}
}

/**
Expand Down
Loading
Loading