void parser_t::expand_argument_list(const wcstring &arg_list_src, std::vector<completion_t> *output_arg_list) { assert(output_arg_list != NULL); expand_flags_t eflags = 0; if (! show_errors) eflags |= EXPAND_NO_DESCRIPTIONS; if (this->parser_type != PARSER_TYPE_GENERAL) eflags |= EXPAND_SKIP_CMDSUBST; /* Suppress calling proc_push_interactive off of the main thread. */ if (this->parser_type == PARSER_TYPE_GENERAL) { proc_push_interactive(0); } /* Parse the string as an argument list */ parse_node_tree_t tree; if (! parse_tree_from_string(arg_list_src, parse_flag_none, &tree, NULL /* errors */, symbol_freestanding_argument_list)) { /* Failed to parse. Here we expect to have reported any errors in test_args */ return; } /* Get the root argument list */ assert(! tree.empty()); const parse_node_t *arg_list = &tree.at(0); assert(arg_list->type == symbol_freestanding_argument_list); /* Extract arguments from it */ while (arg_list != NULL) { const parse_node_t *arg_node = tree.next_node_in_node_list(*arg_list, symbol_argument, &arg_list); if (arg_node != NULL) { const wcstring arg_src = arg_node->get_source(arg_list_src); if (expand_string(arg_src, output_arg_list, eflags, NULL) == EXPAND_ERROR) { /* Failed to expand a string */ break; } } } if (this->parser_type == PARSER_TYPE_GENERAL) { proc_pop_interactive(); } }
/** Evaluate the argument list (as supplied by complete -a) and insert any return matching completions. Matching is done using \c copy_strings_with_prefix, meaning the completion may contain wildcards. Logically, this is not always the right thing to do, but I have yet to come up with a case where this matters. \param str The string to complete. \param args The list of option arguments to be evaluated. \param desc Description of the completion \param comp_out The list into which the results will be inserted */ static void complete_from_args( const wchar_t *str, const wchar_t *args, const wchar_t *desc, array_list_t *comp_out, int flags ) { array_list_t possible_comp; al_init( &possible_comp ); proc_push_interactive(0); eval_args( args, &possible_comp ); proc_pop_interactive(); complete_strings( comp_out, str, desc, 0, &possible_comp, flags ); al_foreach( &possible_comp, &free ); al_destroy( &possible_comp ); }
/** Perform the specified event. Since almost all event firings will not be matched by even a single event handler, we make sure to optimize the 'no matches' path. This means that nothing is allocated/initialized unless needed. */ static void event_fire_internal(const event_t &event) { event_list_t fire; /* First we free all events that have been removed, but only if this invocation of event_fire_internal is not a recursive call. */ if (is_event <= 1) event_free_kills(); if (events.empty()) return; /* Then we iterate over all events, adding events that should be fired to a second list. We need to do this in a separate step since an event handler might call event_remove or event_add_handler, which will change the contents of the \c events list. */ for (size_t i=0; i<events.size(); i++) { event_t *criterion = events.at(i); /* Check if this event is a match */ if (event_match(*criterion, event)) { fire.push_back(criterion); } } /* No matches. Time to return. */ if (fire.empty()) return; if (signal_is_blocked()) { /* Fix for https://github.com/fish-shell/fish-shell/issues/608. Don't run event handlers while signals are blocked. */ event_t *heap_event = new event_t(event); input_common_add_callback(fire_event_callback, heap_event); return; } /* Iterate over our list of matching events */ for (size_t i=0; i<fire.size(); i++) { event_t *criterion = fire.at(i); int prev_status; /* Check if this event has been removed, if so, dont fire it */ if (event_is_killed(*criterion)) continue; /* Fire event */ wcstring buffer = criterion->function_name; for (size_t j=0; j < event.arguments.size(); j++) { wcstring arg_esc = escape_string(event.arguments.at(j), 1); buffer += L" "; buffer += arg_esc; } // debug( 1, L"Event handler fires command '%ls'", buffer.c_str() ); /* Event handlers are not part of the main flow of code, so they are marked as non-interactive */ proc_push_interactive(0); prev_status = proc_get_last_status(); parser_t &parser = parser_t::principal_parser(); block_t *block = new event_block_t(event); parser.push_block(block); parser.eval(buffer, io_chain_t(), TOP); parser.pop_block(); proc_pop_interactive(); proc_set_last_status(prev_status); } /* Free killed events */ if (is_event <= 1) event_free_kills(); }
/** Perform the specified event. Since almost all event firings will not be matched by even a single event handler, we make sure to optimize the 'no matches' path. This means that nothing is allocated/initialized unless needed. */ static void event_fire_internal(const event_t *event) { size_t i, j; event_list_t fire; /* First we free all events that have been removed */ event_free_kills(); if (events.empty()) return; /* Then we iterate over all events, adding events that should be fired to a second list. We need to do this in a separate step since an event handler might call event_remove or event_add_handler, which will change the contents of the \c events list. */ for (i=0; i<events.size(); i++) { event_t *criterion = events.at(i); /* Check if this event is a match */ if (event_match(criterion, event)) { fire.push_back(criterion); } } /* No matches. Time to return. */ if (fire.empty()) return; /* Iterate over our list of matching events */ for (i=0; i<fire.size(); i++) { event_t *criterion = fire.at(i); int prev_status; /* Check if this event has been removed, if so, dont fire it */ if (event_is_killed(criterion)) continue; /* Fire event */ wcstring buffer = criterion->function_name; if (event->arguments.get()) { for (j=0; j< event->arguments->size(); j++) { wcstring arg_esc = escape_string(event->arguments->at(j), 1); buffer += L" "; buffer += arg_esc; } } // debug( 1, L"Event handler fires command '%ls'", buffer.c_str() ); /* Event handlers are not part of the main flow of code, so they are marked as non-interactive */ proc_push_interactive(0); prev_status = proc_get_last_status(); parser_t &parser = parser_t::principal_parser(); block_t *block = new event_block_t(event); parser.push_block(block); parser.eval(buffer, io_chain_t(), TOP); parser.pop_block(); proc_pop_interactive(); proc_set_last_status(prev_status); } /* Free killed events */ event_free_kills(); }