reorganise code and new file - gramscii - A simple editor for ASCII box-and-arr… | |
Log | |
Files | |
Refs | |
Tags | |
README | |
LICENSE | |
--- | |
commit 2f5d0a4be8c029c5a4d1279be8823604db2c0fc2 | |
parent a4c6053e9df10cc4060696d6c29e84fa3105ad0e | |
Author: KatolaZ <[email protected]> | |
Date: Sat, 20 Jul 2019 10:39:38 +0100 | |
reorganise code and new file | |
Diffstat: | |
M TODO | 2 +- | |
M gramscii.c | 461 +++++++++++++++++------------… | |
2 files changed, 249 insertions(+), 214 deletions(-) | |
--- | |
diff --git a/TODO b/TODO | |
@@ -1,7 +1,6 @@ | |
+ optimize redraws (i.e., avoid to redraw if possible) | |
- (?) change cursor shape according to action | |
- auto-arrow 'A' (automatic end-char) | |
-- load from file | |
- read file at point | |
- visual selection | |
- crop | |
@@ -13,6 +12,7 @@ | |
(also do not print unmanaged chars!) | |
- get screen geometry | |
- allow scrolling (both vertical and horizontal) | |
+* load from file | |
* check if modified on exit | |
* write to new file / default file | |
* delete -- 'x' | |
diff --git a/gramscii.c b/gramscii.c | |
@@ -89,6 +89,70 @@ void cleanup(int s){ | |
exit(0); | |
} | |
+/*** Status bar ***/ | |
+ | |
+char* state_str(){ | |
+ switch(state){ | |
+ case MOVE: | |
+ return "mov"; | |
+ case TEXT: | |
+ return "txt"; | |
+ case BOX: | |
+ return "box"; | |
+ case ARROW: | |
+ return "arr"; | |
+ case DEL: | |
+ return "del"; | |
+ default: | |
+ return "ERR"; | |
+ } | |
+ return "ERR"; | |
+} | |
+ | |
+ | |
+void status_bar(){ | |
+ | |
+ printf("\033[%d;1f\033[7m", HEIGHT+1); | |
+ printf("%100s", " "); | |
+ printf("\033[%d;1f\033[7m", HEIGHT+1); | |
+ printf(" x: %3d y: %3d -- mode: %4s hl: %c vl: %c cn: %c <: %c >: %c %… | |
+ x, y, state_str(), line_h, line_v, corner, mark_st, mark_end, … | |
+ printf(" [%s]", fname ); | |
+ printf("\033[0m"); | |
+} | |
+ | |
+char get_key(char *s){ | |
+ | |
+ printf("\033[%d;1f\033[7m", HEIGHT+1); | |
+ printf("%100s", " "); | |
+ printf("\033[%d;1f\033[7m", HEIGHT+1); | |
+ printf("%s ", s); | |
+ printf("\033[0m"); | |
+ return getchar(); | |
+} | |
+ | |
+void get_string(char *msg, char *s, int sz){ | |
+ | |
+ printf("\033[%d;1f\033[7m", HEIGHT+1); | |
+ printf("%100s", " "); | |
+ printf("\033[%d;1f\033[7m", HEIGHT+1); | |
+ /* We must activate echo now */ | |
+ t3 = t2; | |
+ t3.c_lflag |= (ECHO | ICANON); | |
+ tcsetattr(0, TCSANOW, &t3); | |
+ printf("%s", msg); | |
+ printf("\033[0m"); | |
+ fgets(s, sz, stdin); | |
+ s[strlen(s)-1] = '\0'; | |
+ tcsetattr(0, TCSANOW, &t2); | |
+} | |
+ | |
+int is_yes(char c){ | |
+ return c=='y' ? 1 : c == 'Y'? 1 : 0; | |
+} | |
+ | |
+/*** Screen management ***/ | |
+ | |
void show_cursor(){ | |
printf("\033[%d;%df", y+1, x+1); | |
} | |
@@ -108,6 +172,31 @@ void draw_xy(int x, int y, char c){ | |
putchar(c); | |
} | |
+void update_current(){ | |
+ printf("\033[%d'%df",y+1,x+1); | |
+ putchar(screen[y][x]); | |
+} | |
+ | |
+void erase_line(char *s){ | |
+ while(*s){ | |
+ *s++ = BG; | |
+ } | |
+} | |
+ | |
+void erase_screen(){ | |
+ int i; | |
+ for(i=0;i<HEIGHT; i++) | |
+ erase_line(screen[i]); | |
+} | |
+ | |
+ | |
+void check_bound(){ | |
+ if (x<0) x=0; | |
+ else if (x>=WIDTH) x = WIDTH-1; | |
+ if (y<0) y=0; | |
+ else if (y>=HEIGHT) y = HEIGHT -1; | |
+} | |
+ | |
void init_screen(){ | |
int i; | |
for(i=0; i<HEIGHT; i++){ | |
@@ -124,36 +213,6 @@ void init_screen(){ | |
mark_end = end_marks[cur_end]; | |
} | |
-char* state_str(){ | |
- switch(state){ | |
- case MOVE: | |
- return "mov"; | |
- case TEXT: | |
- return "txt"; | |
- case BOX: | |
- return "box"; | |
- case ARROW: | |
- return "arr"; | |
- case DEL: | |
- return "del"; | |
- default: | |
- return "ERR"; | |
- } | |
- return "ERR"; | |
-} | |
- | |
- | |
-void status_bar(){ | |
- | |
- printf("\033[%d;1f\033[7m", HEIGHT+1); | |
- printf("%100s", " "); | |
- printf("\033[%d;1f\033[7m", HEIGHT+1); | |
- printf(" x: %3d y: %3d -- mode: %4s hl: %c vl: %c cn: %c <: %c >: %c %… | |
- x, y, state_str(), line_h, line_v, corner, mark_st, mark_end, … | |
- printf(" [%s]", fname ); | |
- printf("\033[0m"); | |
-} | |
- | |
void redraw(){ | |
int i; | |
@@ -165,12 +224,99 @@ void redraw(){ | |
show_cursor(); | |
} | |
-void update_current(){ | |
- printf("\033[%d'%df",y+1,x+1); | |
- putchar(screen[y][x]); | |
+int move_around(char c){ | |
+ | |
+ switch(c){ | |
+ case 'H': step = 5; | |
+ case 'h': | |
+ dir = DIR_L; | |
+ x -= step; | |
+ break; | |
+ case 'J': step = 5; | |
+ case 'j': | |
+ dir = DIR_D; | |
+ y += step; | |
+ break; | |
+ case 'K': step = 5; | |
+ case 'k': | |
+ dir = DIR_U; | |
+ y -= step; | |
+ break; | |
+ case 'L': step = 5; | |
+ case 'l': | |
+ dir = DIR_R; | |
+ x += step; | |
+ break; | |
+ default: | |
+ return 0; | |
+ } | |
+ return 1; | |
+} | |
+ | |
+void go_to(int where){ | |
+ switch(where){ | |
+ case HOME: | |
+ x = y = 0; | |
+ break; | |
+ case END: | |
+ x = WIDTH-1; | |
+ y = HEIGHT-1; | |
+ break; | |
+ case MIDDLE: | |
+ x = WIDTH/2; | |
+ y = HEIGHT/2; | |
+ break; | |
+ } | |
+ check_bound(); | |
+ show_cursor(); | |
+} | |
+ | |
+int progr_x(int dir){ | |
+ return dir == DIR_L ? -1 : dir == DIR_R ? 1: 0; | |
} | |
+int progr_y(int dir){ | |
+ return dir == DIR_U ? -1 : dir == DIR_D ? 1: 0; | |
+} | |
+ | |
+/*** Lines and markers ***/ | |
+ | |
+void toggle_hline(){ | |
+ | |
+ cur_hl = (cur_hl + 1) % hlines_sz; | |
+ line_h = hlines[cur_hl]; | |
+ | |
+} | |
+ | |
+void toggle_corner(){ | |
+ | |
+ cur_corn = (cur_corn + 1 ) % corners_sz; | |
+ corner = corners[cur_corn]; | |
+ | |
+} | |
+ | |
+void toggle_vline(){ | |
+ | |
+ cur_vl = (cur_vl + 1) % vlines_sz; | |
+ line_v = vlines[cur_vl]; | |
+ | |
+} | |
+ | |
+void toggle_st_mark(){ | |
+ | |
+ cur_start = (cur_start + 1 ) % stmarks_sz; | |
+ mark_st = st_marks[cur_start]; | |
+} | |
+ | |
+void toggle_end_mark(){ | |
+ | |
+ cur_end = (cur_end+ 1 ) % endmarks_sz; | |
+ mark_end = end_marks[cur_end]; | |
+} | |
+ | |
+ | |
+ | |
void init(){ | |
signal(SIGHUP, cleanup); | |
@@ -191,13 +337,6 @@ void init(){ | |
redraw(); | |
} | |
-void check_bound(){ | |
- if (x<0) x=0; | |
- else if (x>=WIDTH) x = WIDTH-1; | |
- if (y<0) y=0; | |
- else if (y>=HEIGHT) y = HEIGHT -1; | |
-} | |
- | |
/***** text, box, arrows *****/ | |
@@ -215,6 +354,7 @@ void get_text(){ | |
else { | |
set(c); | |
update_current(); | |
+ modified = 1; | |
x += 1; | |
if (x >= WIDTH) | |
x = orig_x; | |
@@ -259,35 +399,6 @@ void draw_box(int x1, int y1, int fix){ | |
} | |
-int move_around(char c){ | |
- | |
- switch(c){ | |
- case 'H': step = 5; | |
- case 'h': | |
- dir = DIR_L; | |
- x -= step; | |
- break; | |
- case 'J': step = 5; | |
- case 'j': | |
- dir = DIR_D; | |
- y += step; | |
- break; | |
- case 'K': step = 5; | |
- case 'k': | |
- dir = DIR_U; | |
- y -= step; | |
- break; | |
- case 'L': step = 5; | |
- case 'l': | |
- dir = DIR_R; | |
- x += step; | |
- break; | |
- default: | |
- return 1; | |
- } | |
- return 0; | |
-} | |
- | |
void get_box(){ | |
char c; | |
@@ -296,7 +407,7 @@ void get_box(){ | |
step = 1; | |
draw_box(x,y,NOFIX); | |
while((c=getchar())!=EOF && c != 27 && c!= 'b'){ | |
- if (move_around(c)) continue; | |
+ if (!move_around(c)) continue; | |
check_bound(); | |
redraw(); | |
step = 1; | |
@@ -312,17 +423,6 @@ void get_box(){ | |
state = MOVE; | |
} | |
- | |
-int progr_x(int dir){ | |
- return dir == DIR_L ? -1 : dir == DIR_R ? 1: 0; | |
-} | |
- | |
- | |
-int progr_y(int dir){ | |
- return dir == DIR_U ? -1 : dir == DIR_D ? 1: 0; | |
-} | |
- | |
- | |
void draw_arrow(int x, int y, char *a, int a_len, int fix){ | |
int i, j, cur_dir; | |
@@ -381,7 +481,7 @@ void get_arrow(){ | |
step = 1; | |
draw_arrow(x,y, arrow, 0, NOFIX); | |
while((c=getchar())!=EOF && c != 27 && c!= 'a'){ | |
- if (move_around(c)) continue; | |
+ if (!move_around(c)) continue; | |
check_bound(); | |
/* FIXME: if we are out of bound, do nothing? */ | |
if (arrow_len == arrow_sz){ | |
@@ -404,112 +504,6 @@ void get_arrow(){ | |
state = MOVE; | |
} | |
-char get_key(char *s){ | |
- | |
- printf("\033[%d;1f\033[7m", HEIGHT+1); | |
- printf("%100s", " "); | |
- printf("\033[%d;1f\033[7m", HEIGHT+1); | |
- printf("%s ", s); | |
- printf("\033[0m"); | |
- return getchar(); | |
-} | |
- | |
-void get_string(char *s, int sz){ | |
- | |
- printf("\033[%d;1f\033[7m", HEIGHT+1); | |
- printf("%100s", " "); | |
- printf("\033[%d;1f\033[7m", HEIGHT+1); | |
- /* We must activate echo now */ | |
- t3 = t2; | |
- t3.c_lflag |= (ECHO | ICANON); | |
- tcsetattr(0, TCSANOW, &t3); | |
- printf("Write to: "); | |
- printf("\033[0m"); | |
- fgets(s, sz, stdin); | |
- s[strlen(s)-1] = '\0'; | |
- tcsetattr(0, TCSANOW, &t2); | |
-} | |
- | |
-int is_yes(char c){ | |
- return c=='y' ? 1 : c == 'Y'? 1 : 0; | |
-} | |
- | |
-void write_file(){ | |
- FILE *f; | |
- int i; | |
- | |
- if (!fname[0] || force_new){ | |
- get_string(fname, 255); | |
- if (f=fopen(fname, "r")){ | |
- if (!is_yes(get_key("File exists. Overwrite [y/n]?")) … | |
- fclose(f); | |
- return; | |
- } | |
- fclose(f); | |
- } | |
- } | |
- if((f=fopen(fname, "w"))==NULL){ | |
- get_key("Error opening file."); | |
- return; | |
- } | |
- for (i=0; i<HEIGHT; i++){ | |
- fprintf(f, "%s\n", screen[i]); | |
- } | |
- fclose(f); | |
- modified = 0; | |
- get_key("File saved."); | |
-} | |
- | |
-void toggle_hline(){ | |
- | |
- cur_hl = (cur_hl + 1) % hlines_sz; | |
- line_h = hlines[cur_hl]; | |
- | |
-} | |
- | |
-void toggle_corner(){ | |
- | |
- cur_corn = (cur_corn + 1 ) % corners_sz; | |
- corner = corners[cur_corn]; | |
- | |
-} | |
- | |
-void toggle_vline(){ | |
- | |
- cur_vl = (cur_vl + 1) % vlines_sz; | |
- line_v = vlines[cur_vl]; | |
- | |
-} | |
- | |
-void toggle_st_mark(){ | |
- | |
- cur_start = (cur_start + 1 ) % stmarks_sz; | |
- mark_st = st_marks[cur_start]; | |
-} | |
- | |
-void toggle_end_mark(){ | |
- | |
- cur_end = (cur_end+ 1 ) % endmarks_sz; | |
- mark_end = end_marks[cur_end]; | |
-} | |
- | |
-void go_to(int where){ | |
- switch(where){ | |
- case HOME: | |
- x = y = 0; | |
- break; | |
- case END: | |
- x = WIDTH-1; | |
- y = HEIGHT-1; | |
- break; | |
- case MIDDLE: | |
- x = WIDTH/2; | |
- y = HEIGHT/2; | |
- break; | |
- } | |
- check_bound(); | |
- show_cursor(); | |
-} | |
void do_delete(int x1, int y1){ | |
int i; | |
@@ -536,7 +530,7 @@ void delete(){ | |
status_bar(); | |
show_cursor(); | |
while((c=getchar())!=EOF && c!=27 && c!= 'x'){ | |
- if (move_around(c)) continue; | |
+ if (!move_around(c)) continue; | |
check_bound(); | |
step = 1; | |
do_delete(orig_x, orig_y); | |
@@ -550,6 +544,34 @@ void delete(){ | |
state = MOVE; | |
} | |
+/*** File management ***/ | |
+ | |
+void write_file(){ | |
+ FILE *f; | |
+ int i; | |
+ | |
+ if (!fname[0] || force_new){ | |
+ get_string("Write to: ", fname, 255); | |
+ if (f=fopen(fname, "r")){ | |
+ if (!is_yes(get_key("File exists. Overwrite [y/n]?")) … | |
+ fclose(f); | |
+ return; | |
+ } | |
+ fclose(f); | |
+ } | |
+ } | |
+ if((f=fopen(fname, "w"))==NULL){ | |
+ get_key("Error opening file."); | |
+ return; | |
+ } | |
+ for (i=0; i<HEIGHT; i++){ | |
+ fprintf(f, "%s\n", screen[i]); | |
+ } | |
+ fclose(f); | |
+ modified = 0; | |
+ get_key("File saved."); | |
+} | |
+ | |
void check_modified(){ | |
if (modified){ | |
@@ -560,34 +582,41 @@ void check_modified(){ | |
} | |
} | |
+void load_file(){ | |
+ | |
+ char newfname[256]; | |
+ FILE *f; | |
+ int i; | |
+ | |
+ get_string("Load file: ", newfname, 255); | |
+ if ((f=fopen(newfname, "r")) != NULL){ | |
+ i = 0; | |
+ while((fgets(screen[i], WIDTH+2, f)) != NULL && i<HEIGHT) | |
+ screen[i++][WIDTH-1]='\0'; | |
+ for(;i<HEIGHT; i++){ | |
+ erase_line(screen[i]); | |
+ } | |
+ fclose(f); | |
+ } | |
+ strcpy(fname, newfname); | |
+ modified=0; | |
+ redraw(); | |
+} | |
+void new_file(){ | |
+ check_modified(); | |
+ erase_screen(); | |
+ go_to(MIDDLE); | |
+ redraw(); | |
+ fname[0] = '\0'; | |
+ modified=0; | |
+} | |
void commands(){ | |
char c; | |
while((c=getchar())!=EOF){ | |
- //screen[y][x]=BG; | |
- switch(c){ | |
- case 'H': | |
- step=5; | |
- case 'h': | |
- x-=step; | |
- break; | |
- case 'J': | |
- step=5; | |
- case 'j': | |
- y+=step; | |
- break; | |
- case 'K': | |
- step=5; | |
- case 'k': | |
- y-=step; | |
- break; | |
- case 'L': | |
- step=5; | |
- case 'l': | |
- x+=step; | |
- break; | |
+ if (!move_around(c)) switch(c){ | |
case 'i': | |
state = TEXT; | |
get_text(); | |
@@ -608,6 +637,14 @@ void commands(){ | |
case 'w': | |
write_file(); | |
break; | |
+ case 'e': | |
+ check_modified(); | |
+ case 'E': | |
+ load_file(); | |
+ break; | |
+ case 'N': | |
+ new_file(); | |
+ break; | |
case 'g': | |
go_to(HOME); | |
break; | |
@@ -642,8 +679,6 @@ void commands(){ | |
cleanup(0); | |
exit(0); | |
break; | |
- default:; | |
- //statu("got: %d\n", c); | |
} | |
check_bound(); | |
status_bar(); |