diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1
index f850aded..756feff8 100644
--- a/.claude/skills/form-compile/scripts/form-compile.ps1
+++ b/.claude/skills/form-compile/scripts/form-compile.ps1
@@ -1,4 +1,4 @@
-# form-compile v1.43 — Compile 1C managed form from JSON or object metadata
+# form-compile v1.44 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$JsonPath,
@@ -1563,6 +1563,34 @@ function Emit-MLText {
X "$indent$tag>"
}
+# Детектор «настоящей» inline-разметки форматированного текста (1С: ///…
+# и закрывающий >). Плейсхолдеры вида <не заполнен> НЕ срабатывают (нет известного тега/>).
+# ВАЖНО: regex должен быть идентичен в form-decompile (иначе гибрид-раундтрип поедет).
+$script:fmtMarkupRe = '>|<\s*(?:link|b|i|u|s|color|colorStyle|bgColor|bgColorStyle|font|fontSize|fontStyle|img)(?:\s|>)'
+function Test-HasRealMarkup {
+ param($text)
+ if ($null -eq $text) { return $false }
+ $vals = if ($text -is [System.Collections.IDictionary]) { @($text.Values) }
+ elseif ($text -is [System.Management.Automation.PSCustomObject]) { @($text.PSObject.Properties.Value) }
+ else { @("$text") }
+ foreach ($v in $vals) { if ("$v" -match $script:fmtMarkupRe) { return $true } }
+ return $false
+}
+# DSL-значение ML-поля → @{ text; formatted }. Форма {text, formatted} = явный override;
+# строка/мапа → авто-детект formatted по разметке.
+function Resolve-MLFormatted {
+ param($val)
+ $hasText = $false
+ if ($val -is [System.Management.Automation.PSCustomObject]) { $hasText = [bool]$val.PSObject.Properties['text'] }
+ elseif ($val -is [System.Collections.IDictionary]) { $hasText = $val.Contains('text') }
+ if ($hasText) {
+ $t = if ($val -is [System.Collections.IDictionary]) { $val['text'] } else { $val.text }
+ $f = if ($val -is [System.Collections.IDictionary]) { $val['formatted'] } else { $val.formatted }
+ return @{ text = $t; formatted = [bool]$f }
+ }
+ return @{ text = $val; formatted = (Test-HasRealMarkup $val) }
+}
+
# Каноничные GUID пустых контейнеров ListSettings (умолчание платформы, ~90% форм).
# Декомпилятор опускает пустые настройки → компилятор регенерит этот скелет → раундтрип
# (harness нормализует GUID для хвоста с иными идентификаторами).
@@ -2219,9 +2247,21 @@ function Emit-Events {
}
function Emit-Companion {
- param([string]$tag, [string]$name, [string]$indent)
+ param([string]$tag, [string]$name, [string]$indent, $content = $null)
$id = New-Id
- X "$indent<$tag name=`"$name`" id=`"$id`"/>"
+ $hasContent = $null -ne $content -and -not ($content -is [string] -and "$content" -eq '')
+ if (-not $hasContent) {
+ X "$indent<$tag name=`"$name`" id=`"$id`"/>"
+ return
+ }
+ # Companion с контентом: (расширенная подсказка)
+ X "$indent<$tag name=`"$name`" id=`"$id`">"
+ $r = Resolve-MLFormatted $content
+ $fmt = if ($r.formatted) { 'true' } else { 'false' }
+ X "$indent`t"
+ Emit-MLItems -val $r.text -indent "$indent`t`t"
+ X "$indent`t"
+ X "$indent$tag>"
}
# Табличный addition (СтрокаПоиска/СостояниеПросмотра/УправлениеПоиском) с AdditionSource.
@@ -2316,7 +2356,7 @@ function Emit-Element {
# radio-specific
"radioButtonType"=1;"choiceList"=1;"columnsCount"=1;"checkBoxType"=1;"editMode"=1
# naming & binding
- "name"=1;"path"=1;"title"=1;"tooltip"=1;"tooltipRepresentation"=1
+ "name"=1;"path"=1;"title"=1;"tooltip"=1;"tooltipRepresentation"=1;"extendedTooltip"=1
# visibility & state
"visible"=1;"hidden"=1;"enabled"=1;"disabled"=1;"readOnly"=1;"userVisible"=1
# events ("events" — основной формат; on/handlers — legacy, принимаются ради совместимости)
@@ -2548,7 +2588,7 @@ function Emit-Group {
Emit-Layout -el $el -indent $inner
# Companion: ExtendedTooltip
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
# Children
if ($el.children -and $el.children.Count -gt 0) {
@@ -2590,7 +2630,7 @@ function Emit-ColumnGroup {
Emit-Layout -el $el -indent $inner
# Companion: ExtendedTooltip
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
# Children
if ($el.children -and $el.children.Count -gt 0) {
@@ -2645,7 +2685,7 @@ function Emit-Input {
# Companions
Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
Emit-Events -el $el -elementName $name -indent $inner -typeKey "input"
@@ -2678,7 +2718,7 @@ function Emit-Check {
# Companions
Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
Emit-Events -el $el -elementName $name -indent $inner -typeKey "check"
@@ -2903,7 +2943,7 @@ function Emit-Radio {
# Companions
Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
Emit-Events -el $el -elementName $name -indent $inner -typeKey "radio"
@@ -2935,7 +2975,7 @@ function Emit-Label {
# Companions
Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
Emit-Events -el $el -elementName $name -indent $inner -typeKey "label"
@@ -2961,7 +3001,7 @@ function Emit-LabelField {
# Companions
Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
Emit-Events -el $el -elementName $name -indent $inner -typeKey "labelField"
@@ -3108,7 +3148,7 @@ function Emit-Pages {
Emit-Layout -el $el -indent $inner
# Companion
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
Emit-Events -el $el -elementName $name -indent $inner -typeKey "pages"
@@ -3146,7 +3186,7 @@ function Emit-Page {
Emit-Layout -el $el -indent $inner
# Companion
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
# Children
if ($el.children -and $el.children.Count -gt 0) {
@@ -3244,7 +3284,7 @@ function Emit-Button {
Emit-Layout -el $el -indent $inner
# Companion
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
Emit-Events -el $el -elementName $name -indent $inner -typeKey "button"
@@ -3274,7 +3314,7 @@ function Emit-PictureDecoration {
# Companions
Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
Emit-Events -el $el -elementName $name -indent $inner -typeKey "picture"
@@ -3308,7 +3348,7 @@ function Emit-PictureField {
# Companions
Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
Emit-Events -el $el -elementName $name -indent $inner -typeKey "picField"
@@ -3350,7 +3390,7 @@ function Emit-Calendar {
# Companions
Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
Emit-Events -el $el -elementName $name -indent $inner -typeKey "calendar"
@@ -3398,7 +3438,7 @@ function Emit-ButtonGroup {
Emit-Layout -el $el -indent $inner
# Companion: ExtendedTooltip
- Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner
+ Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip
# Children (кнопки в контексте командной панели)
if ($el.children -and $el.children.Count -gt 0) {
@@ -3676,7 +3716,7 @@ function Emit-Properties {
function Normalize-ElementSynonyms {
param($el)
if ($null -eq $el) { return }
- $synonyms = @{ "commandBar" = "cmdBar"; "autoCommandBar" = "autoCmdBar" }
+ $synonyms = @{ "commandBar" = "cmdBar"; "autoCommandBar" = "autoCmdBar"; "extTooltip" = "extendedTooltip" }
foreach ($pair in $synonyms.GetEnumerator()) {
if ($null -ne $el.PSObject.Properties[$pair.Key] -and $null -eq $el.PSObject.Properties[$pair.Value]) {
$val = $el.($pair.Key)
diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py
index fec14f8c..4e991026 100644
--- a/.claude/skills/form-compile/scripts/form-compile.py
+++ b/.claude/skills/form-compile/scripts/form-compile.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# form-compile v1.43 — Compile 1C managed form from JSON or object metadata
+# form-compile v1.44 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import copy
@@ -1761,7 +1761,7 @@ KNOWN_KEYS = {
"button", "picture", "picField", "calendar", "cmdBar", "popup",
"showInHeader",
"radioButtonType", "choiceList", "columnsCount", "checkBoxType", "editMode",
- "name", "path", "title", "tooltip", "tooltipRepresentation",
+ "name", "path", "title", "tooltip", "tooltipRepresentation", "extendedTooltip",
"visible", "hidden", "enabled", "disabled", "readOnly", "userVisible",
"events", "on", "handlers",
"selectionMode", "showCurrentDate", "widthInMonths", "heightInMonths", "showMonthsPanel",
@@ -2012,9 +2012,37 @@ def emit_events(lines, el, element_name, indent, type_key):
lines.append(f"{indent}")
-def emit_companion(lines, tag, name, indent):
+# Детектор «настоящей» inline-разметки (1С: ///… и >). Должен быть
+# идентичен form-decompile/form-compile.ps1, иначе гибрид-раундтрип поедет.
+_FMT_MARKUP_RE = re.compile(r'>|<\s*(?:link|b|i|u|s|color|colorStyle|bgColor|bgColorStyle|font|fontSize|fontStyle|img)(?:\s|>)', re.I)
+
+
+def _has_real_markup(text):
+ if text is None:
+ return False
+ vals = list(text.values()) if isinstance(text, dict) else [text]
+ return any(_FMT_MARKUP_RE.search(str(v)) for v in vals)
+
+
+def resolve_ml_formatted(val):
+ # {text, formatted} = явный override; строка/мапа → авто-детект formatted
+ if isinstance(val, dict) and 'text' in val:
+ return val['text'], bool(val.get('formatted'))
+ return val, _has_real_markup(val)
+
+
+def emit_companion(lines, tag, name, indent, content=None):
cid = new_id()
- lines.append(f'{indent}<{tag} name="{name}" id="{cid}"/>')
+ has_content = content is not None and not (isinstance(content, str) and content == '')
+ if not has_content:
+ lines.append(f'{indent}<{tag} name="{name}" id="{cid}"/>')
+ return
+ lines.append(f'{indent}<{tag} name="{name}" id="{cid}">')
+ text, fmt = resolve_ml_formatted(content)
+ lines.append(f'{indent}\t')
+ emit_ml_items(lines, f'{indent}\t\t', text)
+ lines.append(f'{indent}\t')
+ lines.append(f'{indent}{tag}>')
def emit_table_addition(lines, tag, table_name, name_suffix, src_type, indent):
@@ -2422,7 +2450,7 @@ def emit_group(lines, el, name, eid, indent):
emit_layout(lines, el, inner)
# Companion: ExtendedTooltip
- emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip'))
# Children
if el.get('children') and len(el['children']) > 0:
@@ -2459,7 +2487,7 @@ def emit_column_group(lines, el, name, eid, indent):
emit_common_flags(lines, el, inner)
emit_layout(lines, el, inner)
- emit_companion(lines, 'ExtendedTooltip', f'{name}РасширеннаяПодсказка', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}РасширеннаяПодсказка', inner, el.get('extendedTooltip'))
if el.get('children') and len(el['children']) > 0:
lines.append(f'{inner}')
@@ -2512,7 +2540,7 @@ def emit_input(lines, el, name, eid, indent):
# Companions
emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner)
- emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip'))
emit_events(lines, el, name, inner, 'input')
@@ -2545,7 +2573,7 @@ def emit_check(lines, el, name, eid, indent):
# Companions
emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner)
- emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip'))
emit_events(lines, el, name, inner, 'check')
@@ -2604,7 +2632,7 @@ def emit_radio_button_field(lines, el, name, eid, indent):
emit_layout(lines, el, inner)
emit_companion(lines, 'ContextMenu', f'{name}КонтекстноеМеню', inner)
- emit_companion(lines, 'ExtendedTooltip', f'{name}РасширеннаяПодсказка', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}РасширеннаяПодсказка', inner, el.get('extendedTooltip'))
emit_events(lines, el, name, inner, 'radio')
@@ -2635,7 +2663,7 @@ def emit_label(lines, el, name, eid, indent):
# Companions
emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner)
- emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip'))
emit_events(lines, el, name, inner, 'label')
@@ -2663,7 +2691,7 @@ def emit_label_field(lines, el, name, eid, indent):
# Companions
emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner)
- emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip'))
emit_events(lines, el, name, inner, 'labelField')
@@ -2815,7 +2843,7 @@ def emit_pages(lines, el, name, eid, indent):
emit_layout(lines, el, inner)
# Companion
- emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip'))
emit_events(lines, el, name, inner, 'pages')
@@ -2849,7 +2877,7 @@ def emit_page(lines, el, name, eid, indent):
emit_layout(lines, el, inner)
# Companion
- emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip'))
# Children
if el.get('children') and len(el['children']) > 0:
@@ -2932,7 +2960,7 @@ def emit_button(lines, el, name, eid, indent, in_cmd_bar=False):
emit_layout(lines, el, inner)
# Companion
- emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip'))
emit_events(lines, el, name, inner, 'button')
@@ -2960,7 +2988,7 @@ def emit_picture_decoration(lines, el, name, eid, indent):
# Companions
emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner)
- emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip'))
emit_events(lines, el, name, inner, 'picture')
@@ -2994,7 +3022,7 @@ def emit_picture_field(lines, el, name, eid, indent):
# Companions
emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner)
- emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip'))
emit_events(lines, el, name, inner, 'picField')
@@ -3032,7 +3060,7 @@ def emit_calendar(lines, el, name, eid, indent):
# Companions
emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner)
- emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip'))
emit_events(lines, el, name, inner, 'calendar')
@@ -3101,7 +3129,7 @@ def emit_button_group(lines, el, name, eid, indent):
emit_layout(lines, el, inner)
# Companion: ExtendedTooltip
- emit_companion(lines, 'ExtendedTooltip', f'{name}РасширеннаяПодсказка', inner)
+ emit_companion(lines, 'ExtendedTooltip', f'{name}РасширеннаяПодсказка', inner, el.get('extendedTooltip'))
# Children (кнопки в контексте командной панели)
if el.get('children') and len(el['children']) > 0:
@@ -3575,7 +3603,7 @@ def main():
def _normalize_synonyms(el):
if not isinstance(el, dict):
return
- synonyms = {'commandBar': 'cmdBar', 'autoCommandBar': 'autoCmdBar'}
+ synonyms = {'commandBar': 'cmdBar', 'autoCommandBar': 'autoCmdBar', 'extTooltip': 'extendedTooltip'}
for src, dst in synonyms.items():
if src in el and dst not in el:
el[dst] = el.pop(src)
diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1
index 751b0510..74595cb6 100644
--- a/.claude/skills/form-decompile/scripts/form-decompile.ps1
+++ b/.claude/skills/form-decompile/scripts/form-decompile.ps1
@@ -1,4 +1,4 @@
-# form-decompile v0.25 — Decompile 1C managed Form.xml to JSON DSL (draft)
+# form-decompile v0.26 — Decompile 1C managed Form.xml to JSON DSL (draft)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
param(
@@ -230,6 +230,27 @@ function Get-LangText {
return $map
}
+# Детектор «настоящей» inline-разметки форматированного текста (идентичен form-compile!).
+$script:fmtMarkupRe = '>|<\s*(?:link|b|i|u|s|color|colorStyle|bgColor|bgColorStyle|font|fontSize|fontStyle|img)(?:\s|>)'
+function Test-HasRealMarkup {
+ param($text)
+ if ($null -eq $text) { return $false }
+ $vals = if ($text -is [System.Collections.IDictionary]) { @($text.Values) } else { @("$text") }
+ foreach ($v in $vals) { if ("$v" -match $script:fmtMarkupRe) { return $true } }
+ return $false
+}
+# Title-узел → DSL-значение ML-поля (гибрид): строка/мапа когда авто-детект formatted
+# совпал с атрибутом; иначе явный {text, formatted}.
+function Get-MLFormattedValue {
+ param($titleNode)
+ if (-not $titleNode) { return $null }
+ $text = Get-LangText $titleNode
+ if ($null -eq $text) { return $null }
+ $fmtAttr = ($titleNode.GetAttribute('formatted') -eq 'true')
+ if ($fmtAttr -eq (Test-HasRealMarkup $text)) { return $text }
+ $o = [ordered]@{}; $o['text'] = $text; $o['formatted'] = $fmtAttr; return $o
+}
+
# Прочитать дочерний скаляр (по local-name, без namespace)
function Get-Child {
param($node, [string]$name)
@@ -1086,6 +1107,9 @@ function Decompile-Element {
if ($autoTitle) { $obj['title'] = '' }
}
Add-Layout $obj $node
+ # extendedTooltip: контент companion (любой элемент)
+ $etTitle = $node.SelectSingleNode("lf:ExtendedTooltip/lf:Title", $ns)
+ if ($etTitle) { $et = Get-MLFormattedValue $etTitle; if ($null -ne $et) { $obj['extendedTooltip'] = $et } }
return $obj
}
diff --git a/docs/form-dsl-spec.md b/docs/form-dsl-spec.md
index e17b8671..bd800883 100644
--- a/docs/form-dsl-spec.md
+++ b/docs/form-dsl-spec.md
@@ -118,6 +118,18 @@
| `titleLocation` | string | Расположение заголовка: `none`/`left`/`right`/`top`/`bottom`/`auto`. Эмитится при наличии (input, labelField, picField, table, calendar). У `check`/`radio` — особая семантика с умным дефолтом (см. их разделы) |
| `tooltip` | string/object | Всплывающая подсказка элемента (``). Строка → ru, объект `{ "ru": …, "en": … }` → мультиязычный (как `title`). Эмитится сразу после `title` |
| `tooltipRepresentation` | string | Режим показа подсказки (``): `None`, `Button`, `ShowBottom`, `ShowTop`, `ShowLeft`, `ShowRight`, `ShowAuto`, `Balloon`. Эмитится при наличии |
+| `extendedTooltip` | string/object | Расширенная подсказка (контент companion ``). См. форму ML-текста ниже. Синоним: `extTooltip` |
+
+#### Форма ML-текста и `formatted`
+
+`title`/`tooltip`/`extendedTooltip` принимают:
+- `"строка"` — ru-текст;
+- `{ "ru": "…", "en": "…" }` — многоязычный;
+- `{ "text": <строка|мапа>, "formatted": true }` — **форматированный** текст (атрибут ``).
+
+**`formatted`** включает интерпретацию inline-разметки в тексте (1С-формат, похож на BBCode): `…>`, ``, ``, `…>`, ``, ``, ``, `…>`, `
`; закрывающий тег — `>`. Текст несётся **raw** (разметка — часть строки), парсинг не требуется.
+
+Флаг авто-детектится по наличию известной разметки/`>`: для plain-строки объект не нужен. Явная форма `{text, formatted}` — только когда авто-детект неверен (formatted-текст без разметки, либо буквальные `<…>`-плейсхолдеры в неформатированном).
### 4.1a. Общие layout-свойства