Exemplo n.º 1
0
static bool test_stuff(screen_t *scr)
{
    data_buffer_t output;
    scoped_buffer_t scoped_buffer(&output);

    s_move(scr, &output, 0, 0);
    int screen_width = common_get_width();

    const wchar_t *left = L"left";
    const wchar_t *right = L"right";

    for (size_t idx = 0; idx < 80; idx++)
    {
        output.push_back('A');
    }

    if (! output.empty())
    {
        write_loop(STDOUT_FILENO, &output.at(0), output.size());
        output.clear();
    }

    sleep(5);

    for (size_t i=0; i < 1; i++)
    {
        writembs(cursor_left);
    }

    if (! output.empty())
    {
        write_loop(1, &output.at(0), output.size());
        output.clear();
    }



    while (1)
    {
        int c = getchar();
        if (c != EOF) break;
    }


    while (1)
    {
        int c = getchar();
        if (c != EOF) break;
    }
    puts("Bye");
    exit(0);
    while (1) sleep(10000);
    return true;
}
Exemplo n.º 2
0
/**
   set_color builtin
*/
static int builtin_set_color(parser_t &parser, wchar_t **argv)
{
    /** Variables used for parsing the argument list */
    const struct woption long_options[] =
    {
        { L"background", required_argument, 0, 'b'},
        { L"help", no_argument, 0, 'h' },
        { L"bold", no_argument, 0, 'o' },
        { L"underline", no_argument, 0, 'u' },
        { L"version", no_argument, 0, 'v' },
        { L"print-colors", no_argument, 0, 'c' },
        { 0, 0, 0, 0 }
    };

    const wchar_t *short_options = L"b:hvocu";

    int argc = builtin_count_args(argv);

    /* Some code passes variables to set_color that don't exist, like $fish_user_whatever. As a hack, quietly return failure. */
    if (argc <= 1)
    {
        return EXIT_FAILURE;
    }

    const wchar_t *bgcolor = NULL;
    bool bold = false, underline=false;
    int errret;

    /* Parse options to obtain the requested operation and the modifiers */
    woptind = 0;
    while (1)
    {
        int c = wgetopt_long(argc, argv, short_options, long_options, 0);

        if (c == -1)
        {
            break;
        }

        switch (c)
        {
            case 0:
                break;

            case 'b':
                bgcolor = woptarg;
                break;

            case 'h':
                builtin_print_help(parser, argv[0], stdout_buffer);
                return STATUS_BUILTIN_OK;

            case 'o':
                bold = true;
                break;

            case 'u':
                underline = true;
                break;

            case 'c':
                print_colors();
                return STATUS_BUILTIN_OK;

            case '?':
                return STATUS_BUILTIN_ERROR;
        }
    }

    /* Remaining argument is foreground color */
    const wchar_t *fgcolor = NULL;
    if (woptind < argc)
    {
        if (woptind + 1 == argc)
        {
            fgcolor = argv[woptind];
        }
        else
        {
            append_format(stderr_buffer,
                          _(L"%ls: Too many arguments\n"),
                          argv[0]);
            return STATUS_BUILTIN_ERROR;
        }
    }

    if (fgcolor == NULL && bgcolor == NULL && !bold && !underline)
    {
        append_format(stderr_buffer,
                      _(L"%ls: Expected an argument\n"),
                      argv[0]);
        return STATUS_BUILTIN_ERROR;
    }

    const rgb_color_t fg = rgb_color_t(fgcolor ? fgcolor : L"");
    if (fgcolor && (fg.is_none() || fg.is_ignore()))
    {
        append_format(stderr_buffer, _(L"%ls: Unknown color '%ls'\n"), argv[0], fgcolor);
        return STATUS_BUILTIN_ERROR;
    }

    const rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : L"");
    if (bgcolor && (bg.is_none() || bg.is_ignore()))
    {
        append_format(stderr_buffer, _(L"%ls: Unknown color '%ls'\n"), argv[0], bgcolor);
        return STATUS_BUILTIN_ERROR;
    }

    /* Make sure that the term exists */
    if (cur_term == NULL && setupterm(0, STDOUT_FILENO, &errret) == ERR)
    {
        append_format(stderr_buffer, _(L"%ls: Could not set up terminal\n"), argv[0]);
        return STATUS_BUILTIN_ERROR;
    }

    /*
       Test if we have at least basic support for setting fonts, colors
       and related bits - otherwise just give up...
    */
    if (! exit_attribute_mode)
    {
        return STATUS_BUILTIN_ERROR;
    }


    /* Save old output function so we can restore it */
    int (* const saved_writer_func)(char) = output_get_writer();

    /* Set our output function, which writes to a std::string */
    builtin_set_color_output.clear();
    output_set_writer(set_color_builtin_outputter);

    if (bold)
    {
        if (enter_bold_mode)
            writembs(tparm(enter_bold_mode));
    }

    if (underline)
    {
        if (enter_underline_mode)
            writembs(enter_underline_mode);
    }

    if (bgcolor != NULL)
    {
        if (bg.is_normal())
        {
            write_color(rgb_color_t::black(), false /* not is_fg */);
            writembs(tparm(exit_attribute_mode));
        }
    }

    if (fgcolor != NULL)
    {
        if (fg.is_normal() || fg.is_reset())
        {
            write_color(rgb_color_t::black(), true /* is_fg */);
            writembs(tparm(exit_attribute_mode));
        }
        else
        {
            write_color(fg, true /* is_fg */);
        }
    }

    if (bgcolor != NULL)
    {
        if (! bg.is_normal() && ! bg.is_reset())
        {
            write_color(bg, false /* not is_fg */);
        }
    }

    /* Restore saved writer function */
    output_set_writer(saved_writer_func);

    /* Output the collected string */
    stdout_buffer.append(str2wcstring(builtin_set_color_output));
    builtin_set_color_output.clear();

    return STATUS_BUILTIN_OK;
}
Exemplo n.º 3
0
static int completion_try_print( int cols,
				 wchar_t *prefix,
				 int is_quoted,
				 std::vector<comp_t *> &lst )
{
	/*
	  The calculated preferred width of each column
	*/
	int pref_width[PAGER_MAX_COLS];
	/*
	  The calculated minimum width of each column
	*/
	int min_width[PAGER_MAX_COLS];
	/*
	  If the list can be printed with this width, width will contain the width of each column
	*/
	int *width=pref_width;
	/*
	  Set to one if the list should be printed at this width
	*/
	int print=0;
	
	long i, j;
	
	int rows = (int)((lst.size()-1)/cols+1);
	
	int pref_tot_width=0;
	int min_tot_width = 0;
	int res=PAGER_RETRY;
	/*
	  Skip completions on tiny terminals
	*/
	
	if( termsize.ws_col < PAGER_MIN_WIDTH )
		return PAGER_DONE;
	
	memset( pref_width, 0, sizeof(pref_width) );
	memset( min_width, 0, sizeof(min_width) );
	
	/* Calculate how wide the list would be */
	for( j = 0; j < cols; j++ )
	{
		for( i = 0; i<rows; i++ )
		{
			int pref,min;
			comp_t *c;
			if( lst.size() <= j*rows + i )
				continue;

			c = lst.at(j*rows + i );
			pref = c->pref_width;
			min = c->min_width;
			
			if( j != cols-1 )
			{
				pref += 2;
				min += 2;
			}
			min_width[j] = maxi( min_width[j],
					     min );
			pref_width[j] = maxi( pref_width[j],
					      pref );
		}
		min_tot_width += min_width[j];
		pref_tot_width += pref_width[j];
	}
	/*
	  Force fit if one column
	*/
	if( cols == 1)
	{
		if( pref_tot_width > termsize.ws_col )
		{
			pref_width[0] = termsize.ws_col;
		}
		width = pref_width;
		print=1;
	}
	else if( pref_tot_width <= termsize.ws_col )
	{
		/* Terminal is wide enough. Print the list! */
		width = pref_width;
		print=1;
	}
	else
	{
		long next_rows = (lst.size()-1)/(cols-1)+1;
/*		fwprintf( stderr,
  L"cols %d, min_tot %d, term %d, rows=%d, nextrows %d, termrows %d, diff %d\n",
  cols,
  min_tot_width, termsize.ws_col,
  rows, next_rows, termsize.ws_row,
  pref_tot_width-termsize.ws_col );
*/
		if( min_tot_width < termsize.ws_col &&
		    ( ( (rows < termsize.ws_row) && (next_rows >= termsize.ws_row ) ) ||
		      ( pref_tot_width-termsize.ws_col< 4 && cols < 3 ) ) )
		{
			/*
			  Terminal almost wide enough, or squeezing makes the
			  whole list fit on-screen.

			  This part of the code is really important. People hate
			  having to scroll through the completion list. In cases
			  where there are a huge number of completions, it can't
			  be helped, but it is not uncommon for the completions to
			  _almost_ fit on one screen. In those cases, it is almost
			  always desirable to 'squeeze' the completions into a
			  single page. 

			  If we are using N columns and can get everything to
			  fit using squeezing, but everything would also fit
			  using N-1 columns, don't try.
			*/

			int tot_width = min_tot_width;
			width = min_width;

			while( tot_width < termsize.ws_col )
			{
				for( i=0; (i<cols) && ( tot_width < termsize.ws_col ); i++ )
				{
					if( width[i] < pref_width[i] )
					{
						width[i]++;
						tot_width++;
					}
				}
			}
			print=1;
		}
	}

	if( print )
	{
		res=PAGER_DONE;
		if( rows < termsize.ws_row )
		{
			/* List fits on screen. Print it and leave */
			if( is_ca_mode )
			{
				is_ca_mode = 0;
				writembs(exit_ca_mode);
			}
			
			completion_print( cols, width, 0, rows, prefix, is_quoted, lst);
			pager_flush();
		}
		else
		{
			int npos, pos = 0;
			int do_loop = 1;

			/*
			  Enter ca_mode, which means that the terminal
			  content will be restored to the current
			  state on exit.
			*/
			if( enter_ca_mode && exit_ca_mode )
			{
				is_ca_mode=1;
				writembs(enter_ca_mode);
			}
			

			completion_print( cols,
					  width,
					  0,
					  termsize.ws_row-1,
					  prefix,
					  is_quoted,
					  lst);
			/*
			  List does not fit on screen. Print one screenfull and
			  leave a scrollable interface
			*/
			while(do_loop)
			{
				set_color( rgb_color_t::black(), get_color(HIGHLIGHT_PAGER_PROGRESS) );
                wcstring msg = format_string(_(L" %d to %d of %d"), pos, pos+termsize.ws_row-1, rows );
				msg.append(L"   \r" );
								
				writestr(msg.c_str());
				set_color( rgb_color_t::normal(), rgb_color_t::normal() );
				pager_flush();
				int c = readch();

				switch( c )
				{
					case LINE_UP:
					{
						if( pos > 0 )
						{
							pos--;
							writembs(tparm( cursor_address, 0, 0));
							writembs(scroll_reverse);
							completion_print( cols,
									  width,
									  pos,
									  pos+1,
									  prefix,
									  is_quoted,
									  lst );
							writembs( tparm( cursor_address,
									 termsize.ws_row-1, 0) );
							writembs(clr_eol );

						}

						break;
					}

					case LINE_DOWN:
					{
						if( pos <= (rows - termsize.ws_row ) )
						{
							pos++;
							completion_print( cols,
									  width,
									  pos+termsize.ws_row-2,
									  pos+termsize.ws_row-1,
									  prefix,
									  is_quoted,
									  lst );
						}
						break;
					}

					case PAGE_DOWN:
					{

						npos = mini( (int)(rows - termsize.ws_row+1), (int)(pos + termsize.ws_row-1) );
						if( npos != pos )
						{
							pos = npos;
							completion_print( cols,
									  width,
									  pos,
									  pos+termsize.ws_row-1,
									  prefix,
									  is_quoted,
									  lst );
						}
						else
						{
							if( flash_screen )
								writembs( flash_screen );
						}

						break;
					}

					case PAGE_UP:
					{
						npos = maxi( 0,
							     pos - termsize.ws_row+1 );

						if( npos != pos )
						{
							pos = npos;
							completion_print( cols,
									  width,
									  pos,
									  pos+termsize.ws_row-1,
									  prefix,
									  is_quoted,
									  lst );
						}
						else
						{
							if( flash_screen )
								writembs( flash_screen );
						}
						break;
					}

					case R_NULL:
					{
						do_loop=0;
						res=PAGER_RESIZE;
						break;
						
					}
					
					default:
					{
						out_buff.push_back( c );
						do_loop = 0;
						break;
					}					
				}
			}
			writembs(clr_eol);
		}
	}
	return res;
}
Exemplo n.º 4
0
int main( int argc, char **argv )
{
	int i;
	int is_quoted=0;	
	wcstring_list_t comp;
	wchar_t *prefix = 0;

	int mangle_descriptors = 0;
	int result_fd = -1;
	set_main_thread();
    setup_fork_guards();
    
	/*
	  This initialization is made early, so that the other init code
	  can use global_context for memory managment
	*/
	program_name = L"fish_pager";


	wsetlocale( LC_ALL, L"" );

	/*
	  The call signature for fish_pager is a mess. Because we want
	  to be able to upgrade fish without breaking running
	  instances, we need to support all previous
	  modes. Unfortunatly, the two previous ones are a mess. The
	  third one is designed to be extensible, so hopefully it will
	  be the last.
	*/

	if( argc > 1 && argv[1][0] == '-' )
	{
		/*
		  Third mode
		*/
			
		int completion_fd = -1;
		FILE *completion_file;
			
		while( 1 )
		{
			static struct option
				long_options[] =
				{
					{
						"result-fd", required_argument, 0, 'r' 
					}
					,
					{
						"completion-fd", required_argument, 0, 'c' 
					}
					,
					{
						"prefix", required_argument, 0, 'p' 
					}
					,
					{
						"is-quoted", no_argument, 0, 'q' 
					}
					,
					{
						"help", no_argument, 0, 'h' 
					}
					,
					{
						"version", no_argument, 0, 'v' 
					}
					,
					{ 
						0, 0, 0, 0 
					}
				}
			;
		
			int opt_index = 0;
		
			int opt = getopt_long( argc,
					       argv, 
					       GETOPT_STRING,
					       long_options, 
					       &opt_index );
		
			if( opt == -1 )
				break;
		
			switch( opt )
			{
				case 0:
				{
					break;
				}
			
				case 'r':
				{
					result_fd = get_fd( optarg );
					break;
				}
			
				case 'c':
				{
					completion_fd = get_fd( optarg );
					break;
				}

				case 'p':
				{
					prefix = str2wcs(optarg);
					break;
				}

				case 'h':
				{
					print_help( argv[0], 1 );
					exit(0);						
				}

				case 'v':
				{
					debug( 0, L"%ls, version %s\n", program_name, PACKAGE_VERSION );
					exit( 0 );				
				}
					
				case 'q':
				{
					is_quoted = 1;
				}
			
			}
		}

		if( completion_fd == -1 || result_fd == -1 )
		{
			debug( 0, _(L"Unspecified file descriptors") );
			exit( 1 );
		}
			

		if( (completion_file = fdopen( completion_fd, "r" ) ) )
		{
			read_array( completion_file, comp );
			fclose( completion_file );
		}
		else
		{
			debug( 0, _(L"Could not read completions") );
			wperror( L"fdopen" );
			exit( 1 );
		}

		if( !prefix )
		{
			prefix = wcsdup( L"" );
		}
			
			
	}
	else
	{
		/*
		  Second or first mode. These suck, but we need to support
		  them for backwards compatibility. At least for some
		  time.

		  Third mode was implemented in January 2007, and previous
		  modes should be considered deprecated from that point
		  forward. A reasonable time frame for removal of the code
		  below has yet to be determined.
		*/
			
		if( argc < 3 )
		{
			print_help( argv[0], 1 );
			exit( 0 );
		}
		else
		{
			mangle_descriptors = 1;
			
			prefix = str2wcs( argv[2] );
			is_quoted = strcmp( "1", argv[1] )==0;
			
			if( argc > 3 )
			{
				/*
				  First mode
				*/
				for( i=3; i<argc; i++ )
				{
					wcstring wcs = str2wcstring( argv[i] );
                    comp.push_back(wcs);
				}
			}
			else
			{
				/*
				  Second mode
				*/
				read_array( stdin, comp );
			}
		}
			
	}
		
//		debug( 3, L"prefix is '%ls'", prefix );
		
	init( mangle_descriptors, result_fd );

	mangle_descriptions( comp );

	if( wcscmp( prefix, L"-" ) == 0 )
		join_completions( comp );

	std::vector<comp_t *> completions = mangle_completions( comp, prefix );

	/**
	   Try to print the completions. Start by trying to print the
	   list in PAGER_MAX_COLS columns, if the completions won't
	   fit, reduce the number of columns by one. Printing a single
	   column never fails.
	*/
	for( i = PAGER_MAX_COLS; i>0; i-- )
	{
		switch( completion_try_print( i, prefix, is_quoted, completions ) )
		{

			case PAGER_RETRY:
				break;

			case PAGER_DONE:
				i=0;
				break;

			case PAGER_RESIZE:
				/*
				  This means we got a resize event, so we start
				  over from the beginning. Since it the screen got
				  bigger, we might be able to fit all completions
				  on-screen.
				*/
				i=PAGER_MAX_COLS+1;
				break;

		}		
	}
	
	free(prefix );

	fwprintf( out_file, L"%ls", out_buff.c_str() );
	if( is_ca_mode )
	{
		writembs(exit_ca_mode);
		pager_flush();
	}
	destroy();

}
Exemplo n.º 5
0
/// Send the specified string through tputs and append the output to the screen's outputter.
static void s_write_mbs(screen_t *screen, const char *s) { writembs(screen->outp(), s); }
Exemplo n.º 6
0
/// Write the bytes needed to move screen cursor to the specified position to the specified buffer.
/// The actual_cursor field of the specified screen_t will be updated.
///
/// \param s the screen to operate on
/// \param b the buffer to send the output escape codes to
/// \param new_x the new x position
/// \param new_y the new y position
static void s_move(screen_t *s, int new_x, int new_y) {
    if (s->actual.cursor.x == new_x && s->actual.cursor.y == new_y) return;

    const scoped_buffer_t buffering(*s);

    // If we are at the end of our window, then either the cursor stuck to the edge or it didn't. We
    // don't know! We can fix it up though.
    if (s->actual.cursor.x == common_get_width()) {
        // Either issue a cr to go back to the beginning of this line, or a nl to go to the
        // beginning of the next one, depending on what we think is more efficient.
        if (new_y <= s->actual.cursor.y) {
            s->outp().push_back('\r');
        } else {
            s->outp().push_back('\n');
            s->actual.cursor.y++;
        }
        // Either way we're not in the first column.
        s->actual.cursor.x = 0;
    }

    int i;
    int x_steps, y_steps;

    const char *str;
    auto &outp = s->outp();

    y_steps = new_y - s->actual.cursor.y;

    if (y_steps > 0 && (std::strcmp(cursor_down, "\n") == 0)) {
        // This is very strange - it seems some (all?) consoles use a simple newline as the cursor
        // down escape. This will of course move the cursor to the beginning of the line as well as
        // moving it down one step. The cursor_up does not have this behavior...
        s->actual.cursor.x = 0;
    }

    if (y_steps < 0) {
        str = cursor_up;
    } else {
        str = cursor_down;
    }

    for (i = 0; i < abs(y_steps); i++) {
        writembs(outp, str);
    }

    x_steps = new_x - s->actual.cursor.x;

    if (x_steps && new_x == 0) {
        outp.push_back('\r');
        x_steps = 0;
    }

    const char *multi_str = NULL;
    if (x_steps < 0) {
        str = cursor_left;
        multi_str = parm_left_cursor;
    } else {
        str = cursor_right;
        multi_str = parm_right_cursor;
    }

    // Use the bulk ('multi') output for cursor movement if it is supported and it would be shorter
    // Note that this is required to avoid some visual glitches in iTerm (issue #1448).
    bool use_multi =
        multi_str != NULL && multi_str[0] != '\0' && abs(x_steps) * std::strlen(str) > std::strlen(multi_str);
    if (use_multi && cur_term) {
        char *multi_param = tparm((char *)multi_str, abs(x_steps));
        writembs(outp, multi_param);
    } else {
        for (i = 0; i < abs(x_steps); i++) {
            writembs(outp, str);
        }
    }

    s->actual.cursor.x = new_x;
    s->actual.cursor.y = new_y;
}
Exemplo n.º 7
0
/**
   Send the specified string through tputs and append the output to
   the specified buffer.
*/
static void s_write_mbs( data_buffer_t *b, char *s )
{
    scoped_buffer_t scoped_buffer(b);
	writembs( s );
}
Exemplo n.º 8
0
/**
   Write the bytes needed to move screen cursor to the specified
   position to the specified buffer. The actual_cursor field of the
   specified screen_t will be updated.
   
   \param s the screen to operate on
   \param b the buffer to send the output escape codes to
   \param new_x the new x position
   \param new_y the new y position
*/
static void s_move( screen_t *s, data_buffer_t *b, int new_x, int new_y )
{
	int i;
	int x_steps, y_steps;
	
	char *str;
/*
  debug( 0, L"move from %d %d to %d %d", 
  s->screen_cursor[0], s->screen_cursor[1],  
  new_x, new_y );
*/
    scoped_buffer_t scoped_buffer(b);
    	
	y_steps = new_y - s->actual.cursor.y;

	if( y_steps > 0 && (strcmp( cursor_down, "\n")==0))
	{	
		/*
		  This is very strange - it seems some (all?) consoles use a
		  simple newline as the cursor down escape. This will of
		  course move the cursor to the beginning of the line as well
		  as moving it down one step. The cursor_up does not have this
		  behaviour...
		*/
		s->actual.cursor.x=0;
	}
	
	if( y_steps < 0 )
	{
		str = cursor_up;
	}
	else
	{
		str = cursor_down;
		
	}
	
	for( i=0; i<abs(y_steps); i++)
	{
		writembs(str);
	}


	x_steps = new_x - s->actual.cursor.x;
	
	if( x_steps && new_x == 0 )
	{
        b->push_back('\r');
		x_steps = 0;
	}
		
	if( x_steps < 0 )
    {
		str = cursor_left;
	}
	else
	{
		str = cursor_right;
	}
	
	for( i=0; i<abs(x_steps); i++)
	{
		writembs(str);
	}


	s->actual.cursor.x = new_x;
	s->actual.cursor.y = new_y;
}
Exemplo n.º 9
0
/// Send the specified string through tputs and append the output to the specified buffer.
static void s_write_mbs(data_buffer_t *b, char *s) {
    scoped_buffer_t scoped_buffer(b);  //!OCLINT(has side effects)
    writembs(s);
}
Exemplo n.º 10
0
/**
   Write the bytes needed to move screen cursor to the specified
   position to the specified buffer. The actual_cursor field of the
   specified screen_t will be updated.

   \param s the screen to operate on
   \param b the buffer to send the output escape codes to
   \param new_x the new x position
   \param new_y the new y position
*/
static void s_move(screen_t *s, data_buffer_t *b, int new_x, int new_y)
{
    if (s->actual.cursor.x == new_x && s->actual.cursor.y == new_y)
        return;

    // If we are at the end of our window, then either the cursor stuck to the edge or it didn't. We don't know! We can fix it up though.
    if (s->actual.cursor.x == common_get_width())
    {
        // Either issue a cr to go back to the beginning of this line, or a nl to go to the beginning of the next one, depending on what we think is more efficient
        if (new_y <= s->actual.cursor.y)
        {
            b->push_back('\r');
        }
        else
        {
            b->push_back('\n');
            s->actual.cursor.y++;
        }
        // Either way we're not in the first column
        s->actual.cursor.x = 0;
    }

    int i;
    int x_steps, y_steps;

    char *str;
    /*
      debug( 0, L"move from %d %d to %d %d",
      s->screen_cursor[0], s->screen_cursor[1],
      new_x, new_y );
    */
    scoped_buffer_t scoped_buffer(b);

    y_steps = new_y - s->actual.cursor.y;

    if (y_steps > 0 && (strcmp(cursor_down, "\n")==0))
    {
        /*
          This is very strange - it seems some (all?) consoles use a
          simple newline as the cursor down escape. This will of
          course move the cursor to the beginning of the line as well
          as moving it down one step. The cursor_up does not have this
          behaviour...
        */
        s->actual.cursor.x=0;
    }

    if (y_steps < 0)
    {
        str = cursor_up;
    }
    else
    {
        str = cursor_down;

    }

    for (i=0; i<abs(y_steps); i++)
    {
        writembs(str);
    }


    x_steps = new_x - s->actual.cursor.x;

    if (x_steps && new_x == 0)
    {
        b->push_back('\r');
        x_steps = 0;
    }

    if (x_steps < 0)
    {
        str = cursor_left;
    }
    else
    {
        str = cursor_right;
    }

    for (i=0; i<abs(x_steps); i++)
    {
        writembs(str);
    }


    s->actual.cursor.x = new_x;
    s->actual.cursor.y = new_y;
}
Exemplo n.º 11
0
/// set_color builtin.
int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    wgetopter_t w;
    // Variables used for parsing the argument list.
    const struct woption long_options[] = {{L"background", required_argument, 0, 'b'},
                                           {L"help", no_argument, 0, 'h'},
                                           {L"bold", no_argument, 0, 'o'},
                                           {L"underline", no_argument, 0, 'u'},
                                           {L"version", no_argument, 0, 'v'},
                                           {L"print-colors", no_argument, 0, 'c'},
                                           {0, 0, 0, 0}};

    const wchar_t *short_options = L"b:hvocu";

    int argc = builtin_count_args(argv);

    // Some code passes variables to set_color that don't exist, like $fish_user_whatever. As a
    // hack, quietly return failure.
    if (argc <= 1) {
        return EXIT_FAILURE;
    }

    const wchar_t *bgcolor = NULL;
    bool bold = false, underline = false;
    int errret;

    // Parse options to obtain the requested operation and the modifiers.
    w.woptind = 0;
    while (1) {
        int c = w.wgetopt_long(argc, argv, short_options, long_options, 0);

        if (c == -1) {
            break;
        }

        switch (c) {
            case 0: {
                break;
            }
            case 'b': {
                bgcolor = w.woptarg;
                break;
            }
            case 'h': {
                builtin_print_help(parser, streams, argv[0], streams.out);
                return STATUS_BUILTIN_OK;
            }
            case 'o': {
                bold = true;
                break;
            }
            case 'u': {
                underline = true;
                break;
            }
            case 'c': {
                print_colors(streams);
                return STATUS_BUILTIN_OK;
            }
            case '?': {
                return STATUS_BUILTIN_ERROR;
            }
        }
    }

    // Remaining arguments are foreground color.
    std::vector<rgb_color_t> fgcolors;
    for (; w.woptind < argc; w.woptind++) {
        rgb_color_t fg = rgb_color_t(argv[w.woptind]);
        if (fg.is_none()) {
            streams.err.append_format(_(L"%ls: Unknown color '%ls'\n"), argv[0], argv[w.woptind]);
            return STATUS_BUILTIN_ERROR;
        }
        fgcolors.push_back(fg);
    }

    if (fgcolors.empty() && bgcolor == NULL && !bold && !underline) {
        streams.err.append_format(_(L"%ls: Expected an argument\n"), argv[0]);
        return STATUS_BUILTIN_ERROR;
    }

    // #1323: We may have multiple foreground colors. Choose the best one. If we had no foreground
    // color, we'll get none(); if we have at least one we expect not-none.
    const rgb_color_t fg = best_color(fgcolors, output_get_color_support());
    assert(fgcolors.empty() || !fg.is_none());

    const rgb_color_t bg = rgb_color_t(bgcolor ? bgcolor : L"");
    if (bgcolor && bg.is_none()) {
        streams.err.append_format(_(L"%ls: Unknown color '%ls'\n"), argv[0], bgcolor);
        return STATUS_BUILTIN_ERROR;
    }

    // Make sure that the term exists.
    if (cur_term == NULL && setupterm(0, STDOUT_FILENO, &errret) == ERR) {
        streams.err.append_format(_(L"%ls: Could not set up terminal\n"), argv[0]);
        return STATUS_BUILTIN_ERROR;
    }

    // Test if we have at least basic support for setting fonts, colors and related bits - otherwise
    // just give up...
    if (!exit_attribute_mode) {
        return STATUS_BUILTIN_ERROR;
    }

    // Save old output function so we can restore it.
    int (*const saved_writer_func)(char) = output_get_writer();

    // Set our output function, which writes to a std::string.
    builtin_set_color_output.clear();
    output_set_writer(set_color_builtin_outputter);

    if (bold) {
        if (enter_bold_mode) writembs(tparm(enter_bold_mode));
    }

    if (underline) {
        if (enter_underline_mode) writembs(enter_underline_mode);
    }

    if (bgcolor != NULL) {
        if (bg.is_normal()) {
            write_color(rgb_color_t::black(), false /* not is_fg */);
            writembs(tparm(exit_attribute_mode));
        }
    }

    if (!fg.is_none()) {
        if (fg.is_normal() || fg.is_reset()) {
            write_color(rgb_color_t::black(), true /* is_fg */);
            writembs(tparm(exit_attribute_mode));
        } else {
            write_color(fg, true /* is_fg */);
        }
    }

    if (bgcolor != NULL) {
        if (!bg.is_normal() && !bg.is_reset()) {
            write_color(bg, false /* not is_fg */);
        }
    }

    // Restore saved writer function.
    output_set_writer(saved_writer_func);

    // Output the collected string.
    streams.out.append(str2wcstring(builtin_set_color_output));
    builtin_set_color_output.clear();

    return STATUS_BUILTIN_OK;
}