URI: 
       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;