void s_write( screen_t *s, const wchar_t *prompt, const wchar_t *commandline, size_t explicit_len, const int *c, const int *indent, size_t cursor_pos ) { screen_data_t::cursor_t cursor_arr; size_t prompt_width; size_t screen_width; int current_line_width = 0, newline_count = 0, explicit_portion_width = 0; size_t max_line_width = 0; CHECK( s, ); CHECK( prompt, ); CHECK( commandline, ); CHECK( c, ); CHECK( indent, ); /* If we are using a dumb terminal, don't try any fancy stuff, just print out the text. */ if( is_dumb() ) { char *prompt_narrow = wcs2str( prompt ); char *buffer_narrow = wcs2str( commandline ); write_loop( 1, "\r", 1 ); write_loop( 1, prompt_narrow, strlen( prompt_narrow ) ); write_loop( 1, buffer_narrow, strlen( buffer_narrow ) ); free( prompt_narrow ); free( buffer_narrow ); return; } prompt_width = calc_prompt_width( prompt ); screen_width = common_get_width(); s_check_status( s ); /* Ignore prompts wider than the screen - only print a two character placeholder... It would be cool to truncate the prompt, but because it can contain escape sequences, this is harder than you'd think. */ if( prompt_width >= screen_width ) { prompt = L"> "; prompt_width = 2; } /* Completely ignore impossibly small screens */ if( screen_width < 4 ) { return; } /* Check if we are overflowing */ size_t last_char_that_fits = 0; for( size_t i=0; commandline[i]; i++ ) { if( commandline[i] == L'\n' ) { if( current_line_width > max_line_width ) max_line_width = current_line_width; current_line_width = indent[i]*INDENT_STEP; newline_count++; } else { int width = fish_wcwidth(commandline[i]); current_line_width += width; if (i < explicit_len) explicit_portion_width += width; if (prompt_width + current_line_width < screen_width) last_char_that_fits = i; } } if( current_line_width > max_line_width ) max_line_width = current_line_width; s->desired.resize(0); s->desired.cursor.x = s->desired.cursor.y = 0; /* If we cannot fit with the autosuggestion, but we can fit without it, truncate the autosuggestion. We limit this check to just one line to avoid confusion; not sure how well this would work with multiple lines */ wcstring truncated_autosuggestion_line; if (newline_count == 0 && prompt_width + max_line_width >= screen_width && prompt_width + explicit_portion_width < screen_width) { assert(screen_width - prompt_width >= 1); max_line_width = screen_width - prompt_width - 1; truncated_autosuggestion_line = wcstring(commandline, 0, last_char_that_fits); commandline = truncated_autosuggestion_line.c_str(); } for( size_t i=0; i<prompt_width; i++ ) { s_desired_append_char( s, L' ', 0, 0, prompt_width ); } /* If overflowing, give the prompt its own line to improve the situation. */ if( max_line_width + prompt_width >= screen_width ) { s_desired_append_char( s, L'\n', 0, 0, 0 ); prompt_width=0; } size_t i; for( i=0; commandline[i]; i++ ) { int col = c[i]; if( i == cursor_pos ) { col = 0; } if( i == cursor_pos ) { cursor_arr = s->desired.cursor; } s_desired_append_char( s, commandline[i], col, indent[i], prompt_width ); } if( i == cursor_pos ) { cursor_arr = s->desired.cursor; } s->desired.cursor = cursor_arr; s_update( s, prompt ); s_save_status( s ); }
void s_write(screen_t *s, const wcstring &left_prompt, const wcstring &right_prompt, const wcstring &commandline, size_t explicit_len, const std::vector<highlight_spec_t> &colors, const std::vector<int> &indent, size_t cursor_pos, const page_rendering_t &pager, bool cursor_is_within_pager) { screen_data_t::cursor_t cursor_arr; // Turn the command line into the explicit portion and the autosuggestion. const wcstring explicit_command_line = commandline.substr(0, explicit_len); const wcstring autosuggestion = commandline.substr(explicit_len); // If we are using a dumb terminal, don't try any fancy stuff, just print out the text. // right_prompt not supported. if (is_dumb()) { const std::string prompt_narrow = wcs2string(left_prompt); const std::string command_line_narrow = wcs2string(explicit_command_line); write_loop(STDOUT_FILENO, "\r", 1); write_loop(STDOUT_FILENO, prompt_narrow.c_str(), prompt_narrow.size()); write_loop(STDOUT_FILENO, command_line_narrow.c_str(), command_line_narrow.size()); return; } s_check_status(s); const size_t screen_width = common_get_width(); // Completely ignore impossibly small screens. if (screen_width < 4) { return; } // Compute a layout. const screen_layout_t layout = compute_layout(s, screen_width, left_prompt, right_prompt, explicit_command_line, autosuggestion, indent); // Determine whether, if we have an autosuggestion, it was truncated. s->autosuggestion_is_truncated = !autosuggestion.empty() && autosuggestion != layout.autosuggestion; // Clear the desired screen. s->desired.resize(0); s->desired.cursor.x = s->desired.cursor.y = 0; // Append spaces for the left prompt. for (size_t i = 0; i < layout.left_prompt_space; i++) { s_desired_append_char(s, L' ', highlight_spec_t{}, 0, layout.left_prompt_space); } // If overflowing, give the prompt its own line to improve the situation. size_t first_line_prompt_space = layout.left_prompt_space; if (layout.prompts_get_own_line) { s_desired_append_char(s, L'\n', highlight_spec_t{}, 0, 0); first_line_prompt_space = 0; } // Reconstruct the command line. wcstring effective_commandline = explicit_command_line + layout.autosuggestion; // Output the command line. size_t i; for (i = 0; i < effective_commandline.size(); i++) { // Grab the current cursor's x,y position if this character matches the cursor's offset. if (!cursor_is_within_pager && i == cursor_pos) { cursor_arr = s->desired.cursor; } s_desired_append_char(s, effective_commandline.at(i), colors[i], indent[i], first_line_prompt_space); } // Cursor may have been at the end too. if (!cursor_is_within_pager && i == cursor_pos) { cursor_arr = s->desired.cursor; } // Now that we've output everything, set the cursor to the position that we saved in the loop // above. s->desired.cursor = cursor_arr; if (cursor_is_within_pager) { s->desired.cursor.x = (int)cursor_pos; s->desired.cursor.y = (int)s->desired.line_count(); } // Append pager_data (none if empty). s->desired.append_lines(pager.screen_data); s_update(s, layout.left_prompt, layout.right_prompt); s_save_status(s); }
void s_write(screen_t *s, const wcstring &left_prompt, const wcstring &right_prompt, const wcstring &commandline, size_t explicit_len, const int *colors, const int *indent, size_t cursor_pos) { screen_data_t::cursor_t cursor_arr; CHECK(s,); CHECK(indent,); /* Turn the command line into the explicit portion and the autosuggestion */ const wcstring explicit_command_line = commandline.substr(0, explicit_len); const wcstring autosuggestion = commandline.substr(explicit_len); /* If we are using a dumb terminal, don't try any fancy stuff, just print out the text. right_prompt not supported. */ if (is_dumb()) { const std::string prompt_narrow = wcs2string(left_prompt); const std::string command_line_narrow = wcs2string(explicit_command_line); write_loop(STDOUT_FILENO, "\r", 1); write_loop(STDOUT_FILENO, prompt_narrow.c_str(), prompt_narrow.size()); write_loop(STDOUT_FILENO, command_line_narrow.c_str(), command_line_narrow.size()); return; } s_check_status(s); const size_t screen_width = common_get_width(); /* Completely ignore impossibly small screens */ if (screen_width < 4) { return; } /* Compute a layout */ const screen_layout_t layout = compute_layout(s, screen_width, left_prompt, right_prompt, explicit_command_line, autosuggestion, indent); /* Determine whether, if we have an autosuggestion, it was truncated */ s->autosuggestion_is_truncated = ! autosuggestion.empty() && autosuggestion != layout.autosuggestion; /* Clear the desired screen */ s->desired.resize(0); s->desired.cursor.x = s->desired.cursor.y = 0; /* Append spaces for the left prompt */ for (size_t i=0; i < layout.left_prompt_space; i++) { s_desired_append_char(s, L' ', 0, 0, layout.left_prompt_space); } /* If overflowing, give the prompt its own line to improve the situation. */ size_t first_line_prompt_space = layout.left_prompt_space; if (layout.prompts_get_own_line) { s_desired_append_char(s, L'\n', 0, 0, 0); first_line_prompt_space = 0; } /* Reconstruct the command line */ wcstring effective_commandline = explicit_command_line + layout.autosuggestion; /* Output the command line */ size_t i; for (i=0; i < effective_commandline.size(); i++) { int color = colors[i]; if (i == cursor_pos) { color = 0; } if (i == cursor_pos) { cursor_arr = s->desired.cursor; } s_desired_append_char(s, effective_commandline.at(i), color, indent[i], first_line_prompt_space); } if (i == cursor_pos) { cursor_arr = s->desired.cursor; } s->desired.cursor = cursor_arr; s_update(s, layout.left_prompt.c_str(), layout.right_prompt.c_str()); s_save_status(s); }