#pragma once #include #include #define iota(x) 1 << (x) typedef struct RGB8 RGB8; typedef struct Pen Pen; typedef struct Cell Cell; typedef struct Row Row; typedef struct Buffer Buffer; struct RGB8 { uint8 r, g, b; }; enum { PenNormal = 0, PenBold = iota(0), PenDim = iota(1), PenInvis = iota(2), PenItalic = iota(3), PenReverse = iota(4), PenStrike = iota(5), PenUnderline = iota(6), PenBlink = iota(7), /* ... */ PenTC = iota(15), }; struct Pen { ushort state; ushort color; union { /* 256 color (legacy) */ struct { sshort fg : 8, bg : 8; /* 0 - 255 or COLOUR_DEFAULT */ } col; /* true color (modern) */ struct { RGB8 fg, bg; } rgb; }; }; struct Cell { rune r; Pen pen; }; struct Row { Cell *cells; uint dirty:1; }; /* Buffer holding the current window content (as an array) as well * as the scroll back buffer content (as a circular/ring buffer). * * If new content is added to terminal the view port slides down and the * previously top most line is moved into the scroll back buffer at postion * scroll.index. This index will eventually wrap around and thus overwrite * the oldest lines. * * In the scenerio below a scroll up has been performed. That is 'scroll.above' * lines still lie above the current view port. Further scrolling up will show * them. Similarly 'scroll.below' is the amount of lines below the current * viewport. * * The function buffer_boundary sets the row pointers to the start/end range * of the section delimiting the region before/after the viewport. The functions * buffer_row_{first,last} return the first/last logical row. And * buffer_row_{next,prev} allows to iterate over the logical lines in either * direction. * * scroll back buffer * * scroll_buf->+----------------+-----+ * | | | ^ \ * | before | | | | * current terminal content | viewport | | | | * | | | | * +----------------+-----+\ | | | s > scroll.above * ^ | | i | \ | | i | c | * | | | n | \ | | n | r | * | | v | \ | | v | o | * r | | i | \ | | i | l / * o | viewport | s | >|<- scroll.index | s | l \ * w | | i | / | | i | | * s | | b | / | after | b | s > scroll.below * | | l | / | viewport | l | i | * v | | e | / | | e | z / * +----------------+-----+/ | unused | | e * <- maxcols -> | scroll back | | * <- cols -> | buffer | | | * | | | | * | | | v * roll_buf + scroll.size->+----------------+-----+ * <- maxcols -> * <- cols -> */ struct Buffer { Row *lines; /* array of Row pointers of size 'rows' */ Row *crow; /* row on which the cursor currently resides */ bool *tabs; /* a boolean flag for each column whether it is a tab */ struct { Row *buf; /* a ring buffer holding the scroll back content */ Row *top; /* row in lines where scrolling region starts */ Row *bot; /* row in lines where scrolling region ends */ int size; /* maximal capacity of scroll back buffer (in lines) */ int index; /* current index into the ring buffer */ int above; /* number of lines above current viewport */ int below; /* number of lines below current viewport */ } scroll; int rows, cols; /* current dimension of buffer */ int maxcols; /* allocated cells (maximal cols over time) */ }; /* exported functions */ void zero(Row *row, int start, int len); void roll(Row *start, Row *end, int count); void bclear(Buffer *b); void bfree(Buffer *b); void bscroll(Buffer *b, int s); void bresize(Buffer *b, int rows, int cols); bool binit(Buffer *b, int rows, int cols, int size); void bboundary(Buffer *b, Row **bs, Row **be, Row **as, Row **ae) ; Row *browfirst(Buffer *b); Row *browlast(Buffer *b); Row *brownext(Buffer *b, Row *row); Row *bprevrow(Buffer *b, Row *row);