@@ -58,6 +58,7 @@ def __init__(self):
5858 self .CLASS_PATTERN = re .compile (r'^\s*class\s+(\w+)\s*[\(:]' )
5959 self .FUNCTION_PATTERN = re .compile (r'^\s*def\s+(\w+)\s*\(' )
6060 self .PROPERTY_PATTERN = re .compile (r'^\s*([\w]+)\s*:\s*[\w\[\]]+' )
61+ self .BLENDER_PROPERTY_PATTERN = re .compile (r'^\s*(\w+)\s*:\s*\w*Property\s*\(' )
6162 self .VARIABLE_PATTERN = re .compile (
6263 r'^\s*([A-Z_][A-Z0-9_]*|[a-zA-Z_]\w*)\s*=\s*' )
6364 self .CONSTANT_PATTERN = re .compile (r'^\s*([A-Z_][A-Z0-9_]*)\s*=' )
@@ -238,7 +239,12 @@ def _parse_line(self, line, line_num, indent, parent_type=None, full_line=""):
238239 'class' , 'function' } else 'function'
239240 return CodeItem (m .group (1 ), kind , line_num , indent )
240241
241- # Property parsing
242+ # Property parsing - Check for Blender properties first
243+ m = self .patterns .BLENDER_PROPERTY_PATTERN .match (line )
244+ if m :
245+ return CodeItem (m .group (1 ), 'property' , line_num , indent )
246+
247+ # Standard property parsing (type annotations)
242248 m = self .patterns .PROPERTY_PATTERN .match (line )
243249 if m and ':' in line and not line .startswith ('#' ) and '=' not in line :
244250 return CodeItem (m .group (1 ), 'property' , line_num , indent )
@@ -329,7 +335,6 @@ class CODE_MAP_OT_jump_to_line(Operator):
329335
330336 def invoke (self , context , event ):
331337 clipboard_helper = ClipboardHelper ()
332-
333338 if event .ctrl :
334339 if self .item_type == 'class' and self .item_bl_idname :
335340 clipboard_helper .copy_to_clipboard (self .item_bl_idname )
@@ -362,27 +367,63 @@ def _select_code_block(self, context):
362367 if not text :
363368 return
364369
370+ # Jump to the starting line
365371 bpy .ops .text .jump (line = self .line_number )
366372 bpy .ops .text .move (type = 'LINE_BEGIN' )
367373
368374 start_line_index = self .line_number - 1
369- end_line_index = min (self .item_end_line - 1 , len (text .lines ) - 1 )
370-
375+ end_line_index = self .item_end_line - 1 if self .item_end_line else start_line_index
376+
377+ # If no end line was provided, try to find the end of the block automatically
378+ if not self .item_end_line :
379+ start_line = text .lines [start_line_index ].body
380+ # Check for opening brackets
381+ if '{' in start_line or '[' in start_line :
382+ open_char = '{' if '{' in start_line else '['
383+ close_char = '}' if open_char == '{' else ']'
384+ open_count = start_line .count (open_char ) - start_line .count (close_char )
385+
386+ # Search forward for matching closing bracket
387+ end_line_index = start_line_index
388+ while end_line_index < len (text .lines ) and open_count > 0 :
389+ end_line_index += 1
390+ if end_line_index < len (text .lines ):
391+ line = text .lines [end_line_index ].body
392+ open_count += line .count (open_char ) - line .count (close_char )
393+
394+ # If we found a matching closing bracket, use that as the end
395+ if open_count == 0 and end_line_index < len (text .lines ):
396+ self .item_end_line = end_line_index + 1
397+ else :
398+ end_line_index = start_line_index
399+
400+ # Clamp the end line index to valid range
401+ end_line_index = min (end_line_index , len (text .lines ) - 1 )
402+
403+ # Find the actual last non-empty line in the block
404+ actual_end_line = end_line_index
405+ while actual_end_line > start_line_index :
406+ line_content = text .lines [actual_end_line ].body .strip ()
407+ if line_content : # Found non-empty line
408+ break
409+ actual_end_line -= 1
410+
411+ # Calculate selection columns
371412 if start_line_index < len (text .lines ):
372413 start_line_body = text .lines [start_line_index ].body
373414 start_column = len (start_line_body ) - len (start_line_body .lstrip ())
374415 else :
375416 start_column = 0
376417
377- end_column = len (text .lines [end_line_index ].body ) if end_line_index < len (
378- text .lines ) else 0
418+ end_column = len (text .lines [actual_end_line ].body ) if actual_end_line < len (text .lines ) else 0
379419
380- if self .line_number == self .item_end_line :
381- text .select_set (start_line_index , start_column , start_line_index , len (
382- text .lines [start_line_index ].body ))
420+ # Set the selection
421+ if start_line_index == actual_end_line :
422+ text .select_set (start_line_index , start_column ,
423+ start_line_index , len (text .lines [start_line_index ].body ))
383424 else :
384425 text .select_set (start_line_index , start_column ,
385- end_line_index , end_column )
426+ actual_end_line , end_column )
386427
387428 context .area .tag_redraw ()
388429
@@ -494,8 +535,7 @@ def draw_code_item(self, layout, item, level=0, nav_state=None, active_class=Non
494535
495536 # Icon + operator
496537 icon_name = 'constant' if item .item_type == 'constant' else item .item_type
497- icon = textify_icons .get_icon (icon_name )
498- icon_id = icon .icon_id if icon else 0
538+ icon_id = textify_icons .get_icon (icon_name ) or 0
499539 sub = row .row (align = True )
500540 sub .alignment = 'LEFT'
501541
@@ -582,8 +622,9 @@ def _draw_toggle_filter_row(layout, nav_data):
582622 "show_properties" , "show_variables" , "show_constants" ]
583623
584624 for prop , icon_name in zip (props , icons ):
585- icon = textify_icons .get_icon (icon_name )
586- icon_id = icon .icon_id if icon else 0
625+ icon_id = textify_icons .get_icon (icon_name )
626+ if icon_id is None :
627+ icon_id = 0
587628 row .prop (nav_data , prop , toggle = True , text = "" , icon_value = icon_id )
588629
589630
0 commit comments