]> git.decadent.org.uk Git - ion3.git/blob - mod_query/complete.c
Imported Upstream version 20090110
[ion3.git] / mod_query / complete.c
1 /*
2  * ion/mod_query/complete.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2009. 
5  *
6  * See the included file LICENSE for details.
7  */
8
9 #include <string.h>
10 #include <ctype.h>
11 #include <string.h>
12 #include <limits.h>
13
14 #include <libtu/objp.h>
15 #include <ioncore/common.h>
16 #include "complete.h"
17 #include "edln.h"
18 #include "wedln.h"
19
20
21 /*{{{ Completion list processing */
22
23
24 static int str_common_part_l(const char *p1, const char *p2)
25 {
26     int i=0;
27     
28     while(1){
29         if(*p1=='\0' || *p1!=*p2)
30             break;
31         p1++; p2++; i++;
32     }
33     
34     return i;
35 }
36
37
38 /* Get length of part common to all completions
39  * and remove duplicates
40  */
41 static int get_common_part_rmdup(char **completions, int *ncomp)
42 {
43     int i, j, c=INT_MAX, c2;
44     
45     for(i=0, j=1; j<*ncomp; j++){
46         c2=str_common_part_l(completions[i], completions[j]);
47         if(c2<c)
48             c=c2;
49
50         if(completions[i][c2]=='\0' && completions[j][c2]=='\0'){
51             free(completions[j]);
52             completions[j]=NULL;
53             continue;
54         }
55         i++;
56         if(i!=j){
57             completions[i]=completions[j];
58             completions[j]=NULL;
59         }
60     }
61     *ncomp=i+1;
62     
63     return c;
64 }
65
66
67 static int compare(const void *p1, const void *p2)
68 {
69     const char **v1, **v2;
70     
71     v1=(const char **)p1;
72     v2=(const char **)p2;
73     return strcoll(*v1, *v2);
74 }
75
76
77 static void edln_reset(Edln *edln)
78 {
79     assert(edln->palloced>=1);
80     
81     edln->p[0]='\0';
82     edln->psize=0;
83     edln->point=0;
84     edln->mark=-1;
85     edln->histent=-1;
86 }
87
88
89 static void edln_do_set_completion(Edln *edln, const char *comp, int len,
90                                    const char *beg, const char *end)
91 {
92     edln_reset(edln);
93     
94     if(beg!=NULL)
95         edln_insstr_n(edln, beg, strlen(beg), FALSE, TRUE);
96     
97     if(len>0)
98         edln_insstr_n(edln, comp, len, FALSE, TRUE);
99         
100     if(end!=NULL)
101         edln_insstr_n(edln, end, strlen(end), FALSE, FALSE);
102     
103     if(edln->ui_update!=NULL){
104         edln->ui_update(edln->uiptr, 0,
105                         EDLN_UPDATE_MOVED|EDLN_UPDATE_CHANGED|
106                         EDLN_UPDATE_NEW);
107     }
108
109 }
110
111
112 void edln_set_completion(Edln *edln, const char *comp, 
113                          const char *beg, const char *end)
114 {
115     edln_do_set_completion(edln, comp, strlen(comp), beg, end);
116 }
117
118
119 int edln_do_completions(Edln *edln, char **completions, int ncomp,
120                         const char *beg, const char *end, bool setcommon,
121                         bool nosort)
122 {
123     int len;
124     int i;
125     
126     if(ncomp==0){
127         return 0;
128     }else if(ncomp==1){
129         len=strlen(completions[0]);
130     }else{
131         if(!nosort)
132             qsort(completions, ncomp, sizeof(char**), compare);
133         len=get_common_part_rmdup(completions, &ncomp);
134     }
135     
136     if(setcommon)
137         edln_do_set_completion(edln, completions[0], len, beg, end);
138     
139     return ncomp;
140 }
141
142
143 /*}}}*/
144
145
146 /*{{{ WComplProxy */
147
148
149 bool complproxy_init(WComplProxy *proxy, WEdln *wedln, int id, int cycle)
150 {
151     watch_init(&(proxy->wedln_watch));
152     if(!watch_setup(&(proxy->wedln_watch), (Obj*)wedln, NULL))
153         return FALSE;
154     
155     proxy->id=id;
156     proxy->cycle=cycle;
157     
158     return TRUE;
159 }
160
161
162 WComplProxy *create_complproxy(WEdln *wedln, int id, int cycle)
163 {
164     CREATEOBJ_IMPL(WComplProxy, complproxy, (p, wedln, id, cycle));
165 }
166
167
168 void complproxy_deinit(WComplProxy *proxy)
169 {
170     watch_reset(&(proxy->wedln_watch));
171 }
172
173
174 /*EXTL_DOC
175  * Set completion list of the \type{WEdln} that \var{proxy} refers to to
176  * \var{compls}, if it is still waiting for this completion run. The 
177  * numerical indexes of \var{compls} list the found completions. If the
178  * entry \var{common_beg} (\var{common_end}) exists, it gives an extra 
179  * common prefix (suffix) of all found completions.
180  */
181 EXTL_EXPORT_MEMBER
182 bool complproxy_set_completions(WComplProxy *proxy, ExtlTab compls)
183 {
184     WEdln *wedln=(WEdln*)proxy->wedln_watch.obj;
185     
186     if(wedln!=NULL){
187         if(wedln->compl_waiting_id==proxy->id){
188             wedln_set_completions(wedln, compls, proxy->cycle);
189             wedln->compl_current_id=proxy->id;
190             return TRUE;
191         }
192     }
193     
194     return FALSE;
195 }
196
197
198 EXTL_EXPORT
199 IMPLCLASS(WComplProxy, Obj, complproxy_deinit, NULL);
200
201
202 /*}}}*/
203