From 7a77c5f0bb988ec2fff52e231590fff93a4ee6b9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ingo=20B=C3=BCrk?= Date: Mon, 19 Oct 2015 18:31:21 +0200 Subject: [PATCH] Introduce "--add" for marking windows. In order to keep compatibility to before allowing multiple marks on a window, we introduce a flag "--add" that must be set to put more than one mark on a window. The default, which is also available as "--replace", keeps the old behavior of overwriting a mark when setting a new one. fixes #2014 --- docs/userguide | 14 +++++++++----- include/commands.h | 4 ++-- include/con.h | 4 ++-- include/data.h | 3 +++ parser-specs/commands.spec | 6 ++++-- src/commands.c | 10 ++++++---- src/con.c | 14 +++++++++++--- src/load_layout.c | 4 ++-- testcases/t/210-mark-unmark.t | 14 ++++++++++++-- testcases/t/255-multiple-marks.t | 20 ++++++++++---------- 10 files changed, 61 insertions(+), 32 deletions(-) diff --git a/docs/userguide b/docs/userguide index f80f19f9..e07e544d 100644 --- a/docs/userguide +++ b/docs/userguide @@ -2115,17 +2115,21 @@ for this purpose: It lets you input a command and sends the command to i3. It can also prefix this command and display a custom prompt for the input dialog. The additional +--toggle+ option will remove the mark if the window already has -this mark, add it if the window has none or replace the current mark if it has -another mark. +this mark or add it otherwise. Note that you may need to use this in +combination with +--add+ (see below) as any other marks will otherwise be +removed. + +By default, a window can only have one mark. You can use the +--add+ flag to +put more than one mark on a window. Refer to <> if you don't want marks to be shown in the window decoration. *Syntax*: ------------------------------- -mark [--toggle] +---------------------------------------------- +mark [--add|--replace] [--toggle] [con_mark="identifier"] focus unmark ------------------------------- +---------------------------------------------- *Example (in a terminal)*: ------------------------------ diff --git a/include/commands.h b/include/commands.h index e0bb2f92..d3485f15 100644 --- a/include/commands.h +++ b/include/commands.h @@ -115,10 +115,10 @@ void cmd_workspace_back_and_forth(I3_CMD); void cmd_workspace_name(I3_CMD, const char *name); /** - * Implementation of 'mark [--toggle] ' + * Implementation of 'mark [--add|--replace] [--toggle] ' * */ -void cmd_mark(I3_CMD, const char *mark, const char *toggle); +void cmd_mark(I3_CMD, const char *mark, const char *mode, const char *toggle); /** * Implementation of 'unmark [mark]' diff --git a/include/con.h b/include/con.h index df94c1ae..b448b8c2 100644 --- a/include/con.h +++ b/include/con.h @@ -158,13 +158,13 @@ bool con_has_mark(Con *con, const char *mark); * Otherwise, the mark is assigned to the container. * */ -void con_mark_toggle(Con *con, const char *mark); +void con_mark_toggle(Con *con, const char *mark, mark_mode_t mode); /** * Assigns a mark to the container. * */ -void con_mark(Con *con, const char *mark); +void con_mark(Con *con, const char *mark, mark_mode_t mode); /** * If mark is NULL, this removes all existing marks. diff --git a/include/data.h b/include/data.h index ee7f82c0..3a752c2e 100644 --- a/include/data.h +++ b/include/data.h @@ -75,6 +75,9 @@ typedef enum { ADJ_NONE = 0, ADJ_UPPER_SCREEN_EDGE = (1 << 2), ADJ_LOWER_SCREEN_EDGE = (1 << 4) } adjacent_t; +typedef enum { MM_REPLACE, + MM_ADD } mark_mode_t; + /** * Container layouts. See Con::layout. */ diff --git a/parser-specs/commands.spec b/parser-specs/commands.spec index b3b5e338..475dc4bd 100644 --- a/parser-specs/commands.spec +++ b/parser-specs/commands.spec @@ -199,12 +199,14 @@ state FLOATING: floating = 'enable', 'disable', 'toggle' -> call cmd_floating($floating) -# mark [--toggle] +# mark [--add|--replace] [--toggle] state MARK: + mode = '--add', '--replace' + -> toggle = '--toggle' -> mark = string - -> call cmd_mark($mark, $toggle) + -> call cmd_mark($mark, $mode, $toggle) # unmark [mark] state UNMARK: diff --git a/src/commands.c b/src/commands.c index ab9a4135..a9b98c53 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1003,10 +1003,10 @@ void cmd_workspace_name(I3_CMD, const char *name) { } /* - * Implementation of 'mark [--toggle] ' + * Implementation of 'mark [--add|--replace] [--toggle] ' * */ -void cmd_mark(I3_CMD, const char *mark, const char *toggle) { +void cmd_mark(I3_CMD, const char *mark, const char *mode, const char *toggle) { HANDLE_EMPTY_MATCH; owindow *current = TAILQ_FIRST(&owindows); @@ -1022,10 +1022,12 @@ void cmd_mark(I3_CMD, const char *mark, const char *toggle) { } DLOG("matching: %p / %s\n", current->con, current->con->name); + + mark_mode_t mark_mode = (mode == NULL || strcmp(mode, "--replace") == 0) ? MM_REPLACE : MM_ADD; if (toggle != NULL) { - con_mark_toggle(current->con, mark); + con_mark_toggle(current->con, mark, mark_mode); } else { - con_mark(current->con, mark); + con_mark(current->con, mark, mark_mode); } cmd_output->needs_tree_render = true; diff --git a/src/con.c b/src/con.c index bf7dd545..9238acad 100644 --- a/src/con.c +++ b/src/con.c @@ -540,14 +540,14 @@ bool con_has_mark(Con *con, const char *mark) { * Otherwise, the mark is assigned to the container. * */ -void con_mark_toggle(Con *con, const char *mark) { +void con_mark_toggle(Con *con, const char *mark, mark_mode_t mode) { assert(con != NULL); DLOG("Toggling mark \"%s\" on con = %p.\n", mark, con); if (con_has_mark(con, mark)) { con_unmark(mark); } else { - con_mark(con, mark); + con_mark(con, mark, mode); } } @@ -555,11 +555,19 @@ void con_mark_toggle(Con *con, const char *mark) { * Assigns a mark to the container. * */ -void con_mark(Con *con, const char *mark) { +void con_mark(Con *con, const char *mark, mark_mode_t mode) { assert(con != NULL); DLOG("Setting mark \"%s\" on con = %p.\n", mark, con); con_unmark(mark); + if (mode == MM_REPLACE) { + DLOG("Removing all existing marks on con = %p.\n", con); + + mark_t *current; + TAILQ_FOREACH(current, &(con->marks_head), marks) { + con_unmark(current->name); + } + } mark_t *new = scalloc(1, sizeof(mark_t)); new->name = sstrdup(mark); diff --git a/src/load_layout.c b/src/load_layout.c index 68c4f4a2..dc84c607 100644 --- a/src/load_layout.c +++ b/src/load_layout.c @@ -246,7 +246,7 @@ static int json_string(void *ctx, const unsigned char *val, size_t len) { char *mark; sasprintf(&mark, "%.*s", (int)len, val); - con_mark(json_node, mark); + con_mark(json_node, mark, MM_ADD); } else { if (strcasecmp(last_key, "name") == 0) { json_node->name = scalloc(len + 1, 1); @@ -354,7 +354,7 @@ static int json_string(void *ctx, const unsigned char *val, size_t len) { char *buf = NULL; sasprintf(&buf, "%.*s", (int)len, val); - con_mark(json_node, buf); + con_mark(json_node, buf, MM_REPLACE); } else if (strcasecmp(last_key, "floating") == 0) { char *buf = NULL; sasprintf(&buf, "%.*s", (int)len, val); diff --git a/testcases/t/210-mark-unmark.t b/testcases/t/210-mark-unmark.t index 39fc0904..446d5465 100644 --- a/testcases/t/210-mark-unmark.t +++ b/testcases/t/210-mark-unmark.t @@ -118,7 +118,17 @@ cmd 'mark --toggle important'; is_deeply(get_mark_for_window_on_workspace($tmp, $con), [ 'important' ], 'container now has the mark'); ############################################################## -# 7: mark a con, toggle the mark on another con, +# 7: mark a con, toggle a different mark, check it is marked +# with the new mark +############################################################## + +$con = open_window; +cmd 'mark boring'; +cmd 'mark --replace --toggle important'; +is_deeply(get_mark_for_window_on_workspace($tmp, $con), [ 'important' ], 'container has the most recent mark'); + +############################################################## +# 8: mark a con, toggle the mark on another con, # check only the latter has the mark ############################################################## @@ -133,7 +143,7 @@ is_deeply(get_mark_for_window_on_workspace($tmp, $first), [ 'important' ], 'left ok(!get_mark_for_window_on_workspace($tmp, $second), 'second containr no longer has the mark'); ############################################################## -# 8: try to mark two cons with the same mark and check that +# 9: try to mark two cons with the same mark and check that # it fails ############################################################## diff --git a/testcases/t/255-multiple-marks.t b/testcases/t/255-multiple-marks.t index d6d86e23..925e39db 100644 --- a/testcases/t/255-multiple-marks.t +++ b/testcases/t/255-multiple-marks.t @@ -38,8 +38,8 @@ sub get_mark_for_window_on_workspace { $ws = fresh_workspace; $con = open_window; -cmd 'mark A'; -cmd 'mark B'; +cmd 'mark --add A'; +cmd 'mark --add B'; is_deeply(sort(get_marks()), [ 'A', 'B' ], 'both marks exist'); is_deeply(get_mark_for_window_on_workspace($ws, $con), [ 'A', 'B' ], 'both marks are on the same window'); @@ -54,9 +54,9 @@ $ws = fresh_workspace; $con = open_window; cmd 'mark A'; -cmd 'mark --toggle B'; +cmd 'mark --add --toggle B'; is_deeply(get_mark_for_window_on_workspace($ws, $con), [ 'A', 'B' ], 'both marks are on the same window'); -cmd 'mark --toggle B'; +cmd 'mark --add --toggle B'; is_deeply(get_mark_for_window_on_workspace($ws, $con), [ 'A' ], 'only mark B has been removed'); cmd 'unmark'; @@ -67,9 +67,9 @@ cmd 'unmark'; $ws = fresh_workspace; $con = open_window; -cmd 'mark A'; -cmd 'mark B'; -cmd 'mark C'; +cmd 'mark --add A'; +cmd 'mark --add B'; +cmd 'mark --add C'; cmd 'unmark B'; is_deeply(get_mark_for_window_on_workspace($ws, $con), [ 'A', 'C' ], 'only mark B has been removed'); @@ -82,11 +82,11 @@ cmd 'unmark'; $ws = fresh_workspace; $con = open_window; -cmd 'mark A'; -cmd 'mark B'; +cmd 'mark --add A'; +cmd 'mark --add B'; open_window; -cmd '[con_mark=B] mark C'; +cmd '[con_mark=B] mark --add C'; is_deeply(get_mark_for_window_on_workspace($ws, $con), [ 'A', 'B', 'C' ], 'matching on a mark works with multiple marks'); cmd 'unmark'; -- 2.39.2