From 18539b22409ae19898abdbf126dd80cfdfab8651 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Fri, 1 Aug 2014 10:47:10 +0200 Subject: [PATCH] Handle movement between editor lines with tabs. --- editor/command.c++ | 36 ++++++++++++++++++++++-------------- editor/display.c++ | 42 ++++++++++++++++++++++++++++++++++++++++++ editor/display.h++ | 8 ++++++++ 3 files changed, 72 insertions(+), 14 deletions(-) diff --git a/editor/command.c++ b/editor/command.c++ index 3f8ddc90..560a2736 100644 --- a/editor/command.c++ +++ b/editor/command.c++ @@ -339,7 +339,7 @@ void editor_type_control_right(struct editor* editor) { struct line* line = &editor->lines[editor->cursor_row]; wchar_t wc = editor->cursor_column != line->used ? - line->data[editor->cursor_column] : ' '; + line->data[editor->cursor_column] : L' '; if ( (state == 0 && !iswspace(wc)) || (state == 1 && iswspace(wc)) ) { if ( ++state == 2 ) @@ -357,7 +357,7 @@ void editor_type_control_select_right(struct editor* editor) { struct line* line = &editor->lines[editor->select_row]; wchar_t wc = editor->select_column != line->used ? - line->data[editor->select_column] : ' '; + line->data[editor->select_column] : L' '; if ( (state == 0 && !iswspace(wc)) || (state == 1 && iswspace(wc)) ) { if ( ++state == 2 ) @@ -375,9 +375,11 @@ void editor_type_up(struct editor* editor) editor_cursor_column_set(editor, 0); return; } - size_t new_line_len = editor->lines[editor_cursor_row_dec(editor)].used; - if ( new_line_len < editor->cursor_column ) - editor_cursor_column_set(editor, new_line_len); + struct line* old_line = &editor->lines[editor->cursor_row]; + struct line* new_line = &editor->lines[editor_cursor_row_dec(editor)]; + size_t old_column = editor_display_column_of_line_offset(editor, old_line, editor->cursor_column); + size_t new_offset = editor_line_offset_of_display_column(editor, new_line, old_column); + editor_cursor_column_set(editor, new_offset); } void editor_type_select_up(struct editor* editor) @@ -387,9 +389,11 @@ void editor_type_select_up(struct editor* editor) editor_select_column_set(editor, 0); return; } - size_t new_line_len = editor->lines[editor_select_row_dec(editor)].used; - if ( new_line_len < editor->select_column ) - editor_select_column_set(editor, new_line_len); + struct line* old_line = &editor->lines[editor->select_row]; + struct line* new_line = &editor->lines[editor_select_row_dec(editor)]; + size_t old_column = editor_display_column_of_line_offset(editor, old_line, editor->select_column); + size_t new_offset = editor_line_offset_of_display_column(editor, new_line, old_column); + editor_select_column_set(editor, new_offset); } void editor_type_control_up(struct editor* editor) @@ -415,9 +419,11 @@ void editor_type_down(struct editor* editor) editor_cursor_column_set(editor, editor->lines[editor->cursor_row].used); return; } - size_t new_line_len = editor->lines[editor_cursor_row_inc(editor)].used; - if ( new_line_len < editor->cursor_column ) - editor_cursor_column_set(editor, new_line_len); + struct line* old_line = &editor->lines[editor->cursor_row]; + struct line* new_line = &editor->lines[editor_cursor_row_inc(editor)]; + size_t old_column = editor_display_column_of_line_offset(editor, old_line, editor->cursor_column); + size_t new_offset = editor_line_offset_of_display_column(editor, new_line, old_column); + editor_cursor_column_set(editor, new_offset); } void editor_type_select_down(struct editor* editor) @@ -427,9 +433,11 @@ void editor_type_select_down(struct editor* editor) editor_select_column_set(editor, editor->lines[editor->select_row].used); return; } - size_t new_line_len = editor->lines[editor_select_row_inc(editor)].used; - if ( new_line_len < editor->select_column ) - editor_select_column_set(editor, new_line_len); + struct line* old_line = &editor->lines[editor->select_row]; + struct line* new_line = &editor->lines[editor_select_row_inc(editor)]; + size_t old_column = editor_display_column_of_line_offset(editor, old_line, editor->select_column); + size_t new_offset = editor_line_offset_of_display_column(editor, new_line, old_column); + editor_select_column_set(editor, new_offset); } void editor_type_control_down(struct editor* editor) diff --git a/editor/display.c++ b/editor/display.c++ index 5b280b83..ef48c87a 100644 --- a/editor/display.c++ +++ b/editor/display.c++ @@ -33,6 +33,48 @@ #include "multibyte.h++" #include "terminal.h++" +size_t editor_display_column_of_line_offset(struct editor* editor, + const struct line* line, + size_t offset) +{ + if ( line->used < offset ) + offset = line->used; + return displayed_string_length(line->data, offset, editor->tabsize); +} + +size_t editor_line_offset_of_display_column(struct editor* editor, + const struct line* line, + size_t column) +{ + size_t current_column = 0; + for ( size_t offset = 0; offset < line->used; offset++ ) + { + if ( column <= current_column ) + return offset; + + wchar_t wc = line->data[offset]; + + if ( wc == L'\t' ) + { + size_t old_column = current_column; + do current_column++; + while ( current_column % editor->tabsize != 0 ); + if ( column <= current_column ) + { + size_t dist_to_old = column - old_column; + size_t dist_to_cur = current_column - column; + if ( dist_to_old < dist_to_cur ) + return offset; + return offset + 1; + } + continue; + } + + current_column++; + } + return line->used; +} + size_t displayed_string_length(const wchar_t* str, size_t len, size_t tabsize) { size_t ret_len = 0; diff --git a/editor/display.h++ b/editor/display.h++ index 3d903eb8..6ad6c9d3 100644 --- a/editor/display.h++ +++ b/editor/display.h++ @@ -27,6 +27,7 @@ #include struct editor; +struct line; struct terminal_state; struct display_char @@ -35,6 +36,13 @@ struct display_char uint8_t color; }; +size_t editor_display_column_of_line_offset(struct editor* editor, + const struct line* line, + size_t offset); +size_t editor_line_offset_of_display_column(struct editor* editor, + const struct line* line, + size_t column); + size_t displayed_string_length(const wchar_t* str, size_t len, size_t tabsize); struct display_char* expand_tabs(const wchar_t* str, size_t len, uint8_t* colors, size_t colors_len, size_t* ret_len_ptr,