/// Calculate layout information for the given prompt. Does some clever magic to detect common /// escape sequences that may be embeded in a prompt, such as those to set visual attributes. static prompt_layout_t calc_prompt_layout(const wcstring &prompt, layout_cache_t &cache) { if (auto cached_layout = cache.find_prompt_layout(prompt)) { return *cached_layout; } prompt_layout_t prompt_layout = {1, 0, 0}; size_t current_line_width = 0; for (int j = 0; prompt[j]; j++) { if (prompt[j] == L'\x1B') { // This is the start of an escape code. Skip over it if it's at least one char long. size_t len = escape_code_length(&prompt[j]); if (len > 0) j += len - 1; } else if (prompt[j] == L'\t') { current_line_width = next_tab_stop(current_line_width); } else if (prompt[j] == L'\n' || prompt[j] == L'\f') { // PCA: At least one prompt uses \f\r as a newline. It's unclear to me what this is // meant to do, but terminals seem to treat it as a newline so we do the same. current_line_width = 0; prompt_layout.line_count += 1; } else if (prompt[j] == L'\r') { current_line_width = 0; } else { // Ordinary char. Add its width with care to ignore control chars which have width -1. current_line_width += fish_wcwidth_min_0(prompt[j]); if (current_line_width > prompt_layout.max_line_width) { prompt_layout.max_line_width = current_line_width; } } } prompt_layout.last_line_width = current_line_width; cache.add_prompt_layout(prompt, prompt_layout); return prompt_layout; }
/// Calculate layout information for the given prompt. Does some clever magic to detect common /// escape sequences that may be embeded in a prompt, such as color codes. static prompt_layout_t calc_prompt_layout(const wchar_t *prompt) { size_t current_line_width = 0; size_t j; prompt_layout_t prompt_layout = {}; prompt_layout.line_count = 1; for (j = 0; prompt[j]; j++) { if (prompt[j] == L'\x1b') { // This is the start of an escape code. Skip over it if it's at least one character // long. size_t escape_len = escape_code_length(&prompt[j]); if (escape_len > 0) { j += escape_len - 1; } } else if (prompt[j] == L'\t') { current_line_width = next_tab_stop(current_line_width); } else if (prompt[j] == L'\n' || prompt[j] == L'\f') { // PCA: At least one prompt uses \f\r as a newline. It's unclear to me what this is // meant to do, but terminals seem to treat it as a newline so we do the same. current_line_width = 0; prompt_layout.line_count += 1; } else if (prompt[j] == L'\r') { current_line_width = 0; } else { // Ordinary decent character. Just add width. This returns -1 for a control character - // don't add that. current_line_width += fish_wcwidth_min_0(prompt[j]); prompt_layout.max_line_width = maxi(prompt_layout.max_line_width, current_line_width); } } prompt_layout.last_line_width = current_line_width; return prompt_layout; }
int main(int argc, char *argv[]) { int column = 0; int space_run = 0; int c; if (argc > 1) { argv++; while (argv[0]) { if (argv[0][0] == '-') to_i(&argv[0][1], &tab_start); if (argv[0][0] == '+') to_i(&argv[0][1], &tab_width); argv++; } } while ((c = getchar()) != EOF) { if (c == ' ') { ++space_run; } else if (c == '\n') { column = -1; space_run = 0; putchar(c); } else { if (space_run == 1) { putchar(' '); space_run = 0; } while (space_run > 0) { int start_of_space_run = column - space_run; int next_stop = next_tab_stop(start_of_space_run); if (next_stop <= column) { putchar('\t'); space_run -= next_stop - start_of_space_run; } else { for (; space_run > 0; space_run--) putchar(' '); } } putchar(c); } ++column; } }
/** Calculate the width of the specified prompt. Does some clever magic to detect common escape sequences that may be embeded in a prompt, such as color codes. */ static int calc_prompt_width( wchar_t *prompt ) { int res = 0; int j, k; for( j=0; prompt[j]; j++ ) { if( prompt[j] == L'\x1b' ) { /* This is the start of an escape code. Try to guess it's width. */ int l; int len=0; int found = 0; /* Detect these terminfo color escapes with parameter value 0..7, all of which don't move the cursor */ char * esc[] = { set_a_foreground, set_a_background, set_foreground, set_background, } ; /* Detect these semi-common terminfo escapes without any parameter values, all of which don't move the cursor */ char *esc2[] = { enter_bold_mode, exit_attribute_mode, enter_underline_mode, exit_underline_mode, enter_standout_mode, exit_standout_mode, flash_screen, enter_subscript_mode, exit_subscript_mode, enter_superscript_mode, exit_superscript_mode, enter_blink_mode, enter_italics_mode, exit_italics_mode, enter_reverse_mode, enter_shadow_mode, exit_shadow_mode, enter_standout_mode, exit_standout_mode, enter_secure_mode } ; for( l=0; l < (sizeof(esc)/sizeof(char *)) && !found; l++ ) { if( !esc[l] ) continue; for( k=0; k<8; k++ ) { len = try_sequence( tparm(esc[l],k), &prompt[j] ); if( len ) { j += (len-1); found = 1; break; } } } for( l=0; l < (sizeof(esc2)/sizeof(char *)) && !found; l++ ) { if( !esc2[l] ) continue; /* Test both padded and unpadded version, just to be safe. Most versions of tparm don't actually seem to do anything these days. */ len = maxi( try_sequence( tparm(esc2[l]), &prompt[j] ), try_sequence( esc2[l], &prompt[j] )); if( len ) { j += (len-1); found = 1; } } if( !found ) { if( prompt[j+1] == L'k' ) { wchar_t *term_name = env_get( L"TERM" ); if( term_name && wcsstr( term_name, L"screen" ) == term_name ) { wchar_t *end; j+=2; found = 1; end = wcsstr( &prompt[j], L"\x1b\\" ); if( end ) { /* You'd thing this should be '(end-prompt)+2', in order to move j past the end of the string, but there is a 'j++' at the end of each lap, so j should always point to the last menged character, e.g. +1. */ j = (end-prompt)+1; } else { break; } } } } } else if( prompt[j] == L'\t' ) { res = next_tab_stop( res ); } else if( prompt[j] == L'\n' ) { res = 0; } else { /* Ordinary decent character. Just add width. */ res += wcwidth( prompt[j] ); } } return res; }
/** Calculate layout information for the given prompt. Does some clever magic to detect common escape sequences that may be embeded in a prompt, such as color codes. */ static prompt_layout_t calc_prompt_layout(const wchar_t *prompt) { size_t current_line_width = 0; size_t j, k; prompt_layout_t prompt_layout = {}; prompt_layout.line_count = 1; for (j=0; prompt[j]; j++) { if (prompt[j] == L'\x1b') { /* This is the start of an escape code. Try to guess its width. */ size_t p; int len=0; bool found = false; /* Detect these terminfo color escapes with parameter value 0..7, all of which don't move the cursor */ char * const esc[] = { set_a_foreground, set_a_background, set_foreground, set_background, } ; /* Detect these semi-common terminfo escapes without any parameter values, all of which don't move the cursor */ char * const esc2[] = { enter_bold_mode, exit_attribute_mode, enter_underline_mode, exit_underline_mode, enter_standout_mode, exit_standout_mode, flash_screen, enter_subscript_mode, exit_subscript_mode, enter_superscript_mode, exit_superscript_mode, enter_blink_mode, enter_italics_mode, exit_italics_mode, enter_reverse_mode, enter_shadow_mode, exit_shadow_mode, enter_standout_mode, exit_standout_mode, enter_secure_mode } ; for (p=0; p < sizeof esc / sizeof *esc && !found; p++) { if (!esc[p]) continue; for (k=0; k<8; k++) { len = try_sequence(tparm(esc[p],k), &prompt[j]); if (len) { j += (len-1); found = true; break; } } } /* PCA for term256 support, let's just detect the escape codes directly */ if (! found) { len = is_term256_escape(&prompt[j]); if (len) { j += (len - 1); found = true; } } for (p=0; p < (sizeof(esc2)/sizeof(char *)) && !found; p++) { if (!esc2[p]) continue; /* Test both padded and unpadded version, just to be safe. Most versions of tparm don't actually seem to do anything these days. */ len = maxi(try_sequence(tparm(esc2[p]), &prompt[j]), try_sequence(esc2[p], &prompt[j])); if (len) { j += (len-1); found = true; } } if (!found) { if (prompt[j+1] == L'k') { const env_var_t term_name = env_get_string(L"TERM"); if (!term_name.missing() && wcsstr(term_name.c_str(), L"screen") == term_name) { const wchar_t *end; j+=2; found = true; end = wcsstr(&prompt[j], L"\x1b\\"); if (end) { /* You'd thing this should be '(end-prompt)+2', in order to move j past the end of the string, but there is a 'j++' at the end of each lap, so j should always point to the last menged character, e.g. +1. */ j = (end-prompt)+1; } else { break; } } } } } else if (prompt[j] == L'\t') { current_line_width = next_tab_stop(current_line_width); } else if (prompt[j] == L'\n' || prompt[j] == L'\f') { /* PCA: At least one prompt uses \f\r as a newline. It's unclear to me what this is meant to do, but terminals seem to treat it as a newline so we do the same. */ current_line_width = 0; prompt_layout.line_count += 1; } else if (prompt[j] == L'\r') { current_line_width = 0; } else { /* Ordinary decent character. Just add width. This returns -1 for a control character - don't add that. */ current_line_width += fish_wcwidth_min_0(prompt[j]); prompt_layout.max_line_width = maxi(prompt_layout.max_line_width, current_line_width); } } prompt_layout.last_line_width = current_line_width; return prompt_layout; }