add auto-arrow, multipliers, -s, -h - gramscii - A simple editor for ASCII box-and-arrow charts DIR Log DIR Files DIR Refs DIR Tags DIR README DIR LICENSE --- DIR commit f0200b8cc94cd6859ee91b7b47d1d89b41b195ed DIR parent cbfdf55b79d29e94b1f3d263dc74ee55140bbc66 HTML Author: KatolaZ <katolaz@freaknet.org> 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(-) --- DIR diff --git a/README.md b/README.md @@ -74,3 +74,16 @@ intellectual, a philosopher, and an artist, and maintained that societal 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 +<katolaz@freaknet.org>. 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. DIR 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 DIR 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 DIR 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-and-arrows 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 DIR 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: "); /** FALLTHROUGH **/ 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;