chore: 规范标点

This commit is contained in:
pluv committed 2026-10-03 14:43:43 +08:00
1 parent e54390a9f8
commit 15e79887fa
84 files changed
+5439 -5398

No files matched your search

+102 -102
View File
@@ -61,7 +61,7 @@ static void print_usage(FILE *out)
static void apply_config(Agent *a, LigentConfig *c)
{
a->llm.base_url = c->base_url; /* 有意借用,配置对象活得和进程一样久 */
a->llm.base_url = c->base_url; /* 有意借用, 配置对象活得和进程一样久 */
a->llm.api_key = c->api_key;
a->llm.model = c->model;
a->llm.temperature = c->temperature;
@@ -110,11 +110,11 @@ static void print_banner(const LigentConfig *c, const Agent *a)
t("repl.banner.hint"), a->color ? "\033[0m" : "");
}
/* 存档目录跟二进制走,和配置同一个原则 */
/* 存档目录跟二进制走, 和配置同一个原则 */
static const char *g_bindir;
/* 当前对话的谱系:最近一次写出或载入的存档名(不含 .json)。
* 下次存档就在它后面接一级分支,于是文件名本身就记录了分支关系。 */
/* 当前对话的谱系:最近一次写出或载入的存档名 (不含 .json).
* 下次存档就在它后面接一级分支, 于是文件名本身就记录了分支关系. */
static char *g_lineage;
static void set_lineage(const char *name)
@@ -123,7 +123,7 @@ static void set_lineage(const char *name)
g_lineage = (name && *name) ? xstrdup(name) : NULL;
}
/* /back 摘掉的消息,供 /unback 撤销;g_back_len 记录摘完之后的长度,
/* /back 摘掉的消息, 供 /unback 撤销; g_back_len 记录摘完之后的长度,
* 用来判断"之后是不是又开了新对话" */
static JsonValue *g_back_undo;
static size_t g_back_len;
@@ -135,25 +135,25 @@ static void back_undo_clear(void)
g_back_len = 0;
}
/* 上次自动存档时的状态,用来避免重复存同一段对话 */
/* 上次自动存档时的状态, 用来避免重复存同一段对话 */
static size_t g_saved_count;
static time_t g_saved_start;
static int g_auto_save_on;
/* 自动存档。只在"有内容"且"自上次存档后又变了"时才写,
* 所以退出、重置、导入前各调一次不会产生重复文件。 */
/* 自动存档. 只在"有内容"且"自上次存档后又变了"时才写,
* 所以退出、重置、导入前各调一次不会产生重复文件. */
static void auto_save(Agent *a, LigentConfig *c, const char *why,
const char *prefix)
{
if (!g_auto_save_on) return;
size_t n = agent_history_len(a);
if (n <= 1) return; /* 只有 system,没内容 */
if (n <= 1) return; /* 只有 system, 没内容 */
if (n == g_saved_count && a->started_at == g_saved_start)
return; /* 内容没变 */
char *path = NULL, *name = NULL;
char err[512];
/* meta 改过就另起一根:<原名>_m<3位>,parent 记空 */
/* meta 改过就另起一根:<原名>_m<3位>, parent 记空 */
int meta = meta_reroot_pending();
if (archive_export(a->messages, g_bindir ? g_bindir : ".", g_lineage,
prefix, meta, a->started_at, time(NULL),
@@ -164,10 +164,10 @@ static void auto_save(Agent *a, LigentConfig *c, const char *why,
}
g_saved_count = n;
g_saved_start = a->started_at;
/* 临时存档只是"换掉当前对话前留一手",不该成为以后分支的祖先 */
/* 临时存档只是"换掉当前对话前留一手", 不该成为以后分支的祖先 */
if (!prefix || !*prefix) {
set_lineage(name);
if (meta) meta_reroot_clear(); /* 新根已经落名,标记用掉了 */
if (meta) meta_reroot_clear(); /* 新根已经落名, 标记用掉了 */
}
fprintf(stderr, "\033[2m%s\033[0m\n",
tf("main.auto_saved", "why", why, "path", path,
@@ -176,8 +176,8 @@ static void auto_save(Agent *a, LigentConfig *c, const char *why,
free(name);
}
/* 真正落地一次模型切换。cap 缓存是按 base_url+model 索引的,所以下次请求
* 会自动重新探测新模型的能力,这里不用额外处理。 */
/* 真正落地一次模型切换. cap 缓存是按 base_url+model 索引的, 所以下次请求
* 会自动重新探测新模型的能力, 这里不用额外处理. */
static void apply_model(Agent *a, LigentConfig *c, const char *name)
{
if (strcmp(c->model, name) == 0) {
@@ -190,16 +190,16 @@ static void apply_model(Agent *a, LigentConfig *c, const char *name)
printf("%s", tf("repl.model.switched", "model", c->model, NULL));
}
/* /model 不带参数:拉一次在线列表,打印出来,然后用**普通输入行**问要哪个。
/* /model 不带参数:拉一次在线列表, 打印出来, 然后用**普通输入行**问要哪个.
*
* 刻意不用"光标选择"那种菜单:一是它会用 ANSI 反复重画、把 stdout 搅乱
* (重定向、日志、粘贴都会跟着遭殃),二是**没法输入列表里没有的东西** ——
* 而"列表里没有"恰恰很常见:内部模型、灰度模型、服务端没列出来的别名。
* 所以这里是 /import 那一套:列表打在上面,输入行里既可以填序号,也可以
* 直接写模型名,回车取消。
* (重定向、日志、粘贴都会跟着遭殃), 二是**没法输入列表里没有的东西** ——
* 而"列表里没有"恰恰很常见:内部模型、灰度模型、服务端没列出来的别名.
* 所以这里是 /import 那一套:列表打在上面, 输入行里既可以填序号, 也可以
* 直接写模型名, 回车取消.
*
* 拉不到列表就明说原因,并提示还能直接用 /model <名字> —— 不能因为网络不行
* 或者服务端不列,就把这条路堵死。 */
* 拉不到列表就明说原因, 并提示还能直接用 /model <名字> —— 不能因为网络不行
* 或者服务端不列, 就把这条路堵死. */
static void cmd_model_pick(Agent *a, LigentConfig *c)
{
printf("%s", tf("repl.model.fetching", "url", c->base_url, NULL));
@@ -238,8 +238,8 @@ static void cmd_model_pick(Agent *a, LigentConfig *c)
return;
}
/* 纯数字按序号理解;其它一律当模型名 —— 这条正是"内部模型"的入口,
* 所以不去列表里校验它,服务端认不认由后端说了算。 */
/* 纯数字按序号理解; 其它一律当模型名 —— 这条正是"内部模型"的入口,
* 所以不去列表里校验它, 服务端认不认由后端说了算. */
char *numend = NULL;
long idx = strtol(ans, &numend, 10);
if (numend != ans && *str_trim(numend) == '\0') {
@@ -259,15 +259,15 @@ static void cmd_model_pick(Agent *a, LigentConfig *c)
models_free(list, n);
}
/* /include 遇到图片时才会被问到。这时候才去跑能力探测 —— 纯文本的附带
* 不该为了"可能出现的图"先花掉两个探测请求。探测结论按 base_url+model
* 缓存,所以一个模型只会真探测一次。 */
/* /include 遇到图片时才会被问到. 这时候才去跑能力探测 —— 纯文本的附带
* 不该为了"可能出现的图"先花掉两个探测请求. 探测结论按 base_url+model
* 缓存, 所以一个模型只会真探测一次. */
static int include_can_image(void *ud)
{
Agent *a = ud;
agent_ensure_caps(a);
/* 只有**明确不支持**才拦。未测(探测被关掉或结论不确定)按支持放行,
* 和别处一个原则:宁可让服务端说不行,也不错误地藏掉东西。 */
/* 只有**明确不支持**才拦. 未测 (探测被关掉或结论不确定)按支持放行,
* 和别处一个原则:宁可让服务端说不行, 也不错误地藏掉东西. */
return a->caps.vision != CAP_NO;
}
@@ -305,12 +305,12 @@ static void cmd_include(Agent *a, const char *arg)
printf("%s", tf("repl.include.none", "n",
i18n_num((long long)skipped), NULL));
}
/* added == 0 且 skipped == 0 = 用户在交互式界面里取消了,不用多嘴 */
/* added == 0 且 skipped == 0 = 用户在交互式界面里取消了, 不用多嘴 */
}
static void cmd_export(Agent *a, LigentConfig *c)
{
/* 只有 system 一条说明这段对话还没发生过什么,导出没有意义 */
/* 只有 system 一条说明这段对话还没发生过什么, 导出没有意义 */
if (agent_history_len(a) <= 1) {
puts(t("repl.export.empty"));
return;
@@ -334,12 +334,12 @@ static void cmd_export(Agent *a, LigentConfig *c)
strlen(g_lineage) + 1 + ARCHIVE_BRANCH_LEN + strlen(".json") > ARCHIVE_NAME_MAX)
printf("%s\n", t("repl.export.name_limit"));
/* 手动导出也算"已存档",否则退出时的自动存档会把同样的内容
* 再分一级存一遍,白占一个文件 */
/* 手动导出也算"已存档", 否则退出时的自动存档会把同样的内容
* 再分一级存一遍, 白占一个文件 */
g_saved_count = agent_history_len(a);
g_saved_start = a->started_at;
set_lineage(name);
if (meta) meta_reroot_clear(); /* 新根已经落名,标记用掉了 */
if (meta) meta_reroot_clear(); /* 新根已经落名, 标记用掉了 */
free(path);
free(name);
}
@@ -361,10 +361,10 @@ static const ArchiveEntry *find_entry(const ArchiveEntry *list, size_t n,
return hit;
}
/* 载入存档:给了名字就直接载入,否则交互式选一份。
* 只把历史装回去,不重放历史内容。 */
/* 问一个是非题,(Y/n) 语义:直接回车算"是"。
* 非终端时没人能回答,按默认值返回 1 —— 和 confirm_tool 一致。 */
/* 载入存档:给了名字就直接载入, 否则交互式选一份.
* 只把历史装回去, 不重放历史内容. */
/* 问一个是非题, (Y/n) 语义:直接回车算"是".
* 非终端时没人能回答, 按默认值返回 1 —— 和 confirm_tool 一致. */
static int ask_yes_no(const char *question)
{
if (!isatty(STDIN_FILENO)) return 1;
@@ -382,14 +382,14 @@ static int ask_yes_no(const char *question)
}
}
/* /import 载入后用户可能想看看这段历史到底聊了什么。
/* /import 载入后用户可能想看看这段历史到底聊了什么.
*
* 这里是**完整**转储:不截断正文、不省略工具参数、不砍总量。既然用户
* 明确回答了 Y,就该看到全部 —— 截一半反而会让人以为历史里就这么点东西。
* 所以只做排版,不做取舍。
* 这里是**完整**转储:不截断正文、不省略工具参数、不砍总量. 既然用户
* 明确回答了 Y, 就该看到全部 —— 截一半反而会让人以为历史里就这么点东西.
* 所以只做排版, 不做取舍.
*
* 唯一"少打印"的地方是没有 content 的消息(工具调用型的 assistant),
* 那种消息本来就没有正文,打出来的是它的 tool_calls。 */
* 唯一"少打印"的地方是没有 content 的消息 (工具调用型的 assistant),
* 那种消息本来就没有正文, 打出来的是它的 tool_calls. */
static void print_history(const Agent *a, const JsonValue *msgs)
{
const char *dim = a->color ? "\033[2m" : "";
@@ -414,7 +414,7 @@ static void print_history(const Agent *a, const JsonValue *msgs)
printf("\n%s-- %zu/%zu %s --%s\n", dim, i + 1, n, label, off);
/* tool 结果要标出它回应的是哪次调用,否则一堆工具输出看不出配对 */
/* tool 结果要标出它回应的是哪次调用, 否则一堆工具输出看不出配对 */
if (strcmp(role, "tool") == 0) {
const char *id = json_get_string(m, "tool_call_id");
printf("%s[tool_call_id=%s]%s\n", dim, id ? id : "", off);
@@ -530,16 +530,16 @@ static void cmd_import(Agent *a, const char *arg)
}
char *loaded = xstrdup(pick->name);
agent_replace_history(a, msgs); /* 取得所有权 */
/* 载入之后再数:换成和 /history 一样的口径(不含 system),
* 否则"已载入 N 条"和"历史消息 M 条"会差 1,看着像出了错 */
/* 载入之后再数:换成和 /history 一样的口径 (不含 system),
* 否则"已载入 N 条"和"历史消息 M 条"会差 1, 看着像出了错 */
size_t count = agent_conversation_len(a);
/* 输入历史不跟着清:它现在是一份持久的、跨会话的用户资源(像 bash 的
* HISTFILE),记的是"我在 ligent> 敲过什么",和当前装的是哪段对话无关。 */
/* 输入历史不跟着清:它现在是一份持久的、跨会话的用户资源 (像 bash 的
* HISTFILE), 记的是"我在 ligent> 敲过什么", 和当前装的是哪段对话无关. */
set_lineage(loaded); /* 之后的分支都挂在它下面 */
printf("%s", tf("repl.import.done", "name", loaded,
"n", i18n_num((long long)count), NULL));
/* 问一句再决定要不要把这段历史打出来 —— 直接回车就输出(默认 Y),
* 历史很长、不想被刷屏时回 n 即可,条数随时可以用 /history 看。 */
/* 问一句再决定要不要把这段历史打出来 —— 直接回车就输出 (默认 Y),
* 历史很长、不想被刷屏时回 n 即可, 条数随时可以用 /history 看. */
if (ask_yes_no(t("repl.import.print_ask")))
print_history(a, a->messages);
free(loaded);
@@ -551,11 +551,11 @@ static void repl_help(void)
fputs(t("repl.help"), stdout);
}
/* 带参数命令的匹配:/name 之后必须是空白或字符串结束。
/* 带参数命令的匹配:/name 之后必须是空白或字符串结束.
*
* 只用前缀匹配是不够的 —— 那样 "/modelxxx" 会被当成 "/model" 并把 xxx
* 当作模型名去切模型,"/thinkfoo" 也会落进 /think 分支。命中返回参数起点
* (已跳过空白;指进 dup 里,调用方不要 free),不命中返回 NULL。 */
* 当作模型名去切模型, "/thinkfoo" 也会落进 /think 分支. 命中返回参数起点
* (已跳过空白; 指进 dup 里, 调用方不要 free), 不命中返回 NULL. */
static char *cmd_arg(char *cmd, const char *name)
{
size_t n = strlen(name);
@@ -565,12 +565,12 @@ static char *cmd_arg(char *cmd, const char *name)
return str_trim(cmd + n);
}
/* 返回 0 继续,1 退出 */
/* 返回 0 继续, 1 退出 */
static int handle_command(Agent *a, LigentConfig *c, const char *line)
{
char *dup = xstrdup(line);
char *cmd = str_trim(dup);
char *arg = NULL; /* 当前分支的参数;指向 dup 内部,不单独释放 */
char *arg = NULL; /* 当前分支的参数; 指向 dup 内部, 不单独释放 */
if (strcmp(cmd, "/exit") == 0 || strcmp(cmd, "/quit") == 0) {
free(dup);
@@ -582,10 +582,10 @@ static int handle_command(Agent *a, LigentConfig *c, const char *line)
} else if (strcmp(cmd, "/reset") == 0 || strcmp(cmd, "/clear") == 0) {
auto_save(a, c, t("repl.why.before_reset"), NULL);
agent_reset(a);
/* 刚存的是"上一段"对话,和新开的这段没关系了,所以把判重状态清掉。
* 不清的话会漏存:判重只看 (条数, started_at),而 time() 只有秒级
* 精度 —— 同一秒里重置、又聊出同样多条消息,退出时就会被当成
* "内容没变"而跳过存档。 */
/* 刚存的是"上一段"对话, 和新开的这段没关系了, 所以把判重状态清掉.
* 不清的话会漏存:判重只看 (条数, started_at), 而 time() 只有秒级
* 精度 —— 同一秒里重置、又聊出同样多条消息, 退出时就会被当成
* "内容没变"而跳过存档. */
g_saved_count = 0;
g_saved_start = 0;
set_lineage(NULL); /* 新对话另起一个根 */
@@ -601,7 +601,7 @@ static int handle_command(Agent *a, LigentConfig *c, const char *line)
free(c->system);
c->system = xstrdup(arg);
agent_reset(a);
attach_clear(); /* 重新开始,暂存的附件也一并丢掉 */
attach_clear(); /* 重新开始, 暂存的附件也一并丢掉 */
agent_add_system(a, c->system);
puts(t("repl.system.updated"));
} else {
@@ -631,33 +631,33 @@ static int handle_command(Agent *a, LigentConfig *c, const char *line)
? c->reasoning_effort : t("cfg.val.server_default"));
}
} else if (strcmp(cmd, "/meta") == 0) {
/* 进 meta 前先留一份保底存档:里面全是不可逆的删改。
* 用 tmp_ 前缀,免得它变成以后分支的祖先。 */
/* 进 meta 前先留一份保底存档:里面全是不可逆的删改.
* 用 tmp_ 前缀, 免得它变成以后分支的祖先. */
auto_save(a, c, t("repl.why.before_meta"), ARCHIVE_TMP_PREFIX);
int r = meta_session(a, c);
if (r == 1) {
/* 历史被改过:/back 的撤销栈基于旧历史,作废;
* 存档判重也清掉,保证退出时一定存下这个新版本。 */
/* 历史被改过:/back 的撤销栈基于旧历史, 作废;
* 存档判重也清掉, 保证退出时一定存下这个新版本. */
back_undo_clear();
g_saved_count = 0;
g_saved_start = 0;
}
} else if (strcmp(cmd, "/cls") == 0) {
/* 只清屏幕,不碰对话历史 —— 和 /reset 是两回事。
* 3J 连回滚缓冲一起清,跟 clear(1) 的行为对齐;不支持 3J 的终端会
* 忽略它,2J + H 照样把可见区域清干净。 */
/* 只清屏幕, 不碰对话历史 —— 和 /reset 是两回事.
* 3J 连回滚缓冲一起清, 跟 clear(1) 的行为对齐; 不支持 3J 的终端会
* 忽略它, 2J + H 照样把可见区域清干净. */
if (isatty(STDOUT_FILENO)) fputs("\033[2J\033[3J\033[H", stdout);
fflush(stdout);
} else if (strcmp(cmd, "/tools") == 0) {
if (a->use_tools) {
/* 只查缓存,绝不为了显示这一行去发探测请求 */
/* 只查缓存, 绝不为了显示这一行去发探测请求 */
Capabilities caps;
tools_print_list(cap_cached(&a->llm, &caps) && caps.vision == CAP_NO);
}
else puts(t("repl.tools.disabled"));
} else if (strcmp(cmd, "/probe") == 0) {
/* 手动测一次模型能力(收不收图片 / 收不收 tools)。
* 刻意绕开 --no-probe 与缓存 —— 理由见 agent_probe_now 的注释。 */
/* 手动测一次模型能力 (收不收图片 / 收不收 tools).
* 刻意绕开 --no-probe 与缓存 —— 理由见 agent_probe_now 的注释. */
agent_probe_now(a);
} else if (strcmp(cmd, "/config") == 0) {
config_dump(c);
@@ -701,7 +701,7 @@ static int handle_command(Agent *a, LigentConfig *c, const char *line)
for (size_t i = 0; i < rn; i++)
json_array_push(g_back_undo, json_clone(json_array_get(removed, i)));
json_free(removed);
g_back_len = agent_history_len(a); /* 比对用,保持数组真实长度 */
g_back_len = agent_history_len(a); /* 比对用, 保持数组真实长度 */
printf("%s", tf("repl.back.done", "n", i18n_num((long long)rn),
"left", i18n_num((long long)agent_conversation_len(a)),
NULL));
@@ -723,7 +723,7 @@ static int handle_command(Agent *a, LigentConfig *c, const char *line)
}
} else if ((arg = cmd_arg(cmd, "/shell")) != NULL) {
if (*arg) {
/* 带参数:直接执行它,不进入交互式 shell */
/* 带参数:直接执行它, 不进入交互式 shell */
JsonValue *args = json_new_object();
json_object_set_string(args, "command", arg);
int is_err = 0;
@@ -746,7 +746,7 @@ static int handle_command(Agent *a, LigentConfig *c, const char *line)
} else {
if (rec[0]) {
char *msg = xasprintf(
"我在交互式 shell 里做了以下操作(shell 退出码 %d):\n\n"
"我在交互式 shell 里做了以下操作 (shell 退出码 %d):\n\n"
"```console\n%s\n```\n", code, rec);
agent_add_user(a, msg);
printf("\n%s\n",
@@ -786,14 +786,14 @@ static int handle_command(Agent *a, LigentConfig *c, const char *line)
i18n_num((long long)n), "file", arg, NULL));
}
} else if (strcmp(cmd, "/history") == 0) {
/* 一行摘要 + 完整对话。
/* 一行摘要 + 完整对话.
*
* 摘要那行报的是"不含 system"的口径(和 /usage、/back、/export 一致),
* 而下面列出来的是**含** system 的全部消息 —— 两个数不一样,所以必须
* 说清楚,否则用户会以为打印漏了或者多了一条。
* 摘要那行报的是"不含 system"的口径 (和 /usage、/back、/export 一致),
* 而下面列出来的是**含** system 的全部消息 —— 两个数不一样, 所以必须
* 说清楚, 否则用户会以为打印漏了或者多了一条.
*
* 为什么要连 system 一起列:那是"模型被要求怎么做"的原文,想核对提示词
* 时只有这里能看到全文(/config 里那行会把多行提示词挤成一团)。 */
* 为什么要连 system 一起列:那是"模型被要求怎么做"的原文, 想核对提示词
* 时只有这里能看到全文 (/config 里那行会把多行提示词挤成一团). */
printf("%s", tf("repl.history.count", "n",
i18n_num((long long)agent_conversation_len(a)), NULL));
printf("%s", tf("repl.history.full", "total",
@@ -806,20 +806,20 @@ static int handle_command(Agent *a, LigentConfig *c, const char *line)
return 0;
}
/* 输入历史最多保留多少条。和 bash 一样有上限,否则文件会一直长下去;
* 只保留最新的,旧的在下次启动时被就地截掉。 */
/* 输入历史最多保留多少条. 和 bash 一样有上限, 否则文件会一直长下去;
* 只保留最新的, 旧的在下次启动时被就地截掉. */
#define LIGENT_HISTORY_KEEP 1000
/* 输入历史文件;NULL 表示禁用(--no-history)。 */
/* 输入历史文件; NULL 表示禁用 (--no-history). */
static char *g_hist_path = NULL;
/* 提示符保持纯文本:绿色由行编辑器统一加在整个输入行(提示符 + 你敲的字)上。
* 在这里塞颜色的话,提示符自带的 reset 会让后面的输入掉回默认色。 */
/* 提示符保持纯文本:绿色由行编辑器统一加在整个输入行 (提示符 + 你敲的字)上.
* 在这里塞颜色的话, 提示符自带的 reset 会让后面的输入掉回默认色. */
#define PROMPT_MAIN "ligent> "
#define PROMPT_CONT " ... "
/* 读一条完整输入。支持行尾反斜杠续行:每段都由行编辑器独立编辑,
* 因此方向键、Home/End、历史在续行的每一段里都可用。 */
/* 读一条完整输入. 支持行尾反斜杠续行:每段都由行编辑器独立编辑,
* 因此方向键、Home/End、历史在续行的每一段里都可用. */
static char *read_prompt_line(const char *prompt, int *interrupted)
{
StrBuf sb;
@@ -839,7 +839,7 @@ static char *read_prompt_line(const char *prompt, int *interrupted)
sb_free(&sb);
return NULL;
}
/* EOF:缓冲区里还有内容就把它交出去,否则终止 */
/* EOF:缓冲区里还有内容就把它交出去, 否则终止 */
if (sb.len > 0) {
if (sb.data[sb.len - 1] != '\n') sb_putc(&sb, '\n');
return sb_detach(&sb);
@@ -863,8 +863,8 @@ static char *read_prompt_line(const char *prompt, int *interrupted)
free(seg);
if (!cont) {
sb_putc(&sb, '\n');
/* 历史记的是"这一整条输入":多行续行算一条,上下键能整条召回。
* 续行的中间段不单独记。这里借尾部那个换行临时当结束符。 */
/* 历史记的是"这一整条输入":多行续行算一条, 上下键能整条召回.
* 续行的中间段不单独记. 这里借尾部那个换行临时当结束符. */
if (sb.len > 1) {
sb.data[sb.len - 1] = '\0';
if (line_history_add(sb.data))
@@ -881,11 +881,11 @@ static char *read_prompt_line(const char *prompt, int *interrupted)
static int run_repl(Agent *a, LigentConfig *c)
{
g_bindir = c->config_dir;
/* 图片备份也要落在二进制旁边。这个函数一度**从来没有被调用过**,
* image_bindir() 于是退化成 ".",备份跟着当前工作目录跑 —— /cd 到别的
* 目录再带图,备份就写到那儿去了,之后从别处发消息会因为找不到备份而
* 把图降级掉。测试一直从二进制所在目录跑,"." 恰好等于正确值,所以
* 一直没暴露。 */
/* 图片备份也要落在二进制旁边. 这个函数一度**从来没有被调用过**,
* image_bindir() 于是退化成 ".", 备份跟着当前工作目录跑 —— /cd 到别的
* 目录再带图, 备份就写到那儿去了, 之后从别处发消息会因为找不到备份而
* 把图降级掉. 测试一直从二进制所在目录跑, "." 恰好等于正确值, 所以
* 一直没暴露. */
image_set_bindir(c->config_dir);
print_banner(c, a);
for (;;) {
@@ -930,9 +930,9 @@ int main(int argc, char **argv)
const char *explicit_config = NULL;
char err[512];
/* 界面语言:--lang > LIGENT_LANG > LC_ALL/LC_MESSAGES/LANG > 英文。
* 先粗扫一遍 argv,好让 --help 和 --lang 的先后顺序不影响结果 ——
* 解析循环一遇到 --help 就直接返回,那之后再写 --lang 就来不及了。 */
/* 界面语言:--lang > LIGENT_LANG > LC_ALL/LC_MESSAGES/LANG > 英文.
* 先粗扫一遍 argv, 好让 --help 和 --lang 的先后顺序不影响结果 ——
* 解析循环一遇到 --help 就直接返回, 那之后再写 --lang 就来不及了. */
{
int lang = -1;
for (int i = 1; i < argc; i++) {
@@ -1154,7 +1154,7 @@ int main(int argc, char **argv)
return 0;
}
/* 没有 key 时尽早报错,而不是等第一次请求失败 */
/* 没有 key 时尽早报错, 而不是等第一次请求失败 */
if (!cfg.api_key || !*cfg.api_key) {
fprintf(stderr, "%s", t("cli.err.no_api_key"));
config_free(&cfg);
@@ -1198,8 +1198,8 @@ int main(int argc, char **argv)
g_bindir = cfg.config_dir;
image_set_bindir(cfg.config_dir); /* 理由见 run_repl 里那段注释 */
/* 输入历史文件:命令行 > 环境变量 > <二进制目录>/ligent.history。
* 和配置一样,默认只放二进制旁边,不碰用户级/系统级目录。 */
/* 输入历史文件:命令行 > 环境变量 > <二进制目录>/ligent.history.
* 和配置一样, 默认只放二进制旁边, 不碰用户级/系统级目录. */
{
const char *env = getenv("LIGENT_HISTORY");
if (cli.history_off) {
@@ -1211,8 +1211,8 @@ int main(int argc, char **argv)
} else {
g_hist_path = xasprintf("%s/ligent.history", cfg.config_dir);
}
/* 读不回来不是错误:第一次跑本来就没有这个文件,只读的目录也不该
* 拦住 REPL。加载失败静默降级成"这次没有历史"。 */
/* 读不回来不是错误:第一次跑本来就没有这个文件, 只读的目录也不该
* 拦住 REPL. 加载失败静默降级成"这次没有历史". */
if (g_hist_path) line_history_load(g_hist_path, LIGENT_HISTORY_KEEP);
}