Nimbin[12]?SDL & Graphics / sdl_runtime_compiler / src/text/vim_buffer.hpp

sdl_runtime_compiler git · main

SDL3 game for running and compiling code at runtime

sdl3 c++ compiler dlopen cmake · first commit 2026-04-19 · last commit 2026-07-03 (3 months ago) · synced 3 days ago · upstream: git.ide3.de/hsnr/sdl-runtime-compiler

C++ 72.3% C 26.2%
git clone https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler.gitwget https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler/archive/sdl_runtime_compiler.tar.gz
src/text/vim_buffer.hpp 4.5 KB · 142 lines raw
#pragma once

#include <algorithm>
#include <cstdint>
#include <string>
#include <vector>

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<std::string>& 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<std::string>&
         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<std::string> lines; int row; int col; };
    std::vector<Snapshot>    _undo;
    std::vector<Snapshot>    _redo;
    std::vector<std::string> _saved;
    std::vector<std::string> _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