Browse code

Implement redata_linecol2pos() so that 'Go To Line' can do its thing

Dario Rodriguez authored on 25/09/2020 20:49:13
Showing 3 changed files
... ...
@@ -1679,10 +1679,64 @@ redata_pos2linecol(redata_t *redata, long pos, int *resline, int *rescol)
1679 1679
 int
1680 1680
 redata_linecol2pos(redata_t *redata, int line, int colrequest, long *pos, int *coldone)
1681 1681
 {
1682
-#warning TODO: XXX Implement this function
1683
-#warning TODO: XXX: Add a parameter so this is like reata_line_inccol (colrequest, coldone) --  maybe also linetrequest linedone? (zed doesn''t let you go to the last line doing a Ctrl+q+l to an arbitrarily large number...)
1684
-#warning TODO: XXX: The extra parameters are super-handy because the main user of this function is Control+Q+L "Go To Line" and we want to go to nearest pos
1685
-        return(-1);
1682
+        long chunkpos,realstart,newpos,curpos,startpos;
1683
+        int startline;
1684
+        int nchunk;
1685
+        rechunk_t *chunk;
1686
+        int i,n;
1687
+        char *ptr;
1688
+        int len;
1689
+        int done;
1690
+        if(redata==NULL || line<0 || colrequest<0)
1691
+                return(-1);
1692
+        /* find line */
1693
+        for(nchunk=0,chunkpos=0,startline=0
1694
+          ;nchunk<redata->sizechunks
1695
+          ;chunkpos+=(chunk!=NULL)?chunk->useddata:0
1696
+            ,startline+=(chunk!=NULL)?chunk->whatin.nlcount:0,nchunk++) {
1697
+                if((chunk=redata->chunks[nchunk])==NULL)
1698
+                        continue;
1699
+                if(!(chunk->whatin_fresh))
1700
+                        redata_whatin_refresh(redata,nchunk);
1701
+                if(line>=startline && line<=(startline+chunk->whatin.nlcount))
1702
+                        break;
1703
+        }
1704
+        if(nchunk>=redata->sizechunks)
1705
+                return(-1); /* line not found */
1706
+        for(i=0;line!=startline && i<chunk->useddata;i++) {
1707
+                if(chunk->data[i]=='\n')
1708
+                        startline++;
1709
+        }
1710
+        if(i>chunk->useddata)
1711
+                return(-1); /* line not found */
1712
+        realstart=chunkpos+i;
1713
+        /* find col */
1714
+        for(n=0,curpos=realstart;n<colrequest;) {
1715
+                if(redata_line_rawinfo(redata,curpos,&startpos,&ptr,&len,NULL)==-1 || len==0)
1716
+                        return(-1); /* couldn't get current line data */
1717
+                done=0;
1718
+                for(i=0;colrequest>0 && i<len && n<=colrequest;i++) {
1719
+                        if(redata_generic_utf8isstartbyte(ptr[i])) {
1720
+                                if(n==colrequest) {
1721
+                                        done=1;
1722
+                                        break;
1723
+                                }
1724
+                                n++;
1725
+                        }
1726
+                        if(ptr[i]=='\n') {
1727
+                                done=1;
1728
+                                break;
1729
+                        }
1730
+                }
1731
+                curpos=startpos+i;
1732
+                if(done)
1733
+                        break;
1734
+        }
1735
+        if(coldone!=NULL)
1736
+                *coldone=n;
1737
+        if(pos!=NULL)
1738
+                *pos=curpos;
1739
+        return(0);
1686 1740
 }
1687 1741
 
1688 1742
 static char *
... ...
@@ -148,7 +148,7 @@ int redata_generic_utf8len(char *ptr, int size);
148 148
 char *redata_generic_utf8col(char *ptr, int size, int col);
149 149
 /* returns the len in bytes of the character starting at ptr (zero on error)*/
150 150
 int redata_generic_utf8charlen(char *ptr, int maxsize);
151
-/* returns true if it's the forst byte of an UTF char */
151
+/* returns true if it's the first byte of an UTF char */
152 152
 int redata_generic_utf8isstartbyte(int candidate);
153 153
 
154 154
 
... ...
@@ -487,8 +487,9 @@ re_processcommand(re_t *re)
487 487
         if(strcmp(re->command,COMMAND_GOTOLINE)==0) {
488 488
                 int line;
489 489
                 long pos;
490
-                line=atoi(re->commandbuf);
491
-                if(redata_linecol2pos(re->data,line,0,&pos,NULL)==-1) {
490
+                line=atoi(re->commandbuf)-1;
491
+                line=(line<0)?0:line;
492
+                if(redata_linecol2pos(re->data,line,re->curcol,&pos,NULL)==-1) {
492 493
                         re->command=COMMAND_WARNING;
493 494
                         snprintf(re->commandbuf,sizeof(re->commandbuf),"Unknown line");
494 495
                         re->commandbuf[sizeof(re->commandbuf)-1]='\0';
... ...
@@ -496,13 +497,9 @@ re_processcommand(re_t *re)
496 497
                         return(-1);
497 498
                 }
498 499
                 re->cursorpos=pos;
499
-                re->curcol=0;
500 500
                 re->curline=line;
501
-                re->origincol=0;
502
-                if((re->originline+re->maxrow)<line)
503
-                        re->originline=line-re->maxrow;
504
-                if(line<re->originline)
505
-                        re->originline=line;
501
+                /* position the line in the center of viewport */
502
+                re->originline=line-(re->maxrow/2);
506 503
                 re->headerdirty=1;
507 504
                 re->contentsdirty=1;
508 505
         }
... ...
@@ -669,7 +666,8 @@ re_drawheader_editing(re_t *re)
669 666
         if(redata_pos2linecol(re->data,re->cursorpos,&line,&col)==-1)
670 667
                 line=col=-1;
671 668
         reui_fill(re->ui,0,0,re->ui->w,re->ui->fontheight,COLOR_STATUSBG);
672
-        reui_printf(re->ui,0,0,COLOR_STATUSFG,"File: %s Line:%i (%i) Col:%i (%i) Pos:%li",re->filename,re->curline,line,re->curcol,col,re->cursorpos);
669
+        /* for the user, lines start at 0 (internally they start at 0) */
670
+        reui_printf(re->ui,0,0,COLOR_STATUSFG,"File: %s Line:%i (%i) Col:%i (%i) Pos:%li",re->filename,re->curline+1,line+1,re->curcol+1,col+1,re->cursorpos);
673 671
         re->headerdirty=0;
674 672
         re->ui->rendererdirty=1;
675 673
         return(0);