feat(tree-sitter, views): initialize AST on focus and emit source view creation event
- Add set_ast helper to centralize Tree-sitter parsing logic - Parse and attach AST on FocusedViewEvent and TextChangedEvent - Request file from buffer on view focus before parsing - Fix parser guard condition in get_parser (handle missing language properly) - Emit CreatedSourceViewEvent when a new source view is added - Register CreatedSourceViewEvent in DTO exports - Update TODO: - Remove completed collapsible code blocks task - Add fix note for code block icon desync issue chore: - Add scaffolding for code_fold UI plugin - Add created_source_view_event DTO
This commit is contained in:
93
plugins/code/ui/code_fold/gutter_renderer.py
Normal file
93
plugins/code/ui/code_fold/gutter_renderer.py
Normal file
@@ -0,0 +1,93 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version("Gtk", "3.0")
|
||||
gi.require_version("GtkSource", "4")
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
from .folding_actions import collapse_range, expand_range
|
||||
|
||||
|
||||
|
||||
def handle_collapse(view, fold):
|
||||
collapse_range(view, fold)
|
||||
|
||||
for inner in view.fold_starts:
|
||||
if fold["start_line"] < inner["start_line"] <= fold["end_line"]:
|
||||
view.fold_states[inner["id"]] = False
|
||||
|
||||
def handle_expand(view, fold):
|
||||
expand_range(view, fold)
|
||||
|
||||
def handle_block_toggle(collapsed, view, fold):
|
||||
if not collapsed:
|
||||
handle_collapse(view, fold)
|
||||
else:
|
||||
handle_expand(view, fold)
|
||||
|
||||
|
||||
def on_query_data(renderer, start_iter, end_iter, state, view):
|
||||
line = start_iter.get_line()
|
||||
|
||||
if not line in view.fold_start_set:
|
||||
renderer.set_text("", -1)
|
||||
return
|
||||
|
||||
fold = next((f for f in view.fold_starts if f["start_line"] == line), None)
|
||||
collapsed = fold and view.fold_states.get(fold["id"], False)
|
||||
|
||||
renderer.set_text( "▶" if collapsed else "▼", -1 )
|
||||
|
||||
def on_click(view, event, renderer):
|
||||
if not event.button == 1: return False
|
||||
window = view.get_window(Gtk.TextWindowType.LEFT)
|
||||
if not event.window == window: return False
|
||||
|
||||
x, y = view.window_to_buffer_coords(
|
||||
Gtk.TextWindowType.LEFT, int(event.x), int(event.y)
|
||||
)
|
||||
|
||||
_, iter_ = view.get_iter_at_location(x, y)
|
||||
line = iter_.get_line()
|
||||
|
||||
if line not in view.fold_start_set: return False
|
||||
|
||||
for fold in view.fold_starts:
|
||||
if not fold["start_line"] == line: continue
|
||||
|
||||
collapsed = view.fold_states.get(fold["id"], False)
|
||||
view.fold_states[fold["id"]] = not collapsed
|
||||
|
||||
handle_block_toggle(collapsed, view, fold)
|
||||
|
||||
renderer.queue_draw()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def setup_gutter(view):
|
||||
gutter = view.get_gutter(Gtk.TextWindowType.LEFT)
|
||||
buffer = view.get_buffer()
|
||||
|
||||
if not buffer.get_tag_table().lookup("invisible"):
|
||||
tag = buffer.create_tag("invisible")
|
||||
tag.set_property("invisible", True)
|
||||
|
||||
view.fold_starts = []
|
||||
view.fold_start_set = set()
|
||||
view.fold_states = {}
|
||||
|
||||
renderer = GtkSource.GutterRendererText()
|
||||
renderer.set_size(12)
|
||||
renderer.set_padding(2, -1)
|
||||
|
||||
renderer.query_data_id = renderer.connect("query-data", on_query_data, view)
|
||||
view.collapse_click_id = view.connect("button-press-event", on_click, renderer)
|
||||
|
||||
gutter.insert(renderer, 0)
|
||||
view.fold_renderer = renderer
|
||||
Reference in New Issue
Block a user