| 1 | #!/usr/bin/env python3 |
| 2 | """Fix intent-catalog.toml: restore melody_*, slash.args, append slashes at block end.""" |
| 3 | from __future__ import annotations |
| 4 | |
| 5 | import re |
| 6 | from pathlib import Path |
| 7 | |
| 8 | ROOT = Path(__file__).resolve().parents[1] / "IntentMelody" / "intent-catalog.toml" |
| 9 | |
| 10 | MELODY: dict[str, list[str]] = { |
| 11 | "apply_edit": [ |
| 12 | 'melody_slug = "eld"', |
| 13 | 'melody_shape = "parametric"', |
| 14 | 'melody_tail_signature = "<start:ln>:<end:ln>"', |
| 15 | 'melody_wire_class = "int_chain_colon_space"', |
| 16 | 'melody_chord_commit = "enter"', |
| 17 | 'melody_palette_usage_hint = "c:eld:<start>:<end> или одна строка c:eld:<line> (в аккорде c:eld;<start>;<end> / c:eld;<line> — «;» без Shift) — удалить строки"', |
| 18 | 'melody_palette_usage_category = "Editor -> Line -> Delete"', |
| 19 | ], |
| 20 | "select": [ |
| 21 | 'melody_slug = "els"', |
| 22 | 'melody_shape = "parametric"', |
| 23 | 'melody_tail_signature = "<start:ln>:<end:ln>"', |
| 24 | 'melody_wire_class = "int_chain_colon_space"', |
| 25 | 'melody_chord_commit = "enter"', |
| 26 | 'melody_palette_usage_hint = "c:els:<start>:<end> или одна строка c:els:<line> (в аккорде c:els;<start>;<end> / c:els;<line> — «;» без Shift) — выделить строки"', |
| 27 | 'melody_palette_usage_category = "Editor -> Line -> Select"', |
| 28 | ], |
| 29 | "chat_export_readable": ['melody_slug = "cex"', 'melody_shape = "simple"'], |
| 30 | "chat_open_selected_thread": ['melody_slug = "ato"', 'melody_shape = "simple"'], |
| 31 | "chat_select_next_message": ['melody_slug = "amn"', 'melody_shape = "simple"'], |
| 32 | "chat_select_next_thread": ['melody_slug = "atn"', 'melody_shape = "simple"'], |
| 33 | "chat_select_prev_message": ['melody_slug = "amp"', 'melody_shape = "simple"'], |
| 34 | "chat_select_prev_thread": ['melody_slug = "atp"', 'melody_shape = "simple"'], |
| 35 | "chat_show_thread_overview": ['melody_slug = "atb"', 'melody_shape = "simple"'], |
| 36 | "chat_toggle_selected_thinking": ['melody_slug = "amt"', 'melody_shape = "simple"'], |
| 37 | "chat_toggle_show_thinking_in_history": ['melody_slug = "amh"', 'melody_shape = "simple"'], |
| 38 | "fork_chat_thread": ['melody_slug = "ctf"', 'melody_shape = "simple"'], |
| 39 | "send_chat": ['melody_slug = "cs"', 'melody_shape = "simple"'], |
| 40 | "show_chat_page": ['melody_slug = "cps"', 'melody_shape = "simple"'], |
| 41 | "build_solution_ui": ['melody_slug = "br"', 'melody_shape = "simple"'], |
| 42 | "build_structured": ['melody_slug = "bs"', 'melody_shape = "simple"'], |
| 43 | "run_tests": ['melody_slug = "bt"', 'melody_shape = "simple"'], |
| 44 | "debug_attach": ['melody_slug = "da"', 'melody_shape = "simple"'], |
| 45 | "debug_continue": ['melody_slug = "dc"', 'melody_shape = "simple"'], |
| 46 | "debug_launch": ['melody_slug = "dl"', 'melody_shape = "simple"'], |
| 47 | "debug_step_into": ['melody_slug = "di"', 'melody_shape = "simple"'], |
| 48 | "debug_step_out": ['melody_slug = "df"', 'melody_shape = "simple"'], |
| 49 | "debug_step_over": ['melody_slug = "dn"', 'melody_shape = "simple"'], |
| 50 | "debug_stop": ['melody_slug = "dx"', 'melody_shape = "simple"'], |
| 51 | "git_commit": ['melody_slug = "gc"', 'melody_shape = "simple"'], |
| 52 | "git_push": ['melody_slug = "gp"', 'melody_shape = "simple"'], |
| 53 | "git_status": ['melody_slug = "gs"', 'melody_shape = "simple"'], |
| 54 | "git_submodule": ['melody_slug = "gsu"', 'melody_shape = "simple"'], |
| 55 | "open_solution_dialog": ['melody_slug = "so"', 'melody_shape = "simple"'], |
| 56 | "toggle_workspace_splitters_lock": ['melody_slug = "tol"', 'melody_shape = "simple"'], |
| 57 | "show_environment_readiness_page": ['melody_slug = "ers"', 'melody_shape = "simple"'], |
| 58 | "show_hybrid_index_page": ['melody_slug = "his"', 'melody_shape = "simple"'], |
| 59 | "show_terminal_panel": ['melody_slug = "ts"', 'melody_shape = "simple"'], |
| 60 | "show_web_ai_portal_page": [ |
| 61 | 'melody_slug = "wai"', |
| 62 | 'melody_shape = "parametric"', |
| 63 | "melody_show_usage_hint_if_bare_slug = false", |
| 64 | 'melody_tail_signature = "<url:url>"', |
| 65 | 'melody_wire_class = "url_remainder"', |
| 66 | 'melody_chord_commit = "enter"', |
| 67 | 'melody_palette_hint_slug = "wai-url"', |
| 68 | 'melody_palette_usage_hint = "c:wai:<адрес> - веб-портал AI; адрес можно без схемы (или c:wai: для страницы по умолчанию)"', |
| 69 | 'melody_palette_usage_category = "Web AI Portal"', |
| 70 | ], |
| 71 | } |
| 72 | |
| 73 | ARGS_AFTER: dict[str, list[str]] = { |
| 74 | "/intercom show": ["", "[command.form.slash.args]", 'surface = "intercom"'], |
| 75 | "/editor show": ["", "[command.form.slash.args]", 'surface = "editor"'], |
| 76 | "/output show": ["", "[command.form.slash.args]", 'page = "Build"'], |
| 77 | "/tests show": ["", "[command.form.slash.args]", 'page = "Tests"'], |
| 78 | "/debug show": ["", "[command.form.slash.args]", 'page = "DebugStack"'], |
| 79 | "/repository show": ["", "[command.form.slash.args]", 'page = "Git"'], |
| 80 | "/editor panel": ["", "[command.form.slash.args]", 'page = "Editor"'], |
| 81 | "/terminal show": ["", "[command.form.slash.args]", 'page = "Terminal"'], |
| 82 | "/problems show": ["", "[command.form.slash.args]", 'page = "Problems"'], |
| 83 | "/events show": ["", "[command.form.slash.args]", 'page = "Events"'], |
| 84 | "/workspace show": ["", "[command.form.slash.args]", 'page = "WorkspaceHealth"'], |
| 85 | "/settings show": ["", "[command.form.slash.args]", 'page = "AiChatSettings"'], |
| 86 | } |
| 87 | |
| 88 | |
| 89 | def insert_melodies(lines: list[str]) -> list[str]: |
| 90 | out: list[str] = [] |
| 91 | i = 0 |
| 92 | while i < len(lines): |
| 93 | line = lines[i] |
| 94 | out.append(line) |
| 95 | m = re.match(r'^command_id = "([^"]*)"', line.strip()) |
| 96 | if m: |
| 97 | cmd = m.group(1) |
| 98 | nxt = lines[i + 1].strip() if i + 1 < len(lines) else "" |
| 99 | if cmd in MELODY and not nxt.startswith("melody_"): |
| 100 | out.extend(MELODY[cmd]) |
| 101 | i += 1 |
| 102 | return out |
| 103 | |
| 104 | |
| 105 | def insert_args(lines: list[str]) -> list[str]: |
| 106 | out: list[str] = [] |
| 107 | i = 0 |
| 108 | while i < len(lines): |
| 109 | line = lines[i] |
| 110 | out.append(line) |
| 111 | m = re.match(r'^path = "([^"]+)"', line.strip()) |
| 112 | if m: |
| 113 | path = m.group(1) |
| 114 | if path in ARGS_AFTER: |
| 115 | j = i + 1 |
| 116 | chunk = [] |
| 117 | while j < len(lines): |
| 118 | s = lines[j].strip() |
| 119 | if s.startswith("group = ") or s.startswith("kind = "): |
| 120 | chunk.append(lines[j]) |
| 121 | j += 1 |
| 122 | continue |
| 123 | break |
| 124 | out.extend(chunk) |
| 125 | i = j - 1 |
| 126 | tail = "\n".join(out[-6:]) |
| 127 | if "[command.form.slash.args]" not in tail: |
| 128 | out.extend(ARGS_AFTER[path]) |
| 129 | i += 1 |
| 130 | return out |
| 131 | |
| 132 | |
| 133 | def strip_trailing_garbage(lines: list[str]) -> list[str]: |
| 134 | while lines and lines[-1].strip().startswith("# =====") or ( |
| 135 | lines and lines[-1].strip() == "[[command]]" and "Other" in (lines[-3] if len(lines) > 3 else "") |
| 136 | ): |
| 137 | lines.pop() |
| 138 | # remove duplicate empty help at end |
| 139 | text = "\n".join(lines) |
| 140 | marker = "# ==============================================================================\n# Other" |
| 141 | if marker in text: |
| 142 | text = text[: text.index(marker)].rstrip() |
| 143 | return text.splitlines() |
| 144 | |
| 145 | |
| 146 | def main() -> None: |
| 147 | lines = ROOT.read_text(encoding="utf-8").splitlines() |
| 148 | lines = strip_trailing_garbage(lines) |
| 149 | lines = insert_melodies(lines) |
| 150 | lines = insert_args(lines) |
| 151 | # fix git commit help TOML |
| 152 | for i, ln in enumerate(lines): |
| 153 | if 'path = "/git commit"' in ln: |
| 154 | j = i + 1 |
| 155 | if j < len(lines) and lines[j].startswith("help = "): |
| 156 | lines[j] = ( |
| 157 | 'help = "Коммит: хвост — сообщение (можно в кавычках: «feat: …»)."' |
| 158 | ) |
| 159 | ROOT.write_text("\n".join(lines).rstrip() + "\n", encoding="utf-8") |
| 160 | print(f"Fixed {ROOT}") |
| 161 | |
| 162 | |
| 163 | if __name__ == "__main__": |
| 164 | main() |
| 165 | |