|
|
@@ -385,49 +385,61 @@ static bool is_word_char(char c) {
|
|
|
}
|
|
|
|
|
|
void EditorCore::move_forward_word() {
|
|
|
- auto& buf = active_window_->buffer();
|
|
|
- auto cursor = active_window_->cursor();
|
|
|
- const auto& line = buf.line(cursor.line);
|
|
|
+ auto new_pos = calculate_forward_word_pos(active_window_->cursor());
|
|
|
+ active_window_->set_cursor(new_pos);
|
|
|
+ emit_event(EditorEvent::CursorMoved);
|
|
|
+}
|
|
|
|
|
|
- // Skip current word if we're in one
|
|
|
- while (cursor.column < line.size() && is_word_char(line[cursor.column])) {
|
|
|
- cursor.column++;
|
|
|
- }
|
|
|
+void EditorCore::move_backward_word() {
|
|
|
+ auto new_pos = calculate_backward_word_pos(active_window_->cursor());
|
|
|
+ active_window_->set_cursor(new_pos);
|
|
|
+ emit_event(EditorEvent::CursorMoved);
|
|
|
+}
|
|
|
|
|
|
- // Skip whitespace and punctuation
|
|
|
+Position EditorCore::calculate_forward_word_pos(Position start_pos) {
|
|
|
+ auto& buf = active_window_->buffer();
|
|
|
+ auto cursor = start_pos;
|
|
|
+
|
|
|
+ // Check if we are at the end of buffer
|
|
|
+ if (cursor.line >= buf.line_count()) {
|
|
|
+ return cursor;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. Skip non-word chars (whitespace/punctuation)
|
|
|
while (true) {
|
|
|
- // Skip non-word chars on current line
|
|
|
+ const auto& line = buf.line(cursor.line);
|
|
|
+
|
|
|
while (cursor.column < line.size() && !is_word_char(line[cursor.column])) {
|
|
|
cursor.column++;
|
|
|
}
|
|
|
-
|
|
|
- // If we found a word char, we're done
|
|
|
+
|
|
|
+ // If we found a word char, we're done with step 1
|
|
|
if (cursor.column < line.size()) {
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Move to next line
|
|
|
if (cursor.line < buf.line_count() - 1) {
|
|
|
cursor.line++;
|
|
|
cursor.column = 0;
|
|
|
- const auto& new_line = buf.line(cursor.line);
|
|
|
- // Update line reference
|
|
|
- if (!new_line.empty()) {
|
|
|
- continue; // Check this new line
|
|
|
- }
|
|
|
} else {
|
|
|
// At end of buffer
|
|
|
- break;
|
|
|
+ return cursor;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- active_window_->set_cursor(cursor);
|
|
|
- emit_event(EditorEvent::CursorMoved);
|
|
|
+ // 2. Skip word chars
|
|
|
+ const auto& line = buf.line(cursor.line);
|
|
|
+ while (cursor.column < line.size() && is_word_char(line[cursor.column])) {
|
|
|
+ cursor.column++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return cursor;
|
|
|
}
|
|
|
|
|
|
-void EditorCore::move_backward_word() {
|
|
|
+Position EditorCore::calculate_backward_word_pos(Position start_pos) {
|
|
|
auto& buf = active_window_->buffer();
|
|
|
- auto cursor = active_window_->cursor();
|
|
|
+ auto cursor = start_pos;
|
|
|
|
|
|
// Skip whitespace and punctuation backwards
|
|
|
while (true) {
|
|
|
@@ -454,12 +466,8 @@ void EditorCore::move_backward_word() {
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
- // Otherwise continue skipping non-word chars
|
|
|
}
|
|
|
-
|
|
|
- active_window_->set_cursor(cursor);
|
|
|
- emit_event(EditorEvent::CursorMoved);
|
|
|
+ return cursor;
|
|
|
}
|
|
|
|
|
|
void EditorCore::page_up() {
|
|
|
@@ -660,6 +668,45 @@ void EditorCore::kill_region() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void EditorCore::kill_word() {
|
|
|
+ auto cursor = active_window_->cursor();
|
|
|
+ auto end_pos = calculate_forward_word_pos(cursor);
|
|
|
+
|
|
|
+ if (cursor == end_pos) return;
|
|
|
+
|
|
|
+ Range range = {cursor, end_pos};
|
|
|
+ auto& buf = active_window_->buffer();
|
|
|
+ std::string text = buf.get_text_in_range(range);
|
|
|
+
|
|
|
+ if (!text.empty()) {
|
|
|
+ kill_ring_.push(text);
|
|
|
+ buf.erase(range);
|
|
|
+ emit_event(EditorEvent::BufferModified);
|
|
|
+ std::cerr << "[DEBUG] Killed word: '" << text << "'" << std::endl;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void EditorCore::backward_kill_word() {
|
|
|
+ auto cursor = active_window_->cursor();
|
|
|
+ auto start_pos = calculate_backward_word_pos(cursor);
|
|
|
+
|
|
|
+ if (cursor == start_pos) return;
|
|
|
+
|
|
|
+ Range range = {start_pos, cursor};
|
|
|
+ auto& buf = active_window_->buffer();
|
|
|
+ std::string text = buf.get_text_in_range(range);
|
|
|
+
|
|
|
+ if (!text.empty()) {
|
|
|
+ kill_ring_.push(text);
|
|
|
+ buf.erase(range);
|
|
|
+ active_window_->set_cursor(start_pos);
|
|
|
+ emit_event(EditorEvent::BufferModified);
|
|
|
+ emit_event(EditorEvent::CursorMoved);
|
|
|
+ std::cerr << "[DEBUG] Backward killed word: '" << text << "'" << std::endl;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
void EditorCore::copy_region_as_kill() {
|
|
|
auto& buf = active_window_->buffer();
|
|
|
auto cursor = active_window_->cursor();
|