Mercurial > ~mikael > mcabber > hg
annotate mcabber/src/compl.c @ 830:80434fde7cfa
Display presence notification timestamps when they exist
These timestamps were used in the roster, but not in the buffer window
message nor in the history logfile. Reported by "ze".
author | Mikael Berthe <mikael@lilotux.net> |
---|---|
date | Wed, 03 May 2006 11:28:41 +0200 |
parents | 80bd7f49075f |
children | f76b32ff2f14 |
rev | line source |
---|---|
94 | 1 /* |
2 * compl.c -- Completion system | |
393 | 3 * |
699 | 4 * Copyright (C) 2005, 2006 Mikael Berthe <bmikael@lists.lilotux.net> |
94 | 5 * |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or (at | |
9 * your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, but | |
12 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 * General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | |
19 * USA | |
20 */ | |
21 | |
22 /* Usage, basically: | |
23 * - new_completion(); // 1. Initialization | |
24 * - complete(); // 2. 1st completion | |
25 * - cancel_completion(); // 3a. 2nd completion / cancel previous | |
26 * - complete(); // 3b. 2nd completion / complete | |
27 * ... | |
28 * - done_completion(); // n. finished -- free allocated areas | |
29 * | |
30 */ | |
31 | |
32 #include <string.h> | |
33 | |
34 #include "compl.h" | |
225 | 35 #include "roster.h" |
757
ae23c8826efb
Improve completion for the "/event" command
Mikael Berthe <mikael@lilotux.net>
parents:
735
diff
changeset
|
36 #include "events.h" |
94 | 37 |
38 // Completion structure | |
39 typedef struct { | |
40 GSList *list; // list of matches | |
41 guint len_prefix; // length of text already typed by the user | |
42 guint len_compl; // length of the last completion | |
43 GSList *next; // pointer to next completion to try | |
44 } compl; | |
45 | |
46 // Category structure | |
47 typedef struct { | |
48 guint flag; | |
49 GSList *words; | |
50 } category; | |
51 | |
52 static GSList *Categories; | |
53 static compl *InputCompl; | |
54 | |
55 // new_completion(prefix, compl_cat) | |
56 // . prefix = beginning of the word, typed by the user | |
57 // . compl_cat = pointer to a completion category list (list of *char) | |
58 // Returns a pointer to an allocated compl structure. This structure should | |
59 // be freed by the caller when not used anymore. | |
60 void new_completion(char *prefix, GSList *compl_cat) | |
61 { | |
62 compl *c; | |
63 GSList *sl_cat; | |
735 | 64 size_t len = strlen(prefix); |
94 | 65 |
66 if (InputCompl) { // This should not happen, but hey... | |
67 cancel_completion(); | |
68 } | |
69 | |
70 c = g_new0(compl, 1); | |
71 // Build the list of matches | |
72 for (sl_cat=compl_cat; sl_cat; sl_cat = g_slist_next(sl_cat)) { | |
73 char *word = sl_cat->data; | |
104 | 74 if (!strncasecmp(prefix, word, len)) { |
98 | 75 if (strlen(word) != len) |
76 c->list = g_slist_append(c->list, g_strdup(word+len)); // TODO sort | |
94 | 77 } |
78 } | |
79 c->next = c->list; | |
80 InputCompl = c; | |
81 } | |
82 | |
83 // done_completion(); | |
84 void done_completion(void) | |
85 { | |
98 | 86 if (!InputCompl) return; |
87 | |
94 | 88 // TODO free everything |
89 g_slist_free(InputCompl->list); | |
90 g_free(InputCompl); | |
91 InputCompl = NULL; | |
92 } | |
93 | |
94 // cancel_completion() | |
95 // Returns the number of chars to delete to cancel the completion | |
96 //guint cancel_completion(compl *c) | |
97 guint cancel_completion(void) | |
98 { | |
98 | 99 if (!InputCompl) return 0; |
94 | 100 return InputCompl->len_compl; |
101 } | |
102 | |
103 // Returns pointer to text to insert, NULL if no completion. | |
104 const char *complete() | |
105 { | |
106 compl* c = InputCompl; | |
107 char *r; | |
98 | 108 |
109 if (!InputCompl) return NULL; | |
110 | |
94 | 111 if (!c->next) { |
112 c->next = c->list; // back to the beginning | |
113 c->len_compl = 0; | |
114 return NULL; | |
115 } | |
116 r = (char*)c->next->data; | |
117 c->next = g_slist_next(c->next); | |
118 c->len_compl = strlen(r); | |
119 return r; | |
120 } | |
121 | |
122 | |
123 /* Categories functions */ | |
124 | |
95 | 125 // compl_add_category_word(categ, command) |
126 // Adds a keyword as a possible completion in category categ. | |
127 void compl_add_category_word(guint categ, const char *word) | |
94 | 128 { |
129 GSList *sl_cat; | |
130 category *cat; | |
121 | 131 char *nword; |
94 | 132 // Look for category |
133 for (sl_cat=Categories; sl_cat; sl_cat = g_slist_next(sl_cat)) { | |
134 if (categ == ((category*)sl_cat->data)->flag) | |
135 break; | |
136 } | |
137 if (!sl_cat) { // Category not found, let's create it | |
138 cat = g_new0(category, 1); | |
139 cat->flag = categ; | |
140 Categories = g_slist_append(Categories, cat); | |
141 } else | |
142 cat = (category*)sl_cat->data; | |
143 | |
121 | 144 // If word is not space-terminated, we add one trailing space |
145 for (nword = (char*)word; *nword; nword++) | |
146 ; | |
147 if (nword > word) nword--; | |
148 if (*nword != ' ') { // Add a space | |
149 nword = g_new(char, strlen(word)+2); | |
150 strcpy(nword, word); | |
151 strcat(nword, " "); | |
152 } else { // word is fine | |
153 nword = g_strdup(word); | |
154 } | |
155 | |
94 | 156 // TODO Check word does not already exist |
121 | 157 cat->words = g_slist_append(cat->words, nword); // TODO sort |
94 | 158 } |
159 | |
284
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
160 // compl_del_category_word(categ, command) |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
161 // Removes a keyword from category categ in completion list. |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
162 void compl_del_category_word(guint categ, const char *word) |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
163 { |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
164 GSList *sl_cat, *sl_elt; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
165 category *cat; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
166 char *nword; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
167 // Look for category |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
168 for (sl_cat=Categories; sl_cat; sl_cat = g_slist_next(sl_cat)) { |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
169 if (categ == ((category*)sl_cat->data)->flag) |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
170 break; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
171 } |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
172 if (!sl_cat) return; // Category not found, finished! |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
173 |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
174 cat = (category*)sl_cat->data; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
175 |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
176 // If word is not space-terminated, we add one trailing space |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
177 for (nword = (char*)word; *nword; nword++) |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
178 ; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
179 if (nword > word) nword--; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
180 if (*nword != ' ') { // Add a space |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
181 nword = g_new(char, strlen(word)+2); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
182 strcpy(nword, word); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
183 strcat(nword, " "); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
184 } else { // word is fine |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
185 nword = g_strdup(word); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
186 } |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
187 |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
188 sl_elt = cat->words; |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
189 while (sl_elt) { |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
190 if (!strcasecmp((char*)sl_elt->data, nword)) { |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
191 g_free(sl_elt->data); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
192 cat->words = g_slist_delete_link(cat->words, sl_elt); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
193 break; // Only remove first occurence |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
194 } |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
195 sl_elt = g_slist_next(sl_elt); |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
196 } |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
197 } |
f879b17ecb8e
Add compl_del_category_word()
Mikael Berthe <mikael@lilotux.net>
parents:
225
diff
changeset
|
198 |
95 | 199 // compl_get_category_list() |
200 // Returns a slist of all words in the categories specified by the given flags | |
94 | 201 GSList *compl_get_category_list(guint cat_flags) |
202 { | |
203 GSList *sl_cat; | |
204 // Look for category | |
205 // XXX Actually that's not that simple... cat_flags can be a combination | |
206 // of several flags! | |
207 for (sl_cat=Categories; sl_cat; sl_cat = g_slist_next(sl_cat)) { | |
208 if (cat_flags == ((category*)sl_cat->data)->flag) | |
209 break; | |
210 } | |
211 if (sl_cat) // Category was found, easy... | |
212 return ((category*)sl_cat->data)->words; | |
213 | |
225 | 214 // Handle dynamic SLists |
215 if (cat_flags == COMPL_GROUPNAME) { | |
216 return compl_list(ROSTER_TYPE_GROUP); | |
217 } | |
218 if (cat_flags == COMPL_JID) { | |
219 return compl_list(ROSTER_TYPE_USER); | |
220 } | |
501
7c1ca00070e8
Add COMPL_RESOURCE (resource completion category)
Mikael Berthe <mikael@lilotux.net>
parents:
393
diff
changeset
|
221 if (cat_flags == COMPL_RESOURCE) { |
792
89ad7b530b3c
MUC: Fix completion for UTF-8 nicknames
Mikael Berthe <mikael@lilotux.net>
parents:
757
diff
changeset
|
222 return buddy_getresources_locale(NULL); |
501
7c1ca00070e8
Add COMPL_RESOURCE (resource completion category)
Mikael Berthe <mikael@lilotux.net>
parents:
393
diff
changeset
|
223 } |
757
ae23c8826efb
Improve completion for the "/event" command
Mikael Berthe <mikael@lilotux.net>
parents:
735
diff
changeset
|
224 if (cat_flags == COMPL_EVENTSID) { |
820
80bd7f49075f
Allow '*' in /event command
Mikael Berthe <mikael@lilotux.net>
parents:
792
diff
changeset
|
225 return evs_geteventslist(TRUE); |
757
ae23c8826efb
Improve completion for the "/event" command
Mikael Berthe <mikael@lilotux.net>
parents:
735
diff
changeset
|
226 } |
225 | 227 |
94 | 228 return NULL; |
229 } | |
230 | |
580 | 231 /* vim: set expandtab cindent cinoptions=>2\:2(0: For Vim users... */ |