Browse code

bugfix: was showing strange characters when a multibyte UTF-8 char crossed a chunk boundary; now behaves as expected (multibyte UTF-8 characters crossing a boundary display correctly)

Dario Rodriguez authored on 20/03/2021 01:53:12
Showing 3 changed files
... ...
@@ -29,13 +29,28 @@
29 29
 //#define CHUNKSIZE 4096
30 30
 //#define CHUNKSIZE 1024
31 31
 //#define CHUNKSIZE 160
32
-#define CHUNKSIZE 16
32
+//#define CHUNKSIZE 16
33
+#define CHUNKSIZE 3
34
+#warning XXX: TODO: CHANGE CHUNKSIZE TO A SANE VALUE (not 1!), THIS IS ONLY FOR TESTING UTF-8 multi-byte CHARS
35
+
33 36
 #define UNDOBLOCK 1024
34 37
 #define ADDNBLOCK 1024
35 38
 #define UNDOGROWSIZE (256*1024)
36 39
 #define SECURESAVEPREFIX "."
37 40
 #define SECURESAVEPOSTFIX ".saving"
38 41
 
42
+#define UTF8_IS_ASCII_OR_START(c) (((c)&0xc0)!=0x80)
43
+#define UTF8_IS_ASCII(c) (((c)&0x80)==0)
44
+#define UTF8_IS_MULTIBYTESTART(c) ((((c)&0x80)==0x80)&&(((c)&(0x80|0x40))!=0x80))
45
+#define UTF8_IS_MULTIBYTECONT(c) (((c)&(0x80|0x40))==0x80)
46
+
47
+#define UTF8_MULTIBYTESTART2LEN(c) ((((c)&0xe0)==0xc0)?2: \
48
+                                    (((c)&0xf0)==0xe0)?3: \
49
+                                    (((c)&0xf8)==0xf0)?4: \
50
+                                    (((c)&0xfc)==0xf8)?5: \
51
+                                    (((c)&0xfe)==0xfc)?6: \
52
+                                    1)
53
+
39 54
 static int redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *resbuf129bytes);
40 55
 static char *securesave_genname(char *filename, char *buf, int bufsize);
41 56
 static void *mymemrchr(const void *s, int c, size_t n);
... ...
@@ -1587,6 +1602,50 @@ redata_memcmp(redata_t *redata, long pos, char *str, int len)
1587 1602
 
1588 1603
 }
1589 1604
 
1605
+int
1606
+redata_getutf8char(redata_t *redata, long pos, char *buf, int len, int *usedbuf)
1607
+{
1608
+        int numchunk;
1609
+        int offset;
1610
+        rechunk_t *chunk;
1611
+        int ooff;
1612
+        int req;
1613
+        int c;
1614
+        if(redata==NULL || pos<0 || pos>redata_getsize(redata) || buf==NULL || len<1 || usedbuf==NULL)
1615
+                return(-1); /* sanity check failed */
1616
+        ooff=0;
1617
+        if(redata_getposptr(redata,pos,&numchunk,&offset)!=0)
1618
+                return(-1); /* couldn't get pos */
1619
+        while(numchunk<redata->sizechunks && redata->chunks[numchunk]!=NULL && offset>=redata->chunks[numchunk]->useddata) {
1620
+                numchunk++;
1621
+                offset=0;
1622
+        }
1623
+        if(numchunk>=redata->sizechunks)
1624
+                return(-1); /* at end; no data */
1625
+        chunk=redata->chunks[numchunk];
1626
+        c=chunk->data[offset];
1627
+        ((unsigned char *)buf)[ooff++]=c;
1628
+        if(UTF8_IS_ASCII(c) || UTF8_IS_MULTIBYTECONT(c))
1629
+                req=1;
1630
+        else
1631
+                req=UTF8_MULTIBYTESTART2LEN(c);
1632
+        offset++;
1633
+        for(;ooff<len && ooff<req && numchunk<redata->sizechunks
1634
+            ;numchunk++,chunk=redata->chunks[numchunk],offset=0) {
1635
+                if(offset>=chunk->useddata)
1636
+                        continue;
1637
+                c=0x80|0x40; /* initialize c to whatever multibycont for the check after the while */
1638
+                while(ooff<len && ooff<req
1639
+                  && (c=chunk->data[offset])!=0 && UTF8_IS_MULTIBYTECONT(c)) {
1640
+                        ((unsigned char *)buf)[ooff++]=c;
1641
+                }
1642
+                if(!UTF8_IS_MULTIBYTECONT(c))
1643
+                        break;
1644
+        }
1645
+        *usedbuf=ooff;
1646
+        return(0);
1647
+}
1648
+
1590 1649
 
