]> git.sur5r.net Git - i3/i3/blob - src/cmdparse.y
5400d76509d72be4ad5d4d98ee172308af0957d0
[i3/i3] / src / cmdparse.y
1 %{
2 /*
3  * vim:ts=4:sw=4:expandtab
4  *
5  * i3 - an improved dynamic tiling window manager
6  * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
7  *
8  * cmdparse.y: the parser for commands you send to i3 (or bind on keys)
9  *
10  */
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <float.h>
16
17 #include "all.h"
18
19 typedef struct yy_buffer_state *YY_BUFFER_STATE;
20 extern int cmdyylex(struct context *context);
21 extern int cmdyyparse(void);
22 extern int cmdyylex_destroy(void);
23 extern FILE *cmdyyin;
24 YY_BUFFER_STATE cmdyy_scan_string(const char *);
25
26 static struct context *context;
27 static Match current_match;
28
29 /* Holds the JSON which will be returned via IPC or NULL for the default return
30  * message */
31 static char *json_output;
32
33 /* We don’t need yydebug for now, as we got decent error messages using
34  * yyerror(). Should you ever want to extend the parser, it might be handy
35  * to just comment it in again, so it stays here. */
36 //int cmdyydebug = 1;
37
38 void cmdyyerror(const char *error_message) {
39     ELOG("\n");
40     ELOG("CMD: %s\n", error_message);
41     ELOG("CMD: in command:\n");
42     ELOG("CMD:   %s\n", context->line_copy);
43     ELOG("CMD:   ");
44     for (int c = 1; c <= context->last_column; c++)
45         if (c >= context->first_column)
46                 printf("^");
47         else printf(" ");
48     printf("\n");
49     ELOG("\n");
50     context->compact_error = sstrdup(error_message);
51 }
52
53 int cmdyywrap() {
54     return 1;
55 }
56
57 char *parse_cmd(const char *new) {
58     json_output = NULL;
59     LOG("COMMAND: *%s*\n", new);
60     cmdyy_scan_string(new);
61
62     cmd_criteria_init(&current_match);
63     context = scalloc(sizeof(struct context));
64     context->filename = "cmd";
65     if (cmdyyparse() != 0) {
66         fprintf(stderr, "Could not parse command\n");
67         sasprintf(&json_output, "{\"success\":false, \"error\":\"%s at position %d\"}",
68                   context->compact_error, context->first_column);
69         FREE(context->line_copy);
70         FREE(context->compact_error);
71         free(context);
72         return json_output;
73     }
74     printf("done, json output = %s\n", json_output);
75
76     cmdyylex_destroy();
77     FREE(context->line_copy);
78     FREE(context->compact_error);
79     free(context);
80     return json_output;
81 }
82
83 %}
84
85 %error-verbose
86 %lex-param { struct context *context }
87
88 %union {
89     char *string;
90     char chr;
91     int number;
92 }
93
94 %token              TOK_EXEC            "exec"
95 %token              TOK_EXIT            "exit"
96 %token              TOK_RELOAD          "reload"
97 %token              TOK_RESTART         "restart"
98 %token              TOK_KILL            "kill"
99 %token              TOK_WINDOW          "window"
100 %token              TOK_CONTAINER       "container"
101 %token              TOK_CLIENT          "client"
102 %token              TOK_FULLSCREEN      "fullscreen"
103 %token              TOK_GLOBAL          "global"
104 %token              TOK_LAYOUT          "layout"
105 %token              TOK_DEFAULT         "default"
106 %token              TOK_STACKED         "stacked"
107 %token              TOK_TABBED          "tabbed"
108 %token              TOK_BORDER          "border"
109 %token              TOK_NORMAL          "normal"
110 %token              TOK_NONE            "none"
111 %token              TOK_1PIXEL          "1pixel"
112 %token              TOK_MODE            "mode"
113 %token              TOK_TILING          "tiling"
114 %token              TOK_FLOATING        "floating"
115 %token              TOK_MODE_TOGGLE     "mode_toggle"
116 %token              TOK_ENABLE          "enable"
117 %token              TOK_DISABLE         "disable"
118 %token              TOK_WORKSPACE       "workspace"
119 %token              TOK_OUTPUT          "output"
120 %token              TOK_TOGGLE          "toggle"
121 %token              TOK_FOCUS           "focus"
122 %token              TOK_MOVE            "move"
123 %token              TOK_OPEN            "open"
124 %token              TOK_NEXT            "next"
125 %token              TOK_PREV            "prev"
126 %token              TOK_NEXT_ON_OUTPUT  "next_on_output"
127 %token              TOK_PREV_ON_OUTPUT  "prev_on_output"
128 %token              TOK_SCRATCHPAD      "scratchpad"
129 %token              TOK_SHOW            "show"
130 %token              TOK_SPLIT           "split"
131 %token              TOK_HORIZONTAL      "horizontal"
132 %token              TOK_VERTICAL        "vertical"
133 %token              TOK_UP              "up"
134 %token              TOK_DOWN            "down"
135 %token              TOK_LEFT            "left"
136 %token              TOK_RIGHT           "right"
137 %token              TOK_PARENT          "parent"
138 %token              TOK_CHILD           "child"
139 %token              TOK_APPEND_LAYOUT   "append_layout"
140 %token              TOK_MARK            "mark"
141 %token              TOK_RESIZE          "resize"
142 %token              TOK_GROW            "grow"
143 %token              TOK_SHRINK          "shrink"
144 %token              TOK_PX              "px"
145 %token              TOK_OR              "or"
146 %token              TOK_PPT             "ppt"
147 %token              TOK_NOP             "nop"
148 %token              TOK_BACK_AND_FORTH  "back_and_forth"
149 %token              TOK_NO_STARTUP_ID   "--no-startup-id"
150 %token              TOK_TO              "to"
151
152 %token              TOK_CLASS           "class"
153 %token              TOK_INSTANCE        "instance"
154 %token              TOK_WINDOW_ROLE     "window_role"
155 %token              TOK_ID              "id"
156 %token              TOK_CON_ID          "con_id"
157 %token              TOK_TITLE           "title"
158
159 %token  <string>    STR                 "<string>"
160 %token  <number>    NUMBER              "<number>"
161
162 %type   <number>    direction
163 %type   <number>    split_direction
164 %type   <number>    fullscreen_mode
165 %type   <number>    level
166 %type   <number>    window_mode
167 %type   <number>    boolean
168 %type   <number>    border_style
169 %type   <number>    layout_mode
170 %type   <number>    resize_px
171 %type   <number>    resize_way
172 %type   <number>    resize_tiling
173 %type   <number>    optional_kill_mode
174 %type   <number>    optional_no_startup_id
175
176 %%
177
178 commands:
179     commands ';' command
180     | command
181     {
182         cmd_criteria_init(&current_match);
183     }
184     ;
185
186 command:
187     match operations
188     ;
189
190 match:
191     | matchstart criteria matchend
192     ;
193
194 matchstart:
195     '['
196     ;
197
198 matchend:
199     ']'
200     {
201         json_output = cmd_criteria_match_windows(&current_match);
202     }
203     ;
204
205 criteria:
206     criteria criterion
207     | criterion
208     ;
209
210 criterion:
211     TOK_CLASS '=' STR
212     {
213         cmd_criteria_add(&current_match, "class", $3);
214         free($3);
215     }
216     | TOK_INSTANCE '=' STR
217     {
218         cmd_criteria_add(&current_match, "instance", $3);
219         free($3);
220     }
221     | TOK_WINDOW_ROLE '=' STR
222     {
223         cmd_criteria_add(&current_match, "window_role", $3);
224         free($3);
225     }
226     | TOK_CON_ID '=' STR
227     {
228         cmd_criteria_add(&current_match, "con_id", $3);
229         free($3);
230     }
231     | TOK_ID '=' STR
232     {
233         cmd_criteria_add(&current_match, "id", $3);
234         free($3);
235     }
236     | TOK_MARK '=' STR
237     {
238         cmd_criteria_add(&current_match, "con_mark", $3);
239         free($3);
240     }
241     | TOK_TITLE '=' STR
242     {
243         cmd_criteria_add(&current_match, "title", $3);
244         free($3);
245     }
246     ;
247
248 operations:
249     operation
250     | operations ',' operation
251     ;
252
253 operation:
254     exec
255     | exit
256     | restart
257     | reload
258     | border
259     | layout
260     | append_layout
261     | move
262     | workspace
263     | focus
264     | kill
265     | open
266     | fullscreen
267     | split
268     | floating
269     | mark
270     | resize
271     | nop
272     | scratchpad
273     | mode
274     ;
275
276 exec:
277     TOK_EXEC optional_no_startup_id STR
278     {
279         json_output = cmd_exec(&current_match, ($2 ? "nosn" : NULL), $3);
280         free($3);
281     }
282     ;
283
284 optional_no_startup_id:
285     /* empty */ { $$ = false; }
286     | TOK_NO_STARTUP_ID  { $$ = true; }
287     ;
288
289 exit:
290     TOK_EXIT
291     {
292         json_output = cmd_exit(&current_match);
293     }
294     ;
295
296 reload:
297     TOK_RELOAD
298     {
299         json_output = cmd_reload(&current_match);
300     }
301     ;
302
303 restart:
304     TOK_RESTART
305     {
306         json_output = cmd_restart(&current_match);
307     }
308     ;
309
310 focus:
311     TOK_FOCUS
312     {
313         json_output = cmd_focus(&current_match);
314     }
315     | TOK_FOCUS direction
316     {
317         json_output = cmd_focus_direction(&current_match,
318                             ($2 == TOK_LEFT ? "left" :
319                              ($2 == TOK_RIGHT ? "right" :
320                               ($2 == TOK_UP ? "up" :
321                                "down"))));
322     }
323     | TOK_FOCUS TOK_OUTPUT STR
324     {
325         json_output = cmd_focus_output(&current_match, $3);
326         free($3);
327     }
328     | TOK_FOCUS window_mode
329     {
330
331         json_output = cmd_focus_window_mode(&current_match,
332                               ($2 == TOK_TILING ? "tiling" :
333                                ($2 == TOK_FLOATING ? "floating" :
334                                 "mode_toggle")));
335     }
336     | TOK_FOCUS level
337     {
338         json_output = cmd_focus_level(&current_match, ($2 == TOK_PARENT ? "parent" : "child"));
339     }
340     ;
341
342 window_mode:
343     TOK_TILING        { $$ = TOK_TILING; }
344     | TOK_FLOATING    { $$ = TOK_FLOATING; }
345     | TOK_MODE_TOGGLE { $$ = TOK_MODE_TOGGLE; }
346     ;
347
348 level:
349     TOK_PARENT  { $$ = TOK_PARENT; }
350     | TOK_CHILD { $$ = TOK_CHILD;  }
351     ;
352
353 kill:
354     TOK_KILL optional_kill_mode
355     {
356         json_output = cmd_kill(&current_match, ($2 == KILL_WINDOW ? "window" : "client"));
357     }
358     ;
359
360 optional_kill_mode:
361     /* empty */             { $$ = KILL_WINDOW; }
362     | TOK_WINDOW { $$ = KILL_WINDOW; }
363     | TOK_CLIENT { $$ = KILL_CLIENT; }
364     ;
365
366 workspace:
367     TOK_WORKSPACE TOK_NEXT
368     {
369         json_output = cmd_workspace(&current_match, "next");
370     }
371     | TOK_WORKSPACE TOK_PREV
372     {
373         json_output = cmd_workspace(&current_match, "prev");
374     }
375     | TOK_WORKSPACE TOK_NEXT_ON_OUTPUT
376     {
377         json_output = cmd_workspace(&current_match, "next_on_output");
378     }
379     | TOK_WORKSPACE TOK_PREV_ON_OUTPUT
380     {
381         json_output = cmd_workspace(&current_match, "prev_on_output");
382     }
383     | TOK_WORKSPACE TOK_BACK_AND_FORTH
384     {
385         json_output = cmd_workspace_back_and_forth(&current_match);
386     }
387     | TOK_WORKSPACE STR
388     {
389         json_output = cmd_workspace_name(&current_match, $2);
390         free($2);
391     }
392     ;
393
394 open:
395     TOK_OPEN
396     {
397         json_output = cmd_open(&current_match);
398     }
399     ;
400
401 fullscreen:
402     TOK_FULLSCREEN fullscreen_mode
403     {
404         json_output = cmd_fullscreen(&current_match, ($2 == CF_OUTPUT ? "output" : "global"));
405     }
406     ;
407
408 fullscreen_mode:
409     /* empty */  { $$ = CF_OUTPUT; }
410     | TOK_GLOBAL { $$ = CF_GLOBAL; }
411     ;
412
413 split:
414     TOK_SPLIT split_direction
415     {
416         char buf[2] = {'\0', '\0'};
417         buf[0] = $2;
418         json_output = cmd_split(&current_match, buf);
419     }
420     ;
421
422 split_direction:
423     TOK_HORIZONTAL  { $$ = 'h'; }
424     | 'h'           { $$ = 'h'; }
425     | TOK_VERTICAL  { $$ = 'v'; }
426     | 'v'           { $$ = 'v'; }
427     ;
428
429 floating:
430     TOK_FLOATING boolean
431     {
432         json_output = cmd_floating(&current_match,
433                      ($2 == TOK_ENABLE ? "enable" :
434                       ($2 == TOK_DISABLE ? "disable" :
435                        "toggle")));
436     }
437     ;
438
439 boolean:
440     TOK_ENABLE    { $$ = TOK_ENABLE; }
441     | TOK_DISABLE { $$ = TOK_DISABLE; }
442     | TOK_TOGGLE  { $$ = TOK_TOGGLE; }
443     ;
444
445 border:
446     TOK_BORDER border_style
447     {
448         json_output = cmd_border(&current_match,
449                    ($2 == BS_NORMAL ? "normal" :
450                     ($2 == BS_NONE ? "none" :
451                      ($2 == BS_1PIXEL ? "1pixel" :
452                       "toggle"))));
453     }
454     ;
455
456 border_style:
457     TOK_NORMAL      { $$ = BS_NORMAL; }
458     | TOK_NONE      { $$ = BS_NONE; }
459     | TOK_1PIXEL    { $$ = BS_1PIXEL; }
460     | TOK_TOGGLE    { $$ = TOK_TOGGLE; }
461     ;
462
463 move:
464     TOK_MOVE direction resize_px
465     {
466         char buffer[128];
467         snprintf(buffer, sizeof(buffer), "%d", $3);
468         json_output = cmd_move_direction(&current_match,
469                            ($2 == TOK_LEFT ? "left" :
470                             ($2 == TOK_RIGHT ? "right" :
471                              ($2 == TOK_UP ? "up" :
472                               "down"))),
473                            buffer);
474     }
475     | TOK_MOVE TOK_WORKSPACE STR
476     {
477         json_output = cmd_move_con_to_workspace_name(&current_match, $3);
478     }
479     | TOK_MOVE TOK_WORKSPACE TOK_NEXT
480     {
481         json_output = cmd_move_con_to_workspace(&current_match, "next");
482     }
483     | TOK_MOVE TOK_WORKSPACE TOK_PREV
484     {
485         json_output = cmd_move_con_to_workspace(&current_match, "prev");
486     }
487     | TOK_MOVE TOK_WORKSPACE TOK_NEXT_ON_OUTPUT
488     {
489         json_output = cmd_move_con_to_workspace(&current_match, "next_on_output");
490     }
491     | TOK_MOVE TOK_WORKSPACE TOK_PREV_ON_OUTPUT
492     {
493         json_output = cmd_move_con_to_workspace(&current_match, "prev_on_output");
494     }
495     | TOK_MOVE TOK_OUTPUT STR
496     {
497         json_output = cmd_move_con_to_output(&current_match, $3);
498         free($3);
499     }
500     | TOK_MOVE TOK_SCRATCHPAD
501     {
502         json_output = cmd_move_scratchpad(&current_match);
503     }
504     | TOK_MOVE TOK_WORKSPACE TOK_TO TOK_OUTPUT STR
505     {
506         json_output = cmd_move_workspace_to_output(&current_match, $5);
507         free($5);
508     }
509     ;
510
511 append_layout:
512     TOK_APPEND_LAYOUT STR
513     {
514         json_output = cmd_append_layout(&current_match, $2);
515         free($2);
516     }
517     ;
518
519 layout:
520     TOK_LAYOUT layout_mode
521     {
522         json_output = cmd_layout(&current_match,
523                    ($2 == L_DEFAULT ? "default" :
524                     ($2 == L_STACKED ? "stacked" :
525                      "tabbed")));
526     }
527     ;
528
529 layout_mode:
530     TOK_DEFAULT   { $$ = L_DEFAULT; }
531     | TOK_STACKED { $$ = L_STACKED; }
532     | TOK_TABBED  { $$ = L_TABBED; }
533     ;
534
535 mark:
536     TOK_MARK STR
537     {
538         json_output = cmd_mark(&current_match, $2);
539         free($2);
540     }
541     ;
542
543 nop:
544     TOK_NOP STR
545     {
546         json_output = cmd_nop(&current_match, $2);
547         free($2);
548     }
549     ;
550
551 scratchpad:
552     TOK_SCRATCHPAD TOK_SHOW
553     {
554         json_output = cmd_scratchpad_show(&current_match);
555     }
556     ;
557
558
559 resize:
560     TOK_RESIZE resize_way direction resize_px resize_tiling
561     {
562         char buffer1[128], buffer2[128];
563         snprintf(buffer1, sizeof(buffer1), "%d", $4);
564         snprintf(buffer2, sizeof(buffer2), "%d", $5);
565         json_output = cmd_resize(&current_match,
566                    ($2 == TOK_SHRINK ? "shrink" : "grow"),
567                    ($3 == TOK_LEFT ? "left" :
568                     ($3 == TOK_RIGHT ? "right" :
569                      ($3 == TOK_DOWN ? "down" :
570                       "up"))),
571                    buffer1,
572                    buffer2);
573     }
574     ;
575
576 resize_px:
577     /* empty */
578     {
579         $$ = 10;
580     }
581     | NUMBER TOK_PX
582     {
583         $$ = $1;
584     }
585     ;
586
587 resize_tiling:
588     /* empty */
589     {
590         $$ = 10;
591     }
592     | TOK_OR NUMBER TOK_PPT
593     {
594         $$ = $2;
595     }
596     ;
597
598 resize_way:
599     TOK_GROW        { $$ = TOK_GROW; }
600     | TOK_SHRINK    { $$ = TOK_SHRINK; }
601     ;
602
603 direction:
604     TOK_UP          { $$ = TOK_UP; }
605     | TOK_DOWN      { $$ = TOK_DOWN; }
606     | TOK_LEFT      { $$ = TOK_LEFT; }
607     | TOK_RIGHT     { $$ = TOK_RIGHT; }
608     ;
609
610 mode:
611     TOK_MODE STR
612     {
613         json_output = cmd_mode(&current_match, $2);
614         free($2);
615     }
616     ;