mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-01 17:39:46 +08:00
Thread a parser into reader
Eliminates uses of principal_parser
This commit is contained in:
parent
7ed1022cf4
commit
d5f2d472d0
|
@ -316,7 +316,7 @@ static int builtin_breakpoint(parser_t &parser, io_streams_t &streams, wchar_t *
|
|||
}
|
||||
|
||||
const block_t *bpb = parser.push_block(block_t::breakpoint_block());
|
||||
reader_read(STDIN_FILENO, streams.io_chain ? *streams.io_chain : io_chain_t());
|
||||
reader_read(parser, STDIN_FILENO, streams.io_chain ? *streams.io_chain : io_chain_t());
|
||||
parser.pop_block(bpb);
|
||||
return parser.get_last_status();
|
||||
}
|
||||
|
|
|
@ -205,7 +205,7 @@ static int read_interactive(parser_t &parser, wcstring &buff, int nchars, bool s
|
|||
const auto &vars = parser.vars();
|
||||
wcstring read_history_ID = history_session_id(vars);
|
||||
if (!read_history_ID.empty()) read_history_ID += L"_read";
|
||||
reader_push(read_history_ID);
|
||||
reader_push(parser, read_history_ID);
|
||||
|
||||
reader_set_left_prompt(prompt);
|
||||
reader_set_right_prompt(right_prompt);
|
||||
|
|
|
@ -83,7 +83,7 @@ int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
null_terminated_array_t<wchar_t>::to_list(argv + optind + (argc == optind ? 0 : 1));
|
||||
parser.vars().set_argv(std::move(argv_list));
|
||||
|
||||
retval = reader_read(fd, streams.io_chain ? *streams.io_chain : io_chain_t());
|
||||
retval = reader_read(parser, fd, streams.io_chain ? *streams.io_chain : io_chain_t());
|
||||
|
||||
parser.pop_block(sb);
|
||||
|
||||
|
|
|
@ -451,7 +451,7 @@ int main(int argc, char **argv) {
|
|||
reader_set_end_loop(false);
|
||||
} else if (my_optind == argc) {
|
||||
// Implicitly interactive mode.
|
||||
res = reader_read(STDIN_FILENO, {});
|
||||
res = reader_read(parser, STDIN_FILENO, {});
|
||||
} else {
|
||||
char *file = *(argv + (my_optind++));
|
||||
int fd = open(file, O_RDONLY);
|
||||
|
@ -471,7 +471,7 @@ int main(int argc, char **argv) {
|
|||
wcstring rel_filename = str2wcstring(file);
|
||||
scoped_push<const wchar_t *> filename_push{&ld.current_filename,
|
||||
intern(rel_filename.c_str())};
|
||||
res = reader_read(fd, {});
|
||||
res = reader_read(parser, fd, {});
|
||||
if (res) {
|
||||
debug(1, _(L"Error while reading file %ls\n"),
|
||||
ld.current_filename ? ld.current_filename : _(L"Standard input"));
|
||||
|
|
|
@ -148,7 +148,7 @@ namespace {
|
|||
|
||||
/// Test if the given string contains error. Since this is the error detection for general purpose,
|
||||
/// there are no invalid strings, so this function always returns false.
|
||||
parser_test_error_bits_t default_test(const wcstring &b) {
|
||||
parser_test_error_bits_t default_test(parser_t &parser, const wcstring &b) {
|
||||
UNUSED(b);
|
||||
return 0;
|
||||
}
|
||||
|
@ -323,6 +323,8 @@ struct readline_loop_state_t;
|
|||
/// reader_readline() calls are nested. This happens when the 'read' builtin is used.
|
||||
class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
||||
public:
|
||||
/// The parser being used.
|
||||
std::shared_ptr<parser_t> parser_ref;
|
||||
/// String containing the whole current commandline.
|
||||
editable_line_t command_line;
|
||||
/// String containing the autosuggestion.
|
||||
|
@ -420,14 +422,14 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
|
|||
void repaint_if_needed();
|
||||
|
||||
/// Return the variable set used for e.g. command duration.
|
||||
env_stack_t &vars() { return parser_t::principal_parser().vars(); }
|
||||
env_stack_t &vars() { return parser_ref->vars(); }
|
||||
const env_stack_t &vars() const { return parser_ref->vars(); }
|
||||
|
||||
/// Hackish access to the parser. TODO: rationalize this.
|
||||
parser_t &parser() { return parser_t::principal_parser(); }
|
||||
/// Access the parser.
|
||||
parser_t &parser() { return *parser_ref; }
|
||||
|
||||
const env_stack_t &vars() const { return parser_t::principal_parser().vars(); }
|
||||
|
||||
reader_data_t(history_t *hist) : history(hist) {}
|
||||
reader_data_t(std::shared_ptr<parser_t> parser, history_t *hist)
|
||||
: parser_ref(std::move(parser)), history(hist) {}
|
||||
|
||||
void update_buff_pos(editable_line_t *el, size_t buff_pos);
|
||||
void repaint();
|
||||
|
@ -1238,9 +1240,9 @@ void reader_data_t::completion_insert(const wchar_t *val, complete_flags_t flags
|
|||
// Returns a function that can be invoked (potentially
|
||||
// on a background thread) to determine the autosuggestion
|
||||
static std::function<autosuggestion_result_t(void)> get_autosuggestion_performer(
|
||||
const wcstring &search_string, size_t cursor_pos, history_t *history) {
|
||||
parser_t &parser, const wcstring &search_string, size_t cursor_pos, history_t *history) {
|
||||
const unsigned int generation_count = read_generation_count();
|
||||
auto vars = parser_t::principal_parser().vars().snapshot();
|
||||
auto vars = parser.vars().snapshot();
|
||||
const wcstring working_directory = vars->get_pwd_slash();
|
||||
// TODO: suspicious use of 'history' here
|
||||
// This is safe because histories are immortal, but perhaps
|
||||
|
@ -1331,7 +1333,7 @@ void reader_data_t::update_autosuggestion() {
|
|||
autosuggestion.clear();
|
||||
if (can_autosuggest()) {
|
||||
const editable_line_t *el = active_edit_line();
|
||||
auto performer = get_autosuggestion_performer(el->text, el->position, history);
|
||||
auto performer = get_autosuggestion_performer(parser(), el->text, el->position, history);
|
||||
auto shared_this = this->shared_from_this();
|
||||
iothread_perform(performer, [shared_this](autosuggestion_result_t result) {
|
||||
shared_this->autosuggest_completed(std::move(result));
|
||||
|
@ -1943,7 +1945,7 @@ void reader_run_command(parser_t &parser, const wcstring &cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
parser_test_error_bits_t reader_shell_test(const wcstring &b) {
|
||||
parser_test_error_bits_t reader_shell_test(parser_t &parser, const wcstring &b) {
|
||||
wcstring bstr = b;
|
||||
|
||||
// Append a newline, to act as a statement terminator.
|
||||
|
@ -1955,7 +1957,7 @@ parser_test_error_bits_t reader_shell_test(const wcstring &b) {
|
|||
|
||||
if (res & PARSER_TEST_ERROR) {
|
||||
wcstring error_desc;
|
||||
parser_t::principal_parser().get_backtrace(bstr, errors, error_desc);
|
||||
parser.get_backtrace(bstr, errors, error_desc);
|
||||
|
||||
// Ensure we end with a newline. Also add an initial newline, because it's likely the user
|
||||
// just hit enter and so there's junk on the current line.
|
||||
|
@ -2001,8 +2003,9 @@ void reader_data_t::highlight_complete(highlight_result_t result) {
|
|||
// Given text, bracket matching position, and whether IO is allowed,
|
||||
// return a function that performs highlighting. The function may be invoked on a background thread.
|
||||
static std::function<highlight_result_t(void)> get_highlight_performer(
|
||||
const wcstring &text, long match_highlight_pos, highlight_function_t highlight_func) {
|
||||
auto vars = parser_t::principal_parser().vars().snapshot();
|
||||
parser_t &parser, const wcstring &text, long match_highlight_pos,
|
||||
highlight_function_t highlight_func) {
|
||||
auto vars = parser.vars().snapshot();
|
||||
unsigned int generation_count = read_generation_count();
|
||||
return [=]() -> highlight_result_t {
|
||||
if (text.empty()) return {};
|
||||
|
@ -2034,7 +2037,7 @@ void reader_data_t::super_highlight_me_plenty(int match_highlight_pos_adjust, bo
|
|||
sanity_check();
|
||||
|
||||
auto highlight_performer = get_highlight_performer(
|
||||
el->text, match_highlight_pos, no_io ? highlight_shell_no_io : highlight_func);
|
||||
parser(), el->text, match_highlight_pos, no_io ? highlight_shell_no_io : highlight_func);
|
||||
if (no_io) {
|
||||
// Highlighting without IO, we just do it.
|
||||
highlight_complete(highlight_performer());
|
||||
|
@ -2083,9 +2086,9 @@ void reader_change_history(const wcstring &name) {
|
|||
}
|
||||
}
|
||||
|
||||
void reader_push(const wcstring &name) {
|
||||
void reader_push(parser_t &parser, const wcstring &name) {
|
||||
history_t *hist = &history_t::history_with_name(name);
|
||||
reader_data_stack.push_back(std::make_shared<reader_data_t>(hist));
|
||||
reader_data_stack.push_back(std::make_shared<reader_data_t>(parser.shared(), hist));
|
||||
reader_data_t *data = current_data();
|
||||
data->command_line_changed(&data->command_line);
|
||||
if (reader_data_stack.size() == 1) {
|
||||
|
@ -2222,9 +2225,8 @@ static relaxed_atomic_t<uint64_t> run_count{0};
|
|||
uint64_t reader_run_count() { return run_count; }
|
||||
|
||||
/// Read interactively. Read input from stdin while providing editing facilities.
|
||||
static int read_i() {
|
||||
parser_t &parser = parser_t::principal_parser();
|
||||
reader_push(history_session_id(parser.vars()));
|
||||
static int read_i(parser_t &parser) {
|
||||
reader_push(parser, history_session_id(parser.vars()));
|
||||
reader_set_complete_function(&complete);
|
||||
reader_set_highlight_function(&highlight_shell);
|
||||
reader_set_test_function(&reader_shell_test);
|
||||
|
@ -2413,7 +2415,7 @@ maybe_t<char_event_t> reader_data_t::read_normal_chars(readline_loop_state_t &rl
|
|||
|
||||
/// Handle a readline command \p c, updating the state \p rls.
|
||||
void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_state_t &rls) {
|
||||
const auto &vars = parser_t::principal_parser().vars();
|
||||
const auto &vars = this->vars();
|
||||
using rl = readline_cmd_t;
|
||||
switch (c) {
|
||||
// Go to beginning of line.
|
||||
|
@ -2460,10 +2462,10 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
|||
// may sometimes take a while but when switching the mode all we care about is the
|
||||
// mode-prompt.
|
||||
//
|
||||
// Because some users set `fish_mode_prompt` to an empty function and display the mode elsewhere,
|
||||
// we detect if the mode output is empty.
|
||||
// Because some users set `fish_mode_prompt` to an empty function and display the mode
|
||||
// elsewhere, we detect if the mode output is empty.
|
||||
exec_mode_prompt();
|
||||
if(!mode_prompt_buff.empty()) {
|
||||
if (!mode_prompt_buff.empty()) {
|
||||
s_reset(&screen, screen_reset_current_line_and_prompt);
|
||||
screen_reset_needed = false;
|
||||
repaint();
|
||||
|
@ -2547,9 +2549,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
|||
// std::fwprintf(stderr, L"Complete (%ls)\n", buffcpy.c_str());
|
||||
completion_request_flags_t complete_flags = {completion_request_t::descriptions,
|
||||
completion_request_t::fuzzy_match};
|
||||
// TODO: eliminate this principal_parser.
|
||||
complete_func(buffcpy, &rls.comp, complete_flags, vars,
|
||||
parser_t::principal_parser().shared());
|
||||
complete_func(buffcpy, &rls.comp, complete_flags, vars, parser_ref);
|
||||
|
||||
// Munge our completions.
|
||||
completions_sort_and_prioritize(&rls.comp);
|
||||
|
@ -2725,7 +2725,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
|||
}
|
||||
|
||||
// See if this command is valid.
|
||||
int command_test_result = test_func(el->text);
|
||||
int command_test_result = test_func(parser(), el->text);
|
||||
if (command_test_result == 0 || command_test_result == PARSER_TEST_INCOMPLETE) {
|
||||
// This command is valid, but an abbreviation may make it invalid. If so, we
|
||||
// will have to test again.
|
||||
|
@ -2733,7 +2733,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
|||
if (abbreviation_expanded) {
|
||||
// It's our reponsibility to rehighlight and repaint. But everything we do
|
||||
// below triggers a repaint.
|
||||
command_test_result = test_func(el->text.c_str());
|
||||
command_test_result = test_func(parser(), el->text.c_str());
|
||||
|
||||
// If the command is OK, then we're going to execute it. We still want to do
|
||||
// syntax highlighting, but a synchronous variant that performs no I/O, so
|
||||
|
@ -3257,7 +3257,8 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
|||
handle_readline_command(readline_cmd, rls);
|
||||
|
||||
if (command_ends_history_search(readline_cmd)) {
|
||||
// "cancel" means to abort the whole thing, other ending commands mean to finish the search.
|
||||
// "cancel" means to abort the whole thing, other ending commands mean to finish the
|
||||
// search.
|
||||
if (history_search.active() && readline_cmd == rl::cancel) {
|
||||
history_search.go_to_end();
|
||||
update_command_line_from_history_search();
|
||||
|
@ -3449,8 +3450,7 @@ bool reader_get_selection(size_t *start, size_t *len) {
|
|||
|
||||
/// Read non-interactively. Read input from stdin without displaying the prompt, using syntax
|
||||
/// highlighting. This is used for reading scripts and init files.
|
||||
static int read_ni(int fd, const io_chain_t &io) {
|
||||
parser_t &parser = parser_t::principal_parser();
|
||||
static int read_ni(parser_t &parser, int fd, const io_chain_t &io) {
|
||||
FILE *in_stream;
|
||||
wchar_t *buff = 0;
|
||||
std::vector<char> acc;
|
||||
|
@ -3524,7 +3524,7 @@ static int read_ni(int fd, const io_chain_t &io) {
|
|||
return res;
|
||||
}
|
||||
|
||||
int reader_read(int fd, const io_chain_t &io) {
|
||||
int reader_read(parser_t &parser, int fd, const io_chain_t &io) {
|
||||
int res;
|
||||
|
||||
// If reader_read is called recursively through the '.' builtin, we need to preserve
|
||||
|
@ -3546,7 +3546,7 @@ int reader_read(int fd, const io_chain_t &io) {
|
|||
}
|
||||
proc_push_interactive(inter);
|
||||
|
||||
res = shell_is_interactive() ? read_i() : read_ni(fd, io);
|
||||
res = shell_is_interactive() ? read_i(parser) : read_ni(parser, fd, io);
|
||||
|
||||
// If the exit command was called in a script, only exit the script, not the program.
|
||||
reader_set_end_loop(false);
|
||||
|
|
12
src/reader.h
12
src/reader.h
|
@ -47,7 +47,7 @@ class editable_line_t {
|
|||
};
|
||||
|
||||
/// Read commands from \c fd until encountering EOF.
|
||||
int reader_read(int fd, const io_chain_t &io);
|
||||
int reader_read(parser_t &parser, int fd, const io_chain_t &io);
|
||||
|
||||
/// Tell the shell whether it should exit after the currently running command finishes.
|
||||
void reader_set_end_loop(bool flag);
|
||||
|
@ -140,7 +140,7 @@ bool reader_thread_job_is_stale();
|
|||
maybe_t<wcstring> reader_readline(int nchars);
|
||||
|
||||
/// Push a new reader environment.
|
||||
void reader_push(const wcstring &name);
|
||||
void reader_push(parser_t &parser, const wcstring &name);
|
||||
|
||||
/// Return to previous reader environment.
|
||||
void reader_pop();
|
||||
|
@ -152,11 +152,11 @@ typedef void (*complete_function_t)(const wcstring &, std::vector<completion_t>
|
|||
void reader_set_complete_function(complete_function_t);
|
||||
|
||||
/// The type of a highlight function.
|
||||
typedef void (*highlight_function_t)(const wcstring &, std::vector<highlight_spec_t> &, size_t,
|
||||
wcstring_list_t *, const environment_t &vars);
|
||||
using highlight_function_t = void (*)(const wcstring &, std::vector<highlight_spec_t> &, size_t,
|
||||
wcstring_list_t *, const environment_t &vars);
|
||||
|
||||
/// Function type for testing if a string is valid for the reader to return.
|
||||
using test_function_t = parser_test_error_bits_t (*)(const wcstring &);
|
||||
using test_function_t = parser_test_error_bits_t (*)(parser_t &, const wcstring &);
|
||||
|
||||
/// Specify function for syntax highlighting. The function must take these arguments:
|
||||
///
|
||||
|
@ -198,7 +198,7 @@ bool reader_exit_forced();
|
|||
|
||||
/// Test if the given shell command contains errors. Uses parser_test for testing. Suitable for
|
||||
/// reader_set_test_function().
|
||||
parser_test_error_bits_t reader_shell_test(const wcstring &);
|
||||
parser_test_error_bits_t reader_shell_test(parser_t &parser, const wcstring &);
|
||||
|
||||
/// Test whether the interactive reader is in search mode.
|
||||
bool reader_is_in_search_mode();
|
||||
|
|
Loading…
Reference in New Issue
Block a user