From 58347d494a7c5da3692f7fe57a95b608c0c42368 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Fri, 23 Dec 2016 13:08:45 -0800 Subject: [PATCH] update PROMPT_SP heuristic Update our implementation of the PROMPT_SP heuristic to match current zsh behavior. This makes it behave better on terminals like ConEmu and the native MS Windows console which automatically insert a newline when writing to the last column of the line. Fixes #789 --- src/env.cpp | 11 +++++++++++ src/env.h | 2 ++ src/screen.cpp | 18 +++++++++++++----- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/env.cpp b/src/env.cpp index 3f98f3504..a8b8618fa 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -14,6 +14,13 @@ #include #include #include + +#if HAVE_TERM_H +#include +#elif HAVE_NCURSES_TERM_H +#include +#endif + #include #include #include @@ -50,6 +57,9 @@ extern char **environ; bool g_use_posix_spawn = false; // will usually be set to true +/// Does the terminal have the "eat_newline_glitch". +bool term_has_xn = false; + /// Struct representing one level in the function variable stack. struct env_node_t { /// Variable table. @@ -245,6 +255,7 @@ static void handle_curses(const wchar_t *env_var_name) { // changed. At the present time it can be called just once. Also, we should really only do this // if the TERM var is set. // input_init(); + term_has_xn = tgetflag((char *)"xn") == 1; // does terminal have the eat_newline_glitch } /// React to modifying the given variable. diff --git a/src/env.h b/src/env.h index 56a84ffde..90861f6e0 100644 --- a/src/env.h +++ b/src/env.h @@ -184,4 +184,6 @@ struct var_entry_t { }; typedef std::map var_table_t; + +extern bool term_has_xn; // does the terminal have the "eat_newline_glitch" #endif diff --git a/src/screen.cpp b/src/screen.cpp index 19836a14d..e962b51b2 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -31,6 +31,7 @@ #include #include "common.h" +#include "env.h" #include "fallback.h" // IWYU pragma: keep #include "highlight.h" #include "output.h" @@ -1194,7 +1195,8 @@ void s_reset(screen_t *s, screen_reset_mode_t mode) { // Don't need to check for fish_wcwidth errors; this is done when setting up // omitted_newline_char in common.cpp. int non_space_width = fish_wcwidth(omitted_newline_char); - if (screen_width >= non_space_width) { + // We do `>` rather than `>=` because the code below might require one extra space. + if (screen_width > non_space_width) { bool justgrey = true; if (enter_dim_mode) { std::string dim = tparm(enter_dim_mode); @@ -1224,16 +1226,22 @@ void s_reset(screen_t *s, screen_reset_mode_t mode) { abandon_line_string.append( str2wcstring(tparm(exit_attribute_mode))); // normal text ANSI escape sequence } - abandon_line_string.append(screen_width - non_space_width, L' '); + int newline_glitch_width = term_has_xn ? 0 : 1; + abandon_line_string.append(screen_width - non_space_width - newline_glitch_width, L' '); } abandon_line_string.push_back(L'\r'); + abandon_line_string.push_back(omitted_newline_char); // Now we are certainly on a new line. But we may have dropped the omitted newline char on // it. So append enough spaces to overwrite the omitted newline char, and then clear all the - // spaces from the new line + // spaces from the new line. abandon_line_string.append(non_space_width, L' '); abandon_line_string.push_back(L'\r'); - // clear entire line - el2 - abandon_line_string.append(L"\x1b[2K"); + // Clear entire line. Zsh doesn't do this. Fish added this with commit 4417a6ee: If you have + // a prompt preceded by a new line, you'll get a line full of spaces instead of an empty + // line above your prompt. This doesn't make a difference in normal usage, but copying and + // pasting your terminal log becomes a pain. This commit clears that line, making it an + // actual empty line. + abandon_line_string.append(L"\e[2K"); const std::string narrow_abandon_line_string = wcs2string(abandon_line_string); write_loop(STDOUT_FILENO, narrow_abandon_line_string.c_str(),