Implement 'rename workspace <old_name> to <new_name>'

This commit is contained in:
Michael Stapelberg 2012-04-08 20:34:31 +02:00
parent ad513b4799
commit 373b4ad74a
7 changed files with 183 additions and 4 deletions

View File

@ -1,7 +1,7 @@
i3 Users Guide i3 Users Guide
=============== ===============
Michael Stapelberg <michael+i3@stapelberg.de> Michael Stapelberg <michael+i3@stapelberg.de>
January 2012 April 2012
This document contains all the information you need to configure and use the i3 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 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 workspaces name it has. This is useful in case you are changing the workspaces name
dynamically. 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 whats 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]] [[resizingconfig]]
=== Resizing containers/windows === Resizing containers/windows

View File

@ -259,4 +259,10 @@ void cmd_move_scratchpad(I3_CMD);
*/ */
void cmd_scratchpad_show(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 #endif

View File

@ -31,6 +31,7 @@ state INITIAL:
'floating' -> FLOATING 'floating' -> FLOATING
'mark' -> MARK 'mark' -> MARK
'resize' -> RESIZE 'resize' -> RESIZE
'rename' -> RENAME
'nop' -> NOP 'nop' -> NOP
'scratchpad' -> SCRATCHPAD 'scratchpad' -> SCRATCHPAD
'mode' -> MODE 'mode' -> MODE
@ -173,6 +174,21 @@ state RESIZE_TILING_OR:
end end
-> call cmd_resize($way, $direction, $resize_px, $resize_ppt) -> 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 <direction> [<pixels> [px]]
# move [window|container] [to] workspace <str> # move [window|container] [to] workspace <str>
# move [window|container] [to] output <str> # move [window|container] [to] output <str>

View File

@ -1556,3 +1556,63 @@ void cmd_scratchpad_show(I3_CMD) {
// XXX: default reply for now, make this a better reply // XXX: default reply for now, make this a better reply
cmd_output->json_output = sstrdup("{\"success\": true}"); 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\"}");
}

View File

@ -52,8 +52,8 @@ Con *workspace_get(const char *num, bool *created) {
workspace->type = CT_WORKSPACE; workspace->type = CT_WORKSPACE;
FREE(workspace->name); FREE(workspace->name);
workspace->name = sstrdup(num); workspace->name = sstrdup(num);
/* We set ->num to the number if this workspaces name consists only of /* We set ->num to the number if this workspaces name begins with a
* a positive number. Otherwise its a named ws and num will be -1. */ * positive number. Otherwise its a named ws and num will be -1. */
char *endptr = NULL; char *endptr = NULL;
long parsed_num = strtol(num, &endptr, 10); long parsed_num = strtol(num, &endptr, 10);
if (parsed_num == LONG_MIN || if (parsed_num == LONG_MIN ||

View File

@ -134,4 +134,83 @@ cmd 'workspace number 4';
is(focused_ws(), '4: foo', 'now on workspace 4: foo'); is(focused_ws(), '4: foo', 'now on workspace 4: foo');
ok(!workspace_exists('4'), 'workspace 4 still does not exist'); 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; done_testing;

View File

@ -127,7 +127,7 @@ is(parser_calls("\nworkspace test"),
################################################################################ ################################################################################
is(parser_calls('unknown_literal'), 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" . "Your command: unknown_literal\n" .
" ^^^^^^^^^^^^^^^", " ^^^^^^^^^^^^^^^",
'error for unknown literal ok'); 'error for unknown literal ok');