]> git.sur5r.net Git - i3/i3/commitdiff
Implement 'rename workspace <old_name> to <new_name>'
authorMichael Stapelberg <michael@stapelberg.de>
Sun, 8 Apr 2012 18:34:31 +0000 (20:34 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Sun, 8 Apr 2012 18:40:00 +0000 (20:40 +0200)
docs/userguide
include/commands.h
parser-specs/commands.spec
src/commands.c
src/workspace.c
testcases/t/117-workspace.t
testcases/t/187-commands-parser.t

index 667cdde92eae574c012c6c72f1a58c5c5b0b4763..4145279302eff8368eaf01d353a8add6840d8d49 100644 (file)
@@ -1,7 +1,7 @@
 i3 User’s Guide
 ===============
 Michael Stapelberg <michael+i3@stapelberg.de>
-January 2012
+April 2012
 
 This document contains all the information you need to configure and use the i3
 window manager. If it does not, please contact us on IRC (preferred) or post your
@@ -1356,6 +1356,24 @@ to switch to the workspace which begins with number 1, regardless of which name
 it has. This is useful in case you are changing the workspace’s name
 dynamically.
 
+=== Renaming workspaces
+
+You can rename workspaces. This might be useful to start with the default
+numbered workspaces, do your work, and rename the workspaces afterwards to
+reflect what’s actually on them.
+
+*Syntax*:
+----------------------------------------------------
+rename workspace <old_name> to <new_name>
+----------------------------------------------------
+
+*Examples*:
+------------------------------------------------
+i3-msg 'rename workspace 5 to 6'
+i3-msg 'rename workspace 1 to "1: www"'
+i3-msg 'rename workspace "1: www" to "10: www"'
+------------------------------------------------
+
 [[resizingconfig]]
 
 === Resizing containers/windows
index 942007416bd29c88468e0ef9c7bb50e51240103d..85057d1919e9d31a171598d115d5491eabb07263 100644 (file)
@@ -259,4 +259,10 @@ void cmd_move_scratchpad(I3_CMD);
  */
 void cmd_scratchpad_show(I3_CMD);
 
+/**
+ * Implementation of 'rename workspace <name> to <name>'
+ *
+ */
+void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name);
+
 #endif
index aab5529da47eb199dd74453c083cd9405ff29911..684fd23e438a586f8b7b41f94ee2c8e75b438171 100644 (file)
@@ -31,6 +31,7 @@ state INITIAL:
   'floating' -> FLOATING
   'mark' -> MARK
   'resize' -> RESIZE
+  'rename' -> RENAME
   'nop' -> NOP
   'scratchpad' -> SCRATCHPAD
   'mode' -> MODE
@@ -173,6 +174,21 @@ state RESIZE_TILING_OR:
   end
       -> call cmd_resize($way, $direction, $resize_px, $resize_ppt)
 
+# rename workspace <name> to <name>
+state RENAME:
+  'workspace'
+      -> RENAME_WORKSPACE
+
+state RENAME_WORKSPACE:
+  old_name = word
+      -> RENAME_WORKSPACE_TO
+
+state RENAME_WORKSPACE_TO:
+  'to'
+      ->
+  new_name = string
+      -> call cmd_rename_workspace($old_name, $new_name)
+
 # move <direction> [<pixels> [px]]
 # move [window|container] [to] workspace <str>
 # move [window|container] [to] output <str>
index 1eff73909eb219579a48179d77f4cb7c017484d8..e8fb7f9068480c77351f2f53be0e4ed7b848253b 100644 (file)
@@ -1556,3 +1556,63 @@ void cmd_scratchpad_show(I3_CMD) {
     // XXX: default reply for now, make this a better reply
     cmd_output->json_output = sstrdup("{\"success\": true}");
 }
