... | ... |
@@ -23,7 +23,8 @@ |
23 | 23 |
#include "re_data.h" |
24 | 24 |
#include "sha3/sha3.h" |
25 | 25 |
|
26 |
-#define CHUNKSIZE 32768 |
|
26 |
+//#define CHUNKSIZE 32768 |
|
27 |
+#define CHUNKSIZE 160 |
|
27 | 28 |
#define UNDOBLOCK 1024 |
28 | 29 |
#define UNDOGROWSIZE (256*1024) |
29 | 30 |
#define SECURESAVEPREFIX "." |
... | ... |
@@ -1304,6 +1305,53 @@ redata_hash_gen(redata_t *redata, char *filename, char *buf, long buflen, char * |
1304 | 1305 |
return(0); |
1305 | 1306 |
} |
1306 | 1307 |
|
1308 |
+/*#define DEBUG_LINE_INFO*/ |
|
1309 |
+ |
|
1310 |
+#ifdef DEBUG_LINE_INFO |
|
1311 |
+#define LINEINFODEBUG(a) fprintf a |
|
1312 |
+#else |
|
1313 |
+#define LINEINFODEBUG(a) |
|
1314 |
+#endif |
|
1315 |
+ |
|
1316 |
+int |
|
1317 |
+redata_line_info(redata_t *redata, long pos, long *startpos, char **startptr, int *len) |
|
1318 |
+{ |
|
1319 |
+ int chunkno; |
|
1320 |
+ long start; |
|
1321 |
+ unsigned char *ptr,*end; |
|
1322 |
+ rechunk_t *chunk; |
|
1323 |
+ if(redata==NULL || pos<0) |
|
1324 |
+ return(-1); |
|
1325 |
+ /* search chunk of pos */ |
|
1326 |
+ for(chunkno=0,start=0;chunkno<redata->sizechunks;start+=(redata->chunks[chunkno]==NULL)?0:redata->chunks[chunkno]->useddata,chunkno++) { |
|
1327 |
+ LINEINFODEBUG((stderr,"redata_line_info: searchchunk: pos:%li chunkno:%i start:%li\n",pos,chunkno,start)); |
|
1328 |
+ if(redata->chunks[chunkno]==NULL) |
|
1329 |
+ continue; |
|
1330 |
+ if((start+redata->chunks[chunkno]->useddata)>pos) |
|
1331 |
+ break; |
|
1332 |
+ } |
|
1333 |
+ if(chunkno>=redata->sizechunks) |
|
1334 |
+ return(-1); |
|
1335 |
+ chunk=redata->chunks[chunkno]; |
|
1336 |
+ /* search line start */ |
|
1337 |
+ LINEINFODEBUG((stderr,"redata_line_info: searchstart: pos:%li start:%li offset:%li\n",pos,start,(pos-start))); |
|
1338 |
+ for(ptr=chunk->data+(pos-start);ptr>chunk->data && ptr[-1]!='\n';ptr--) |
|
1339 |
+ ; |
|
1340 |
+ /* search line end */ |
|
1341 |
+ LINEINFODEBUG((stderr,"redata_line_info: searchend: pos:%li start:%li offset:%li\n",pos,start,(pos-start))); |
|
1342 |
+ for(end=chunk->data+(pos-start)+1;end<=(chunk->data+chunk->useddata) && end[-1]!='\n';end++) |
|
1343 |
+ ; |
|
1344 |
+ /* fill results */ |
|
1345 |
+ LINEINFODEBUG((stderr,"redata_line_info: filling results: len:%li\n",end-ptr)); |
|
1346 |
+ if(startpos!=NULL) |
|
1347 |
+ *startpos=(pos-((chunk->data+(pos-start))-ptr)); |
|
1348 |
+ if(startptr!=NULL) |
|
1349 |
+ *startptr=(char *) ptr; |
|
1350 |
+ if(len!=NULL) |
|
1351 |
+ *len=end-ptr; |
|
1352 |
+ return(0); |
|
1353 |
+} |
|
1354 |
+ |
|
1307 | 1355 |
static char * |
1308 | 1356 |
securesave_genname(char *filename, char *buf, int bufsize) |
1309 | 1357 |
{ |
... | ... |
@@ -128,3 +128,5 @@ int redata_memhash(redata_t *redata, char *buf, long buflen, char *resbuf129byte |
128 | 128 |
undostack_t *redata_getstack(redata_t *redata, undo_t *undo); |
129 | 129 |
char *redata_generic_genname(char *filename,char *prefix, char *postfix, char *buf, int bufsize); |
130 | 130 |
|
131 |
+/* line convenience funtions */ |
|
132 |
+int redata_line_info(redata_t *redata, long pos, long *startpos, char **startptr, int *len); |
... | ... |
@@ -56,6 +56,17 @@ reui_init() |
56 | 56 |
reui_free(ui),ui=NULL; |
57 | 57 |
return(NULL); |
58 | 58 |
} |
59 |
+ /* font width */ |
|
60 |
+ { |
|
61 |
+ SDL_Surface *s; |
|
62 |
+ SDL_Color c={0,0,0,0}; |
|
63 |
+ if((s=TTF_RenderUTF8_Blended(ui->font,"m",c))==NULL) { |
|
64 |
+ reui_free(ui),ui=NULL; |
|
65 |
+ return(NULL); |
|
66 |
+ } |
|
67 |
+ ui->fontwidth=s->w; |
|
68 |
+ SDL_FreeSurface(s),s=NULL; |
|
69 |
+ } |
|
59 | 70 |
/* finished */ |
60 | 71 |
ui->scrdirty=1; |
61 | 72 |
ui->rendererdirty=1; |
... | ... |
@@ -98,13 +109,17 @@ reui_title(reui_t *ui, char *titlefilename) |
98 | 109 |
|
99 | 110 |
|
100 | 111 |
int |
101 |
-reui_fill(reui_t *ui, int x, int y, int w, int h, unsigned char *rgba) |
|
112 |
+reui_fill(reui_t *ui, int x, int y, int w, int h, char *rgba) |
|
102 | 113 |
{ |
103 | 114 |
SDL_Rect dstrect; |
104 | 115 |
if(ui==NULL || rgba==NULL) |
105 | 116 |
return(-1); |
106 | 117 |
RECTFILL(dstrect,x,y,w,h); |
107 |
- SDL_SetRenderDrawColor(ui->renderer,rgba[0],rgba[1],rgba[2],rgba[3]); |
|
118 |
+ SDL_SetRenderDrawColor(ui->renderer, |
|
119 |
+ ((unsigned char *)rgba)[0], |
|
120 |
+ ((unsigned char *)rgba)[1], |
|
121 |
+ ((unsigned char *)rgba)[2], |
|
122 |
+ ((unsigned char *)rgba)[3]); |
|
108 | 123 |
SDL_RenderFillRect(ui->renderer, &dstrect); |
109 | 124 |
ui->rendererdirty=1; |
110 | 125 |
return(0); |
... | ... |
@@ -134,12 +149,15 @@ reui_present(reui_t *ui) |
134 | 149 |
} |
135 | 150 |
|
136 | 151 |
int |
137 |
-reui_write(reui_t *ui, int x, int y, unsigned char *rgba, char *str, int nchar) |
|
152 |
+reui_write(reui_t *ui, int x, int y, char *rgba, char *str, int nchar) |
|
138 | 153 |
{ |
139 | 154 |
char buf[1024]; |
140 | 155 |
SDL_Surface *fgsurface; |
141 | 156 |
SDL_Texture *fg; |
142 |
- SDL_Color c={rgba[0],rgba[1],rgba[2],rgba[3]}; |
|
157 |
+ SDL_Color c={((unsigned char *)rgba)[0], |
|
158 |
+ ((unsigned char *)rgba)[1], |
|
159 |
+ ((unsigned char *)rgba)[2], |
|
160 |
+ ((unsigned char *)rgba)[3]}; |
|
143 | 161 |
SDL_Rect dstrect; |
144 | 162 |
if(nchar<sizeof(buf)) { |
145 | 163 |
memcpy(buf,str,nchar); |
... | ... |
@@ -164,7 +182,7 @@ reui_write(reui_t *ui, int x, int y, unsigned char *rgba, char *str, int nchar) |
164 | 182 |
|
165 | 183 |
|
166 | 184 |
int |
167 |
-reui_printf(reui_t *ui, int x, int y, unsigned char *rgba, char *format, ...) |
|
185 |
+reui_printf(reui_t *ui, int x, int y, char *rgba, char *format, ...) |
|
168 | 186 |
{ |
169 | 187 |
char buf[1024]; |
170 | 188 |
va_list l; |
... | ... |
@@ -176,3 +194,25 @@ reui_printf(reui_t *ui, int x, int y, unsigned char *rgba, char *format, ...) |
176 | 194 |
return(-1); |
177 | 195 |
return(0); |
178 | 196 |
} |
197 |
+ |
|
198 |
+int |
|
199 |
+reui_utf8len(reui_t *ui, char *ptr, int size) |
|
200 |
+{ |
|
201 |
+ /* calculate the number of utf8-charaters in buffer */ |
|
202 |
+ if(ui==NULL || size<0 || (ptr==NULL && size!=0)) |
|
203 |
+ return(-1); |
|
204 |
+#warning TODO |
|
205 |
+ return(size); |
|
206 |
+#warning Also consider tabs |
|
207 |
+} |
|
208 |
+ |
|
209 |
+char * |
|
210 |
+reui_utf8col(reui_t *ui, char *ptr, int size, int col) |
|
211 |
+{ |
|
212 |
+ /* return a pointer to the "n"th ("col"th) utf8-character in buffer */ |
|
213 |
+#warning TODO |
|
214 |
+ if(col<size) |
|
215 |
+ return(ptr+col); |
|
216 |
+ return(NULL); |
|
217 |
+#warning Also consider tabs |
|
218 |
+} |
... | ... |
@@ -25,6 +25,7 @@ typedef struct reui_t { |
25 | 25 |
SDL_RWops *fontdata; |
26 | 26 |
TTF_Font *font; |
27 | 27 |
int fontheight; |
28 |
+ int fontwidth; |
|
28 | 29 |
int scrdirty; |
29 | 30 |
int rendererdirty; |
30 | 31 |
} reui_t; |
... | ... |
@@ -33,13 +34,20 @@ reui_t *reui_init(); |
33 | 34 |
void reui_free(reui_t *ui); |
34 | 35 |
|
35 | 36 |
int reui_title(reui_t *ui, char *titlefilename); |
36 |
-int reui_fill(reui_t *ui, int x, int y, int w, int h, unsigned char *rgba); |
|
37 |
+int reui_fill(reui_t *ui, int x, int y, int w, int h, char *rgba); |
|
37 | 38 |
int reui_scr2renderer(reui_t *ui, int x, int y, int w, int h); |
38 | 39 |
int reui_present(reui_t *ui); |
39 | 40 |
|
40 |
-int reui_write(reui_t *ui, int x, int y, unsigned char *rgba, char *str, int nchar); |
|
41 |
+int reui_write(reui_t *ui, int x, int y, char *rgba, char *str, int nchar); |
|
41 | 42 |
#ifdef __GNUC__ |
42 |
-int reui_printf(reui_t *ui, int x, int y, unsigned char *rgba, char *format, ...) __attribute__ ((format (printf, 5, 6))); |
|
43 |
+int reui_printf(reui_t *ui, int x, int y, char *rgba, char *format, ...) __attribute__ ((format (printf, 5, 6))); |
|
43 | 44 |
#else |
44 |
-int reui_printf(reui_t *ui, int x, int y, unsigned char *rgba, char *format, ...); |
|
45 |
+int reui_printf(reui_t *ui, int x, int y, char *rgba, char *format, ...); |
|
45 | 46 |
#endif |
47 |
+ |
|
48 |
+/* calculate the number of utf8-charaters in buffer */ |
|
49 |
+int reui_utf8len(reui_t *ui, char *ptr, int size); |
|
50 |
+ |
|
51 |
+/* return a pointer to the "n"th ("col"th) utf8-character in buffer */ |
|
52 |
+char *reui_utf8col(reui_t *ui, char *ptr, int size, int col); |
|
53 |
+ |
... | ... |
@@ -19,11 +19,14 @@ |
19 | 19 |
#include "ext/socklib.h" |
20 | 20 |
|
21 | 21 |
typedef struct re_t { |
22 |
- redata_t *redata; |
|
22 |
+ redata_t *data; |
|
23 | 23 |
reui_t *ui; |
24 | 24 |
int flag_newfile; |
25 | 25 |
char filename[PATH_MAX]; |
26 | 26 |
int x, y, w, h; // contents rect |
27 |
+ long cursorpos; |
|
28 |
+ int lastcol,lastrow; |
|
29 |
+ int maxrow,maxcol; |
|
27 | 30 |
} re_t; |
28 | 31 |
|
29 | 32 |
volatile int flag_sigint; |
... | ... |
@@ -50,6 +53,7 @@ main(int argc, char *argv[]) |
50 | 53 |
int do_exit; |
51 | 54 |
SDL_Event event; |
52 | 55 |
sselect *ssel; |
56 |
+ int flag_had_events; |
|
53 | 57 |
if(argc!=2 || strcmp(argv[argc-1],"--help")==0) { |
54 | 58 |
fprintf(stderr,"Syntax: %s filename\n",argv[0]); |
55 | 59 |
return(1); |
... | ... |
@@ -68,17 +72,18 @@ main(int argc, char *argv[]) |
68 | 72 |
re_free(re),re=NULL; |
69 | 73 |
return(2); |
70 | 74 |
} |
71 |
- if((redata_load(re->redata,re->filename,NULL,NULL))!=0) |
|
75 |
+ if((redata_load(re->data,re->filename,NULL,NULL))!=0) |
|
72 | 76 |
re->flag_newfile=1; |
73 | 77 |
else |
74 | 78 |
re->flag_newfile=0; |
79 |
+#if 0 |
|
75 | 80 |
#warning TESTS |
76 | 81 |
{ |
77 | 82 |
char buf[129]; |
78 |
- redata_hash(re->redata,buf); |
|
83 |
+ redata_hash(re->data,buf); |
|
79 | 84 |
fprintf(stderr,"%s %s\n",buf,re->filename); |
80 | 85 |
} |
81 |
-#warning TODO |
|
86 |
+#endif |
|
82 | 87 |
reui_title(re->ui,re->filename); |
83 | 88 |
flag_sigint=flag_sigpipe=0; |
84 | 89 |
setsignal(SIGINT,sighandler_sigint); |
... | ... |
@@ -91,15 +96,20 @@ main(int argc, char *argv[]) |
91 | 96 |
} |
92 | 97 |
reui_scr2renderer(re->ui,0,0,re->ui->w,re->ui->h); |
93 | 98 |
re->x=0,re->y=re->ui->fontheight,re->w=re->ui->w,re->h=re->ui->h-re->y; |
94 |
- reui_fill(re->ui,0,0,re->ui->w,re->ui->fontheight,(unsigned char *) "\x00\x00\xff\xff"); |
|
95 |
- reui_printf(re->ui,0,0,(unsigned char *) "\xff\xff\x00\xff","Fichero: %s",re->filename); |
|
99 |
+ re->maxrow=re->h/re->ui->fontheight-1; |
|
100 |
+ re->maxcol=re->w/re->ui->fontwidth-1; |
|
101 |
+ reui_fill(re->ui,0,0,re->ui->w,re->ui->fontheight,"\x00\x00\xff\xff"); |
|
102 |
+ reui_printf(re->ui,0,0,"\xff\xff\x00\xff","Fichero: %s",re->filename); |
|
96 | 103 |
re_drawcontents(re); |
104 |
+ flag_had_events=0; |
|
97 | 105 |
while(do_exit==0 && flag_sigint==0) { |
98 | 106 |
if(re->ui->rendererdirty) |
99 | 107 |
reui_present(re->ui); |
100 |
- sselect_wait(ssel,100); |
|
108 |
+ sselect_wait(ssel,(flag_had_events)?10:100); |
|
109 |
+ flag_had_events=(flag_had_events>0)?flag_had_events-1:0; |
|
101 | 110 |
SDL_PumpEvents(); |
102 | 111 |
while(SDL_PeepEvents(&event,1,SDL_GETEVENT,SDL_FIRSTEVENT,SDL_LASTEVENT)>0) { |
112 |
+ flag_had_events=10; |
|
103 | 113 |
switch(event.type) { |
104 | 114 |
case SDL_QUIT: |
105 | 115 |
do_exit=1; |
... | ... |
@@ -153,7 +163,7 @@ re_init(void) |
153 | 163 |
if((re=malloc(sizeof(re_t)))==NULL) |
154 | 164 |
return(NULL); /* insuf. mem. */ |
155 | 165 |
memset(re,0,sizeof(re_t)); |
156 |
- if((re->redata=redata_init(NULL))==NULL) { |
|
166 |
+ if((re->data=redata_init(NULL))==NULL) { |
|
157 | 167 |
re_free(re),re=NULL; |
158 | 168 |
return(NULL); /* insuf. mem. */ |
159 | 169 |
} |
... | ... |
@@ -171,8 +181,8 @@ re_free(re_t *re) |
171 | 181 |
return; /* all done */ |
172 | 182 |
if(re->ui!=NULL) |
173 | 183 |
reui_free(re->ui),re->ui=NULL; |
174 |
- if(re->redata!=NULL) |
|
175 |
- redata_free(re->redata),re->redata=NULL; |
|
184 |
+ if(re->data!=NULL) |
|
185 |
+ redata_free(re->data),re->data=NULL; |
|
176 | 186 |
free(re),re=NULL; |
177 | 187 |
return; |
178 | 188 |
} |
... | ... |
@@ -192,7 +202,33 @@ re_setfilename(re_t *re, char *filename) |
192 | 202 |
int |
193 | 203 |
re_processkey(re_t *re, SDL_Event *event) |
194 | 204 |
{ |
195 |
-#warning TODO |
|
205 |
+ long newpos,newpos2; |
|
206 |
+ char *ptr,*ptr2; |
|
207 |
+ int len; |
|
208 |
+ int has_nl; |
|
209 |
+ int oldcol; |
|
210 |
+ if(re==NULL || event==NULL || event->type!=SDL_KEYDOWN) |
|
211 |
+ return(-1); |
|
212 |
+ if(event->key.keysym.sym==SDLK_DOWN || event->key.keysym.sym==SDLK_UP) { |
|
213 |
+ if(redata_line_info(re->data,re->cursorpos,&newpos,&ptr,&len)==-1) |
|
214 |
+ return(-1); /* couldn't get current line data */ |
|
215 |
+ if(event->key.keysym.sym==SDLK_UP && newpos==0) |
|
216 |
+ return(-1); /* going up but already at top */ |
|
217 |
+ oldcol=reui_utf8len(re->ui,ptr,re->cursorpos-newpos); |
|
218 |
+ if(redata_line_info(re->data,(event->key.keysym.sym==SDLK_DOWN)?(newpos+len):(newpos-1),&newpos2,&ptr,&len)==-1) |
|
219 |
+ return(-1); /* couldn't get next line data */ |
|
220 |
+ has_nl=((len>0 && ptr[len-1]=='\n')?1:0); |
|
221 |
+ ptr2=reui_utf8col(re->ui,ptr,len-has_nl,oldcol); |
|
222 |
+ if(ptr2!=NULL) |
|
223 |
+ re->cursorpos=newpos2+(ptr2-ptr); |
|
224 |
+ else |
|
225 |
+ re->cursorpos=newpos2+len-has_nl; |
|
226 |
+ if(event->key.keysym.sym==SDLK_DOWN && re->lastrow<re->maxrow) |
|
227 |
+ re->lastrow++; |
|
228 |
+ else if(event->key.keysym.sym==SDLK_UP && re->lastrow>0) |
|
229 |
+ re->lastrow--; |
|
230 |
+ re_drawcontents(re); |
|
231 |
+ } |
|
196 | 232 |
return(-1); |
197 | 233 |
} |
198 | 234 |
|
... | ... |
@@ -200,24 +236,40 @@ re_processkey(re_t *re, SDL_Event *event) |
200 | 236 |
int |
201 | 237 |
re_drawcontents(re_t *re) |
202 | 238 |
{ |
203 |
- int numchunk; |
|
204 |
- long offset; |
|
205 |
- rechunk_t *chunk; |
|
206 |
- unsigned char *ptr,*end; |
|
207 |
- int y; |
|
208 |
- reui_fill(re->ui,re->x,re->y,re->w,re->h,(unsigned char *) "\xdf\xdf\xdf\xff"); |
|
209 |
- if(redata_getposptr(re->redata,0,&numchunk,&offset)==-1) |
|
210 |
- return(-1); |
|
211 |
- chunk=re->redata->chunks[numchunk]; |
|
212 |
- /* iterate on lines */ |
|
213 |
- for(y=re->y,ptr=chunk->data+offset,end=memchr(ptr,'\n',chunk->useddata-(ptr-chunk->data)), |
|
214 |
- end=(end==NULL)?chunk->data+chunk->useddata:end;ptr!=NULL && y<(re->y+re->h); |
|
215 |
- y+=re->ui->fontheight,ptr=(end!=(chunk->data+chunk->useddata))?end+1:NULL, |
|
216 |
- end=(ptr==NULL)?NULL:memchr(ptr,'\n',chunk->useddata-(ptr-chunk->data)), |
|
217 |
- end=(end==NULL)?chunk->data+chunk->useddata:end) { |
|
218 |
- reui_write(re->ui,re->x,y,(unsigned char *) "\x00\x00\x00\xff",ptr,end-ptr); |
|
239 |
+ long pos,newpos; |
|
240 |
+ char *ptr; |
|
241 |
+ int len; |
|
242 |
+ int y,row; |
|
243 |
+ char c; |
|
244 |
+ int has_nl; |
|
245 |
+ reui_fill(re->ui,re->x,re->y,re->w,re->h,"\xdf\xdf\xdf\xff"); |
|
246 |
+ row=re->lastrow; |
|
247 |
+ pos=re->cursorpos; |
|
248 |
+ while(row>0) { |
|
249 |
+ if(redata_line_info(re->data,pos,&newpos,NULL,NULL)==-1) |
|
250 |
+ return(-1); |
|
251 |
+ pos=(newpos>0)?newpos-1:0; |
|
252 |
+ row--; |
|
219 | 253 |
} |
220 |
-#warning TODO |
|
221 |
- return(-1); |
|
254 |
+ /* highlight current line */ |
|
255 |
+ reui_fill(re->ui,re->x,re->y+(re->lastrow)*re->ui->fontheight,re->w,re->ui->fontheight+1,"\xef\xef\xef\xff"); |
|
256 |
+ /* draw the lines */ |
|
257 |
+ for(y=re->y;y<(re->y+re->h);y+=re->ui->fontheight,row++) { |
|
258 |
+ if(redata_line_info(re->data,pos,&newpos,&ptr,&len)==-1) |
|
259 |
+ break; /* couldn't get line start pos */ |
|
260 |
+ has_nl=((len>0 && ptr[len-1]=='\n')?1:0); |
|
261 |
+ reui_write(re->ui,re->x,y,"\x00\x00\x00\xff",(char *)ptr,len-has_nl); |
|
262 |
+ if(row==re->lastrow) { |
|
263 |
+ reui_fill(re->ui,re->x+re->ui->fontwidth*re->lastcol,y,re->ui->fontwidth,re->ui->fontheight+1,"\x00\x00\x00\xff"); |
|
264 |
+#warning TODO: consider multibytes characters and tabs to position on the corect character and to pass the correct number of bytes to reui_write |
|
265 |
+ c=(re->lastcol>=(len-has_nl))?' ':ptr[re->lastcol]; |
|
266 |
+ reui_write(re->ui,re->x+re->ui->fontwidth*re->lastcol,y,"\xff\xff\xff\xff",&c,1); |
|
267 |
+#warning TODO: if it is one of '[','{','<','>','}',']', highlight the matching bracket/parens/anglebracket. |
|
268 |
+ } |
|
269 |
+ pos=newpos+len; |
|
270 |
+ } |
|
271 |
+ re->ui->rendererdirty=1; |
|
272 |
+ return(0); |
|
222 | 273 |
} |
223 | 274 |
|
275 |
+ |