} owindow;
static TAILQ_HEAD(owindows_head, owindow) owindows;
+/* Holds the JSON which will be returned via IPC or NULL for the default return
+ * message */
+static char *json_output;
+
/* We don’t need yydebug for now, as we got decent error messages using
* yyerror(). Should you ever want to extend the parser, it might be handy
* to just comment it in again, so it stays here. */
void cmdyyerror(const char *error_message) {
ELOG("\n");
ELOG("CMD: %s\n", error_message);
- ELOG("CMD: in file \"%s\", line %d:\n",
- context->filename, context->line_number);
+ ELOG("CMD: in command:\n");
ELOG("CMD: %s\n", context->line_copy);
ELOG("CMD: ");
for (int c = 1; c <= context->last_column; c++)
else printf(" ");
printf("\n");
ELOG("\n");
+ context->compact_error = sstrdup(error_message);
}
int cmdyywrap() {
return 1;
}
-void parse_cmd(const char *new) {
-
- //const char *new = "[level-up workspace] attach $output, focus";
-
+char *parse_cmd(const char *new) {
cmdyy_scan_string(new);
+ match_init(¤t_match);
context = scalloc(sizeof(struct context));
context->filename = "cmd";
+ FREE(json_output);
if (cmdyyparse() != 0) {
- fprintf(stderr, "Could not parse configfile\n");
- exit(1);
+ fprintf(stderr, "Could not parse command\n");
+ asprintf(&json_output, "{\"success\":false, \"error\":\"%s at position %d\"}",
+ context->compact_error, context->first_column);
+ FREE(context->line_copy);
+ FREE(context->compact_error);
+ free(context);
+ return json_output;
}
- printf("done\n");
+ printf("done, json output = %s\n", json_output);
FREE(context->line_copy);
+ FREE(context->compact_error);
free(context);
+ return json_output;
}
%}
%token TOK_STACKED "stacked"
%token TOK_TABBED "tabbed"
%token TOK_BORDER "border"
+%token TOK_NORMAL "normal"
%token TOK_NONE "none"
%token TOK_1PIXEL "1pixel"
%token TOK_MODE "mode"
%token TOK_TILING "tiling"
%token TOK_FLOATING "floating"
%token TOK_WORKSPACE "workspace"
+%token TOK_TOGGLE "toggle"
%token TOK_FOCUS "focus"
%token TOK_MOVE "move"
%token TOK_OPEN "open"
%token TOK_LEVEL "level"
%token TOK_UP "up"
%token TOK_DOWN "down"
+%token TOK_LEFT "left"
+%token TOK_RIGHT "right"
%token TOK_AFTER "after"
%token TOK_BEFORE "before"
%token TOK_RESTORE "restore"
+%token TOK_MARK "mark"
+%token TOK_RESIZE "resize"
+%token TOK_GROW "grow"
+%token TOK_SHRINK "shrink"
+%token TOK_PX "px"
+%token TOK_OR "or"
+%token TOK_PPT "ppt"
%token TOK_CLASS "class"
%token TOK_ID "id"
%token WHITESPACE "<whitespace>"
%token STR "<string>"
+%token NUMBER "<number>"
%%
TAILQ_REMOVE(&owindows, current, owindows);
free(current);
}
- memset(¤t_match, 0, sizeof(Match));
+ match_init(¤t_match);
}
;
'['
{
printf("start\n");
- memset(¤t_match, '\0', sizeof(Match));
+ match_init(¤t_match);
TAILQ_INIT(&owindows);
/* copy all_cons */
Con *con;
TAILQ_INSERT_TAIL(&owindows, current, owindows);
}
+ } else if (current_match.mark != NULL && current->con->mark != NULL &&
+ strcasecmp(current_match.mark, current->con->mark) == 0) {
+ printf("match by mark\n");
+ TAILQ_INSERT_TAIL(&owindows, current, owindows);
+
} else {
if (current->con->window == NULL)
continue;
current_match.con_id = atoi($<string>3);
printf("id as int = %d\n", current_match.con_id);
}
+ | TOK_ID '=' STR
+ {
+ printf("criteria: window id = %s\n", $<string>3);
+ /* TODO: correctly parse number */
+ current_match.id = atoi($<string>3);
+ printf("window id as int = %d\n", current_match.id);
+ }
+ | TOK_MARK '=' STR
+ {
+ printf("criteria: mark = %s\n", $<string>3);
+ current_match.mark = $<string>3;
+ }
;
operations:
exec
| exit
| restart
- /*| reload
- | mark
+ | reload
+ | border
| layout
- | border */
| restore
| move
| workspace
| split
| mode
| level
+ | mark
+ | resize
;
exec:
}
;
+reload:
+ TOK_RELOAD
+ {
+ printf("reloading\n");
+ load_configuration(conn, NULL, true);
+ /* Send an IPC event just in case the ws names have changed */
+ ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"reload\"}");
+ }
+ ;
+
restart:
TOK_RESTART
{
focus:
TOK_FOCUS
{
+ owindow *current;
+
printf("should focus\n");
+ if (match_is_empty(¤t_match)) {
+ /* TODO: better error message */
+ LOG("Error: The foucs command requires you to use some criteria.\n");
+ return;
+ }
+
+ /* TODO: warning if the match contains more than one entry. does not
+ * make so much sense when focusing */
+ TAILQ_FOREACH(current, &owindows, owindows) {
+ LOG("focusing %p / %s\n", current->con, current->con->name);
+ con_focus(current->con);
+ }
}
;
printf("killing!\n");
/* check if the match is empty, not if the result is empty */
if (match_is_empty(¤t_match))
- tree_close(focused, true);
+ tree_close_con();
else {
TAILQ_FOREACH(current, &owindows, owindows) {
printf("matching: %p / %s\n", current->con, current->con->name);
- tree_close(current->con, true);
+ tree_close(current->con, true, false);
}
}
TOK_OPEN
{
printf("opening new container\n");
- tree_open_con(NULL);
+ Con *con = tree_open_con(NULL);
+ asprintf(&json_output, "{\"success\":true, \"id\":%d}", (long int)con);
}
;
mode:
TOK_MODE WHITESPACE window_mode
{
- printf("should switch mode to %s\n", ($<number>3 == TOK_FLOATING ? "floating" : "tiling"));
- /* TODO: actually switch mode (not toggle) */
+ if ($<number>3 == TOK_TOGGLE) {
+ printf("should toggle mode\n");
+ toggle_floating_mode(focused, false);
+ } else {
+ printf("should switch mode to %s\n", ($<number>3 == TOK_FLOATING ? "floating" : "tiling"));
+ if ($<number>3 == TOK_FLOATING) {
+ floating_enable(focused, false);
+ } else {
+ floating_disable(focused, false);
+ }
+ }
}
;
window_mode:
TOK_FLOATING { $<number>$ = TOK_FLOATING; }
| TOK_TILING { $<number>$ = TOK_TILING; }
+ | TOK_TOGGLE { $<number>$ = TOK_TOGGLE; }
;
+border:
+ TOK_BORDER WHITESPACE border_style
+ {
+ printf("border style should be changed to %d\n", $<number>3);
+ owindow *current;
+
+ /* check if the match is empty, not if the result is empty */
+ if (match_is_empty(¤t_match))
+ focused->border_style = $<number>3;
+ else {
+ TAILQ_FOREACH(current, &owindows, owindows) {
+ printf("matching: %p / %s\n", current->con, current->con->name);
+ current->con->border_style = $<number>3;
+ }
+ }
+ }
+ ;
+
+border_style:
+ TOK_NORMAL { $<number>$ = BS_NORMAL; }
+ | TOK_NONE { $<number>$ = BS_NONE; }
+ | TOK_1PIXEL { $<number>$ = BS_1PIXEL; }
+ ;
+
+
level:
TOK_LEVEL WHITESPACE level_direction
{
* we should not need any of both */
tree_move(($<number>3 == TOK_BEFORE ? 'p' : 'n'), ($<chr>5 == 'v' ? VERT : HORIZ));
}
+ | TOK_MOVE WHITESPACE TOK_WORKSPACE WHITESPACE STR
+ {
+ owindow *current;
+
+ printf("should move window to workspace %s\n", $<string>5);
+ /* get the workspace */
+ Con *ws = workspace_get($<string>5);
+
+ /* check if the match is empty, not if the result is empty */
+ if (match_is_empty(¤t_match))
+ con_move_to_workspace(focused, ws);
+ else {
+ TAILQ_FOREACH(current, &owindows, owindows) {
+ printf("matching: %p / %s\n", current->con, current->con->name);
+ con_move_to_workspace(current->con, ws);
+ }
+ }
+ }
;
before_after:
tree_append_json($<string>3);
}
;
+
+layout:
+ TOK_LAYOUT WHITESPACE layout_mode
+ {
+ printf("changing layout to %d\n", $<number>3);
+ owindow *current;
+
+ /* check if the match is empty, not if the result is empty */
+ if (match_is_empty(¤t_match))
+ focused->parent->layout = $<number>3;
+ else {
+ TAILQ_FOREACH(current, &owindows, owindows) {
+ printf("matching: %p / %s\n", current->con, current->con->name);
+ current->con->layout = $<number>3;
+ }
+ }
+
+ }
+ ;
+
+layout_mode:
+ TOK_DEFAULT { $<number>$ = L_DEFAULT; }
+ | TOK_STACKED { $<number>$ = L_STACKED; }
+ | TOK_TABBED { $<number>$ = L_TABBED; }
+ ;
+
+mark:
+ TOK_MARK WHITESPACE STR
+ {
+ printf("marking window with str %s\n", $<string>3);
+ owindow *current;
+
+ /* check if the match is empty, not if the result is empty */
+ if (match_is_empty(¤t_match))
+ focused->mark = sstrdup($<string>3);
+ else {
+ TAILQ_FOREACH(current, &owindows, owindows) {
+ printf("matching: %p / %s\n", current->con, current->con->name);
+ current->con->mark = sstrdup($<string>3);
+ }
+ }
+
+ free($<string>3);
+ }
+ ;
+
+resize:
+ TOK_RESIZE WHITESPACE resize_way WHITESPACE direction resize_px resize_tiling
+ {
+ /* resize <grow|shrink> <direction> [<px> px] [or <ppt> ppt] */
+ printf("resizing in way %d, direction %d, px %d or ppt %d\n", $<number>3, $<number>5, $<number>6, $<number>7);
+ int direction = $<number>5;
+ int px = $<number>6;
+ int ppt = $<number>7;
+ if ($<number>3 == TOK_SHRINK) {
+ px *= -1;
+ ppt *= -1;
+ }
+
+ if (con_is_floating(focused)) {
+ printf("floating resize\n");
+ if (direction == TOK_UP) {
+ focused->parent->rect.y -= px;
+ focused->parent->rect.height += px;
+ } else if (direction == TOK_DOWN) {
+ focused->rect.height += px;
+ } else if (direction == TOK_LEFT) {
+ focused->rect.x -= px;
+ focused->rect.width += px;
+ } else {
+ focused->rect.width += px;
+ }
+ } else {
+ LOG("tiling resize\n");
+ /* get the default percentage */
+ int children = 0;
+ Con *other;
+ TAILQ_FOREACH(other, &(focused->parent->nodes_head), nodes)
+ children++;
+ LOG("ins. %d children\n", children);
+ double percentage = 1.0 / children;
+ LOG("default percentage = %f\n", percentage);
+
+ if (direction == TOK_UP || direction == TOK_LEFT) {
+ other = TAILQ_PREV(focused, nodes_head, nodes);
+ } else {
+ other = TAILQ_NEXT(focused, nodes);
+ }
+ if (other == TAILQ_END(workspaces)) {
+ LOG("No other container in this direction found, cannot resize.\n");
+ return 0;
+ }
+ LOG("other->percent = %f\n", other->percent);
+ LOG("focused->percent before = %f\n", focused->percent);
+ if (focused->percent == 0.0)
+ focused->percent = percentage;
+ if (other->percent == 0.0)
+ other->percent = percentage;
+ focused->percent += ((double)ppt / 100.0);
+ other->percent -= ((double)ppt / 100.0);
+ LOG("focused->percent after = %f\n", focused->percent);
+ LOG("other->percent after = %f\n", other->percent);
+ }
+ }
+ ;
+
+resize_px:
+ /* empty */
+ {
+ $<number>$ = 10;
+ }
+ | WHITESPACE NUMBER WHITESPACE TOK_PX
+ {
+ $<number>$ = $<number>2;
+ }
+ ;
+
+resize_tiling:
+ /* empty */
+ {
+ $<number>$ = 10;
+ }
+ | WHITESPACE TOK_OR WHITESPACE NUMBER WHITESPACE TOK_PPT
+ {
+ $<number>$ = $<number>4;
+ }
+ ;
+
+resize_way:
+ TOK_GROW { $<number>$ = TOK_GROW; }
+ | TOK_SHRINK { $<number>$ = TOK_SHRINK; }
+ ;
+
+direction:
+ TOK_UP { $<number>$ = TOK_UP; }
+ | TOK_DOWN { $<number>$ = TOK_DOWN; }
+ | TOK_LEFT { $<number>$ = TOK_LEFT; }
+ | TOK_RIGHT { $<number>$ = TOK_RIGHT; }
+ ;