1 /*
2 * Terminal-handling definitions common to the interpreter and edlis.
3 * This also includes some presentation-related functions, e.g. syntax highlighting.
4 *
5 * There are two relevant library layers here:
6 * 1. Curses is high-level, but only appropriate for fullscreen programs
7 * 2. Terminfo is lower-level (curses is built on it)
8 *
9 * I only considered standardized libraries (e.g. X/Open).
10 */
11
12 #ifndef TERM_H
13 #define TERM_H
14
15 #include <ncurses.h>
16 #ifndef FULLSCREEN
17 #include <term.h>
18 #endif
19
20 struct position {
21 int row;
22 int col;
23 };
24
25 // special charactor
26 #define EOL '\n'
27 #define RET '\r'
28 #define TAB '\t'
29 #define SPACE ' '
30 #define ESC 27
31 static const char NUL = '\0';
32 static const char BEL = '\a';
33 static const char BS = '\b';
34 #define DEL 127
35
36 #ifndef FULLSCREEN
37 #define ARROW_PREFIX '['
38 extern char ed_key_down;
39 extern char ed_key_left;
40 extern char ed_key_right;
41 extern char ed_key_up;
42 #endif
43
44 #ifdef FULLSCREEN
45 /*
46 * Edlis uses the higher-level curses interface
47 */
48
49 __dead void errw(const char *msg);
50 #define CHECK(fn, ...) { \
51 if ((fn)(__VA_ARGS__) == ERR) { \
52 errw(#fn); \
53 } \
54 }
55
56 static inline void
ESCHOME(void)57 ESCHOME(void)
58 {
59 CHECK(move, 0, 0);
60 }
61
62 static inline void
ESCTOP(void)63 ESCTOP(void)
64 {
65 CHECK(move, 1, 0);
66 }
67
68 static inline void
ESCCLS(void)69 ESCCLS(void)
70 {
71 CHECK(clear);
72 }
73
74 static inline void
ESCCLS1(void)75 ESCCLS1(void)
76 {
77 CHECK(clrtobot);
78 }
79
80 static inline void
ESCCLSL(void)81 ESCCLSL(void)
82 {
83 CHECK(clrtoeol);
84 }
85
86 static inline void
ESCMVLEFT(int x)87 ESCMVLEFT(int x)
88 {
89 int dummy,
90 cur_y;
91
92 getyx(stdscr, cur_y, dummy);
93 CHECK(move, cur_y, x - 1);
94 }
95
96 static inline void
ESCCLSLA(void)97 ESCCLSLA(void)
98 {
99 ESCMVLEFT(1);
100 CHECK(clrtoeol);
101 }
102
103 static inline void
ESCMOVE(int y,int x)104 ESCMOVE(int y, int x)
105 {
106 CHECK(move, y - 1, x - 1);
107 }
108
109 static inline void
ESCFORG(void)110 ESCFORG(void)
111 {
112 if (has_colors()) {
113 CHECK(color_set, 0, NULL);
114 }
115 }
116
117 enum Color { RED_ON_DFL =
118 1, YELLOW_ON_DFL, BLUE_ON_DFL, MAGENTA_ON_DFL, CYAN_ON_DFL,
119 DFL_ON_CYAN,
120 };
121 static inline void
ESCBCYAN(void)122 ESCBCYAN(void)
123 {
124 if (has_colors()) {
125 CHECK(color_set, DFL_ON_CYAN, NULL);
126 }
127 }
128
129 static inline void
ESCBORG(void)130 ESCBORG(void)
131 {
132 if (has_colors()) {
133 CHECK(color_set, 0, NULL);
134 }
135 }
136
137 static inline void
ESCREV(void)138 ESCREV(void)
139 {
140 CHECK(attron, A_REVERSE);
141 }
142
143 static inline void
ESCRST(void)144 ESCRST(void)
145 {
146 CHECK(attrset, A_NORMAL);
147 }
148
149 static inline void
ESCBOLD(void)150 ESCBOLD(void)
151 {
152 CHECK(attron, A_BOLD);
153 }
154 #else
155 /*
156 * The REPL uses the lower-level terminfo interface because we don't want
157 * to clear the screen
158 */
159
160 static inline void
ESCCLSL(void)161 ESCCLSL(void)
162 {
163 putp(clr_eol);
164 }
165
166 static inline void
ESCMVLEFT(int x)167 ESCMVLEFT(int x)
168 {
169 putp(tparm(column_address, x - 1));
170 }
171
172 static inline void
ESCMVU(void)173 ESCMVU(void)
174 {
175 putp(cursor_up);
176 }
177
178 static inline void
ESCSCR(void)179 ESCSCR(void)
180 {
181 putp(scroll_forward);
182 }
183
184 static inline void
ESCFORG(void)185 ESCFORG(void)
186 {
187 putp(exit_attribute_mode);
188 }
189
190 static inline void
ESCBCYAN(void)191 ESCBCYAN(void)
192 {
193 putp(tparm(set_a_background, COLOR_CYAN));
194 }
195
196 static inline void
ESCBORG(void)197 ESCBORG(void)
198 {
199 putp(exit_attribute_mode);
200 }
201
202 static inline void
ESCREV(void)203 ESCREV(void)
204 {
205 putp(enter_reverse_mode);
206 }
207
208 static inline void
ESCRST(void)209 ESCRST(void)
210 {
211 putp(exit_attribute_mode);
212 }
213
214 static inline void
ESCBOLD(void)215 ESCBOLD(void)
216 {
217 putp(enter_bold_mode);
218 }
219 #endif
220
221 enum HighlightToken { HIGHLIGHT_NONE, HIGHLIGHT_SYNTAX, HIGHLIGHT_BUILTIN,
222 HIGHLIGHT_STRING, HIGHLIGHT_COMMENT, HIGHLIGHT_EXTENDED,
223 HIGHLIGHT_MULTILINE_COMMENT,
224 };
225 enum HighlightToken maybe_match(const char *str);
226 bool in_special_table(const char *str);
227 void gather_fuzzy_matches(const char *str,
228 const char *candidates[],
229 int *candidate_pt);
230 #define COMPLETION_CANDIDATES_MAX 50
231
232 #endif
233