Introduction
Introduction Statistics Contact Development Disclaimer Help
dmenu-vi_mode-20230416-0fe460d.diff - sites - public wiki contents of suckless.…
git clone git://git.suckless.org/sites
Log
Files
Refs
---
dmenu-vi_mode-20230416-0fe460d.diff (7192B)
---
1 diff --git a/config.def.h b/config.def.h
2 index 1edb647..7bf5f4a 100644
3 --- a/config.def.h
4 +++ b/config.def.h
5 @@ -12,6 +12,7 @@ static const char *colors[SchemeLast][2] = {
6 [SchemeNorm] = { "#bbbbbb", "#222222" },
7 [SchemeSel] = { "#eeeeee", "#005577" },
8 [SchemeOut] = { "#000000", "#00ffff" },
9 + [SchemeCursor] = { "#222222", "#bbbbbb"},
10 };
11 /* -l option; if nonzero, dmenu uses vertical list with given number of…
12 static unsigned int lines = 0;
13 @@ -21,3 +22,15 @@ static unsigned int lines = 0;
14 * for example: " /?\"&[]"
15 */
16 static const char worddelimiters[] = " ";
17 +
18 +/*
19 + * -vi option; if nonzero, vi mode is always enabled and can be
20 + * accessed with the global_esc keysym + mod mask
21 + */
22 +static unsigned int vi_mode = 1;
23 +static unsigned int start_mode = 0; /* mode to u…
24 +static Key global_esc = { XK_n, Mod1Mask }; /* escape key when v…
25 +static Key quit_keys[] = {
26 + /* keysym modifier */
27 + { XK_q, 0 }
28 +};
29 diff --git a/dmenu.c b/dmenu.c
30 index 62f1089..8066271 100644
31 --- a/dmenu.c
32 +++ b/dmenu.c
33 @@ -26,7 +26,7 @@
34 #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
35
36 /* enums */
37 -enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes…
38 +enum { SchemeNorm, SchemeSel, SchemeOut, SchemeCursor, SchemeLast }; /*…
39
40 struct item {
41 char *text;
42 @@ -34,6 +34,11 @@ struct item {
43 int out;
44 };
45
46 +typedef struct {
47 + KeySym ksym;
48 + unsigned int state;
49 +} Key;
50 +
51 static char text[BUFSIZ] = "";
52 static char *embed;
53 static int bh, mw, mh;
54 @@ -44,6 +49,7 @@ static struct item *items = NULL;
55 static struct item *matches, *matchend;
56 static struct item *prev, *curr, *next, *sel;
57 static int mon = -1, screen;
58 +static unsigned int using_vi_mode = 0;
59
60 static Atom clip, utf8;
61 static Display *dpy;
62 @@ -163,7 +169,15 @@ drawmenu(void)
63 drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
64
65 curpos = TEXTW(text) - TEXTW(&text[cursor]);
66 - if ((curpos += lrpad / 2 - 1) < w) {
67 + curpos += lrpad / 2 - 1;
68 + if (using_vi_mode && text[0] != '\0') {
69 + drw_setscheme(drw, scheme[SchemeCursor]);
70 + char vi_char[] = {text[cursor], '\0'};
71 + drw_text(drw, x + curpos, 0, TEXTW(vi_char) - lrpad, bh…
72 + } else if (using_vi_mode) {
73 + drw_setscheme(drw, scheme[SchemeNorm]);
74 + drw_rect(drw, x + curpos, 2, lrpad / 2, bh - 4, 1, 0);
75 + } else if (curpos < w) {
76 drw_setscheme(drw, scheme[SchemeNorm]);
77 drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
78 }
79 @@ -321,6 +335,181 @@ movewordedge(int dir)
80 }
81 }
82
83 +static void
84 +vi_keypress(KeySym ksym, const XKeyEvent *ev)
85 +{
86 + static const size_t quit_len = LENGTH(quit_keys);
87 + if (ev->state & ControlMask) {
88 + switch(ksym) {
89 + /* movement */
90 + case XK_d: /* fallthrough */
91 + if (next) {
92 + sel = curr = next;
93 + calcoffsets();
94 + goto draw;
95 + } else
96 + ksym = XK_G;
97 + break;
98 + case XK_u:
99 + if (prev) {
100 + sel = curr = prev;
101 + calcoffsets();
102 + goto draw;
103 + } else
104 + ksym = XK_g;
105 + break;
106 + case XK_p: /* fallthrough */
107 + case XK_P: break;
108 + case XK_c:
109 + cleanup();
110 + exit(1);
111 + case XK_Return: /* fallthrough */
112 + case XK_KP_Enter: break;
113 + default: return;
114 + }
115 + }
116 +
117 + switch(ksym) {
118 + /* movement */
119 + case XK_0:
120 + cursor = 0;
121 + break;
122 + case XK_dollar:
123 + if (text[cursor + 1] != '\0') {
124 + cursor = strlen(text) - 1;
125 + break;
126 + }
127 + break;
128 + case XK_b:
129 + movewordedge(-1);
130 + break;
131 + case XK_e:
132 + cursor = nextrune(+1);
133 + movewordedge(+1);
134 + if (text[cursor] == '\0')
135 + --cursor;
136 + else
137 + cursor = nextrune(-1);
138 + break;
139 + case XK_g:
140 + if (sel == matches) {
141 + break;
142 + }
143 + sel = curr = matches;
144 + calcoffsets();
145 + break;
146 + case XK_G:
147 + if (next) {
148 + /* jump to end of list and position items in re…
149 + curr = matchend;
150 + calcoffsets();
151 + curr = prev;
152 + calcoffsets();
153 + while (next && (curr = curr->right))
154 + calcoffsets();
155 + }
156 + sel = matchend;
157 + break;
158 + case XK_h:
159 + if (cursor)
160 + cursor = nextrune(-1);
161 + break;
162 + case XK_j:
163 + if (sel && sel->right && (sel = sel->right) == next) {
164 + curr = next;
165 + calcoffsets();
166 + }
167 + break;
168 + case XK_k:
169 + if (sel && sel->left && (sel = sel->left)->right == cur…
170 + curr = prev;
171 + calcoffsets();
172 + }
173 + break;
174 + case XK_l:
175 + if (text[cursor] != '\0' && text[cursor + 1] != '\0')
176 + cursor = nextrune(+1);
177 + else if (text[cursor] == '\0' && cursor)
178 + --cursor;
179 + break;
180 + case XK_w:
181 + movewordedge(+1);
182 + if (text[cursor] != '\0' && text[cursor + 1] != '\0')
183 + cursor = nextrune(+1);
184 + else if (cursor)
185 + --cursor;
186 + break;
187 + /* insertion */
188 + case XK_a:
189 + cursor = nextrune(+1);
190 + /* fallthrough */
191 + case XK_i:
192 + using_vi_mode = 0;
193 + break;
194 + case XK_A:
195 + if (text[cursor] != '\0')
196 + cursor = strlen(text);
197 + using_vi_mode = 0;
198 + break;
199 + case XK_I:
200 + cursor = using_vi_mode = 0;
201 + break;
202 + case XK_p:
203 + if (text[cursor] != '\0')
204 + cursor = nextrune(+1);
205 + XConvertSelection(dpy, (ev->state & ControlMask) ? clip…
206 + utf8, utf8, win…
207 + return;
208 + case XK_P:
209 + XConvertSelection(dpy, (ev->state & ControlMask) ? clip…
210 + utf8, utf8, win…
211 + return;
212 + /* deletion */
213 + case XK_D:
214 + text[cursor] = '\0';
215 + if (cursor)
216 + cursor = nextrune(-1);
217 + match();
218 + break;
219 + case XK_x:
220 + cursor = nextrune(+1);
221 + insert(NULL, nextrune(-1) - cursor);
222 + if (text[cursor] == '\0' && text[0] != '\0')
223 + --cursor;
224 + match();
225 + break;
226 + /* misc. */
227 + case XK_Return:
228 + case XK_KP_Enter:
229 + puts((sel && !(ev->state & ShiftMask)) ? sel->text : te…
230 + if (!(ev->state & ControlMask)) {
231 + cleanup();
232 + exit(0);
233 + }
234 + if (sel)
235 + sel->out = 1;
236 + break;
237 + case XK_Tab:
238 + if (!sel)
239 + return;
240 + strncpy(text, sel->text, sizeof text - 1);
241 + text[sizeof text - 1] = '\0';
242 + cursor = strlen(text) - 1;
243 + match();
244 + break;
245 + default:
246 + for (size_t i = 0; i < quit_len; ++i)
247 + if (quit_keys[i].ksym == ksym &&
248 + (quit_keys[i].state & ev->state) == qui…
249 + cleanup();
250 + exit(1);
251 + }
252 + }
253 +
254 +draw:
255 + drawmenu();
256 +}
257 +
258 static void
259 keypress(XKeyEvent *ev)
260 {
261 @@ -340,6 +529,18 @@ keypress(XKeyEvent *ev)
262 break;
263 }
264
265 + if (using_vi_mode) {
266 + vi_keypress(ksym, ev);
267 + return;
268 + } else if (vi_mode &&
269 + (ksym == global_esc.ksym &&
270 + (ev->state & global_esc.state) == globa…
271 + using_vi_mode = 1;
272 + if (cursor)
273 + cursor = nextrune(-1);
274 + goto draw;
275 + }
276 +
277 if (ev->state & ControlMask) {
278 switch(ksym) {
279 case XK_a: ksym = XK_Home; break;
280 @@ -543,6 +744,8 @@ paste(void)
281 insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strl…
282 XFree(p);
283 }
284 + if (using_vi_mode && text[cursor] == '\0')
285 + --cursor;
286 drawmenu();
287 }
288
289 @@ -738,6 +941,11 @@ main(int argc, char *argv[])
290 else if (!strcmp(argv[i], "-i")) { /* case-insensitive …
291 fstrncmp = strncasecmp;
292 fstrstr = cistrstr;
293 + } else if (!strcmp(argv[i], "-vi")) {
294 + vi_mode = 1;
295 + using_vi_mode = start_mode;
296 + global_esc.ksym = XK_Escape;
297 + global_esc.state = 0;
298 } else if (i + 1 == argc)
299 usage();
300 /* these options take one argument */
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.