more gui_2.py
This commit is contained in:
+104
-132
@@ -3603,7 +3603,7 @@ def render_ast_inspector_modal(app: App) -> None:
|
||||
if getattr(app, 'show_structural_editor_modal', False):
|
||||
imgui.open_popup('Structural File Editor')
|
||||
app.show_structural_editor_modal = False
|
||||
|
||||
|
||||
imgui.set_next_window_size(imgui.ImVec2(1400, 900), imgui.Cond_.first_use_ever)
|
||||
expanded, opened = imgui.begin_popup_modal('Structural File Editor', True, imgui.WindowFlags_.none)
|
||||
if opened:
|
||||
@@ -3613,19 +3613,19 @@ def render_ast_inspector_modal(app: App) -> None:
|
||||
else:
|
||||
f_item = app.ui_editing_slices_file
|
||||
f_path = f_item.path if hasattr(f_item, "path") else str(f_item)
|
||||
|
||||
|
||||
if f_path != getattr(app, '_cached_ast_file_path', None):
|
||||
outline = ""
|
||||
try:
|
||||
proj_dir = str(Path(app.controller.active_project_path).parent.resolve()) if getattr(app, 'controller', None) and app.controller.active_project_path else None
|
||||
mcp_client.configure([{"path": f_path}], [proj_dir] if proj_dir else None)
|
||||
|
||||
|
||||
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)
|
||||
elif f_path.lower().endswith(('.cpp', '.hpp', '.cxx', '.cc')): outline = mcp_client.ts_cpp_get_code_outline(f_path)
|
||||
except Exception as e:
|
||||
outline = f"Error fetching outline: {e}"
|
||||
|
||||
|
||||
app._cached_ast_nodes = []
|
||||
import re #TODO(Ed): Review local import
|
||||
pattern = re.compile(r'^(\s*)\[(.*?)\] (.*?) \(Lines (\d+)-(\d+)\)')
|
||||
@@ -3639,34 +3639,34 @@ def render_ast_inspector_modal(app: App) -> None:
|
||||
stack.append((indent, name))
|
||||
full_path = '::'.join([s[1] for s in stack])
|
||||
app._cached_ast_nodes.append({
|
||||
'indent': indent,
|
||||
'kind': kind,
|
||||
'name': name,
|
||||
'full_path': full_path,
|
||||
'indent': indent,
|
||||
'kind': kind,
|
||||
'name': name,
|
||||
'full_path': full_path,
|
||||
'start_line': int(start_ln),
|
||||
'end_line': int(end_ln)
|
||||
'end_line': int(end_ln)
|
||||
})
|
||||
try:
|
||||
content = mcp_client.read_file(f_path)
|
||||
content = mcp_client.read_file(f_path)
|
||||
app._cached_ast_file_lines = content.splitlines()
|
||||
app.text_viewer_content = content
|
||||
app.text_viewer_content = content
|
||||
except Exception:
|
||||
app._cached_ast_file_lines = ["Error loading file content."]
|
||||
app.text_viewer_content = "Error loading file content."
|
||||
app._cached_ast_file_path = f_path
|
||||
|
||||
app.text_viewer_content = "Error loading file content."
|
||||
app._cached_ast_file_path = f_path
|
||||
|
||||
imgui.text(f"Editing Structure: {f_path}")
|
||||
imgui.separator()
|
||||
|
||||
avail = imgui.get_content_region_avail()
|
||||
|
||||
avail = imgui.get_content_region_avail()
|
||||
table_height = max(100.0, avail.y - imgui.get_frame_height_with_spacing() * 2 - 20)
|
||||
|
||||
|
||||
if imgui.begin_table('structure_dual_pane', 2, imgui.TableFlags_.resizable | imgui.TableFlags_.borders_inner_v, imgui.ImVec2(0, table_height)):
|
||||
imgui.table_setup_column("AST & Slices", imgui.TableColumnFlags_.width_fixed, 400)
|
||||
imgui.table_setup_column("AST & Slices", imgui.TableColumnFlags_.width_fixed, 400)
|
||||
imgui.table_setup_column("Content Preview", imgui.TableColumnFlags_.width_stretch)
|
||||
imgui.table_next_row()
|
||||
imgui.table_next_column()
|
||||
|
||||
|
||||
# --- LEFT COLUMN: AST Tree & Slice Management ---
|
||||
imgui.begin_child("ast_tree_scroll", imgui.ImVec2(0, 0), True)
|
||||
# if True:
|
||||
@@ -3700,7 +3700,7 @@ def render_ast_inspector_modal(app: App) -> None:
|
||||
# if do_align: imgui.same_line((avail_width - btn_width))
|
||||
# else: imgui.same_line()
|
||||
# imgui.same_line((avail_width - btn_width) * 0.925)
|
||||
|
||||
|
||||
if not hasattr(f_item, 'ast_mask'): f_item.ast_mask = {}
|
||||
current_mode = f_item.ast_mask.get(full_path, 'hide')
|
||||
|
||||
@@ -3721,12 +3721,15 @@ def render_ast_inspector_modal(app: App) -> None:
|
||||
s_line = min(app._slice_sel_start, app._slice_sel_end)
|
||||
e_line = max(app._slice_sel_start, app._slice_sel_end)
|
||||
from src.fuzzy_anchor import FuzzyAnchor
|
||||
slice_data = FuzzyAnchor.create_slice(app.text_viewer_content, s_line, e_line)
|
||||
slice_data = FuzzyAnchor.create_slice(app.text_viewer_content, s_line, e_line)
|
||||
slice_data['tag'] = ""; slice_data['comment'] = ""
|
||||
f_item.custom_slices.append(slice_data)
|
||||
app._slice_sel_start = -1; app._slice_sel_end = -1
|
||||
app._slice_sel_start = -1
|
||||
app._slice_sel_end = -1
|
||||
imgui.same_line()
|
||||
if imgui.button("Clear Selection"): app._slice_sel_start = -1; app._slice_sel_end = -1
|
||||
if imgui.button("Clear Selection"):
|
||||
app._slice_sel_start = -1
|
||||
app._slice_sel_end = -1
|
||||
imgui.same_line()
|
||||
if imgui.button("Auto-Populate"): app._populate_auto_slices(f_item)
|
||||
|
||||
@@ -3747,9 +3750,9 @@ def render_ast_inspector_modal(app: App) -> None:
|
||||
imgui.pop_id()
|
||||
if to_remove != -1: f_item.custom_slices.pop(to_remove)
|
||||
imgui.end_child()
|
||||
|
||||
|
||||
imgui.table_next_column()
|
||||
|
||||
|
||||
# --- RIGHT COLUMN: Content Preview with Highlights ---
|
||||
with imscope.child("ast_content_scroll", imgui.ImVec2(0, 0), True):
|
||||
if not getattr(app, '_cached_ast_file_lines', None):
|
||||
@@ -3758,10 +3761,10 @@ def render_ast_inspector_modal(app: App) -> None:
|
||||
draw_list = imgui.get_window_draw_list()
|
||||
for i, line_text in enumerate(app._cached_ast_file_lines):
|
||||
line_num = i + 1
|
||||
pos = imgui.get_cursor_screen_pos()
|
||||
pos = imgui.get_cursor_screen_pos()
|
||||
line_height = imgui.get_text_line_height()
|
||||
avail_width = imgui.get_content_region_avail().x
|
||||
|
||||
|
||||
# 1. AST Highlight
|
||||
deepest_node = None
|
||||
for node in app._cached_ast_nodes:
|
||||
@@ -3769,31 +3772,29 @@ def render_ast_inspector_modal(app: App) -> None:
|
||||
if deepest_node is None or node['indent'] > deepest_node['indent']: deepest_node = node
|
||||
mode = 'hide'
|
||||
if deepest_node: mode = getattr(f_item, 'ast_mask', {}).get(deepest_node['full_path'], 'hide')
|
||||
if mode == 'def':
|
||||
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_auto", alpha=0.15)))
|
||||
elif mode == 'sig':
|
||||
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_selection", alpha=0.15)))
|
||||
if mode == 'def': draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_auto", alpha=0.15)))
|
||||
elif mode == 'sig': draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_selection", alpha=0.15)))
|
||||
elif deepest_node and deepest_node['full_path'] == getattr(app, '_hovered_ast_node', None):
|
||||
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("status_warning", alpha=0.2)))
|
||||
|
||||
|
||||
# 2. Slice Highlight
|
||||
if hasattr(f_item, 'custom_slices'):
|
||||
is_auto = any(slc['start_line'] <= line_num <= slc['end_line'] for slc in f_item.custom_slices if slc.get('tag') == 'auto-ast')
|
||||
is_man = any(slc['start_line'] <= line_num <= slc['end_line'] for slc in f_item.custom_slices if slc.get('tag') != 'auto-ast')
|
||||
is_man = any(slc['start_line'] <= line_num <= slc['end_line'] for slc in f_item.custom_slices if slc.get('tag') != 'auto-ast')
|
||||
if is_man: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_manual", alpha=0.2)))
|
||||
elif is_auto and mode == 'hide': draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_auto", alpha=0.1)))
|
||||
|
||||
|
||||
# 3. Active Selection Highlight
|
||||
if getattr(app, '_slice_sel_start', -1) != -1 and getattr(app, '_slice_sel_end', -1) != -1:
|
||||
s, e = min(app._slice_sel_start, app._slice_sel_end), max(app._slice_sel_start, app._slice_sel_end)
|
||||
if s <= line_num <= e: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_selection", alpha=0.3)))
|
||||
|
||||
|
||||
imgui.selectable(f"{line_num:4} | {line_text}##ln{line_num}", False)
|
||||
if imgui.is_item_clicked(): app._slice_sel_start = line_num; app._slice_sel_end = line_num
|
||||
if imgui.is_item_hovered(imgui.HoveredFlags_.allow_when_blocked_by_active_item) and imgui.is_mouse_down(0): app._slice_sel_end = line_num
|
||||
|
||||
|
||||
imgui.end_table()
|
||||
|
||||
|
||||
imgui.separator()
|
||||
if imgui.button("Close", imgui.ImVec2(120, 0)):
|
||||
app.ui_editing_slices_file = None
|
||||
@@ -3806,11 +3807,9 @@ def render_ast_inspector_modal(app: App) -> None:
|
||||
app.ui_inspecting_ast_file = None
|
||||
|
||||
def render_save_workspace_profile_modal(app: App) -> None:
|
||||
"""
|
||||
Renders a popup modal for saving the current workspace profile (projects, layout, configuration).
|
||||
"""Renders a popup modal for saving the current workspace profile (projects, layout, configuration).
|
||||
|
||||
SSDL Shape:
|
||||
`[I:name_input] -> [B:scope_radio] -> [B:save_button] => [B:cancel_button]`
|
||||
SSDL: `[I:name_input] -> [B:scope_radio] -> [B:save_button] => [B:cancel_button]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -3831,7 +3830,7 @@ def render_save_workspace_profile_modal(app: App) -> None:
|
||||
imgui.text("Scope:")
|
||||
if imgui.radio_button("Project", app._new_workspace_profile_scope == "project"): app._new_workspace_profile_scope = "project"
|
||||
imgui.same_line()
|
||||
if imgui.radio_button("Global", app._new_workspace_profile_scope == "global"): app._new_workspace_profile_scope = "global"
|
||||
if imgui.radio_button("Global", app._new_workspace_profile_scope == "global"): app._new_workspace_profile_scope = "global"
|
||||
|
||||
imgui.separator()
|
||||
if imgui.button("Save", (120, 0)):
|
||||
@@ -3848,12 +3847,10 @@ def render_save_workspace_profile_modal(app: App) -> None:
|
||||
imgui.end_popup()
|
||||
|
||||
def render_context_presets_panel(app: App) -> None:
|
||||
"""
|
||||
Renders the Context Presets configuration panel. Enables naming, saving, loading,
|
||||
"""Renders the Context Presets configuration panel. Enables naming, saving, loading,
|
||||
and deleting context presets.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:presets_list] -> [B:save_new_preset] => [B:presets_action_buttons]`
|
||||
SSDL: `[I:presets_list] -> [B:save_new_preset] => [B:presets_action_buttons]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -3885,11 +3882,9 @@ def render_context_presets_panel(app: App) -> None:
|
||||
if imgui.button(f"Delete##{name}"): app.delete_context_preset(name)
|
||||
|
||||
def render_context_screenshots(app: App) -> None:
|
||||
"""
|
||||
Renders a list of the currently attached screenshot image files.
|
||||
"""Renders a list of the currently attached screenshot image files.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:screenshots]`
|
||||
SSDL: `[I:screenshots]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -3900,12 +3895,10 @@ def render_context_screenshots(app: App) -> None:
|
||||
for i, s in enumerate(app.screenshots): imgui.text(s)
|
||||
|
||||
def render_context_files_table(app: App) -> None:
|
||||
"""
|
||||
Renders a two-column table mapping active context files to their AST view modes
|
||||
"""Renders a two-column table mapping active context files to their AST view modes
|
||||
(Definition, Signature, Hide) and slice indicators. Grouped by directories.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:group_by_dir] -> o-> [I:dir_node] -> o-> [I:file_row]`
|
||||
SSDL: `[I:group_by_dir] -> o-> [I:dir_node] -> o-> [I:file_row]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+-------------------------------------------------------------+
|
||||
@@ -3921,7 +3914,7 @@ def render_context_files_table(app: App) -> None:
|
||||
|
||||
with imscope.table("ctx_comp_table", 2, imgui.TableFlags_.resizable | imgui.TableFlags_.borders) as active:
|
||||
if active:
|
||||
imgui.table_setup_column("File", imgui.TableColumnFlags_.width_stretch)
|
||||
imgui.table_setup_column("File", imgui.TableColumnFlags_.width_stretch)
|
||||
imgui.table_setup_column("Flags", imgui.TableColumnFlags_.width_fixed, 200)
|
||||
imgui.table_headers_row()
|
||||
|
||||
@@ -4017,11 +4010,9 @@ def render_context_files_table(app: App) -> None:
|
||||
imgui.text_colored(theme.get_color("status_warning"), "[Slices Active]")
|
||||
|
||||
def render_context_presets(app: App) -> None:
|
||||
"""
|
||||
Renders context preset management controls (combobox selector, update button, save-as, and delete active).
|
||||
"""Renders context preset management controls (combobox selector, update button, save-as, and delete active).
|
||||
|
||||
SSDL Shape:
|
||||
`[I:presets] -> [B:presets_combo] -> [B:save_as_button] => [B:delete_active]`
|
||||
SSDL: `[I:presets] -> [B:presets_combo] -> [B:save_as_button] => [B:delete_active]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -4055,12 +4046,12 @@ def render_context_presets(app: App) -> None:
|
||||
for f in app.context_files:
|
||||
import copy
|
||||
from src import models
|
||||
p = f.path if hasattr(f, 'path') else str(f)
|
||||
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
||||
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
|
||||
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
|
||||
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
|
||||
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
|
||||
p = f.path if hasattr(f, 'path') else str(f)
|
||||
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
||||
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
|
||||
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
|
||||
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
|
||||
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
|
||||
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
|
||||
preset = models.ContextPreset(name=active, files=preset_files, screenshots=list(app.screenshots))
|
||||
app.controller.save_context_preset(preset)
|
||||
@@ -4082,12 +4073,9 @@ def render_context_presets(app: App) -> None:
|
||||
root = app.controller.active_project_root
|
||||
for f in app.context_files:
|
||||
path = f.path if hasattr(f, "path") else str(f)
|
||||
if not os.path.isabs(path):
|
||||
full_path = os.path.join(root, path)
|
||||
else:
|
||||
full_path = path
|
||||
if not os.path.exists(full_path):
|
||||
missing.append(path)
|
||||
if not os.path.isabs(path): full_path = os.path.join(root, path)
|
||||
else: full_path = path
|
||||
if not os.path.exists(full_path): missing.append(path)
|
||||
|
||||
if missing:
|
||||
app.missing_context_files = missing
|
||||
@@ -4098,12 +4086,12 @@ def render_context_presets(app: App) -> None:
|
||||
for f in app.context_files:
|
||||
import copy
|
||||
from src import models
|
||||
p = f.path if hasattr(f, 'path') else str(f)
|
||||
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
||||
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
|
||||
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
|
||||
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
|
||||
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
|
||||
p = f.path if hasattr(f, 'path') else str(f)
|
||||
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
||||
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
|
||||
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
|
||||
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
|
||||
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
|
||||
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
|
||||
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
|
||||
app.controller.save_context_preset(preset)
|
||||
@@ -4118,11 +4106,9 @@ def render_context_presets(app: App) -> None:
|
||||
app.ui_active_context_preset = ""
|
||||
|
||||
def render_snapshot_tab(app: App) -> None:
|
||||
"""
|
||||
Renders the Snapshot tab-bar, containing the resolved aggregate markdown and active system prompts.
|
||||
"""Renders the Snapshot tab-bar, containing the resolved aggregate markdown and active system prompts.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:aggregate_text] -> [B:copy_buttons] => [I:preview_panes]`
|
||||
SSDL: `[I:aggregate_text] -> [B:copy_buttons] => [I:preview_panes]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -4150,13 +4136,13 @@ def render_snapshot_tab(app: App) -> None:
|
||||
display_md = app._focus_md_cache[cp_name]
|
||||
else:
|
||||
flat = src.project_manager.flat_config(app.controller.project, app.active_discussion)
|
||||
cp = app.controller.project.get('context_presets', {}).get(cp_name)
|
||||
cp = app.controller.project.get('context_presets', {}).get(cp_name)
|
||||
if cp:
|
||||
flat["files"]["paths"] = cp.get("files", [])
|
||||
flat["files"]["paths"] = cp.get("files", [])
|
||||
flat["screenshots"]["paths"] = cp.get("screenshots", [])
|
||||
full_md, _, _ = src.aggregate.run(flat)
|
||||
full_md, _, _ = src.aggregate.run(flat)
|
||||
app._focus_md_cache[cp_name] = full_md
|
||||
display_md = full_md
|
||||
display_md = full_md
|
||||
if imgui.button("Copy"): imgui.set_clipboard_text(display_md)
|
||||
with imscope.child("last_agg_md", 0, 0, True):
|
||||
markdown_helper.render(display_md, context_id="snapshot_agg")
|
||||
@@ -4167,11 +4153,9 @@ def render_snapshot_tab(app: App) -> None:
|
||||
markdown_helper.render(app.last_resolved_system_prompt, context_id="snapshot_sys")
|
||||
|
||||
def render_empty_context_modal(app: App) -> None:
|
||||
"""
|
||||
Renders a popup modal warning the user when the context composition is empty.
|
||||
"""Renders a popup modal warning the user when the context composition is empty.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:warning_text] -> [B:proceed_button] => [B:cancel_button]`
|
||||
SSDL: `[I:warning_text] -> [B:proceed_button] => [B:cancel_button]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -4192,8 +4176,8 @@ def render_empty_context_modal(app: App) -> None:
|
||||
imgui.text("This may result in poor AI performance or loss of project context.")
|
||||
imgui.separator()
|
||||
if imgui.button("Proceed Anyway", imgui.ImVec2(150, 0)):
|
||||
if app._pending_generation_action == 'generate': app.controller._handle_generate_send()
|
||||
elif app._pending_generation_action == 'md_only': app.controller._handle_md_only()
|
||||
if app._pending_generation_action == 'generate': app.controller._handle_generate_send()
|
||||
elif app._pending_generation_action == 'md_only': app.controller._handle_md_only()
|
||||
app._pending_generation_action = None
|
||||
imgui.close_current_popup()
|
||||
imgui.same_line()
|
||||
@@ -4202,12 +4186,10 @@ def render_empty_context_modal(app: App) -> None:
|
||||
imgui.end_popup()
|
||||
|
||||
def render_context_modals(app: App) -> None:
|
||||
"""
|
||||
Dispatches rendering calls to sub-modals relating to context management
|
||||
"""Dispatches rendering calls to sub-modals relating to context management
|
||||
(empty context warning, file picker, missing files warning, and AST inspector).
|
||||
|
||||
SSDL Shape:
|
||||
`[I] -> [I:modals_dispatch]`
|
||||
SSDL: `[I] -> [I:modals_dispatch]`
|
||||
|
||||
ASCII Layout Map:
|
||||
Conditionally opens (in order):
|
||||
@@ -4239,12 +4221,12 @@ def render_context_modals(app: App) -> None:
|
||||
for f in app.context_files:
|
||||
import copy
|
||||
from src import models
|
||||
p = f.path if hasattr(f, 'path') else str(f)
|
||||
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
||||
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
|
||||
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
|
||||
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
|
||||
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
|
||||
p = f.path if hasattr(f, 'path') else str(f)
|
||||
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
||||
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
|
||||
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
|
||||
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
|
||||
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
|
||||
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
|
||||
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
|
||||
app.controller.save_context_preset(preset)
|
||||
@@ -4262,10 +4244,10 @@ def render_context_modals(app: App) -> None:
|
||||
def _get_context_composition_state(app: App) -> tuple:
|
||||
files_state = []
|
||||
for f in app.context_files:
|
||||
p = f.path if hasattr(f, 'path') else str(f)
|
||||
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
||||
agg = f.auto_aggregate if hasattr(f, 'auto_aggregate') else False
|
||||
slc = tuple((s.get('start_line'), s.get('end_line'), s.get('tag'), s.get('comment')) for s in getattr(f, 'custom_slices', []))
|
||||
p = f.path if hasattr(f, 'path') else str(f)
|
||||
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
||||
agg = f.auto_aggregate if hasattr(f, 'auto_aggregate') else False
|
||||
slc = tuple((s.get('start_line'), s.get('end_line'), s.get('tag'), s.get('comment')) for s in getattr(f, 'custom_slices', []))
|
||||
mask = tuple(sorted(getattr(f, 'ast_mask', {}).items()))
|
||||
files_state.append((p, vm, agg, slc, mask))
|
||||
screenshots_state = tuple(app.screenshots)
|
||||
@@ -4287,8 +4269,8 @@ def _check_auto_refresh_context_preview(app: App) -> None:
|
||||
def worker():
|
||||
try:
|
||||
app.controller.context_files = app.context_files
|
||||
res = app.controller._do_generate()
|
||||
app.context_preview_text = res[0]
|
||||
res = app.controller._do_generate()
|
||||
app.context_preview_text = res[0]
|
||||
except Exception:
|
||||
app.context_preview_text = "Error generating context preview."
|
||||
finally:
|
||||
@@ -4303,12 +4285,10 @@ def _check_auto_refresh_context_preview(app: App) -> None:
|
||||
app.controller.submit_io(worker)
|
||||
|
||||
def render_context_preview_window(app: App) -> None:
|
||||
"""
|
||||
Renders the Context Preview window. Automatically refreshes aggregated context previews in the background
|
||||
"""Renders the Context Preview window. Automatically refreshes aggregated context previews in the background
|
||||
and renders formatted markdown text.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:preview_text] -> [B:clipboard_button] => [I:preview_box]`
|
||||
SSDL: `[I:preview_text] -> [B:clipboard_button] => [I:preview_box]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -4330,7 +4310,7 @@ def render_context_preview_window(app: App) -> None:
|
||||
if exp:
|
||||
if imgui.button("Close"):
|
||||
app.show_windows["Context Preview"] = False
|
||||
app.ui_separate_context_preview = False
|
||||
app.ui_separate_context_preview = False
|
||||
imgui.same_line()
|
||||
if imgui.button("Copy to Clipboard"):
|
||||
imgui.set_clipboard_text(app.context_preview_text)
|
||||
@@ -4342,12 +4322,10 @@ def render_context_preview_window(app: App) -> None:
|
||||
#region: Discussions
|
||||
|
||||
def render_discussion_hub(app: App) -> None:
|
||||
"""
|
||||
Top-level hub for the Discussion panel. Houses tabs for Discussion, Context Composition,
|
||||
"""Top-level hub for the Discussion panel. Houses tabs for Discussion, Context Composition,
|
||||
Context Preview (inline or detached), Snapshot, and Takes.
|
||||
|
||||
SSDL Shape:
|
||||
`[B:pop_out_toggle] -> [I:tab_bar] => [I:active_tab_content]`
|
||||
SSDL: `[B:pop_out_toggle] -> [I:tab_bar] => [I:active_tab_content]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+---------------------------------------------------------+
|
||||
@@ -4383,12 +4361,10 @@ def render_discussion_hub(app: App) -> None:
|
||||
return
|
||||
|
||||
def render_thinking_trace(app: App, entry: dict, segments: list[dict], entry_index: int, is_standalone: bool = False) -> None:
|
||||
"""
|
||||
Renders a collapsible thinking-trace section within a discussion entry bubble.
|
||||
"""Renders a collapsible thinking-trace section within a discussion entry bubble.
|
||||
Displays each reasoning segment labeled by its marker tag (e.g. [thinking]).
|
||||
|
||||
SSDL Shape:
|
||||
`[I:segment_list] -> [B:read_pure_toggle] => [I:trace_child]`
|
||||
SSDL: `[I:segment_list] -> [B:read_pure_toggle] => [I:trace_child]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+----------------------------------------------------------+
|
||||
@@ -4426,22 +4402,18 @@ def render_thinking_trace(app: App, entry: dict, segments: list[dict], entry_ind
|
||||
imgui.text_colored(C_TC(), f"[{marker}]")
|
||||
if thinking_read_mode:
|
||||
if app.ui_word_wrap:
|
||||
with imscope.text_wrap(imgui.get_content_region_avail().x):
|
||||
imgui.text(content)
|
||||
else:
|
||||
imgui.text(content)
|
||||
with imscope.text_wrap(imgui.get_content_region_avail().x): imgui.text(content)
|
||||
else: imgui.text(content)
|
||||
else:
|
||||
render_selectable_label(app, f"think_text_{entry_index}_{idx}", content, multiline=True, height=-1)
|
||||
imgui.separator()
|
||||
|
||||
def render_discussion_entry(app: App, entry: dict, index: int) -> None:
|
||||
"""
|
||||
Renders a single discussion message entry as a colored visual bubble.
|
||||
"""Renders a single discussion message entry as a colored visual bubble.
|
||||
Supports collapsible states, read/edit mode toggles, role selection,
|
||||
input/output token metrics, and action footers.
|
||||
|
||||
SSDL Shape:
|
||||
`[I:header] -> [B:collapsed] => [I:preview] | [I:body] -> [I:footer]`
|
||||
SSDL: `[I:header] -> [B:collapsed] => [I:preview] | [I:body] -> [I:footer]`
|
||||
|
||||
ASCII Layout Map:
|
||||
+-------------------------------------------------------------+
|
||||
@@ -7139,13 +7111,13 @@ def render_task_dag_panel(app: App) -> None: # 4. Task DAG Visualizer
|
||||
imgui.end_combo()
|
||||
if imgui.button("Create"):
|
||||
new_ticket = {
|
||||
"id": app.ui_new_ticket_id,
|
||||
"id": app.ui_new_ticket_id,
|
||||
"description": app.ui_new_ticket_desc,
|
||||
"status": "todo",
|
||||
"priority": app.ui_new_ticket_priority,
|
||||
"status": "todo",
|
||||
"priority": app.ui_new_ticket_priority,
|
||||
"assigned_to": "tier3-worker",
|
||||
"target_file": app.ui_new_ticket_target,
|
||||
"depends_on": [d.strip() for d in app.ui_new_ticket_deps.split(",") if d.strip()]
|
||||
"depends_on": [d.strip() for d in app.ui_new_ticket_deps.split(",") if d.strip()]
|
||||
}
|
||||
app.active_tickets.append(new_ticket)
|
||||
app._show_add_ticket_form = False
|
||||
|
||||
Reference in New Issue
Block a user