From 11dccccdcc88375f52a385a3d00a111ab15dace6 Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Mon, 9 Jan 2017 18:35:37 -0800 Subject: [PATCH] optimize determining if can set term title Decide if the terminal supports setting its title only when necessary (e.g., when TERM changes) rather than everytime we're about to write the prompt. --- src/env.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ src/env.h | 3 +++ src/reader.cpp | 29 ----------------------------- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/env.cpp b/src/env.cpp index a8b8618fa..c1199480c 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -238,6 +238,47 @@ static bool var_is_curses(const wcstring &key) { return false; } +/// True if we think we can set the terminal title else false. +static bool can_set_term_title = false; + +/// Returns true if we think the terminal supports setting its title. +bool term_supports_setting_title() { + return can_set_term_title; +} + +/// This is a pretty lame heuristic for detecting terminals that do not support setting the +/// title. If we recognise the terminal name as that of a virtual terminal, we assume it supports +/// setting the title. If we recognise it as that of a console, we assume it does not support +/// setting the title. Otherwise we check the ttyname and see if we believe it is a virtual +/// terminal. +/// +/// One situation in which this breaks down is with screen, since screen supports setting the +/// terminal title if the underlying terminal does so, but will print garbage on terminals that +/// don't. Since we can't see the underlying terminal below screen there is no way to fix this. +static bool does_term_support_setting_title() { + const env_var_t term_str = env_get_string(L"TERM"); + if (term_str.missing()) return false; + + const wchar_t *term = term_str.c_str(); + bool recognized = contains(term, L"xterm", L"screen", L"tmux", L"nxterm", L"rxvt"); + if (!recognized) recognized = !wcsncmp(term, L"xterm-", wcslen(L"xterm-")); + if (!recognized) recognized = !wcsncmp(term, L"screen-", wcslen(L"screen-")); + if (!recognized) recognized = !wcsncmp(term, L"tmux-", wcslen(L"tmux-")); + if (!recognized) { + if (contains(term, L"linux", L"dumb")) return false; + + char *n = ttyname(STDIN_FILENO); + if (!n || strstr(n, "tty") || strstr(n, "/vc/")) return false; + } + + return true; +} + +/// Handle changes to the TERM env var that do not involves the curses subsystem. +static void handle_term() { + can_set_term_title = does_term_support_setting_title(); +} + /// Push all curses/terminfo env vars into the global environment where they can be found by those /// libraries. static void handle_curses(const wchar_t *env_var_name) { @@ -264,6 +305,7 @@ static void react_to_variable_change(const wcstring &key) { handle_locale(key.c_str()); } else if (var_is_curses(key)) { handle_curses(key.c_str()); + if (key == L"TERM") handle_term(); } else if (var_is_timezone(key)) { handle_timezone(key.c_str()); } else if (key == L"fish_term256" || key == L"fish_term24bit") { diff --git a/src/env.h b/src/env.h index 90861f6e0..8f09f99b6 100644 --- a/src/env.h +++ b/src/env.h @@ -186,4 +186,7 @@ struct var_entry_t { typedef std::map var_table_t; extern bool term_has_xn; // does the terminal have the "eat_newline_glitch" + +/// Returns true if we think the terminal supports setting its title. +bool term_supports_setting_title(); #endif diff --git a/src/reader.cpp b/src/reader.cpp index 0838162d5..0b67d5be6 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -660,35 +660,6 @@ bool reader_thread_job_is_stale() { return (void *)(uintptr_t)s_generation_count != pthread_getspecific(generation_count_key); } - -/// This is a pretty lame heuristic for detecting terminals that do not support setting the -/// title. If we recognise the terminal name as that of a virtual terminal, we assume it supports -/// setting the title. If we recognise it as that of a console, we assume it does not support -/// setting the title. Otherwise we check the ttyname and see if we believe it is a virtual -/// terminal. -/// -/// One situation in which this breaks down is with screen, since screen supports setting the -/// terminal title if the underlying terminal does so, but will print garbage on terminals that -/// don't. Since we can't see the underlying terminal below screen there is no way to fix this. -static bool term_supports_setting_title() { - const env_var_t term_str = env_get_string(L"TERM"); - if (term_str.missing()) return false; - - const wchar_t *term = term_str.c_str(); - bool recognized = contains(term, L"xterm", L"screen", L"tmux", L"nxterm", L"rxvt"); - if (!recognized) recognized = !wcsncmp(term, L"xterm-", wcslen(L"xterm-")); - if (!recognized) recognized = !wcsncmp(term, L"screen-", wcslen(L"screen-")); - if (!recognized) recognized = !wcsncmp(term, L"tmux-", wcslen(L"tmux-")); - if (!recognized) { - if (contains(term, L"linux", L"dumb")) return false; - - char *n = ttyname(STDIN_FILENO); - if (!n || strstr(n, "tty") || strstr(n, "/vc/")) return false; - } - - return true; -} - void reader_write_title(const wcstring &cmd, bool reset_cursor_position) { if (!term_supports_setting_title()) return;