More compaction/cleanup to gui
This commit is contained in:
+122
-242
@@ -1,6 +1,7 @@
|
||||
# gui_2.py
|
||||
# defer: parse
|
||||
from __future__ import annotations
|
||||
import copy
|
||||
import datetime
|
||||
import difflib
|
||||
import json
|
||||
@@ -23,6 +24,7 @@ from pathlib import Path
|
||||
from pydantic import BaseModel
|
||||
from tkinter import filedialog, Tk
|
||||
from typing import Optional, Any
|
||||
from src.diff_viewer import apply_patch_to_file
|
||||
from src import ai_client
|
||||
from src import aggregate
|
||||
from src import api_hooks
|
||||
@@ -40,6 +42,8 @@ from src import log_pruner
|
||||
from src import models
|
||||
from src import mcp_client
|
||||
from src import markdown_helper
|
||||
from src import shaders
|
||||
from src import synthesis_formatter
|
||||
from src import theme_2 as theme
|
||||
from src import theme_nerv_fx as theme_fx
|
||||
from src import thinking_parser
|
||||
@@ -1249,10 +1253,8 @@ class App:
|
||||
imgui.text(f"Age: {age_str}")
|
||||
imgui.text(f"TTL: {remaining_str} ({ttl_pct:.0f}%)")
|
||||
color = imgui.ImVec4(0.2, 0.8, 0.2, 1.0)
|
||||
if ttl_pct < 20:
|
||||
color = imgui.ImVec4(1.0, 0.2, 0.2, 1.0)
|
||||
elif ttl_pct < 50:
|
||||
color = imgui.ImVec4(1.0, 0.8, 0.0, 1.0)
|
||||
if ttl_pct < 20: color = imgui.ImVec4(1.0, 0.2, 0.2, 1.0)
|
||||
elif ttl_pct < 50: color = imgui.ImVec4(1.0, 0.8, 0.0, 1.0)
|
||||
imgui.push_style_color(imgui.Col_.plot_histogram, color)
|
||||
imgui.progress_bar(ttl_pct / 100.0, imgui.ImVec2(-1, 0), f"{ttl_pct:.0f}%")
|
||||
imgui.pop_style_color()
|
||||
@@ -1401,10 +1403,8 @@ class App:
|
||||
imgui.table_set_column_index(2)
|
||||
imgui.text(f"{avg_time:.0f}")
|
||||
imgui.table_set_column_index(3)
|
||||
if fail_pct > 0:
|
||||
imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{fail_pct:.0f}%")
|
||||
else:
|
||||
imgui.text("0%")
|
||||
if fail_pct > 0: imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{fail_pct:.0f}%")
|
||||
else: imgui.text("0%")
|
||||
imgui.end_table()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_tool_analytics_panel")
|
||||
|
||||
@@ -1413,15 +1413,11 @@ class App:
|
||||
imgui.text_colored(C_LBL, 'Prompt Utilization')
|
||||
usage = self.session_usage
|
||||
total = usage["input_tokens"] + usage["output_tokens"]
|
||||
if total == 0 and usage.get("total_tokens", 0) > 0:
|
||||
total = usage["total_tokens"]
|
||||
if total == 0 and usage.get("total_tokens", 0) > 0: total = usage["total_tokens"]
|
||||
self._render_selectable_label("session_telemetry_tokens", f"Tokens: {total:,} (In: {usage['input_tokens']:,} Out: {usage['output_tokens']:,})", width=-1, color=C_RES)
|
||||
if usage.get("last_latency", 0.0) > 0:
|
||||
imgui.text_colored(C_LBL, f" Last Latency: {usage['last_latency']:.2f}s")
|
||||
if usage["cache_read_input_tokens"]:
|
||||
imgui.text_colored(C_LBL, f" Cache Read: {usage['cache_read_input_tokens']:,} Creation: {usage['cache_creation_input_tokens']:,}")
|
||||
if self._gemini_cache_text:
|
||||
imgui.text_colored(C_SUB, self._gemini_cache_text)
|
||||
if usage.get("last_latency", 0.0) > 0: imgui.text_colored(C_LBL, f" Last Latency: {usage['last_latency']:.2f}s")
|
||||
if usage["cache_read_input_tokens"]: imgui.text_colored(C_LBL, f" Cache Read: {usage['cache_read_input_tokens']:,} Creation: {usage['cache_creation_input_tokens']:,}")
|
||||
if self._gemini_cache_text: imgui.text_colored(C_SUB, self._gemini_cache_text)
|
||||
imgui.separator()
|
||||
|
||||
if self._token_stats_dirty:
|
||||
@@ -1437,12 +1433,9 @@ class App:
|
||||
current = stats.get("estimated_prompt_tokens", stats.get("total_tokens", 0))
|
||||
limit = stats.get("max_prompt_tokens", 0)
|
||||
headroom = stats.get("headroom_tokens", max(0, limit - current))
|
||||
if pct < 50.0:
|
||||
color = imgui.ImVec4(0.2, 0.8, 0.2, 1.0)
|
||||
elif pct < 80.0:
|
||||
color = imgui.ImVec4(1.0, 0.8, 0.0, 1.0)
|
||||
else:
|
||||
color = imgui.ImVec4(1.0, 0.2, 0.2, 1.0)
|
||||
if pct < 50.0: color = imgui.ImVec4(0.2, 0.8, 0.2, 1.0)
|
||||
elif pct < 80.0: color = imgui.ImVec4(1.0, 0.8, 0.0, 1.0)
|
||||
else: color = imgui.ImVec4(1.0, 0.2, 0.2, 1.0)
|
||||
imgui.push_style_color(imgui.Col_.plot_histogram, color)
|
||||
imgui.progress_bar(pct / 100.0, imgui.ImVec2(-1, 0), f"{pct:.1f}%")
|
||||
imgui.pop_style_color()
|
||||
@@ -1490,14 +1483,12 @@ class App:
|
||||
if stats.get("would_trim"):
|
||||
imgui.text_colored(imgui.ImVec4(1.0, 0.3, 0.0, 1.0), "WARNING: Next call will trim history")
|
||||
trimmable = stats.get("trimmable_turns", 0)
|
||||
if trimmable:
|
||||
imgui.text_disabled(f"Trimmable turns: {trimmable}")
|
||||
if trimmable: imgui.text_disabled(f"Trimmable turns: {trimmable}")
|
||||
msgs = stats.get("messages")
|
||||
if msgs:
|
||||
shown = 0
|
||||
for msg in msgs:
|
||||
if shown >= 3:
|
||||
break
|
||||
if shown >= 3: break
|
||||
if msg.get("trimmable"):
|
||||
role = msg.get("role", "?")
|
||||
toks = msg.get("tokens", 0)
|
||||
@@ -1634,8 +1625,7 @@ class App:
|
||||
modes = ["native", "beads"]
|
||||
current_idx = modes.index(self.ui_project_execution_mode) if self.ui_project_execution_mode in modes else 0
|
||||
ch, new_idx = imgui.combo("##exec_mode", current_idx, modes)
|
||||
if ch:
|
||||
self.ui_project_execution_mode = modes[new_idx]
|
||||
if ch: self.ui_project_execution_mode = modes[new_idx]
|
||||
imgui.separator()
|
||||
imgui.text("Git Directory")
|
||||
ch, self.ui_project_git_dir = imgui.input_text("##git_dir", self.ui_project_git_dir)
|
||||
@@ -1670,14 +1660,12 @@ class App:
|
||||
is_active = (pp == self.active_project_path)
|
||||
if imgui.button(f"x##p{i}"):
|
||||
removed = self.project_paths.pop(i)
|
||||
if removed == self.active_project_path and self.project_paths:
|
||||
self._switch_project(self.project_paths[0])
|
||||
if removed == self.active_project_path and self.project_paths: self._switch_project(self.project_paths[0])
|
||||
break
|
||||
imgui.same_line()
|
||||
marker = " *" if is_active else ""
|
||||
if is_active: imgui.push_style_color(imgui.Col_.text, C_IN)
|
||||
if imgui.button(f"{Path(pp).stem}{marker}##ps{i}"):
|
||||
self._switch_project(pp)
|
||||
if imgui.button(f"{Path(pp).stem}{marker}##ps{i}"): self._switch_project(pp)
|
||||
if is_active: imgui.pop_style_color()
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_LBL, pp)
|
||||
@@ -1700,8 +1688,7 @@ class App:
|
||||
name = Path(p).stem
|
||||
proj = project_manager.default_project(name)
|
||||
project_manager.save_project(proj, p)
|
||||
if p not in self.project_paths:
|
||||
self.project_paths.append(p)
|
||||
if p not in self.project_paths: self.project_paths.append(p)
|
||||
self._switch_project(p)
|
||||
imgui.same_line()
|
||||
if imgui.button("Save All"):
|
||||
@@ -1721,7 +1708,7 @@ class App:
|
||||
imgui.text_colored(C_IN, "System Path Configuration")
|
||||
imgui.separator()
|
||||
|
||||
def render_path_field(label: str, attr: str, key: str, tooltip: str):
|
||||
def _render_path_field(label: str, attr: str, key: str, tooltip: str):
|
||||
info = path_info.get(key, {'source': 'unknown'})
|
||||
imgui.text(label)
|
||||
if imgui.is_item_hovered(): imgui.set_tooltip(tooltip)
|
||||
@@ -1741,8 +1728,7 @@ class App:
|
||||
|
||||
def _render_external_tools_panel(self) -> None:
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_external_tools_panel")
|
||||
if imgui.button("Refresh External MCPs"):
|
||||
self.event_queue.put("refresh_external_mcps", None)
|
||||
if imgui.button("Refresh External MCPs"): self.event_queue.put("refresh_external_mcps", None)
|
||||
|
||||
imgui.separator()
|
||||
|
||||
@@ -1755,12 +1741,9 @@ class App:
|
||||
imgui.same_line()
|
||||
# Green for running, Yellow for starting, Red for error, Gray for idle
|
||||
col = (0.5, 0.5, 0.5, 1.0)
|
||||
if status == 'running':
|
||||
col = (0.0, 1.0, 0.0, 1.0)
|
||||
elif status == 'starting':
|
||||
col = (1.0, 1.0, 0.0, 1.0)
|
||||
elif status == 'error':
|
||||
col = (1.0, 0.0, 0.0, 1.0)
|
||||
if status == 'running': col = (0.0, 1.0, 0.0, 1.0)
|
||||
elif status == 'starting': col = (1.0, 1.0, 0.0, 1.0)
|
||||
elif status == 'error': col = (1.0, 0.0, 0.0, 1.0)
|
||||
imgui.color_button(f"##status_{sname}", col)
|
||||
imgui.same_line()
|
||||
imgui.text(sname)
|
||||
@@ -1795,13 +1778,11 @@ class App:
|
||||
models.save_config(self.config)
|
||||
self.ai_status = f"Default editor set to: {editor_name}"
|
||||
|
||||
|
||||
render_path_field("Logs Directory", "ui_logs_dir", "logs_dir", "Directory where session JSON-L logs and artifacts are stored.")
|
||||
render_path_field("Scripts Directory", "ui_scripts_dir", "scripts_dir", "Directory for AI-generated PowerShell scripts.")
|
||||
_render_path_field("Logs Directory", "ui_logs_dir", "logs_dir", "Directory where session JSON-L logs and artifacts are stored.")
|
||||
_render_path_field("Scripts Directory", "ui_scripts_dir", "scripts_dir", "Directory for AI-generated PowerShell scripts.")
|
||||
|
||||
imgui.separator()
|
||||
if imgui.button("Apply", imgui.ImVec2(120, 0)):
|
||||
self._save_paths()
|
||||
if imgui.button("Apply", imgui.ImVec2(120, 0)): self._save_paths()
|
||||
imgui.same_line()
|
||||
if imgui.button("Reset", imgui.ImVec2(120, 0)):
|
||||
self.init_state()
|
||||
@@ -1818,8 +1799,7 @@ class App:
|
||||
"scripts_dir": self.ui_scripts_dir
|
||||
}
|
||||
cfg_path = paths.get_config_path()
|
||||
if cfg_path.exists():
|
||||
shutil.copy(cfg_path, str(cfg_path) + ".bak")
|
||||
if cfg_path.exists(): shutil.copy(cfg_path, str(cfg_path) + ".bak")
|
||||
models.save_config(self.config)
|
||||
paths.reset_resolved()
|
||||
self.init_state()
|
||||
@@ -1871,8 +1851,7 @@ class App:
|
||||
imgui.separator()
|
||||
imgui.text(f"Status: {self.controller.rag_status}")
|
||||
|
||||
if imgui.button("Rebuild Index"):
|
||||
self.controller.event_queue.put('click', 'btn_rebuild_rag_index')
|
||||
if imgui.button("Rebuild Index"): self.controller.event_queue.put('click', 'btn_rebuild_rag_index')
|
||||
|
||||
def _render_system_prompts_panel(self) -> None:
|
||||
imgui.text("Global System Prompt (all projects)")
|
||||
@@ -1882,24 +1861,19 @@ class App:
|
||||
if imgui.begin_combo("##global_preset", current_global):
|
||||
for name in preset_names:
|
||||
is_sel = (name == current_global)
|
||||
if imgui.selectable(name, is_sel)[0]:
|
||||
self.controller._apply_preset(name, "global")
|
||||
if is_sel:
|
||||
imgui.set_item_default_focus()
|
||||
if imgui.selectable(name, is_sel)[0]: self.controller._apply_preset(name, "global")
|
||||
if is_sel: imgui.set_item_default_focus()
|
||||
imgui.end_combo()
|
||||
imgui.same_line(0, 8)
|
||||
if imgui.button("Manage Presets##global"):
|
||||
self.show_preset_manager_window = True
|
||||
if imgui.button("Manage Presets##global"): self.show_preset_manager_window = True
|
||||
imgui.set_item_tooltip("Open preset management modal")
|
||||
ch, self.ui_global_system_prompt = imgui.input_text_multiline("##gsp", self.ui_global_system_prompt, imgui.ImVec2(-1, 100))
|
||||
imgui.separator()
|
||||
_, self.ui_use_default_base_prompt = imgui.checkbox("Use Default Base System Prompt", self.ui_use_default_base_prompt)
|
||||
imgui.same_line()
|
||||
if imgui.button("Reset to Default##btn_reset_base_prompt"):
|
||||
self.controller._cb_reset_base_prompt()
|
||||
if imgui.button("Reset to Default##btn_reset_base_prompt"): self.controller._cb_reset_base_prompt()
|
||||
imgui.same_line()
|
||||
if imgui.button("Show Diff##btn_show_base_prompt_diff"):
|
||||
self.controller._cb_show_base_prompt_diff()
|
||||
if imgui.button("Show Diff##btn_show_base_prompt_diff"): self.controller._cb_show_base_prompt_diff()
|
||||
imgui.set_item_tooltip("Compare current base prompt with the default.")
|
||||
|
||||
imgui.same_line()
|
||||
@@ -1923,14 +1897,11 @@ class App:
|
||||
if imgui.begin_combo("##project_preset", current_project):
|
||||
for name in preset_names:
|
||||
is_sel = (name == current_project)
|
||||
if imgui.selectable(name, is_sel)[0]:
|
||||
self.controller._apply_preset(name, "project")
|
||||
if is_sel:
|
||||
imgui.set_item_default_focus()
|
||||
if imgui.selectable(name, is_sel)[0]: self.controller._apply_preset(name, "project")
|
||||
if is_sel: imgui.set_item_default_focus()
|
||||
imgui.end_combo()
|
||||
imgui.same_line(0, 8)
|
||||
if imgui.button("Manage Presets##project"):
|
||||
self.show_preset_manager_window = True
|
||||
if imgui.button("Manage Presets##project"): self.show_preset_manager_window = True
|
||||
imgui.set_item_tooltip("Open preset management modal")
|
||||
ch, self.ui_project_system_prompt = imgui.input_text_multiline("##psp", self.ui_project_system_prompt, imgui.ImVec2(-1, 100))
|
||||
|
||||
@@ -1952,10 +1923,8 @@ class App:
|
||||
self.ui_active_tool_preset = preset_names[new_idx]
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button("Manage Presets##tools"):
|
||||
self.show_tool_preset_manager_window = True
|
||||
if imgui.is_item_hovered():
|
||||
imgui.set_tooltip("Configure tool availability and default modes.")
|
||||
if imgui.button("Manage Presets##tools"): self.show_tool_preset_manager_window = True
|
||||
if imgui.is_item_hovered(): imgui.set_tooltip("Configure tool availability and default modes.")
|
||||
|
||||
imgui.dummy(imgui.ImVec2(0, 4))
|
||||
imgui.text("Bias Profile")
|
||||
@@ -1964,8 +1933,7 @@ class App:
|
||||
self.ui_active_bias_profile = ""
|
||||
ai_client.set_bias_profile(None)
|
||||
for bname in sorted(self.controller.bias_profiles.keys()):
|
||||
if not bname:
|
||||
continue
|
||||
if not bname: continue
|
||||
if imgui.selectable(bname, bname == getattr(self, 'ui_active_bias_profile', ""))[0]:
|
||||
self.ui_active_bias_profile = bname
|
||||
ai_client.set_bias_profile(bname)
|
||||
@@ -1989,14 +1957,10 @@ class App:
|
||||
if self.ui_tool_filter_category != "All" and self.ui_tool_filter_category != cat_name: continue
|
||||
if imgui.tree_node(cat_name):
|
||||
for tool in tools:
|
||||
if tool.weight >= 5:
|
||||
imgui.text_colored(vec4(255, 100, 100), "[HIGH]"); imgui.same_line()
|
||||
elif tool.weight == 4:
|
||||
imgui.text_colored(vec4(255, 255, 100), "[PREF]"); imgui.same_line()
|
||||
elif tool.weight == 2:
|
||||
imgui.text_colored(vec4(255, 150, 50), "[REJECT]"); imgui.same_line()
|
||||
elif tool.weight <= 1:
|
||||
imgui.text_colored(vec4(180, 180, 180), "[LOW]"); imgui.same_line()
|
||||
if tool.weight >= 5: imgui.text_colored(vec4(255, 100, 100), "[HIGH]"); imgui.same_line()
|
||||
elif tool.weight == 4: imgui.text_colored(vec4(255, 255, 100), "[PREF]"); imgui.same_line()
|
||||
elif tool.weight == 2: imgui.text_colored(vec4(255, 150, 50), "[REJECT]"); imgui.same_line()
|
||||
elif tool.weight <= 1: imgui.text_colored(vec4(180, 180, 180), "[LOW]"); imgui.same_line()
|
||||
|
||||
imgui.text(tool.name); imgui.same_line(180)
|
||||
|
||||
@@ -2090,8 +2054,7 @@ class App:
|
||||
self._selected_preset_idx = -1
|
||||
if not is_embedded:
|
||||
imgui.same_line()
|
||||
if imgui.button("Close##p", imgui.ImVec2(100, 0)):
|
||||
self.show_preset_manager_window = False
|
||||
if imgui.button("Close##p", imgui.ImVec2(100, 0)): self.show_preset_manager_window = False
|
||||
imgui.end_table()
|
||||
|
||||
def _render_preset_manager_window(self, is_embedded: bool = False) -> None:
|
||||
@@ -2100,8 +2063,7 @@ class App:
|
||||
imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever)
|
||||
with imscope.window("Prompt Presets Manager", self.show_preset_manager_window) as (opened, visible):
|
||||
self.show_preset_manager_window = visible
|
||||
if opened:
|
||||
self._render_preset_manager_content(is_embedded=is_embedded)
|
||||
if opened: self._render_preset_manager_content(is_embedded=is_embedded)
|
||||
else:
|
||||
self._render_preset_manager_content(is_embedded=is_embedded)
|
||||
|
||||
@@ -2284,8 +2246,7 @@ class App:
|
||||
imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever)
|
||||
with imscope.window("Tool Preset Manager", self.show_tool_preset_manager_window) as (opened, visible):
|
||||
self.show_tool_preset_manager_window = visible
|
||||
if opened:
|
||||
self._render_tool_preset_manager_content(is_embedded=is_embedded)
|
||||
if opened: self._render_tool_preset_manager_content(is_embedded=is_embedded)
|
||||
else:
|
||||
self._render_preset_manager_content(is_embedded=is_embedded)
|
||||
|
||||
@@ -2523,15 +2484,12 @@ class App:
|
||||
def _render_persona_selector_panel(self) -> None:
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_persona_selector_panel")
|
||||
imgui.text("Persona")
|
||||
if not hasattr(self, 'ui_active_persona'):
|
||||
self.ui_active_persona = ""
|
||||
if not hasattr(self, 'ui_active_persona'): self.ui_active_persona = ""
|
||||
personas = getattr(self.controller, 'personas', {})
|
||||
if imgui.begin_combo("##persona", self.ui_active_persona or "None"):
|
||||
if imgui.selectable("None", not self.ui_active_persona)[0]:
|
||||
self.ui_active_persona = ""
|
||||
if imgui.selectable("None", not self.ui_active_persona)[0]: self.ui_active_persona = ""
|
||||
for pname in sorted(personas.keys()):
|
||||
if not pname:
|
||||
continue
|
||||
if not pname: continue
|
||||
if imgui.selectable(pname, pname == self.ui_active_persona)[0]:
|
||||
self.ui_active_persona = pname
|
||||
if pname in personas:
|
||||
@@ -2542,7 +2500,6 @@ class App:
|
||||
self._editing_persona_bias_profile_id = persona.bias_profile or ""
|
||||
self._editing_persona_context_preset_id = getattr(persona, 'context_preset', '') or ""
|
||||
self._editing_persona_aggregation_strategy = getattr(persona, 'aggregation_strategy', '') or ""
|
||||
import copy
|
||||
self._editing_persona_preferred_models_list = copy.deepcopy(persona.preferred_models) if persona.preferred_models else []
|
||||
self._editing_persona_is_new = False
|
||||
|
||||
@@ -2562,8 +2519,7 @@ class App:
|
||||
if first_model.get("history_trunc_limit"):
|
||||
self.history_trunc_limit = first_model.get("history_trunc_limit")
|
||||
|
||||
if persona.system_prompt:
|
||||
self.ui_project_system_prompt = persona.system_prompt
|
||||
if persona.system_prompt: self.ui_project_system_prompt = persona.system_prompt
|
||||
if persona.tool_preset:
|
||||
self.ui_active_tool_preset = persona.tool_preset
|
||||
ai_client.set_tool_preset(persona.tool_preset)
|
||||
@@ -2585,7 +2541,6 @@ class App:
|
||||
self._editing_persona_bias_profile_id = persona.bias_profile or ""
|
||||
self._editing_persona_context_preset_id = getattr(persona, 'context_preset', '') or ""
|
||||
self._editing_persona_aggregation_strategy = getattr(persona, 'aggregation_strategy', '') or ""
|
||||
import copy
|
||||
self._editing_persona_preferred_models_list = copy.deepcopy(persona.preferred_models) if persona.preferred_models else []
|
||||
self._editing_persona_scope = self.controller.persona_manager.get_persona_scope(persona.name)
|
||||
self._editing_persona_is_new = False
|
||||
@@ -2863,12 +2818,9 @@ class App:
|
||||
if f_path != self._cached_ast_file_path:
|
||||
outline = ""
|
||||
try:
|
||||
if f_path.lower().endswith('.py'):
|
||||
outline = mcp_client.py_get_code_outline(f_path)
|
||||
elif f_path.lower().endswith(('.c', '.h')):
|
||||
outline = mcp_client.ts_c_get_code_outline(f_path)
|
||||
else:
|
||||
outline = mcp_client.ts_cpp_get_code_outline(f_path)
|
||||
if f_path.lower().endswith('.py'): outline = mcp_client.py_get_code_outline(f_path)
|
||||
elif f_path.lower().endswith(('.c', '.h')): outline = mcp_client.ts_c_get_code_outline(f_path)
|
||||
else: outline = mcp_client.ts_cpp_get_code_outline(f_path)
|
||||
except Exception as e:
|
||||
outline = f"Error fetching outline: {e}"
|
||||
|
||||
@@ -2881,8 +2833,7 @@ class App:
|
||||
if m:
|
||||
indent_str, kind, name, start_ln, end_ln = m.groups()
|
||||
indent = len(indent_str)
|
||||
while stack and stack[-1][0] >= indent:
|
||||
stack.pop()
|
||||
while stack and stack[-1][0] >= indent: stack.pop()
|
||||
stack.append((indent, name))
|
||||
full_path = '::'.join([s[1] for s in stack])
|
||||
self._cached_ast_nodes.append({
|
||||
@@ -2909,8 +2860,7 @@ class App:
|
||||
|
||||
#region: LEFT COLUMN (Tree) ---
|
||||
if imgui.begin_child("ast_tree_scroll", imgui.ImVec2(0, 600), True):
|
||||
if not self._cached_ast_nodes:
|
||||
imgui.text("No AST nodes found or error fetching outline.")
|
||||
if not self._cached_ast_nodes: imgui.text("No AST nodes found or error fetching outline.")
|
||||
else:
|
||||
for node in self._cached_ast_nodes:
|
||||
indent = node['indent']
|
||||
@@ -2926,14 +2876,11 @@ class App:
|
||||
current_mode = f_item.ast_mask.get(full_path, 'hide')
|
||||
|
||||
imgui.push_id(full_path)
|
||||
if imgui.radio_button("Def", current_mode == 'def'):
|
||||
f_item.ast_mask[full_path] = 'def'
|
||||
if imgui.radio_button("Def", current_mode == 'def'): f_item.ast_mask[full_path] = 'def'
|
||||
imgui.same_line()
|
||||
if imgui.radio_button("Sig", current_mode == 'sig'):
|
||||
f_item.ast_mask[full_path] = 'sig'
|
||||
if imgui.radio_button("Sig", current_mode == 'sig'): f_item.ast_mask[full_path] = 'sig'
|
||||
imgui.same_line()
|
||||
if imgui.radio_button("Hide", current_mode == 'hide'):
|
||||
f_item.ast_mask[full_path] = 'hide'
|
||||
if imgui.radio_button("Hide", current_mode == 'hide'): f_item.ast_mask[full_path] = 'hide'
|
||||
imgui.pop_id()
|
||||
imgui.end_child()
|
||||
#endregion: LEFT COLUMN (Tree)
|
||||
@@ -2953,12 +2900,10 @@ class App:
|
||||
deepest_node = None
|
||||
for node in self._cached_ast_nodes:
|
||||
if node['start_line'] <= line_num <= node['end_line']:
|
||||
if deepest_node is None or node['indent'] > deepest_node['indent']:
|
||||
deepest_node = node
|
||||
if deepest_node is None or node['indent'] > deepest_node['indent']: deepest_node = node
|
||||
|
||||
mode = 'hide'
|
||||
if deepest_node:
|
||||
mode = f_item.ast_mask.get(deepest_node['full_path'], 'hide')
|
||||
if deepest_node: mode = f_item.ast_mask.get(deepest_node['full_path'], 'hide')
|
||||
|
||||
pos = imgui.get_cursor_screen_pos()
|
||||
line_height = imgui.get_text_line_height()
|
||||
@@ -2986,8 +2931,7 @@ class App:
|
||||
|
||||
#endregion: AST Inspector
|
||||
|
||||
if not opened:
|
||||
self.ui_inspecting_ast_file = None
|
||||
if not opened: self.ui_inspecting_ast_file = None
|
||||
|
||||
def _render_add_context_files_modal(self) -> None:
|
||||
if imgui.begin_popup_modal("Select Context Files", None, imgui.WindowFlags_.always_auto_resize)[0]:
|
||||
@@ -3034,11 +2978,9 @@ class App:
|
||||
_, self._new_workspace_profile_name = imgui.input_text("##profile_name", self._new_workspace_profile_name)
|
||||
|
||||
imgui.text("Scope:")
|
||||
if imgui.radio_button("Project", self._new_workspace_profile_scope == "project"):
|
||||
self._new_workspace_profile_scope = "project"
|
||||
if imgui.radio_button("Project", self._new_workspace_profile_scope == "project"): self._new_workspace_profile_scope = "project"
|
||||
imgui.same_line()
|
||||
if imgui.radio_button("Global", self._new_workspace_profile_scope == "global"):
|
||||
self._new_workspace_profile_scope = "global"
|
||||
if imgui.radio_button("Global", self._new_workspace_profile_scope == "global"): self._new_workspace_profile_scope = "global"
|
||||
|
||||
imgui.separator()
|
||||
if imgui.button("Save", (120, 0)):
|
||||
@@ -3108,8 +3050,7 @@ class App:
|
||||
f_item.custom_slices.append(slice_data)
|
||||
|
||||
def _render_context_screenshots(self) -> None:
|
||||
for i, s in enumerate(self.screenshots):
|
||||
imgui.text(s)
|
||||
for i, s in enumerate(self.screenshots): imgui.text(s)
|
||||
|
||||
def _render_context_batch_actions(self, total_lines: int, total_ast: int) -> None:
|
||||
imgui.text("Batch:")
|
||||
@@ -3117,22 +3058,18 @@ class App:
|
||||
if imgui.button(f"{mode.capitalize()}##batch"):
|
||||
for f in self.context_files:
|
||||
f_path = f.path if hasattr(f, "path") else str(f)
|
||||
if f_path in self.ui_selected_context_files:
|
||||
f.view_mode = mode
|
||||
if f_path in self.ui_selected_context_files: f.view_mode = mode
|
||||
imgui.same_line()
|
||||
if imgui.button("Sel All##selall"):
|
||||
for f in self.context_files:
|
||||
f_path = f.path if hasattr(f, "path") else str(f)
|
||||
self.ui_selected_context_files.add(f_path)
|
||||
imgui.same_line()
|
||||
if imgui.button("Unsel All##unselall"):
|
||||
self.ui_selected_context_files.clear()
|
||||
if imgui.button("Unsel All##unselall"): self.ui_selected_context_files.clear()
|
||||
imgui.same_line()
|
||||
if imgui.button("Add Files"):
|
||||
imgui.open_popup("Select Context Files")
|
||||
if imgui.button("Add Files"): imgui.open_popup("Select Context Files")
|
||||
imgui.same_line()
|
||||
if imgui.button("Add All##addall"):
|
||||
import copy
|
||||
context_paths = {f.path if hasattr(f, "path") else str(f) for f in self.context_files}
|
||||
for f in self.files:
|
||||
f_path = f.path if hasattr(f, "path") else str(f)
|
||||
@@ -3145,8 +3082,7 @@ class App:
|
||||
new_files = []
|
||||
for f in self.context_files:
|
||||
f_path = f.path if hasattr(f, "path") else str(f)
|
||||
if f_path not in self.ui_selected_context_files:
|
||||
new_files.append(f)
|
||||
if f_path not in self.ui_selected_context_files: new_files.append(f)
|
||||
self.context_files = new_files
|
||||
self.ui_selected_context_files.clear()
|
||||
imgui.same_line()
|
||||
@@ -3185,15 +3121,11 @@ class App:
|
||||
for idx in range(start, end + 1):
|
||||
item = self.context_files[idx]
|
||||
item_path = item.path if hasattr(item, "path") else str(item)
|
||||
if is_sel:
|
||||
self.ui_selected_context_files.add(item_path)
|
||||
if is_sel: self.ui_selected_context_files.add(item_path)
|
||||
else: self.ui_selected_context_files.discard(item_path)
|
||||
else:
|
||||
self.ui_selected_context_files.discard(item_path)
|
||||
else:
|
||||
if is_sel:
|
||||
self.ui_selected_context_files.add(f_path)
|
||||
else:
|
||||
self.ui_selected_context_files.discard(f_path)
|
||||
if is_sel: self.ui_selected_context_files.add(f_path)
|
||||
else: self.ui_selected_context_files.discard(f_path)
|
||||
self._last_selected_context_index = i
|
||||
imgui.same_line()
|
||||
|
||||
@@ -3222,8 +3154,7 @@ class App:
|
||||
self.show_text_viewer = True
|
||||
|
||||
imgui.table_set_column_index(1)
|
||||
if not hasattr(f_item, "view_mode"):
|
||||
f_item.view_mode = "summary"
|
||||
if not hasattr(f_item, "view_mode"): f_item.view_mode = "summary"
|
||||
view_modes = ["full", "summary", "skeleton", "outline", "masked", "none"]
|
||||
try:
|
||||
current_idx = view_modes.index(f_item.view_mode)
|
||||
@@ -3232,12 +3163,10 @@ class App:
|
||||
f_item.view_mode = "summary"
|
||||
imgui.set_next_item_width(120)
|
||||
changed_vm, new_idx = imgui.combo(f"##vm{i}", current_idx, view_modes)
|
||||
if changed_vm:
|
||||
f_item.view_mode = view_modes[new_idx]
|
||||
if changed_vm: f_item.view_mode = view_modes[new_idx]
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button(f"[Save]##vpsave{i}"):
|
||||
imgui.open_popup(f"save_vp_popup{i}")
|
||||
if imgui.button(f"[Save]##vpsave{i}"): imgui.open_popup(f"save_vp_popup{i}")
|
||||
|
||||
if imgui.begin_popup(f"save_vp_popup{i}"):
|
||||
imgui.text("Preset Name:")
|
||||
@@ -3250,13 +3179,11 @@ class App:
|
||||
imgui.end_popup()
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button(f"[Load]##vpload{i}"):
|
||||
imgui.open_popup(f"load_vp_popup{i}")
|
||||
if imgui.button(f"[Load]##vpload{i}"): imgui.open_popup(f"load_vp_popup{i}")
|
||||
|
||||
if imgui.begin_popup(f"load_vp_popup{i}"):
|
||||
vp_names = sorted([vp.name for vp in self.controller.view_presets])
|
||||
if not vp_names:
|
||||
imgui.text("No presets saved.")
|
||||
if not vp_names: imgui.text("No presets saved.")
|
||||
for vp_name in vp_names:
|
||||
if imgui.selectable(vp_name):
|
||||
self.controller._cb_apply_view_preset(vp_name, f_item)
|
||||
@@ -3271,8 +3198,7 @@ class App:
|
||||
presets = self.controller.project.get('context_presets', {})
|
||||
preset_names = [""] + sorted(presets.keys())
|
||||
active = getattr(self, "ui_active_context_preset", "")
|
||||
if active not in preset_names:
|
||||
active = ""
|
||||
if active not in preset_names: active = ""
|
||||
try:
|
||||
idx = preset_names.index(active)
|
||||
except ValueError:
|
||||
@@ -3280,12 +3206,10 @@ class App:
|
||||
ch, new_idx = imgui.combo("##ctx_preset", idx, preset_names)
|
||||
if ch:
|
||||
self.ui_active_context_preset = preset_names[new_idx]
|
||||
if preset_names[new_idx]:
|
||||
self.load_context_preset(preset_names[new_idx])
|
||||
if preset_names[new_idx]: self.load_context_preset(preset_names[new_idx])
|
||||
imgui.same_line()
|
||||
changed, new_name = imgui.input_text("##new_preset", getattr(self, "ui_new_context_preset_name", ""))
|
||||
if changed:
|
||||
self.ui_new_context_preset_name = new_name
|
||||
if changed: self.ui_new_context_preset_name = new_name
|
||||
imgui.same_line()
|
||||
if imgui.button("Save##ctx"):
|
||||
if getattr(self, "ui_new_context_preset_name", "").strip():
|
||||
@@ -3298,13 +3222,9 @@ class App:
|
||||
self.ui_active_context_preset = ""
|
||||
|
||||
def _update_context_file_stats(self) -> tuple[int, int]:
|
||||
if not hasattr(self, '_file_stats_cache'):
|
||||
self._file_stats_cache = {}
|
||||
if not hasattr(self, '_file_stats_queue'):
|
||||
self._file_stats_queue = []
|
||||
if not hasattr(self, '_file_stats_worker_active'):
|
||||
self._file_stats_worker_active = False
|
||||
|
||||
if not hasattr(self, '_file_stats_cache'): self._file_stats_cache = {}
|
||||
if not hasattr(self, '_file_stats_queue'): self._file_stats_queue = []
|
||||
if not hasattr(self, '_file_stats_worker_active'): self._file_stats_worker_active = False
|
||||
total_lines = 0
|
||||
total_ast = 0
|
||||
|
||||
@@ -3313,8 +3233,7 @@ class App:
|
||||
f_path = f.path if hasattr(f, "path") else str(f)
|
||||
mtime = os.path.getmtime(f_path) if os.path.exists(f_path) else 0
|
||||
cache_key = f"{f_path}_{mtime}"
|
||||
if cache_key not in self._file_stats_cache:
|
||||
missing_keys.append((f_path, cache_key))
|
||||
if cache_key not in self._file_stats_cache: missing_keys.append((f_path, cache_key))
|
||||
else:
|
||||
stats = self._file_stats_cache[cache_key]
|
||||
total_lines += stats.get("lines", 0)
|
||||
@@ -3330,7 +3249,6 @@ class App:
|
||||
self._file_stats_worker_active = False
|
||||
|
||||
threading.Thread(target=_stats_worker, daemon=True).start()
|
||||
|
||||
return total_lines, total_ast
|
||||
|
||||
#endregion: Context Management
|
||||
@@ -3704,43 +3622,35 @@ class App:
|
||||
val = math.sin(time.time() * 10 * math.pi)
|
||||
alpha = 1.0 if val > 0 else 0.0
|
||||
c = imgui.ImVec4(0.39, 1.0, 0.39, alpha)
|
||||
if theme.is_nerv_active():
|
||||
c = vec4(80, 255, 80, alpha) # DATA_GREEN for LIVE in NERV
|
||||
if theme.is_nerv_active(): c = vec4(80, 255, 80, alpha) # DATA_GREEN for LIVE in NERV
|
||||
imgui.text_colored(c, "LIVE")
|
||||
imgui.separator()
|
||||
ch, self.ui_ai_input = imgui.input_text_multiline("##ai_in", self.ui_ai_input, imgui.ImVec2(-1, -40))
|
||||
# Keyboard shortcuts
|
||||
io = imgui.get_io()
|
||||
ctrl_l = io.key_ctrl and imgui.is_key_pressed(imgui.Key.l)
|
||||
if ctrl_l:
|
||||
self.ui_ai_input = ""
|
||||
if ctrl_l: self.ui_ai_input = ""
|
||||
imgui.separator()
|
||||
is_busy = self.ai_status in ['sending...', 'streaming...']
|
||||
send_busy = False
|
||||
with self._send_thread_lock:
|
||||
if self.send_thread and self.send_thread.is_alive():
|
||||
send_busy = True
|
||||
if self.send_thread and self.send_thread.is_alive(): send_busy = True
|
||||
if is_busy: send_busy = True
|
||||
|
||||
imgui.begin_disabled(send_busy)
|
||||
ctrl_enter = io.key_ctrl and imgui.is_key_pressed(imgui.Key.enter)
|
||||
label = "Gen + Send (Busy)" if send_busy else "Gen + Send"
|
||||
if (imgui.button(label) or ctrl_enter) and not send_busy:
|
||||
self._handle_generate_send()
|
||||
if (imgui.button(label) or ctrl_enter) and not send_busy: self._handle_generate_send()
|
||||
imgui.end_disabled()
|
||||
imgui.same_line()
|
||||
if imgui.button("MD Only"):
|
||||
self._handle_md_only()
|
||||
if imgui.button("MD Only"): self._handle_md_only()
|
||||
imgui.same_line()
|
||||
if imgui.button("Inject File"):
|
||||
self.show_inject_modal = True
|
||||
if imgui.button("Inject File"): self.show_inject_modal = True
|
||||
imgui.same_line()
|
||||
if imgui.button("-> History"):
|
||||
if self.ui_ai_input:
|
||||
self.disc_entries.append({"role": "User", "content": self.ui_ai_input, "collapsed": False, "ts": project_manager.now_ts()})
|
||||
if self.ui_ai_input: self.disc_entries.append({"role": "User", "content": self.ui_ai_input, "collapsed": False, "ts": project_manager.now_ts()})
|
||||
imgui.same_line()
|
||||
if imgui.button("Reset"):
|
||||
self._handle_reset_session()
|
||||
if imgui.button("Reset"): self._handle_reset_session()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_message_panel")
|
||||
|
||||
def _render_synthesis_panel(self) -> None:
|
||||
@@ -3750,19 +3660,15 @@ class App:
|
||||
"""
|
||||
imgui.text("Select takes to synthesize:")
|
||||
discussions = self.project.get('discussion', {}).get('discussions', {})
|
||||
if not hasattr(self, 'ui_synthesis_selected_takes'):
|
||||
self.ui_synthesis_selected_takes = {name: False for name in discussions}
|
||||
if not hasattr(self, 'ui_synthesis_prompt'):
|
||||
self.ui_synthesis_prompt = ""
|
||||
for name in discussions:
|
||||
_, self.ui_synthesis_selected_takes[name] = imgui.checkbox(name, self.ui_synthesis_selected_takes.get(name, False))
|
||||
if not hasattr(self, 'ui_synthesis_selected_takes'): self.ui_synthesis_selected_takes = {name: False for name in discussions}
|
||||
if not hasattr(self, 'ui_synthesis_prompt'): self.ui_synthesis_prompt = ""
|
||||
for name in discussions: _, self.ui_synthesis_selected_takes[name] = imgui.checkbox(name, self.ui_synthesis_selected_takes.get(name, False))
|
||||
imgui.spacing()
|
||||
imgui.text("Synthesis Prompt:")
|
||||
_, self.ui_synthesis_prompt = imgui.input_text_multiline("##synthesis_prompt", self.ui_synthesis_prompt, imgui.ImVec2(-1, 100))
|
||||
if imgui.button("Generate Synthesis"):
|
||||
selected = [name for name, sel in self.ui_synthesis_selected_takes.items() if sel]
|
||||
if len(selected) > 1:
|
||||
from src import synthesis_formatter
|
||||
discussions_dict = self.project.get('discussion', {}).get('discussions', {})
|
||||
takes_dict = {name: discussions_dict.get(name, {}).get('history', []) for name in selected}
|
||||
diff_text = synthesis_formatter.format_takes_diff(takes_dict)
|
||||
@@ -3801,15 +3707,13 @@ class App:
|
||||
full_md, _, _ = src.aggregate.run(flat)
|
||||
self._focus_md_cache[cp_name] = full_md
|
||||
display_md = full_md
|
||||
if imgui.button("Copy"):
|
||||
imgui.set_clipboard_text(display_md)
|
||||
if imgui.button("Copy"): imgui.set_clipboard_text(display_md)
|
||||
imgui.begin_child("last_agg_md", imgui.ImVec2(0, 0), True)
|
||||
markdown_helper.render(display_md, context_id="snapshot_agg")
|
||||
imgui.end_child()
|
||||
imgui.end_tab_item()
|
||||
if imgui.begin_tab_item("System Prompt")[0]:
|
||||
if imgui.button("Copy"):
|
||||
imgui.set_clipboard_text(self.last_resolved_system_prompt)
|
||||
if imgui.button("Copy"): imgui.set_clipboard_text(self.last_resolved_system_prompt)
|
||||
imgui.begin_child("last_sys_prompt", imgui.ImVec2(0, 0), True)
|
||||
markdown_helper.render(self.last_resolved_system_prompt, context_id="snapshot_sys")
|
||||
imgui.end_child()
|
||||
@@ -3852,8 +3756,7 @@ class App:
|
||||
if self.ai_response:
|
||||
segments, response = thinking_parser.parse_thinking_trace(self.ai_response)
|
||||
entry = {"role": "AI", "content": response, "collapsed": True, "ts": project_manager.now_ts()}
|
||||
if segments:
|
||||
entry["thinking_segments"] = [{"content": s.content, "marker": s.marker} for s in segments]
|
||||
if segments: entry["thinking_segments"] = [{"content": s.content, "marker": s.marker} for s in segments]
|
||||
self.disc_entries.append(entry)
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_response_panel")
|
||||
|
||||
@@ -3969,8 +3872,7 @@ class App:
|
||||
def _render_comms_history_panel(self) -> None:
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_comms_history_panel")
|
||||
st_col = vec4(200, 220, 160)
|
||||
if theme.is_nerv_active():
|
||||
st_col = vec4(80, 255, 80) # DATA_GREEN for status in NERV
|
||||
if theme.is_nerv_active(): st_col = vec4(80, 255, 80) # DATA_GREEN for status in NERV
|
||||
imgui.text_colored(st_col, f"Status: {self.ai_status}")
|
||||
imgui.same_line()
|
||||
if imgui.button("Clear##comms"):
|
||||
@@ -4082,8 +3984,7 @@ class App:
|
||||
self._scroll_comms_to_bottom = False
|
||||
|
||||
imgui.end_child()
|
||||
if self.is_viewing_prior_session:
|
||||
imgui.pop_style_color()
|
||||
if self.is_viewing_prior_session: imgui.pop_style_color()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_comms_history_panel")
|
||||
|
||||
#endregion: Operations Monitor
|
||||
@@ -4254,7 +4155,6 @@ class App:
|
||||
imgui.open_popup("Apply Patch?")
|
||||
with imscope.popup_modal("Apply Patch?", True, imgui.WindowFlags_.always_auto_resize) as (opened, _):
|
||||
if opened:
|
||||
from src import shaders
|
||||
p_min = imgui.get_window_pos()
|
||||
p_max = imgui.ImVec2(p_min.x + imgui.get_window_size().x, p_min.y + imgui.get_window_size().y)
|
||||
shaders.draw_soft_shadow(imgui.get_background_draw_list(), p_min, p_max, imgui.ImVec4(0, 0, 0, 0.6), 25.0, 6.0)
|
||||
@@ -4263,8 +4163,7 @@ class App:
|
||||
imgui.separator()
|
||||
if self._pending_patch_files:
|
||||
imgui.text("Files to modify:")
|
||||
for f in self._pending_patch_files:
|
||||
imgui.text(f" - {f}")
|
||||
for f in self._pending_patch_files: imgui.text(f" - {f}")
|
||||
imgui.separator()
|
||||
if self._patch_error_message:
|
||||
imgui.text_colored(vec4(255, 77, 77), f"Error: {self._patch_error_message}")
|
||||
@@ -4274,18 +4173,13 @@ class App:
|
||||
if self._pending_patch_text:
|
||||
diff_lines = self._pending_patch_text.split("\n")
|
||||
for line in diff_lines:
|
||||
if line.startswith("+++") or line.startswith("---") or line.startswith("@@"):
|
||||
imgui.text_colored(vec4(77, 178, 255), line)
|
||||
elif line.startswith("+"):
|
||||
imgui.text_colored(vec4(51, 230, 51), line)
|
||||
elif line.startswith("-"):
|
||||
imgui.text_colored(vec4(230, 51, 51), line)
|
||||
else:
|
||||
imgui.text(line)
|
||||
if line.startswith("+++") or line.startswith("---") or line.startswith("@@"): imgui.text_colored(vec4(77, 178, 255), line)
|
||||
elif line.startswith("+"): imgui.text_colored(vec4(51, 230, 51), line)
|
||||
elif line.startswith("-"): imgui.text_colored(vec4(230, 51, 51), line)
|
||||
else: imgui.text(line)
|
||||
imgui.end_child()
|
||||
imgui.separator()
|
||||
if imgui.button("Open in External Editor"):
|
||||
self._open_patch_in_external_editor()
|
||||
if imgui.button("Open in External Editor"): self._open_patch_in_external_editor()
|
||||
imgui.same_line()
|
||||
if imgui.button("Apply Patch"):
|
||||
self._apply_pending_patch()
|
||||
@@ -4304,7 +4198,6 @@ class App:
|
||||
self._patch_error_message = "No patch to apply"
|
||||
return
|
||||
try:
|
||||
from src.diff_viewer import apply_patch_to_file
|
||||
base_dir = str(self.controller.current_project_dir) if hasattr(self.controller, 'current_project_dir') else "."
|
||||
success, msg = apply_patch_to_file(self._pending_patch_text, base_dir)
|
||||
if success:
|
||||
@@ -4337,8 +4230,7 @@ class App:
|
||||
return
|
||||
temp_path = create_temp_modified_file(self._pending_patch_text)
|
||||
result = launcher.launch_diff(None, original_path, temp_path)
|
||||
if result is None:
|
||||
self._patch_error_message = "Failed to launch external editor"
|
||||
if result is None: self._patch_error_message = "Failed to launch external editor"
|
||||
else:
|
||||
self._patch_error_message = None
|
||||
self._vscode_diff_process = result
|
||||
@@ -4369,29 +4261,22 @@ class App:
|
||||
else:
|
||||
imgui.text("Default Editor:")
|
||||
editor_names = sorted(list(editors.keys()))
|
||||
if default_name and default_name in editor_names:
|
||||
current_idx = editor_names.index(default_name)
|
||||
else:
|
||||
current_idx = 0
|
||||
if default_name and default_name in editor_names: current_idx = editor_names.index(default_name)
|
||||
else: current_idx = 0
|
||||
changed, new_idx = imgui.combo("##editor_combo", current_idx, editor_names)
|
||||
if changed:
|
||||
self._set_external_editor_default(editor_names[new_idx])
|
||||
if changed: self._set_external_editor_default(editor_names[new_idx])
|
||||
imgui.text("")
|
||||
imgui.text("Configured Editors:")
|
||||
imgui.separator()
|
||||
for name in editor_names:
|
||||
editor = editors.get(name)
|
||||
if not editor:
|
||||
continue
|
||||
if not editor: continue
|
||||
is_default = name == default_name
|
||||
marker = " (default)" if is_default else ""
|
||||
if is_default:
|
||||
imgui.text_colored(C_IN, f" {name}{marker}")
|
||||
else:
|
||||
imgui.text(f" {name}{marker}")
|
||||
if is_default: imgui.text_colored(C_IN, f" {name}{marker}")
|
||||
else: imgui.text(f" {name}{marker}")
|
||||
imgui.text(f" {editor.path}")
|
||||
if editor.diff_args:
|
||||
imgui.textDisabled(f" diff: {editor.diff_args}")
|
||||
if editor.diff_args: imgui.textDisabled(f" diff: {editor.diff_args}")
|
||||
imgui.text("")
|
||||
imgui.text("Config: config.toml [tools.text_editors]")
|
||||
imgui.text("Override: manual_slop.toml default_editor")
|
||||
@@ -4410,8 +4295,7 @@ class App:
|
||||
self._pending_dialog_open = False
|
||||
|
||||
if imgui.begin_popup_modal("Approve PowerShell Command", None, imgui.WindowFlags_.always_auto_resize)[0]:
|
||||
if not dlg:
|
||||
imgui.close_current_popup()
|
||||
if not dlg: imgui.close_current_popup()
|
||||
else:
|
||||
imgui.text("The AI wants to run the following PowerShell script:")
|
||||
imgui.text_colored(vec4(200, 200, 100), f"base_dir: {dlg._base_dir}")
|
||||
@@ -4430,8 +4314,7 @@ class App:
|
||||
dlg._approved = True
|
||||
dlg._done = True
|
||||
dlg._condition.notify_all()
|
||||
with self._pending_dialog_lock:
|
||||
self._pending_dialog = None
|
||||
with self._pending_dialog_lock: self._pending_dialog = None
|
||||
imgui.close_current_popup()
|
||||
imgui.same_line()
|
||||
if imgui.button("Reject", imgui.ImVec2(120, 0)):
|
||||
@@ -4439,8 +4322,7 @@ class App:
|
||||
dlg._approved = False
|
||||
dlg._done = True
|
||||
dlg._condition.notify_all()
|
||||
with self._pending_dialog_lock:
|
||||
self._pending_dialog = None
|
||||
with self._pending_dialog_lock: self._pending_dialog = None
|
||||
imgui.close_current_popup()
|
||||
imgui.end_popup()
|
||||
|
||||
@@ -4750,8 +4632,7 @@ def hello():
|
||||
self._show_add_ticket_form = False
|
||||
self._push_mma_state_update()
|
||||
imgui.same_line()
|
||||
if imgui.button("Cancel"):
|
||||
self._show_add_ticket_form = False
|
||||
if imgui.button("Cancel"): self._show_add_ticket_form = False
|
||||
imgui.end_child()
|
||||
else:
|
||||
imgui.text_disabled("No active MMA track or tickets.")
|
||||
@@ -4911,8 +4792,7 @@ def hello():
|
||||
if imgui.begin_popup_modal("Cycle Detected!", None, imgui.WindowFlags_.always_auto_resize)[0]:
|
||||
imgui.text_colored(imgui.ImVec4(1, 0.3, 0.3, 1), "The dependency graph contains a cycle!")
|
||||
imgui.text("Please remove the circular dependency.")
|
||||
if imgui.button("OK"):
|
||||
imgui.close_current_popup()
|
||||
if imgui.button("OK"): imgui.close_current_popup()
|
||||
imgui.end_popup()
|
||||
|
||||
def _render_mma_track_summary(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user