trunk: changeset 1958
[notion/jeffpc.git] / mod_query / edln.c
blob486e7af6173c83c3b266ff4c72f21abbf8b6bd3c
1 /*
2 * ion/mod_query/edln.c
4 * Copyright (c) Tuomo Valkonen 1999-2005.
6 * Ion is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
12 #include <string.h>
14 #include <libtu/minmax.h>
15 #include <ioncore/common.h>
16 #include <ioncore/selection.h>
17 #include <ioncore/strings.h>
19 #include "edln.h"
20 #include "wedln.h"
21 #include "history.h"
23 #define EDLN_ALLOCUNIT 16
25 #define UPDATE(X) edln->ui_update(edln->uiptr, X, EDLN_UPDATE_STAT)
26 #define UPDATE_MOVED(X) edln->ui_update(edln->uiptr, X, EDLN_UPDATE_MOVED)
27 #define UPDATE_NEW() edln->ui_update(edln->uiptr, 0, EDLN_UPDATE_NEW)
29 #define CHAR wchar_t
30 #define ISALNUM iswalnum
31 #define CHAR_AT(P, N) str_wchar_at(P, N)
34 /*{{{ Alloc */
37 static bool edln_pspc(Edln *edln, int n)
39 char *np;
40 int pa;
42 if(edln->palloced<edln->psize+1+n){
43 pa=edln->palloced+n;
44 pa|=(EDLN_ALLOCUNIT-1);
45 np=ALLOC_N(char, pa);
47 if(np==NULL)
48 return FALSE;
50 memmove(np, edln->p, edln->point*sizeof(char));
51 memmove(np+edln->point+n, edln->p+edln->point,
52 (edln->psize-edln->point+1)*sizeof(char));
53 free(edln->p);
54 edln->p=np;
55 edln->palloced=pa;
56 }else{
57 memmove(edln->p+edln->point+n, edln->p+edln->point,
58 (edln->psize-edln->point+1)*sizeof(char));
61 if(edln->mark>edln->point)
62 edln->mark+=n;
64 edln->psize+=n;
66 edln->modified=1;
67 return TRUE;
71 static bool edln_rspc(Edln *edln, int n)
73 char *np;
74 int pa;
76 if(n+edln->point>=edln->psize)
77 n=edln->psize-edln->point;
79 if(n==0)
80 return TRUE;
82 if((edln->psize+1-n)<(edln->palloced&~(EDLN_ALLOCUNIT-1))){
83 pa=edln->palloced&~(EDLN_ALLOCUNIT-1);
84 np=ALLOC_N(char, pa);
86 if(np==NULL)
87 goto norm;
89 memmove(np, edln->p, edln->point*sizeof(char));
90 memmove(np+edln->point, edln->p+edln->point+n,
91 (edln->psize-edln->point+1-n)*sizeof(char));
92 free(edln->p);
93 edln->p=np;
94 edln->palloced=pa;
95 }else{
96 norm:
97 memmove(edln->p+edln->point, edln->p+edln->point+n,
98 (edln->psize-edln->point+1-n)*sizeof(char));
100 edln->psize-=n;
102 if(edln->mark>edln->point)
103 edln->mark-=n;
105 edln->modified=1;
106 return TRUE;
110 static void edln_clearstr(Edln *edln)
112 if(edln->p!=NULL){
113 free(edln->p);
114 edln->p=NULL;
116 edln->palloced=0;
117 edln->psize=0;
121 static bool edln_initstr(Edln *edln, const char *p)
123 int l=strlen(p), al;
125 al=(l+1)|(EDLN_ALLOCUNIT-1);
127 edln->p=ALLOC_N(char, al);
129 if(edln->p==NULL)
130 return FALSE;
132 edln->palloced=al;
133 edln->psize=l;
134 strcpy(edln->p, p);
136 return TRUE;
140 static bool edln_setstr(Edln *edln, const char *p)
142 edln_clearstr(edln);
143 return edln_initstr(edln, p);
147 /*}}}*/
150 /*{{{ Insert */
152 #if 0
153 bool edln_insch(Edln *edln, char ch)
155 if(edln_pspc(edln, 1)){
156 edln->p[edln->point]=ch;
157 edln->point++;
158 UPDATE_MOVED(edln->point-1);
159 return TRUE;
161 return FALSE;
165 bool edln_ovrch(Edln *edln, char ch)
167 edln_delete(edln);
168 return edln_insch(edln, ch);
170 #endif
173 bool edln_insstr(Edln *edln, const char *str)
175 int l;
177 if(str==NULL)
178 return FALSE;
180 l=strlen(str);
182 return edln_insstr_n(edln, str, l);
186 bool edln_insstr_n(Edln *edln, const char *str, int l)
188 if(!edln_pspc(edln, l))
189 return FALSE;
191 memmove(&(edln->p[edln->point]), str, l);
192 edln->point+=l;
193 UPDATE_MOVED(edln->point-l);
195 return TRUE;
199 /*}}}*/
202 /*{{{ Movement */
205 static int do_edln_back(Edln *edln)
207 int l=str_prevoff(edln->p, edln->point);
208 edln->point-=l;
209 return l;
213 void edln_back(Edln *edln)
215 int p=edln->point;
216 do_edln_back(edln);
217 /*if(edln->point!=p)*/
218 UPDATE_MOVED(edln->point);
222 static int do_edln_forward(Edln *edln)
224 int l=str_nextoff(edln->p, edln->point);
225 edln->point+=l;
226 return l;
230 void edln_forward(Edln *edln)
232 int p=edln->point;
233 do_edln_forward(edln);
234 /*if(edln->point!=p)*/
235 UPDATE_MOVED(p);
239 void edln_bol(Edln *edln)
241 if(edln->point!=0){
242 edln->point=0;
243 UPDATE_MOVED(0);
248 void edln_eol(Edln *edln)
250 int o=edln->point;
252 if(edln->point!=edln->psize){
253 edln->point=edln->psize;
254 UPDATE_MOVED(o);
259 void edln_bskip_word(Edln *edln)
261 int p, n;
262 CHAR c;
264 while(edln->point>0){
265 n=do_edln_back(edln);
266 c=CHAR_AT(edln->p+edln->point, n);
267 if(ISALNUM(c))
268 goto fnd;
270 UPDATE_MOVED(edln->point);
271 return;
273 fnd:
274 while(edln->point>0){
275 p=edln->point;
276 n=do_edln_back(edln);
277 c=CHAR_AT(edln->p+edln->point, n);
279 if(!ISALNUM(c)){
280 edln->point=p;
281 break;
284 UPDATE_MOVED(edln->point);
288 void edln_skip_word(Edln *edln)
290 int oldp=edln->point;
291 CHAR c;
293 while(edln->point<edln->psize){
294 c=CHAR_AT(edln->p+edln->point, edln->psize-edln->point);
295 if(ISALNUM(c))
296 goto fnd;
297 if(do_edln_forward(edln)==0)
298 break;
300 UPDATE_MOVED(oldp);
301 return;
303 fnd:
304 while(edln->point<edln->psize){
305 c=CHAR_AT(edln->p+edln->point, edln->psize-edln->point);
306 if(!ISALNUM(c))
307 break;
308 if(do_edln_forward(edln)==0)
309 break;
311 UPDATE_MOVED(oldp);
315 void edln_set_point(Edln *edln, int point)
317 int o=edln->point;
319 if(point<0)
320 point=0;
321 else if(point>edln->psize)
322 point=edln->psize;
324 edln->point=point;
326 if(o<point)
327 UPDATE_MOVED(o);
328 else
329 UPDATE_MOVED(point);
333 /*}}}*/
336 /*{{{ Delete */
339 void edln_delete(Edln *edln)
341 int left=edln->psize-edln->point;
342 size_t l;
344 if(left<=0)
345 return;
347 l=str_nextoff(edln->p, edln->point);
349 if(l>0)
350 edln_rspc(edln, l);
352 UPDATE(edln->point);
356 void edln_backspace(Edln *edln)
358 int n;
359 if(edln->point==0)
360 return;
361 n=do_edln_back(edln);
362 if(n!=0){
363 edln_rspc(edln, n);
364 UPDATE_MOVED(edln->point);
368 void edln_kill_to_eol(Edln *edln)
370 edln_rspc(edln, edln->psize-edln->point);
371 UPDATE(edln->point);
375 void edln_kill_to_bol(Edln *edln)
377 int p=edln->point;
379 edln_bol(edln);
380 edln_rspc(edln, p);
381 edln->point=0;
382 UPDATE_MOVED(0);
386 void edln_kill_line(Edln *edln)
388 edln_bol(edln);
389 edln_kill_to_eol(edln);
390 UPDATE_MOVED(0);
394 void edln_kill_word(Edln *edln)
396 int oldp=edln->point;
397 int l;
398 edln_skip_word(edln);
400 if(edln->point==oldp)
401 return;
403 l=edln->point-oldp;
404 edln->point=oldp;
405 edln_rspc(edln, l);
407 UPDATE(oldp);
411 void edln_bkill_word(Edln *edln)
413 int oldp=edln->point;
415 edln_bskip_word(edln);
417 if(edln->point==oldp)
418 return;
420 edln_rspc(edln, oldp-edln->point);
421 UPDATE(edln->point);
425 /*}}}*/
428 /*{{{ Selection */
431 static void do_set_mark(Edln *edln, int nm)
433 int m=edln->mark;
434 edln->mark=nm;
435 if(m!=-1)
436 UPDATE(m < edln->point ? m : edln->point);
440 void edln_set_mark(Edln *edln)
442 do_set_mark(edln, edln->point);
446 void edln_clear_mark(Edln *edln)
448 do_set_mark(edln, -1);
452 static void edln_do_copy(Edln *edln, bool del)
454 int beg, end;
456 if(edln->mark<0 || edln->point==edln->mark)
457 return;
459 if(edln->point<edln->mark){
460 beg=edln->point;
461 end=edln->mark;
462 }else{
463 beg=edln->mark;
464 end=edln->point;
467 ioncore_set_selection_n(edln->p+beg, end-beg);
469 if(del){
470 edln->point=beg;
471 edln_rspc(edln, end-beg);
473 edln->mark=-1;
475 UPDATE(beg);
479 void edln_cut(Edln *edln)
481 edln_do_copy(edln, TRUE);
485 void edln_copy(Edln *edln)
487 edln_do_copy(edln, FALSE);
491 /*}}}*/
494 /*{{{ History */
497 bool edln_set_context(Edln *edln, const char *str)
499 char *s=scat(str, ":"), *cp;
501 if(s==NULL)
502 return FALSE;
504 cp=strchr(s, ':');
505 while(cp!=NULL && *(cp+1)!='\0'){
506 *cp='_';
507 cp=strchr(cp, ':');
510 if(edln->context!=NULL)
511 free(edln->context);
512 edln->context=s;
514 return TRUE;
518 static void edln_do_set_hist(Edln *edln, int e, bool match)
520 const char *str=mod_query_history_get(e), *s2;
521 if(str!=NULL){
522 if(edln->histent<0){
523 edln->tmp_p=edln->p;
524 edln->tmp_palloced=edln->palloced;
525 edln->p=NULL;
528 /* Skip context label */
529 s2=strchr(str, ':');
530 if(s2!=NULL)
531 str=s2+1;
533 edln->histent=e;
534 edln_setstr(edln, str);
535 edln->point=(match
536 ? minof(edln->point, edln->psize)
537 : edln->psize);
538 edln->mark=-1;
539 edln->modified=FALSE;
540 UPDATE_NEW();
545 static int search(Edln *edln, int from, bool bwd, bool match)
547 int e;
549 if(match && edln->point>0){
550 char *tmpstr;
551 char tmp=edln->p[edln->point];
552 edln->p[edln->point]='\0';
553 tmpstr=scat(edln->context ? edln->context : "*:", edln->p);
554 edln->p[edln->point]=tmp;
555 if(tmpstr==NULL)
556 return edln->histent;
557 e=mod_query_history_search(tmpstr, from, bwd);
558 free(tmpstr);
559 }else{
560 e=mod_query_history_search(edln->context, from, bwd);
563 return e;
567 void edln_history_prev(Edln *edln, bool match)
569 int e=search(edln, edln->histent+1, FALSE, match);
570 if(e>=0)
571 edln_do_set_hist(edln, e, match);
575 void edln_history_next(Edln *edln, bool match)
577 int e=edln->histent;
579 if(edln->histent<0)
580 return;
582 e=search(edln, edln->histent-1, TRUE, match);
584 if(e>=0){
585 edln_do_set_hist(edln, e, match);
586 }else{
587 edln->histent=-1;
588 if(edln->p!=NULL)
589 free(edln->p);
590 edln->p=edln->tmp_p;
591 edln->palloced=edln->tmp_palloced;
592 edln->tmp_p=NULL;
593 edln->psize=(edln->p==NULL ? 0 : strlen(edln->p));
594 edln->point=edln->psize;
595 edln->mark=-1;
596 edln->modified=TRUE;
597 UPDATE_NEW();
602 /*}}}*/
605 /*{{{ Init/deinit */
608 bool edln_init(Edln *edln, const char *p)
610 if(p==NULL)
611 p="";
613 if(!edln_initstr(edln, p))
614 return FALSE;
616 edln->point=edln->psize;
617 edln->mark=-1;
618 edln->histent=-1;
619 edln->modified=FALSE;
620 edln->completion_handler=NULL;
621 edln->tmp_p=NULL;
622 edln->context=NULL;
624 return TRUE;
628 void edln_deinit(Edln *edln)
630 if(edln->p!=NULL){
631 free(edln->p);
632 edln->p=NULL;
634 if(edln->tmp_p!=NULL){
635 free(edln->tmp_p);
636 edln->tmp_p=NULL;
638 if(edln->context!=NULL){
639 free(edln->context);
640 edln->context=NULL;
645 static const char *ctx(Edln *edln)
647 if(edln->context!=NULL)
648 return edln->context;
649 else
650 return "default:";
654 char* edln_finish(Edln *edln)
656 char *p=edln->p, *hist;
658 if(p!=NULL){
659 libtu_asprintf(&hist, "%s%s", ctx(edln), p);
660 if(hist!=NULL)
661 mod_query_history_push_(hist);
664 edln->p=NULL;
665 edln->psize=edln->palloced=0;
667 /*stripws(p);*/
668 return str_stripws(p);
671 /*}}}*/