Просмотр исходного кода

fix(renderer): resolve GTK crash and TUI cursor glitch

Fixed GTK renderer crash by adding bounds check before completion substring extraction. Fixed TUI minibuffer cursor position by explicitly setting it after rendering content.
Bernardo Magri 1 месяц назад
Родитель
Сommit
2c6e725dda
2 измененных файлов с 36 добавлено и 29 удалено
  1. 32 29
      src/gtk_renderer.cpp
  2. 4 0
      src/tui_editor.cpp

+ 32 - 29
src/gtk_renderer.cpp

@@ -522,36 +522,39 @@ void GtkRenderer::render_minibuffer(const Cairo::RefPtr<Cairo::Context>& cr, int
         // Render completion overlay if applicable
         auto current_completion = core_.minibuffer_manager().get_current_completion();
         if (current_completion && input_part != *current_completion) {
-            std::string completion_suffix = current_completion->substr(input_part.length());
-            if (!completion_suffix.empty()) {
-                // Calculate width of existing text to position suffix
-                Pango::Rectangle ink_rect, logical_rect;
-                layout->get_pixel_extents(ink_rect, logical_rect);
-                double text_width = logical_rect.get_width();
-
-                auto completion_layout = Pango::Layout::create(main_drawing_area_.get_pango_context());
-                completion_layout->set_font_description(font_desc_);
-                completion_layout->set_text(completion_suffix); // Only draw suffix
-                
-                Pango::AttrList completion_attr_list;
-                if (auto face = theme->get_face("minibuffer-completion")) {
-                    apply_face_attributes(completion_attr_list, *face, 0, static_cast<int>(completion_suffix.length()));
-                } else {
-                    // Fallback: dimmed foreground
-                    Color dim_fg = fg;
-                    dim_fg.r = static_cast<unsigned char>(dim_fg.r * 0.7);
-                    dim_fg.g = static_cast<unsigned char>(dim_fg.g * 0.7);
-                    dim_fg.b = static_cast<unsigned char>(dim_fg.b * 0.7);
-                    auto attr = Pango::Attribute::create_attr_foreground(dim_fg.r * 257, dim_fg.g * 257, dim_fg.b * 257);
-                    attr.set_start_index(0);
-                    attr.set_end_index(static_cast<int>(completion_suffix.length()));
-                    completion_attr_list.insert(attr);
-                }
-                completion_layout->set_attributes(completion_attr_list);
+            // Safety check: ensure input_part length is valid for substring extraction
+            if (input_part.length() <= current_completion->length()) {
+                std::string completion_suffix = current_completion->substr(input_part.length());
+                if (!completion_suffix.empty()) {
+                    // Calculate width of existing text to position suffix
+                    Pango::Rectangle ink_rect, logical_rect;
+                    layout->get_pixel_extents(ink_rect, logical_rect);
+                    double text_width = logical_rect.get_width();
+
+                    auto completion_layout = Pango::Layout::create(main_drawing_area_.get_pango_context());
+                    completion_layout->set_font_description(font_desc_);
+                    completion_layout->set_text(completion_suffix); // Only draw suffix
+                    
+                    Pango::AttrList completion_attr_list;
+                    if (auto face = theme->get_face("minibuffer-completion")) {
+                        apply_face_attributes(completion_attr_list, *face, 0, static_cast<int>(completion_suffix.length()));
+                    } else {
+                        // Fallback: dimmed foreground
+                        Color dim_fg = fg;
+                        dim_fg.r = static_cast<unsigned char>(dim_fg.r * 0.7);
+                        dim_fg.g = static_cast<unsigned char>(dim_fg.g * 0.7);
+                        dim_fg.b = static_cast<unsigned char>(dim_fg.b * 0.7);
+                        auto attr = Pango::Attribute::create_attr_foreground(dim_fg.r * 257, dim_fg.g * 257, dim_fg.b * 257);
+                        attr.set_start_index(0);
+                        attr.set_end_index(static_cast<int>(completion_suffix.length()));
+                        completion_attr_list.insert(attr);
+                    }
+                    completion_layout->set_attributes(completion_attr_list);
 
-                cr->set_source_rgb(fg.r / 255.0, fg.g / 255.0, fg.b / 255.0);
-                cr->move_to(minibuffer_x + text_width, minibuffer_y); // Position after text
-                completion_layout->show_in_cairo_context(cr);
+                    cr->set_source_rgb(fg.r / 255.0, fg.g / 255.0, fg.b / 255.0);
+                    cr->move_to(minibuffer_x + text_width, minibuffer_y); // Position after text
+                    completion_layout->show_in_cairo_context(cr);
+                }
             }
         }
     }

+ 4 - 0
src/tui_editor.cpp

@@ -707,6 +707,10 @@ void TuiEditor::render_message_line() {
             mvprintw(msg_y - 1, 0, "%s", completion_display.c_str());
         }
 
+        // Explicitly place cursor at the correct position in minibuffer
+        // prompt_part is handled by get_prompt(), cursor_position is relative to input_buffer
+        move(msg_y, prompt_part.length() + core_->minibuffer_manager().get_cursor_position());
+
     } else if (!message_line_.empty()) {
         // Display transient message
         mvprintw(msg_y, 0, "%s", message_line_.c_str());