1591 1650
 int
1592 1651
 redata_generic_utf8len(char *ptr, int size)
... ...
@@ -1606,6 +1665,63 @@ redata_generic_utf8len(char *ptr, int size)
1606 1665
 /*#warning TODO: XXX Also consider tabs*/
1607 1666
 }
1608 1667
 
1668
+int
1669
+redata_generic_utf8lenincomplete(char *ptr, int size, int *nstartincomplete,int *nendincomplete, int *nendrequired)
1670
+{
1671
+        int len,i;
1672
+        int lastistart,lastclen;
1673
+/*#warning TODO: XXX support combining code points (at least U+0300 - U+036F ( https://en.wikipedia.org/wiki/Combining_character ) */
1674
+        if(size<0 || (ptr==NULL && size!=0) || nstartincomplete==NULL || nendincomplete==NULL)
1675
+                return(-1);
1676
+        /* from RFC2279/RFC3629, one character is up to 6 bytes:
1677
+           first    last     Byte1      Byte2      Byte3      Byte4
1678
+           U+0000   U+007F   0xxxxxxx
1679
+           U+0080   U+07FF   110xxxxx   10xxxxxx
1680
+           U+0800   U+FFFF   1110xxxx   10xxxxxx   10xxxxxx
1681
+          U+10000 U+10FFFF   11110xxx   10xxxxxx   10xxxxxx   10xxxxxx
1682
+            ...
1683
+         */   
1684
+        i=0;
1685
+        len=0;
1686
+        /* nstartincomplete */
1687
+        *nstartincomplete=0;
1688
+        while(i<size && (ptr[i]&(0x80|0x40))==0x80) {
1689
+                (*nstartincomplete)++;
1690
+                i++;
1691
+        }
1692
+        /* len */
1693
+        lastistart=-1;
1694
+        lastclen=0;
1695
+        for(;i<size;i++) { 
1696
+                len+=((ptr[i]&0xc0)!=0x80)?1:0;
1697
+                if((ptr[i]&0x80)==0x00) {
1698
+                        /* ASCII */
1699
+                        lastistart=i;
1700
+                        lastclen=1;
1701
+                } else if((ptr[i]&0xc0)!=0x80) {
1702
+                        /* multibytechar start (as ASCII case has already been processed) */
1703
+                        lastistart=i;
1704
+                        lastclen=((ptr[i]&0xe0)==0xc0)?2:
1705
+                                 ((ptr[i]&0xf0)==0xe0)?3:
1706
+                                 ((ptr[i]&0xf8)==0xf0)?4:
1707
+                                 ((ptr[i]&0xfc)==0xf8)?5:
1708
+                                 ((ptr[i]&0xfe)==0xfc)?6:
1709
+                                 1; /* unknown type of multibytechar */
1710
+                }
1711
+        }
1712
+        /* nendincomplete */
1713
+        *nendincomplete=0;
1714
+        *nendrequired=0;
1715
+        if(lastistart!=-1 && (lastistart+lastclen)>size) {
1716
+                *nendrequired=lastclen;
1717
+                *nendincomplete=(lastistart+lastclen-size);
1718
+                len--;
1719
+        }
1720
+        /* all done */
1721
+        return(len);
1722
+/*#warning TODO: XXX Also consider tabs*/
1723
+}
1724
+
1609 1725
 char *
