From fd72d416db10a6e4121077d75dade671aa674dbe Mon Sep 17 00:00:00 2001 From: dzaima Date: Fri, 3 Mar 2023 15:54:03 +0200 Subject: [PATCH] manual prefix character typing detecting --- docs/commands.md | 4 ++ src/main.c | 130 ++++++++++++++++++++++++++++++----------------- 2 files changed, 88 insertions(+), 46 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index 345f8842..5869a65f 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -42,6 +42,10 @@ Changes the color scheme of syntax highlighting; Supported: `)theme light`, `)th Enable or disable backslash input for BQN characters. +## `)kb character` (replxx-only) + +Set keyboard prefix character to a custom one. Default is backslash, i.e. `)kb \` + ## `)erase name` Erase the specified variable name. diff --git a/src/main.c b/src/main.c index 07e08da8..675facf3 100644 --- a/src/main.c +++ b/src/main.c @@ -49,6 +49,17 @@ static bool isCmd(char* s, char** e, const char* cmd) { return t.r; } +static NOINLINE i64 readInt(char** p) { + char* c = *p; + i64 am = 0; + while (*c>='0' & *c<='9') { + am = am*10 + (*c - '0'); + c++; + } + *p = c; + return am; +} + #if USE_REPLXX #include @@ -57,6 +68,7 @@ static bool isCmd(char* s, char** e, const char* cmd) { #include "utils/cstr.h" Replxx* global_replxx; static char* global_histfile; + static u32 cfg_prefixChar = U'\\'; static i8 themes[3][12][3] = { // {-1,-1,-1} for default/unchanged color, {-1,-1,n} for grayscale 0…23, else RGB 0…5 @@ -125,7 +137,7 @@ static bool isCmd(char* s, char** e, const char* cmd) { NOINLINE void cfg_changed(void) { B s = emptyCVec(); - AFMT("theme=%i\nkeyboard=%i\n", cfg_theme, cfg_enableKeyboard); + AFMT("theme=%i\nkeyboard=%i\nprefix=%i\n", cfg_theme, cfg_enableKeyboard, cfg_prefixChar); if (CATCH) { freeThrown(); goto end; } path_wChars(incG(cfg_path), s); popCatch(); @@ -348,7 +360,7 @@ static bool isCmd(char* s, char** e, const char* cmd) { void hint_replxx(const char* inp, replxx_hints* res, int* dist, ReplxxColor* c, void* data) { completion_impl(inp, res, true, dist); } - static NOINLINE char* malloc_B(B x) { // toCStr but allocated by malloc; frees x + static NOINLINE char* malloc_B(B x) { // toCStr but allocated by malloc; consumes x u64 len1 = utf8lenB(x); char* s1 = malloc(len1+1); toUTF8(x, s1); @@ -365,7 +377,7 @@ static bool isCmd(char* s, char** e, const char* cmd) { replxx_get_state(global_replxx, &st); return (TmpState){.s = utf8Decode0(st.text), .pos = st.cursorPosition}; } - static NOINLINE void setState(TmpState s) { // frees s.s + static NOINLINE void setState(TmpState s) { // consumes s.s char* r = malloc_B(s.s); ReplxxState st = (ReplxxState){.text = r, .cursorPosition = s.pos}; replxx_set_state(global_replxx, &st); @@ -386,29 +398,23 @@ static bool isCmd(char* s, char** e, const char* cmd) { } static B b_pv; static int b_pp; - static bool inBackslash() { return b_pv.u!=0; } - static void stopBackslash() { decG(b_pv); b_pv.u = 0; } - ReplxxActionResult backslash_replxx(int code, void* data) { - CATCH_OOM(goto end) - if (inBackslash()) { - setState(insertChar('\\', false)); - stopBackslash(); - } else if (!cfg_enableKeyboard) { - setState(insertChar('\\', false)); - } else { - ReplxxState st; - replxx_get_state(global_replxx, &st); - b_pv = utf8Decode0(st.text); - b_pp = st.cursorPosition; - } - popCatch(); - end: - return REPLXX_ACTION_RESULT_CONTINUE; + static bool inBackslash; + static void stopBackslash() { inBackslash = false; } + NOINLINE void setPrev(B s, u64 pos) { // consumes + decG(b_pv); + b_pv = s; + b_pp = pos; + } + NOINLINE void setPrevNow() { + ReplxxState st; + replxx_get_state(global_replxx, &st); + setPrev(utf8Decode0(st.text), st.cursorPosition); } ReplxxActionResult enter_replxx(int code, void* data) { - if (inBackslash()) { + if (inBackslash) { setState(insertChar('\n', false)); stopBackslash(); + setPrevNow(); return REPLXX_ACTION_RESULT_CONTINUE; } return replxx_invoke(global_replxx, REPLXX_ACTION_COMMIT_LINE, 0); @@ -427,23 +433,42 @@ static bool isCmd(char* s, char** e, const char* cmd) { static B b_key, b_val; void modified_replxx(char** s_res, int* p_res, void* userData) { if (!cfg_enableKeyboard) return; - if (!inBackslash()) return; CATCH_OOM(return) TmpState t = getState(); B s = t.s; u64 pos = t.pos; - if (IA(b_pv)+1 != IA(s) || b_pp+1 != pos) goto stop; - if (!slice_equal(b_pv, 0, s, 0, pos-1)) goto stop; - if (!slice_equal(b_pv, b_pp, s, pos, IA(s)-pos)) goto stop; - usz mapPos = o2i(C1(pick, C2(indexOf, incG(b_key), IGet(s,pos-1)))); - if (mapPos==IA(b_key)) goto stop; + if (equal(b_pv, s) && pos==b_pp) goto end_withPrev; // sometimes this is called when nothing actually changed - TmpState t2 = insertChar(o2c(IGetU(b_val, mapPos)), true); - *s_res = malloc_B(t2.s); // will be free()'d by replxx - *p_res = t2.pos; + if (IA(b_pv)+1 != IA(s) || b_pp+1 != pos) goto stop; // user did something other than type a single character - stop: decG(s); + if (inBackslash) { + if (!slice_equal(b_pv, 0, s, 0, pos-1)) goto stop; + if (!slice_equal(b_pv, b_pp, s, pos, IA(s)-pos)) goto stop; + if (o2cG(IGet(s,pos-1)) == cfg_prefixChar) goto stop; // always make sure that the prefix char typed in twice types in the prefix char + usz mapPos = o2i(C1(pick, C2(indexOf, incG(b_key), IGet(s,pos-1)))); + if (mapPos==IA(b_key)) goto stop; + + TmpState t2 = insertChar(o2c(IGetU(b_val, mapPos)), true); + *s_res = malloc_B(t2.s); // will be free()'d by replxx + *p_res = t2.pos; + goto stop; + } else { + if (o2cG(IGetU(s,b_pp))==cfg_prefixChar) { + inBackslash = true; + *s_res = malloc_B(incG(b_pv)); // will be free()'d by replxx + *p_res = b_pp; + // restore state to previous one, and don't call setPrev as that'll set it to the updated one + goto end_noPrev; + } + goto end_withPrev; + } + + stop: stopBackslash(); + end_withPrev: + setPrevNow(); + end_noPrev: + decG(s); popCatch(); } @@ -486,6 +511,9 @@ static bool isCmd(char* s, char** e, const char* cmd) { char* s = toCStr(ln); char* e; if (isCmd(s, &e, "theme=" )) cfg_theme = e[0]-'0'; else if (isCmd(s, &e, "keyboard=")) cfg_enableKeyboard = e[0]-'0'; + #if !NO_RYU + else if (isCmd(s, &e, "prefix=" )) cfg_prefixChar = readInt(&e); + #endif freeCStr(s); } decG(lns); @@ -508,6 +536,12 @@ static bool isCmd(char* s, char** e, const char* cmd) { gc_add_ref(&b_pv); global_replxx = replxx_init(); + b_pv = emptyCVec(); + b_pp = 0; + } + const char* cbqn_replxx_input(char* prefix) { + setPrev(emptyCVec(), 0); + return replxx_input(global_replxx, prefix); } #else void before_exit(void) { } @@ -543,16 +577,6 @@ static B simple_unescape(B x) { return c1(escape_parser, x); } -static NOINLINE i64 readInt(char** p) { - char* c = *p; - i64 am = 0; - while (*c>='0' & *c<='9') { - am = am*10 + (*c - '0'); - c++; - } - *p = c; - return am; -} void cbqn_runLine0(char* ln, i64 read) { if (ln[0]==0 || read==0) return; @@ -641,8 +665,23 @@ void cbqn_runLine0(char* ln, i64 read) { return; #if USE_REPLXX } else if (isCmd(cmdS, &cmdE, "kb ")) { - cfg_set_keyboard(!cfg_enableKeyboard, true); - printf("Backslash input %s\n", cfg_enableKeyboard? "enabled" : "disabled"); + if (*cmdE == 0) { + kb_toggle: + cfg_set_keyboard(!cfg_enableKeyboard, true); + printf("Backslash input %s\n", cfg_enableKeyboard? "enabled" : "disabled"); + } else { + B a = utf8Decode0(cmdE); + if (IA(a)==0) goto kb_toggle; + if (IA(a)!=1) { + printf("Invalid )kb usage: expected either no argument, or a single character\n"); + } else { + u32 c = o2cG(IGetU(a,0)); + printf("Backslash input prefix character set to U+%04x\n", c); + cfg_prefixChar = c; + cfg_changed(); + } + decG(a); + } return; } else if (isCmd(cmdS, &cmdE, "theme ")) { if (strcmp(cmdE,"dark" )==0) cfg_set_theme(1, true); @@ -967,7 +1006,6 @@ int main(int argc, char* argv[]) { replxx_set_hint_callback(global_replxx, hint_replxx, NULL); replxx_set_completion_callback(global_replxx, complete_replxx, NULL); replxx_enable_bracketed_paste(global_replxx); - replxx_bind_key(global_replxx, '\\', backslash_replxx, NULL); replxx_bind_key(global_replxx, REPLXX_KEY_ENTER, enter_replxx, NULL); replxx_set_modify_callback(global_replxx, modified_replxx, NULL); replxx_bind_key_internal(global_replxx, REPLXX_KEY_CONTROL('N'), "history_next"); @@ -975,7 +1013,7 @@ int main(int argc, char* argv[]) { replxx_set_max_history_size(global_replxx, 50000); while(true) { - const char* ln = replxx_input(global_replxx, " "); + const char* ln = cbqn_replxx_input(" "); if (ln==NULL) { if (errno==0) printf("\n"); break;