Private
Public Access
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):
|
if getattr(app, 'show_structural_editor_modal', False):
|
||||||
imgui.open_popup('Structural File Editor')
|
imgui.open_popup('Structural File Editor')
|
||||||
app.show_structural_editor_modal = False
|
app.show_structural_editor_modal = False
|
||||||
|
|
||||||
imgui.set_next_window_size(imgui.ImVec2(1400, 900), imgui.Cond_.first_use_ever)
|
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)
|
expanded, opened = imgui.begin_popup_modal('Structural File Editor', True, imgui.WindowFlags_.none)
|
||||||
if opened:
|
if opened:
|
||||||
@@ -3613,19 +3613,19 @@ def render_ast_inspector_modal(app: App) -> None:
|
|||||||
else:
|
else:
|
||||||
f_item = app.ui_editing_slices_file
|
f_item = app.ui_editing_slices_file
|
||||||
f_path = f_item.path if hasattr(f_item, "path") else str(f_item)
|
f_path = f_item.path if hasattr(f_item, "path") else str(f_item)
|
||||||
|
|
||||||
if f_path != getattr(app, '_cached_ast_file_path', None):
|
if f_path != getattr(app, '_cached_ast_file_path', None):
|
||||||
outline = ""
|
outline = ""
|
||||||
try:
|
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
|
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)
|
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)
|
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(('.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)
|
elif f_path.lower().endswith(('.cpp', '.hpp', '.cxx', '.cc')): outline = mcp_client.ts_cpp_get_code_outline(f_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
outline = f"Error fetching outline: {e}"
|
outline = f"Error fetching outline: {e}"
|
||||||
|
|
||||||
app._cached_ast_nodes = []
|
app._cached_ast_nodes = []
|
||||||
import re #TODO(Ed): Review local import
|
import re #TODO(Ed): Review local import
|
||||||
pattern = re.compile(r'^(\s*)\[(.*?)\] (.*?) \(Lines (\d+)-(\d+)\)')
|
pattern = re.compile(r'^(\s*)\[(.*?)\] (.*?) \(Lines (\d+)-(\d+)\)')
|
||||||
@@ -3639,34 +3639,34 @@ def render_ast_inspector_modal(app: App) -> None:
|
|||||||
stack.append((indent, name))
|
stack.append((indent, name))
|
||||||
full_path = '::'.join([s[1] for s in stack])
|
full_path = '::'.join([s[1] for s in stack])
|
||||||
app._cached_ast_nodes.append({
|
app._cached_ast_nodes.append({
|
||||||
'indent': indent,
|
'indent': indent,
|
||||||
'kind': kind,
|
'kind': kind,
|
||||||
'name': name,
|
'name': name,
|
||||||
'full_path': full_path,
|
'full_path': full_path,
|
||||||
'start_line': int(start_ln),
|
'start_line': int(start_ln),
|
||||||
'end_line': int(end_ln)
|
'end_line': int(end_ln)
|
||||||
})
|
})
|
||||||
try:
|
try:
|
||||||
content = mcp_client.read_file(f_path)
|
content = mcp_client.read_file(f_path)
|
||||||
app._cached_ast_file_lines = content.splitlines()
|
app._cached_ast_file_lines = content.splitlines()
|
||||||
app.text_viewer_content = content
|
app.text_viewer_content = content
|
||||||
except Exception:
|
except Exception:
|
||||||
app._cached_ast_file_lines = ["Error loading file content."]
|
app._cached_ast_file_lines = ["Error loading file content."]
|
||||||
app.text_viewer_content = "Error loading file content."
|
app.text_viewer_content = "Error loading file content."
|
||||||
app._cached_ast_file_path = f_path
|
app._cached_ast_file_path = f_path
|
||||||
|
|
||||||
imgui.text(f"Editing Structure: {f_path}")
|
imgui.text(f"Editing Structure: {f_path}")
|
||||||
imgui.separator()
|
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)
|
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)):
|
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_setup_column("Content Preview", imgui.TableColumnFlags_.width_stretch)
|
||||||
imgui.table_next_row()
|
imgui.table_next_row()
|
||||||
imgui.table_next_column()
|
imgui.table_next_column()
|
||||||
|
|
||||||
# --- LEFT COLUMN: AST Tree & Slice Management ---
|
# --- LEFT COLUMN: AST Tree & Slice Management ---
|
||||||
imgui.begin_child("ast_tree_scroll", imgui.ImVec2(0, 0), True)
|
imgui.begin_child("ast_tree_scroll", imgui.ImVec2(0, 0), True)
|
||||||
# if 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))
|
# if do_align: imgui.same_line((avail_width - btn_width))
|
||||||
# else: imgui.same_line()
|
# else: imgui.same_line()
|
||||||
# imgui.same_line((avail_width - btn_width) * 0.925)
|
# imgui.same_line((avail_width - btn_width) * 0.925)
|
||||||
|
|
||||||
if not hasattr(f_item, 'ast_mask'): f_item.ast_mask = {}
|
if not hasattr(f_item, 'ast_mask'): f_item.ast_mask = {}
|
||||||
current_mode = f_item.ast_mask.get(full_path, 'hide')
|
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)
|
s_line = min(app._slice_sel_start, app._slice_sel_end)
|
||||||
e_line = max(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
|
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'] = ""
|
slice_data['tag'] = ""; slice_data['comment'] = ""
|
||||||
f_item.custom_slices.append(slice_data)
|
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()
|
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()
|
imgui.same_line()
|
||||||
if imgui.button("Auto-Populate"): app._populate_auto_slices(f_item)
|
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()
|
imgui.pop_id()
|
||||||
if to_remove != -1: f_item.custom_slices.pop(to_remove)
|
if to_remove != -1: f_item.custom_slices.pop(to_remove)
|
||||||
imgui.end_child()
|
imgui.end_child()
|
||||||
|
|
||||||
imgui.table_next_column()
|
imgui.table_next_column()
|
||||||
|
|
||||||
# --- RIGHT COLUMN: Content Preview with Highlights ---
|
# --- RIGHT COLUMN: Content Preview with Highlights ---
|
||||||
with imscope.child("ast_content_scroll", imgui.ImVec2(0, 0), True):
|
with imscope.child("ast_content_scroll", imgui.ImVec2(0, 0), True):
|
||||||
if not getattr(app, '_cached_ast_file_lines', None):
|
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()
|
draw_list = imgui.get_window_draw_list()
|
||||||
for i, line_text in enumerate(app._cached_ast_file_lines):
|
for i, line_text in enumerate(app._cached_ast_file_lines):
|
||||||
line_num = i + 1
|
line_num = i + 1
|
||||||
pos = imgui.get_cursor_screen_pos()
|
pos = imgui.get_cursor_screen_pos()
|
||||||
line_height = imgui.get_text_line_height()
|
line_height = imgui.get_text_line_height()
|
||||||
avail_width = imgui.get_content_region_avail().x
|
avail_width = imgui.get_content_region_avail().x
|
||||||
|
|
||||||
# 1. AST Highlight
|
# 1. AST Highlight
|
||||||
deepest_node = None
|
deepest_node = None
|
||||||
for node in app._cached_ast_nodes:
|
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
|
if deepest_node is None or node['indent'] > deepest_node['indent']: deepest_node = node
|
||||||
mode = 'hide'
|
mode = 'hide'
|
||||||
if deepest_node: mode = getattr(f_item, 'ast_mask', {}).get(deepest_node['full_path'], 'hide')
|
if deepest_node: mode = getattr(f_item, 'ast_mask', {}).get(deepest_node['full_path'], 'hide')
|
||||||
if mode == 'def':
|
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)))
|
||||||
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 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):
|
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)))
|
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
|
# 2. Slice Highlight
|
||||||
if hasattr(f_item, 'custom_slices'):
|
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_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)))
|
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)))
|
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
|
# 3. Active Selection Highlight
|
||||||
if getattr(app, '_slice_sel_start', -1) != -1 and getattr(app, '_slice_sel_end', -1) != -1:
|
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)
|
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)))
|
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)
|
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_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
|
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.end_table()
|
||||||
|
|
||||||
imgui.separator()
|
imgui.separator()
|
||||||
if imgui.button("Close", imgui.ImVec2(120, 0)):
|
if imgui.button("Close", imgui.ImVec2(120, 0)):
|
||||||
app.ui_editing_slices_file = None
|
app.ui_editing_slices_file = None
|
||||||
@@ -3806,11 +3807,9 @@ def render_ast_inspector_modal(app: App) -> None:
|
|||||||
app.ui_inspecting_ast_file = None
|
app.ui_inspecting_ast_file = None
|
||||||
|
|
||||||
def render_save_workspace_profile_modal(app: App) -> 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:
|
SSDL: `[I:name_input] -> [B:scope_radio] -> [B:save_button] => [B:cancel_button]`
|
||||||
`[I:name_input] -> [B:scope_radio] -> [B:save_button] => [B:cancel_button]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -3831,7 +3830,7 @@ def render_save_workspace_profile_modal(app: App) -> None:
|
|||||||
imgui.text("Scope:")
|
imgui.text("Scope:")
|
||||||
if imgui.radio_button("Project", app._new_workspace_profile_scope == "project"): app._new_workspace_profile_scope = "project"
|
if imgui.radio_button("Project", app._new_workspace_profile_scope == "project"): app._new_workspace_profile_scope = "project"
|
||||||
imgui.same_line()
|
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()
|
imgui.separator()
|
||||||
if imgui.button("Save", (120, 0)):
|
if imgui.button("Save", (120, 0)):
|
||||||
@@ -3848,12 +3847,10 @@ def render_save_workspace_profile_modal(app: App) -> None:
|
|||||||
imgui.end_popup()
|
imgui.end_popup()
|
||||||
|
|
||||||
def render_context_presets_panel(app: App) -> None:
|
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.
|
and deleting context presets.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:presets_list] -> [B:save_new_preset] => [B:presets_action_buttons]`
|
||||||
`[I:presets_list] -> [B:save_new_preset] => [B:presets_action_buttons]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
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)
|
if imgui.button(f"Delete##{name}"): app.delete_context_preset(name)
|
||||||
|
|
||||||
def render_context_screenshots(app: App) -> None:
|
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:
|
SSDL: `[I:screenshots]`
|
||||||
`[I:screenshots]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -3900,12 +3895,10 @@ def render_context_screenshots(app: App) -> None:
|
|||||||
for i, s in enumerate(app.screenshots): imgui.text(s)
|
for i, s in enumerate(app.screenshots): imgui.text(s)
|
||||||
|
|
||||||
def render_context_files_table(app: App) -> None:
|
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.
|
(Definition, Signature, Hide) and slice indicators. Grouped by directories.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:group_by_dir] -> o-> [I:dir_node] -> o-> [I:file_row]`
|
||||||
`[I:group_by_dir] -> o-> [I:dir_node] -> o-> [I:file_row]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
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:
|
with imscope.table("ctx_comp_table", 2, imgui.TableFlags_.resizable | imgui.TableFlags_.borders) as active:
|
||||||
if 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_setup_column("Flags", imgui.TableColumnFlags_.width_fixed, 200)
|
||||||
imgui.table_headers_row()
|
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]")
|
imgui.text_colored(theme.get_color("status_warning"), "[Slices Active]")
|
||||||
|
|
||||||
def render_context_presets(app: App) -> None:
|
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:
|
SSDL: `[I:presets] -> [B:presets_combo] -> [B:save_as_button] => [B:delete_active]`
|
||||||
`[I:presets] -> [B:presets_combo] -> [B:save_as_button] => [B:delete_active]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -4055,12 +4046,12 @@ def render_context_presets(app: App) -> None:
|
|||||||
for f in app.context_files:
|
for f in app.context_files:
|
||||||
import copy
|
import copy
|
||||||
from src import models
|
from src import models
|
||||||
p = f.path if hasattr(f, 'path') else str(f)
|
p = f.path if hasattr(f, 'path') else str(f)
|
||||||
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
||||||
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
|
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
|
||||||
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
|
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
|
||||||
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
|
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
|
||||||
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') 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_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))
|
preset = models.ContextPreset(name=active, files=preset_files, screenshots=list(app.screenshots))
|
||||||
app.controller.save_context_preset(preset)
|
app.controller.save_context_preset(preset)
|
||||||
@@ -4082,12 +4073,9 @@ def render_context_presets(app: App) -> None:
|
|||||||
root = app.controller.active_project_root
|
root = app.controller.active_project_root
|
||||||
for f in app.context_files:
|
for f in app.context_files:
|
||||||
path = f.path if hasattr(f, "path") else str(f)
|
path = f.path if hasattr(f, "path") else str(f)
|
||||||
if not os.path.isabs(path):
|
if not os.path.isabs(path): full_path = os.path.join(root, path)
|
||||||
full_path = os.path.join(root, path)
|
else: full_path = path
|
||||||
else:
|
if not os.path.exists(full_path): missing.append(path)
|
||||||
full_path = path
|
|
||||||
if not os.path.exists(full_path):
|
|
||||||
missing.append(path)
|
|
||||||
|
|
||||||
if missing:
|
if missing:
|
||||||
app.missing_context_files = missing
|
app.missing_context_files = missing
|
||||||
@@ -4098,12 +4086,12 @@ def render_context_presets(app: App) -> None:
|
|||||||
for f in app.context_files:
|
for f in app.context_files:
|
||||||
import copy
|
import copy
|
||||||
from src import models
|
from src import models
|
||||||
p = f.path if hasattr(f, 'path') else str(f)
|
p = f.path if hasattr(f, 'path') else str(f)
|
||||||
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
||||||
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
|
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
|
||||||
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
|
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
|
||||||
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
|
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
|
||||||
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') 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_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))
|
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
|
||||||
app.controller.save_context_preset(preset)
|
app.controller.save_context_preset(preset)
|
||||||
@@ -4118,11 +4106,9 @@ def render_context_presets(app: App) -> None:
|
|||||||
app.ui_active_context_preset = ""
|
app.ui_active_context_preset = ""
|
||||||
|
|
||||||
def render_snapshot_tab(app: App) -> None:
|
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:
|
SSDL: `[I:aggregate_text] -> [B:copy_buttons] => [I:preview_panes]`
|
||||||
`[I:aggregate_text] -> [B:copy_buttons] => [I:preview_panes]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -4150,13 +4136,13 @@ def render_snapshot_tab(app: App) -> None:
|
|||||||
display_md = app._focus_md_cache[cp_name]
|
display_md = app._focus_md_cache[cp_name]
|
||||||
else:
|
else:
|
||||||
flat = src.project_manager.flat_config(app.controller.project, app.active_discussion)
|
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:
|
if cp:
|
||||||
flat["files"]["paths"] = cp.get("files", [])
|
flat["files"]["paths"] = cp.get("files", [])
|
||||||
flat["screenshots"]["paths"] = cp.get("screenshots", [])
|
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
|
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)
|
if imgui.button("Copy"): imgui.set_clipboard_text(display_md)
|
||||||
with imscope.child("last_agg_md", 0, 0, True):
|
with imscope.child("last_agg_md", 0, 0, True):
|
||||||
markdown_helper.render(display_md, context_id="snapshot_agg")
|
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")
|
markdown_helper.render(app.last_resolved_system_prompt, context_id="snapshot_sys")
|
||||||
|
|
||||||
def render_empty_context_modal(app: App) -> None:
|
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:
|
SSDL: `[I:warning_text] -> [B:proceed_button] => [B:cancel_button]`
|
||||||
`[I:warning_text] -> [B:proceed_button] => [B:cancel_button]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
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.text("This may result in poor AI performance or loss of project context.")
|
||||||
imgui.separator()
|
imgui.separator()
|
||||||
if imgui.button("Proceed Anyway", imgui.ImVec2(150, 0)):
|
if imgui.button("Proceed Anyway", imgui.ImVec2(150, 0)):
|
||||||
if app._pending_generation_action == 'generate': app.controller._handle_generate_send()
|
if app._pending_generation_action == 'generate': app.controller._handle_generate_send()
|
||||||
elif app._pending_generation_action == 'md_only': app.controller._handle_md_only()
|
elif app._pending_generation_action == 'md_only': app.controller._handle_md_only()
|
||||||
app._pending_generation_action = None
|
app._pending_generation_action = None
|
||||||
imgui.close_current_popup()
|
imgui.close_current_popup()
|
||||||
imgui.same_line()
|
imgui.same_line()
|
||||||
@@ -4202,12 +4186,10 @@ def render_empty_context_modal(app: App) -> None:
|
|||||||
imgui.end_popup()
|
imgui.end_popup()
|
||||||
|
|
||||||
def render_context_modals(app: App) -> None:
|
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).
|
(empty context warning, file picker, missing files warning, and AST inspector).
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I] -> [I:modals_dispatch]`
|
||||||
`[I] -> [I:modals_dispatch]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
Conditionally opens (in order):
|
Conditionally opens (in order):
|
||||||
@@ -4239,12 +4221,12 @@ def render_context_modals(app: App) -> None:
|
|||||||
for f in app.context_files:
|
for f in app.context_files:
|
||||||
import copy
|
import copy
|
||||||
from src import models
|
from src import models
|
||||||
p = f.path if hasattr(f, 'path') else str(f)
|
p = f.path if hasattr(f, 'path') else str(f)
|
||||||
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
||||||
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
|
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
|
||||||
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
|
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
|
||||||
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
|
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
|
||||||
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') 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_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))
|
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
|
||||||
app.controller.save_context_preset(preset)
|
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:
|
def _get_context_composition_state(app: App) -> tuple:
|
||||||
files_state = []
|
files_state = []
|
||||||
for f in app.context_files:
|
for f in app.context_files:
|
||||||
p = f.path if hasattr(f, 'path') else str(f)
|
p = f.path if hasattr(f, 'path') else str(f)
|
||||||
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
|
||||||
agg = f.auto_aggregate if hasattr(f, 'auto_aggregate') else False
|
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', []))
|
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()))
|
mask = tuple(sorted(getattr(f, 'ast_mask', {}).items()))
|
||||||
files_state.append((p, vm, agg, slc, mask))
|
files_state.append((p, vm, agg, slc, mask))
|
||||||
screenshots_state = tuple(app.screenshots)
|
screenshots_state = tuple(app.screenshots)
|
||||||
@@ -4287,8 +4269,8 @@ def _check_auto_refresh_context_preview(app: App) -> None:
|
|||||||
def worker():
|
def worker():
|
||||||
try:
|
try:
|
||||||
app.controller.context_files = app.context_files
|
app.controller.context_files = app.context_files
|
||||||
res = app.controller._do_generate()
|
res = app.controller._do_generate()
|
||||||
app.context_preview_text = res[0]
|
app.context_preview_text = res[0]
|
||||||
except Exception:
|
except Exception:
|
||||||
app.context_preview_text = "Error generating context preview."
|
app.context_preview_text = "Error generating context preview."
|
||||||
finally:
|
finally:
|
||||||
@@ -4303,12 +4285,10 @@ def _check_auto_refresh_context_preview(app: App) -> None:
|
|||||||
app.controller.submit_io(worker)
|
app.controller.submit_io(worker)
|
||||||
|
|
||||||
def render_context_preview_window(app: App) -> None:
|
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.
|
and renders formatted markdown text.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:preview_text] -> [B:clipboard_button] => [I:preview_box]`
|
||||||
`[I:preview_text] -> [B:clipboard_button] => [I:preview_box]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -4330,7 +4310,7 @@ def render_context_preview_window(app: App) -> None:
|
|||||||
if exp:
|
if exp:
|
||||||
if imgui.button("Close"):
|
if imgui.button("Close"):
|
||||||
app.show_windows["Context Preview"] = False
|
app.show_windows["Context Preview"] = False
|
||||||
app.ui_separate_context_preview = False
|
app.ui_separate_context_preview = False
|
||||||
imgui.same_line()
|
imgui.same_line()
|
||||||
if imgui.button("Copy to Clipboard"):
|
if imgui.button("Copy to Clipboard"):
|
||||||
imgui.set_clipboard_text(app.context_preview_text)
|
imgui.set_clipboard_text(app.context_preview_text)
|
||||||
@@ -4342,12 +4322,10 @@ def render_context_preview_window(app: App) -> None:
|
|||||||
#region: Discussions
|
#region: Discussions
|
||||||
|
|
||||||
def render_discussion_hub(app: App) -> None:
|
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.
|
Context Preview (inline or detached), Snapshot, and Takes.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[B:pop_out_toggle] -> [I:tab_bar] => [I:active_tab_content]`
|
||||||
`[B:pop_out_toggle] -> [I:tab_bar] => [I:active_tab_content]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -4383,12 +4361,10 @@ def render_discussion_hub(app: App) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
def render_thinking_trace(app: App, entry: dict, segments: list[dict], entry_index: int, is_standalone: bool = False) -> None:
|
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]).
|
Displays each reasoning segment labeled by its marker tag (e.g. [thinking]).
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:segment_list] -> [B:read_pure_toggle] => [I:trace_child]`
|
||||||
`[I:segment_list] -> [B:read_pure_toggle] => [I:trace_child]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
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}]")
|
imgui.text_colored(C_TC(), f"[{marker}]")
|
||||||
if thinking_read_mode:
|
if thinking_read_mode:
|
||||||
if app.ui_word_wrap:
|
if app.ui_word_wrap:
|
||||||
with imscope.text_wrap(imgui.get_content_region_avail().x):
|
with imscope.text_wrap(imgui.get_content_region_avail().x): imgui.text(content)
|
||||||
imgui.text(content)
|
else: imgui.text(content)
|
||||||
else:
|
|
||||||
imgui.text(content)
|
|
||||||
else:
|
else:
|
||||||
render_selectable_label(app, f"think_text_{entry_index}_{idx}", content, multiline=True, height=-1)
|
render_selectable_label(app, f"think_text_{entry_index}_{idx}", content, multiline=True, height=-1)
|
||||||
imgui.separator()
|
imgui.separator()
|
||||||
|
|
||||||
def render_discussion_entry(app: App, entry: dict, index: int) -> None:
|
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,
|
Supports collapsible states, read/edit mode toggles, role selection,
|
||||||
input/output token metrics, and action footers.
|
input/output token metrics, and action footers.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:header] -> [B:collapsed] => [I:preview] | [I:body] -> [I:footer]`
|
||||||
`[I:header] -> [B:collapsed] => [I:preview] | [I:body] -> [I:footer]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+-------------------------------------------------------------+
|
+-------------------------------------------------------------+
|
||||||
@@ -7139,13 +7111,13 @@ def render_task_dag_panel(app: App) -> None: # 4. Task DAG Visualizer
|
|||||||
imgui.end_combo()
|
imgui.end_combo()
|
||||||
if imgui.button("Create"):
|
if imgui.button("Create"):
|
||||||
new_ticket = {
|
new_ticket = {
|
||||||
"id": app.ui_new_ticket_id,
|
"id": app.ui_new_ticket_id,
|
||||||
"description": app.ui_new_ticket_desc,
|
"description": app.ui_new_ticket_desc,
|
||||||
"status": "todo",
|
"status": "todo",
|
||||||
"priority": app.ui_new_ticket_priority,
|
"priority": app.ui_new_ticket_priority,
|
||||||
"assigned_to": "tier3-worker",
|
"assigned_to": "tier3-worker",
|
||||||
"target_file": app.ui_new_ticket_target,
|
"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.active_tickets.append(new_ticket)
|
||||||
app._show_add_ticket_form = False
|
app._show_add_ticket_form = False
|
||||||
|
|||||||
Reference in New Issue
Block a user