From a595d71cbdf34236d3fc2d85cf076b80f4d57b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sat, 22 Oct 2022 18:31:35 +0200 Subject: [PATCH] Improved support for leading newline * New modes that either print it only when it isn't the first line, or only add it (as well as a warning) if the last command didn't return a newline. * Overengineered af. --- README.md | 12 ++++- example-gprompt.rc | 5 +- gprompt.pl | 101 +++++++++++++++++++++++++++++++++++++--- themes/ascii_gyr.pm | 7 +++ themes/ascii_yb.pm | 7 +++ themes/blocks_gyr.pm | 7 +++ themes/blocks_yb.pm | 7 +++ themes/powerline_gyr.pm | 7 +++ themes/powerline_yb.pm | 7 +++ 9 files changed, 149 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index a24d0f7..e5ac56e 100644 --- a/README.md +++ b/README.md @@ -142,8 +142,16 @@ The `layout_*` variables control the prompt's layout and general appearance: default this entry contains an empty string. * `layout_input_always` determines whether the input line should be rendered even if no generators are specified (`0` or `1`, default `0`). -* `layout_empty_line` prints an empty line before the prompt's top line. This - prevents display problems when some command outputs a line without `\n`. +* `layout_empty_line` determines how the prompt handles printing an empty line + before the prompt's top line. + * When set to `0`, no extra line is drawn, and commands that do not end with + an EOL will cause the prompt's first line to be displayed incorrectly. + * When set to `1`, the prompt's top line will always be preceeded with an + empty line. + * When set to `2`, the prompt will be preceeded by an empty line unless it + is being drawn on the terminal's first line. + * When set to `3`, a newline will be added to the prompt if the last + command's output didn't end with a newline. The `term_*` variables control the prompt's ability to change the terminal's title and/or icon title: diff --git a/example-gprompt.rc b/example-gprompt.rc index e121bd4..5030c29 100644 --- a/example-gprompt.rc +++ b/example-gprompt.rc @@ -33,8 +33,9 @@ ] , # - Always generate input line? layout_input_always => 0 , - # - Add an empty line before the prompt? - layout_empty_line => 0 , + # - Add an empty line before the prompt? 0=no, 1=always, 2=not at the top + # of the terminal, 3=only if the previous command didn't finish with \n + layout_empty_line => 3 , # TERMINAL TITLE # - Set title from the prompt? 0=no, 1=normal, 2=minimized, 3=both diff --git a/gprompt.pl b/gprompt.pl index e60e868..b0648df 100644 --- a/gprompt.pl +++ b/gprompt.pl @@ -12,7 +12,7 @@ use strict; use warnings; use utf8; use open ':std', ':encoding(UTF-8)'; -use POSIX qw(strftime); +use POSIX qw(strftime :termios_h); use Cwd qw(abs_path getcwd); @@ -45,8 +45,9 @@ our %CONFIG = ( layout_input => [ qw( userhost cwd ) ] , # - Always generate input line? layout_input_always => 0 , - # - Add an empty line before the prompt? - layout_empty_line => 0 , + # - Add an empty line before the prompt? 0=no, 1=always, 2=not at the top + # of the terminal, 3=only if the previous command didn't finish with \n + layout_empty_line => 3 , # TERMINAL TITLE # - Set title from the prompt? 0=no, 1=normal, 2=minimized, 3=both @@ -151,6 +152,13 @@ sub default_theme 'bg_ps2' => -2, ps2_suffix => ' : ' , + # Text appended to a line without EOL when layout_empty_line is 3 + 'noeol_text' => '' , + # Colors and style for the above text + 'noeol_fg' => 1 , + 'noeol_bg' => -1 , + 'noeol_style' => 'b' , + # Current working directory - Truncation string cwd_trunc => '...' , # Current working directory - Foreground / background colors @@ -302,6 +310,51 @@ sub set_color return tput_sequence( "seta$type $index" ); } +sub get_cursor_pos +{ + local $| = 1; + open(my $ttyIn, '<:bytes' , '/dev/tty'); + open(my $ttyOut, '>:bytes' , '/dev/tty'); + + # Enable raw mode + my $term = POSIX::Termios->new; + my $ttyInFd = fileno $ttyIn; + $term->getattr($ttyInFd); + my $oTerm = $term ->getlflag; + $term->setlflag($oTerm & ~( ECHO | ECHOK | ICANON )); + $term->setcc(VTIME, 1); + $term->setattr($ttyInFd, TCSANOW); + + # Read position + syswrite $ttyOut, "\033[6n", 4; + my ($input, $col, $line) = ("", "", ""); + my $state = 0; + while (sysread $ttyIn, $input, 1) { + if ($state == 0) { + $state = 1 if $input eq '['; + } elsif ($state == 1) { + if ($input eq ';') { + $state = 2; + } else { + $line .= $input; + } + } elsif ($state == 2) { + last if $input eq 'R'; + $col .= $input; + } + } + + # Enable cooked mode + $term->setlflag($oTerm); + $term->setcc(VTIME, 0); + $term->setattr($ttyInFd, TCSANOW); + + close $ttyIn; + close $ttyOut; + + return $line, $col; +} + #}}} # Theming support -----------------------------------------------------------{{{ @@ -593,6 +646,33 @@ sub render #}}} # Prompt parts --------------------------------------------------------------{{{ +sub gen_empty_line +{ + my $lel = $CONFIG{layout_empty_line}; + my $nl; + my $out = ""; + if ($lel > 1) { + my ($line, $col) = get_cursor_pos; + $nl = ( $lel == 2 && $line != 1 ) || ( $lel == 3 && $col != 1 ); + if ( $lel == 3 && $col != 1 ) { + $out .= render('input', { + content => [ + { + style => themed 'noeol_style' , + fg => themed 'noeol_fg' , + bg => themed 'noeol_bg' , + }, + ( themed 'noeol_text' ) + ] + }); + } + } else { + $nl = $lel + } + $out .= "\\n" if $nl; + return $out; +} + sub gen_top_line { my @left = @{ $CONFIG{layout_left} }; @@ -750,17 +830,24 @@ _gprompt_set_return() { return "\${1:-0}" } gprompt_command() { - local cmd_status=\$? + _GPROMPT_PREV_STATUS=\$? local jobs=(\$(jobs -p)) eval "\$_GPROMPT_PREVIOUS_PCMD" - eval "\$( perl \Q$gpPath\E "rc:\$cmd_status" "jobs:\${#jobs[@]}" )" - _gprompt_set_return "\$cmd_status" + eval "\$( perl \Q$gpPath\E "rc:\$_GPROMPT_PREV_STATUS" "jobs:\${#jobs[@]}" )" + _gprompt_set_return "\$_GPROMPT_PREV_STATUS" +} +_gprompt_clear() { + clear -x + _gprompt_set_return "\${_GPROMPT_PREV_STATUS:-0}" + gprompt_command + echo -n "\${PS1\@P}\r" } shopt -s checkwinsize if [[ \$PROMPT_COMMAND != *"gprompt_command"* ]]; then _GPROMPT_PREVIOUS_PCMD="\$PROMPT_COMMAND" PROMPT_COMMAND="gprompt_command" fi +bind -x \$'"\\C-l":_gprompt_clear' EOF exit 0; } @@ -793,7 +880,7 @@ sub main %TLEN = compute_trans_lengths; my $pg = gen_term_title; my $ps1 = $pg; - $ps1 .= "\\n" if $CONFIG{layout_empty_line}; + $ps1 .= gen_empty_line; $ps1 .= gen_top_line; my ( $ill , $ilt ) = gen_input_line; $ps1 .= $ilt; diff --git a/themes/ascii_gyr.pm b/themes/ascii_gyr.pm index 4339e93..1d10e41 100644 --- a/themes/ascii_gyr.pm +++ b/themes/ascii_gyr.pm @@ -42,6 +42,13 @@ 'bg_ps2' => thref 'bg', ps2_suffix => '\b2\f3| ' , + # Text appended to a line without EOL when layout_empty_line is 3 + 'noeol_text' => '' , + # Colors and style for the above text + 'noeol_fg' => thref 'fg3' , + 'noeol_bg' => thref 'bg3' , + 'noeol_style' => 'b' , + # Current working directory - Truncation string cwd_trunc => '...' , # Current working directory - Foreground / background colors diff --git a/themes/ascii_yb.pm b/themes/ascii_yb.pm index 39ebc3e..fbd3592 100644 --- a/themes/ascii_yb.pm +++ b/themes/ascii_yb.pm @@ -42,6 +42,13 @@ 'bg_ps2' => thref 'bg', ps2_suffix => '\b2\f3| ' , + # Text appended to a line without EOL when layout_empty_line is 3 + 'noeol_text' => '' , + # Colors and style for the above text + 'noeol_fg' => thref 'fg3' , + 'noeol_bg' => thref 'bg3' , + 'noeol_style' => 'b' , + # Current working directory - Truncation string cwd_trunc => '...' , # Current working directory - Foreground / background colors diff --git a/themes/blocks_gyr.pm b/themes/blocks_gyr.pm index 703c4ab..bcb6007 100644 --- a/themes/blocks_gyr.pm +++ b/themes/blocks_gyr.pm @@ -42,6 +42,13 @@ 'bg_ps2' => thref 'bg', 'ps2_suffix' => "\\b2\\f3\x{250a} ", + # Text appended to a line without EOL when layout_empty_line is 3 + 'noeol_text' => "\x{b6}" , + # Colors and style for the above text + 'noeol_fg' => thref 'fg3' , + 'noeol_bg' => thref 'bg3' , + 'noeol_style' => 'b' , + # Current working directory - Truncation string 'cwd_trunc' => "\x{2026}", # Current working directory - Foreground / background colors diff --git a/themes/blocks_yb.pm b/themes/blocks_yb.pm index 76e1708..5832bc7 100644 --- a/themes/blocks_yb.pm +++ b/themes/blocks_yb.pm @@ -42,6 +42,13 @@ 'bg_ps2' => thref 'bg', 'ps2_suffix' => "\\b2\\f3\x{250a} ", + # Text appended to a line without EOL when layout_empty_line is 3 + 'noeol_text' => "\x{b6}" , + # Colors and style for the above text + 'noeol_fg' => thref 'fg3' , + 'noeol_bg' => thref 'bg3' , + 'noeol_style' => 'b' , + # Current working directory - Truncation string 'cwd_trunc' => "\x{2026}", # Current working directory - Foreground / background colors diff --git a/themes/powerline_gyr.pm b/themes/powerline_gyr.pm index 3db23f7..cda8f83 100644 --- a/themes/powerline_gyr.pm +++ b/themes/powerline_gyr.pm @@ -41,6 +41,13 @@ 'bg_ps2' => 234, 'ps2_suffix' => '\f0\b2'."\x{e0b0}".'\f2\b1'."\x{e0b0}".' ' , + # Text appended to a line without EOL when layout_empty_line is 3 + 'noeol_text' => "\x{e0b0} \x{26a0} \x{e0b2}" , + # Colors and style for the above text + 'noeol_fg' => thref 'fg3' , + 'noeol_bg' => thref 'bg3' , + 'noeol_style' => 'b' , + # Current working directory - Truncation string 'cwd_trunc' => "\x{2026}", # Current working directory - Foreground / background colors diff --git a/themes/powerline_yb.pm b/themes/powerline_yb.pm index aa02959..feec55f 100644 --- a/themes/powerline_yb.pm +++ b/themes/powerline_yb.pm @@ -41,6 +41,13 @@ 'bg_ps2' => 234, 'ps2_suffix' => '\f0\b2'."\x{e0b0}".'\f2\b1'."\x{e0b0}".' ' , + # Text appended to a line without EOL when layout_empty_line is 3 + 'noeol_text' => "\x{e0b0} \x{26a0} \x{e0b2}" , + # Colors and style for the above text + 'noeol_fg' => thref 'fg3' , + 'noeol_bg' => thref 'bg3' , + 'noeol_style' => 'b' , + # Current working directory - Truncation string 'cwd_trunc' => "\x{2026}", # Current working directory - Foreground / background colors