Пример #1
0
/**
   The commandline builtin. It is used for specifying a new value for
   the commandline.
*/
static int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
{
    wgetopter_t w;
    int buffer_part=0;
    int cut_at_cursor=0;

    int argc = builtin_count_args(argv);
    int append_mode=0;

    int function_mode = 0;
    int selection_mode = 0;

    int tokenize = 0;

    int cursor_mode = 0;
    int line_mode = 0;
    int search_mode = 0;
    int paging_mode = 0;
    const wchar_t *begin = NULL, *end = NULL;
    
    scoped_push<const wchar_t *> saved_current_buffer(&current_buffer);
    scoped_push<size_t> saved_current_cursor_pos(&current_cursor_pos);
    
    wcstring transient_commandline;
    if (get_top_transient(&transient_commandline))
    {
        current_buffer = transient_commandline.c_str();
        current_cursor_pos = transient_commandline.size();
    }
    else
    {
        current_buffer = reader_get_buffer();
        current_cursor_pos = reader_get_cursor_pos();
    }

    if (!get_buffer())
    {
        if (is_interactive_session)
        {
            /*
              Prompt change requested while we don't have
              a prompt, most probably while reading the
              init files. Just ignore it.
            */
            return 1;
        }

        streams.err.append(argv[0]);
        streams.err.append(L": Can not set commandline in non-interactive mode\n");
        builtin_print_help(parser, streams, argv[0], streams.err);
        return 1;
    }

    w.woptind=0;

    while (1)
    {
        static const struct woption
                long_options[] =
        {
            { L"append", no_argument, 0, 'a' },
            { L"insert", no_argument, 0, 'i' },
            { L"replace", no_argument, 0, 'r' },
            { L"current-job", no_argument, 0, 'j' },
            { L"current-process", no_argument, 0, 'p' },
            { L"current-token", no_argument, 0, 't' },
            { L"current-buffer", no_argument, 0, 'b' },
            { L"cut-at-cursor", no_argument, 0, 'c' },
            { L"function", no_argument, 0, 'f' },
            { L"tokenize", no_argument, 0, 'o' },
            { L"help", no_argument, 0, 'h' },
            { L"input", required_argument, 0, 'I' },
            { L"cursor", no_argument, 0, 'C' },
            { L"line", no_argument, 0, 'L' },
            { L"search-mode", no_argument, 0, 'S' },
            { L"selection", no_argument, 0, 's' },
            { L"paging-mode", no_argument, 0, 'P' },
            { 0, 0, 0, 0 }
        };

        int opt_index = 0;

        int opt = w.wgetopt_long(argc,
                                 argv,
                                 L"abijpctwforhI:CLSsP",
                                 long_options,
                                 &opt_index);
        if (opt == -1)
            break;

        switch (opt)
        {
            case 0:
                if (long_options[opt_index].flag != 0)
                    break;
                streams.err.append_format(BUILTIN_ERR_UNKNOWN,
                              argv[0],
                              long_options[opt_index].name);
                builtin_print_help(parser, streams, argv[0], streams.err);

                return 1;

            case L'a':
                append_mode = APPEND_MODE;
                break;

            case L'b':
                buffer_part = STRING_MODE;
                break;


            case L'i':
                append_mode = INSERT_MODE;
                break;

            case L'r':
                append_mode = REPLACE_MODE;
                break;

            case 'c':
                cut_at_cursor=1;
                break;

            case 't':
                buffer_part = TOKEN_MODE;
                break;

            case 'j':
                buffer_part = JOB_MODE;
                break;

            case 'p':
                buffer_part = PROCESS_MODE;
                break;

            case 'f':
                function_mode=1;
                break;

            case 'o':
                tokenize=1;
                break;

            case 'I':
                current_buffer = w.woptarg;
                current_cursor_pos = wcslen(w.woptarg);
                break;

            case 'C':
                cursor_mode = 1;
                break;

            case 'L':
                line_mode = 1;
                break;

            case 'S':
                search_mode = 1;
                break;

            case 's':
                selection_mode = 1;
                break;

            case 'P':
                paging_mode = 1;
                break;

            case 'h':
                builtin_print_help(parser, streams, argv[0], streams.out);
                return 0;

            case L'?':
                builtin_unknown_option(parser, streams, argv[0], argv[w.woptind-1]);
                return 1;
        }
    }

    if (function_mode)
    {
        int i;

        /*
          Check for invalid switch combinations
        */
        if (buffer_part || cut_at_cursor || append_mode || tokenize || cursor_mode || line_mode || search_mode || paging_mode)
        {
            streams.err.append_format(BUILTIN_ERR_COMBO,
                          argv[0]);

            builtin_print_help(parser, streams, argv[0], streams.err);
            return 1;
        }


        if (argc == w.woptind)
        {
            streams.err.append_format(BUILTIN_ERR_MISSING,
                          argv[0]);

            builtin_print_help(parser, streams, argv[0], streams.err);
            return 1;
        }
        for (i=w.woptind; i<argc; i++)
        {
            wchar_t c = input_function_get_code(argv[i]);
            if (c != INPUT_CODE_NONE)
            {
                /*
                  input_unreadch inserts the specified keypress or
                  readline function at the back of the queue of unused
                  keypresses
                */
                input_queue_ch(c);
            }
            else
            {
                streams.err.append_format(_(L"%ls: Unknown input function '%ls'\n"),
                              argv[0],
                              argv[i]);
                builtin_print_help(parser, streams, argv[0], streams.err);
                return 1;
            }
        }

        return 0;
    }

    if (selection_mode)
    {
        size_t start, len;
        const wchar_t *buffer = reader_get_buffer();
        if (reader_get_selection(&start, &len))
        {
            streams.out.append(buffer + start, len);
        }
        return 0;
    }

    /*
      Check for invalid switch combinations
    */
    if ((search_mode || line_mode || cursor_mode || paging_mode) && (argc-w.woptind > 1))
    {

        streams.err.append_format(argv[0],
                      L": Too many arguments\n",
                      NULL);
        builtin_print_help(parser, streams, argv[0], streams.err);
        return 1;
    }

    if ((buffer_part || tokenize || cut_at_cursor) && (cursor_mode || line_mode || search_mode || paging_mode))
    {
        streams.err.append_format(BUILTIN_ERR_COMBO,
                      argv[0]);

        builtin_print_help(parser, streams, argv[0], streams.err);
        return 1;
    }


    if ((tokenize || cut_at_cursor) && (argc-w.woptind))
    {
        streams.err.append_format(BUILTIN_ERR_COMBO2,
                      argv[0],
                      L"--cut-at-cursor and --tokenize can not be used when setting the commandline");


        builtin_print_help(parser, streams, argv[0], streams.err);
        return 1;
    }

    if (append_mode && !(argc-w.woptind))
    {
        streams.err.append_format(BUILTIN_ERR_COMBO2,
                      argv[0],
                      L"insertion mode switches can not be used when not in insertion mode");

        builtin_print_help(parser, streams, argv[0], streams.err);
        return 1;
    }

    /*
      Set default modes
    */
    if (!append_mode)
    {
        append_mode = REPLACE_MODE;
    }

    if (!buffer_part)
    {
        buffer_part = STRING_MODE;
    }

    if (cursor_mode)
    {
        if (argc-w.woptind)
        {
            wchar_t *endptr;
            long new_pos;
            errno = 0;

            new_pos = wcstol(argv[w.woptind], &endptr, 10);
            if (*endptr || errno)
            {
                streams.err.append_format(BUILTIN_ERR_NOT_NUMBER,
                              argv[0],
                              argv[w.woptind]);
                builtin_print_help(parser, streams, argv[0], streams.err);
            }

            current_buffer = reader_get_buffer();
            new_pos = maxi(0L, mini(new_pos, (long)wcslen(current_buffer)));
            reader_set_buffer(current_buffer, (size_t)new_pos);
            return 0;
        }
        else
        {
            streams.out.append_format( L"%lu\n", (unsigned long)reader_get_cursor_pos());
            return 0;
        }

    }

    if (line_mode)
    {
        size_t pos = reader_get_cursor_pos();
        const wchar_t *buff = reader_get_buffer();
        streams.out.append_format( L"%lu\n", (unsigned long)parse_util_lineno(buff, pos));
        return 0;

    }

    if (search_mode)
    {
        return ! reader_search_mode();
    }

    if (paging_mode)
    {
        return ! reader_has_pager_contents();
    }


    switch (buffer_part)
    {
        case STRING_MODE:
        {
            begin = get_buffer();
            end = begin+wcslen(begin);
            break;
        }

        case PROCESS_MODE:
        {
            parse_util_process_extent(get_buffer(),
                                      get_cursor_pos(),
                                      &begin,
                                      &end);
            break;
        }

        case JOB_MODE:
        {
            parse_util_job_extent(get_buffer(),
                                  get_cursor_pos(),
                                  &begin,
                                  &end);
            break;
        }

        case TOKEN_MODE:
        {
            parse_util_token_extent(get_buffer(),
                                    get_cursor_pos(),
                                    &begin,
                                    &end,
                                    0, 0);
            break;
        }

    }

    switch (argc-w.woptind)
    {
        case 0:
        {
            write_part(begin, end, cut_at_cursor, tokenize, streams);
            break;
        }

        case 1:
        {
            replace_part(begin, end, argv[w.woptind], append_mode);
            break;
        }

        default:
        {
            wcstring sb = argv[w.woptind];
            int i;

            for (i=w.woptind+1; i<argc; i++)
            {
                sb.push_back(L'\n');
                sb.append(argv[i]);
            }

            replace_part(begin, end, sb.c_str(), append_mode);

            break;
        }
    }

    return 0;
}
Пример #2
0
/**
   The commandline builtin. It is used for specifying a new value for
   the commandline.
*/
static int builtin_commandline( wchar_t **argv )
{

	int buffer_part=0;
	int cut_at_cursor=0;

	int argc = builtin_count_args( argv );
	int append_mode=0;

	int function_mode = 0;

	int tokenize = 0;

	int cursor_mode = 0;
	int line_mode = 0;
	int search_mode = 0;
	wchar_t *begin, *end;

	current_buffer = (wchar_t *)builtin_complete_get_temporary_buffer();
	if( current_buffer )
	{
		current_cursor_pos = wcslen( current_buffer );
	}
	else
	{
		current_buffer = reader_get_buffer();
		current_cursor_pos = reader_get_cursor_pos();
	}

	if( !get_buffer() )
	{
		if (is_interactive_session)
		{
			/*
			  Prompt change requested while we don't have
			  a prompt, most probably while reading the
			  init files. Just ignore it.
			*/
			return 1;
		}

		sb_append( sb_err,
			    argv[0],
			    L": Can not set commandline in non-interactive mode\n",
			    (void *)0 );
		builtin_print_help( argv[0], sb_err );
		return 1;
	}

	woptind=0;

	while( 1 )
	{
		static const struct woption
			long_options[] =
			{
				{
					L"append", no_argument, 0, 'a'
				}
				,
				{
					L"insert", no_argument, 0, 'i'
				}
				,
				{
					L"replace", no_argument, 0, 'r'
				}
				,
				{
					L"current-job", no_argument, 0, 'j'
				}
				,
				{
					L"current-process", no_argument, 0, 'p'
				}
				,
				{
					L"current-token", no_argument, 0, 't'
				}
				,
				{
					L"current-buffer", no_argument, 0, 'b'
				}
				,
				{
					L"cut-at-cursor", no_argument, 0, 'c'
				}
				,
				{
					L"function", no_argument, 0, 'f'
				}
				,
				{
					L"tokenize", no_argument, 0, 'o'
				}
				,
				{
					L"help", no_argument, 0, 'h'
				}
				,
				{
					L"input", required_argument, 0, 'I'
				}
				,
				{
					L"cursor", no_argument, 0, 'C'
				}
				,
				{
					L"line", no_argument, 0, 'L'
				}
				,
				{
					L"search-mode", no_argument, 0, 'S'
				}
				,
				{
					0, 0, 0, 0
				}
			}
		;

		int opt_index = 0;

		int opt = wgetopt_long( argc,
								argv,
								L"abijpctwforhI:CLS",
								long_options,
								&opt_index );
		if( opt == -1 )
			break;

		switch( opt )
		{
			case 0:
				if(long_options[opt_index].flag != 0)
					break;
                sb_printf( sb_err,
                           BUILTIN_ERR_UNKNOWN,
                           argv[0],
                           long_options[opt_index].name );
				builtin_print_help( argv[0], sb_err );

				return 1;

			case L'a':
				append_mode = APPEND_MODE;
				break;

			case L'b':
				buffer_part = STRING_MODE;
				break;


			case L'i':
				append_mode = INSERT_MODE;
				break;

			case L'r':
				append_mode = REPLACE_MODE;
				break;

			case 'c':
				cut_at_cursor=1;
				break;

			case 't':
				buffer_part = TOKEN_MODE;
				break;

			case 'j':
				buffer_part = JOB_MODE;
				break;

			case 'p':
				buffer_part = PROCESS_MODE;
				break;

			case 'f':
				function_mode=1;
				break;

			case 'o':
				tokenize=1;
				break;

			case 'I':
				current_buffer = woptarg;
				current_cursor_pos = wcslen( woptarg );
				break;

			case 'C':
				cursor_mode = 1;
				break;

			case 'L':
				line_mode = 1;
				break;

			case 'S':
				search_mode = 1;
				break;

			case 'h':
				builtin_print_help( argv[0], sb_out );
				return 0;

			case L'?':
				builtin_unknown_option( argv[0], argv[woptind-1] );
				return 1;
		}
	}

	if( function_mode )
	{
		int i;

		/*
		  Check for invalid switch combinations
		*/
		if( buffer_part || cut_at_cursor || append_mode || tokenize || cursor_mode || line_mode || search_mode )
		{
			sb_printf(sb_err,
					  BUILTIN_ERR_COMBO,
					  argv[0] );

			builtin_print_help( argv[0], sb_err );
			return 1;
		}


		if( argc == woptind )
		{
			sb_printf( sb_err,
					   BUILTIN_ERR_MISSING,
					   argv[0] );

			builtin_print_help( argv[0], sb_err );
			return 1;
 		}
		for( i=woptind; i<argc; i++ )
		{
			wint_t c = input_function_get_code( argv[i] );
			if( c != -1 )
			{
				/*
				  input_unreadch inserts the specified keypress or
				  readline function at the top of the stack of unused
				  keypresses
				*/
				input_unreadch(c);
			}
			else
			{
				sb_printf( sb_err,
					   _(L"%ls: Unknown input function '%ls'\n"),
					   argv[0],
					   argv[i] );
				builtin_print_help( argv[0], sb_err );
				return 1;
			}
		}

		return 0;
	}

	/*
	  Check for invalid switch combinations
	*/
	if( (search_mode || line_mode || cursor_mode) && (argc-woptind > 1) )
	{

		sb_append( sb_err,
					argv[0],
					L": Too many arguments\n",
					(void *)0 );
		builtin_print_help( argv[0], sb_err );
		return 1;
	}

	if( (buffer_part || tokenize || cut_at_cursor) && (cursor_mode || line_mode || search_mode) )
	{
		sb_printf( sb_err,
				   BUILTIN_ERR_COMBO,
				   argv[0] );

		builtin_print_help( argv[0], sb_err );
		return 1;
	}


	if( (tokenize || cut_at_cursor) && (argc-woptind) )
	{
		sb_printf( sb_err,
				   BUILTIN_ERR_COMBO2,
				   argv[0],
				   L"--cut-at-cursor and --tokenize can not be used when setting the commandline" );


		builtin_print_help( argv[0], sb_err );
		return 1;
	}

	if( append_mode && !(argc-woptind) )
	{
		sb_printf( sb_err,
                    BUILTIN_ERR_COMBO2,
                    argv[0],
				   L"insertion mode switches can not be used when not in insertion mode" );

        builtin_print_help( argv[0], sb_err );
        return 1;
	}

	/*
	  Set default modes
	*/
	if( !append_mode )
	{
		append_mode = REPLACE_MODE;
	}

	if( !buffer_part )
	{
		buffer_part = STRING_MODE;
	}

	if( cursor_mode )
	{
		if( argc-woptind )
		{
			wchar_t *endptr;
			int new_pos;
			errno = 0;

			new_pos = wcstol( argv[woptind], &endptr, 10 );
			if( *endptr || errno )
			{
				sb_printf( sb_err,
					   BUILTIN_ERR_NOT_NUMBER,
					   argv[0],
					   argv[woptind] );
				builtin_print_help( argv[0], sb_err );
			}

			current_buffer = reader_get_buffer();
			new_pos = maxi( 0, mini( new_pos, wcslen( current_buffer ) ) );
			reader_set_buffer( current_buffer, new_pos );
			return 0;
		}
		else
		{
			sb_printf( sb_out, L"%d\n", reader_get_cursor_pos() );
			return 0;
		}

	}

	if( line_mode )
	{
		int pos = reader_get_cursor_pos();
		wchar_t *buff = reader_get_buffer();
		sb_printf( sb_out, L"%d\n", parse_util_lineno( buff, pos ) );
		return 0;

	}

	if( search_mode )
	{
		return !reader_search_mode();
	}


	switch( buffer_part )
	{
		case STRING_MODE:
		{
			begin = get_buffer();
			end = begin+wcslen(begin);
			break;
		}

		case PROCESS_MODE:
		{
			parse_util_process_extent( get_buffer(),
									   get_cursor_pos(),
									   &begin,
									   &end );
			break;
		}

		case JOB_MODE:
		{
			parse_util_job_extent( get_buffer(),
								   get_cursor_pos(),
								   &begin,
								   &end );
			break;
		}

		case TOKEN_MODE:
		{
			parse_util_token_extent( get_buffer(),
									 get_cursor_pos(),
									 &begin,
									 &end,
									 0, 0 );
			break;
		}

	}

	switch(argc-woptind)
	{
		case 0:
		{
			write_part( begin, end, cut_at_cursor, tokenize );
			break;
		}

		case 1:
		{
			replace_part( begin, end, argv[woptind], append_mode );
			break;
		}

		default:
		{
			string_buffer_t sb;
			int i;

			sb_init( &sb );

			sb_append( &sb, argv[woptind] );

			for( i=woptind+1; i<argc; i++ )
			{
				sb_append( &sb, L"\n" );
				sb_append( &sb, argv[i] );
			}

			replace_part( begin, end, (wchar_t *)sb.buff, append_mode );
			sb_destroy( &sb );

			break;
		}
	}

	return 0;
}
Пример #3
0
/// The commandline builtin. It is used for specifying a new value for the commandline.
int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    // Pointer to what the commandline builtin considers to be the current contents of the command
    // line buffer.
    const wchar_t *current_buffer = 0;

    // What the commandline builtin considers to be the current cursor position.
    size_t current_cursor_pos = (size_t)(-1);

    wchar_t *cmd = argv[0];
    int buffer_part = 0;
    int cut_at_cursor = 0;

    int argc = builtin_count_args(argv);
    int append_mode = 0;

    int function_mode = 0;
    int selection_mode = 0;

    int tokenize = 0;

    int cursor_mode = 0;
    int line_mode = 0;
    int search_mode = 0;
    int paging_mode = 0;
    const wchar_t *begin = NULL, *end = NULL;

    wcstring transient_commandline;
    if (get_top_transient(&transient_commandline)) {
        current_buffer = transient_commandline.c_str();
        current_cursor_pos = transient_commandline.size();
    } else {
        current_buffer = reader_get_buffer();
        current_cursor_pos = reader_get_cursor_pos();
    }

    if (!current_buffer) {
        if (is_interactive_session) {
            // Prompt change requested while we don't have a prompt, most probably while reading the
            // init files. Just ignore it.
            return STATUS_CMD_ERROR;
        }

        streams.err.append(argv[0]);
        streams.err.append(L": Can not set commandline in non-interactive mode\n");
        builtin_print_help(parser, streams, cmd, streams.err);
        return STATUS_CMD_ERROR;
    }

    static const wchar_t *const short_options = L":abijpctwforhI:CLSsP";
    static const struct woption long_options[] = {{L"append", no_argument, NULL, 'a'},
                                                  {L"insert", no_argument, NULL, 'i'},
                                                  {L"replace", no_argument, NULL, 'r'},
                                                  {L"current-buffer", no_argument, NULL, 'b'},
                                                  {L"current-job", no_argument, NULL, 'j'},
                                                  {L"current-process", no_argument, NULL, 'p'},
                                                  {L"current-selection", no_argument, NULL, 's'},
                                                  {L"current-token", no_argument, NULL, 't'},
                                                  {L"cut-at-cursor", no_argument, NULL, 'c'},
                                                  {L"function", no_argument, NULL, 'f'},
                                                  {L"tokenize", no_argument, NULL, 'o'},
                                                  {L"help", no_argument, NULL, 'h'},
                                                  {L"input", required_argument, NULL, 'I'},
                                                  {L"cursor", no_argument, NULL, 'C'},
                                                  {L"line", no_argument, NULL, 'L'},
                                                  {L"search-mode", no_argument, NULL, 'S'},
                                                  {L"paging-mode", no_argument, NULL, 'P'},
                                                  {NULL, 0, NULL, 0}};

    int opt;
    wgetopter_t w;
    while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
        switch (opt) {
            case L'a': {
                append_mode = APPEND_MODE;
                break;
            }
            case L'b': {
                buffer_part = STRING_MODE;
                break;
            }
            case L'i': {
                append_mode = INSERT_MODE;
                break;
            }
            case L'r': {
                append_mode = REPLACE_MODE;
                break;
            }
            case 'c': {
                cut_at_cursor = 1;
                break;
            }
            case 't': {
                buffer_part = TOKEN_MODE;
                break;
            }
            case 'j': {
                buffer_part = JOB_MODE;
                break;
            }
            case 'p': {
                buffer_part = PROCESS_MODE;
                break;
            }
            case 'f': {
                function_mode = 1;
                break;
            }
            case 'o': {
                tokenize = 1;
                break;
            }
            case 'I': {
                current_buffer = w.woptarg;
                current_cursor_pos = wcslen(w.woptarg);
                break;
            }
            case 'C': {
                cursor_mode = 1;
                break;
            }
            case 'L': {
                line_mode = 1;
                break;
            }
            case 'S': {
                search_mode = 1;
                break;
            }
            case 's': {
                selection_mode = 1;
                break;
            }
            case 'P': {
                paging_mode = 1;
                break;
            }
            case 'h': {
                builtin_print_help(parser, streams, cmd, streams.out);
                return STATUS_CMD_OK;
            }
            case ':': {
                builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]);
                return STATUS_INVALID_ARGS;
            }
            case L'?': {
                builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
                return STATUS_INVALID_ARGS;
            }
            default: {
                DIE("unexpected retval from wgetopt_long");
                break;
            }
        }
    }

    if (function_mode) {
        int i;

        // Check for invalid switch combinations.
        if (buffer_part || cut_at_cursor || append_mode || tokenize || cursor_mode || line_mode ||
            search_mode || paging_mode) {
            streams.err.append_format(BUILTIN_ERR_COMBO, argv[0]);
            builtin_print_help(parser, streams, cmd, streams.err);
            return STATUS_INVALID_ARGS;
        }

        if (argc == w.woptind) {
            builtin_missing_argument(parser, streams, cmd, argv[0]);
            return STATUS_INVALID_ARGS;
        }

        for (i = w.woptind; i < argc; i++) {
            wchar_t c = input_function_get_code(argv[i]);
            if (c != INPUT_CODE_NONE) {
                // input_unreadch inserts the specified keypress or readline function at the back of
                // the queue of unused keypresses.
                input_queue_ch(c);
            } else {
                streams.err.append_format(_(L"%ls: Unknown input function '%ls'"), cmd, argv[i]);
                builtin_print_help(parser, streams, cmd, streams.err);
                return STATUS_INVALID_ARGS;
            }
        }

        return STATUS_CMD_OK;
    }

    if (selection_mode) {
        size_t start, len;
        const wchar_t *buffer = reader_get_buffer();
        if (reader_get_selection(&start, &len)) {
            streams.out.append(buffer + start, len);
        }
        return STATUS_CMD_OK;
    }

    // Check for invalid switch combinations.
    if ((search_mode || line_mode || cursor_mode || paging_mode) && (argc - w.woptind > 1)) {
        streams.err.append_format(L"%ls: Too many arguments", argv[0]);
        builtin_print_help(parser, streams, cmd, streams.err);
        return STATUS_INVALID_ARGS;
    }

    if ((buffer_part || tokenize || cut_at_cursor) &&
        (cursor_mode || line_mode || search_mode || paging_mode)) {
        streams.err.append_format(BUILTIN_ERR_COMBO, argv[0]);
        builtin_print_help(parser, streams, cmd, streams.err);
        return STATUS_INVALID_ARGS;
    }

    if ((tokenize || cut_at_cursor) && (argc - w.woptind)) {
        streams.err.append_format(
            BUILTIN_ERR_COMBO2, cmd,
            L"--cut-at-cursor and --tokenize can not be used when setting the commandline");
        builtin_print_help(parser, streams, cmd, streams.err);
        return STATUS_INVALID_ARGS;
    }

    if (append_mode && !(argc - w.woptind)) {
        streams.err.append_format(
            BUILTIN_ERR_COMBO2, cmd,
            L"insertion mode switches can not be used when not in insertion mode");
        builtin_print_help(parser, streams, cmd, streams.err);
        return STATUS_INVALID_ARGS;
    }

    // Set default modes.
    if (!append_mode) {
        append_mode = REPLACE_MODE;
    }

    if (!buffer_part) {
        buffer_part = STRING_MODE;
    }

    if (cursor_mode) {
        if (argc - w.woptind) {
            long new_pos = fish_wcstol(argv[w.woptind]);
            if (errno) {
                streams.err.append_format(BUILTIN_ERR_NOT_NUMBER, cmd, argv[w.woptind]);
                builtin_print_help(parser, streams, cmd, streams.err);
            }

            current_buffer = reader_get_buffer();
            new_pos = maxi(0L, mini(new_pos, (long)wcslen(current_buffer)));
            reader_set_buffer(current_buffer, (size_t)new_pos);
        } else {
            streams.out.append_format(L"%lu\n", (unsigned long)reader_get_cursor_pos());
        }
        return STATUS_CMD_OK;
    }

    if (line_mode) {
        size_t pos = reader_get_cursor_pos();
        const wchar_t *buff = reader_get_buffer();
        streams.out.append_format(L"%lu\n", (unsigned long)parse_util_lineno(buff, pos));
        return STATUS_CMD_OK;
    }

    if (search_mode) {
        return reader_is_in_search_mode() ? 0 : 1;
    }

    if (paging_mode) {
        return reader_has_pager_contents() ? 0 : 1;
    }

    switch (buffer_part) {
        case STRING_MODE: {
            begin = current_buffer;
            end = begin + wcslen(begin);
            break;
        }
        case PROCESS_MODE: {
            parse_util_process_extent(current_buffer, current_cursor_pos, &begin, &end);
            break;
        }
        case JOB_MODE: {
            parse_util_job_extent(current_buffer, current_cursor_pos, &begin, &end);
            break;
        }
        case TOKEN_MODE: {
            parse_util_token_extent(current_buffer, current_cursor_pos, &begin, &end, 0, 0);
            break;
        }
        default: {
            DIE("unexpected buffer_part");
            break;
        }
    }

    int arg_count = argc - w.woptind;
    if (arg_count == 0) {
        write_part(begin, end, cut_at_cursor, tokenize, current_buffer, current_cursor_pos,
                   streams);
    } else if (arg_count == 1) {
        replace_part(begin, end, argv[w.woptind], append_mode, current_buffer, current_cursor_pos);
    } else {
        wcstring sb = argv[w.woptind];
        for (int i = w.woptind + 1; i < argc; i++) {
            sb.push_back(L'\n');
            sb.append(argv[i]);
        }
        replace_part(begin, end, sb.c_str(), append_mode, current_buffer, current_cursor_pos);
    }

    return STATUS_CMD_OK;
}
Пример #4
0
Файл: enter.c Проект: 0xAX/muttx
int _mutt_enter_string(char *buf, size_t buflen, int y, int x,
			int flags, int multiple, char ***files, int *numfiles,
			struct enter_state *state)
{
	int width = COLS - x - 1;
	int redraw;
	int pass =(flags & M_PASS);
	int first = 1;
	int ch, w, r;
	size_t i;
	wchar_t *tempbuf = 0;
	size_t templen = 0;
	history_class_t hclass;
	wchar_t wc;
	mbstate_t mbstate;