1610 1726
 redata_generic_utf8col(char *ptr, int size, int col)
1611 1727
 {
... ...
@@ -1654,7 +1770,6 @@ redata_generic_utf8isstartbyte(int candidate)
1654 1770
         return(0);
1655 1771
 }
1656 1772
 
1657
-
1658 1773
 static int
1659 1774
 redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char *resbuf129bytes)
1660 1775
 {
... ...
@@ -1933,7 +2048,7 @@ redata_linecol2pos(redata_t *redata, int line, int colrequest, long *pos, int *c
1933 2048
         int i,n;
1934 2049
         char *ptr;
1935 2050
         int len;
1936
-        int done;
2051
+        int done;                       
1937 2052
         if(redata==NULL || line<0 || colrequest<0)
1938 2053
                 return(-1);
1939 2054
         /* find line */
... ...
@@ -1958,21 +2073,18 @@ redata_linecol2pos(redata_t *redata, int line, int colrequest, long *pos, int *c
1958 2073
                 return(-1); /* line not found */
1959 2074
         realstart=chunkpos+i;
1960 2075
         /* find col */
1961
-        for(n=0,curpos=realstart;n<colrequest;) {
2076
+        for(n=-1,curpos=realstart;n<colrequest;) {
1962 2077
                 if(redata_line_rawinfo(redata,curpos,&startpos,&ptr,&len,NULL)==-1 || len==0)
1963 2078
                         return(-1); /* couldn't get current line data */
1964 2079
                 done=0;
1965
-                for(i=0;colrequest>0 && i<len && n<=colrequest;i++) {
1966
-                        if(redata_generic_utf8isstartbyte(ptr[i])) {
1967
-                                if(n==colrequest) {
1968
-                                        done=1;
1969
-                                        break;
1970
-                                }
1971
-                                n++;
1972
-                        }
2080
+                for(i=0;i<len && n<colrequest;i++) {
1973 2081
                         if(ptr[i]=='\n') {
1974 2082
                                 done=1;
1975 2083
                                 break;
2084
+                        } else if(UTF8_IS_ASCII_OR_START(ptr[i])) {                    
2085
+                                n++;
2086
+                                if(n==colrequest)
2087
+                                        break;
1976 2088
                         }
1977 2089
                 }
1978 2090
                 curpos=startpos+i;
... ...
@@ -171,10 +171,17 @@ long redata_searchforward(redata_t *redata, long posini, char *str, int len);
171 171
 long redata_searchbackwards(redata_t *redata, long posini, char *str, int len);
172 172
 int redata_memcmp(redata_t *redata, long pos, char *str, int len);
173 173
 
174
+int redata_getutf8char(redata_t *redata, long pos, char *buf, int len, int *usedbuf);
175
+
174 176
 /* utf8 convenience functions */
175 177
 
176 178
 /* calculate the number of utf8-charaters in buffer */
177 179
 int redata_generic_utf8len(char *ptr, int size);
180
+
181
+/* calculate the number of utf8-charaters in buffer ignoring incomplete multibytechars at start and end */
182
+int redata_generic_utf8lenincomplete(char *ptr, int size, int *nstartincomplete,int *nendincomplete, int *nendrequired
183
+);
184
+
178 185
 /* return a pointer to the "n"th ("col"th) utf8-character in buffer */
179 186
 char *redata_generic_utf8col(char *ptr, int size, int col);
180 187
 /* returns the len in bytes of the character starting at ptr (zero on error)*/
... ...
@@ -1889,31 +1889,24 @@ re_drawcontents(re_t *re, printout_t *printout)
1889 1889
         int curline,curcol;
1890 1890
         int maxcol,maxrow;
1891 1891
         long pos,newpos;
1892
-        char *ptr;
1893
-        int len;
1894 1892
         int y,row,tmprow;
1895
-        char *curptr;
1896
-        int curptrlen;
1897
-        int has_nl;
1893
+        long cursorpos;
1898 1894
         int is_continuation;
1899
-        int tmpcol,availcol;
1900
-        int in_error;
1901
-        long realstart,realend;
1902
-        int drawn_cursor;
1903
-        hcolor_t *colors;
1895
+        printout_t fakeprintout;
1896
+        hcolor_t *colors,fakecolor;
1904 1897
         int ncolors;
1905
-        linecolor_t *linecolors;
1898
+        const char selcolornormal[]={"\xde\xcf\x7f\xff"};
1899
+        const char selcolorcurline[]={"\xf0\xea\xc9\xff"};
1900
+        long realstart,realend;
1901
+        linecolor_t *linecolors,fakelinecolors;
1906 1902
         int nlinecolors;
1903
+        int drawn_cursor;
1907 1904
         int matchingpos;
1908 1905
         char matchingchar;
1909 1906
         int mline,mcol;
1910
-        long cursorpos;
1911
-        printout_t fakeprintout;
1912
-        const char *hint;
1913
-        const char selcolornormal[]={"\xde\xcf\x7f\xff"};
1914
-        const char selcolorcurline[]={"\xf0\xea\xc9\xff"};
1915 1907
         if(re==NULL || (printout!=NULL && (printout->ui==NULL || printout->data==NULL)))
1916 1908
                 return(-1);
1909
+        /* init vars and clear screen */
1917 1910
         ui=re->ui;
1918 1911
         data=re->data;
1919 1912
         x0=re->x;
... ...
@@ -1950,6 +1943,7 @@ re_drawcontents(re_t *re, printout_t *printout)
1950 1943
         reui_fill(ui,x0,y0,w,h,"\xdf\xdf\xdf\xff");
1951 1944
         row=curline-originline;
1952 1945
         pos=cursorpos;
1946
+        /* get position/row/col of character at top left of screen */
1953 1947
         while(row>0 && pos>0) {
1954 1948
                 if(redata_line_rawinfo(data,pos,&newpos,NULL,NULL,&is_continuation)==-1)
1955 1949
                         return(-1);
... ...
@@ -1985,70 +1979,108 @@ re_drawcontents(re_t *re, printout_t *printout)
1985 1979
                                 if(x2>(x0))
1986 1980
                                         reui_fill(ui,x0,y0+row*ui->fontheight,x2-x0,ui->fontheight+1,selcolor);
1987 1981
                         }
1988
-
1989 1982
                 }
1990 1983
                 row=tmprow;
1991 1984
         }
1992 1985
         /* draw the lines */
1986
+        if((colors=redata_highlighter_getcolors(data,&ncolors))==NULL) {
1987
+                colors=&fakecolor;
1988
+                ncolors=1;
1989
+                memcpy(fakecolor.rgba,"\x00\x00\x00\xff",5);
1990
+        }
1993 1991
         drawn_cursor=0;
1994
-        colors=redata_highlighter_getcolors(data,&ncolors);
1995 1992
         matchingpos=-1;
1996 1993
         matchingchar='\0';
1997 1994
         for(y=y0;y<(y0+h);y+=ui->fontheight,row++) {
1995
+                int in_error;
1996
+                int availcol,tmpcol,len;
1997
+                char *lastcolor;
1998 1998
                 /* definition of vars for tracking linecolor usage */
1999 1999
                 int curlinecolor; /* current linecolor */
2000 2000
                 int usedlenlinecolor; /* number of bytes of current linecolor already drawn */
2001
-                /* end of definitions */
2002
-                if(redata_line_realstart(data,pos,&realstart)==-1 || redata_line_realend(data,pos,&realend)==-1) {
2001
+                /* get start/end of line */
2002
+                if(redata_line_realstart(data,pos,&realstart)==-1 || redata_line_realend(data,pos,&realend)==-1)
2003 2003
                         break; /* couldn't get real start/end */
2004
+                /* setup colors */
2005
+                if(colors==(&fakecolor) || (linecolors=redata_highlighter_getline(data,originline+row,&nlinecolors))==NULL) {
2006
+                        linecolors=&fakelinecolors;
2007
+                        fakelinecolors.len=1;
2008
+                        fakelinecolors.color=0;
2004 2009
                 }
2005
-                in_error=0;
2006
-                linecolors=(colors==NULL)?NULL:redata_highlighter_getline(data,originline+row,&nlinecolors);
2007 2010
                 curlinecolor=0;
2008 2011
                 usedlenlinecolor=0;
2012
+                lastcolor="\x00\x00\x00\xff";                      
2013
+                in_error=0;
2014
+                /* draw each part of this line */
2009 2015
                 for(tmpcol=0,pos=realstart,availcol=0;tmpcol<(origincol+maxcol) && pos<=realend;pos=newpos+len,tmpcol+=availcol) {
2016
+                        int has_nl;
2017
+                        char *ptr;
2018
+                        int incompletestart,incompleteend,endreq;
2019
+                        int used,usedcol; /* number of bytes/columns used of redata chunk (those are already drawn) */
2010 2020
                         if(redata_line_rawinfo(data,pos,&newpos,&ptr,&len,&is_continuation)==-1) {
2011 2021
                                 in_error=1;
2012 2022
                                 break; /* couldn't get this line part info */
2013 2023
                         }
2014 2024
                         has_nl=((len>0 && ptr[len-1]=='\n')?1:0);
2015
-                        availcol=redata_generic_utf8len(ptr,len-has_nl);
2016
-#warning TODO: consider tabs
2017
-                        if(linecolors!=NULL) {
2018
-                                int used,usedcol; /* number of bytes/columns used of redata chunk (those are already drawn) */
2019
-                                used=usedcol=0;
2020
-                                /* while the avail text is larger than the linecolor len */
2021
-                                while(curlinecolor<nlinecolors && (len-has_nl-used)>=(linecolors[curlinecolor].len-usedlenlinecolor)) {
2022
-                                        reui_write(ui,x0+(tmpcol-origincol+usedcol)*ui->fontwidth,y,colors[linecolors[curlinecolor].color].rgba,ptr+used,linecolors[curlinecolor].len-usedlenlinecolor);
2023
-                                        usedcol+=redata_generic_utf8len(ptr+used,linecolors[curlinecolor].len-usedlenlinecolor);
2024
-                                        used+=linecolors[curlinecolor].len-usedlenlinecolor;
2025
-                                        curlinecolor++;
2026
-                                        usedlenlinecolor=0;
2027
-                                }
2028
-                                /* for the last bytes of avail text, after writing them we save how many bytes we have processed of that linecolor to be able to continue later */
2029
-                                if(curlinecolor<nlinecolors && (len-has_nl-used)>0 && (linecolors[curlinecolor].len-usedlenlinecolor)>(len-has_nl-used)) {
2030
-                                        reui_write(ui,x0+(tmpcol-origincol+usedcol)*ui->fontwidth,y,colors[linecolors[curlinecolor].color].rgba,ptr+used,(len-has_nl-used));
2031
-                                        usedcol+=redata_generic_utf8len(ptr+used,(len-has_nl-used));
2032
-                                        usedlenlinecolor+=(len-has_nl-used);
2033
-                                        used+=(len-has_nl-used);
2025
+                        availcol=redata_generic_utf8lenincomplete(ptr,len-has_nl,&incompletestart,&incompleteend,&endreq);
2026
+                        /* display the line */
2027
+                        used=incompletestart;
2028
+                        usedcol=0;
2029
+                        /* while the avail text is larger than the linecolor len */
2030
+                        while(curlinecolor<nlinecolors && (len-has_nl-incompleteend-used)>=(linecolors[curlinecolor].len-usedlenlinecolor)) {
2031
+                                lastcolor=colors[linecolors[curlinecolor].color].rgba;
2032
+                                reui_write(ui,x0+(tmpcol-origincol+usedcol)*ui->fontwidth,y,lastcolor,ptr+used,linecolors[curlinecolor].len-usedlenlinecolor);
2033
+                                usedcol+=redata_generic_utf8len(ptr+used,linecolors[curlinecolor].len-usedlenlinecolor);
2034
+                                used+=linecolors[curlinecolor].len-usedlenlinecolor;
2035
+                                curlinecolor++;
2036
+                                usedlenlinecolor=0;
2037
+                        }
2038
+                        /* for the last bytes of avail text, after writing them we save how many bytes we have processed of that linecolor to be able to continue later */
2039
+                        if((len-has_nl-incompleteend-used)>0) {
2040
+                                if(curlinecolor<nlinecolors && (linecolors[curlinecolor].len-usedlenlinecolor)>(len-has_nl-incompleteend-used)) {
2041
+                                        lastcolor=colors[linecolors[curlinecolor].color].rgba;
2042
+                                        usedlenlinecolor+=(len-has_nl-incompleteend-used);
2043
+                                        if(usedlenlinecolor==linecolors[curlinecolor].len) {
2044
+                                                curlinecolor++;
2045
+                                                usedlenlinecolor=0;
2046
+                                        }
2034 2047
                                 }
2035
-                        } else {
2036
-                                reui_write(ui,x0+(tmpcol-origincol)*ui->fontwidth,y,"\x00\x00\x00\xff",ptr,len-has_nl);
2048
+                                reui_write(ui,x0+(tmpcol-origincol+usedcol)*ui->fontwidth,y,lastcolor,ptr+used,(len-has_nl-incompleteend-used));
2049
+                                usedcol+=redata_generic_utf8len(ptr+used,(len-has_nl-incompleteend-used));
2050
+                                used+=(len-has_nl-incompleteend-used);
2037 2051
                         }
2038
-                        if(printout==NULL && row==(curline-originline)) {
2039
-                                if(curcol>=tmpcol && curcol<(tmpcol+availcol)) {
2040
-                                        int utf8charlen;
2041
-                                        /* draw cursor */
2042
-                                        reui_fill(ui,x0+ui->fontwidth*(curcol-origincol),y,ui->fontwidth,ui->fontheight+1,"\x00\x00\x00\xff");
2043
-                                        drawn_cursor=1;
2044
-                                        curptr=redata_generic_utf8col(ptr,len-has_nl,curcol-tmpcol);
2045
-                                        curptrlen=(curptr==NULL)?0:(len-has_nl)-(curptr-ptr);
2046
-                                        utf8charlen=redata_generic_utf8charlen(curptr,curptrlen);
2047
-                                        reui_write(ui,x0+ui->fontwidth*(curcol-origincol),y,"\xff\xff\xff\xff",curptr,utf8charlen);
2048
-                                        /* get matching braces/parens/anglebracket/curlybraces for highlighting */
2049
-                                        if(utf8charlen==1 && strchr("[]{}<>()",*curptr)!=NULL)
2050
-                                                matchingpos=re_getmatchingbracket(re,cursorpos,*curptr,&matchingchar);
2052
+                        /* if the last utf-8 char is broken into several blocks */
2053
+                        if(incompleteend>0) {
2054
+                                char broken[7];
2055
+                                int usedbroken;
2056
+                                usedbroken=0;
2057
+                                redata_getutf8char(re->data,newpos+len-has_nl-incompleteend,broken,sizeof(broken),&usedbroken);
2058
+                                /* write the just-recomposer character in the correct color */
2059
+                                if(curlinecolor<nlinecolors && (linecolors[curlinecolor].len-usedlenlinecolor)>=1) {
2060
+                                        lastcolor=colors[linecolors[curlinecolor].color].rgba;
2061
+                                        usedlenlinecolor+=1;
2062
+                                        if(usedlenlinecolor==linecolors[curlinecolor].len) {
2063
+                                                curlinecolor++;
2064
+                                                usedlenlinecolor=0;
2065
+                                        }
2051 2066
                                 }
2067
+                                reui_write(ui,x0+(tmpcol-origincol+usedcol)*ui->fontwidth,y,lastcolor,broken,usedbroken);
2068
+                                usedcol++;
2069
+                                availcol++;
2070
+                        }
2071
+                        /* draw cursor if applicable */
2072
+                        if(printout==NULL && row==(curline-originline) && curcol>=tmpcol && curcol<(tmpcol+availcol)) {
2073
+                                char cursorchar[7];
2074
+                                int usedcursorchar;
2075
+                                /* draw cursor */
2076
+                                reui_fill(ui,x0+ui->fontwidth*(curcol-origincol),y,ui->fontwidth,ui->fontheight+1,"\x00\x00\x00\xff");
2077
+                                drawn_cursor=1;
2078
+                                usedcursorchar=0;
2079
+                                redata_getutf8char(re->data,cursorpos,cursorchar,sizeof(cursorchar),&usedcursorchar);
2080
+                                reui_write(ui,x0+ui->fontwidth*(curcol-origincol),y,"\xff\xff\xff\xff",cursorchar,usedcursorchar);
2081
+                                /* get matching braces/parens/anglebracket/curlybraces for highlighting */
2082
+                                if(usedcursorchar==1 && strchr("[]{}<>()",*cursorchar)!=NULL)
2083
+                                        matchingpos=re_getmatchingbracket(re,cursorpos,*cursorchar,&matchingchar);
2052 2084
                         }
2053 2085
                 }
2054 2086
                 if(printout==NULL && row==(curline-originline) && !drawn_cursor)
... ...
@@ -2056,7 +2088,6 @@ re_drawcontents(re_t *re, printout_t *printout)
2056 2088
                 if(in_error)
2057 2089
                         break;
2058 2090
                 pos=realend+1;
2059
-/*LONG LINE LEFT FOR DEBUGGING PURPOSES: reui_write(ui,x0+ui->fontwidth*(curcol-origincol),y,"\xff\xff\xff\xff",curptr,redata_generic_utf8charlen(ptr,curptrlen));*/
2060 2091
         }
2061 2092
         /* highlight matching parens/brace/... if applicable */
2062 2093
         if(printout==NULL && matchingpos!=-1 && redata_pos2linecol(data,matchingpos,&mline,&mcol)!=-1) {
... ...
@@ -2078,14 +2109,14 @@ re_drawcontents(re_t *re, printout_t *printout)
2078 2109
                 else
2079 2110
                         reui_balloon(ui, '\0', x,y, fg, bg, &matchingchar,1);
2080 2111
         }
2081
-        /* display prototypes info if applicable */
2082 2112
         if(printout==NULL) {
2113
+                const char *hint;
2083 2114
                 hint=redata_prototypes_get(data, cursorpos);
2084 2115
                 if(hint!=NULL) {
2085
-                        if((curline-originline)>=(maxrow/2))
2116
+                        if((curline-originline)>=3)
2086 2117
                                 reui_balloon(ui, '\0', x0+w/2, y0+ui->fontheight*3/2, "\x80\x80\x80\xff", "\xff\xff\xff\xcf",(char *) hint,strlen(hint));
2087 2118
                         else
2088
-                                reui_balloon(ui, '\0', x0+w/2, y0+h-ui->fontheight*3/2, "\x80\x80\x80\xff", "\xff\xff\xff\xcf",(char *)hint,strlen(hint));
2119
+                                reui_balloon(ui, '\0', x0+w/2, y0+ui->fontheight*((curline-originline)*2+5)/2, "\x80\x80\x80\xff", "\xff\xff\xff\xcf",(char *) hint,strlen(hint));
2089 2120
                 }
2090 2121
         }
2091 2122
         /* all done */