1 | // This is an open source non-commercial project. Dear PVS-Studio, please check |
2 | // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com |
3 | |
4 | // Built-in fallback terminfo entries. |
5 | |
6 | #include <stdbool.h> |
7 | #include <string.h> |
8 | |
9 | #include <unibilium.h> |
10 | |
11 | #include "nvim/log.h" |
12 | #include "nvim/globals.h" |
13 | #include "nvim/memory.h" |
14 | #include "nvim/message.h" |
15 | #include "nvim/option.h" |
16 | #include "nvim/os/os.h" |
17 | #include "nvim/tui/terminfo.h" |
18 | #include "nvim/tui/terminfo_defs.h" |
19 | |
20 | #ifdef INCLUDE_GENERATED_DECLARATIONS |
21 | # include "tui/terminfo.c.generated.h" |
22 | #endif |
23 | |
24 | bool terminfo_is_term_family(const char *term, const char *family) |
25 | { |
26 | if (!term) { |
27 | return false; |
28 | } |
29 | size_t tlen = strlen(term); |
30 | size_t flen = strlen(family); |
31 | return tlen >= flen |
32 | && 0 == memcmp(term, family, flen) |
33 | // Per commentary in terminfo, minus is the only valid suffix separator. |
34 | && ('\0' == term[flen] || '-' == term[flen]); |
35 | } |
36 | |
37 | bool terminfo_is_bsd_console(const char *term) |
38 | { |
39 | #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \ |
40 | || defined(__DragonFly__) |
41 | if (strequal(term, "vt220" ) // OpenBSD |
42 | || strequal(term, "vt100" )) { // NetBSD |
43 | return true; |
44 | } |
45 | # if defined(__FreeBSD__) |
46 | // FreeBSD console sets TERM=xterm, but it does not support xterm features |
47 | // like cursor-shaping. Assume that TERM=xterm is degraded. #8644 |
48 | return strequal(term, "xterm" ) && !!os_getenv("XTERM_VERSION" ); |
49 | # endif |
50 | #else |
51 | return false; |
52 | #endif |
53 | } |
54 | |
55 | /// Loads a built-in terminfo db when we (unibilium) failed to load a terminfo |
56 | /// record from the environment (termcap systems, unrecognized $TERM, …). |
57 | /// We do not attempt to detect xterm pretenders here. |
58 | /// |
59 | /// @param term $TERM value |
60 | /// @param[out,allocated] termname decided builtin 'term' name |
61 | /// @return [allocated] terminfo structure |
62 | static unibi_term *terminfo_builtin(const char *term, char **termname) |
63 | { |
64 | if (terminfo_is_term_family(term, "xterm" )) { |
65 | *termname = xstrdup("builtin_xterm" ); |
66 | return unibi_from_mem((const char *)xterm_256colour_terminfo, |
67 | sizeof xterm_256colour_terminfo); |
68 | } else if (terminfo_is_term_family(term, "screen" )) { |
69 | *termname = xstrdup("builtin_screen" ); |
70 | return unibi_from_mem((const char *)screen_256colour_terminfo, |
71 | sizeof screen_256colour_terminfo); |
72 | } else if (terminfo_is_term_family(term, "tmux" )) { |
73 | *termname = xstrdup("builtin_tmux" ); |
74 | return unibi_from_mem((const char *)tmux_256colour_terminfo, |
75 | sizeof tmux_256colour_terminfo); |
76 | } else if (terminfo_is_term_family(term, "rxvt" )) { |
77 | *termname = xstrdup("builtin_rxvt" ); |
78 | return unibi_from_mem((const char *)rxvt_256colour_terminfo, |
79 | sizeof rxvt_256colour_terminfo); |
80 | } else if (terminfo_is_term_family(term, "putty" )) { |
81 | *termname = xstrdup("builtin_putty" ); |
82 | return unibi_from_mem((const char *)putty_256colour_terminfo, |
83 | sizeof putty_256colour_terminfo); |
84 | } else if (terminfo_is_term_family(term, "linux" )) { |
85 | *termname = xstrdup("builtin_linux" ); |
86 | return unibi_from_mem((const char *)linux_16colour_terminfo, |
87 | sizeof linux_16colour_terminfo); |
88 | } else if (terminfo_is_term_family(term, "interix" )) { |
89 | *termname = xstrdup("builtin_interix" ); |
90 | return unibi_from_mem((const char *)interix_8colour_terminfo, |
91 | sizeof interix_8colour_terminfo); |
92 | } else if (terminfo_is_term_family(term, "iterm" ) |
93 | || terminfo_is_term_family(term, "iterm2" ) |
94 | || terminfo_is_term_family(term, "iTerm.app" ) |
95 | || terminfo_is_term_family(term, "iTerm2.app" )) { |
96 | *termname = xstrdup("builtin_iterm" ); |
97 | return unibi_from_mem((const char *)iterm_256colour_terminfo, |
98 | sizeof iterm_256colour_terminfo); |
99 | } else if (terminfo_is_term_family(term, "st" )) { |
100 | *termname = xstrdup("builtin_st" ); |
101 | return unibi_from_mem((const char *)st_256colour_terminfo, |
102 | sizeof st_256colour_terminfo); |
103 | } else if (terminfo_is_term_family(term, "gnome" ) |
104 | || terminfo_is_term_family(term, "vte" )) { |
105 | *termname = xstrdup("builtin_vte" ); |
106 | return unibi_from_mem((const char *)vte_256colour_terminfo, |
107 | sizeof vte_256colour_terminfo); |
108 | } else if (terminfo_is_term_family(term, "cygwin" )) { |
109 | *termname = xstrdup("builtin_cygwin" ); |
110 | return unibi_from_mem((const char *)cygwin_terminfo, |
111 | sizeof cygwin_terminfo); |
112 | } else if (terminfo_is_term_family(term, "win32con" )) { |
113 | *termname = xstrdup("builtin_win32con" ); |
114 | return unibi_from_mem((const char *)win32con_terminfo, |
115 | sizeof win32con_terminfo); |
116 | } else if (terminfo_is_term_family(term, "conemu" )) { |
117 | *termname = xstrdup("builtin_conemu" ); |
118 | return unibi_from_mem((const char *)conemu_terminfo, |
119 | sizeof conemu_terminfo); |
120 | } else if (terminfo_is_term_family(term, "vtpcon" )) { |
121 | *termname = xstrdup("builtin_vtpcon" ); |
122 | return unibi_from_mem((const char *)vtpcon_terminfo, |
123 | sizeof vtpcon_terminfo); |
124 | } else { |
125 | *termname = xstrdup("builtin_ansi" ); |
126 | return unibi_from_mem((const char *)ansi_terminfo, |
127 | sizeof ansi_terminfo); |
128 | } |
129 | } |
130 | |
131 | /// @param term $TERM value |
132 | /// @param[out,allocated] termname decided builtin 'term' name |
133 | /// @return [allocated] terminfo structure |
134 | unibi_term *terminfo_from_builtin(const char *term, char **termname) |
135 | { |
136 | unibi_term *ut = terminfo_builtin(term, termname); |
137 | if (*termname == NULL) { |
138 | *termname = xstrdup("builtin_?" ); |
139 | } |
140 | return ut; |
141 | } |
142 | |
143 | /// Dumps termcap info to the messages area. |
144 | /// Serves a similar purpose as Vim `:set termcap` (removed in Nvim). |
145 | /// |
146 | /// @note adapted from unibilium unibi-dump.c |
147 | void terminfo_info_msg(const unibi_term *const ut) |
148 | { |
149 | if (exiting) { |
150 | return; |
151 | } |
152 | msg_puts_title("\n\n--- Terminal info --- {{{\n" ); |
153 | |
154 | char *term; |
155 | get_tty_option("term" , &term); |
156 | msg_printf_attr(0, "&term: %s\n" , term); |
157 | msg_printf_attr(0, "Description: %s\n" , unibi_get_name(ut)); |
158 | const char **a = unibi_get_aliases(ut); |
159 | if (*a) { |
160 | msg_puts("Aliases: " ); |
161 | do { |
162 | msg_printf_attr(0, "%s%s\n" , *a, a[1] ? " | " : "" ); |
163 | a++; |
164 | } while (*a); |
165 | } |
166 | |
167 | msg_puts("Boolean capabilities:\n" ); |
168 | for (enum unibi_boolean i = unibi_boolean_begin_ + 1; |
169 | i < unibi_boolean_end_; i++) { |
170 | msg_printf_attr(0, " %-25s %-10s = %s\n" , unibi_name_bool(i), |
171 | unibi_short_name_bool(i), |
172 | unibi_get_bool(ut, i) ? "true" : "false" ); |
173 | } |
174 | |
175 | msg_puts("Numeric capabilities:\n" ); |
176 | for (enum unibi_numeric i = unibi_numeric_begin_ + 1; |
177 | i < unibi_numeric_end_; i++) { |
178 | int n = unibi_get_num(ut, i); // -1 means "empty" |
179 | msg_printf_attr(0, " %-25s %-10s = %d\n" , unibi_name_num(i), |
180 | unibi_short_name_num(i), n); |
181 | } |
182 | |
183 | msg_puts("String capabilities:\n" ); |
184 | for (enum unibi_string i = unibi_string_begin_ + 1; |
185 | i < unibi_string_end_; i++) { |
186 | const char *s = unibi_get_str(ut, i); |
187 | if (s) { |
188 | msg_printf_attr(0, " %-25s %-10s = " , unibi_name_str(i), |
189 | unibi_short_name_str(i)); |
190 | // Most of these strings will contain escape sequences. |
191 | msg_outtrans_special((char_u *)s, false); |
192 | msg_putchar('\n'); |
193 | } |
194 | } |
195 | |
196 | if (unibi_count_ext_bool(ut)) { |
197 | msg_puts("Extended boolean capabilities:\n" ); |
198 | for (size_t i = 0; i < unibi_count_ext_bool(ut); i++) { |
199 | msg_printf_attr(0, " %-25s = %s\n" , |
200 | unibi_get_ext_bool_name(ut, i), |
201 | unibi_get_ext_bool(ut, i) ? "true" : "false" ); |
202 | } |
203 | } |
204 | |
205 | if (unibi_count_ext_num(ut)) { |
206 | msg_puts("Extended numeric capabilities:\n" ); |
207 | for (size_t i = 0; i < unibi_count_ext_num(ut); i++) { |
208 | msg_printf_attr(0, " %-25s = %d\n" , |
209 | unibi_get_ext_num_name(ut, i), |
210 | unibi_get_ext_num(ut, i)); |
211 | } |
212 | } |
213 | |
214 | if (unibi_count_ext_str(ut)) { |
215 | msg_puts("Extended string capabilities:\n" ); |
216 | for (size_t i = 0; i < unibi_count_ext_str(ut); i++) { |
217 | msg_printf_attr(0, " %-25s = " , unibi_get_ext_str_name(ut, i)); |
218 | msg_outtrans_special((char_u *)unibi_get_ext_str(ut, i), false); |
219 | msg_putchar('\n'); |
220 | } |
221 | } |
222 | |
223 | msg_puts("}}}\n" ); |
224 | xfree(term); |
225 | } |
226 | |