diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-07 04:48:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-07 04:48:35 +0000 |
commit | 207df6fc406e81bfeebdff7f404bd242ff3f099f (patch) | |
tree | a1a796b056909dd0a04ffec163db9363a8757808 /src/readline_curses.cc | |
parent | Releasing progress-linux version 0.11.2-1~progress7.99u1. (diff) | |
download | lnav-207df6fc406e81bfeebdff7f404bd242ff3f099f.tar.xz lnav-207df6fc406e81bfeebdff7f404bd242ff3f099f.zip |
Merging upstream version 0.12.2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/readline_curses.cc')
-rw-r--r-- | src/readline_curses.cc | 492 |
1 files changed, 383 insertions, 109 deletions
diff --git a/src/readline_curses.cc b/src/readline_curses.cc index f74a45c..326b453 100644 --- a/src/readline_curses.cc +++ b/src/readline_curses.cc @@ -30,9 +30,11 @@ */ #include <errno.h> +#include <fcntl.h> #include <signal.h> #include <stdlib.h> #include <string.h> +#include <sys/ioctl.h> #include <sys/socket.h> #include <sys/wait.h> #include <unistd.h> @@ -56,12 +58,13 @@ #include "base/ansi_scrubber.hh" #include "base/auto_mem.hh" +#include "base/fs_util.hh" +#include "base/itertools.hh" #include "base/lnav_log.hh" #include "base/paths.hh" #include "base/string_util.hh" #include "fmt/format.h" #include "fts_fuzzy_match.hh" -#include "lnav_util.hh" #include "readline_curses.hh" #include "shlex.hh" #include "spookyhash/SpookyV2.h" @@ -89,6 +92,8 @@ static const char* RL_INIT[] = { "set menu-complete-display-prefix on", "TAB: menu-complete", "\"\\e[Z\": menu-complete-backward", + "\"\\eC\": lnav-forward-complete", + "\"\\C-f\": lnav-forward-complete", }; readline_context* readline_context::loaded_context; @@ -97,6 +102,7 @@ static std::string last_match_str; static bool last_match_str_valid; static bool arg_needs_shlex; static nonstd::optional<std::string> rewrite_line_start; +static std::string rc_local_suggestion; static void sigalrm(int sig) @@ -235,10 +241,10 @@ readline_context::completion_generator(const char* text_in, int state) if (arg_needs_shlex) { shlex arg_lexer(text_str); - std::map<std::string, std::string> scope; + std::map<std::string, scoped_value_t> scope; std::string result; - if (arg_lexer.eval(result, scope)) { + if (arg_lexer.eval(result, scoped_resolver{&scope})) { text_str = result; } } @@ -364,28 +370,75 @@ readline_context::attempted_completion(const char* text, int start, int end) { char** retval = nullptr; + log_info("completion start %d:%d -- %s", start, end, text); + + auto at_start = start == 0; + auto cmd_start = 0; + auto cmd_key = std::string("__command"); + if (loaded_context->rc_splitter != nullptr) { + auto split_res + = loaded_context->rc_splitter(*loaded_context, rl_line_buffer); + + readline_context::command_t* last_cmd = nullptr; + for (const auto& stage : split_res.sr_stages) { + if (stage.s_args.empty()) { + continue; + } + + if (stage.s_args.front().lr_start == start) { + at_start = true; + break; + } + if (start <= stage.s_args.back().lr_end) { + cmd_start = stage.s_args.front().lr_start; + } + auto cmd_lr = stage.s_args.front(); + auto cmd_name = std::string(&rl_line_buffer[cmd_lr.lr_start], + cmd_lr.length()); + auto cmd_iter = loaded_context->rc_commands.find(cmd_name); + if (cmd_iter == loaded_context->rc_commands.end()) { + continue; + } + last_cmd = cmd_iter->second; + } + if (last_cmd != nullptr && !last_cmd->c_provides.empty()) { + cmd_key + = fmt::format(FMT_STRING("__command_{}"), last_cmd->c_provides); + } + } + completion_start = start; - if (start == 0 - && loaded_context->rc_possibilities.find("__command") - != loaded_context->rc_possibilities.end()) + if (text[0] == '\0' && !rc_local_suggestion.empty()) { + static std::set<std::string> suggestion_possibilities; + + suggestion_possibilities.clear(); + suggestion_possibilities.emplace(rc_local_suggestion); + arg_possibilities = &suggestion_possibilities; + rl_completion_append_character = 0; + } else if (at_start + && loaded_context->rc_possibilities.find(cmd_key) + != loaded_context->rc_possibilities.end()) { - arg_possibilities = &loaded_context->rc_possibilities["__command"]; + arg_possibilities = &loaded_context->rc_possibilities[cmd_key]; arg_needs_shlex = false; rl_completion_append_character = loaded_context->rc_append_character; } else { char* space; std::string cmd; - std::vector<std::string> prefix; int point = rl_point; while (point > 0 && rl_line_buffer[point] != ' ') { point -= 1; } shlex lexer(rl_line_buffer, point); - std::map<std::string, std::string> scope; + std::map<std::string, scoped_value_t> scope; arg_possibilities = nullptr; rl_completion_append_character = 0; - if (lexer.split(prefix, scope)) { + auto split_res = lexer.split(scoped_resolver{&scope}); + if (split_res.isOk()) { + auto prefix = split_res.unwrap() + | lnav::itertools::map( + [](const auto& elem) { return elem.se_value; }); auto prefix2 = fmt::format(FMT_STRING("{}"), fmt::join(prefix, "\x1f")); auto prefix_iter = loaded_context->rc_prefixes.find(prefix2); @@ -398,12 +451,12 @@ readline_context::attempted_completion(const char* text, int start, int end) } if (arg_possibilities == nullptr) { - space = strchr(rl_line_buffer, ' '); + space = strchr(&rl_line_buffer[cmd_start], ' '); if (space == nullptr) { space = rl_line_buffer + strlen(rl_line_buffer); } - cmd = std::string(rl_line_buffer, space - rl_line_buffer); - + cmd = std::string(&rl_line_buffer[cmd_start], + space - &rl_line_buffer[cmd_start]); auto iter = loaded_context->rc_prototypes.find(cmd); if (iter == loaded_context->rc_prototypes.end()) { @@ -416,71 +469,107 @@ readline_context::attempted_completion(const char* text, int start, int end) = loaded_context->rc_append_character; } } else { - std::vector<std::string>& proto - = loaded_context->rc_prototypes[cmd]; + auto& proto = loaded_context->rc_prototypes[cmd]; if (proto.empty()) { arg_possibilities = nullptr; - } else if (proto[0] == "filename") { + } else if (proto[0] == "dirname") { shlex fn_lexer(rl_line_buffer, rl_point); - std::vector<std::string> fn_list; - int found = 0; - - fn_lexer.split(fn_list, scope); - - const auto& last_fn = fn_list.size() <= 1 ? "" - : fn_list.back(); + auto split_res = fn_lexer.split(scoped_resolver{&scope}); + if (split_res.isOk()) { + auto fn_list = split_res.unwrap(); + const auto& last_fn = fn_list.size() <= 1 + ? "" + : fn_list.back().se_value; - if (last_fn.find(':') != std::string::npos) { - auto rp_iter = loaded_context->rc_possibilities.find( - "remote-path"); - if (rp_iter != loaded_context->rc_possibilities.end()) { - for (const auto& poss : rp_iter->second) { - if (startswith(poss, last_fn.c_str())) { - found += 1; - } - } - if (found) { - arg_possibilities = &rp_iter->second; - arg_needs_shlex = false; - } - } - if (!found || (endswith(last_fn, "/") && found == 1)) { - char msg[2048]; - - snprintf( - msg, sizeof(msg), "\t:%s", last_fn.c_str()); - sendstring(child_this->rc_command_pipe[1], - msg, - strlen(msg)); - } - } - if (!found) { - static std::set<std::string> file_name_set; + static std::set<std::string> dir_name_set; - file_name_set.clear(); + dir_name_set.clear(); auto_mem<char> completed_fn; int fn_state = 0; - auto recent_netlocs_iter - = loaded_context->rc_possibilities.find( - "recent-netlocs"); - if (recent_netlocs_iter - != loaded_context->rc_possibilities.end()) - { - file_name_set.insert( - recent_netlocs_iter->second.begin(), - recent_netlocs_iter->second.end()); - } while ((completed_fn = rl_filename_completion_function( last_fn.c_str(), fn_state)) != nullptr) { - file_name_set.insert(completed_fn.in()); + dir_name_set.insert(completed_fn.in()); fn_state += 1; } - arg_possibilities = &file_name_set; + arg_possibilities = &dir_name_set; arg_needs_shlex = true; + } else { + arg_possibilities = nullptr; + } + } else if (proto[0] == "filename") { + shlex fn_lexer(rl_line_buffer, rl_point); + int found = 0; + + auto split_res = fn_lexer.split(scoped_resolver{&scope}); + if (split_res.isOk()) { + auto fn_list = split_res.unwrap(); + const auto& last_fn = fn_list.size() <= 1 + ? "" + : fn_list.back().se_value; + + if (last_fn.find(':') != std::string::npos) { + auto rp_iter + = loaded_context->rc_possibilities.find( + "remote-path"); + if (rp_iter + != loaded_context->rc_possibilities.end()) + { + for (const auto& poss : rp_iter->second) { + if (startswith(poss, last_fn.c_str())) { + found += 1; + } + } + if (found) { + arg_possibilities = &rp_iter->second; + arg_needs_shlex = false; + } + } + if (!found + || (endswith(last_fn, "/") && found == 1)) + { + char msg[2048]; + + snprintf( + msg, sizeof(msg), "\t:%s", last_fn.c_str()); + sendstring(child_this->rc_command_pipe[1], + msg, + strlen(msg)); + } + } + if (!found) { + static std::set<std::string> file_name_set; + + file_name_set.clear(); + auto_mem<char> completed_fn; + int fn_state = 0; + auto recent_netlocs_iter + = loaded_context->rc_possibilities.find( + "recent-netlocs"); + + if (recent_netlocs_iter + != loaded_context->rc_possibilities.end()) + { + file_name_set.insert( + recent_netlocs_iter->second.begin(), + recent_netlocs_iter->second.end()); + } + while ( + (completed_fn = rl_filename_completion_function( + last_fn.c_str(), fn_state)) + != nullptr) + { + file_name_set.insert(completed_fn.in()); + fn_state += 1; + } + arg_possibilities = &file_name_set; + arg_needs_shlex = true; + } + } else { + arg_possibilities = nullptr; } } else { arg_possibilities @@ -500,6 +589,22 @@ readline_context::attempted_completion(const char* text, int start, int end) } static int +lnav_forward_complete(int count, int key) +{ + if (!rc_local_suggestion.empty() && rl_point == rl_end) { + rl_extend_line_buffer(strlen(rl_line_buffer) + + rc_local_suggestion.size() + 1); + strcat(rl_line_buffer, rc_local_suggestion.c_str()); + rl_point = strlen(rl_line_buffer); + rl_end = rl_point; + rc_local_suggestion.clear(); + return 0; + } + + return rl_forward_char(count, key); +} + +static int rubout_char_or_abort(int count, int key) { if (rl_line_buffer[0] == '\0') { @@ -546,8 +651,24 @@ readline_context::readline_context(std::string name, for (iter = commands->begin(); iter != commands->end(); ++iter) { std::string cmd = iter->first; + auto cmd_complete = cmd; + const auto& ht = iter->second->c_help; - this->rc_possibilities["__command"].insert(cmd); + if (!ht.ht_parameters.empty() + && ht.ht_parameters.front().ht_group_start != nullptr) + { + cmd_complete.append(" "); + cmd_complete.append(ht.ht_parameters.front().ht_group_start); + } + if (iter->second->c_dependencies.empty()) { + this->rc_possibilities["__command"].insert(cmd_complete); + } else { + for (const auto& dep : iter->second->c_dependencies) { + auto cmd_key = fmt::format(FMT_STRING("__command_{}"), dep); + this->rc_possibilities[cmd_key].insert(cmd_complete); + } + } + this->rc_commands[cmd] = iter->second; iter->second->c_func( INIT_EXEC_CONTEXT, cmd, this->rc_prototypes[cmd]); } @@ -560,8 +681,12 @@ readline_context::readline_context(std::string name, auto hpath = (config_dir / this->rc_name).string() + ".history"; read_history(hpath.c_str()); this->save(); +} - this->rc_append_character = ' '; +void +readline_context::set_history() +{ + history_set_history_state(&this->rc_history); } void @@ -690,7 +815,9 @@ readline_curses::start() } this->rc_command_pipe[RCF_MASTER] = sp[RCF_MASTER]; + this->rc_command_pipe[RCF_MASTER].close_on_exec(); this->rc_command_pipe[RCF_SLAVE] = sp[RCF_SLAVE]; + this->rc_command_pipe[RCF_SLAVE].close_on_exec(); if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1) { throw error(errno); @@ -699,21 +826,61 @@ readline_curses::start() if (this->vc_width > 0) { ws.ws_col = this->vc_width; } else if (this->vc_width < 0) { - ws.ws_col -= this->vc_left; + ws.ws_col -= this->vc_x; ws.ws_col += this->vc_width; } - if (openpty(this->rc_pty[RCF_MASTER].out(), - this->rc_pty[RCF_SLAVE].out(), - nullptr, - nullptr, - &ws) - < 0) + + auto openpt_res = auto_fd::openpt(O_NOCTTY | O_RDWR); + if (openpt_res.isErr()) { + log_error("readline_curses: cannot open pty -- %s", + openpt_res.unwrapErr().c_str()); + throw error(errno); + } + + this->rc_pty[RCF_MASTER] = openpt_res.unwrap(); + log_perror(grantpt(this->rc_pty[RCF_MASTER])); + log_perror(unlockpt(this->rc_pty[RCF_MASTER])); + char slave_path_str[PATH_MAX]; + if (ptsname_r( + this->rc_pty[RCF_MASTER], slave_path_str, sizeof(slave_path_str)) + == -1) { - perror("error: failed to open terminal(openpty)"); + perror("ptsname_r"); + throw error(errno); + } + + auto slave_path = ghc::filesystem::path(slave_path_str); + std::error_code ec; + if (!ghc::filesystem::exists(slave_path, ec)) { + log_warning("ptsname_r() result does not exist -- %s", slave_path_str); +#ifdef TIOCGPTN + int ptn = 0; + if (ioctl(this->rc_pty[RCF_MASTER], TIOCGPTN, &ptn) == 0) { + snprintf( + slave_path_str, sizeof(slave_path_str), "/dev/ttyp%d", ptn); + slave_path = ghc::filesystem::path(slave_path_str); + log_warning("... trying %s", slave_path.c_str()); + } +#endif + } + auto slave_open_res = lnav::filesystem::open_file( + slave_path, O_RDWR | O_NOCTTY | O_CLOEXEC); + if (slave_open_res.isErr()) { + log_error("open pseudo failed -- %s", + slave_open_res.unwrapErr().c_str()); + throw error(errno); + } + this->rc_pty[RCF_SLAVE] = slave_open_res.unwrap(); + + if (ioctl(this->rc_pty[RCF_SLAVE], TIOCSWINSZ, &ws) == -1) { throw error(errno); } + this->rc_pty[RCF_MASTER].close_on_exec(); + this->rc_pty[RCF_SLAVE].close_on_exec(); + if ((this->rc_child = fork()) == -1) { + log_error("fork() failed -- %s", strerror(errno)); throw error(errno); } @@ -731,7 +898,7 @@ readline_curses::start() signal(SIGALRM, sigalrm); signal(SIGWINCH, sigwinch); - signal(SIGINT, sigterm); + signal(SIGINT, SIG_IGN); signal(SIGTERM, sigterm); dup2(this->rc_pty[RCF_SLAVE], STDIN_FILENO); @@ -743,6 +910,7 @@ readline_curses::start() using_history(); stifle_history(HISTORY_SIZE); + rl_add_defun("lnav-forward-complete", lnav_forward_complete, -1); rl_add_defun("rubout-char-or-abort", rubout_char_or_abort, '\b'); rl_add_defun("alt-done", alt_done_func, '\x0a'); // rl_add_defun("command-complete", readline_context::command_complete, @@ -750,7 +918,10 @@ readline_curses::start() for (const auto* init_cmd : RL_INIT) { snprintf(buffer, sizeof(buffer), "%s", init_cmd); - rl_parse_and_bind(buffer); /* NOTE: buffer is modified */ + /* NOTE: buffer is modified */ + if (rl_parse_and_bind(buffer)) { + log_error("rl_parse_and_bind(%s) failed", init_cmd); + } } child_this = this; @@ -767,6 +938,8 @@ readline_curses::start() maxfd = std::max(STDIN_FILENO, this->rc_command_pipe[RCF_SLAVE].get()); + static uint64_t last_h1, last_h2; + while (looping) { fd_set ready_rfds; int rc; @@ -785,8 +958,6 @@ readline_curses::start() } } else { if (FD_ISSET(STDIN_FILENO, &ready_rfds)) { - static uint64_t last_h1, last_h2; - struct itimerval itv; itv.it_value.tv_sec = 0; @@ -794,7 +965,6 @@ readline_curses::start() itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; setitimer(ITIMER_REAL, &itv, nullptr); - rl_callback_read_char(); if (RL_ISSTATE(RL_STATE_DONE) && !got_line) { got_line = 1; @@ -842,14 +1012,17 @@ readline_curses::start() if (h1 == last_h1 && h2 == last_h2) { // do nothing - } else if (sendcmd(this->rc_command_pipe[RCF_SLAVE], - complete_done ? 'l' : 'c', - rl_line_buffer, - rl_end) - != 0) - { - perror("line: write failed"); - _exit(1); + } else { + rc_local_suggestion.clear(); + if (sendcmd(this->rc_command_pipe[RCF_SLAVE], + complete_done ? 'l' : 'c', + rl_line_buffer, + rl_end) + != 0) + { + perror("line: write failed"); + _exit(1); + } } last_h1 = h1; last_h2 = h2; @@ -862,7 +1035,7 @@ readline_curses::start() } } if (FD_ISSET(this->rc_command_pipe[RCF_SLAVE], &ready_rfds)) { - char msg[1024 + 1]; + char msg[8 + MAXPATHLEN + 1024]; if ((rc = recvstring(this->rc_command_pipe[RCF_SLAVE], msg, @@ -871,11 +1044,31 @@ readline_curses::start() { looping = false; } else { - int context, prompt_start = 0; + int context, prompt_start = 0, new_point = 0; char type[1024]; msg[rc] = '\0'; - if (sscanf(msg, "i:%d:%n", &rl_point, &prompt_start) == 1) { + if (startswith(msg, "cd:")) { + const char* cwd = &msg[3]; + + log_perror(chdir(cwd)); + } else if (startswith(msg, "sugg:")) { + rc_local_suggestion = &msg[5]; + } else if (sscanf(msg, "x:%d", &new_point) == 1) { + if (rl_prompt) { + new_point -= strlen(rl_prompt); + } + if (new_point < 0) { + new_point = 0; + } + if (new_point > rl_end) { + new_point = rl_end; + } + rl_point = new_point; + rl_redisplay(); + } else if (sscanf(msg, "i:%d:%n", &rl_point, &prompt_start) + == 1) + { const char* initial = &msg[prompt_start]; rl_extend_line_buffer(strlen(initial) + 1); @@ -978,6 +1171,11 @@ readline_curses::start() this->rc_contexts[context]->rem_possibility( std::string(type), std::string(&msg[prompt_start])); + } else if (sscanf(msg, "ah:%d:%n", &context, &prompt_start) + == 1) + { + this->rc_contexts[context]->set_history(); + add_history(&msg[prompt_start]); } else if (sscanf(msg, "cpre:%d", &context) == 1) { this->rc_contexts[context]->rc_prefixes.clear(); } else if (sscanf(msg, "cp:%d:%s", &context, type)) { @@ -1020,6 +1218,7 @@ readline_curses::start() struct winsize new_ws; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &new_ws) == -1) { + log_error("ioctl() failed -- %s", strerror(errno)); throw error(errno); } got_winch = 0; @@ -1110,6 +1309,23 @@ readline_curses::line_ready(const char* line) } void +readline_curses::append_to_history(int context, const std::string& line) +{ + if (line.empty()) { + return; + } + + char buffer[2048]; + snprintf(buffer, sizeof(buffer), "ah:%d:%s", context, line.c_str()); + if (sendstring( + this->rc_command_pipe[RCF_MASTER], buffer, strlen(buffer) + 1) + == -1) + { + perror("add_possibility: write failed"); + } +} + +void readline_curses::check_poll_set(const std::vector<struct pollfd>& pollfds) { int rc; @@ -1119,10 +1335,10 @@ readline_curses::check_poll_set(const std::vector<struct pollfd>& pollfds) rc = read(this->rc_pty[RCF_MASTER], buffer, sizeof(buffer)); if (rc > 0) { - int old_x = this->vc_x; + int old_x = this->vc_cursor_x; this->map_output(buffer, rc); - if (this->vc_x != old_x) { + if (this->vc_cursor_x != old_x) { this->rc_change(this); } } @@ -1205,9 +1421,10 @@ readline_curses::check_poll_set(const std::vector<struct pollfd>& pollfds) this->rc_blur(this); break; - case 'l': + case 'l': { this->rc_line_buffer = &msg[2]; if (this->rc_active_context != -1) { + this->rc_suggestion.clear(); this->rc_change(this); } this->rc_matches.clear(); @@ -1215,9 +1432,11 @@ readline_curses::check_poll_set(const std::vector<struct pollfd>& pollfds) this->rc_display_match(this); } break; + } case 'c': this->rc_line_buffer = &msg[2]; + this->rc_suggestion.clear(); this->rc_change(this); this->rc_display_match(this); break; @@ -1247,12 +1466,21 @@ readline_curses::focus(int context, const std::string& prompt, const std::string& initial) { - char buffer[1024]; + char cwd[MAXPATHLEN + 1024]; + char buffer[8 + sizeof(cwd)]; curs_set(1); this->rc_active_context = context; + getcwd(cwd, sizeof(cwd)); + snprintf(buffer, sizeof(buffer), "cd:%s", cwd); + if (sendstring( + this->rc_command_pipe[RCF_MASTER], buffer, strlen(buffer) + 1) + == -1) + { + perror("focus: write failed"); + } snprintf(buffer, sizeof(buffer), "f:%d:%s", context, prompt.c_str()); if (sendstring( this->rc_command_pipe[RCF_MASTER], buffer, strlen(buffer) + 1) @@ -1260,8 +1488,13 @@ readline_curses::focus(int context, { perror("focus: write failed"); } - wmove(this->vc_window, this->get_actual_y(), this->vc_left); - wclrtoeol(this->vc_window); + auto al = attr_line_t(); + al.append(lnav::roles::suggestion(this->rc_suggestion)); + view_curses::mvwattrline(this->vc_window, + this->get_actual_y(), + this->vc_x, + al, + line_range{0, (int) this->get_actual_width()}); if (!initial.empty()) { this->rewrite_line(initial.size(), initial); } @@ -1284,11 +1517,27 @@ readline_curses::rewrite_line(int pos, const std::string& value) } void +readline_curses::set_suggestion(const std::string& value) +{ + char buffer[1024]; + + snprintf(buffer, sizeof(buffer), "sugg:%s", value.c_str()); + if (sendstring( + this->rc_command_pipe[RCF_MASTER], buffer, strlen(buffer) + 1) + == -1) + { + perror("set_suggestion: write failed"); + } + this->rc_suggestion = value; + this->set_needs_update(); +} + +void readline_curses::abort() { char buffer[1024]; - this->vc_x = 0; + this->vc_cursor_x = 0; snprintf(buffer, sizeof(buffer), "a"); if (sendstring(this->rc_command_pipe[RCF_MASTER], buffer, strlen(buffer)) == -1) @@ -1393,11 +1642,11 @@ readline_curses::clear_possibilities(int context, std::string type) } } -void +bool readline_curses::do_update() { if (!this->vc_visible || this->vc_window == nullptr) { - return; + return false; } auto actual_width = this->get_actual_width(); @@ -1407,7 +1656,7 @@ readline_curses::do_update() attr_line_t alt_al; auto& vc = view_colors::singleton(); - wmove(this->vc_window, this->get_actual_y(), this->vc_left); + wmove(this->vc_window, this->get_actual_y(), this->vc_x); auto attrs = vc.attrs_for_role(role_t::VCR_TEXT); wattr_set(this->vc_window, attrs.ta_attrs, @@ -1435,35 +1684,58 @@ readline_curses::do_update() lr.lr_end = this->rc_value.length(); view_curses::mvwattrline(this->vc_window, this->get_actual_y(), - this->vc_left, + this->vc_x, this->rc_value, lr); - this->set_x(0); + this->set_cursor_x(0); } if (this->rc_active_context != -1) { - readline_context* rc = this->rc_contexts[this->rc_active_context]; - readline_highlighter_t hl = rc->get_highlighter(); - attr_line_t al = this->vc_line; + auto* rc = this->rc_contexts[this->rc_active_context]; + auto hl = rc->get_highlighter(); + auto al = this->vc_line; if (hl != nullptr) { - hl(al, this->vc_left + this->vc_x); + hl(al, this->vc_x + this->vc_cursor_x); } + al.append(lnav::roles::suggestion(this->rc_suggestion)); view_curses::mvwattrline(this->vc_window, this->get_actual_y(), - this->vc_left, + this->vc_x, al, line_range{0, (int) actual_width}); - wmove( - this->vc_window, this->get_actual_y(), this->vc_left + this->vc_x); + wmove(this->vc_window, + this->get_actual_y(), + this->vc_x + this->vc_cursor_x); + } + + return true; +} + +bool +readline_curses::handle_mouse(mouse_event& me) +{ + if (this->rc_active_context == -1) { + return false; + } + + char buffer[32]; + + snprintf(buffer, sizeof(buffer), "x:%d", me.me_x); + if (sendstring( + this->rc_command_pipe[RCF_MASTER], buffer, strlen(buffer) + 1) + == -1) + { + perror("handle_mouse: write failed"); } + return true; } std::string readline_curses::get_match_string() const { - auto len = std::min((size_t) this->vc_x, this->rc_line_buffer.size()) + auto len = std::min((size_t) this->vc_cursor_x, this->rc_line_buffer.size()) - this->rc_match_start; auto* context = this->get_active_context(); @@ -1520,15 +1792,17 @@ readline_curses::window_change() struct winsize ws; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1) { + log_error("ioctl() failed -- %s", strerror(errno)); throw error(errno); } if (this->vc_width > 0) { ws.ws_col = this->vc_width; } else if (this->vc_width < 0) { - ws.ws_col -= this->vc_left; + ws.ws_col -= this->vc_x; ws.ws_col += this->vc_width; } if (ioctl(this->rc_pty[RCF_MASTER], TIOCSWINSZ, &ws) == -1) { + log_error("ioctl() failed -- %s", strerror(errno)); throw error(errno); } kill(this->rc_child, SIGWINCH); |