diff --git a/src/core/BufferView.cc b/src/core/BufferView.cc index edc17d5..f4fd123 100644 --- a/src/core/BufferView.cc +++ b/src/core/BufferView.cc @@ -191,6 +191,15 @@ bool BufferView::cursor_move(CursorMovement which, uint32_t c, bool allow_eol) case CursorMovement::BACK_ON_TO_CHAR: moved = m_iterator->go_backward_in_line_on_to_char(c); break; + case CursorMovement::TOP_OF_SCREEN: + moved = cursor_move_to_screen_position(0, effective_scroll_offset(), allow_eol); + break; + case CursorMovement::MIDDLE_OF_SCREEN: + moved = cursor_move_to_screen_position(0, m_height / 2, allow_eol); + break; + case CursorMovement::BOTTOM_OF_SCREEN: + moved = cursor_move_to_screen_position(0, m_height - effective_scroll_offset() - 1, allow_eol); + break; } if (moved) { @@ -223,6 +232,12 @@ bool BufferView::cursor_move(CursorMovement which, uint32_t c, bool allow_eol) case CursorMovement::LAST_LINE: m_cursor_screen_row = m_height - 1; break; + case CursorMovement::TOP_OF_SCREEN: + case CursorMovement::MIDDLE_OF_SCREEN: + case CursorMovement::BOTTOM_OF_SCREEN: + m_target_virtual_column = 0; + m_target_screen_column = 0; + break; } } @@ -266,6 +281,41 @@ bool BufferView::cursor_move_to_line(size_t target_line) return false; } +bool BufferView::cursor_move_to_screen_position(int x, int y, bool allow_eol) +{ + bool moved = false; + for (const LineDescriptor & screen_line : m_lines) + { + if ((y >= screen_line.row_offset) && + (y < (screen_line.row_offset + screen_line.n_rows))) + { + Buffer::Iterator scan_iter = *m_iterator; + bool set = false; + int desired_row_offset = y - screen_line.row_offset; + for (auto it = horiz_iter(screen_line.line); it.is_valid(); it++) + { + if (it.row_offset() == desired_row_offset) + { + if ((!set) || + ((it.screen_column() <= x) && (allow_eol || (!it.is_eol())))) + { + scan_iter = *it.iterator(); + set = true; + } + } + } + if (scan_iter != *m_iterator) + { + *m_iterator = scan_iter; + moved = true; + determine_new_cursor_screen_row(); + } + break; + } + } + return moved; +} + void BufferView::scroll_view_up(int n_lines, bool allow_eol) { int orig_cursor_screen_row = m_cursor_screen_row; diff --git a/src/core/BufferView.h b/src/core/BufferView.h index 1a71fcd..ea01835 100644 --- a/src/core/BufferView.h +++ b/src/core/BufferView.h @@ -32,6 +32,9 @@ public: FORWARD_ON_TO_CHAR, BACK_UP_TO_CHAR, BACK_ON_TO_CHAR, + TOP_OF_SCREEN, + MIDDLE_OF_SCREEN, + BOTTOM_OF_SCREEN, }; class Iterator @@ -84,6 +87,7 @@ public: } bool cursor_move(CursorMovement which, uint32_t c, bool allow_eol); bool cursor_move_to_line(size_t line); + bool cursor_move_to_screen_position(int x, int y, bool allow_eol); int cursor_screen_row() const { return m_cursor_screen_row; } int cursor_screen_column() const { return m_cursor_screen_column; } int cursor_virtual_column() const { return m_cursor_virtual_column; } @@ -112,6 +116,7 @@ protected: int m_cursor_screen_row; int m_cursor_screen_column; int m_cursor_virtual_column; + /** Holds the screen row offset of the cursor in the current line */ int m_cursor_row_offset; int m_rows_in_cursor_line; int m_target_screen_column; diff --git a/src/core/Command.h b/src/core/Command.h index 71907c6..1aba69c 100644 --- a/src/core/Command.h +++ b/src/core/Command.h @@ -42,6 +42,9 @@ public: GO_RIGHT, GO_START_OF_LINE, GO_END_OF_LINE, + GO_TOP_OF_SCREEN, + GO_MIDDLE_OF_SCREEN, + GO_BOTTOM_OF_SCREEN, NEXT, PREV, SCROLL_WINDOW_UP_ONE_LINE, diff --git a/src/core/DefaultCommandMap.cc b/src/core/DefaultCommandMap.cc index a64e53d..55b7070 100644 --- a/src/core/DefaultCommandMap.cc +++ b/src/core/DefaultCommandMap.cc @@ -47,9 +47,11 @@ static void build_command_mode() dcm->add("gg", Command::GO_TO_LINE, nullptr, false); dcm->add("G", Command::GO_TO_LAST_LINE, nullptr, false); dcm->add("h", Command::GO_LEFT, nullptr, false); + dcm->add("H", Command::GO_TOP_OF_SCREEN, nullptr, false); dcm->add("j", Command::GO_DOWN, nullptr, false); dcm->add("k", Command::GO_UP, nullptr, false); dcm->add("l", Command::GO_RIGHT, nullptr, false); + dcm->add("L", Command::GO_BOTTOM_OF_SCREEN, nullptr, false); dcm->add(":", Command::ENTER_COMMAND_LINE_PROMPT, nullptr, false); dcm->add("x", Command::DELETE_CHAR, nullptr, false); @@ -59,6 +61,7 @@ static void build_command_mode() dcm->add({JES_KEY_MODS_CTRL + 'b'}, Command::SCROLL_WINDOW_UP_WHOLE_SCREEN, nullptr, false); dcm->add("n", Command::NEXT, nullptr, false); dcm->add("N", Command::PREV, nullptr, false); + dcm->add("M", Command::GO_MIDDLE_OF_SCREEN, nullptr, false); dcm->add({JES_KEY_HOME}, Command::GO_START_OF_LINE, nullptr, false); dcm->add({JES_KEY_MODS_CTRL + JES_KEY_HOME}, Command::GO_START_OF_FILE, nullptr, false); diff --git a/src/gui/Window.cc b/src/gui/Window.cc index a7574f5..13bee83 100644 --- a/src/gui/Window.cc +++ b/src/gui/Window.cc @@ -418,6 +418,15 @@ void Window::execute_command(const Command & command) case Command::GO_END_OF_LINE: m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::EOL, 0u); break; + case Command::GO_TOP_OF_SCREEN: + m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::TOP_OF_SCREEN, 0u); + break; + case Command::GO_MIDDLE_OF_SCREEN: + m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::MIDDLE_OF_SCREEN, 0u); + break; + case Command::GO_BOTTOM_OF_SCREEN: + m_focused_buffer_pane->cursor_move(BufferPane::CursorMovement::BOTTOM_OF_SCREEN, 0u); + break; case Command::NEXT: break; case Command::PREV: