add auto-arrow, multipliers, -s, -h - gramscii - A simple editor for ASCII box-… | |
Log | |
Files | |
Refs | |
Tags | |
README | |
LICENSE | |
--- | |
commit f0200b8cc94cd6859ee91b7b47d1d89b41b195ed | |
parent cbfdf55b79d29e94b1f3d263dc74ee55140bbc66 | |
Author: KatolaZ <[email protected]> | |
Date: Fri, 26 Jul 2019 10:26:40 +0100 | |
add auto-arrow, multipliers, -s, -h | |
Diffstat: | |
M README.md | 13 +++++++++++++ | |
M TODO | 11 ++++++----- | |
M config.mk | 2 +- | |
M gramscii.1 | 56 +++++++++++++++++++++++++++++… | |
M gramscii.c | 114 ++++++++++++++++++++++++++++-… | |
5 files changed, 180 insertions(+), 16 deletions(-) | |
--- | |
diff --git a/README.md b/README.md | |
@@ -74,3 +74,16 @@ intellectual, a philosopher, and an artist, and maintained t… | |
changes are only possible when a class exerts intellectual and moral | |
leadership over its contemporaries. So just get rid of all your shiny | |
iPointless things and come back to reality. | |
+ | |
+COPYING | |
+======= | |
+ | |
+`gramscii` is written and maintained by Vincenzo 'KatolaZ' Nicosia | |
+<[email protected]>. You can use, modify and/or redistribute it under | |
+the terms of the GNU General Public Licence, either version 3 of the | |
+License or, at your option, any later version. | |
+ | |
+This program is distributed in the hope that it will be useful, but | |
+WITHOUT ANY WARRANTY; without even the implied warranty of | |
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
+General Public License for more details. | |
diff --git a/TODO b/TODO | |
@@ -1,14 +1,13 @@ | |
+ optimize redraws (redraw only the modified rectangle) | |
- change screen management (i.e., dynamic array of lines) | |
-- add action multiplier (e.g., "7h" moves left by 7 cols) | |
-- add scripting mode option ("-s"?) | |
- add screen geometry option (-g 25x80?) | |
- read file at point | |
+ - read output of command (!) | |
- use [ENTER] to exit from text insert | |
- maybe move "text" mode to "t" | |
- implement ellipse | |
-- parse control characters | |
- - parse arrows (text-mode will allow movements as well) | |
++ parse control characters | |
+ + parse arrows (text-mode will allow movements as well) | |
- (?) implement CTRL+G as abort (aside ESC) | |
- add crop command (c) | |
- remove extra blanks until EOL when saving to file | |
@@ -23,7 +22,9 @@ | |
- allow scrolling (both vertical and horizontal) | |
- catch SIGWINCH and react appropriately (after scroll is | |
enabled) | |
-- auto-arrow 'A' (automatic end-char) | |
+* add action multiplier (e.g., "7h" moves left by 7 cols) | |
+* add scripting mode option ("-s"?) | |
+* auto-arrow 'A' (automatic end-char) | |
* move configs in config.h | |
* get screen geometry | |
* allow the use of [ENTER] to confirm arrow, boxes (useful | |
diff --git a/config.mk b/config.mk | |
@@ -3,4 +3,4 @@ BINDIR = ${PREFIX}/bin | |
MANDIR = ${PREFIX}/share/man | |
CFLAGS = -O3 -std=c90 -pedantic -Wall | |
-##CC = cc | |
+CC = cc | |
diff --git a/gramscii.1 b/gramscii.1 | |
@@ -4,6 +4,9 @@ gramscii \- simple editor for ASCII box diagrams | |
.SH SYNOPSIS | |
.PP | |
gramscii | |
+.RI [-s] | |
+.RI [-h] | |
+.RI [file ...] | |
.PP | |
.SH DESCRIPTION | |
.PP | |
@@ -11,6 +14,18 @@ gramscii is a simple interactive editor to create ASCII box-… | |
diagrams. It uses vi-like keybindings for drawing and editing boxes, | |
arrows, and text. | |
.PP | |
+.SH OPTIONS | |
+.TP 5m | |
+.BI -s | |
+Start gramscii in script-mode. In this mode the screen is set to 25 rows | |
+by 80 columns, no status bar is present, drawings and cursor movements | |
+are not shown, and the state of the screen is dumped to stdout when the | |
+program ends. With this flag, gramscii can be used in a pipeline, | |
+getting commands from stdin (or from a file) and making its output | |
+available for further processing. | |
+.TP | |
+.BI -h | |
+Print short usage unstructions and exit. | |
.SH COMMANDS | |
gramscii is a visual modal editor. Commands are associated to | |
keystrokes, and keystrokes have different meaning in different modes. | |
@@ -97,7 +112,9 @@ move the cursor right by 1 column | |
.PP | |
gramscii accepts also the uppercase commands | |
.B H, J, K, L, | |
-which will move in the corresponding direction by 5 units at a time. | |
+which will move in the corresponding direction by a LONG_STEP number of | |
+units at a time (defaults to 5, change LONG_STEP in config.h as you | |
+wish). | |
.TP 5m | |
.BI g | |
Initiate a global positioning command (go). These are two-letter | |
@@ -152,8 +169,35 @@ Typing | |
.BI g | |
followed by any character that is not listed above has no effect on the | |
cursor. | |
+.SS MULTIPLIERS | |
+Simple cursor movement commands (hjklHJKL) can be preceded by a number | |
+that acts as a multiplier. For instance, the command: | |
+.PP | |
+.RS | |
+14h | |
+.PP | |
.RE | |
- | |
+will move the cursor by 14 steps to the left. Similarily, the command: | |
+.PP | |
+.RS | |
+7J | |
+.PP | |
+.RE | |
+will move the cursor by 7 LONG_STEPs rows down (with the default | |
+LONG_STEP equal to 5, this will correspond to 35 rows down). | |
+.PP | |
+Multipliers can be used whenever a movement command is legal, i.e. in | |
+move, box, arrox, visual, and erase mode. So for instance the sequence: | |
+.RS | |
+ggb13l18jb | |
+.PP | |
+.RE | |
+will draw a 18x13 box whose top-left corner coincides with the top-left | |
+corner of the screen. | |
+.PP | |
+Multipliers are ignored by global positioning commands (i.e., those | |
+starting with | |
+.B g) | |
.SS MODES | |
The currently supported modes are: | |
.B move, | |
@@ -233,6 +277,14 @@ styles. See | |
.B STYLES | |
below for more information. | |
.TP 7m | |
+.BI A | |
+Exactly as | |
+.BI a | |
+toggles | |
+.B arrow | |
+mode, but the end point marker is automatically set according to the | |
+direction of the arrow. | |
+.TP 7m | |
.BI x | |
Toggle | |
.B erase | |
diff --git a/gramscii.c b/gramscii.c | |
@@ -27,6 +27,7 @@ | |
#include <signal.h> | |
#include <string.h> | |
#include <sys/ioctl.h> | |
+#include <ctype.h> | |
#include "config.h" | |
@@ -80,6 +81,7 @@ int dir; | |
int x; | |
int y; | |
int step; | |
+int mult; | |
int force_new; | |
char cursor; | |
char corner; | |
@@ -101,6 +103,7 @@ char fname[256]; | |
char visual; | |
char silent; | |
+char autoend; | |
char *argv0; | |
@@ -147,6 +150,20 @@ char* state_str(){ | |
return "ERR"; | |
} | |
+char get_mark(char dir){ | |
+ switch(dir){ | |
+ case DIR_U: | |
+ return '^'; | |
+ case DIR_D: | |
+ return 'v'; | |
+ case DIR_L: | |
+ return '<'; | |
+ case DIR_R: | |
+ return '>'; | |
+ } | |
+ return '>'; | |
+} | |
+ | |
void status_bar(){ | |
@@ -355,26 +372,78 @@ void handle_goto(){ | |
show_cursor(); | |
} | |
-int move_around(char c){ | |
+int get_escape(FILE *fc){ | |
+ char c[4]; | |
+ | |
+ c[0] = fgetc(fc); | |
+ if (c[0] == '['){ | |
+ c[1] = fgetc(fc); | |
+ switch(c[1]){ | |
+ case 'D': | |
+ dir = DIR_L; | |
+ x -= step; | |
+ break; | |
+ case 'B': | |
+ dir = DIR_D; | |
+ y += step; | |
+ break; | |
+ case 'A': | |
+ dir = DIR_U; | |
+ y -= step; | |
+ break; | |
+ case 'C': | |
+ dir = DIR_R; | |
+ x += step; | |
+ break; | |
+ } | |
+ return 1; | |
+ } | |
+ else{ | |
+ ungetc(c[0], fc); | |
+ return 0; | |
+ } | |
+ | |
+} | |
+ | |
+ | |
+int move_around(char c, FILE *fc){ | |
+ | |
+ if (isdigit(c)){ | |
+ if (mult) | |
+ mult *=10; | |
+ mult += c - '0'; | |
+ return 0; | |
+ } | |
switch(c){ | |
+ case 27: /* control sequence? */ | |
+ c = get_escape(fc); | |
+ break; | |
case 'H': step = LONG_STEP;/** FALLTHROUGH **/ | |
case 'h': | |
dir = DIR_L; | |
+ if (mult) | |
+ step *= mult; | |
x -= step; | |
break; | |
case 'J': step = LONG_STEP;/** FALLTHROUGH **/ | |
case 'j': | |
+ if (mult) | |
+ step *= mult; | |
dir = DIR_D; | |
y += step; | |
break; | |
case 'K': step = LONG_STEP;/** FALLTHROUGH **/ | |
case 'k': | |
+ if (mult) | |
+ step *= mult; | |
dir = DIR_U; | |
y -= step; | |
break; | |
case 'L': step = LONG_STEP;/** FALLTHROUGH **/ | |
case 'l': | |
+ if (mult) | |
+ step *= mult; | |
dir = DIR_R; | |
x += step; | |
break; | |
@@ -384,6 +453,7 @@ int move_around(char c){ | |
default: | |
return 0; | |
} | |
+ mult = 0; | |
return c; | |
} | |
@@ -535,7 +605,7 @@ void get_box(FILE *fc){ | |
while((c=fgetc(fc))!=EOF && c != 27 && c!= 'b' && c != '\n'){ | |
if (change_style(c)) | |
goto update_box; | |
- if (!move_around(c)) | |
+ if (!move_around(c, fc)) | |
continue; | |
check_bound(); | |
redraw(); | |
@@ -589,7 +659,12 @@ void draw_arrow(int x, int y, char *a, int a_len, int fix){ | |
/* f(x,y,mark_end);*/ | |
cur_dir = a[i]; | |
} | |
- f(x,y,mark_end); | |
+ if (autoend){ | |
+ if (cur_dir != DIR_N) | |
+ f(x,y, get_mark(cur_dir)); | |
+ } | |
+ else | |
+ f(x,y,mark_end); | |
show_cursor(); | |
} | |
@@ -613,7 +688,7 @@ void get_arrow(FILE *fc){ | |
while((c=fgetc(fc))!=EOF && c != 27 && c!= 'a' && c != '\n'){ | |
if (change_style(c)) | |
goto update_arrow; | |
- if (!move_around(c)) | |
+ if (!move_around(c, fc)) | |
continue; | |
check_bound(); | |
/* FIXME: if we are out of bound, do nothing? */ | |
@@ -664,7 +739,7 @@ void delete(FILE *fc){ | |
status_bar(); | |
show_cursor(); | |
while((c=fgetc(fc))!=EOF && c!=27 && c!= 'x' && c != '\n'){ | |
- if (!move_around(c)) continue; | |
+ if (!move_around(c, fc)) continue; | |
check_bound(); | |
do_delete(orig_x, orig_y); | |
step = 1; | |
@@ -758,7 +833,7 @@ void visual_box(FILE *fc){ | |
set_video(VIDEO_REV); | |
draw_box(x,y,NOFIX); | |
while((c=fgetc(fc))!=EOF && c != 27 && c!= 'v' && c != '\n'){ | |
- if (!move_around(c)) switch(c){ | |
+ if (!move_around(c, fc)) switch(c){ | |
case 'f':/* fill */ | |
f = get_key(fc, "fill char: "); /** FALLTHROUG… | |
case 'x':/* erase */ | |
@@ -842,7 +917,7 @@ void commands(FILE *fc){ | |
char c; | |
while((c=fgetc(fc))!=EOF){ | |
- if (!change_style(c) && !move_around(c)){ | |
+ if (!change_style(c) && !move_around(c, fc)){ | |
switch(c){ | |
case 'i': | |
state = TEXT; | |
@@ -855,9 +930,11 @@ void commands(FILE *fc){ | |
state = BOX; | |
get_box(fc); | |
break; | |
+ case 'A': autoend=1; | |
case 'a': | |
state = ARROW; | |
get_arrow(fc); | |
+ autoend = 0; | |
break; | |
case 'W': | |
force_new = 1;/** FALLTHROUGH **/ | |
@@ -897,17 +974,38 @@ void commands(FILE *fc){ | |
} | |
+void usage(){ | |
+ fprintf(stderr, "Usage: %s [-s] [-h] [file ...]\n", argv0); | |
+ exit(1); | |
+} | |
+ | |
int main(int argc, char *argv[]){ | |
+ FILE *fc; | |
ARGBEGIN { | |
case 's': | |
silent = 1; | |
break; | |
+ case 'h': /* FALLTHROUGH */ | |
+ default: | |
+ usage(); | |
} ARGEND; | |
init(); | |
- | |
+ while (argc){ | |
+ fc = fopen(argv[0], "r"); | |
+ if (fc == NULL){ | |
+ fprintf(stderr, "Error opening file %s\n", argv[0]); | |
+ } | |
+ else { | |
+ commands(fc); | |
+ fclose(fc); | |
+ redraw(); | |
+ } | |
+ argv++; | |
+ argc--; | |
+ } | |
commands(stdin); | |
cleanup(0); | |
return 0; |