A tiling window manager
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 207 lines 5.0 kB view raw
1/* 2 * Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <sabetts@vcn.bc.ca> 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License as published by the Free 6 * Software Foundation; either version 2 of the License, or (at your option) 7 * any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 16 * Place, Suite 330, Boston, MA 02111-1307 USA. 17 */ 18 19/* Needed on Linux for strcasestr */ 20#define _GNU_SOURCE 21#include <string.h> 22 23#include "sdorfehs.h" 24 25rp_completions * 26completions_new(completion_fn list_fn, enum completion_styles style) 27{ 28 rp_completions *c; 29 30 c = xmalloc(sizeof(rp_completions)); 31 32 INIT_LIST_HEAD(&c->completion_list); 33 c->complete_fn = list_fn; 34 c->last_match = NULL; 35 c->partial = NULL; 36 c->virgin = 1; 37 c->style = style; 38 39 return c; 40} 41 42void 43completions_free(rp_completions *c) 44{ 45 struct sbuf *cur; 46 struct list_head *tmp, *iter; 47 48 /* Clear our list */ 49 list_for_each_safe_entry(cur, iter, tmp, &c->completion_list, node) { 50 list_del(&cur->node); 51 sbuf_free(cur); 52 } 53 54 /* Free the partial string. */ 55 free(c->partial); 56 57 free(c); 58} 59 60static void 61completions_assign(rp_completions *c, struct list_head *new_list) 62{ 63 struct sbuf *cur; 64 struct list_head *tmp, *iter; 65 66 /* Clear our list */ 67 list_for_each_safe_entry(cur, iter, tmp, &c->completion_list, node) { 68 list_del(&cur->node); 69 sbuf_free(cur); 70 } 71 72 /* 73 * splice the list into completion_list. Note that we SHOULDN'T free 74 * new_list, because they share the same memory. 75 */ 76 INIT_LIST_HEAD(&c->completion_list); 77 list_splice(new_list, &c->completion_list); 78 79 list_first(c->last_match, &c->completion_list, node); 80} 81 82static void 83completions_update(rp_completions *c, char *partial) 84{ 85 struct list_head *new_list; 86 87 new_list = c->complete_fn(partial); 88 89 c->virgin = 0; 90 free(c->partial); 91 c->partial = xstrdup(partial); 92 93 completions_assign(c, new_list); 94 95 /* Free the head structure for our list. */ 96 free(new_list); 97} 98 99/* 100 * Return true if completion is an alternative for partial string, given the 101 * style used. 102 */ 103static int 104completions_match(rp_completions *c, char *completion, char *partial) 105{ 106 int match = 0; 107 108 switch (c->style) { 109 case BASIC: 110 match = str_comp(completion, partial, strlen(partial)); 111 break; 112 case SUBSTRING: 113 match = (strcasestr(completion, partial) != NULL); 114 break; 115 } 116 117 return match; 118} 119 120static char * 121completions_prev_match(rp_completions *c) 122{ 123 struct sbuf *cur; 124 125 /* 126 * search forward from our last match through the list looking for 127 * another match. 128 */ 129 for (cur = list_prev_entry(c->last_match, &c->completion_list, node); 130 cur != c->last_match; 131 cur = list_prev_entry(cur, &c->completion_list, node)) { 132 if (completions_match(c, sbuf_get(cur), c->partial)) { 133 /* 134 * We found a match so update our last_match pointer 135 * and return the string. 136 */ 137 c->last_match = cur; 138 return sbuf_get(cur); 139 } 140 } 141 142 return NULL; 143} 144 145static char * 146completions_next_match(rp_completions *c) 147{ 148 struct sbuf *cur; 149 150 /* 151 * search forward from our last match through the list looking for 152 * another match. 153 */ 154 for (cur = list_next_entry(c->last_match, &c->completion_list, node); 155 cur != c->last_match; 156 cur = list_next_entry(cur, &c->completion_list, node)) { 157 if (completions_match(c, sbuf_get(cur), c->partial)) { 158 /* 159 * We found a match so update our last_match pointer 160 * and return the string. 161 */ 162 c->last_match = cur; 163 return sbuf_get(cur); 164 } 165 } 166 167 return NULL; 168} 169 170/* Return a completed string that starts with partial. */ 171char * 172completions_complete(rp_completions *c, char *partial, int direction) 173{ 174 if (c->virgin) { 175 completions_update(c, partial); 176 177 /* 178 * Since it's never been completed on and c->last_match points 179 * to the first element of the list which may be a match. So 180 * check it. FIXME: This is a bit of a hack. 181 */ 182 if (c->last_match == NULL) 183 return NULL; 184 185 /* 186 * c->last_match contains the first match in the forward 187 * direction. So if we're looking for the previous match, then 188 * check the previous element from last_match. 189 */ 190 if (direction == COMPLETION_PREVIOUS) 191 c->last_match = list_prev_entry(c->last_match, 192 &c->completion_list, node); 193 194 /* Now check if last_match is a match for partial. */ 195 if (completions_match(c, sbuf_get(c->last_match), c->partial)) 196 return sbuf_get(c->last_match); 197 } 198 if (c->last_match == NULL) 199 return NULL; 200 201 /* Depending on the direction, find our "next" match. */ 202 if (direction == COMPLETION_NEXT) 203 return completions_next_match(c); 204 205 /* Otherwise get the previous match */ 206 return completions_prev_match(c); 207}