Browse code

Implement highlight matching bracket (parens/curly-braces/square-brackets/angle-brackets)

Dario Rodriguez authored on 23/10/2020 22:51:48
Showing 3 changed files
... ...
@@ -69,13 +69,13 @@ redata_highlighter_register(redata_t *redata, redata_plugin_t *slot)
69 69
         if(redata==NULL || slot==NULL)
70 70
                 return(-1);
71 71
         colors=hl_initcolors(&ncolors,
72
-                             color_normal,"\x38\x17\x1e\xff",
72
+                             color_keyword,"\x38\x17\x1e\xff",
73 73
                              color_directive,"\x38\x4b\x00\xff",
74 74
                              color_directivekeyword,"\x63\x7d\x16\xff",
75 75
                              color_directivestring,"\x07\x20\3b\xff",
76 76
                              color_directiveinclude,"\x16\x63\x7d\xff",
77 77
                              color_directiveincludestring,"\x6\x13\x2d\xff",
78
-                             color_keyword,"\x9d\x15\x00\xff",
78
+                             color_normal,"\x9d\x15\x00\xff",
79 79
                              color_string,"\x68\x00\x01\xff",
80 80
                              color_multilinecomment,"\x4f\x40\x57\xff",
81 81
                              color_linecomment,"\xc6\x8c\xa4\xff",
... ...
@@ -155,6 +155,22 @@ redata_highlighter_getline(redata_t *redata, int line, int *nlinecolors)
155 155
         return((linecolor_t *) (hl->buf+hl->lines[line].off));
156 156
 }
157 157
 
158
+int
159
+redata_highlighter_getcolorindex(redata_t *redata, int line, int nthbyte)
160
+{
161
+        int i,n;
162
+        int nlinecolors;
163
+        linecolor_t *linecolors;
164
+        if((linecolors=redata_highlighter_getline(redata,line,&nlinecolors))==NULL)
165
+                return(-1);
166
+        for(i=0,n=0;n<nlinecolors;i+=linecolors[n].len,n++) {
167
+                if(nthbyte<(i+linecolors[n].len))
168
+                        return(linecolors[n].color);
169
+        }
170
+        return(-1);
171
+}
172
+
173
+
158 174
 static int
159 175
 redata_highlighter_add(redata_t *redata, redata_plugin_t *slot, undo_t *undo)
