starship / starship

☄🌌️ The minimal, blazing-fast, and infinitely customizable prompt for any shell!
https://starship.rs
ISC License
42.92k stars 1.84k forks source link

Empty line when opening terminal #560

Open martensjostrand opened 4 years ago

martensjostrand commented 4 years ago

Bug Report

Current Behavior

When add_line is enabled a new line is added at the beginning of every new terminal window/tab.

Expected Behavior

Using add_line should not add a new line above the first line of every window / tab.

Additional context/Screenshots

new-line

Environment

Relevant Shell Configuration

eval "$(starship init zsh)"

source <(antibody init)
antibody bundle < ~/.zsh_plugins.txt

Starship Configuration

add_newline = true

Possible Solution

if config.add_newline {
        writeln!(buf).unwrap();
}

The above if-statement from https://github.com/starship/starship/blob/master/src/print.rs#L23 could be changed into something inspired by Spaceship's solution: https://github.com/maximbaz/spaceship-prompt/commit/815b68c70f21c5512765c87985897b98b8ed232c found in https://github.com/denysdovhan/spaceship-prompt/issues/462

yuri1969 commented 4 years ago

It is certainly possible to reuse https://github.com/maximbaz/spaceship-prompt/commit/815b68c70f21c5512765c87985897b98b8ed232c - check if starship has been called for the first time and pass it that information. This would prevent printing the newline after a shell initiation.

However, since starship includes the newline in PS1 it would still display the newline when issuing Ctrl+L/clear. Correct me if I'm wrong.

taranjlu commented 4 years ago

I also find this very visually distracting, particularly on clearing the screen.

mnpw commented 4 years ago

image

VSCode integrated terminal adds more padding on top of this which I find very annoying.

Sharpeee commented 4 years ago

How about something like this?

diff --git a/Cargo.toml b/Cargo.toml
index 4837654..17b0a3d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -59,6 +59,7 @@ open = "1.4.0"
 unicode-width = "0.1.8"
 textwrap = "0.12.0"
 term_size = "0.3.2"
+crossterm = "0.17"

 # Optional/http:
 attohttpc = { version = "0.15.0", optional = true, default-features = false, features = ["tls", "form"] }
diff --git a/src/print.rs b/src/print.rs
index 369f3b3..47e4783 100644
--- a/src/print.rs
+++ b/src/print.rs
@@ -4,6 +4,7 @@ use rayon::prelude::*;
 use std::fmt::{self, Debug, Write as FmtWrite};
 use std::io::{self, Write};
 use unicode_width::UnicodeWidthChar;
+use crossterm::cursor;

 use crate::context::{Context, Shell};
 use crate::module::Module;
