Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tui: expose terminal type in 'term' option #7640

Merged
merged 3 commits into from
Nov 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions runtime/doc/vim_diff.txt
Original file line number Diff line number Diff line change
Expand Up @@ -333,9 +333,11 @@ terminal capabilities. Instead Nvim treats the terminal as any other UI. For
example, 'guicursor' sets the terminal cursor style if possible.

*'term'* *E529* *E530* *E531*
The 'term' option has a fixed value, present only for script compatibility and
intentionally not the same as any known terminal type name. It should be a
rare case in Nvim where one needs |term-dependent-settings|.
'term' reflects the terminal type derived from |$TERM| and other environment
checks. For debugging only; not reliable during startup. >
:echo &term
"builtin_x" means one of the |builtin-terms| was chosen, because the expected
terminfo file was not found on the system.

*termcap*
Nvim never uses the termcap database, only |terminfo| and |builtin-terms|.
Expand Down
96 changes: 53 additions & 43 deletions src/nvim/option.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ typedef enum {
*/
#define VAR_WIN ((char_u *)-1)

static char *p_term = NULL;
static char *p_ttytype = NULL;

/*
* These are the global values for options which are also local to a buffer.
* Only to be used in option.c!
Expand Down Expand Up @@ -4530,13 +4533,17 @@ int findoption_len(const char *const arg, const size_t len)
bool is_tty_option(const char *name)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return (name[0] == 't' && name[1] == '_') || strcmp(name, "term") == 0;
return (name[0] == 't' && name[1] == '_')
|| strequal(name, "term")
|| strequal(name, "ttytype");
}

#define TCO_BUFFER_SIZE 8
/// @param name TUI-related option
/// @param[out,allocated] value option string value
bool get_tty_option(char *name, char **value)
{
if (!strcmp(name, "t_Co")) {
if (strequal(name, "t_Co")) {
if (value) {
if (t_colors <= 1) {
*value = xstrdup("");
Expand All @@ -4548,9 +4555,16 @@ bool get_tty_option(char *name, char **value)
return true;
}

if (!strcmp(name, "term") || !strcmp(name, "ttytype")) {
if (strequal(name, "term")) {
if (value) {
*value = xstrdup("nvim");
*value = p_term ? xstrdup(p_term) : xstrdup("nvim");
}
return true;
}

if (strequal(name, "ttytype")) {
if (value) {
*value = p_ttytype ? xstrdup(p_ttytype) : xstrdup("nvim");
}
return true;
}
Expand All @@ -4566,25 +4580,25 @@ bool get_tty_option(char *name, char **value)
return false;
}

bool set_tty_option(const char *name, const char *value)
bool set_tty_option(const char *name, char *value)
{
if (!strcmp(name, "t_Co")) {
int colors = atoi(value);

// Only reinitialize colors if t_Co value has really changed to
// avoid expensive reload of colorscheme if t_Co is set to the
// same value multiple times
if (colors != t_colors) {
t_colors = colors;
// We now have a different color setup, initialize it again.
init_highlight(true, false);
if (strequal(name, "term")) {
if (p_term) {
xfree(p_term);
}
p_term = value;
return true;
}

if (strequal(name, "ttytype")) {
if (p_ttytype) {
xfree(p_ttytype);
}
p_ttytype = value;
return true;
}

return (is_tty_option(name) || !strcmp(name, "term")
|| !strcmp(name, "ttytype"));
return false;
}

/// Find index for an option
Expand All @@ -4597,54 +4611,50 @@ static int findoption(const char *const arg)
return findoption_len(arg, strlen(arg));
}

/*
* Get the value for an option.
*
* Returns:
* Number or Toggle option: 1, *numval gets value.
* String option: 0, *stringval gets allocated string.
* Hidden Number or Toggle option: -1.
* hidden String option: -2.
* unknown option: -3.
*/
int
get_option_value (
/// Gets the value for an option.
///
/// @returns:
/// Number or Toggle option: 1, *numval gets value.
/// String option: 0, *stringval gets allocated string.
/// Hidden Number or Toggle option: -1.
/// hidden String option: -2.
/// unknown option: -3.
int get_option_value(
char_u *name,
long *numval,
char_u **stringval, /* NULL when only checking existence */
char_u **stringval, ///< NULL when only checking existence
int opt_flags
)
{
if (get_tty_option((char *)name, (char **)stringval)) {
return 0;
}

int opt_idx;
char_u *varp;

opt_idx = findoption((const char *)name);
int opt_idx = findoption((const char *)name);
if (opt_idx < 0) { // Unknown option.
return -3;
}

varp = get_varp_scope(&(options[opt_idx]), opt_flags);
char_u *varp = get_varp_scope(&(options[opt_idx]), opt_flags);

if (options[opt_idx].flags & P_STRING) {
if (varp == NULL) /* hidden option */
if (varp == NULL) { // hidden option
return -2;
}
if (stringval != NULL) {
*stringval = vim_strsave(*(char_u **)(varp));
}
return 0;
}

if (varp == NULL) /* hidden option */
if (varp == NULL) { // hidden option
return -1;
if (options[opt_idx].flags & P_NUM)
}
if (options[opt_idx].flags & P_NUM) {
*numval = *(long *)varp;
else {
/* Special case: 'modified' is b_changed, but we also want to consider
* it set when 'ff' or 'fenc' changed. */
} else {
// Special case: 'modified' is b_changed, but we also want to consider
// it set when 'ff' or 'fenc' changed.
if ((int *)varp == &curbuf->b_changed) {
*numval = curbufIsChanged();
} else {
Expand Down Expand Up @@ -4791,8 +4801,8 @@ char *set_option_value(const char *const name, const long number,
const char *const string, const int opt_flags)
FUNC_ATTR_NONNULL_ARG(1)
{
if (set_tty_option(name, string)) {
return NULL;
if (is_tty_option(name)) {
return NULL; // Fail silently; many old vimrcs set t_xx options.
}

int opt_idx;
Expand Down
28 changes: 25 additions & 3 deletions src/nvim/tui/terminfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <unibilium.h>

#include "nvim/log.h"
#include "nvim/memory.h"
#include "nvim/tui/terminfo.h"

#ifdef INCLUDE_GENERATED_DECLARATIONS
Expand Down Expand Up @@ -94,51 +95,72 @@ bool terminfo_is_term_family(const char *term, const char *family)
/// Loads a built-in terminfo db when we (unibilium) failed to load a terminfo
/// record from the environment (termcap systems, unrecognized $TERM, …).
/// We do not attempt to detect xterm pretenders here.
static unibi_term *terminfo_builtin(const char *term)
///
/// @param term $TERM value
/// @param[out,allocated] termname decided builtin 'term' name
/// @return [allocated] terminfo structure
static unibi_term *terminfo_builtin(const char *term, char **termname)
{
if (terminfo_is_term_family(term, "xterm")) {
*termname = xstrdup("builtin_xterm");
return unibi_from_mem((const char *)xterm_256colour_terminfo,
sizeof xterm_256colour_terminfo);
} else if (terminfo_is_term_family(term, "screen")) {
*termname = xstrdup("builtin_screen");
return unibi_from_mem((const char *)screen_256colour_terminfo,
sizeof screen_256colour_terminfo);
} else if (terminfo_is_term_family(term, "tmux")) {
*termname = xstrdup("builtin_tmux");
return unibi_from_mem((const char *)tmux_256colour_terminfo,
sizeof tmux_256colour_terminfo);
} else if (terminfo_is_term_family(term, "rxvt")) {
*termname = xstrdup("builtin_rxvt");
return unibi_from_mem((const char *)rxvt_256colour_terminfo,
sizeof rxvt_256colour_terminfo);
} else if (terminfo_is_term_family(term, "putty")) {
*termname = xstrdup("builtin_putty");
return unibi_from_mem((const char *)putty_256colour_terminfo,
sizeof putty_256colour_terminfo);
} else if (terminfo_is_term_family(term, "linux")) {
*termname = xstrdup("builtin_linux");
return unibi_from_mem((const char *)linux_16colour_terminfo,
sizeof linux_16colour_terminfo);
} else if (terminfo_is_term_family(term, "interix")) {
*termname = xstrdup("builtin_interix");
return unibi_from_mem((const char *)interix_8colour_terminfo,
sizeof interix_8colour_terminfo);
} else if (terminfo_is_term_family(term, "iterm")
|| terminfo_is_term_family(term, "iterm2")
|| terminfo_is_term_family(term, "iTerm.app")
|| terminfo_is_term_family(term, "iTerm2.app")) {
*termname = xstrdup("builtin_iterm");
return unibi_from_mem((const char *)iterm_256colour_terminfo,
sizeof iterm_256colour_terminfo);
} else if (terminfo_is_term_family(term, "st")) {
*termname = xstrdup("builtin_st");
return unibi_from_mem((const char *)st_256colour_terminfo,
sizeof st_256colour_terminfo);
} else if (terminfo_is_term_family(term, "gnome")
|| terminfo_is_term_family(term, "vte")) {
*termname = xstrdup("builtin_vte");
return unibi_from_mem((const char *)vte_256colour_terminfo,
sizeof vte_256colour_terminfo);
} else {
*termname = xstrdup("builtin_ansi");
return unibi_from_mem((const char *)ansi_terminfo,
sizeof ansi_terminfo);
}
}

unibi_term *terminfo_from_builtin(const char *term)
/// @param term $TERM value
/// @param[out,allocated] termname decided builtin 'term' name
/// @return [allocated] terminfo structure
unibi_term *terminfo_from_builtin(const char *term, char **termname)
{
unibi_term *ut = terminfo_builtin(term);
unibi_term *ut = terminfo_builtin(term, termname);
if (*termname == NULL) {
*termname = xstrdup("builtin_?");
}
// Disable BCE by default (for built-in terminfos). #7624
// https://github.com/kovidgoyal/kitty/issues/160#issuecomment-346470545
unibi_set_bool(ut, unibi_back_color_erase, false);
Expand Down
22 changes: 19 additions & 3 deletions src/nvim/tui/tui.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "nvim/map.h"
#include "nvim/main.h"
#include "nvim/memory.h"
#include "nvim/option.h"
#include "nvim/api/vim.h"
#include "nvim/api/private/helpers.h"
#include "nvim/event/loop.h"
Expand Down Expand Up @@ -166,6 +167,13 @@ static size_t unibi_pre_fmt_str(TUIData *data, unsigned int unibi_index,
return unibi_run(str, data->params, buf, len);
}

static void termname_set_event(void **argv)
{
char *termname = argv[0];
set_tty_option("term", termname);
// Do not free termname, it is freed by set_tty_option.
}

static void terminfo_start(UI *ui)
{
TUIData *data = ui->data;
Expand All @@ -190,12 +198,20 @@ static void terminfo_start(UI *ui)
data->unibi_ext.reset_cursor_style = -1;
data->out_fd = 1;
data->out_isatty = os_isatty(data->out_fd);
// setup unibilium

// Set up unibilium/terminfo.
const char *term = os_getenv("TERM");
data->ut = unibi_from_env();
char *termname = NULL;
if (!data->ut) {
data->ut = terminfo_from_builtin(term);
data->ut = terminfo_from_builtin(term, &termname);
} else {
termname = xstrdup(term);
}
// Update 'term' option.
loop_schedule_deferred(&main_loop,
event_create(termname_set_event, 1, termname));

// None of the following work over SSH; see :help TERM .
const char *colorterm = os_getenv("COLORTERM");
const char *termprg = os_getenv("TERM_PROGRAM");
Expand Down Expand Up @@ -344,7 +360,7 @@ static void tui_scheduler(Event event, void *d)
{
UI *ui = d;
TUIData *data = ui->data;
loop_schedule(data->loop, event);
loop_schedule(data->loop, event); // `tui_loop` local to tui_main().
}

#ifdef UNIX
Expand Down
10 changes: 10 additions & 0 deletions test/functional/helpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,15 @@ local function get_pathsep()
return funcs.fnamemodify('.', ':p'):sub(-1)
end

-- Returns a valid, platform-independent $NVIM_LISTEN_ADDRESS.
-- Useful for communicating with child instances.
local function new_pipename()
-- HACK: Start a server temporarily, get the name, then stop it.
local pipename = nvim_eval('serverstart()')
funcs.serverstop(pipename)
return pipename
end

local function missing_provider(provider)
if provider == 'ruby' then
local prog = funcs['provider#' .. provider .. '#Detect']()
Expand Down Expand Up @@ -732,6 +741,7 @@ local module = {
missing_provider = missing_provider,
alter_slashes = alter_slashes,
hexdump = hexdump,
new_pipename = new_pipename,
}

return function(after_each)
Expand Down
Loading