diff --git a/src/client.cc b/src/client.cc index 3ce8436d..d41a1ba9 100644 --- a/src/client.cc +++ b/src/client.cc @@ -246,6 +246,9 @@ void Client::redraw_ifn() if (m_ui_pending & StatusLine) m_ui->draw_status(m_status_line, m_mode_line, get_face("StatusLine")); + auto cursor = m_input_handler.get_cursor_info(); + m_ui->set_cursor(cursor.first, cursor.second); + m_ui->refresh(m_ui_pending | Refresh); m_ui_pending = 0; } diff --git a/src/input_handler.cc b/src/input_handler.cc index 4edce81c..b378b871 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -37,6 +37,12 @@ public: virtual KeymapMode keymap_mode() const = 0; + virtual std::pair get_cursor_info() const + { + DisplayCoord coord = context().window().display_position(context().selections().main().cursor()); + return {CursorMode::Buffer, coord}; + } + using Insertion = InputHandler::Insertion; Insertion& last_insert() { return m_input_handler.m_last_insert; } @@ -467,6 +473,11 @@ public: const String& line() const { return m_line; } CharCount cursor_pos() const { return m_cursor_pos; } + ColumnCount cursor_display_column() const + { + return m_line.substr(m_display_pos, m_cursor_pos).column_length(); + } + DisplayLine build_display_line(ColumnCount in_width) { auto cleanup = [](StringView str) { @@ -873,6 +884,12 @@ public: KeymapMode keymap_mode() const override { return KeymapMode::Prompt; } + std::pair get_cursor_info() const override + { + DisplayCoord coord{0_line, m_prompt.column_length() + m_line_editor.cursor_display_column()}; + return { CursorMode::Prompt, coord }; + } + private: void refresh_completions(CompletionFlags flags) { @@ -1521,6 +1538,11 @@ DisplayLine InputHandler::mode_line() const return current_mode().mode_line(); } +std::pair InputHandler::get_cursor_info() const +{ + return current_mode().get_cursor_info(); +} + bool show_auto_info_ifn(StringView title, StringView info, AutoInfo mask, const Context& context) { if (not (context.options()["autoinfo"].get() & mask) or diff --git a/src/input_handler.hh b/src/input_handler.hh index 2962ac12..17c655d9 100644 --- a/src/input_handler.hh +++ b/src/input_handler.hh @@ -43,6 +43,7 @@ using KeyCallback = std::function; class InputMode; enum class InsertMode : unsigned; enum class KeymapMode : char; +enum class CursorMode; class InputHandler : public SafeCountable { @@ -91,6 +92,8 @@ public: DisplayLine mode_line() const; + std::pair get_cursor_info() const; + // Force an input handler into normal mode temporarily struct ScopedForceNormal { diff --git a/src/json_ui.cc b/src/json_ui.cc index 8a436513..e907be24 100644 --- a/src/json_ui.cc +++ b/src/json_ui.cc @@ -135,6 +135,16 @@ String to_json(InfoStyle style) return ""; } +String to_json(CursorMode mode) +{ + switch (mode) + { + case CursorMode::Prompt: return R"("prompt")"; + case CursorMode::Buffer: return R"("buffer")"; + } + return ""; +} + String concat() { return ""; @@ -209,6 +219,11 @@ void JsonUI::info_hide() rpc_call("info_hide"); } +void JsonUI::set_cursor(CursorMode mode, DisplayCoord coord) +{ + rpc_call("set_cursor", mode, coord); +} + void JsonUI::refresh(bool force) { rpc_call("refresh", force); diff --git a/src/json_ui.hh b/src/json_ui.hh index 1b35538f..ad887561 100644 --- a/src/json_ui.hh +++ b/src/json_ui.hh @@ -38,6 +38,8 @@ public: InfoStyle style) override; void info_hide() override; + void set_cursor(CursorMode mode, DisplayCoord coord) override; + void refresh(bool force) override; DisplayCoord dimensions() override; diff --git a/src/main.cc b/src/main.cc index b8f27622..24f1ae4b 100644 --- a/src/main.cc +++ b/src/main.cc @@ -356,6 +356,7 @@ std::unique_ptr make_ui(UIType ui_type) void draw(const DisplayBuffer&, const Face&, const Face&) override {} void draw_status(const DisplayLine&, const DisplayLine&, const Face&) override {} DisplayCoord dimensions() override { return {24,80}; } + void set_cursor(CursorMode, DisplayCoord) override {} void refresh(bool) override {} void set_on_key(OnKeyCallback) override {} void set_ui_options(const Options&) override {} diff --git a/src/ncurses_ui.cc b/src/ncurses_ui.cc index 991cb79b..2e2cb5ad 100644 --- a/src/ncurses_ui.cc +++ b/src/ncurses_ui.cc @@ -312,11 +312,25 @@ void NCursesUI::redraw() { pnoutrefresh(m_window, 0, 0, 0, 0, (int)m_dimensions.line + 1, (int)m_dimensions.column); + m_menu.refresh(); m_info.refresh(); + + if (m_cursor.mode == CursorMode::Prompt) + wmove(newscr, m_status_on_top ? 0 : (int)m_dimensions.line + 1, + (int)m_cursor.coord.column); + else + wmove(newscr, (int)m_cursor.coord.line + (m_status_on_top ? 1 : 0), + (int)m_cursor.coord.column); + doupdate(); } +void NCursesUI::set_cursor(CursorMode mode, DisplayCoord coord) +{ + m_cursor = Cursor{ mode, coord }; +} + void NCursesUI::refresh(bool force) { if (force) diff --git a/src/ncurses_ui.hh b/src/ncurses_ui.hh index 02270a8d..35889193 100644 --- a/src/ncurses_ui.hh +++ b/src/ncurses_ui.hh @@ -43,8 +43,9 @@ public: InfoStyle style) override; void info_hide() override; - void refresh(bool force) override; + void set_cursor(CursorMode mode, DisplayCoord coord) override; + void refresh(bool force) override; DisplayCoord dimensions() override; void set_on_key(OnKeyCallback callback) override; @@ -121,6 +122,12 @@ private: InfoStyle style; } m_info; + struct Cursor + { + CursorMode mode; + DisplayCoord coord; + } m_cursor; + FDWatcher m_stdin_watcher; OnKeyCallback m_on_key; diff --git a/src/remote.cc b/src/remote.cc index 721c4759..bb577aa2 100644 --- a/src/remote.cc +++ b/src/remote.cc @@ -35,6 +35,7 @@ enum class MessageType : char InfoHide, Draw, DrawStatus, + SetCursor, Refresh, SetOptions, Key @@ -335,6 +336,8 @@ public: const DisplayLine& mode_line, const Face& default_face) override; + void set_cursor(CursorMode mode, DisplayCoord coord) override; + void refresh(bool force) override; DisplayCoord dimensions() override { return m_dimensions; } @@ -483,6 +486,14 @@ void RemoteUI::draw_status(const DisplayLine& status_line, m_socket_watcher.events() |= FdEvents::Write; } +void RemoteUI::set_cursor(CursorMode mode, DisplayCoord coord) +{ + MsgWriter msg{m_send_buffer, MessageType::SetCursor}; + msg.write(mode); + msg.write(coord); + m_socket_watcher.events() |= FdEvents::Write; +} + void RemoteUI::refresh(bool force) { MsgWriter msg{m_send_buffer, MessageType::Refresh}; @@ -611,6 +622,13 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr&& m_ui->draw_status(status_line, mode_line, default_face); break; } + case MessageType::SetCursor: + { + auto mode = reader.read(); + auto coord = reader.read(); + m_ui->set_cursor(mode, coord); + break; + } case MessageType::Refresh: m_ui->refresh(reader.read()); break; diff --git a/src/user_interface.hh b/src/user_interface.hh index b202f188..d8139336 100644 --- a/src/user_interface.hh +++ b/src/user_interface.hh @@ -34,6 +34,12 @@ enum class InfoStyle enum class EventMode; +enum class CursorMode +{ + Prompt, + Buffer, +}; + using OnKeyCallback = std::function; class UserInterface @@ -62,6 +68,8 @@ public: virtual DisplayCoord dimensions() = 0; + virtual void set_cursor(CursorMode mode, DisplayCoord coord) = 0; + virtual void refresh(bool force) = 0; virtual void set_on_key(OnKeyCallback callback) = 0;