160 176
 {
... ...
@@ -54,4 +54,5 @@ int redata_highlighter_unregister(redata_t *redata, redata_plugin_t *slot,char *
54 54
 
55 55
 hcolor_t *redata_highlighter_getcolors(redata_t *redata, int *ncolors);
56 56
 linecolor_t *redata_highlighter_getline(redata_t *redata, int line, int *nlinecolors);
57
+int redata_highlighter_getcolorindex(redata_t *redata, int line, int nthbyte);
57 58
 
... ...
@@ -31,6 +31,9 @@
31 31
 #define COMMAND_WARNING "(!)"
32 32
 #define COMMAND_GOTOLINE "Go to line:"
33 33
 #define COMMAND_SEARCHFORWARD "Search:"
34
+#define COMMAND_REPLACEWHAT "Search for:"
35
+#define COMMAND_REPLACEWITH "Replace with:"
36
+#define COMMAND_REPLACEHOW "Replace options (Igncase Selected Backwards Entire All Noconfirm):"
34 37
 #define COMMAND_QUESTION "(?)"
35 38
 #define COMMAND_EXIT "Exit"
36 39
 
... ...
@@ -88,6 +91,7 @@ int re_processcommand(re_t *re);
88 91
 int re_moveupdown(re_t *re, int totalinc);
89 92
 int re_moveleftright(re_t *re, int totalinc);
90 93
 int re_rtrim(re_t *re, long curpos, int *trimmed);
94
+long re_getmatchingbracket(re_t *re,long posini, char originalchar, char *matchingchar);
91 95
 int re_drawheader_editing(re_t *re);
92 96
 int re_drawheader_command(re_t *re);
93 97
 int re_drawcontents(re_t *re);
... ...
@@ -661,6 +665,7 @@ re_processkey_commandwait(re_t *re, SDL_Event *event)
661 665
                 strncpy(re->commandbuf,re->cachelastsearch,sizeof(re->commandbuf));
662 666
                 re->commandbuf[sizeof(re->commandbuf)-1]='\0';
663 667
                 re->headerdirty=1;
668
+#warning TODO: Search and replace (control+q+a)
664 669
         } else if(re->command_first_key=='k' && event->key.keysym.sym==SDLK_q) {
665 670
                 re->command=COMMAND_EXIT;
666 671
                 re->commandbuf[0]='\0';
... ...
@@ -938,6 +943,70 @@ re_rtrim(re_t *re, long curpos, int *trimmed)
938 943
         return(0);
939 944
 }
940 945
 
946
+long
947
+re_getmatchingbracket(re_t *re,long posini, char originalchar, char *matchingchar)
948
+{
949
+        char *ori,*dest;
950
+        char *pairs="[]{}<>()";
951
+        int is_backwards;
952
+        int colorindex,newcolor;
953
+        long realstart;
954
+        int line;
955
+        long pos;
956
+        long posnextori,posnextdest;
957
+        long posnext;
958
+        int counter;
959
+        if(re==NULL)
960
+                return(-1); /* sanity check failed */
961
+        if((ori=strchr(pairs,originalchar))==NULL)
962
+                return(-1); /* unknown char */
963
+        is_backwards=(ori-pairs)%2;
964
+        dest=ori+((is_backwards)?-1:1);
965
+        if(redata_pos2linecol(re->data,posini,&line,NULL)==-1
966
+          || redata_line_realstart(re->data,posini,&realstart)==-1) {
967
+                return(-1); /* couldn't get line number or startpos */
968
+        }
969
+        colorindex=redata_highlighter_getcolorindex(re->data,line,posini-realstart);
970
+        pos=posini;
971
+        counter=1;
972
+        while(1) {
973
+                /* get the next pos */
974
+                if(!is_backwards) {
975
+                        posnextori=redata_searchforward(re->data,pos+1,ori,1);
976
+                        posnextdest=redata_searchforward(re->data,pos+1,dest,1);
977
+                        posnext=(posnextori==-1)?posnextdest:(posnextdest==-1)?posnextori:(posnextori<posnextdest)?posnextori:posnextdest;
978
+                } else {
979
+                        posnextori=redata_searchbackwards(re->data,pos-1,ori,1);
980
+                        posnextdest=redata_searchbackwards(re->data,pos-1,dest,1);
981
+                        posnext=(posnextori==-1)?posnextdest:(posnextdest==-1)?posnextori:(posnextori>posnextdest)?posnextori:posnextdest;
982
+                }
983
+                if(posnext==-1)
984
+                        break; /* search ended and couln't get the counter to zero */
985
+                /* check that the color index is ok */
986
+                if(redata_pos2linecol(re->data,posnext,&line,NULL)==-1
987
+                  || redata_line_realstart(re->data,posnext,&realstart)==-1) {
988
+                        return(-1); /* couldn't get line number or startpos */
989
+                }
990
+                newcolor=redata_highlighter_getcolorindex(re->data,line,posnext-realstart);
991
+                if(colorindex!=newcolor) {
992
+                        pos=posnext;
993
+                        continue; /* it doesn't have the same color */
994
+                }
995
+                /* do the math */
996
+                if(posnext==posnextori)
997
+                        counter++;
998
+                if(posnext==posnextdest)
999
+                        counter--;
1000
+                pos=posnext;
1001
+                if(counter==0) {
1002
+                        if(matchingchar!=NULL)
1003
+                                *matchingchar=*dest;
1004
+                        return(posnext); /* found matching bracket */
1005
+                }
1006
+        }
1007
+        return(-1);
1008
+}
1009
+
941 1010
 int
942 1011
 re_drawheader_editing(re_t *re)
943 1012
 {
... ...
@@ -1012,6 +1081,9 @@ re_drawcontents(re_t *re)
1012 1081
         int ncolors;
1013 1082
         linecolor_t *linecolors;
1014 1083
         int nlinecolors;
1084
+        int matchingpos;
1085
+        char matchingchar;
1086
+        int mline,mcol;
1015 1087
         if(re==NULL)
1016 1088
                 return(-1);
1017 1089
         reui_fill(re->ui,re->x,re->y,re->w,re->h,"\xdf\xdf\xdf\xff");
... ...
@@ -1029,8 +1101,10 @@ re_drawcontents(re_t *re)
1029 1101
         /* draw the lines */
1030 1102
         drawn_cursor=0;
1031 1103
         colors=redata_highlighter_getcolors(re->data,&ncolors);
1104
+        matchingpos=-1;
1105
+        matchingchar='\0';
1032 1106
         for(y=re->y;y<(re->y+re->h);y+=re->ui->fontheight,row++) {
1033
-                /* definiciton of vars for teacking linecolor usage */
1107
+                /* definition of vars for tracking linecolor usage */
1034 1108
                 int curlinecolor; /* current linecolor */
1035 1109
                 int usedlenlinecolor; /* number of bytes of current linecolor already drawn */
1036 1110
                 /* end of deifinitions */
... ...
@@ -1072,15 +1146,18 @@ re_drawcontents(re_t *re)
1072 1146
                         }
1073 1147
                         if(row==(re->curline-re->originline)) {
1074 1148
                                 if(re->curcol>=tmpcol && re->curcol<(tmpcol+availcol)) {
1149
+                                        int utf8charlen;
1150
+                                        /* draw cursor */
1075 1151
                                         reui_fill(re->ui,re->x+re->ui->fontwidth*(re->curcol-re->origincol),y,re->ui->fontwidth,re->ui->fontheight+1,"\x00\x00\x00\xff");
1076 1152
                                         drawn_cursor=1;
1077 1153
                                         curptr=redata_generic_utf8col(ptr,len-has_nl,re->curcol-tmpcol);
1078 1154
                                         curptrlen=(curptr==NULL)?0:(len-has_nl)-(curptr-ptr);
1079
-                                        reui_write(re->ui,re->x+re->ui->fontwidth*(re->curcol-re->origincol),y,"\xff\xff\xff\xff",curptr,redata_generic_utf8charlen(curptr,curptrlen));
1155
+                                        utf8charlen=redata_generic_utf8charlen(curptr,curptrlen);
1156
+                                        reui_write(re->ui,re->x+re->ui->fontwidth*(re->curcol-re->origincol),y,"\xff\xff\xff\xff",curptr,utf8charlen);
1157
+                                        /* get matching braces/parens/anglebracket/curlybraces for highlighting */
1158
+                                        if(utf8charlen==1 && strchr("[]{}<>()",*curptr)!=NULL)
1159
+                                                matchingpos=re_getmatchingbracket(re,re->cursorpos,*curptr,&matchingchar);
1080 1160
                                 }
1081
-#warning TODO: if it is one of  '[','{','<','>','}',']', highlight the matching bracket/parens/anglebracket.
1082
-#warning When searching for matching backet/..., count only the ones in the same highlighting color.
1083
-#warning If it is ourside of the visible part of the code, put a comic baloon (with some transparency) in that dir. (up, down or right) at the correct height/position to mark the direction of where it is.
1084 1161
 #warning TODO: Select(control+k+b/control+k+k/...)
1085 1162
                         }
1086 1163
                 }
... ...
@@ -1091,22 +1168,40 @@ re_drawcontents(re_t *re)
1091 1168
                 pos=realend+1;
1092 1169
 /*LONG LINE LEFT FOR DEBUGGING PURPOSES: reui_write(re->ui,re->x+re->ui->fontwidth*(re->curcol-re->origincol),y,"\xff\xff\xff\xff",curptr,redata_generic_utf8charlen(ptr,curptrlen));*/
1093 1170
         }
