#ifdef CS_REPL_USE_READLINE #ifndef CS_REPL_HAS_EDIT #define CS_REPL_HAS_EDIT /* use the GNU readline library */ #include #include #include #include #include static cs_state *rd_cs = nullptr; inline char *ln_complete_list(char const *buf, int state) { static ostd::string_range cmd; static ostd::iterator_range itr; if (!state) { cmd = get_complete_cmd(buf); itr = rd_cs->get_idents(); } for (; !itr.empty(); itr.pop_front()) { cs_ident *id = itr.front(); if (!id->is_command()) { continue; } ostd::string_range idname = id->get_name(); if (idname.size() <= cmd.size()) { continue; } if (idname.slice(0, cmd.size()) == cmd) { itr.pop_front(); return strdup(idname.data()); } } return nullptr; } inline char **ln_complete(char const *buf, int, int) { rl_attempted_completion_over = 1; return rl_completion_matches(buf, ln_complete_list); } inline void ln_hint() { cs_command *cmd = get_hint_cmd(*rd_cs, rl_line_buffer); if (!cmd) { rl_redisplay(); return; } std::string old = rl_line_buffer; std::string args = old; args += " ["; fill_cmd_args(args, cmd->get_args()); args += "] "; rl_extend_line_buffer(args.size()); rl_replace_line(args.data(), 0); rl_redisplay(); rl_replace_line(old.data(), 0); } inline void init_lineedit(cs_state &cs, ostd::string_range) { rd_cs = &cs; rl_attempted_completion_function = ln_complete; rl_redisplay_function = ln_hint; } inline std::optional read_line(cs_state &, cs_svar *pr) { auto line = readline(pr->get_value().data()); if (!line) { return std::string(); } std::string ret = line; free(line); return std::move(ret); } inline void add_history(cs_state &, ostd::string_range line) { /* backed by std::string so it's terminated */ add_history(line.data()); } #endif #endif