]> git.sur5r.net Git - i3/i3/blob - i3-config-wizard/cfgparse.y
Merge branch 'master' into next
[i3/i3] / i3-config-wizard / cfgparse.y
1 %{
2 /*
3  * vim:ts=4:sw=4:expandtab
4  *
5  */
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include <X11/Xlib.h>
16
17 #include "libi3.h"
18
19 extern Display *dpy;
20
21 struct context {
22         int line_number;
23         char *line_copy;
24
25         char *compact_error;
26
27         /* These are the same as in YYLTYPE */
28         int first_column;
29         int last_column;
30
31         char *result;
32 };
33
34 typedef struct yy_buffer_state *YY_BUFFER_STATE;
35 extern int yylex(struct context *context);
36 extern int yyparse(void);
37 extern FILE *yyin;
38 YY_BUFFER_STATE yy_scan_string(const char *);
39
40 static struct context *context;
41
42 /* We don’t need yydebug for now, as we got decent error messages using
43  * yyerror(). Should you ever want to extend the parser, it might be handy
44  * to just comment it in again, so it stays here. */
45 //int yydebug = 1;
46
47 void yyerror(const char *error_message) {
48     fprintf(stderr, "\n");
49     fprintf(stderr, "CONFIG: %s\n", error_message);
50     fprintf(stderr, "CONFIG: line %d:\n",
51         context->line_number);
52     fprintf(stderr, "CONFIG:   %s\n", context->line_copy);
53     fprintf(stderr, "CONFIG:   ");
54     for (int c = 1; c <= context->last_column; c++)
55         if (c >= context->first_column)
56             fprintf(stderr, "^");
57         else fprintf(stderr, " ");
58     fprintf(stderr, "\n");
59     fprintf(stderr, "\n");
60 }
61
62 int yywrap() {
63     return 1;
64 }
65
66 char *rewrite_binding(const char *bindingline) {
67     char *result = NULL;
68
69     context = calloc(sizeof(struct context), 1);
70
71     yy_scan_string(bindingline);
72
73     if (yyparse() != 0) {
74         fprintf(stderr, "Could not parse configfile\n");
75         exit(1);
76     }
77
78     result = context->result;
79
80     if (context->line_copy)
81         free(context->line_copy);
82     free(context);
83
84     return result;
85 }
86
87 /* XXX: does not work for combinations of modifiers yet */
88 static char *modifier_to_string(int modifiers) {
89     //printf("should convert %d to string\n", modifiers);
90     if (modifiers == (1 << 3))
91         return strdup("$mod+");
92     else if (modifiers == ((1 << 3) | (1 << 0)))
93         return strdup("$mod+Shift+");
94     else if (modifiers == (1 << 9))
95         return strdup("$mod+");
96     else if (modifiers == ((1 << 9) | (1 << 0)))
97         return strdup("$mod+Shift+");
98     else if (modifiers == (1 << 0))
99         return strdup("Shift+");
100     else return strdup("");
101 }
102
103 %}
104
105 %error-verbose
106 %lex-param { struct context *context }
107
108 %union {
109     int number;
110     char *string;
111 }
112
113 %token <number>NUMBER "<number>"
114 %token <string>STR "<string>"
115 %token TOKBINDCODE
116 %token TOKMODVAR "$mod"
117 %token MODIFIER "<modifier>"
118 %token TOKCONTROL "control"
119 %token TOKSHIFT "shift"
120 %token WHITESPACE "<whitespace>"
121
122 %%
123
124 lines: /* empty */
125     | lines WHITESPACE bindcode
126     | lines error
127     | lines bindcode
128     ;
129
130 bindcode:
131     TOKBINDCODE WHITESPACE binding_modifiers NUMBER WHITESPACE STR
132     {
133         //printf("\tFound keycode binding mod%d with key %d and command %s\n", $<number>3, $4, $<string>6);
134         int level = 0;
135         if (($<number>3 & (1 << 0))) {
136             /* When shift is included, we really need to use the second-level
137              * symbol (upper-case). The lower-case symbol could be on a
138              * different key than the upper-case one (unlikely for letters, but
139              * more likely for special characters). */
140             level = 1;
141         }
142         KeySym sym = XKeycodeToKeysym(dpy, $4, level);
143         char *str = XKeysymToString(sym);
144         char *modifiers = modifier_to_string($<number>3);
145         // TODO: modifier to string
146         sasprintf(&(context->result), "bindsym %s%s %s\n", modifiers, str, $<string>6);
147         free(modifiers);
148     }
149     ;
150
151 binding_modifiers:
152     /* NULL */                               { $<number>$ = 0; }
153     | binding_modifier
154     | binding_modifiers '+' binding_modifier { $<number>$ = $<number>1 | $<number>3; }
155     | binding_modifiers '+'                  { $<number>$ = $<number>1; }
156     ;
157
158 binding_modifier:
159     MODIFIER        { $<number>$ = $<number>1; }
160     | TOKMODVAR     { $<number>$ = $<number>1; }
161     | TOKCONTROL    { $<number>$ = (1 << 2); }
162     | TOKSHIFT      { $<number>$ = (1 << 0); }
163     ;