TUI: mouse drag selection with OSC 52 copy; Markdown emphasis follows CommonMark; v0.5.0
ci / linux (clang) (push) Failing after 21m53s
ci / linux (gcc) (push) Failing after 48s
ci / musl (push) Canceled after 0s
ci / macos (push) Canceled after 0s
ci / sanitizers (push) Canceled after 11m39s

- Drag, double-click (word) and triple-click (line) selection in the log,
  auto-scroll at the edges, soft-wrapped lines joined on copy.
- sashidown ANSI renderer: delimiter runs with flanking rules, so
  intraword underscores (test_apply_patch.c) stay literal; unmatched
  * _ and backticks are shown as-is; * and _ do not close each other.
- tests: test_textsel, test_markdown.
This commit is contained in:
WHC
2026-10-06 14:24:42 +08:00
parent b28bca2cfc
commit 1c26cc6e30
11 changed files with 875 additions and 111 deletions
+41
View File
@@ -0,0 +1,41 @@
#ifndef CST_TEXTSEL_H
#define CST_TEXTSEL_H
#include <stddef.h>
#include <wchar.h>
/* UTF-8 / ANSI helpers shared by the TUI renderer and mouse selection, so both
* agree on which character occupies each column. */
int cst_utf8_decode(const char *s, size_t avail, wchar_t *wc, size_t *eaten);
/* wcwidth(), with an East-Asian / ASCII heuristic on Windows. */
int cst_wcwidth(wchar_t wc);
/* Columns of wc; 1 for non-printing characters. */
int cst_utf8_width(wchar_t wc);
/* Length of the escape sequence at s (CSI or two-byte ESC), 0 if none. */
size_t cst_ansi_skip(const char *s, size_t n);
typedef struct {
char *s; /* NUL-terminated once anything was appended */
size_t n, cap;
} cst_selbuf_t;
void cst_selbuf_free(cst_selbuf_t *b);
int cst_selbuf_putc(cst_selbuf_t *b, char c);
/* Appends the text drawn in columns [c1, c2] of a row whose content `line`
* (ANSI escapes allowed) starts at column `indent`; c2 < 0 means the end of
* the row. A wide character is taken whole when either of its cells is in
* range. With `trim`, trailing spaces of the appended part are dropped.
* Returns 0, or -1 when out of memory. */
int cst_textsel_append(cst_selbuf_t *b, const char *line, int indent, int c1,
int c2, int trim);
/* Column span [*c1, *c2] of the word under column `col`; just that cell (or
* both cells of a wide character) when it is not on a word character. */
void cst_textsel_word(const char *line, int indent, int col, int *c1, int *c2);
/* Widens [*c1, *c2] so that neither end splits a wide character; highlighting
* half of one desynchronizes curses from the terminal. *c2 < 0 is left as is. */
void cst_textsel_snap(const char *line, int indent, int *c1, int *c2);
#endif
+1 -1
View File
@@ -1,6 +1,6 @@
#ifndef CST_VERSION_H
#define CST_VERSION_H
#define CST_VERSION "0.4.0"
#define CST_VERSION "0.5.0"
#endif