	int rv = 0;
	memset(&mbstate, 0, sizeof(mbstate));

	if (state->wbuf)
	{
		/* Coming back after return 1 */
		redraw = M_REDRAW_LINE;
		first = 0;
	}
	else
	{
		/* Initialise wbuf from buf */
		state->wbuflen = 0;
		state->lastchar = my_mbstowcs(&state->wbuf, &state->wbuflen, 0, buf);
		redraw = M_REDRAW_INIT;
	}

	if (flags & M_FILE)
		hclass = HC_FILE;
	else if (flags & M_EFILE)
		hclass = HC_MBOX;
	else if (flags & M_CMD)
		hclass = HC_CMD;
	else if (flags & M_ALIAS)
		hclass = HC_ALIAS;
	else if (flags & M_COMMAND)
		hclass = HC_COMMAND;
	else if (flags & M_PATTERN)
		hclass = HC_PATTERN;
	else
		hclass = HC_OTHER;

	for(;;)
	{
		if (redraw && !pass)
		{
			if (redraw == M_REDRAW_INIT)
			{
				/* Go to end of line */
				state->curpos = state->lastchar;
				state->begin = width_ceiling(state->wbuf, state->lastchar, my_wcswidth(state->wbuf, state->lastchar) - width + 1);
			}
			if (state->curpos < state->begin ||
			    my_wcswidth(state->wbuf + state->begin, state->curpos - state->begin) >= width)
				state->begin = width_ceiling(state->wbuf, state->lastchar, my_wcswidth(state->wbuf, state->curpos) - width / 2);
			move(y, x);
			w = 0;
			for(i = state->begin; i < state->lastchar; i++)
			{
				w += my_wcwidth(state->wbuf[i]);
				if (w > width)
					break;
				my_addwch(state->wbuf[i]);
			}
			clrtoeol();
			move(y, x + my_wcswidth(state->wbuf + state->begin, state->curpos - state->begin));
		}
		mutt_refresh();

		if ((ch = km_dokey(MENU_EDITOR)) == -1)
		{
			rv = -1;
			goto bye;
		}

		if (ch != OP_NULL)
		{
			first = 0;
			if (ch != OP_EDITOR_COMPLETE && ch != OP_EDITOR_COMPLETE_QUERY)
				state->tabs = 0;
			redraw = M_REDRAW_LINE;
			switch(ch)
			{
			case OP_EDITOR_HISTORY_UP:
				state->curpos = state->lastchar;
				if (mutt_history_at_scratch(hclass))
				{
					my_wcstombs(buf, buflen, state->wbuf, state->curpos);
					mutt_history_save_scratch(hclass, buf);
				}
				replace_part(state, 0, mutt_history_prev(hclass));
				redraw = M_REDRAW_INIT;
				break;

			case OP_EDITOR_HISTORY_DOWN:
				state->curpos = state->lastchar;
				if (mutt_history_at_scratch(hclass))
				{
					my_wcstombs(buf, buflen, state->wbuf, state->curpos);
					mutt_history_save_scratch(hclass, buf);
				}
				replace_part(state, 0, mutt_history_next(hclass));
				redraw = M_REDRAW_INIT;
				break;

			case OP_EDITOR_BACKSPACE:
				if (state->curpos == 0)
					BEEP();
				else
				{
					i = state->curpos;
					while(i && COMB_CHAR(state->wbuf[i - 1]))
						--i;
					if (i)
						--i;
					memmove(state->wbuf + i, state->wbuf + state->curpos,(state->lastchar - state->curpos) * sizeof(wchar_t));
					state->lastchar -= state->curpos - i;
					state->curpos = i;
				}
				break;

			case OP_EDITOR_BOL:
				state->curpos = 0;
				break;

			case OP_EDITOR_EOL:
				redraw= M_REDRAW_INIT;
				break;

			case OP_EDITOR_KILL_LINE:
				state->curpos = state->lastchar = 0;
				break;

			case OP_EDITOR_KILL_EOL:
				state->lastchar = state->curpos;
				break;

			case OP_EDITOR_BACKWARD_CHAR:
				if (state->curpos == 0)
					BEEP();
				else
				{
					while(state->curpos && COMB_CHAR(state->wbuf[state->curpos - 1]))
						state->curpos--;
					if (state->curpos)
						state->curpos--;
				}
				break;

			case OP_EDITOR_FORWARD_CHAR:
				if (state->curpos == state->lastchar)
					BEEP();
				else
				{
					++state->curpos;
					while(state->curpos < state->lastchar && COMB_CHAR(state->wbuf[state->curpos]))
						++state->curpos;
				}
				break;

			case OP_EDITOR_BACKWARD_WORD:
				if (state->curpos == 0)
					BEEP();
				else
				{
					while(state->curpos && iswspace(state->wbuf[state->curpos - 1]))
						--state->curpos;
					while(state->curpos && !iswspace(state->wbuf[state->curpos - 1]))
						--state->curpos;
				}
				break;

			case OP_EDITOR_FORWARD_WORD:
				if (state->curpos == state->lastchar)
					BEEP();
				else
				{
					while(state->curpos < state->lastchar && iswspace(state->wbuf[state->curpos]))
						++state->curpos;
					while(state->curpos < state->lastchar && !iswspace(state->wbuf[state->curpos]))
						++state->curpos;
				}
				break;

			case OP_EDITOR_CAPITALIZE_WORD:
			case OP_EDITOR_UPCASE_WORD:
			case OP_EDITOR_DOWNCASE_WORD:
				if (state->curpos == state->lastchar)
				{
					BEEP();
					break;
				}
				while(state->curpos && !iswspace(state->wbuf[state->curpos]))
					--state->curpos;
				while(state->curpos < state->lastchar && iswspace(state->wbuf[state->curpos]))
					++state->curpos;
				while(state->curpos < state->lastchar && !iswspace(state->wbuf[state->curpos]))
				{
					if (ch == OP_EDITOR_DOWNCASE_WORD)
						state->wbuf[state->curpos] = towlower(state->wbuf[state->curpos]);
					else
					{
						state->wbuf[state->curpos] = towupper(state->wbuf[state->curpos]);
						if (ch == OP_EDITOR_CAPITALIZE_WORD)
							ch = OP_EDITOR_DOWNCASE_WORD;
					}
					state->curpos++;
				}
				break;

			case OP_EDITOR_DELETE_CHAR:
				if (state->curpos == state->lastchar)
					BEEP();
				else
				{
					i = state->curpos;
					while(i < state->lastchar && COMB_CHAR(state->wbuf[i]))
						++i;
					if (i < state->lastchar)
						++i;
					while(i < state->lastchar && COMB_CHAR(state->wbuf[i]))
						++i;
					memmove(state->wbuf + state->curpos, state->wbuf + i,(state->lastchar - i) * sizeof(wchar_t));
					state->lastchar -= i - state->curpos;
				}
				break;

			case OP_EDITOR_KILL_WORD:
				/* delete to beginning of word */
				if (state->curpos != 0)
				{
					i = state->curpos;
					while(i && iswspace(state->wbuf[i - 1]))
						--i;
					if (i)
					{
						if (iswalnum(state->wbuf[i - 1]))
						{
							for(--i; i && iswalnum(state->wbuf[i - 1]); i--)
								;
						}
						else
							--i;
					}
					memmove(state->wbuf + i, state->wbuf + state->curpos,
						(state->lastchar - state->curpos) * sizeof(wchar_t));
					state->lastchar += i - state->curpos;
					state->curpos = i;
				}
				break;

			case OP_EDITOR_KILL_EOW:
				/* delete to end of word */

				/* first skip over whitespace */
				for(i = state->curpos;
				     i < state->lastchar && iswspace(state->wbuf[i]); i++)
					;

				/* if there are any characters left.. */
				if (i < state->lastchar)
				{
					/* if the current character is alphanumeric.. */
					if (iswalnum(state->wbuf[i]))
					{
						/* skip over the rest of the word consistent of only alphanumerics */
						for(; i < state->lastchar && iswalnum(state->wbuf[i]); i++)
							;
					}
					else
					{
						/* skip over one non-alphanumeric character */
						++i;
					}
				}

				memmove(state->wbuf + state->curpos, state->wbuf + i,
					(state->lastchar - i) * sizeof(wchar_t));
				state->lastchar += state->curpos - i;
				break;

			case OP_EDITOR_BUFFY_CYCLE:
				if (flags & M_EFILE)
				{
					first = 1; /* clear input if user types a real key later */
					my_wcstombs(buf, buflen, state->wbuf, state->curpos);
					mutt_buffy(buf, buflen);
					state->curpos = state->lastchar = my_mbstowcs(&state->wbuf, &state->wbuflen, 0, buf);
					break;
				}
				else if (!(flags & M_FILE))
					goto self_insert;
				/* fall through to completion routine(M_FILE) */

			case OP_EDITOR_COMPLETE:
			case OP_EDITOR_COMPLETE_QUERY:
				state->tabs++;
				if (flags & M_CMD)
				{
					for(i = state->curpos; i && !is_shell_char(state->wbuf[i-1]); i--)
						;
					my_wcstombs(buf, buflen, state->wbuf + i, state->curpos - i);
					if (tempbuf && templen == state->lastchar - i &&
					    !memcmp(tempbuf, state->wbuf + i,(state->lastchar - i) * sizeof(wchar_t)))
					{
						mutt_select_file(buf, buflen,(flags & M_EFILE) ? M_SEL_FOLDER : 0);
						set_bit(options, OPTNEEDREDRAW);
						if (*buf)
							replace_part(state, i, buf);
						rv = 1;
						goto bye;
					}
					if (!mutt_complete(buf, buflen))
					{
						templen = state->lastchar - i;
						safe_realloc(&tempbuf, templen * sizeof(wchar_t));
					}
					else
						BEEP();

					replace_part(state, i, buf);
				}
				else if (flags & M_ALIAS && ch == OP_EDITOR_COMPLETE)
				{
					/* invoke the alias-menu to get more addresses */
					for(i = state->curpos; i && state->wbuf[i-1] != ',' &&
						     state->wbuf[i-1] != ':'; i--)
						;
					for(; i < state->lastchar && state->wbuf[i] == ' '; i++)
						;
					my_wcstombs(buf, buflen, state->wbuf + i, state->curpos - i);
					r = mutt_alias_complete(buf, buflen);
					replace_part(state, i, buf);
					if (!r)
					{
						rv = 1;
						goto bye;
					}
					break;
				}
				else if (flags & M_ALIAS && ch == OP_EDITOR_COMPLETE_QUERY)
				{
					/* invoke the query-menu to get more addresses */
					if ((i = state->curpos))
					{
						for(; i && state->wbuf[i - 1] != ','; i--)
							;
						for(; i < state->curpos && state->wbuf[i] == ' '; i++)
							;
					}

					my_wcstombs(buf, buflen, state->wbuf + i, state->curpos - i);
					mutt_query_complete(buf, buflen);
					replace_part(state, i, buf);

					rv = 1;
					goto bye;
				}
				else if (flags & M_COMMAND)
				{
					my_wcstombs(buf, buflen, state->wbuf, state->curpos);
					i = strlen(buf);
					if (i && buf[i - 1] == '=' &&
					    mutt_var_value_complete(buf, buflen, i))
						state->tabs = 0;
					else if (!mutt_command_complete(buf, buflen, i, state->tabs))
						BEEP();
					replace_part(state, 0, buf);
				}
				else if (flags &(M_FILE | M_EFILE))
				{
					my_wcstombs(buf, buflen, state->wbuf, state->curpos);

					/* see if the path has changed from the last time */
					if ((!tempbuf && !state->lastchar) ||(tempbuf && templen == state->lastchar &&
									       !memcmp(tempbuf, state->wbuf, state->lastchar * sizeof(wchar_t))))
					{
						_mutt_select_file(buf, buflen,
								  ((flags & M_EFILE) ? M_SEL_FOLDER : 0) |(multiple ? M_SEL_MULTI : 0),
								   files, numfiles);
						set_bit(options, OPTNEEDREDRAW);
						if (*buf)
						{
							mutt_pretty_mailbox(buf, buflen);
							if (!pass)
								mutt_history_add(hclass, buf, 1);
							rv = 0;
							goto bye;
						}

						/* file selection cancelled */
						rv = 1;
						goto bye;
					}

					if (!mutt_complete(buf, buflen))
					{
						templen = state->lastchar;
						safe_realloc(&tempbuf, templen * sizeof(wchar_t));
						memcpy(tempbuf, state->wbuf, templen * sizeof(wchar_t));
					}
					else
						BEEP(); /* let the user know that nothing matched */
					replace_part(state, 0, buf);
				}
				else
					goto self_insert;
				break;

			case OP_EDITOR_QUOTE_CHAR:
			{
				struct event event;
				/*ADDCH(LastKey);*/
				event = mutt_getch();
				if (event.ch >= 0)
				{
					LastKey = event.ch;
					goto self_insert;
				}
			}

			case OP_EDITOR_TRANSPOSE_CHARS:
				if (state->lastchar < 2)
					BEEP();
				else
				{
					wchar_t t;

					if (state->curpos == 0)
						state->curpos = 2;
					else if (state->curpos < state->lastchar)
						++state->curpos;

					t = state->wbuf[state->curpos - 2];
					state->wbuf[state->curpos - 2] = state->wbuf[state->curpos - 1];
					state->wbuf[state->curpos - 1] = t;
				}
				break;

			default:
				BEEP();
			}
		}
		else
		{

		self_insert:

			state->tabs = 0;
			/* use the raw keypress */
			ch = LastKey;

#if KEY_ENTER
			/* treat ENTER the same as RETURN */
			if (ch == KEY_ENTER)
				ch = '\r';
#endif

			/* quietly ignore all other function keys */
			if (ch & ~0xff)
				continue;

			/* gather the octets into a wide character */
			{
				char c;
				size_t k;

				c = ch;
				k = mbrtowc(&wc, &c, 1, &mbstate);
				if (k ==(size_t)(-2))
					continue;
				else if (k && k != 1)
				{
					memset(&mbstate, 0, sizeof(mbstate));
					continue;
				}
			}

			if (first &&(flags & M_CLEAR))
			{
				first = 0;
				if (IsWPrint(wc)) /* why? */
					state->curpos = state->lastchar = 0;
			}

			if (wc == '\r' || wc == '\n')
			{
				/* Convert from wide characters */
				my_wcstombs(buf, buflen, state->wbuf, state->lastchar);
				if (!pass)
					mutt_history_add(hclass, buf, 1);

				if (multiple)
				{
					char **tfiles;
					*numfiles = 1;
					tfiles = safe_calloc(*numfiles, sizeof(char *));
					mutt_expand_path(buf, buflen);
					tfiles[0] = safe_strdup(buf);
					*files = tfiles;
				}
				rv = 0;
				goto bye;
			}
			else if (wc &&(wc < ' ' || IsWPrint(wc))) /* why? */
			{
				if (state->lastchar >= state->wbuflen)
				{
					state->wbuflen = state->lastchar + 20;
					safe_realloc(&state->wbuf, state->wbuflen * sizeof(wchar_t));
				}
				memmove(state->wbuf + state->curpos + 1, state->wbuf + state->curpos,(state->lastchar - state->curpos) * sizeof(wchar_t));
				state->wbuf[state->curpos++] = wc;
				state->lastchar++;
			}
			else
			{
				mutt_flushinp();
				BEEP();
			}
		}
	}

bye:

	mutt_reset_history_state(hclass);
	safe_free(&tempbuf);
	return rv;
}