#pragma once #include #include #include #include namespace Nimbin { class VimBuffer { public: enum class Mode : uint8_t { Normal, Insert, Command }; enum class Signal : uint8_t { None, Exit, Help, Write, WriteQuit, QuitDiscard }; void key_char (char c); void key_enter (); void key_backspace(); void key_escape (); void key_tab (); void key_redo (); // ctrl+r void load (const std::vector& src); Signal take_Signal(); void mark_Saved (); // Shoot-merge: splice a whole word into line `row` at character `col`, // adding surrounding spaces so it tokenizes back out as its own token. // `col` is expected pre-snapped to an inter-token gap by the caller // (Text::Handler::attach). Clamps row/col, bumps version, marks dirty. void insert_Word_At(int row, int col, const std::string& word, bool new_line = false); bool is_Empty() const { return _lines.size() == 1 && _lines[0].empty(); } const std::vector& get_Lines () const { return _lines; } int get_Row () const { return _row; } int get_Col () const { return _col; } Mode get_Mode () const { return _mode; } unsigned get_Version () const { return _version; } const std::string& get_Cmdline () const { return _cmd; } const std::string& get_Status () const { return _status; } // Pending operator + count for the bottom-right "showcmd" area, e.g. "d", // "2d", "c", "g", or a bare count "3". Empties as soon as the command // completes (both _pending and _count are cleared on dispatch). std::string get_ShowCmd() const { std::string s; if (_count > 0) s += std::to_string(_count); s += _pending; return s; } void start_Insert() { _mode = Mode::Insert; _col = 0; touch(); } void enter_Insert() { _mode = Mode::Insert; clamp_Col(); touch(); } // insert at current cursor void set_Cursor(int row, int col) { if (_lines.empty()) { _row = 0; _col = 0; return; } _row = (row < 0) ? 0 : (row >= (int)_lines.size() ? (int)_lines.size() - 1 : row); _col = (col < 0) ? 0 : col; clamp_Col(); touch(); } private: struct Snapshot { std::vector lines; int row; int col; }; std::vector _undo; std::vector _redo; std::vector _saved; std::vector _lines{ "" }; Mode _mode = Mode::Normal; Signal _sig = Signal::None; std::string _pending; std::string _cmd; std::string _status; std::string _register; unsigned _version = 0; int _row = 0, _col = 0; int _count = 0; bool _dirty = false; bool _reg_linewise = false; void touch (); void clamp_Col (); void normal_Key (char c); void insert_Char (char c); void split_Line (); void backspace_Insert(); void delete_Chars (int n); void delete_Lines (int n); void open_Below (); void open_Above (); void run_Command (); void cancel_Command (); // word motion (whitespace-delimited, matching the tokenizer) int word_EndCol (int times) const; // exclusive end of word(s) from _col (for cw) int next_WordCol (int times) const; // start of the n-th next word (for dw/yw/w) int end_WordCol (int times) const; // last char of the n-th word fwd (for e) int prev_WordCol (int times) const; // start of the n-th word back (for b) // undo/redo void push_Undo (); // snapshot current state, clear redo void undo (); void redo (); // yank / paste / change void yank_Lines (int n); // linewise yank n lines from _row void op_ToNextWord (int times, bool del, bool yank); // dw / yw void op_ChangeWord (int times); // cw void change_Line (); // cc (register filled by caller) void paste_After (); void paste_Before (); // indentation void indent_Lines (int n, int dir); // dir +1 = indent, -1 = dedent bool is_Dirty () const; int get_LineLen () const; int get_Eff () const; int get_ClampRow (int r) const; }; } // namespace Nimbin