Browse code

implement selections and wordstar-style cut/copy/move of selection

Dario Rodriguez authored on 22/11/2020 23:17:44
Showing 1 changed files
... ...
@@ -28,7 +28,8 @@
28 28
 #define IDLETIMEOUTSECONDS 10
29 29
 
30 30
 #define COMMANDBUFSIZE 1024
31
-#define DEFAULTFONTHEIGHT 16
31
+#define DEFAULTFONTHEIGHT 14
32
+#define SELECTBUFBLOCK 16384
32 33
 
33 34
 #define COMMAND_WARNING "(!)"
34 35
 #define COMMAND_GOTOLINE "Go to line:"
... ...
@@ -63,6 +64,12 @@ typedef struct re_t {
63 64
         int headerdirty;
64 65
         int contentsdirty;
65 66
         int command_first_key;
67
+        int selactive;
68
+        int sellinefrom,sellineto;
69
+        int selcolfrom,selcolto;
70
+        long sizeselectbuf;
71
+        long usedselectbuf;
72
+        char *selectbuf;
66 73
         char *command;
67 74
         char commandbuf[COMMANDBUFSIZE];
68 75
         char cachelastsearch[COMMANDBUFSIZE];
... ...
@@ -94,13 +101,19 @@ int re_processcommand(re_t *re);
94 101
 int re_moveupdown(re_t *re, int totalinc);
95 102
 int re_moveleftright(re_t *re, int totalinc);
96 103
 int re_changefontsize(re_t *re, int direction);
104
+int re_sel_setstart(re_t *re, int line, int col);
105
+int re_sel_setend(re_t *re, int line, int col);
106
+int re_sel_toggle(re_t *re);
107
+int re_sel_lincolisinside(re_t *re, int line, int col);
108
+int re_sel_lincolisbefore(re_t *re, int line, int col);
109
+int re_sel_lincolisafter(re_t *re, int line, int col);
110
+int re_selectbuf_fill(re_t *re,long frompos,long size, int nadditionalspaces);
97 111
 int re_rtrim(re_t *re, long curpos, int *trimmed);
98 112
 long re_getmatchingbracket(re_t *re,long posini, char originalchar, char *matchingchar);
99 113
 int re_drawheader_editing(re_t *re);
100 114
 int re_drawheader_command(re_t *re);
101 115
 int re_drawcontents(re_t *re);
102 116
 
103
-
104 117
 int
105 118
 main(int argc, char *argv[])
106 119
 {
... ...
@@ -340,6 +353,8 @@ re_free(re_t *re)
340 353
                 reui_free(re->ui),re->ui=NULL;
341 354
         if(re->data!=NULL)
342 355
                 redata_free(re->data),re->data=NULL;
356
+        if(re->selectbuf!=NULL)
357
+                free(re->selectbuf),re->selectbuf=NULL,re->usedselectbuf=re->sizeselectbuf=NULL;
343 358
         free(re),re=NULL;
344 359
         return;
345 360
 }
... ...
@@ -531,9 +546,32 @@ fprintf(stderr,"SDL_TEXTEDITING: composition:\"%s\" start:%i len:%i\n",event->ed
531 546
 fprintf(stderr,"SDL_KEYDOWN: sym:%i\n",event->key.keysym.sym);
532 547
 #endif
533 548
         if(event->key.keysym.sym==SDLK_DOWN || event->key.keysym.sym==SDLK_UP) {
534
-                re_moveupdown(re,(event->key.keysym.sym==SDLK_UP)?-1:1);
549
+#warning #error BUG: Played with selections a bit, resized font twice, go down a lot of lines, when after about last line previously displayed it segfaulted
550
+                int oldcol=re->curline,oldline=re->curcol;
551
+                if(re_moveupdown(re,(event->key.keysym.sym==SDLK_UP)?-1:1)==0 && (SDL_GetModState()&KMOD_SHIFT)!=0 && (re->curcol!=oldcol || re->curline!=oldline)) {
552
+                        if(event->key.keysym.sym==SDLK_UP) {
553
+                                if(re->selactive==0 || re_sel_lincolisafter(re,oldcol,oldline))
554
+                                        re_sel_setend(re,oldcol,oldline);
555
+                                re_sel_setstart(re,re->curline,re->curcol);
556
+                        } else {
557
+                                if(re->selactive==0 || re_sel_lincolisbefore(re,oldcol,oldline))
558
+                                        re_sel_setstart(re,oldcol,oldline);
559
+                                re_sel_setend(re,re->curline,re->curcol);
560
+                        }
561
+                }
535 562
         } else if(event->key.keysym.sym==SDLK_LEFT || event->key.keysym.sym==SDLK_RIGHT) {
536
-                re_moveleftright(re,(event->key.keysym.sym==SDLK_LEFT)?-1:1);
563
+                int oldcol=re->curline,oldline=re->curcol;
564
+                if(re_moveleftright(re,(event->key.keysym.sym==SDLK_LEFT)?-1:1)==0 && (SDL_GetModState()&KMOD_SHIFT)!=0 && (re->curcol!=oldcol || re->curline!=oldline)) {
565
+                        if(event->key.keysym.sym==SDLK_LEFT) {
566
+                                if(re->selactive==0 || re_sel_lincolisafter(re,oldcol,oldline))
567
+                                        re_sel_setend(re,oldcol,oldline);
568
+                                re_sel_setstart(re,re->curline,re->curcol);
569
+                        } else {
570
+                                if(re->selactive==0 || re_sel_lincolisbefore(re,oldcol,oldline))
571
+                                        re_sel_setstart(re,oldcol,oldline);
572
+                                re_sel_setend(re,re->curline,re->curcol);
573
+                        }
574
+                }
537 575
         } else if((SDL_GetModState()&KMOD_CTRL)!=0 && (event->key.keysym.sym==SDLK_PAGEDOWN || event->key.keysym.sym==SDLK_PAGEUP)) {
538 576
                 re->cursorpos=(event->key.keysym.sym==SDLK_PAGEDOWN)?(redata_getused(re->data)-1):0;
539 577
                 re->cursorpos=(re->cursorpos<0)?0:re->cursorpos;
... ...
@@ -688,6 +726,87 @@ re_processkey_commandwait(re_t *re, SDL_Event *event)
688 726
                 re->command=COMMAND_EXIT;
689 727
                 re->commandbuf[0]='\0';
690 728
                 re->headerdirty=1;
729
+        } else if(re->command_first_key=='k' && event->key.keysym.sym==SDLK_h) {
730
+#warning #error TODO: IF Ctrl+C, get a buffer of the right size into re (re->selectbuf), use redata_extract() to get those bytes into the buffer
731
+#warning #error TODO: IF Ctrl+X, do as in Ctrl+X, but delete the bytes from redata afterwards
732
+#warning #error TODO: IF Ctrl+V, insert the bytes in re->selectbuf into the curent cursor pos
733
+                re_sel_toggle(re);
734
+                re->command=NULL;
735
+                re->headerdirty=1;
736
+        } else if(re->command_first_key=='k' && event->key.keysym.sym==SDLK_b) {
737
+                re_sel_setstart(re,re->curline,re->curcol);
738
+                re->command=NULL;
739
+                re->headerdirty=1;
740
+        } else if(re->command_first_key=='k' && event->key.keysym.sym==SDLK_k) {
741
+                re_sel_setend(re,re->curline,re->curcol);
742
+                re->command=NULL;
743
+                re->headerdirty=1;
744
+        } else if(re->command_first_key=='k' && event->key.keysym.sym==SDLK_y) {
745
+                long frompos,topos,coldone;
746
+                /* wordstar-style blockdel (ctrl+k+y) */
747
+                if(re->selactive
748
+                  && redata_linecol2pos(re->data,re->sellinefrom,re->selcolfrom,&frompos,NULL)==0
749
+                  && redata_linecol2pos(re->data,re->sellineto,re->selcolto,&topos,&coldone)==0) {
750
+                        re_selectbuf_fill(re,frompos,topos-frompos,re->selcolto-coldone);
751
+                        redata_undo_groupinit(re->data,NULL);
752
+                        redata_op_del(re->data,frompos,topos-frompos,NULL);
753
+                        redata_undo_groupcommit(re->data,NULL);
754
+                        if(re->cursorpos>frompos) {
755
+                                re->cursorpos=frompos;
756
+                                redata_pos2linecol(re->data,re->cursorpos,&(re->curline),&(re->curcol));
757
+                                re_fixorigin(re);
758
+                        }
759
+                        re->headerdirty=1;
760
+                        re->contentsdirty=1;
761
+                }
762
+                if(re->selactive)
763
+                        re_sel_toggle(re);
764
+                re->command=NULL;
765
+                re->headerdirty=1;
766
+        } else if(re->command_first_key=='k' && (event->key.keysym.sym==SDLK_c || event->key.keysym.sym==SDLK_v)) {
767
+                long frompos,topos,insertpos;
768
+                int tocoldone,coldone;
769
+                /* wordstar-style blockcopy (ctrl+k+c) or move (ctrl+k+v)*/
770
+                int is_move=(event->key.keysym.sym==SDLK_v)?1:0;
771
+                if(re->selactive
772
+                  && redata_linecol2pos(re->data,re->sellinefrom,re->selcolfrom,&frompos,NULL)==0
773
+                  && redata_linecol2pos(re->data,re->sellineto,re->selcolto,&topos,&tocoldone)==0
774
+                  && redata_linecol2pos(re->data,re->curline,re->curcol,&insertpos,&coldone)==0
775
+                  && re_selectbuf_fill(re,frompos,topos-frompos,re->selcolto-tocoldone)==0
776
+                  && redata_preallocate(re->data,redata_getused(re->data)+(re->curcol-coldone)+(is_move?0:re->usedselectbuf))==0) {
777
+                        if(is_move && insertpos>=frompos && insertpos<topos) {
778
+                                re->curline=re->sellinefrom;
779
+                                re->curcol=re->selcolfrom;
780
+                                redata_linecol2pos(re->data,re->curline,re->curcol,&insertpos,&coldone);
781
+                        }
782
+                        redata_undo_groupinit(re->data,NULL);
783
+                        if(coldone<re->curcol
784
+                          && redata_op_addn(re->data,insertpos,' ',re->curcol-coldone,NULL)==0) {
785
+                                insertpos+=re->curcol-coldone;
786
+                        }
787
+                        if(is_move) {
788
+                                redata_op_del(re->data,frompos,re->usedselectbuf,NULL);
789
+                                redata_op_add(re->data,insertpos-((insertpos>frompos)?re->usedselectbuf:0),re->selectbuf,re->usedselectbuf,NULL);
790
+                                re->cursorpos=insertpos-((insertpos>frompos)?re->usedselectbuf:0)+re->usedselectbuf;
791
+                                redata_pos2linecol(re->data,re->cursorpos,&(re->curline),&(re->curcol));
792
+                                redata_pos2linecol(re->data,re->cursorpos-re->usedselectbuf,&(re->sellinefrom),&(re->selcolfrom));
793
+                                re->sellineto=re->curline;
794
+                                re->selcolto=re->curcol;
795
+                        } else {
796
+                                redata_op_add(re->data,insertpos,re->selectbuf,re->usedselectbuf,NULL);
797
+                                re->cursorpos=insertpos+re->usedselectbuf;
798
+                                redata_pos2linecol(re->data,re->cursorpos,&(re->curline),&(re->curcol));
799
+                                redata_pos2linecol(re->data,insertpos,&(re->sellinefrom),&(re->selcolfrom));
800
+                                re->sellineto=re->curline;
801
+                                re->selcolto=re->curcol;
802
+                        }
803
+                        redata_undo_groupcommit(re->data,NULL);
804
+                        re_fixorigin(re);
805
+                        re->headerdirty=1;
806
+                        re->contentsdirty=1;
807
+                }
808
+                re->command=NULL;
809
+                re->headerdirty=1;
691 810
         } else {
692 811
                 re->command=NULL;
693 812
                 re->headerdirty=1;
... ...
@@ -968,6 +1087,130 @@ re_changefontsize(re_t *re, int direction)
968 1087
         return(0);
969 1088
 }
970 1089
 
1090
+int
1091
+re_sel_setstart(re_t *re, int line, int col)
1092
+{
1093
+        if(re==NULL || line<0 || col<0)
1094
+                return(-1);
1095
+        re->sellinefrom=line;
1096
+        re->selcolfrom=col;
1097
+        if(re->selactive==0
1098
+          || (re->sellineto<re->sellinefrom)
1099
+          || (re->sellineto==re->sellinefrom && re->selcolto<re->selcolfrom)) {
1100
+              re->sellineto=re->sellinefrom;
1101
+              re->selcolto=re->selcolfrom;
1102
+        }
1103
+        re->selactive=1;
1104
+        re->contentsdirty=1;
1105
+        return(0);
1106
+}
1107
+
1108
+int
1109
+re_sel_setend(re_t *re, int line, int col)
1110
+{
1111
+        if(re==NULL || line<0 || col<0)
1112
+                return(-1);
1113
+        re->sellineto=line;
1114
+        re->selcolto=col;
1115
+        if(re->selactive==0
1116
+          || (re->sellineto<re->sellinefrom)
1117
+          || (re->sellineto==re->sellinefrom && re->selcolto<re->selcolfrom)) {
1118
+              re->sellinefrom=re->sellineto;
1119
+              re->selcolfrom=re->selcolto;
1120
+        }
1121
+        re->selactive=1;
1122
+        re->contentsdirty=1;
1123
+        return(0);
1124
+}
1125
+
1126
+int
1127
+re_sel_toggle(re_t *re)
1128
+{
1129
+        if(re==NULL)
1130
+                return(-1);
1131
+        re->selactive=1-re->selactive;
1132
+        re->contentsdirty=1;
1133
+        return(0);
1134
+}
1135
+
1136
+int
1137
+re_sel_lincolisinside(re_t *re, int line, int col)
1138
+{
1139
+        if(re==NULL || line<0 || col<0)
1140
+                return(0);
1141
+        if(line==re->sellinefrom && line==re->sellineto) {
1142
+                if(col>=re->selcolfrom && col<re->selcolto)
1143
+                        return(1);
1144
+                return(0);
1145
+        } else if(line==re->sellinefrom) {
1146
+                if(col>=re->selcolfrom)
1147
+                        return(1);
1148
+                return(0);
1149
+        } else if(line>re->sellinefrom && line<re->sellineto) {
1150
+                return(1);
1151
+        } else if(line==re->sellineto) {
1152
+                if(col<re->selcolto)
1153
+                        return(1);
1154
+                return(0);
1155
+        }
1156
+        return(0);
1157
+}
1158
+
1159
+int
1160
+re_sel_lincolisbefore(re_t *re, int line, int col)
1161
+{
1162
+        if(re==NULL || line<0 || col<0)
1163
+                return(0);
1164
+        if(line<re->sellinefrom || (line==re->sellinefrom && col<re->selcolfrom))
1165
+                return(1);
1166
+        return(0);
1167
+}
1168
+
1169
+int
1170
+re_sel_lincolisafter(re_t *re, int line, int col)
1171
+{
1172
+        if(re==NULL || line<0 || col<0)
1173
+                return(0);
1174
+        if(line>re->sellineto || (line==re->sellineto && col>=re->selcolto))
1175
+                return(1);
1176
+        return(0);
1177
+}
1178
+
1179
+int
1180
+re_selectbuf_fill(re_t *re,long frompos,long size, int nadditionalspaces)
1181
+{
1182
+        int nchunk,off,avail;
1183
+        long n;
1184
+        if(re==NULL || size<0 || nadditionalspaces<0 || (frompos+size)>redata_getused(re->data) || redata_getposptr(re->data,frompos,&nchunk,&off)!=0)
1185
+                return(-1); /* sanity check failed */
1186
+        re->usedselectbuf=0;
1187
+        if((size+nadditionalspaces)>re->sizeselectbuf) {
1188
+                long newsize;
1189
+                char *newptr;
1190
+                newsize=(size+nadditionalspaces+SELECTBUFBLOCK-1)/SELECTBUFBLOCK;
1191
+                newsize*=SELECTBUFBLOCK;
1192
+                if((newptr=realloc(re->selectbuf,newsize))==NULL)
1193
+                        return(-1);
1194
+                re->selectbuf=newptr;
1195
+                re->sizeselectbuf=newsize;
1196
+        }
1197
+        for(n=0;n<size && nchunk<re->data->sizechunks;nchunk++,off=0) {
1198
+                avail=re->data->chunks[nchunk]->useddata-off;
1199
+                if(avail<=0)
1200
+                        continue;
1201
+                if(avail>(size-n))
1202
+                        avail=size-n;
1203
+                memcpy(re->selectbuf+n,re->data->chunks[nchunk]->data+off,avail);
1204
+                n+=avail;
1205
+        }
1206
+        re->usedselectbuf=n;
1207
+        if(nadditionalspaces>0) {
1208
+                memset(re->selectbuf+re->usedselectbuf,' ',nadditionalspaces);
1209
+                re->usedselectbuf+=nadditionalspaces;
1210
+        }
1211
+        return(0);
1212
+}
1213
+
971 1214
 
972 1215
 int
973 1216
 re_rtrim(re_t *re, long curpos, int *trimmed)
... ...
@@ -1124,7 +1367,7 @@ re_drawcontents(re_t *re)
1124 1367
         long pos,newpos;
1125 1368
         char *ptr;
1126 1369
         int len;
1127
-        int y,row;
1370
+        int y,row,tmprow;
1128 1371
         char *curptr;
1129 1372
         int curptrlen;
1130 1373
         int has_nl;
... ...
@@ -1141,9 +1384,17 @@ re_drawcontents(re_t *re)
1141 1384
         char matchingchar;
1142 1385
         int mline,mcol;
1143 1386
         const char *hint;
1387
+        const char selcolornormal[]={"\xde\xcf\x7f\xff"};
1388
+        const char selcolorcurline[]={"\xf0\xea\xc9\xff"};
1144 1389
         if(re==NULL)
1145 1390
                 return(-1);
1391
+#if 0
1392
+fprintf(stderr,"re_drawcontents: pre  reuifill1\n");
1393
+#endif
1146 1394
         reui_fill(re->ui,re->x,re->y,re->w,re->h,"\xdf\xdf\xdf\xff");
1395
+#if 0
1396
+fprintf(stderr,"re_drawcontents: post reuifill1\n");
1397
+#endif
1147 1398
         row=re->curline-re->originline;
1148 1399
         pos=re->cursorpos;
1149 1400
         while(row>0 && pos>0) {
... ...
@@ -1154,7 +1405,50 @@ re_drawcontents(re_t *re)
1154 1405
                         row--;
1155 1406
         }
1156 1407
         /* highlight current line */
1408
+#if 0
1409
+fprintf(stderr,"re_drawcontents: pre  reuifill2\n");
1410
+#endif
1157 1411
         reui_fill(re->ui,re->x,re->y+(re->curline-re->originline)*re->ui->fontheight,re->w,re->ui->fontheight+1,"\xef\xef\xef\xff");
1412
+#if 0
1413
+fprintf(stderr,"re_drawcontents: post reuifill2\n");
1414
+#endif
1415
+        /* highlight the selection */
1416
+        if(re->selactive) {
1417
+                const char *selcolor;
1418
+                tmprow=row;
1419
+#if 0
1420
+fprintf(stderr,"re_drawcontents: reuifill3: ");
1421
+#endif
1422
+                for(y=re->y;y<(re->y+re->h);y+=re->ui->fontheight,row++) {
1423
+                        selcolor=(row==(re->curline-re->originline))?selcolorcurline:selcolornormal;
1424
+                        if((re->originline+row)==re->sellinefrom && (re->originline+row)==re->sellineto) {
1425
+                                reui_fill(re->ui,re->x+(re->selcolfrom-re->origincol)*re->ui->fontwidth,re->y+row*re->ui->fontheight,(re->selcolto-re->selcolfrom)*re->ui->fontwidth,re->ui->fontheight+1,selcolor);
1426
+                        } else if((re->originline+row)==re->sellinefrom) {
1427
+                                int x1;
1428
+                                x1=re->x+(re->selcolfrom-re->origincol)*re->ui->fontwidth;
1429
+                                if(x1<(re->x+re->w))
1430
+                                        reui_fill(re->ui,x1,re->y+row*re->ui->fontheight,re->w-x1,re->ui->fontheight+1,selcolor);
1431
+                        } else if((re->originline+row)>re->sellinefrom && (re->originline+row)<re->sellineto) {
1432
+#if 0
1433
+fprintf(stderr,"{(ui,%i,%i,%i,%i,#%02X%02X%02X%02X)",re->x,re->y+row*re->ui->fontheight,re->w,re->ui->fontheight+1,((unsigned char *)selcolor)[0],((unsigned char *)selcolor)[1],((unsigned char *)selcolor)[2],((unsigned char *)selcolor)[3]);
1434
+#endif
1435
+                                reui_fill(re->ui,re->x,re->y+row*re->ui->fontheight,re->w,re->ui->fontheight+1,selcolor);
1436
+#if 0
1437
+fprintf(stderr,"}");
1438
+#endif
1439
+                        } else if((re->originline+row)==re->sellineto) {
1440
+                                int x2;
1441
+                                x2=re->x+(re->selcolto-re->origincol)*re->ui->fontwidth;
1442
+                                if(x2>(re->x))
1443
+                                        reui_fill(re->ui,re->x,re->y+row*re->ui->fontheight,x2-re->x,re->ui->fontheight+1,selcolor);
1444
+                        }
1445
+
1446
+                }
1447
+                row=tmprow;
1448
+#if 0
1449
+fprintf(stderr,"\n");
1450
+#endif
1451
+        }
1158 1452
         /* draw the lines */
1159 1453
         drawn_cursor=0;
1160 1454
         colors=redata_highlighter_getcolors(re->data,&ncolors);
... ...
@@ -1164,7 +1458,7 @@ re_drawcontents(re_t *re)
1164 1458
                 /* definition of vars for tracking linecolor usage */
1165 1459
                 int curlinecolor; /* current linecolor */
1166 1460
                 int usedlenlinecolor; /* number of bytes of current linecolor already drawn */
1167
-                /* end of deifinitions */
1461
+                /* end of definitions */
1168 1462
                 if(redata_line_realstart(re->data,pos,&realstart)==-1 || redata_line_realend(re->data,pos,&realend)==-1) {
1169 1463
                         break; /* couldn't get real start/end */
1170 1464
                 }