Beispiel #1
0
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();
    }
}
Beispiel #2
0
/**
   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 );
}
Beispiel #3
0
/**
   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();

}
Beispiel #4
0
/**
   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();

}