53 |
int color, def_color; |
int color, def_color; |
54 |
int cur_offset; /* current offset at position x, y */ |
int cur_offset; /* current offset at position x, y */ |
55 |
int esc_params[MAX_ESC_PARAMS]; |
int esc_params[MAX_ESC_PARAMS]; |
56 |
|
int has_params[MAX_ESC_PARAMS]; |
57 |
int nb_esc_params; |
int nb_esc_params; |
58 |
int state; |
int state; |
59 |
int esc1; |
int esc1; |
62 |
EditBuffer *b_color; /* color buffer, one byte per char */ |
EditBuffer *b_color; /* color buffer, one byte per char */ |
63 |
int is_shell; /* only used to display final message */ |
int is_shell; /* only used to display final message */ |
64 |
struct QEmacsState *qe_state; |
struct QEmacsState *qe_state; |
65 |
|
const char *ka1, *ka3, *kb2, *kc1, *kc3, *kcbt, *kspd; |
66 |
|
const char *kbeg, *kbs, *kent, *kdch1, *kich1; |
67 |
|
const char *kcub1, *kcud1, *kcuf1, *kcuu1; |
68 |
|
const char *kf1, *kf2, *kf3, *kf4, *kf5; |
69 |
|
const char *kf6, *kf7, *kf8, *kf9, *kf10; |
70 |
|
const char *kf11, *kf12, *kf13, *kf14, *kf15; |
71 |
|
const char *kf16, *kf17, *kf18, *kf19, *kf20; |
72 |
|
const char *khome, *kend, *kmous, *knp, *kpp; |
73 |
|
|
74 |
} ShellState; |
} ShellState; |
75 |
|
|
76 |
static int shell_get_colorized_line(EditState *e, unsigned int *buf, int buf_size, |
static int shell_get_colorized_line(EditState *e, |
77 |
|
unsigned int *buf, int buf_size, |
78 |
int offset, int line_num); |
int offset, int line_num); |
79 |
|
|
80 |
/* move to mode */ |
/* move to mode */ |
167 |
|
|
168 |
static void tty_init(ShellState *s) |
static void tty_init(ShellState *s) |
169 |
{ |
{ |
170 |
|
char *term; |
171 |
|
|
172 |
s->state = TTY_STATE_NORM; |
s->state = TTY_STATE_NORM; |
173 |
s->cur_offset = 0; |
s->cur_offset = 0; |
174 |
s->def_color = TTY_GET_COLOR(7, 0); |
s->def_color = TTY_GET_COLOR(7, 0); |
175 |
s->color = s->def_color; |
s->color = s->def_color; |
176 |
|
|
177 |
|
term = getenv("TERM"); |
178 |
|
/* vt100 terminfo definitions */ |
179 |
|
s->kbs = "\010"; |
180 |
|
s->ka1 = "\033Oq"; |
181 |
|
s->ka3 = "\033Os"; |
182 |
|
s->kb2 = "\033Or"; |
183 |
|
s->kc1 = "\033Op"; |
184 |
|
s->kc3 = "\033On"; |
185 |
|
s->kcub1 = "\033OD"; |
186 |
|
s->kcud1 = "\033OB"; |
187 |
|
s->kcuf1 = "\033OC"; |
188 |
|
s->kcuu1 = "\033OA"; |
189 |
|
s->kent = "\033OM"; |
190 |
|
s->kf1 = "\033OP"; |
191 |
|
s->kf2 = "\033OQ"; |
192 |
|
s->kf3 = "\033OR"; |
193 |
|
s->kf4 = "\033OS"; |
194 |
|
s->kf5 = "\033Ot"; |
195 |
|
s->kf6 = "\033Ou"; |
196 |
|
s->kf7 = "\033Ov"; |
197 |
|
s->kf8 = "\033Ol"; |
198 |
|
s->kf9 = "\033Ow"; |
199 |
|
s->kf10 = "\033Ox"; |
200 |
|
|
201 |
|
/* ansi terminfo definitions */ |
202 |
|
if (strstart(term, "ansi", NULL)) { |
203 |
|
s->kbs = "\010"; |
204 |
|
s->kcbt = "\033[Z"; |
205 |
|
s->kcub1 = "\033[D"; |
206 |
|
s->kcud1 = "\033[B"; |
207 |
|
s->kcuf1 = "\033[C"; |
208 |
|
s->kcuu1 = "\033[A"; |
209 |
|
s->khome = "\033[H"; |
210 |
|
s->kich1 = "\033[L"; |
211 |
|
} |
212 |
|
if (strstart(term, "vt220", NULL)) { |
213 |
|
s->kcub1 = "\033[D"; |
214 |
|
s->kcud1 = "\033[B"; |
215 |
|
s->kcuf1 = "\033[C"; |
216 |
|
s->kcuu1 = "\033[A"; |
217 |
|
s->kdch1 = "\033[3~"; |
218 |
|
s->kend = "\033[4~"; |
219 |
|
s->khome = "\033[1~"; |
220 |
|
s->kich1 = "\033[2~"; |
221 |
|
s->knp = "\033[6~"; |
222 |
|
s->kpp = "\033[5~"; |
223 |
|
s->kf1 = "\033OP"; |
224 |
|
s->kf2 = "\033OQ"; |
225 |
|
s->kf3 = "\033OR"; |
226 |
|
s->kf4 = "\033OS"; |
227 |
|
s->kf5 = "\033[17~"; |
228 |
|
s->kf6 = "\033[18~"; |
229 |
|
s->kf7 = "\033[19~"; |
230 |
|
s->kf8 = "\033[20~"; |
231 |
|
s->kf9 = "\033[21~"; |
232 |
|
s->kf10 = "\033[29~"; |
233 |
|
} |
234 |
|
if (strstart(term, "cygwin", NULL)) { |
235 |
|
s->kbs = "\10"; |
236 |
|
goto linux_cygwin; |
237 |
|
} |
238 |
|
if (strstart(term, "linux", NULL)) { |
239 |
|
s->kbs = "\177"; |
240 |
|
s->kb2 = "\033[G"; |
241 |
|
s->kcbt = "\033[Z"; |
242 |
|
s->kspd = "\032"; // ^Z |
243 |
|
linux_cygwin: |
244 |
|
s->kcub1 = "\033[D"; |
245 |
|
s->kcud1 = "\033[B"; |
246 |
|
s->kcuf1 = "\033[C"; |
247 |
|
s->kcuu1 = "\033[A"; |
248 |
|
s->kdch1 = "\033[3~"; |
249 |
|
s->kend = "\033[4~"; |
250 |
|
s->khome = "\033[1~"; |
251 |
|
s->kich1 = "\033[2~"; |
252 |
|
s->knp = "\033[6~"; |
253 |
|
s->kpp = "\033[5~"; |
254 |
|
s->kf1 = "\033[[A"; |
255 |
|
s->kf2 = "\033[[B"; |
256 |
|
s->kf3 = "\033[[C"; |
257 |
|
s->kf4 = "\033[[D"; |
258 |
|
s->kf5 = "\033[[E"; |
259 |
|
s->kf6 = "\033[17~"; |
260 |
|
s->kf7 = "\033[18~"; |
261 |
|
s->kf8 = "\033[19~"; |
262 |
|
s->kf9 = "\033[20~"; |
263 |
|
s->kf10 = "\033[21~"; |
264 |
|
s->kf11 = "\033[23~"; |
265 |
|
s->kf12 = "\033[24~"; |
266 |
|
s->kf13 = "\033[25~"; |
267 |
|
s->kf14 = "\033[26~"; |
268 |
|
s->kf15 = "\033[28~"; |
269 |
|
s->kf16 = "\033[29~"; |
270 |
|
s->kf17 = "\033[31~"; |
271 |
|
s->kf18 = "\033[32~"; |
272 |
|
s->kf19 = "\033[33~"; |
273 |
|
s->kf20 = "\033[34~"; |
274 |
|
} |
275 |
|
if (strstart(term, "xterm", NULL)) { |
276 |
|
s->ka1 = "\033Ow"; |
277 |
|
s->ka3 = "\033Ou"; |
278 |
|
s->kb2 = "\033Oy"; |
279 |
|
s->kbeg = "\033OE"; |
280 |
|
s->kbs = "\03377"; |
281 |
|
s->kc1 = "\033Oq"; |
282 |
|
s->kc3 = "\033Os"; |
283 |
|
s->kcub1 = "\033OD"; |
284 |
|
s->kcud1 = "\033OB"; |
285 |
|
s->kcuf1 = "\033OC"; |
286 |
|
s->kcuu1 = "\033OA"; |
287 |
|
s->kdch1 = "\033[3~"; |
288 |
|
s->kend = "\033[4~"; |
289 |
|
s->kent = "\033OM"; |
290 |
|
s->khome = "\033[1~"; |
291 |
|
s->kich1 = "\033[2~"; |
292 |
|
s->kmous = "\033[M"; |
293 |
|
s->knp = "\033[6~"; |
294 |
|
s->kpp = "\033[5~"; |
295 |
|
s->kf1 = "\033OP"; |
296 |
|
s->kf2 = "\033OQ"; |
297 |
|
s->kf3 = "\033OR"; |
298 |
|
s->kf4 = "\033OS"; |
299 |
|
s->kf5 = "\033[15~"; |
300 |
|
s->kf6 = "\033[17~"; |
301 |
|
s->kf7 = "\033[18~"; |
302 |
|
s->kf8 = "\033[19~"; |
303 |
|
s->kf9 = "\033[20~"; |
304 |
|
s->kf10 = "\033[21~"; |
305 |
|
s->kf11 = "\033[23~"; |
306 |
|
s->kf12 = "\033[24~"; |
307 |
|
s->kf13 = "\033[25~"; |
308 |
|
s->kf14 = "\033[26~"; |
309 |
|
s->kf15 = "\033[28~"; |
310 |
|
s->kf16 = "\033[29~"; |
311 |
|
s->kf17 = "\033[31~"; |
312 |
|
s->kf18 = "\033[32~"; |
313 |
|
s->kf19 = "\033[33~"; |
314 |
|
s->kf20 = "\033[34~"; |
315 |
|
} |
316 |
} |
} |
317 |
|
|
318 |
static void tty_write(ShellState *s, const unsigned char *buf, int len) |
static void tty_write(ShellState *s, const unsigned char *buf, int len) |
335 |
/* compute offset the char at 'x' and 'y'. Can insert spaces or lines |
/* compute offset the char at 'x' and 'y'. Can insert spaces or lines |
336 |
if needed */ |
if needed */ |
337 |
/* XXX: optimize !!!!! */ |
/* XXX: optimize !!!!! */ |
338 |
static void tty_gotoxy(ShellState *s, int x, int y) |
static void tty_gotoxy(ShellState *s, int x, int y, int relative) |
339 |
{ |
{ |
340 |
int total_lines, line_num, col_num, offset, offset1, c; |
int total_lines, cur_line, line_num, col_num, offset, offset1, c; |
341 |
unsigned char buf1[10]; |
unsigned char buf1[10]; |
342 |
|
|
343 |
/* compute offset */ |
/* compute offset */ |
345 |
line_num = total_lines - TTY_YSIZE; |
line_num = total_lines - TTY_YSIZE; |
346 |
if (line_num < 0) |
if (line_num < 0) |
347 |
line_num = 0; |
line_num = 0; |
348 |
|
|
349 |
|
if (relative) { |
350 |
|
eb_get_pos(s->b, &cur_line, &col_num, s->cur_offset); |
351 |
|
cur_line -= line_num; |
352 |
|
if (cur_line < 0) |
353 |
|
cur_line = 0; |
354 |
|
x += col_num; |
355 |
|
y += line_num; |
356 |
|
} |
357 |
|
if (y < 0) |
358 |
|
y = 0; |
359 |
|
else if (y >= TTY_YSIZE) |
360 |
|
y = TTY_YSIZE - 1; |
361 |
|
if (x < 0) |
362 |
|
x = 0; |
363 |
|
|
364 |
line_num += y; |
line_num += y; |
365 |
/* add lines if necessary */ |
/* add lines if necessary */ |
366 |
while (line_num >= total_lines) { |
while (line_num >= total_lines) { |
435 |
int i, offset, offset1, offset2, n; |
int i, offset, offset1, offset2, n; |
436 |
unsigned char buf1[10]; |
unsigned char buf1[10]; |
437 |
|
|
438 |
|
#define ESC2(c1,c2) (((c1)<<8)|((unsigned char)c2)) |
439 |
switch (s->state) { |
switch (s->state) { |
440 |
case TTY_STATE_NORM: |
case TTY_STATE_NORM: |
441 |
switch(c) { |
switch(c) { |
512 |
break; |
break; |
513 |
case TTY_STATE_ESC: |
case TTY_STATE_ESC: |
514 |
if (c == '[') { |
if (c == '[') { |
515 |
for (i = 0; i < MAX_ESC_PARAMS; i++) |
for (i = 0; i < MAX_ESC_PARAMS; i++) { |
516 |
s->esc_params[i] = 0; |
s->esc_params[i] = 0; |
517 |
|
s->has_params[i] = 0; |
518 |
|
} |
519 |
s->nb_esc_params = 0; |
s->nb_esc_params = 0; |
520 |
|
s->esc1 = 0; |
521 |
s->state = TTY_STATE_CSI; |
s->state = TTY_STATE_CSI; |
522 |
} else { |
} else { |
523 |
/* CG: should deal with other sequences: |
/* CG: should deal with other sequences: |
556 |
break; |
break; |
557 |
case TTY_STATE_ESC2: |
case TTY_STATE_ESC2: |
558 |
s->state = TTY_STATE_NORM; |
s->state = TTY_STATE_NORM; |
|
#define ESC2(c1,c2) (((c1)<<8)|((unsigned char)c2)) |
|
559 |
switch (ESC2(s->esc1, c)) { |
switch (ESC2(s->esc1, c)) { |
560 |
case ESC2('(','B'): |
case ESC2('(','B'): |
561 |
case ESC2(')','B'): |
case ESC2(')','B'): |
567 |
/* XXX: ??? */ |
/* XXX: ??? */ |
568 |
break; |
break; |
569 |
} |
} |
|
#undef ESC2 |
|
570 |
break; |
break; |
571 |
case TTY_STATE_CSI: |
case TTY_STATE_CSI: |
572 |
|
if (c == '?') { |
573 |
|
s->esc1 = c; |
574 |
|
break; |
575 |
|
} |
576 |
if (c >= '0' && c <= '9') { |
if (c >= '0' && c <= '9') { |
577 |
if (s->nb_esc_params < MAX_ESC_PARAMS) { |
if (s->nb_esc_params < MAX_ESC_PARAMS) { |
578 |
s->esc_params[s->nb_esc_params] = |
s->esc_params[s->nb_esc_params] = |
579 |
s->esc_params[s->nb_esc_params] * 10 + c - '0'; |
s->esc_params[s->nb_esc_params] * 10 + c - '0'; |
580 |
|
s->has_params[s->nb_esc_params] = 1; |
581 |
} |
} |
582 |
} else { |
} else { |
583 |
s->nb_esc_params++; |
s->nb_esc_params++; |
584 |
if (c == ';') |
if (c == ';') |
585 |
break; |
break; |
586 |
s->state = TTY_STATE_NORM; |
s->state = TTY_STATE_NORM; |
587 |
switch(c) { |
switch (ESC2(s->esc1,c)) { |
588 |
|
case ESC2('?','h'): /* set terminal mode */ |
589 |
|
/* 1047, 1048 -> cup mode: |
590 |
|
* should grab all keys while active! |
591 |
|
*/ |
592 |
|
case ESC2('?','l'): /* reset terminal mode */ |
593 |
|
break; |
594 |
|
case 'A': |
595 |
|
/* move relative up */ |
596 |
|
tty_gotoxy(s, 0, -(s->esc_params[0] + 1 - s->has_params[0]), 1); |
597 |
|
break; |
598 |
|
case 'B': |
599 |
|
/* move relative down */ |
600 |
|
tty_gotoxy(s, 0, (s->esc_params[0] + 1 - s->has_params[0]), 1); |
601 |
|
break; |
602 |
|
case 'C': |
603 |
|
/* move relative forward */ |
604 |
|
tty_gotoxy(s, -(s->esc_params[0] + 1 - s->has_params[0]), 0, 1); |
605 |
|
break; |
606 |
|
case 'D': |
607 |
|
/* move relative backward */ |
608 |
|
tty_gotoxy(s, (s->esc_params[0] + 1 - s->has_params[0]), 0, 1); |
609 |
|
break; |
610 |
case 'H': |
case 'H': |
611 |
/* goto xy */ |
/* goto xy */ |
612 |
{ |
tty_gotoxy(s, s->esc_params[1] - s->has_params[1], |
613 |
int x, y; |
s->esc_params[0] - s->has_params[0], 0); |
|
y = s->esc_params[0] - 1; |
|
|
x = s->esc_params[1] - 1; |
|
|
if (y < 0) |
|
|
y = 0; |
|
|
else if (y >= TTY_YSIZE) |
|
|
y = TTY_YSIZE - 1; |
|
|
if (x < 0) |
|
|
x = 0; |
|
|
tty_gotoxy(s, x, y); |
|
|
} |
|
614 |
break; |
break; |
615 |
case 'K': |
case 'J': /* clear to end of screen */ |
616 |
/* clear to eol */ |
case 'L': /* insert lines */ |
617 |
|
case 'M': /* delete lines */ |
618 |
|
case 'S': /* scroll forward P lines */ |
619 |
|
case 'T': /* scroll back P lines */ |
620 |
|
case 'X': /* erase P characters */ |
621 |
|
break; |
622 |
|
case 'K': /* clear eol (parm=1 -> bol) */ |
623 |
offset1 = s->cur_offset; |
offset1 = s->cur_offset; |
624 |
for(;;) { |
for(;;) { |
625 |
c = eb_nextc(s->b, offset1, &offset2); |
c = eb_nextc(s->b, offset1, &offset2); |
664 |
case 'n': |
case 'n': |
665 |
if (s->esc_params[0] == 6) { |
if (s->esc_params[0] == 6) { |
666 |
/* XXX: send cursor position, just to be able to |
/* XXX: send cursor position, just to be able to |
667 |
launch qemacs in qemacs ! */ |
launch qemacs in qemacs (in 8859-1) ! */ |
668 |
char buf2[20]; |
char buf2[20]; |
669 |
snprintf(buf2, sizeof(buf2), "\033[%d;%dR", 1, 1); |
snprintf(buf2, sizeof(buf2), "\033[%d;%dR", 1, 1); |
670 |
tty_write(s, buf2, -1); |
tty_write(s, buf2, -1); |
676 |
} |
} |
677 |
break; |
break; |
678 |
} |
} |
679 |
|
#undef ESC2 |
680 |
tty_update_cursor(s); |
tty_update_cursor(s); |
681 |
} |
} |
682 |
|
|
767 |
if (len <= 0) |
if (len <= 0) |
768 |
return; |
return; |
769 |
|
|
770 |
|
if (trace_buffer) |
771 |
|
eb_write(trace_buffer, trace_buffer->total_size, buf, len); |
772 |
|
|
773 |
for (i = 0; i < len; i++) |
for (i = 0; i < len; i++) |
774 |
tty_emulate(s, buf[i]); |
tty_emulate(s, buf[i]); |
775 |
|
|
860 |
if (!b) |
if (!b) |
861 |
return NULL; |
return NULL; |
862 |
set_buffer_name(b, name); /* ensure that the name is unique */ |
set_buffer_name(b, name); /* ensure that the name is unique */ |
863 |
|
eb_set_charset(b, &charset_vt100); |
864 |
|
|
865 |
s = malloc(sizeof(ShellState)); |
s = malloc(sizeof(ShellState)); |
866 |
if (!s) { |
if (!s) { |
904 |
return b; |
return b; |
905 |
} |
} |
906 |
|
|
907 |
static void do_shell(EditState *e) |
static void do_shell(EditState *s, int force) |
908 |
{ |
{ |
909 |
|
QEmacsState *qs = s->qe_state; |
910 |
|
EditState *e; |
911 |
EditBuffer *b; |
EditBuffer *b; |
912 |
const char *argv[3]; |
const char *argv[3]; |
913 |
const char *shell_path; |
const char *shell_path; |
914 |
|
|
915 |
|
/* CG: Should prompt for buffer name if arg: |
916 |
|
* find a syntax for optional string argument w/ prompt |
917 |
|
*/ |
918 |
|
/* find shell buffer if any */ |
919 |
|
if (!force || force == NO_ARG) { |
920 |
|
b = eb_find("*shell*"); |
921 |
|
if (b) { |
922 |
|
e = edit_find(b); |
923 |
|
if (e) |
924 |
|
qs->active_window = e; |
925 |
|
else |
926 |
|
switch_to_buffer(s, b); |
927 |
|
return; |
928 |
|
} |
929 |
|
} |
930 |
|
|
931 |
/* find shell name */ |
/* find shell name */ |
932 |
shell_path = getenv("SHELL"); |
shell_path = getenv("SHELL"); |
933 |
if (!shell_path) |
if (!shell_path) |
940 |
if (!b) |
if (!b) |
941 |
return; |
return; |
942 |
|
|
943 |
switch_to_buffer(e, b); |
switch_to_buffer(s, b); |
944 |
do_set_mode(e, &shell_mode, NULL); |
do_set_mode(s, &shell_mode, NULL); |
945 |
|
|
946 |
put_status(e, "Press C-o to toggle between shell/edit mode"); |
put_status(s, "Press C-o to toggle between shell/edit mode"); |
947 |
shell_launched = 1; |
shell_launched = 1; |
948 |
} |
} |
949 |
|
|
951 |
{ |
{ |
952 |
if (e->interactive) { |
if (e->interactive) { |
953 |
ShellState *s = e->b->priv_data; |
ShellState *s = e->b->priv_data; |
954 |
tty_write(s, dir > 0 ? "\033[C" : "\033[D", -1); |
tty_write(s, dir > 0 ? s->kcuf1 : s->kcub1, -1); |
955 |
} else { |
} else { |
956 |
text_move_left_right_visual(e, dir); |
text_move_left_right_visual(e, dir); |
957 |
} |
} |
971 |
{ |
{ |
972 |
if (e->interactive) { |
if (e->interactive) { |
973 |
ShellState *s = e->b->priv_data; |
ShellState *s = e->b->priv_data; |
974 |
tty_write(s, dir > 0 ? "\033[B" : "\033[A", -1); |
tty_write(s, dir > 0 ? s->kcud1 : s->kcuu1, -1); |
975 |
} else { |
} else { |
976 |
text_move_up_down(e, dir); |
text_move_up_down(e, dir); |
977 |
} |
} |
1186 |
|
|
1187 |
/* specific shell commands */ |
/* specific shell commands */ |
1188 |
static CmdDef shell_commands[] = { |
static CmdDef shell_commands[] = { |
|
CMD0( KEY_NONE, KEY_NONE, "shell", do_shell) |
|
1189 |
CMD0( KEY_CTRL('o'), KEY_NONE, "shell-toggle-input", do_shell_toggle_input) |
CMD0( KEY_CTRL('o'), KEY_NONE, "shell-toggle-input", do_shell_toggle_input) |
1190 |
CMD1( '\r', KEY_NONE, "shell-return", shell_write_char, '\r') |
CMD1( '\r', KEY_NONE, "shell-return", shell_write_char, '\r') |
1191 |
|
/* CG: should send s->kbs */ |
1192 |
CMD1( 127, KEY_NONE, "shell-backward-delete-char", shell_write_char, 127) |
CMD1( 127, KEY_NONE, "shell-backward-delete-char", shell_write_char, 127) |
1193 |
CMD1( KEY_CTRL('d'), KEY_DELETE, "shell-delete-char", shell_write_char, 4) |
CMD1( KEY_CTRL('d'), KEY_DELETE, "shell-delete-char", shell_write_char, 4) |
1194 |
CMD1( KEY_CTRL('i'), KEY_NONE, "shell-tabulate", shell_write_char, 9) |
CMD1( KEY_CTRL('i'), KEY_NONE, "shell-tabulate", shell_write_char, 9) |
1198 |
|
|
1199 |
/* compilation commands */ |
/* compilation commands */ |
1200 |
static CmdDef compile_commands[] = { |
static CmdDef compile_commands[] = { |
1201 |
|
CMD_( KEY_CTRLXRET('\r'), KEY_NONE, "shell", do_shell, "i") |
1202 |
CMD_( KEY_CTRLX(KEY_CTRL('e')), KEY_NONE, "compile", do_compile, |
CMD_( KEY_CTRLX(KEY_CTRL('e')), KEY_NONE, "compile", do_compile, |
1203 |
"s{Compile command: }|compile|") |
"s{Compile command: }|compile|") |
1204 |
CMD1( KEY_CTRLX(KEY_CTRL('p')), KEY_NONE, "previous-error", |
CMD1( KEY_CTRLX(KEY_CTRL('p')), KEY_NONE, "previous-error", |