i3 - improved tiling WM


implement unmark command

Patch status: merged

Patch by koebi

To apply this patch, use:
curl http://cr.i3wm.org/patch/193/raw.patch | git am

b/docs/ipc

20
@@ -458,9 +458,8 @@ JSON dump:
21
 === MARKS reply
22
 
23
 The reply consists of a single array of strings for each container that has a
24
-mark. The order of that array is undefined. If more than one container has the
25
-same mark, it will be represented multiple times in the reply (the array
26
-contents are not unique).
27
+mark. A mark can only be set on one container, so the array is unique.
28
+The order of that array is undefined.
29
 
30
 If no window has a mark the response will be the empty array [].
31
 

b/docs/userguide

36
@@ -1679,9 +1679,10 @@ bindsym $mod+a [class="urxvt" title="VIM"] focus
37
 This feature is like the jump feature: It allows you to directly jump to a
38
 specific window (this means switching to the appropriate workspace and setting
39
 focus to the windows). However, you can directly mark a specific window with
40
-an arbitrary label and use it afterwards.  You do not need to ensure that your
41
-windows have unique classes or titles, and you do not need to change your
42
-configuration file.
43
+an arbitrary label and use it afterwards. You can unmark the label in the same
44
+way, using the unmark command. If you don't specify a label, unmark removes all
45
+marks. You do not need to ensure that your windows have unique classes or
46
+titles, and you do not need to change your configuration file.
47
 
48
 As the command needs to include the label with which you want to mark the
49
 window, you cannot simply bind it to a key.  +i3-input+ is a tool created
50
@@ -1692,12 +1693,14 @@ can also prefix this command and display a custom prompt for the input dialog.
51
 ------------------------------
52
 mark identifier
53
 [con_mark="identifier"] focus
54
+unmark identifier
55
 ------------------------------
56
 
57
 *Example (in a terminal)*:
58
 ------------------------------
59
 $ i3-msg mark irssi
60
 $ i3-msg '[con_mark="irssi"] focus'
61
+$ i3-msg unmark irssi
62
 ------------------------------
63
 
64
 ///////////////////////////////////////////////////////////////////

b/include/commands.h

69
@@ -116,6 +116,12 @@ void cmd_workspace_name(I3_CMD, char *name);
70
 void cmd_mark(I3_CMD, char *mark);
71
 
72
 /**
73
+ * Implementation of 'unmark [mark]'
74
+ *
75
+ */
76
+void cmd_unmark(I3_CMD, char *mark);
77
+
78
+/**
79
  * Implementation of 'mode <string>'.
80
  *
81
  */

b/parser-specs/commands.spec

86
@@ -32,6 +32,7 @@ state INITIAL:
87
   'split' -> SPLIT
88
   'floating' -> FLOATING
89
   'mark' -> MARK
90
+  'unmark' -> UNMARK
91
   'resize' -> RESIZE
92
   'rename' -> RENAME
93
   'nop' -> NOP
94
@@ -177,6 +178,13 @@ state MARK:
95
   mark = string
96
       -> call cmd_mark($mark)
97
 
98
+# unmark [mark]
99
+state UNMARK:
100
+  end
101
+      -> call cmd_unmark($mark)
102
+  mark = string
103
+      -> call cmd_unmark($mark)
104
+
105
 # resize
106
 state RESIZE:
107
   way = 'grow', 'shrink'

b/src/commands.c

112
@@ -1032,6 +1032,31 @@ void cmd_mark(I3_CMD, char *mark) {
113
 }
114
 
115
 /*
116
+ * Implementation of 'unmark [mark]'
117
+ *
118
+ */
119
+void cmd_unmark(I3_CMD, char *mark) {
120
+   if (mark == NULL) {
121
+       Con *con;
122
+       TAILQ_FOREACH(con, &all_cons, all_cons) {
123
+           FREE(con->mark);
124
+       }
125
+       DLOG("removed all window marks");
126
+   } else {
127
+       Con *con;
128
+       TAILQ_FOREACH(con, &all_cons, all_cons) {
129
+           if (con->mark && strcmp(con->mark, mark) == 0)
130
+               FREE(con->mark);
131
+       }
132
+       DLOG("removed window mark %s\n", mark);
133
+    }
134
+
135
+    cmd_output->needs_tree_render = true;
136
+    // XXX: default reply for now, make this a better reply
137
+    ysuccess(true);
138
+}
139
+
140
+/*
141
  * Implementation of 'mode <string>'.
142
  *
143
  */

