initial commit - gramscii - A simple editor for ASCII box-and-arrow charts
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 478c03adcdc7d76595a311a0dba682917ab97d62
 (HTM) Author: KatolaZ <katolaz@freaknet.org>
       Date:   Thu, 18 Jul 2019 17:45:38 +0100
       
       initial commit
       
       Diffstat:
         A README                              |       2 ++
         A TODO                                |       9 +++++++++
         A gramscii.c                          |     353 +++++++++++++++++++++++++++++++
       
       3 files changed, 364 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/README b/README
       @@ -0,0 +1,2 @@
       +Simple tool to draw ascii box plots from the terminal.
       +No need to use 1 million line of javascript code on a browser.
 (DIR) diff --git a/TODO b/TODO
       @@ -0,0 +1,9 @@
       ++ optimize redraws (i.e., avoid to redraw if possible)
       +- change cursor shape according to action
       ++ implement box
       +- implement arrow
       +- set different box styles
       ++ add status bar
       +- get screen geometry
       +- allow scrolling (both vertical and horizontal)
       + 
 (DIR) diff --git a/gramscii.c b/gramscii.c
       @@ -0,0 +1,353 @@
       +/*
       +*
       +* This is `gramscii`, a simple tool to create ascii box graphs
       +*
       +*/
       +
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <termios.h>
       +#include <unistd.h>
       +#include <signal.h>
       +#include <string.h>
       +
       +#define MOVE   0x00
       +#define BOX    0x01
       +#define ARROW  0x02
       +#define TEXT   0x04
       +
       +
       +#define DIR_R  0x01
       +#define DIR_U  0x02
       +#define DIR_D  0x04
       +#define DIR_L  0x08
       +
       +
       +#define WIDTH  100
       +#define HEIGHT  25
       +
       +#define BG        ' '
       +#define PTR       '+'
       +#define UND       '_'
       +#define LINE_H    '-'
       +#define LINE_V    '|'
       +#define DBLINE_H  '='
       +#define DBLINE_V  'u'
       +#define BLDLINE   '#'
       +#define ARR_L     '<'
       +#define ARR_R     '>'
       +#define ARR_U     '^'
       +#define ARR_D     'v'
       +
       +
       +#define MIN(x,y)  (x) < (y) ? (x) : (y)
       +#define MAX(x,y)  (x) > (y) ? (x) : (y)
       +
       +char screen[HEIGHT][WIDTH+1];
       +
       +int state;
       +int dir;
       +int x;
       +int y;
       +int step;
       +char cursor;
       +char corner;
       +char box_line_h;
       +char box_line_v;
       +char arrow_line_h;
       +char arrow_line_v;
       +
       +struct termios t1, t2;
       +
       +
       +void cleanup(int s){
       +
       +        printf("\033[;H\033[2J");
       +        tcsetattr(0, TCSANOW, &t1);
       +        exit(0);
       +}
       +
       +void show_cursor(){
       +        printf("\033[%d;%df", y+1, x+1);
       +        //putchar(screen[y][x]);
       +        //printf("\033[%d;%df", y+1, x+2);
       +}
       +
       +void set(char c){
       +        screen[y][x] = c;
       +}
       +
       +void set_xy(int x, int y, char c){
       +        /* FIXME: check if x and y are valid!!!! */
       +        screen[y][x] = c;
       +}
       +
       +void draw_xy(int x, int y, char c){
       +        /* FIXME: check if x and y are valid!!!! */
       +        printf("\033[%d;%df",y+1,x+1);
       +        putchar(c);        
       +}
       +
       +void clear(){
       +        screen[y][x] = BG;
       +}
       +
       +void init_screen(){
       +        int i;
       +        for(i=0; i<HEIGHT; i++){
       +                memset(screen[i], ' ', WIDTH);
       +                screen[i][WIDTH]='\0';
       +        }
       +        cursor = PTR;
       +        corner = PTR;
       +        box_line_h = LINE_H;
       +        box_line_v = LINE_V;
       +        arrow_line_h = LINE_H;        
       +        arrow_line_v = LINE_V;        
       +}
       +
       +char* state_str(){
       +        switch(state){
       +                case MOVE:
       +                        return "mv ";
       +                case TEXT:
       +                        return "txt";
       +                case BOX:
       +                        return "box";
       +                case ARROW:
       +                        return "arr";
       +        }
       +}
       +
       +
       +void status_bar(){
       +        
       +        printf("\033[%d;1f\033[7m", HEIGHT+1);
       +        printf(" x: %d y: %d -- mode: %s", x, y, state_str());
       +        printf("\033[0m");
       +}
       +
       +int redraw(){
       +        int i;
       +        
       +        printf("\033[2J\033[1;1H");
       +        for (i=0;i<HEIGHT;i++){
       +                fprintf(stdout,"%s\n",screen[i]);
       +        }
       +        status_bar();
       +        show_cursor();
       +        step = 1;
       +}
       +
       +void update_current(){
       +        printf("\033[%d'%df",y+1,x+1);
       +        putchar(screen[y][x]);
       +}
       +
       +
       +void init(){
       +
       +        signal(SIGHUP, cleanup);
       +        signal(SIGINT, cleanup);
       +        signal(SIGTERM, cleanup);
       +        signal(SIGQUIT, cleanup);
       +        
       +        tcgetattr(0, &t1);
       +        t2 = t1;
       +        t2.c_lflag &= ~(ICANON | ECHO);
       +        tcsetattr(0, TCSANOW, &t2);
       +        
       +        init_screen();
       +        x = WIDTH/2;
       +        y = HEIGHT/2;
       +        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; 
       +}
       +
       +
       +void get_text(){
       +        char c;
       +        int orig_x = x, orig_y = y;
       +        
       +        //cursor = UND;
       +        redraw();
       +        while((c=getchar())!=EOF && c != 27){
       +                if(c=='\n'){
       +                        set(BG);
       +                        y += 1;
       +                        x = orig_x;
       +                }
       +                else {
       +                        set(c);
       +                        update_current();
       +                        x += 1;
       +                        if (x >= WIDTH)
       +                                x = orig_x;
       +                }
       +                check_bound();
       +                status_bar();
       +                show_cursor();
       +        }
       +        cursor = PTR;
       +        state=MOVE;
       +}
       +
       +
       +void fix_box(int x1, int y1){
       +
       +        int xmin, ymin, xmax, ymax;
       +        int i;
       +        
       +        xmin = MIN(x, x1);
       +        xmax = MAX(x, x1);
       +        ymin = MIN(y, y1);
       +        ymax = MAX(y, y1);
       +
       +        
       +        for(i=xmin+1; i<=xmax; i++){
       +                set_xy(i, ymin, box_line_h);
       +                set_xy(i, ymax, box_line_h);
       +        }
       +        for(i=ymin+1; i<=ymax; i++){
       +                set_xy(xmin, i, box_line_v);
       +                set_xy(xmax, i, box_line_v);
       +        }
       +        set_xy(xmin, ymin, corner);
       +        set_xy(xmin, ymax, corner);
       +        set_xy(xmax, ymin, corner);
       +        set_xy(xmax, ymax, corner);
       +}
       +
       +void draw_box(int x1, int y1){
       +
       +        int xmin, ymin, xmax, ymax;
       +        int i;
       +        
       +        xmin = MIN(x, x1);
       +        xmax = MAX(x, x1);
       +        ymin = MIN(y, y1);
       +        ymax = MAX(y, y1);
       +
       +        
       +        for(i=xmin+1; i<=xmax; i++){
       +                draw_xy(i, ymin, box_line_h);
       +                draw_xy(i, ymax, box_line_h);
       +        }
       +        for(i=ymin+1; i<=ymax; i++){
       +                draw_xy(xmin, i, box_line_v);
       +                draw_xy(xmax, i, box_line_v);
       +        }
       +        draw_xy(xmin, ymin, corner);
       +        draw_xy(xmin, ymax, corner);
       +        draw_xy(xmax, ymin, corner);
       +        draw_xy(xmax, ymax, corner);
       +        show_cursor();
       +}
       +
       +
       +void get_box(){
       +        char c;
       +        int orig_x=x, orig_y=y;
       +
       +        set(PTR);
       +        redraw();
       +        while((c=getchar())!=EOF && c != 27){
       +                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;         
       +                }
       +                check_bound();
       +                redraw();
       +                draw_box(orig_x, orig_y);
       +                status_bar();
       +                show_cursor();
       +        }
       +        fix_box(orig_x, orig_y);
       +        redraw();
       +}
       +
       +
       +int 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;
       +                        case 'i':
       +                                state = TEXT;
       +                                get_text();
       +                                break;
       +                        case 'r':
       +                                redraw();
       +                                break;
       +                        case 'b':
       +                                get_box();
       +                                break;
       +                        case 'Q':
       +                        case 'q':
       +                                cleanup(0);
       +                                exit(0);
       +                                break;
       +                        default:;
       +                                //statu("got: %d\n", c);
       +                }
       +                check_bound();
       +                //update();
       +                //redraw();
       +                status_bar();
       +                show_cursor();
       +                step = 1;
       +        }
       +
       +}
       +
       +
       +
       +
       +int main(int argc, char *argv[]){
       +
       +        init();
       +
       +        commands();
       +        cleanup(0);
       +}