geevi: set window default size
[geevi.git] / cmd.c
blob71ca6eeb01cc0130f2770d54b0f5845c8df4dfef
1 #include <string.h>
2 #include <ctype.h>
3 #include <gtk/gtk.h>
4 #include <gdk/gdkkeysyms.h>
5 #include "geevi.h"
6 #include "im.h"
8 static void mkmm(struct movement *mm, int count, enum movekind kind)
10 mm->count = count;
11 mm->kind = kind;
12 mm->eolfix = 1;
15 static void mkmm_noeolfix(struct movement *mm, int count, enum movekind kind)
17 mkmm(mm, count, kind);
18 mm->eolfix = 0;
21 static void command_line_mode(struct vi *vi, char *init);
23 static int read_movement_key(struct vi *vi, GdkEventKey *event)
25 struct movement *mm = &vi->mm;
26 if (mm->pending) {
27 mm->pending = 0;
28 switch (mm->kind) {
29 case MM_MARK:
30 mm->arg.m = event->keyval;
31 return 0;
32 case MM_SEARCH:
33 mm->arg.s = vi->word;
34 return 0;
35 case MM_CFIND:
36 mm->arg.c = event->keyval;
37 return 0;
38 default:
39 return 1;
42 memset(&vi->mm, 0, sizeof(vi->mm));
43 switch(event->keyval) {
44 case GDK_j:
45 mkmm(mm, 1, MM_LINE);
46 break;
47 case GDK_k:
48 mkmm(mm, -1, MM_LINE);
49 break;
50 case GDK_l:
51 mkmm(mm, 1, MM_CHAR);
52 break;
53 case GDK_h:
54 mkmm(mm, -1, MM_CHAR);
55 break;
56 case GDK_dollar:
57 mkmm(mm, 1, MM_EOL);
58 break;
59 case GDK_e:
60 mkmm(mm, 1, MM_WORDEND);
61 break;
62 case GDK_b:
63 mkmm(mm, -1, MM_WORDSTART);
64 break;
65 case GDK_w:
66 mkmm(mm, 1, MM_WORDSTART);
67 break;
68 case GDK_0:
69 mkmm(mm, 1, MM_FIRST);
70 break;
71 case GDK_asciicircum:
72 mkmm(mm, 1, MM_FIRSTNB);
73 break;
74 case GDK_G:
75 mkmm(mm, 1, MM_GOTOLINE);
76 break;
77 case GDK_d:
78 mkmm_noeolfix(mm, 1, MM_WHOLELINE);
79 mm->onemore = 1;
80 break;
81 case GDK_c:
82 mkmm_noeolfix(mm, 1, MM_WHOLELINE);
83 break;
84 case GDK_quoteleft:
85 mkmm(mm, 1, MM_MARK);
86 mm->pending = 1;
87 break;
88 case GDK_H:
89 mkmm(mm, 1, MM_TOP);
90 break;
91 case GDK_M:
92 mkmm(mm, 1, MM_CENTER);
93 break;
94 case GDK_L:
95 mkmm(mm, 1, MM_BOTTOM);
96 break;
97 case GDK_slash:
98 mkmm(mm, 1, MM_SEARCH);
99 mm->pending = 1;
100 command_line_mode(vi, "/");
101 break;
102 case GDK_question:
103 mkmm(mm, -1, MM_SEARCH);
104 mm->pending = 1;
105 command_line_mode(vi, "?");
106 break;
107 case GDK_n:
108 mkmm(mm, 1, MM_SEARCH);
109 mm->arg.s = vi->word;
110 break;
111 case GDK_N:
112 mkmm(mm, -1, MM_SEARCH);
113 mm->arg.s = vi->word;
114 break;
115 case GDK_f:
116 mkmm(mm, 1, MM_CFIND);
117 mm->pending = 1;
118 break;
119 case GDK_F:
120 mkmm(mm, -1, MM_CFIND);
121 mm->pending = 1;
122 break;
123 default:
124 return 1;
126 return 0;
129 static void set_mm_onemore(struct movement *mm)
131 if (mm->kind == MM_WORDEND || mm->kind == MM_EOL)
132 mm->onemore = 1;
135 static GtkTextBuffer *vi_buffer(struct vi *vi)
137 return gtk_text_view_get_buffer(GTK_TEXT_VIEW(vi->view));
140 static void insert_mode(struct vi *vi);
142 static void perform_move_command(
143 struct vi *vi, struct movement *mm,
144 void (*perform)(struct vi *vi, GtkTextIter *iter,
145 GtkTextIter *start))
147 GtkTextIter start, iter;
148 cursor_get(GTK_TEXT_VIEW(vi->view), &iter);
149 start = iter;
150 moveiter(GTK_TEXT_VIEW(vi->view), mm, &iter, &start);
151 perform(vi, &iter, &start);
152 cursor_place(GTK_TEXT_VIEW(vi->view), &iter);
155 static void dodel(struct vi *vi, GtkTextIter *iter, GtkTextIter *start)
157 gtk_text_buffer_delete(vi_buffer(vi), start, iter);
158 cursor_place(GTK_TEXT_VIEW(vi->view), iter);
161 static void domove(struct vi *vi, GtkTextIter *iter, GtkTextIter *start)
163 cursor_place(GTK_TEXT_VIEW(vi->view), iter);
166 static void dochange(struct vi *vi, GtkTextIter *iter, GtkTextIter *start)
168 gtk_text_buffer_delete(vi_buffer(vi), start, iter);
169 insert_mode(vi);
172 static int delctx(struct vi *vi, GdkEventKey *event)
174 if (!read_movement_key(vi, event)) {
175 if (vi->mm.pending)
176 return 0;
177 set_mm_onemore(&vi->mm);
178 perform_move_command(vi, &vi->mm, dodel);
180 return 1;
183 static int changectx(struct vi *vi, GdkEventKey *event)
185 if (!read_movement_key(vi, event)) {
186 if (vi->mm.pending)
187 return 0;
188 set_mm_onemore(&vi->mm);
189 perform_move_command(vi, &vi->mm, dochange);
191 return 1;
194 static int scrollctx(struct vi *vi, GdkEventKey *event)
196 GtkTextIter iter;
197 double align;
198 cursor_get(GTK_TEXT_VIEW(vi->view), &iter);
199 switch(event->keyval) {
200 case GDK_Return:
201 align = 0.0;
202 break;
203 case GDK_period:
204 align = 0.5;
205 break;
206 case GDK_minus:
207 align = 1.0;
208 break;
209 default:
210 return 1;
212 gtk_text_iter_set_line_offset(&iter, 0);
213 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(vi->view), &iter,
214 0.0, TRUE, 0, align);
215 return 1;
218 static int replacectx(struct vi *vi, GdkEventKey *event)
220 GtkTextIter start, end;
221 GtkTextBuffer *buffer = vi_buffer(vi);
222 char *imc;
223 int key = event->keyval;
224 int mod = event->state & gtk_accelerator_get_default_mod_mask();
225 if (mod == GDK_CONTROL_MASK)
226 return 1;
227 cursor_get(GTK_TEXT_VIEW(vi->view), &start);
228 end = start;
229 gtk_text_iter_forward_char(&end);
230 gtk_text_buffer_delete(buffer, &start, &end);
231 if (vi->im && (imc = im_char(vi->im, key))) {
232 gtk_text_buffer_insert(buffer, &start, imc, strlen(imc));
233 } else {
234 char c = key;
235 gtk_text_buffer_insert(buffer, &start, &c, 1);
237 cursor_redraw(GTK_TEXT_VIEW(vi->view));
238 return 1;
241 static int markctx(struct vi *vi, GdkEventKey *event)
243 GtkTextIter iter;
244 GtkTextBuffer *buffer = vi_buffer(vi);
245 cursor_get(GTK_TEXT_VIEW(vi->view), &iter);
246 if (isprint(event->keyval)) {
247 char name[2];
248 name[0] = event->keyval;
249 name[1] = '\0';
250 gtk_text_buffer_create_mark(buffer, name, &iter, 1);
252 return 1;
255 static void move(struct vi *vi, struct movement *mm)
257 perform_move_command(vi, mm, domove);
260 static void normal_mode(struct vi *vi)
262 struct movement mm;
263 if (vi->mode == EM_INSERT) {
264 mkmm(&mm, -1, MM_CHAR);
265 move(vi, &mm);
267 vi->mode = EM_NORMAL;
268 gtk_widget_grab_focus(vi->view);
271 static void insert_mode(struct vi *vi)
273 vi->mode = EM_INSERT;
274 gtk_widget_grab_focus(vi->view);
277 static void ex_mode(struct vi *vi)
279 vi->mode = EM_EX;
280 gtk_widget_grab_focus(vi->entry);
283 static void command_line_mode(struct vi *vi, char *init)
285 ex_mode(vi);
286 gtk_entry_set_text(GTK_ENTRY(vi->entry), init);
287 gtk_editable_set_position(GTK_EDITABLE(vi->entry), -1);
290 static void move_page(GtkTextView *view, int count)
292 GdkRectangle rect;
293 GtkTextIter iter;
294 GtkTextBuffer *buffer;
295 int y;
296 int yalign = count > 0 ? 0.0 : 1.0;
297 buffer = gtk_text_view_get_buffer(view);
298 gtk_text_view_get_visible_rect(view, &rect);
299 y = rect.y + (count > 0 ? count : count + 1) * rect.height;
300 gtk_text_view_get_iter_at_location(view, &iter, 0, y);
301 cursor_place(view, &iter);
302 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(view), &iter,
303 0.0, TRUE, 0, yalign);
306 static void openline(struct vi *vi, int n)
308 GtkTextIter iter;
309 GtkTextBuffer *buffer = vi_buffer(vi);
310 cursor_get(GTK_TEXT_VIEW(vi->view), &iter);
311 if (n > 0) {
312 gtk_text_iter_forward_to_line_end(&iter);
313 } else {
314 gtk_text_iter_set_line_offset(&iter, 0);
315 gtk_text_iter_backward_char(&iter);
317 gtk_text_buffer_insert(buffer, &iter, "\n", 1);
318 cursor_place(GTK_TEXT_VIEW(vi->view), &iter);
319 insert_mode(vi);
322 static void rmchar(struct vi *vi, int n)
324 GtkTextIter start, end;
325 GtkTextBuffer *buffer = vi_buffer(vi);
326 cursor_get(GTK_TEXT_VIEW(vi->view), &start);
327 end = start;
328 if (n > 0)
329 gtk_text_iter_forward_char(&end);
330 else
331 gtk_text_iter_backward_char(&start);
332 gtk_text_buffer_delete(buffer, &start, &end);
333 cursor_redraw(GTK_TEXT_VIEW(vi->view));
336 static void join(struct vi *vi, int n)
338 GtkTextIter start, end;
339 GtkTextBuffer *buffer = vi_buffer(vi);
340 cursor_get(GTK_TEXT_VIEW(vi->view), &start);
341 if (!gtk_text_iter_ends_line(&start))
342 gtk_text_iter_forward_to_line_end(&start);
343 end = start;
344 gtk_text_iter_forward_char(&end);
345 gtk_text_buffer_delete(buffer, &start, &end);
346 cursor_place(GTK_TEXT_VIEW(vi->view), &end);
349 static void del_till_eol(struct vi *vi, int change)
351 GtkTextIter start, end;
352 GtkTextBuffer *buffer = vi_buffer(vi);
353 cursor_get(GTK_TEXT_VIEW(vi->view), &start);
354 end = start;
355 if (!gtk_text_iter_ends_line(&end))
356 gtk_text_iter_forward_to_line_end(&end);
357 gtk_text_buffer_delete(buffer, &start, &end);
358 if (change) {
359 insert_mode(vi);
360 } else if (!gtk_text_iter_starts_line(&start)) {
361 gtk_text_iter_backward_char(&start);
362 cursor_place(GTK_TEXT_VIEW(vi->view), &start);
366 static int im_insert(struct vi *vi, int c)
368 char *s;
369 GtkTextBuffer *buffer = vi_buffer(vi);
370 s = im_char(vi->im, c);
371 if (s) {
372 gtk_text_buffer_insert_at_cursor(buffer, s, strlen(s));
373 return 0;
375 return 1;
378 int ex_ctx(struct vi *vi, GdkEventKey *event)
380 int key = event->keyval;
381 int mod = event->state & gtk_accelerator_get_default_mod_mask();
382 if (key == GDK_Escape) {
383 normal_mode(vi);
384 return 1;
386 /* execute command */
387 if (key == GDK_Return) {
388 char cmd[MAX_COMMAND_LENGTH];
389 strncpy(cmd, gtk_entry_get_text(GTK_ENTRY(vi->entry)),
390 sizeof(cmd));
391 cmd[sizeof(cmd) - 1] = '\0';
392 execcmd(vi, cmd);
393 normal_mode(vi);
394 if (vi->mm.pending)
395 vi->ctx(vi, event);
396 return 1;
398 /* insert normal keys */
399 if (mod != GDK_CONTROL_MASK)
400 return FALSE;
401 switch (key) {
402 case GDK_bracketleft:
403 case GDK_c:
404 normal_mode(vi);
405 return 1;
406 default:
407 return 0;
411 static int rootctx_insert(struct vi *vi, GdkEventKey *event)
413 int key = event->keyval;
414 int mod = event->state & gtk_accelerator_get_default_mod_mask();
415 if (key == GDK_Escape) {
416 normal_mode(vi);
417 return 1;
419 if (mod != GDK_CONTROL_MASK)
420 return vi->im && !im_insert(vi, key);
421 switch (key) {
422 case GDK_bracketleft:
423 case GDK_c:
424 normal_mode(vi);
425 return 1;
426 case GDK_6:
427 if (vi->im)
428 vi->im = NULL;
429 else
430 vi->im = vi->alt_im;
431 break;
432 default:
433 return 0;
435 return 1;
438 static int real_key(int c)
440 return c < 256 || c == GDK_Return;
443 int rootctx(struct vi *vi, GdkEventKey *event)
445 int mod = event->state & gtk_accelerator_get_default_mod_mask();
446 struct movement mm;
447 if (!real_key(event->keyval))
448 return 0;
449 if (vi->mode == EM_INSERT)
450 return rootctx_insert(vi, event);
451 /* handle normal mode binding */
452 if (vi->mm.pending) {
453 if (!read_movement_key(vi, event))
454 perform_move_command(vi, &vi->mm, domove);
455 return 1;
457 if (mod == GDK_CONTROL_MASK) {
458 switch (event->keyval) {
459 case GDK_f:
460 move_page(GTK_TEXT_VIEW(vi->view), 1);
461 break;
462 case GDK_b:
463 move_page(GTK_TEXT_VIEW(vi->view), -1);
464 break;
465 default:
466 break;
468 return 1;
470 switch (event->keyval) {
471 case GDK_i:
472 insert_mode(vi);
473 break;
474 case GDK_a:
475 mkmm_noeolfix(&mm, 1, MM_CHAR);
476 move(vi, &mm);
477 insert_mode(vi);
478 break;
479 case GDK_A:
480 mkmm_noeolfix(&mm, 1, MM_EOL);
481 move(vi, &mm);
482 insert_mode(vi);
483 break;
484 case GDK_I:
485 mkmm_noeolfix(&mm, 1, MM_FIRSTNB);
486 move(vi, &mm);
487 insert_mode(vi);
488 break;
489 case GDK_colon:
490 command_line_mode(vi, ":");
491 break;
492 case GDK_d:
493 vi->ctx = delctx;
494 break;
495 case GDK_c:
496 vi->ctx = changectx;
497 break;
498 case GDK_z:
499 vi->ctx = scrollctx;
500 break;
501 case GDK_o:
502 openline(vi, 1);
503 break;
504 case GDK_O:
505 openline(vi, -1);
506 break;
507 case GDK_x:
508 rmchar(vi, 1);
509 break;
510 case GDK_X:
511 rmchar(vi, -1);
512 break;
513 case GDK_J:
514 join(vi, 1);
515 break;
516 case GDK_r:
517 vi->ctx = replacectx;
518 break;
519 case GDK_m:
520 vi->ctx = markctx;
521 break;
522 case GDK_D:
523 del_till_eol(vi, 0);
524 break;
525 case GDK_C:
526 del_till_eol(vi, 1);
527 break;
528 default:
529 if (!read_movement_key(vi, event)) {
530 if (vi->mm.pending)
531 break;
532 perform_move_command(vi, &vi->mm, domove);
535 return 1;