@@ -23,7 +24,11 @@ pub fn get_prompt(context: Context) -> String {

     // Write a new line before the prompt
     if config.add_newline {
-        writeln!(buf).unwrap();
+        if let Ok(pos) = cursor::position() {
+            if pos != (0, 0) {
+                writeln!(buf).unwrap();
+            }
+        }
     }

     // A workaround for a fish bug (see #739,#279). Applying it to all shells

I think this should eliminate the Ctrl+L/clear problem as well and handle the root situation as well.

Note, I am not a Rust programmer. In fact, this is my first Rust code, so you can probably do better. I have only tested this using cargo run -- prompt as I do not know how to use this binary outside of the project tree.

yuri1969 commented 4 years ago

@Sharpeee Just a quick observation. On my machine (Linux urxvt+Bash), it takes over 1sec to render when running the patched binary as a prompt (on $PATH).

Sharpeee commented 4 years ago

@yuri1969 I have seen some weird behaviour as well. It works as expected when I run it through cargo, but fails when running as stand-alone. I will look into it when I have time.

If it does not work using crossterm, maybe there is another way to get the current cursor position?

Sharpeee commented 3 years ago

FYI: I have moved back to a one line prompt (not because of this issue), so I will not look any more at this.

chipbuster commented 3 years ago

Related issue at spaceship: https://github.com/denysdovhan/spaceship-prompt/issues/462

Looks like Spaceship hasn't solved this issue either. I tried applying the patch from https://github.com/maximbaz/spaceship-prompt/commit/815b68c70f21c5512765c87985897b98b8ed232c to the current version of spaceship, but it straight-up doesn't work--it just disables the newlines altogether.

The issue that @yuri1969 brought up is also relevant here, since even if we fix the first newline (when the shell initializes), we have no way of knowing if the screen's been cleared, since that happens while the shell is still running.

It seems that at least some shells implement screen clear by just emitting a form-feed character, so there's no way in general to figure out if the screen has been cleared, because the shell doesn't have to tell us what it's doing, and starship does not read the output of the shell it's currently attached to (nor should it).

I really don't want to tie the prompt to a terminal either. While the crossterm trick is an interesting idea, we already have several terminal compatibility issues, and I the last thing I want is to make those more explicit.

So at the moment, I'm stumped. In essence, we need some way to detect if we're printing at the top of the terminal (because the shell was just launched, or because the user cleared the screen with CTRL+L, or because the user ran echo -e '\0033\0143', or because the VTE-based terminal received a Reset-and-Clear command, or because an xterm-based system received Esc-c......) but without being explicitly tied to a terminal type.

chipbuster commented 3 years ago

If we're shooting for ANSI-compatible terminals, I suppose we could try using ANSI escape codes to query the cursor position, but we'd need some way to intercept that response before it gets printed to the terminal. We do currently use ANSI color codes already, but I don't know how general the support is for the full ANSI escape code set: it might be a very different game for a terminal to support just color codes vs. a full set of ANSI control sequences.

jspiro commented 3 years ago

While I see how this issue is the commonality of the others referenced and closed, and an extra empty line is annoying–I don't feel it's as significant as the first line of the prompt being missing after clearing the buffer (when you run Clear Buffer in e.g. iTerm), and may garner more attention from the community.

I.e. #1601 seems like it should be left open, even if it shares the cause of #560.

chipbuster commented 3 years ago

I wasn't tracking #1601 closely, but the post there mentions that zprezto doesn't have this issue, which we could potentially investigate for a solution (I had tried previously to look at how this was supposedly solved in a spaceship fork, but the patches there just caused my shell to crash and I couldn't work out why).

ghost commented 2 years ago

I have a question.. Will this bug be fixed and merged say EVER in future?

matchai commented 2 years ago

I have a question.. Will this bug be fixed and merged say EVER in future?

If you have an idea for how to address this issue, pull requests are welcome. 😊

cbrnr commented 1 year ago

I don't know if this is possible, but instead of adding a newline before the prompt, would it be possible to add it after any output?

chipbuster commented 1 year ago

@cbrnr The tricky part is that we don't control that from within starship. If this were a shell-language-based prompt, this would be much easier to do, but currently (as far as I know), detecting that output occurred would require us to write a hook into the shell init scripts, then examine that from starship (and we'd have to do this for all 10 shells we currently support, plus potentially additional ones we have support requests for like mksh).

justaskz commented 1 year ago

zsh users can add this to their .zshrc:

precmd() { precmd() { echo "" } }
cbrnr commented 1 year ago

Thanks @justaskz, this is a nice workaround which I will use (in combination with add_newline = false).

JJJ commented 1 year ago
# Put new-line inside of ($all) variable)
format = """($all
)$character"""

add_newline = false

[line_break]
disabled = true

This config successfully omits empty lines (even for clear) while also ensuring the prompt itself starts on its own line when output exists ahead of it.

See: https://starship.rs/config/#conditional-format-strings

Edit: Above snippet intentionally omits the single empty line used to separate commands. To include it anyways, use this instead:

# Put extra empty new-line inside of ($all) variable)
format = """($all

)$character"""

add_newline = false

[line_break]
disabled = true

jjj-on-2023-01-09-at-09-32-02@2x
jjj-on-2023-01-09-at-09-33-05@2x
domsleee commented 1 year ago

@JJJ isn't your suggestion the same as add_newline = false and [line_break.disabled] = false? It seems to be the same on windows terminal + powershell: image

The issue I'm having is with add_newline = true and [line_break.disabled] = false, this newline specifically: image

AnkushMalaker commented 1 year ago

Using @JJJ 's solution did work to remove the new_line, but also removed the new_line after commands, which is important for me.

I tried to adapt @justaskz 's answer for fish shell by putting the following in my ~/.config/fish/config.fish like this:

function fish_preexec
  echo ""
end

This doesn't work.

The following also doesn't work:

function fish_prompt
    echo ""
end

I understand it's a bit more complicated to solve completely within starship but could I have any workarounds for fish? Thanks!

domsleee commented 1 year ago

@AnkushMalaker try this for fish? Looks like the syntax is --on-event to hook into those events

~/.config/fish/config.fish:

if status is-interactive
    function echo_prompt --on-event fish_postexec
        echo ""
    end
end

With the defaults of starship.toml (for example an empty starship.toml) With add_newline = false in starship.toml, screenshot:

image

AnkushMalaker commented 1 year ago

Thanks for the suggestion @domsleee , unfortunately that doesn't work either. @justaskz , just to confirm, can your suggestion be used along with "new_line = true"? If not, then I assume the behaviour of suggestion by JJJ is the same.

justaskz commented 1 year ago

@AnkushMalaker my solution is tested only on zsh

Aleksanaa commented 1 year ago

For ble.sh/bash users, you don't have to use add_newline = true, instead, add bleopt prompt_ruler=empty-line to .blerc. This will get all the things done, including clear and Ctrl+L. Also see blerc.template

domsleee commented 11 months ago

zsh users can add this to their .zshrc:

precmd() { precmd() { echo "" } }

I would add that a similar approach for bash in .bashrc is this:

my_precmd() {
    echo ''
}
export PROMPT_COMMAND=my_precmd

# By defining starship after, PROMPT_COMMAND is wrapped by the init script
eval "$(starship init bash)"

With add_newline = false in starship config

JJJ commented 11 months ago

I assume the behaviour of suggestion by JJJ is the same.

👋 I updated my snippet to include both configs (single & double breaks between commands)

Tottitov commented 5 days ago

zsh users can add this to their .zshrc:

precmd() { precmd() { echo "" } }

I would add that a similar approach for bash in .bashrc is this:

my_precmd() {
    echo ''
}
export PROMPT_COMMAND=my_precmd

# By defining starship after, PROMPT_COMMAND is wrapped by the init script
eval "$(starship init bash)"

With add_newline = false in starship config

I found that using clear still adds a new line in zsh, so I added this alias for clear

clear="precmd() { precmd() { echo } } && clear"