Implement 'rename workspace <old_name> to <new_name>'
This commit is contained in:
parent
ad513b4799
commit
373b4ad74a
|
@ -1,7 +1,7 @@
|
||||||
i3 User’s Guide
|
i3 User’s 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 workspace’s name
|
it has. This is useful in case you are changing the workspace’s 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 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]]
|
[[resizingconfig]]
|
||||||
|
|
||||||
=== Resizing containers/windows
|
=== Resizing containers/windows
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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\"}");
|
||||||
|
}
|
||||||
|
|
|
@ -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 workspace’s name consists only of
|
/* We set ->num to the number if this workspace’s name begins with a
|
||||||
* a positive number. Otherwise it’s a named ws and num will be -1. */
|
* positive number. Otherwise it’s 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 ||
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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');
|
||||||
|
|
Loading…
Reference in New Issue