1094
-        re->contentsdirty=0;
1095
-        re->ui->rendererdirty=1;
1171
+        /* highlight matching parens/brace/... if applicable */
1172
+        if(matchingpos!=-1 && redata_pos2linecol(re->data,matchingpos,&mline,&mcol)!=-1) {
1173
+                int x,y;
1174
+                char *fg="\xff\x00\x00\x80";
1175
+                char *bg="\xff\xff\xff\xaf";
1176
+                x=re->x+(mcol-re->origincol)*re->ui->fontwidth+(re->ui->fontwidth/2);
1177
+                x=(x<re->x)?re->x:(x>=(re->x+re->w))?(re->x+re->w-1):x;
1178
+                y=re->y+(mline-re->originline)*re->ui->fontheight+(re->ui->fontheight/2);
1179
+                y=(y<re->y)?re->y:(y>=(re->y+re->h))?(re->y+re->h-1):y;
1180
+                if(mline<re->originline)
1181
+                        reui_balloon(re->ui, 'n', x, re->y, fg, bg, &matchingchar,1);
1182
+                else if(mline>=(re->originline+re->maxrow))
1183
+                        reui_balloon(re->ui, 's', x, re->y+re->h-1, fg, bg, &matchingchar,1);
1184
+                else if(mcol<re->origincol)
1185
+                        reui_balloon(re->ui, 'w', re->x, y, fg, bg, &matchingchar,1);
1186
+                else if(mcol>=(re->origincol+re->maxcol))
1187
+                        reui_balloon(re->ui, 'e', re->x+re->w-1,y, fg, bg, &matchingchar,1);
1188
+                else
1189
+                        reui_balloon(re->ui, '\0', x,y, fg, bg, &matchingchar,1);
1190
+        }
1191
+        /* display commonprototypes info if applicable */
1096 1192
 #if 1
