Released version 3-2014010900
[notion/jeffpc.git] / mod_query / edln.c
blob6951014748166a4dba886a11d5414e01134417f8
1 /*
2 * ion/mod_query/edln.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <string.h>
11 #include <libtu/minmax.h>
12 #include <ioncore/common.h>
13 #include <ioncore/selection.h>
14 #include <ioncore/strings.h>
16 #include "edln.h"
17 #include "wedln.h"
18 #include "history.h"
20 #define EDLN_ALLOCUNIT 16
22 #define UPDATE(X) \
23 edln->ui_update(edln->uiptr, X, 0)
25 #define UPDATE_MOVED(X) \
26 edln->ui_update(edln->uiptr, X, EDLN_UPDATE_MOVED)
28 #define UPDATE_CHANGED(X) \
29 edln->ui_update(edln->uiptr, X, \
30 EDLN_UPDATE_MOVED|EDLN_UPDATE_CHANGED)
32 #define UPDATE_CHANGED_NOMOVE(X) \
33 edln->ui_update(edln->uiptr, X, \
34 EDLN_UPDATE_CHANGED)
36 #define UPDATE_NEW() \
37 edln->ui_update(edln->uiptr, 0, \
38 EDLN_UPDATE_NEW|EDLN_UPDATE_MOVED|EDLN_UPDATE_CHANGED)
40 #define CHAR wchar_t
41 #define ISALNUM iswalnum
42 #define CHAR_AT(P, N) str_wchar_at(P, N)
45 /*{{{ Alloc */
48 static bool edln_pspc(Edln *edln, int n)
50 char *np;
51 int pa;
53 if(edln->palloced<edln->psize+1+n){
54 pa=edln->palloced+n;
55 pa|=(EDLN_ALLOCUNIT-1);
56 np=ALLOC_N(char, pa);
58 if(np==NULL)
59 return FALSE;
61 memmove(np, edln->p, edln->point*sizeof(char));
62 memmove(np+edln->point+n, edln->p+edln->point,
63 (edln->psize-edln->point+1)*sizeof(char));
64 free(edln->p);
65 edln->p=np;
66 edln->palloced=pa;
67 }else{
68 memmove(edln->p+edln->point+n, edln->p+edln->point,
69 (edln->psize-edln->point+1)*sizeof(char));
72 if(edln->mark>edln->point)
73 edln->mark+=n;
75 edln->psize+=n;
77 edln->modified=1;
78 return TRUE;
82 static bool edln_rspc(Edln *edln, int n)
84 char *np;
85 int pa;
87 if(n+edln->point>=edln->psize)
88 n=edln->psize-edln->point;
90 if(n==0)
91 return TRUE;
93 if((edln->psize+1-n)<(edln->palloced&~(EDLN_ALLOCUNIT-1))){
94 pa=edln->palloced&~(EDLN_ALLOCUNIT-1);
95 np=ALLOC_N(char, pa);
97 if(np==NULL)
98 goto norm;
100 memmove(np, edln->p, edln->point*sizeof(char));
101 memmove(np+edln->point, edln->p+edln->point+n,
102 (edln->psize-edln->point+1-n)*sizeof(char));
103 free(edln->p);
104 edln->p=np;
105 edln->palloced=pa;
106 }else{
107 norm:
108 memmove(edln->p+edln->point, edln->p+edln->point+n,
109 (edln->psize-edln->point+1-n)*sizeof(char));
111 edln->psize-=n;
113 if(edln->mark>edln->point)
114 edln->mark-=n;
116 edln->modified=1;
117 return TRUE;
121 static void edln_clearstr(Edln *edln)
123 if(edln->p!=NULL){
124 free(edln->p);
125 edln->p=NULL;
127 edln->palloced=0;
128 edln->psize=0;
132 static bool edln_initstr(Edln *edln, const char *p)
134 int l=strlen(p), al;
136 al=(l+1)|(EDLN_ALLOCUNIT-1);
138 edln->p=ALLOC_N(char, al);
140 if(edln->p==NULL)
141 return FALSE;
143 edln->palloced=al;
144 edln->psize=l;
145 strcpy(edln->p, p);
147 return TRUE;
151 static bool edln_setstr(Edln *edln, const char *p)
153 edln_clearstr(edln);
154 return edln_initstr(edln, p);
158 /*}}}*/
161 /*{{{ Insert */
164 bool edln_insstr(Edln *edln, const char *str)
166 int l;
168 if(str==NULL)
169 return FALSE;
171 l=strlen(str);
173 return edln_insstr_n(edln, str, l, TRUE, TRUE);
177 bool edln_insstr_n(Edln *edln, const char *str, int l,
178 bool update, bool movepoint)
180 if(!edln_pspc(edln, l))
181 return FALSE;
183 memmove(&(edln->p[edln->point]), str, l);
184 if(movepoint){
185 edln->point+=l;
186 if(update)
187 UPDATE_CHANGED(edln->point-l);
188 }else{
189 if(update)
190 UPDATE_CHANGED_NOMOVE(edln->point-l);
193 return TRUE;
197 /*}}}*/
200 /*{{{ Transpose */
203 bool edln_transpose_chars(Edln *edln)
205 int off1, off2, pos;
206 char *buf;
208 if((edln->point==0) || (edln->psize<2))
209 return FALSE;
211 pos=edln->point;
212 if(edln->point==edln->psize)
213 pos=pos-str_prevoff(edln->p, edln->point);
215 off1=str_nextoff(edln->p, pos);
216 off2=str_prevoff(edln->p, pos);
218 buf=ALLOC_N(char, off2);
219 if(buf==NULL)
220 return FALSE;
221 memmove(buf, &(edln->p[pos-off2]), off2);
222 memmove(&(edln->p[pos-off2]), &(edln->p[pos]), off1);
223 memmove(&(edln->p[pos-off2+off1]), buf, off2);
224 FREE(buf);
226 if(edln->point!=edln->psize)
227 edln->point+=off1;
229 UPDATE_CHANGED(0);
230 return TRUE;
234 bool edln_transpose_words(Edln *edln)
236 int m1, m2, m3, m4, off1, off2, oldp;
237 char *buf;
239 if((edln->point==edln->psize) || (edln->psize<3))
240 return FALSE;
242 oldp=edln->point;
243 edln_bskip_word(edln);
244 m1=edln->point;
245 edln_skip_word(edln);
246 m2=edln->point;
247 edln_skip_word(edln);
248 if(edln->point==m2)
249 goto noact;
250 m4=edln->point;
251 edln_bskip_word(edln);
252 if(edln->point==m1)
253 goto noact;
254 m3=edln->point;
256 off1=m4-m3;
257 off2=m3-m2;
259 buf=ALLOC_N(char, m4-m1);
260 if(buf==NULL)
261 goto noact;
262 memmove(buf, &(edln->p[m3]), off1);
263 memmove(buf+off1, &(edln->p[m2]), off2);
264 memmove(buf+off1+off2, &(edln->p[m1]), m2-m1);
265 memmove(&(edln->p[m1]), buf, m4-m1);
266 FREE(buf);
268 edln->point=m4;
269 UPDATE_CHANGED(0);
270 return TRUE;
272 noact:
273 edln->point=oldp;
274 UPDATE_MOVED(edln->point);
275 return FALSE;
279 /*}}}*/
282 /*{{{ Movement */
285 static int do_edln_back(Edln *edln)
287 int l=str_prevoff(edln->p, edln->point);
288 edln->point-=l;
289 return l;
293 void edln_back(Edln *edln)
295 int p=edln->point;
296 do_edln_back(edln);
297 /*if(edln->point!=p)*/
298 UPDATE_MOVED(edln->point);
302 static int do_edln_forward(Edln *edln)
304 int l=str_nextoff(edln->p, edln->point);
305 edln->point+=l;
306 return l;
310 void edln_forward(Edln *edln)
312 int p=edln->point;
313 do_edln_forward(edln);
314 /*if(edln->point!=p)*/
315 UPDATE_MOVED(p);
319 void edln_bol(Edln *edln)
321 if(edln->point!=0){
322 edln->point=0;
323 UPDATE_MOVED(0);
328 void edln_eol(Edln *edln)
330 int o=edln->point;
332 if(edln->point!=edln->psize){
333 edln->point=edln->psize;
334 UPDATE_MOVED(o);
339 void edln_bskip_word(Edln *edln)
341 int p, n;
342 CHAR c;
344 while(edln->point>0){
345 n=do_edln_back(edln);
346 c=CHAR_AT(edln->p+edln->point, n);
347 if(ISALNUM(c))
348 goto fnd;
350 UPDATE_MOVED(edln->point);
351 return;
353 fnd:
354 while(edln->point>0){
355 p=edln->point;
356 n=do_edln_back(edln);
357 c=CHAR_AT(edln->p+edln->point, n);
359 if(!ISALNUM(c)){
360 edln->point=p;
361 break;
364 UPDATE_MOVED(edln->point);
368 void edln_skip_word(Edln *edln)
370 int oldp=edln->point;
371 CHAR c;
373 while(edln->point<edln->psize){
374 c=CHAR_AT(edln->p+edln->point, edln->psize-edln->point);
375 if(ISALNUM(c))
376 goto fnd;
377 if(do_edln_forward(edln)==0)
378 break;
380 UPDATE_MOVED(oldp);
381 return;
383 fnd:
384 while(edln->point<edln->psize){
385 c=CHAR_AT(edln->p+edln->point, edln->psize-edln->point);
386 if(!ISALNUM(c))
387 break;
388 if(do_edln_forward(edln)==0)
389 break;
391 UPDATE_MOVED(oldp);
395 void edln_set_point(Edln *edln, int point)
397 int o=edln->point;
399 if(point<0)
400 point=0;
401 else if(point>edln->psize)
402 point=edln->psize;
404 edln->point=point;
406 if(o<point)
407 UPDATE_MOVED(o);
408 else
409 UPDATE_MOVED(point);
413 /*}}}*/
416 /*{{{ Delete */
419 void edln_delete(Edln *edln)
421 int left=edln->psize-edln->point;
422 size_t l;
424 if(left<=0)
425 return;
427 l=str_nextoff(edln->p, edln->point);
429 if(l>0)
430 edln_rspc(edln, l);
432 UPDATE_CHANGED_NOMOVE(edln->point);
436 void edln_backspace(Edln *edln)
438 int n;
439 if(edln->point==0)
440 return;
441 n=do_edln_back(edln);
442 if(n!=0){
443 edln_rspc(edln, n);
444 UPDATE_CHANGED(edln->point);
448 void edln_kill_to_eol(Edln *edln)
450 edln_rspc(edln, edln->psize-edln->point);
451 UPDATE_CHANGED_NOMOVE(edln->point);
455 void edln_kill_to_bol(Edln *edln)
457 int p=edln->point;
459 edln_bol(edln);
460 edln_rspc(edln, p);
461 edln->point=0;
462 UPDATE_CHANGED(0);
466 void edln_kill_line(Edln *edln)
468 edln_bol(edln);
469 edln_kill_to_eol(edln);
470 UPDATE_CHANGED(0);
474 void edln_kill_word(Edln *edln)
476 int oldp=edln->point;
477 int l;
478 edln_skip_word(edln);
480 if(edln->point==oldp)
481 return;
483 l=edln->point-oldp;
484 edln->point=oldp;
485 edln_rspc(edln, l);
487 UPDATE_CHANGED_NOMOVE(oldp);
491 void edln_bkill_word(Edln *edln)
493 int oldp=edln->point;
495 edln_bskip_word(edln);
497 if(edln->point==oldp)
498 return;
500 edln_rspc(edln, oldp-edln->point);
501 UPDATE_CHANGED(edln->point);
505 /*}}}*/
508 /*{{{ Selection */
511 static void do_set_mark(Edln *edln, int nm)
513 int m=edln->mark;
514 edln->mark=nm;
515 if(m!=-1)
516 UPDATE(m < edln->point ? m : edln->point);
520 void edln_set_mark(Edln *edln)
522 do_set_mark(edln, edln->point);
526 void edln_clear_mark(Edln *edln)
528 do_set_mark(edln, -1);
532 static void edln_do_copy(Edln *edln, bool del)
534 int beg, end;
536 if(edln->mark<0 || edln->point==edln->mark)
537 return;
539 if(edln->point<edln->mark){
540 beg=edln->point;
541 end=edln->mark;
542 }else{
543 beg=edln->mark;
544 end=edln->point;
547 ioncore_set_selection_n(edln->p+beg, end-beg);
549 if(del){
550 edln->point=beg;
551 edln_rspc(edln, end-beg);
553 edln->mark=-1;
555 UPDATE(beg);
559 void edln_cut(Edln *edln)
561 edln_do_copy(edln, TRUE);
565 void edln_copy(Edln *edln)
567 edln_do_copy(edln, FALSE);
571 /*}}}*/
574 /*{{{ History */
577 bool edln_set_context(Edln *edln, const char *str)
579 char *s=scat(str, ":"), *cp;
581 if(s==NULL)
582 return FALSE;
584 cp=strchr(s, ':');
585 while(cp!=NULL && *(cp+1)!='\0'){
586 *cp='_';
587 cp=strchr(cp, ':');
590 if(edln->context!=NULL)
591 free(edln->context);
592 edln->context=s;
594 return TRUE;
598 static void edln_do_set_hist(Edln *edln, int e, bool match)
600 const char *str=mod_query_history_get(e), *s2;
601 if(str!=NULL){
602 if(edln->histent<0){
603 edln->tmp_p=edln->p;
604 edln->tmp_palloced=edln->palloced;
605 edln->p=NULL;
608 /* Skip context label */
609 s2=strchr(str, ':');
610 if(s2!=NULL)
611 str=s2+1;
613 edln->histent=e;
614 edln_setstr(edln, str);
615 edln->point=(match
616 ? minof(edln->point, edln->psize)
617 : edln->psize);
618 edln->mark=-1;
619 edln->modified=FALSE;
620 UPDATE_NEW();
625 static char *history_search_str(Edln *edln)
627 char *sstr;
628 char tmp=edln->p[edln->point];
629 edln->p[edln->point]='\0';
630 sstr=scat(edln->context ? edln->context : "*:", edln->p);
631 edln->p[edln->point]=tmp;
632 return sstr;
636 static int search(Edln *edln, int from, bool bwd, bool match)
638 int e;
640 if(match && edln->point>0){
641 char *tmpstr=history_search_str(edln);
642 if(tmpstr==NULL)
643 return edln->histent;
644 e=mod_query_history_search(tmpstr, from, bwd, FALSE);
645 free(tmpstr);
646 }else{
647 e=mod_query_history_search(edln->context, from, bwd, FALSE);
650 return e;
654 void edln_history_prev(Edln *edln, bool match)
656 int e=search(edln, edln->histent+1, FALSE, match);
657 if(e>=0)
658 edln_do_set_hist(edln, e, match);
662 void edln_history_next(Edln *edln, bool match)
664 int e=edln->histent;
666 if(edln->histent<0)
667 return;
669 e=search(edln, edln->histent-1, TRUE, match);
671 if(e>=0){
672 edln_do_set_hist(edln, e, match);
673 }else{
674 edln->histent=-1;
675 if(edln->p!=NULL)
676 free(edln->p);
677 edln->p=edln->tmp_p;
678 edln->palloced=edln->tmp_palloced;
679 edln->tmp_p=NULL;
680 edln->psize=(edln->p==NULL ? 0 : strlen(edln->p));
681 edln->point=edln->psize;
682 edln->mark=-1;
683 edln->modified=TRUE;
684 UPDATE_NEW();
689 uint edln_history_matches(Edln *edln, char ***h_ret)
691 char *tmpstr=history_search_str(edln);
692 uint ret;
694 if(tmpstr==NULL){
695 *h_ret=NULL;
696 return 0;
699 ret=mod_query_history_complete(tmpstr, h_ret);
701 free(tmpstr);
703 return ret;
707 /*}}}*/
710 /*{{{ Init/deinit */
713 bool edln_init(Edln *edln, const char *p)
715 if(p==NULL)
716 p="";
718 if(!edln_initstr(edln, p))
719 return FALSE;
721 edln->point=edln->psize;
722 edln->mark=-1;
723 edln->histent=-1;
724 edln->modified=FALSE;
725 edln->tmp_p=NULL;
726 edln->context=NULL;
728 return TRUE;
732 void edln_deinit(Edln *edln)
734 if(edln->p!=NULL){
735 free(edln->p);
736 edln->p=NULL;
738 if(edln->tmp_p!=NULL){
739 free(edln->tmp_p);
740 edln->tmp_p=NULL;
742 if(edln->context!=NULL){
743 free(edln->context);
744 edln->context=NULL;
749 static const char *ctx(Edln *edln)
751 if(edln->context!=NULL)
752 return edln->context;
753 else
754 return "default:";
758 char* edln_finish(Edln *edln)
760 char *p=edln->p, *hist;
762 if(p!=NULL){
763 libtu_asprintf(&hist, "%s%s", ctx(edln), p);
764 if(hist!=NULL)
765 mod_query_history_push_(hist);
768 edln->p=NULL;
769 edln->psize=edln->palloced=0;
771 /*stripws(p);*/
772 return str_stripws(p);
775 /*}}}*/