i3 - improved tiling WM


add command to remove marks

Patch status: needinfo

Patch by koebi

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

b/docs/ipc

21
@@ -458,9 +458,7 @@ JSON dump:
22
 === MARKS reply
23
 
24
 The reply consists of a single array of strings for each container that has a
25
-mark. The order of that array is undefined. If more than one container has the
26
-same mark, it will be represented multiple times in the reply (the array
27
-contents are not unique).
28
+mark. 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/173-get-marks.t

148
@@ -46,6 +46,6 @@ is_deeply(get_marks(), [ 'foo' ], 'mark foo set');
149
 
150
 cmd 'kill';
151
 
152
-is_deeply(get_marks(), [ ], 'mark gone');
153
+is_deeply(get_marks(), [], 'mark gone');
154
 
155
 done_testing;

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

160
@@ -144,7 +144,7 @@ is(parser_calls("\nworkspace test"),
161
 ################################################################################
162
 
163
 is(parser_calls('unknown_literal'),
164
-   "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" .
165
+   "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" .
166
    "ERROR: Your command: unknown_literal\n" .
167
    "ERROR:               ^^^^^^^^^^^^^^^",
168
    'error for unknown literal ok');

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

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