|
@@ -37,16 +37,9 @@ private:
|
|
|
std::string message_line_;
|
|
std::string message_line_;
|
|
|
int height_ = 0, width_ = 0;
|
|
int height_ = 0, width_ = 0;
|
|
|
|
|
|
|
|
- // Meta key handling
|
|
|
|
|
- bool waiting_for_meta_ = false;
|
|
|
|
|
- std::chrono::steady_clock::time_point meta_time_;
|
|
|
|
|
- static constexpr auto META_TIMEOUT = std::chrono::milliseconds(100);
|
|
|
|
|
-
|
|
|
|
|
// Private helper method declarations
|
|
// Private helper method declarations
|
|
|
std::string resolve_key(int ch);
|
|
std::string resolve_key(int ch);
|
|
|
- bool handle_input(int ch); // This will be updated
|
|
|
|
|
- bool process_key(const std::string& key_name);
|
|
|
|
|
- int get_attributes_for_face(const std::string& face_name);
|
|
|
|
|
|
|
+ bool handle_input(int ch);
|
|
|
void render();
|
|
void render();
|
|
|
void render_layout_node(std::shared_ptr<LayoutNode> node, int x, int y, int width, int height);
|
|
void render_layout_node(std::shared_ptr<LayoutNode> node, int x, int y, int width, int height);
|
|
|
void render_window(std::shared_ptr<Window> window, int x, int y, int width, int height);
|
|
void render_window(std::shared_ptr<Window> window, int x, int y, int width, int height);
|
|
@@ -160,18 +153,11 @@ void TuiEditor::handle_editor_event(EditorEvent event) {
|
|
|
core_->minibuffer_manager().activate_minibuffer(
|
|
core_->minibuffer_manager().activate_minibuffer(
|
|
|
MinibufferMode::BufferName, "Kill buffer: ",
|
|
MinibufferMode::BufferName, "Kill buffer: ",
|
|
|
[this](const std::string& input) {
|
|
[this](const std::string& input) {
|
|
|
- auto buf = core_->get_buffer_by_name(input);
|
|
|
|
|
- if (buf && buf->is_modified()) {
|
|
|
|
|
- // Enter a confirmation sub-mode
|
|
|
|
|
- mode_ = Mode::ConfirmKill; // Temporarily use local mode for confirmation
|
|
|
|
|
- command_buffer_ = input; // Store buffer name for confirmation
|
|
|
|
|
- core_->set_message("Buffer modified! Kill anyway? (y/n)");
|
|
|
|
|
|
|
+ // MinibufferManager should handle confirmation for modified buffers
|
|
|
|
|
+ if (core_->close_buffer(input)) {
|
|
|
|
|
+ core_->set_message("Closed buffer: " + input);
|
|
|
} else {
|
|
} else {
|
|
|
- if (core_->close_buffer(input)) {
|
|
|
|
|
- core_->set_message("Closed buffer: " + input);
|
|
|
|
|
- } else {
|
|
|
|
|
- core_->set_message("Failed to close buffer: " + input);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ core_->set_message("Failed to close buffer: " + input);
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
[this]() { core_->set_message("Cancelled"); }
|
|
[this]() { core_->set_message("Cancelled"); }
|
|
@@ -235,95 +221,26 @@ std::string TuiEditor::resolve_key(int ch) {
|
|
|
|
|
|
|
|
|
|
|
|
|
bool TuiEditor::handle_input(int ch) {
|
|
bool TuiEditor::handle_input(int ch) {
|
|
|
- // Handle confirmation mode - this remains local to TuiEditor for now
|
|
|
|
|
- if (core_->minibuffer_manager().get_current_mode() == MinibufferMode::None && mode_ == Mode::ConfirmKill) {
|
|
|
|
|
- if (ch == 'y' || ch == 'Y') {
|
|
|
|
|
- if (core_->close_buffer(command_buffer_)) {
|
|
|
|
|
- core_->set_message("Closed modified buffer: " + command_buffer_);
|
|
|
|
|
- } else {
|
|
|
|
|
- core_->set_message("Failed to close buffer");
|
|
|
|
|
- }
|
|
|
|
|
- mode_ = Mode::Normal;
|
|
|
|
|
- command_buffer_.clear();
|
|
|
|
|
- } else if (ch == 'n' || ch == 'N' || ch == 27) { // n or ESC
|
|
|
|
|
- mode_ = Mode::Normal;
|
|
|
|
|
- core_->set_message("Cancelled kill buffer");
|
|
|
|
|
- command_buffer_.clear();
|
|
|
|
|
- }
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Resolve key name, including Meta combinations
|
|
|
|
|
- std::string key_name;
|
|
|
|
|
-
|
|
|
|
|
- // Check for expired meta key before processing current input
|
|
|
|
|
- if (waiting_for_meta_) {
|
|
|
|
|
- auto now = std::chrono::steady_clock::now();
|
|
|
|
|
- if (now - meta_time_ > META_TIMEOUT) {
|
|
|
|
|
- debug_log << "Meta timeout, treating ESC as Escape key" << std::endl;
|
|
|
|
|
- waiting_for_meta_ = false;
|
|
|
|
|
- // Process the ESC as a normal Escape key by pushing it back
|
|
|
|
|
- // This is a bit hacky for ncurses, cleaner would be to simulate a key event
|
|
|
|
|
- // For now, let's just make the original ESC be processed normally in next loop
|
|
|
|
|
- key_name = "Escape"; // Treat previous ESC as an Escape key
|
|
|
|
|
- if (core_->lua_api()->execute_key_binding(key_name)) {
|
|
|
|
|
- core_->record_key_sequence(key_name);
|
|
|
|
|
- return true; // Consume the "timed out ESC"
|
|
|
|
|
- }
|
|
|
|
|
- core_->set_message("Key: " + key_name);
|
|
|
|
|
- return false; // Not consumed by keybinding, so UI should re-evaluate
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (ch == 27 && !waiting_for_meta_ && !core_->minibuffer_manager().is_active()) { // ESC
|
|
|
|
|
- waiting_for_meta_ = true;
|
|
|
|
|
- meta_time_ = std::chrono::steady_clock::now();
|
|
|
|
|
- debug_log << "ESC received, waiting for meta key..." << std::endl;
|
|
|
|
|
- return true; // Consume ESC, wait for next key
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // If we're waiting for a meta key and got one, combine them
|
|
|
|
|
- if (waiting_for_meta_) {
|
|
|
|
|
- waiting_for_meta_ = false;
|
|
|
|
|
- std::string base_key = resolve_key(ch);
|
|
|
|
|
- if (base_key.empty()) {
|
|
|
|
|
- debug_log << "Empty base key after ESC, ignoring" << std::endl;
|
|
|
|
|
- // If the key after ESC is not recognized, treat ESC as a normal Escape key
|
|
|
|
|
- key_name = "Escape";
|
|
|
|
|
- } else {
|
|
|
|
|
- key_name = "M-" + base_key;
|
|
|
|
|
- }
|
|
|
|
|
- debug_log << "Meta sequence complete: " << key_name << std::endl;
|
|
|
|
|
- } else {
|
|
|
|
|
- key_name = resolve_key(ch);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // Resolve key name
|
|
|
|
|
+ std::string key_name = resolve_key(ch);
|
|
|
|
|
|
|
|
if (key_name.empty()) {
|
|
if (key_name.empty()) {
|
|
|
debug_log << "Empty key name, ignoring input" << std::endl;
|
|
debug_log << "Empty key name, ignoring input" << std::endl;
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Handle Minibuffer Input Logic
|
|
|
|
|
|
|
+ // Handle Minibuffer Input Logic first
|
|
|
if (core_->minibuffer_manager().is_active()) {
|
|
if (core_->minibuffer_manager().is_active()) {
|
|
|
- // Pass the key event to the MinibufferManager
|
|
|
|
|
return core_->minibuffer_manager().handle_key_event(key_name);
|
|
return core_->minibuffer_manager().handle_key_event(key_name);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Normal mode processing (pass to keybinding system)
|
|
// Normal mode processing (pass to keybinding system)
|
|
|
- return process_key(key_name);
|
|
|
|
|
|
|
+ return core_->keybinding_manager().process_key(Key::parse(key_name)) != KeyResult::Unbound;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-int TuiEditor::get_attributes_for_face(const std::string& face_name) {
|
|
|
|
|
- auto theme = core_->active_theme();
|
|
|
|
|
- if (!theme) return 0;
|
|
|
|
|
- return theme->get_face_attributes_ncurses(face_name);
|
|
|
|
|
-}
|
|
|
|
|
|
|
+// process_key is removed as keybinding_manager handles it
|
|
|
|
|
+
|
|
|
|
|
|
|
|
-int TuiEditor::get_attributes_for_face(const std::string& face_name) {
|
|
|
|
|
- auto theme = core_->active_theme();
|
|
|
|
|
- if (!theme) return 0;
|
|
|
|
|
- return theme->get_face_attributes_ncurses(face_name);
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
void TuiEditor::render() {
|
|
void TuiEditor::render() {
|
|
|
// Clear and update screen info
|
|
// Clear and update screen info
|
|
@@ -491,29 +408,29 @@ void TuiEditor::render_window(std::shared_ptr<Window> window, int x, int y, int
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Highlight ISearch match
|
|
|
|
|
- if (mode_ == Mode::ISearch && isearch_match_ && isearch_match_->start.line == buffer_line_idx) {
|
|
|
|
|
- size_t match_start = isearch_match_->start.column;
|
|
|
|
|
- size_t match_len = isearch_match_->end.column - match_start;
|
|
|
|
|
- if (match_start < line_text.size()) {
|
|
|
|
|
- size_t display_len = std::min(match_len, line_text.size() - match_start);
|
|
|
|
|
- std::string matched_text = line_text.substr(match_start, display_len);
|
|
|
|
|
|
|
+ // Highlight ISearch match - now handled by MinibufferManager
|
|
|
|
|
+ // if (mode_ == Mode::ISearch && isearch_match_ && isearch_match_->start.line == buffer_line_idx) {
|
|
|
|
|
+ // size_t match_start = isearch_match_->start.column;
|
|
|
|
|
+ // size_t match_len = isearch_match_->end.column - match_start;
|
|
|
|
|
+ // if (match_start < line_text.size()) {
|
|
|
|
|
+ // size_t display_len = std::min(match_len, line_text.size() - match_start);
|
|
|
|
|
+ // std::string matched_text = line_text.substr(match_start, display_len);
|
|
|
|
|
|
|
|
- int match_x = x + line_number_width + match_start;
|
|
|
|
|
- // Simple clipping check
|
|
|
|
|
- if (match_x < x + width) {
|
|
|
|
|
- int attrs = get_attributes_for_face(isearch_failed_ ? "isearch-fail" : "isearch");
|
|
|
|
|
- if (attrs == 0) attrs = A_REVERSE; // Fallback
|
|
|
|
|
|
|
+ // int match_x = x + line_number_width + match_start;
|
|
|
|
|
+ // // Simple clipping check
|
|
|
|
|
+ // if (match_x < x + width) {
|
|
|
|
|
+ // int attrs = get_attributes_for_face(isearch_failed_ ? "isearch-fail" : "isearch");
|
|
|
|
|
+ // if (attrs == 0) attrs = A_REVERSE; // Fallback
|
|
|
|
|
|
|
|
- attron(attrs);
|
|
|
|
|
- mvprintw(y + screen_y, match_x, "%s", matched_text.c_str());
|
|
|
|
|
- attroff(attrs);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // attron(attrs);
|
|
|
|
|
+ // mvprintw(y + screen_y, match_x, "%s", matched_text.c_str());
|
|
|
|
|
+ // attroff(attrs);
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
|
|
|
// Show cursor if this is the cursor line and this is the active window
|
|
// Show cursor if this is the cursor line and this is the active window
|
|
|
- if (buffer_line_idx == cursor.line && is_active && mode_ == Mode::Normal) {
|
|
|
|
|
|
|
+ if (buffer_line_idx == cursor.line && is_active) {
|
|
|
int cursor_screen_x = x + line_number_width + cursor.column;
|
|
int cursor_screen_x = x + line_number_width + cursor.column;
|
|
|
if (cursor_screen_x < x + width) {
|
|
if (cursor_screen_x < x + width) {
|
|
|
char cursor_char = ' ';
|
|
char cursor_char = ' ';
|