+
+/*
+ * Implementation of 'rename workspace <name> to <name>'
+ *
+ */
+void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) {
+    LOG("Renaming workspace \"%s\" to \"%s\"\n", old_name, new_name);
+
+    Con *output, *workspace = NULL;
+    TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
+        GREP_FIRST(workspace, output_get_content(output),
+            !strcasecmp(child->name, old_name));
+
+    if (!workspace) {
+        // TODO: we should include the old workspace name here and use yajl for
+        // generating the reply.
+        cmd_output->json_output = sstrdup("{\"success\": false, "
+            "\"error\":\"Old workspace not found\"}");
+        return;
+    }
+
+    Con *check_dest = NULL;
+    TAILQ_FOREACH(output, &(croot->nodes_head), nodes)
+        GREP_FIRST(check_dest, output_get_content(output),
+            !strcasecmp(child->name, new_name));
+
+    if (check_dest != NULL) {
+        // TODO: we should include the new workspace name here and use yajl for
+        // generating the reply.
+        cmd_output->json_output = sstrdup("{\"success\": false, "
+            "\"error\":\"New workspace already exists\"}");
+        return;
+    }
+
+    /* Change the name and try to parse it as a number. */
+    FREE(workspace->name);
+    workspace->name = sstrdup(new_name);
+    char *endptr = NULL;
+    long parsed_num = strtol(new_name, &endptr, 10);
+    if (parsed_num == LONG_MIN ||
+        parsed_num == LONG_MAX ||
+        parsed_num < 0 ||
+        endptr == new_name)
+        workspace->num = -1;
+    else workspace->num = parsed_num;
+    LOG("num = %d\n", workspace->num);
+
+    /* By re-attaching, the sort order will be correct afterwards. */
+    Con *previously_focused = focused;
+    Con *parent = workspace->parent;
+    con_detach(workspace);
+    con_attach(workspace, parent, false);
+    /* Restore the previous focus since con_attach messes with the focus. */
+    con_focus(previously_focused);
+
+    cmd_output->needs_tree_render = true;
+    cmd_output->json_output = sstrdup("{\"success\": true}");
+
+    ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"rename\"}");
+}
index 75b8a7b3f3289ce964e96494c48a1518a56a015f..87e26049ff5866a4c0eaaf763840b6c50a0d1f07 100644 (file)
@@ -52,8 +52,8 @@ Con *workspace_get(const char *num, bool *created) {
         workspace->type = CT_WORKSPACE;
         FREE(workspace->name);
         workspace->name = sstrdup(num);
-        /* We set ->num to the number if this workspace’s name consists only of
-         * positive number. Otherwise it’s a named ws and num will be -1. */
+        /* We set ->num to the number if this workspace’s name begins with a
+         * positive number. Otherwise it’s a named ws and num will be -1. */
         char *endptr = NULL;
         long parsed_num = strtol(num, &endptr, 10);
         if (parsed_num == LONG_MIN ||
index 9f4d270ca9055d77a3e2c74c137873eee33c56a8..6c9fc6e135c0110127a48c75cac382c55a6bfde0 100644 (file)
@@ -134,4 +134,83 @@ cmd 'workspace number 4';
 is(focused_ws(), '4: foo', 'now on workspace 4: foo');
 ok(!workspace_exists('4'), 'workspace 4 still does not exist');
 
+################################################################################
+# Verify that renaming workspaces works.
+################################################################################
+
+sub workspace_numbers_sorted {
+    my ($name) = @_;
+    my $i3 = i3(get_socket_path());
+    my $tree = $i3->get_tree->recv;
+
+    my @outputs = @{$tree->{nodes}};
+    my @workspaces;
+    for my $output (@outputs) {
+        # get the first CT_CON of each output
+        my $content = first { $_->{type} == 2 } @{$output->{nodes}};
+        @workspaces = (@workspaces, @{$content->{nodes}});
+    }
+
+    my @numbers = grep { $_ != -1 } map { $_->{num} } @workspaces;
+    is_deeply(
+        [ sort { $a <=> $b } @numbers ],
+        \@numbers,
+        'workspace numbers sorted');
+}
+
+# 1: numbered workspace
+cmd 'workspace 10';
+cmd 'open';
+cmd 'workspace 13';
+cmd 'open';
+
+workspace_numbers_sorted();
+
+cmd 'workspace 9';
+is(focused_ws(), '9', 'now on workspace 9');
+
+ok(!workspace_exists('12'), 'workspace 12 does not exist yet');
+cmd 'rename workspace 9 to 12';
+ok(!workspace_exists('9'), 'workspace 9 does not exist anymore');
+is(focused_ws(), '12', 'now on workspace 12');
+$ws = get_ws('12');
+is($ws->{num}, 12, 'number correctly changed');
+
+workspace_numbers_sorted();
+
+# 2: numbered + named workspace
+cmd 'workspace 9: foo';
+is(focused_ws(), '9: foo', 'now on workspace 9: foo');
+
+ok(!workspace_exists('11: bar'), 'workspace 11: bar does not exist yet');
+cmd 'rename workspace "9: foo" to "11: bar"';
+ok(!workspace_exists('9: foo'), 'workspace 9 does not exist anymore');
+is(focused_ws(), '11: bar', 'now on workspace 10');
+$ws = get_ws('11: bar');
+is($ws->{num}, 11, 'number correctly changed');
+workspace_numbers_sorted();
+# keep that one open, we need it later
+cmd 'open';
+
+# 3: named workspace
+cmd 'workspace bleh';
+is(focused_ws(), 'bleh', 'now on workspace bleh');
+
+ok(!workspace_exists('qux'), 'workspace qux does not exist yet');
+cmd 'rename workspace bleh to qux';
+ok(!workspace_exists('bleh'), 'workspace 9 does not exist anymore');
+is(focused_ws(), 'qux', 'now on workspace qux');
+$ws = get_ws('qux');
+is($ws->{num}, -1, 'number correctly changed');
+workspace_numbers_sorted();
+
+# 5: already existing workspace
+my $result = cmd 'rename workspace qux to 11: bar';
+ok(!$result->[0]->{success}, 'renaming workspace to an already existing one failed');
+
+# 6: non-existing old workspace (verify command result)
+$result = cmd 'rename workspace notexistant to bleh';
+ok(!$result->[0]->{success}, 'renaming workspace which does not exist failed');
+
+
 done_testing;
index 7e6f97bd1607fd7815c856e3aa8f39ff3716bfd8..8b57a0a1c7c9c4789871353b3e9d0dd5827181eb 100644 (file)
@@ -127,7 +127,7 @@ is(parser_calls("\nworkspace test"),
 ################################################################################
 
 is(parser_calls('unknown_literal'),
-   "Expected one of these tokens: <end>, '[', 'move', 'exec', 'exit', 'restart', 'reload', 'border', 'layout', 'append_layout', 'workspace', 'focus', 'kill', 'open', 'fullscreen', 'split', 'floating', 'mark', 'resize', 'nop', 'scratchpad', 'mode'\n" .
+   "Expected one of these tokens: <end>, '[', 'move', 'exec', 'exit', 'restart', 'reload', 'border', 'layout', 'append_layout', 'workspace', 'focus', 'kill', 'open', 'fullscreen', 'split', 'floating', 'mark', 'resize', 'rename', 'nop', 'scratchpad', 'mode'\n" .
    "Your command: unknown_literal\n" .
    "              ^^^^^^^^^^^^^^^",
    'error for unknown literal ok');