b/testcases/t/187-commands-parser.t

148
@@ -144,7 +144,7 @@ is(parser_calls("\nworkspace test"),
149
 ################################################################################
150
 
151
 is(parser_calls('unknown_literal'),
152
-   "ERROR: Expected one of these tokens: <end>, '[', 'move', 'exec', 'exit', 'restart', 'reload', 'shmlog', 'debuglog', 'border', 'layout', 'append_layout', 'workspace', 'focus', 'kill', 'open', 'fullscreen', 'split', 'floating', 'mark', 'resize', 'rename', 'nop', 'scratchpad', 'mode', 'bar'\n" .
153
+   "ERROR: Expected one of these tokens: <end>, '[', 'move', 'exec', 'exit', 'restart', 'reload', 'shmlog', 'debuglog', 'border', 'layout', 'append_layout', 'workspace', 'focus', 'kill', 'open', 'fullscreen', 'split', 'floating', 'mark', 'unmark', 'resize', 'rename', 'nop', 'scratchpad', 'mode', 'bar'\n" .
154
    "ERROR: Your command: unknown_literal\n" .
155
    "ERROR:               ^^^^^^^^^^^^^^^",
156
    'error for unknown literal ok');

b/testcases/t/210-mark-unmark.t

162
@@ -0,0 +1,79 @@
163
+#!perl
164
+# vim:ts=4:sw=4:expandtab
165
+#
166
+# Please read the following documents before working on tests:
167
+# • http://build.i3wm.org/docs/testsuite.html
168
+#   (or docs/testsuite)
169
+#
170
+# • http://build.i3wm.org/docs/lib-i3test.html
171
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
172
+#
173
+# • http://build.i3wm.org/docs/ipc.html
174
+#   (or docs/ipc)
175
+#
176
+# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
177
+#   (unless you are already familiar with Perl)
178
+#
179
+# checks if mark and unmark work correctly
180
+use i3test;
181
+
182
+sub get_marks {
183
+    return i3(get_socket_path())->get_marks->recv;
184
+}
185
+
186
+##############################################################
187
+# 1: check that there are no marks set yet
188
+##############################################################
189
+
190
+my $tmp = fresh_workspace;
191
+
192
+cmd 'split h';
193
+
194
+is_deeply(get_marks(), [], 'no marks set yet');
195
+
196
+
197
+##############################################################
198
+# 2: mark a con, check that it's marked, unmark it, check that
199
+##############################################################
200
+
201
+my $one = open_window;
202
+cmd 'mark foo';
203
+
204
+is_deeply(get_marks(), ["foo"], 'mark foo set');
205
+
206
+cmd 'unmark foo';
207
+
208
+is_deeply(get_marks(), [], 'mark foo removed');
209
+
210
+##############################################################
211
+# 3: mark three cons, check that they are marked
212
+#    unmark one con, check that it's unmarked
213
+#    unmark all cons, check that they are unmarked
214
+##############################################################
215
+
216
+my $left = open_window;
217
+my $middle = open_window;
218
+my $right = open_window;
219
+
220
+cmd 'mark right';
221
+cmd 'focus left';
222
+cmd 'mark middle';
223
+cmd 'focus left';
224
+cmd 'mark left';
225
+
226
+#
227
+# get_marks replys an array of marks, whose order is undefined,
228
+# so we use sort to be able to compare the output
229
+#
230
+
231
+is_deeply(sort(get_marks()), ["left","middle","right"], 'all three marks set');
232
+
233
+cmd 'unmark right';
234
+
235
+is_deeply(sort(get_marks()), ["left","middle"], 'mark right removed');
236
+
237
+cmd 'unmark';
238
+
239
+is_deeply(get_marks(), [], 'all marks removed');
240
+
241
+done_testing;