Introduction
Introduction Statistics Contact Development Disclaimer Help
screen.c - gramscii - A simple editor for ASCII box-and-arrow charts
Log
Files
Refs
Tags
README
LICENSE
---
screen.c (10512B)
---
1 #define _POSIX_C_SOURCE 200112L
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <termios.h>
7 #include <sys/ioctl.h>
8 #include <ctype.h>
9
10 #include "gramscii.h"
11 #include "config.h"
12
13 /** extern declarations **/
14
15 extern lineset_t screen; /* what is visualised */
16 extern lineset_t cutbuf; /* cut/paste buffer */
17 extern lineset_t *undo; /* undo list */
18
19 extern pos_t marks[26]; /* position marks */
20 extern char mark_map[26]; /* marks map */
21
22 extern int undo_sz;/* allocated size of undo list*/
23 extern int undo_cur;/* undo position */
24 extern int undo_lst;/* last valid undo position */
25
26 extern int WIDTH, HEIGHT;
27
28 extern int mode;/* mode */
29 extern int dir;/* line direction */
30 extern int x;
31 extern int y;
32 extern int step;/* current step */
33 extern int mult;/* current multiplier */
34
35 extern char corner;
36
37 /* number of available markers for each type */
38 extern int hlines_sz;
39 extern int vlines_sz;
40 extern int corners_sz;
41 extern int stmarks_sz;
42 extern int endmarks_sz;
43 /**/
44
45 /* line and arrow markers */
46 extern int cur_hl, cur_vl, cur_corn, cur_start, cur_end;
47 extern char line_h;
48 extern char line_v;
49 extern char mark_st;
50 extern char mark_end;
51 /**/
52
53 extern char modified; /* set to 1 if screen modified since last save */
54 extern char fname[256];
55
56
57 extern char script; /* set to 1 in script-mode */
58
59 extern struct termios t2, t3;
60
61
62 /*** screen management functions ***/
63
64 /*** _isblank ***/
65
66 int _isblank(int c){
67 return c==32 || c==9 ? 1 : 0;
68 }
69
70
71 /*** Status bar ***/
72
73 char* mode_str(){
74 switch(mode){
75 case MOVE:
76 return "mov";
77 case TEXT:
78 return "txt";
79 case BOX:
80 return "box";
81 case ARROW:
82 return "arr";
83 case DEL:
84 return "del";
85 case VIS:
86 return "vis";
87 case PAR:
88 return "par";
89 case REM:
90 return "rem";
91 case TRP:
92 return "trp";
93 default:
94 return "ERR";
95 }
96 return "ERR";
97 }
98
99 char get_mark(char dir){
100 switch(dir){
101 case DIR_U:
102 return '^';
103 case DIR_D:
104 return 'v';
105 case DIR_L:
106 return '<';
107 case DIR_R:
108 return '>';
109 }
110 return '>';
111 }
112
113
114 void status_bar(){
115
116 if (script)
117 return;
118 printf("\033[%d;1f\033[7m", HEIGHT+1);
119 printf("%*s", WIDTH-1, "");
120 printf("\033[%d;1f\033[7m", HEIGHT+1);
121 printf(" x:%3d y:%3d -- MODE:%4s HL:%c VL:%c CN:%c SP:%c EP:%c %…
122 x, y, mode_str(), line_h, line_v, corner, mark_st, mark_…
123 if (!modified)
124 printf(" [%s]", fname );
125 else
126 printf(" *%s*", fname );
127 #ifdef DEBUG
128 printf(" '%d' ", screen.l[y].s[x]);
129 #endif
130 printf("\033[0m");
131 fflush(stdout);
132 }
133
134 char get_key(FILE *fc, char *msg){
135
136 if (script)
137 return 0;
138 printf("\033[%d;1f\033[7m", HEIGHT+1);
139 printf("%*s", WIDTH, "");
140 printf("\033[%d;1f\033[7m", HEIGHT+1);
141 printf("%s", msg);
142 fflush(stdout);
143 printf("\033[0m");
144 fflush(stdout);
145 return fgetc(fc);
146 }
147
148 void get_string(FILE *fc, char *msg, char *s, int sz){
149
150 if (!script){
151 printf("\033[%d;1f\033[7m", HEIGHT+1);
152 printf("%*s", WIDTH, "");
153 printf("\033[%d;1f\033[7m", HEIGHT+1);
154
155 /* We must activate echo now */
156 t3 = t2;
157 t3.c_lflag |= (ECHO | ICANON);
158 tcsetattr(0, TCSANOW, &t3);
159 printf("%s", msg);
160 printf("\033[0m");
161 }
162 fgets(s, sz, fc);
163 s[strlen(s)-1] = '\0';
164 if (!script){
165 tcsetattr(0, TCSANOW, &t2);
166 fflush(stdout);
167 }
168 }
169
170 int is_yes(char c){
171 return c=='y' ? 1 : c == 'Y'? 1 : 0;
172 }
173
174 /*** Screen management ***/
175
176
177 void show_cursor(){
178 if (script)
179 return;
180 printf("\033[%d;%df", y+1, x+1);
181 fflush(stdout);
182 }
183
184
185 void set_xy(int _x, int _y, char c){
186 ensure_num_lines(&screen, _y + 1);
187 ensure_line_length(&(screen.l[_y]), _x + 1);
188 while (screen.l[_y].lst<_x){
189 screen.l[_y].lst ++;
190 screen.l[_y].s[screen.l[_y].lst] = BG;
191 }
192 screen.l[_y].s[_x] = c;
193 if (_x == screen.l[_y].lst)
194 screen.l[_y].s[_x+1] = '\0';
195 }
196
197 void set_cur(char c){
198 set_xy(x, y, c);
199 }
200
201 void draw_xy(int x, int y, char c){
202 /* FIXME: check if x and y are valid!!!! */
203 if (script)
204 return;
205 printf("\033[%d;%df",y+1,x+1);
206 putchar(c);
207 fflush(stdout);
208 }
209
210 void update_current(){
211 if (script)
212 return;
213 printf("\033[%d;%df",y+1,x+1);
214 putchar(screen.l[y].s[x]);
215 fflush(stdout);
216 }
217
218 void erase_blank_lines(int y1, int y2){
219 int j;
220 if (y1 > y2){
221 y1 ^= y2;
222 y2 ^= y1;
223 y1 ^= y2;
224 }
225
226 for (; y1 <= y2; y1++){
227 j = screen.l[y1].lst;
228 while (j>=0 && _isblank(screen.l[y1].s[j]))
229 j--;
230 if (j<0){
231 screen.l[y1].lst = -1;
232 screen.l[y1].s[0] = '\0';
233 }
234 }
235 }
236
237
238 void erase_line(int i){
239 screen.l[i].lst = -1;
240 screen.l[i].s[0] = '\0';
241 }
242
243 void erase_box(int x1, int y1, char c){
244 int x_incr, y_incr, i;
245
246 x_incr = x1 < x? +1: -1;
247 y_incr = y1 < y? +1: -1;
248 do{
249 i = y1;
250 do{
251 set_xy(x1, i, c);
252 } while(i != y && (1 | (i += y_incr)));
253 } while(x1 != x && (1 | (x1 += x_incr)));
254
255 }
256
257 void erase_screen(){
258 int i;
259 for(i=0;i<HEIGHT; i++)
260 erase_line(i);
261 }
262
263 void check_bound(int *x, int *y){
264 if (*x<0) *x=0;
265 else if (*x>=WIDTH) *x = WIDTH-1;
266 if (*y<0) *y=0;
267 else if (*y>=HEIGHT) *y = HEIGHT -1;
268 }
269
270 void reset_styles(){
271
272 cur_corn = 0;
273 corner = corners[0];
274 cur_hl = cur_vl = 0;
275 cur_start = cur_end = 0;
276 line_h = hlines[cur_hl];
277 line_v = vlines[cur_vl];
278 mark_st = st_marks[cur_start];
279 mark_end = end_marks[cur_end];
280 }
281
282 void redraw(){
283 int i;
284
285 if (script)
286 return;
287 printf("\033[2J\033[1;1H");
288 for (i=0;i<HEIGHT;i++){
289 fprintf(stdout,"%s\n",screen.l[i].s);
290 }
291 status_bar();
292 show_cursor();
293 }
294
295 void go_to(int where){
296 switch(where){
297 case HOME:
298 x = y = 0;
299 break;
300 case END:
301 x = WIDTH-1;
302 y = HEIGHT-1;
303 break;
304 case MIDDLE:
305 x = WIDTH/2;
306 y = HEIGHT/2;
307 break;
308 }
309 check_bound(&x, &y);
310 show_cursor();
311 }
312
313 void handle_goto(FILE *fc, char global){
314 char c;
315 c=fgetc(fc);
316 switch(c){
317 case 'h':
318 dir = DIR_L;
319 step = x;
320 x = 0;
321 break;
322 case 'l':
323 dir = DIR_R;
324 step = WIDTH - x -1;
325 x = WIDTH - 1;
326 break;
327 case 'j':
328 dir = DIR_D;
329 step = HEIGHT - y-1;
330 y = HEIGHT - 1;
331 break;
332 case 'k':
333 dir = DIR_U;
334 step = y;
335 y = 0;
336 break;
337 case 'g':
338 if (global){
339 dir = DIR_N;
340 go_to(HOME);
341 } else step = 0;
342 break;
343 case 'G':
344 if (global){
345 dir = DIR_N;
346 go_to(END);
347 } else step = 0;
348 break;
349 case 'm':
350 if (global){
351 dir = DIR_N;
352 go_to(MIDDLE);
353 } else step = 0;
354 break;
355 case '\'':
356 c = tolower(fgetc(fc));
357 if (global) {
358 dir = DIR_N;
359 if (isalpha(c) && mark_map[c - 'a']){
360 x = marks[c - 'a'].x;
361 y = marks[c - 'a'].y;
362 #ifdef DEBUG
363 fprintf(stderr, "going to valid …
364 #endif
365 }
366 #ifdef DEBUG
367 else
368 fprintf(stderr, "invalid mark '%…
369 #endif
370 } else step = 0;
371 break;
372
373 }
374
375 #ifdef DEBUG
376 fprintf(stderr, "global move: dir: %d x: %d y: %d\n", dir, x, y);
377 #endif
378 check_bound(&x, &y);
379 show_cursor();
380 }
381
382
383 int get_escape(FILE *fc){
384 char c[4];
385
386 c[0] = fgetc(fc);
387 if (c[0] == '['){
388 c[1] = fgetc(fc);
389 switch(c[1]){
390 case 'D':
391 dir = DIR_L;
392 x -= step;
393 break;
394 case 'B':
395 dir = DIR_D;
396 y += step;
397 break;
398 case 'A':
399 dir = DIR_U;
400 y -= step;
401 break;
402 case 'C':
403 dir = DIR_R;
404 x += step;
405 break;
406 }
407 return 1;
408 }
409 else{
410 ungetc(c[0], fc);
411 return 0;
412 }
413
414 }
415
416
417 int move_around(char c, FILE *fc, char global){
418
419 if (isdigit(c)){
420 if (mult)
421 mult *=10;
422 mult += c - '0';
423 return 0;
424 }
425 #ifdef DEBUG
426 fprintf(stderr, "got char: %c\n", c);
427 #endif
428 switch(c){
429 case 27: /* control sequence? */
430 c = get_escape(fc);
431 break;
432 case 'H': step = LONG_STEP;/** FALLTHROUGH **/
433 case 'h':
434 dir = DIR_L;
435 if (mult)
436 step *= mult;
437 x -= step;
438 break;
439 case 'J': step = LONG_STEP;/** FALLTHROUGH **/
440 case 'j':
441 if (mult)
442 step *= mult;
443 dir = DIR_D;
444 y += step;
445 break;
446 case 'K': step = LONG_STEP;/** FALLTHROUGH **/
447 case 'k':
448 if (mult)
449 step *= mult;
450 dir = DIR_U;
451 y -= step;
452 break;
453 case 'L': step = LONG_STEP;/** FALLTHROUGH **/
454 case 'l':
455 if (mult)
456 step *= mult;
457 dir = DIR_R;
458 x += step;
459 break;
460 case 'g':
461 #ifdef DEBUG
462 fprintf(stderr, "before handle_goto: step: %d x:…
463 #endif
464 handle_goto(fc, global);
465 #ifdef DEBUG
466 fprintf(stderr, "after handle_goto: step: %d x: …
467 #endif
468 break;
469 default:
470 return 0;
471 }
472 mult = 0;
473 return c;
474 }
475
476
477 void set_video(int v){
478 if (script)
479 return;
480 printf("\033[%dm", v);
481 fflush(stdout);
482 }
483
484
485 void init_screen(){
486 int i;
487 struct winsize wsz;
488
489 if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz)){
490 WIDTH=wsz.ws_col - 2;
491 HEIGHT=wsz.ws_row - 1;
492 }
493 else {
494 WIDTH=80;
495 HEIGHT=24;
496 }
497 screen.l = malloc(HEIGHT * sizeof(line_t));
498 screen.sz = HEIGHT;
499 screen.num = HEIGHT;
500 if (screen.l == NULL){
501 fprintf(stderr, "Error allocating screen");
502 cleanup(1);
503 }
504 for (i=0; i<HEIGHT; i++){
505 alloc_line(&(screen.l[i]));
506 }
507 /* init markers */
508 hlines_sz= sizeof(hlines) -1;
509 vlines_sz= sizeof(vlines) -1;
510 corners_sz = sizeof(corners) -1;
511 stmarks_sz = sizeof(st_marks) - 1;
512 endmarks_sz = sizeof(st_marks) - 1;
513 reset_styles();
514 /* init undo ring */
515 cutbuf.sz = 0;
516 cutbuf.l = NULL;
517 cutbuf.num = 0;
518 undo = NULL;
519 undo_sz = 0;
520 undo_cur = -2;
521 undo_lst = -2;
522 /* init pos marks */
523 memset(mark_map, 0, 26 * sizeof(char));
524 }
525
526 void find_nonblank_rect(int *x1, int *y1, int *x2, int *y2){
527
528 int i, j;
529 int first;
530 *x1= WIDTH; /** FIXME: replace with num_cols **/
531 *y1 = screen.num;
532 *x2 = *y2 = 0;
533
534 for (i=0; i<screen.num; i++){
535 if (screen.l[i].lst < 0)
536 continue;
537 *y2 = i;
538 if (i < *y1)
539 *y1 = i;
540 j = 0;
541 while((j <= screen.l[i].lst) && _isblank(first=screen.l…
542 j++;
543 if (j < *x1)
544 *x1 = j;
545 j = screen.l[i].lst;
546 while(_isblank(screen.l[i].s[j]))
547 j--;
548 if (j > *x2)
549 *x2 = j;
550 }
551 }
552
553 void crop_to_rect(int x1, int y1, int x2, int y2){
554 int i;
555
556 for (i=0; i<= y2-y1; i ++){
557 ensure_line_length(&(screen.l[i]), screen.l[i+y1].lst+1);
558 sprintf(screen.l[i].s, "%s", screen.l[i+y1].s + x1);
559 screen.l[i].lst = x2 - x1;
560 screen.l[i].s[screen.l[i].lst + 1] = '\0';
561 }
562 while (i< HEIGHT){
563 screen.l[i].lst = -1;
564 screen.l[i].s[0]= '\0';
565 i ++;
566 }
567 }
568
569 void crop_to_nonblank(){
570 int x1, x2, y1, y2;
571 find_nonblank_rect(&x1, &y1, &x2, &y2);
572 #ifdef DEBUG
573 fprintf(stderr, "crop rectangle: (%d, %d)-(%d, %d)\n", x1, y1, x…
574 #endif
575 copy_lines_to_ring(0, y2, PRV_STATE);
576 crop_to_rect(x1, y1, x2, y2);
577 copy_lines_to_ring(0, y2, NEW_STATE);
578 modified=1;
579 redraw();
580 }
581
582 /** position marks **/
583
584 void mark_pos(FILE *fc){
585
586 char c;
587 c = tolower(fgetc(fc));
588 if (isalpha(c)){
589 marks[c - 'a'].x = x;
590 marks[c - 'a'].y = y;
591 mark_map[c - 'a'] = 1;
592 #ifdef DEBUG
593 fprintf(stderr, "marking pos (%d, %d) as '%c'\n", x, y, …
594 #endif
595 }
596 }
You are viewing proxied material from bitreich.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.