first step towards crop + some fixes to erase - gramscii - A simple editor for ASCII box-and-arrow charts
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit b38ed132a7df231fc08ce384d8559e6648fdd0cc
 (DIR) parent f678684b470f02d9fed4818eb92c2a925380c428
 (HTM) Author: KatolaZ <katolaz@freaknet.org>
       Date:   Sat, 27 Jul 2019 08:06:27 +0100
       
       first step towards crop + some fixes to erase
       
       Diffstat:
         M TODO                                |       3 ++-
         M files.c                             |       2 +-
         M gramscii.h                          |       5 +++--
         M main.c                              |       3 +++
         M screen.c                            |     138 ++++++++++++++++++++++---------
       
       5 files changed, 110 insertions(+), 41 deletions(-)
       ---
 (DIR) diff --git a/TODO b/TODO
       @@ -1,4 +1,6 @@
        + optimize redraws (redraw only the modified rectangle)
       ++ add crop command (C)
       +- fix bug with 'g' commands in arrow mode
        - add screen geometry option (-g 25x80?)
        - read file at point
          - read output of command (!)
       @@ -11,7 +13,6 @@
        + 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
        + visual selection
          - crop-to
 (DIR) diff --git a/files.c b/files.c
       @@ -53,7 +53,7 @@ void load_file(FILE *fc){
                        while((fgets(screen[i].s, WIDTH+2, fin)) != NULL && i<HEIGHT)
                                screen[i++].s[WIDTH-1]='\0';
                        for(;i<HEIGHT; i++){
       -                        erase_line(screen[i].s);
       +                        erase_line(i);
                        }
                        fclose(fin);
                }
 (DIR) diff --git a/gramscii.h b/gramscii.h
       @@ -59,7 +59,7 @@ typedef struct{
        #define progr_x(d) ((d) == DIR_L ? -1 : (d) == DIR_R ? 1 : 0)
        #define progr_y(d) ((d) == DIR_U ? -1 : (d) == DIR_D ? 1 : 0)
        
       -/* #define DEBUG 1 */
       +#define DEBUG 1
        
        /** global variables **/ 
        
       @@ -116,9 +116,10 @@ void get_string(FILE *fc, char *msg, char *s, int sz);
        void erase_box(int x1, int y1, char c);
        int is_yes(char c);
        void init_screen();
       -void erase_line(char *s);
       +void erase_line(int i);
        void erase_screen();
        void go_to(int where);
       +void crop_to_nonblank();
        
        /** drawing-related functions **/
        int change_style(char c);
 (DIR) diff --git a/main.c b/main.c
       @@ -122,6 +122,9 @@ void commands(FILE *fc){
                                                mode = VIS;
                                                visual_box(fc);
                                                break;
       +                                case 'C':
       +                                        crop_to_nonblank();
       +                                        break;
                                        case 'q':
                                                check_modified(fc);/** FALLTHROUGH **/
                                        case 'Q':
 (DIR) diff --git a/screen.c b/screen.c
       @@ -109,39 +109,64 @@ int is_yes(char c){
        
        /*** Screen management ***/
        
       -void show_cursor(){
       -        if (silent)
       -                return;
       -        printf("\033[%d;%df", y+1, x+1);
       -        fflush(stdout);
       +void ensure_line_length(int i, int len){
       +        char *tmp;
       +
       +        if (screen[i].sz < len + 1){
       +                tmp = realloc(screen[i].s, (len+1) * 2 * sizeof(char));
       +                if (!tmp){
       +                        fprintf(stderr, "Unable to allocate string\n");
       +                        exit(1);
       +                }
       +                screen[i].s = tmp;
       +                screen[i].sz = (len + 1) * 2;
       +        }
        }
        
        
       -void set_xy(int _x, int _y, char c){
       +void alloc_line(int i){
       +        char *tmp;
       +
       +        screen[i].sz = WIDTH+1;
       +        tmp = malloc((screen[i].sz) * sizeof(char));
       +        if (tmp == NULL){
       +                fprintf(stderr, "unable to allocate line %d\n", i+1);
       +                exit(1);
       +        }
       +        screen[i].s = tmp;
       +        memset(screen[i].s, BG, screen[i].sz);
       +        screen[i].lst = -1;
       +        screen[i].s[0]='\0';
       +}
       +
       +void ensure_num_lines(int n){
                line_t *tmp;
       -        if (_y >= num_lines){
       -                tmp = realloc(screen, (_y + LONG_STEP)* sizeof(line_t));
       +
       +        if (n > num_lines){
       +                tmp = realloc(screen, (n + LONG_STEP) * sizeof(line_t));
                        if (tmp == NULL){
                                fprintf(stderr, "Unable to allocate memory for more lines");
                                exit(1);
                        }
       -                else while ( num_lines < _y + LONG_STEP){
       -                        screen[num_lines].sz = WIDTH+1;
       -                        screen[num_lines].s = malloc((screen[num_lines].sz) * sizeof(char));
       -                        if (screen[num_lines].s == NULL){
       -                                perror("allocating screen[num_lines].s");
       -                                exit(1);
       -                        }
       -                        memset(screen[num_lines].s, BG, screen[num_lines].sz);
       -                        screen[num_lines].lst = 0;
       -                        screen[num_lines].s[screen[num_lines].lst+1]='\0';
       +                else while ( num_lines < n + LONG_STEP){
       +                        alloc_line(num_lines);
                                num_lines ++;
                        }
                }
       -        if (screen[_y].sz < _x + 2){
       -                screen[_y].sz = (_x +2) * 2;
       -                screen[_y].s = realloc(screen[_y].s, screen[_y].sz * sizeof(char));
       -        }
       +}
       +
       +
       +void show_cursor(){
       +        if (silent)
       +                return;
       +        printf("\033[%d;%df", y+1, x+1);
       +        fflush(stdout);
       +}
       +
       +
       +void set_xy(int _x, int _y, char c){
       +        ensure_num_lines(_y + 1);
       +        ensure_line_length(_y, _x + 1);
                while (screen[_y].lst<_x){
                        screen[_y].lst ++;
                        screen[_y].s[screen[_y].lst] = BG;
       @@ -172,11 +197,9 @@ void update_current(){
                fflush(stdout);
        }
        
       -void erase_line(char *s){
       -        while(*s){
       -                *s = BG;
       -                s++;
       -        }
       +void erase_line(int i){
       +        screen[i].lst = -1;
       +        screen[i].s[0] = '\0';
        }
        
        void erase_box(int x1, int y1, char c){
       @@ -196,7 +219,7 @@ void erase_box(int x1, int y1, char c){
        void erase_screen(){
                int i;
                for(i=0;i<HEIGHT; i++)
       -                erase_line(screen[i].s);
       +                erase_line(i);
        }
        
        void check_bound(){
       @@ -399,15 +422,7 @@ void init_screen(){
                        exit(1);
                }
                for (i=0; i<HEIGHT; i++){
       -                screen[i].sz = WIDTH+1;
       -                screen[i].s = malloc((screen[i].sz) * sizeof(char));
       -                if (screen[i].s == NULL){
       -                        perror("allocating screen[i].s");
       -                        exit(1);
       -                }
       -                memset(screen[i].s, BG, screen[i].sz);
       -                screen[i].lst = 0;
       -                screen[i].s[screen[i].lst+1]='\0';
       +                alloc_line(i);
                }
                hlines_sz= sizeof(hlines) -1;
                vlines_sz= sizeof(vlines) -1;
       @@ -417,3 +432,52 @@ void init_screen(){
                reset_styles();
        }
        
       +void find_nonblank_rect(int *x1, int *y1, int *x2, int *y2){
       +
       +        int i, j;
       +        int first;
       +        *x1= WIDTH; /** FIXME: replace with num_cols **/
       +        *y1 = num_lines;
       +        *x2 = *y2 = 0; 
       +
       +        for (i=0; i<num_lines; i++){
       +                if (screen[i].lst < 0)
       +                        continue;
       +                *y2 = i;
       +                if (i < *y1)
       +                        *y1 = i;
       +                if (screen[i].lst > *x2)
       +                        *x2 = screen[i].lst;
       +                j = 0;
       +                while(j <= screen[i].lst && isblank(first=screen[i].s[j]))
       +                        j++;
       +                if (j < *x1)
       +                        *x1 = j;
       +        }
       +}
       +
       +void crop_to_rect(int x1, int y1, int x2, int y2){
       +        int i;
       +
       +        for (i=0; i<= y2-y1; i ++){
       +                ensure_line_length(i, screen[i+y1].lst);
       +                sprintf(screen[i].s, "%s", screen[i+y1].s + x1);
       +                screen[i].lst = screen[i+y1].lst - x1;
       +        } 
       +        while (i<=y2){
       +                screen[i].lst = -1;
       +                screen[i].s[0]= '\0';
       +                i ++;
       +        }
       +}
       +
       +void crop_to_nonblank(){
       +        int x1, x2, y1, y2;
       +        find_nonblank_rect(&x1, &y1, &x2, &y2);
       +#ifdef DEBUG
       +        fprintf(stderr, "crop rectangle: (%d, %d)-(%d, %d)\n", x1, y1, x2, y2);
       +#endif
       +        crop_to_rect(x1, y1, x2, y2);
       +        redraw();
       +}
       +