Files
ligent/src/lineedit.h
T
2026-10-03 14:13:21 +08:00

83 lines
3.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* lineedit.h - REPL 的行编辑器
*
* 为什么需要它:原来的 REPL 用 fgets 直接读,终端停在规范模式,
* 方向键发出的转义序列(\x1b[D 之类)会被当成普通字节读进来,
* 显示成 ^[[D 而不是移动光标。要有行内编辑就必须自己进 raw 模式接管按键。
*
* 缓冲区与编辑操作是纯逻辑,可以脱离终端单测;只有渲染与按键读取需要 tty。
*/
#ifndef LIGENT_LINEEDIT_H
#define LIGENT_LINEEDIT_H
#include <stddef.h>
/* 可编辑缓冲区。pos 是字节偏移,且始终落在字符边界上 */
typedef struct {
char *buf;
size_t len;
size_t cap;
size_t pos;
} LineBuf;
void linebuf_init(LineBuf *lb);
void linebuf_free(LineBuf *lb);
/* 用 text 整体替换内容,光标移到末尾 */
void linebuf_set(LineBuf *lb, const char *text);
/* 在光标处插入 n 字节,光标随之后移 */
void linebuf_insert(LineBuf *lb, const char *text, size_t n);
void linebuf_backspace(LineBuf *lb); /* 删除光标前一个字符 */
void linebuf_delete(LineBuf *lb); /* 删除光标处的字符 */
void linebuf_left(LineBuf *lb); /* 光标左移一个字符 */
void linebuf_right(LineBuf *lb); /* 光标右移一个字符 */
void linebuf_home(LineBuf *lb);
void linebuf_end(LineBuf *lb);
void linebuf_kill_to_end(LineBuf *lb); /* 删到行尾 */
void linebuf_kill_to_start(LineBuf *lb); /* 删到行首 */
void linebuf_kill_word(LineBuf *lb); /* 往回删一个词 */
/* 输入行是否着色(整行:提示符 + 你敲进去的字)。
* 传进来的 prompt 应当是纯文本 —— 颜色由编辑器统一加在两头。 */
void line_edit_set_color(int enabled);
/* 换输入行的墨色(ANSI 起手式,例如 "\033[35m")。NULL 恢复默认的绿色。
* meta 模式靠它和主提示符区分开。 */
void line_edit_set_ink(const char *ansi);
/* 读入一行(不含换行符,malloc)。
* Ctrl-C -> 返回 NULL,*interrupted = 1
* Ctrl-D 空行 -> 返回 NULL,*interrupted = 0(终止输入)
* stdin 非终端 -> 退化为按行读取
* 返回的字符串可能为空串(用户直接回车),调用方负责 free。 */
char *line_edit(const char *prompt, int *interrupted);
/* 进程内的历史记录(上下方向键用) */
/* 追加一条。返回 1 表示真的记下了,0 表示被忽略(空行,或与上一条重复)。 */
int line_history_add(const char *line);
void line_history_clear(void);
size_t line_history_len(void);
const char *line_history_get(size_t i);
/* ---- 输入历史的持久化 ----
*
* 文件位置由调用方决定(ligent 用 <二进制目录>/ligent.history)。
* 一条历史在文件里占一行,所以条目里的反斜杠和换行会被转义
* (\ -> \\,换行 -> \n),保证读回来和写出去一模一样。不含反斜杠的
* 普通命令在文件里与输入完全一致,肉眼可读。
*
* 时间戳之类的元数据刻意不记:目的只是"上下键能翻到",不是审计。 */
/* 从 path 读取历史,追加到当前历史之后。最多保留最新的 keep 条;
* 文件本身更长时会被就地截短(否则会无限增长)。
* 文件不存在返回 0,读出错返回 -1。 */
int line_history_load(const char *path, size_t keep);
/* 把一条输入实时追加到 path —— 每提交一条就写一次并立刻 flush,
* 因此另一个 ligent 实例马上就能翻到。line 为空时什么都不做。
* 成功返回 0,失败返回 -1(失败不打断 REPL)。 */
int line_history_append(const char *path, const char *line);
#endif /* LIGENT_LINEEDIT_H */