i3 - improved tiling WM


implement unmark command

Patch status: superseded

Patch by koebi

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

b/docs/ipc

20
@@ -458,9 +458,7 @@ 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. The order of that array is undefined.
28
 
29
 If no window has a mark the response will be the empty array [].
30
 

b/docs/userguide

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

b/include/commands.h

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

b/parser-specs/commands.spec

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

b/src/commands.c

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

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

147
@@ -144,7 +144,7 @@ is(parser_calls("\nworkspace test"),
148
 ################################################################################
149
 
150
 is(parser_calls('unknown_literal'),
151
-   "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" .
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', 'unmark', 'resize', 'rename', 'nop', 'scratchpad', 'mode', 'bar'\n" .
153
    "ERROR: Your command: unknown_literal\n" .
154
    "ERROR:               ^^^^^^^^^^^^^^^",
155
    'error for unknown literal ok');

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

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