1193
+#warning TODO: display commonprototypes info if applicable
1097 1194
 {
1098
-char sampletext[]={"Here is the top"};
1099
-char sampletextlarge[]={"void *memcpy(void *dest, const void *src, size_t n)"};
1100
-reui_balloon(re->ui, 'n', re->x+re->w/2, re->y, "\xff\x00\x00\xff", "\x00\x00\xff\x80",sampletext,strlen(sampletext));
1101
-reui_balloon(re->ui, 's', re->x+re->w/2, re->y+re->h-1, "\xff\x00\x00\x80", "\xff\xff\xff\xaf", "}",1);
1102
-reui_balloon(re->ui, 'e', re->x+re->w-1,re->y+re->h/2, "\xff\x00\x00\x80", "\xff\xff\xff\xaf", "[",1);
1103
-reui_balloon(re->ui, 'w', re->x, re->y+re->h/2, "\xff\x00\x00\x80", "\xff\xff\xff\xaf", "]",1);
1104
-if((re->curline-re->originline)>=(re->maxrow/2))
1105
-        reui_balloon(re->ui, '\0', re->x+re->w/2, re->y+re->ui->fontheight*3/2, "\x80\x80\x80\xff", "\xff\xff\xff\xcf",sampletextlarge,strlen(sampletextlarge));
1106
-else
1107
-        reui_balloon(re->ui, '\0', re->x+re->w/2, re->y+re->h-re->ui->fontheight*3/2, "\x80\x80\x80\xff", "\xff\xff\xff\xcf",sampletextlarge,strlen(sampletextlarge));
1195
+                char sampletextlarge[]={"void *memcpy(void *dest, const void *src, size_t n)"};
1196
+                if((re->curline-re->originline)>=(re->maxrow/2))
1197
+                        reui_balloon(re->ui, '\0', re->x+re->w/2, re->y+re->ui->fontheight*3/2, "\x80\x80\x80\xff", "\xff\xff\xff\xcf",sampletextlarge,strlen(sampletextlarge));
1198
+                else
1199
+                        reui_balloon(re->ui, '\0', re->x+re->w/2, re->y+re->h-re->ui->fontheight*3/2, "\x80\x80\x80\xff", "\xff\xff\xff\xcf",sampletextlarge,strlen(sampletextlarge));
1108 1200
 }
1109 1201
 #endif
1202
+        /* all done */
1203
+        re->contentsdirty=0;
1204
+        re->ui->rendererdirty=1;
1110 1205
         return(0);
1111 1206
 }
1112 1207