2011-07-06 13:56:58 +02:00
|
|
|
|
#!/usr/bin/env perl
|
|
|
|
|
# vim:ts=4:sw=4:expandtab
|
|
|
|
|
#
|
|
|
|
|
# script to migrate an old config file (i3 < 4.0) to the new format (>= 4.0)
|
|
|
|
|
# this script only uses modules which come with perl 5.10
|
|
|
|
|
#
|
|
|
|
|
# reads an i3 v3 config from stdin and spits out a v4 config on stdout
|
|
|
|
|
# exit codes:
|
|
|
|
|
# 0 = the input was a v3 config
|
|
|
|
|
# 1 = the input was already a v4 config
|
|
|
|
|
# (the config is printed to stdout nevertheless)
|
|
|
|
|
#
|
|
|
|
|
# © 2011 Michael Stapelberg and contributors, see LICENSE
|
|
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
|
use warnings;
|
|
|
|
|
use Getopt::Long;
|
|
|
|
|
use v5.10;
|
|
|
|
|
|
|
|
|
|
# is this a version 3 config file? disables auto-detection
|
|
|
|
|
my $v3 = 0;
|
|
|
|
|
my $result = GetOptions('v3' => \$v3);
|
|
|
|
|
|
|
|
|
|
# reads stdin
|
|
|
|
|
sub slurp {
|
|
|
|
|
local $/;
|
|
|
|
|
<>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
my @unchanged = qw(
|
|
|
|
|
font
|
|
|
|
|
set
|
|
|
|
|
mode
|
|
|
|
|
exec
|
|
|
|
|
assign
|
|
|
|
|
floating_modifier
|
|
|
|
|
focus_follows_mouse
|
|
|
|
|
ipc-socket
|
|
|
|
|
ipc_socket
|
|
|
|
|
client.focused
|
|
|
|
|
client.focused_inactive
|
|
|
|
|
client.unfocused
|
|
|
|
|
client.urgent
|
2011-07-06 17:51:32 +02:00
|
|
|
|
client.background
|
2011-07-06 13:56:58 +02:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
my %workspace_names;
|
|
|
|
|
my $workspace_bar = 1;
|
|
|
|
|
|
|
|
|
|
my $input = slurp();
|
|
|
|
|
my @lines = split /\n/, $input;
|
|
|
|
|
|
|
|
|
|
# remove whitespaces in the beginning of lines
|
|
|
|
|
@lines = map { s/^[ \t]*//g; $_ } @lines;
|
|
|
|
|
|
|
|
|
|
# Try to auto-detect if this is a v3 config file.
|
|
|
|
|
sub need_to_convert {
|
|
|
|
|
# If the user passed --v3, we need to convert in any case
|
|
|
|
|
return 1 if $v3;
|
|
|
|
|
|
|
|
|
|
for my $line (@lines) {
|
|
|
|
|
# only v4 configfiles can use bindcode or workspace_layout
|
2011-07-08 00:17:48 +02:00
|
|
|
|
return 0 if $line =~ /^bindcode/ ||
|
|
|
|
|
$line =~ /^workspace_layout/ ||
|
|
|
|
|
$line =~ /^force_focus_wrapping/;
|
2011-07-06 13:56:58 +02:00
|
|
|
|
|
|
|
|
|
# have a look at bindings
|
|
|
|
|
next unless $line =~ /^bind/;
|
|
|
|
|
|
|
|
|
|
my ($statement, $key, $command) = ($line =~ /([a-zA-Z_-]+)[ \t]+([^ \t]+)[ \t]+(.*)/);
|
|
|
|
|
return 0 if $command =~ /^layout/ ||
|
|
|
|
|
$command =~ /^floating/ ||
|
|
|
|
|
$command =~ /^workspace/ ||
|
|
|
|
|
$command =~ /^focus (left|right|up|down)/ ||
|
2011-07-06 20:21:39 +02:00
|
|
|
|
$command =~ /^border (normal|1pixel|none)/;
|
2011-07-06 13:56:58 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!need_to_convert()) {
|
|
|
|
|
# If this is already a v4 config file, we will spit out the lines
|
|
|
|
|
# and exit with return code 1
|
|
|
|
|
print $input;
|
|
|
|
|
exit 1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-06 17:56:09 +02:00
|
|
|
|
# first pass: get workspace names
|
|
|
|
|
for my $line (@lines) {
|
|
|
|
|
next if $line =~ /^#/ || $line =~ /^$/;
|
|
|
|
|
|
|
|
|
|
my ($statement, $parameters) = ($line =~ /([a-zA-Z._-]+)(.*)/);
|
|
|
|
|
|
|
|
|
|
# skip everything but workspace lines
|
|
|
|
|
next unless defined($statement) and $statement eq 'workspace';
|
|
|
|
|
|
|
|
|
|
my ($number, $params) = ($parameters =~ /[ \t]+([0-9]+) (.+)/);
|
|
|
|
|
|
|
|
|
|
# save workspace name (unless the line is actually a workspace assignment)
|
|
|
|
|
$workspace_names{$number} = $params unless $params =~ /^output/;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-06 13:56:58 +02:00
|
|
|
|
for my $line (@lines) {
|
|
|
|
|
# directly use comments and empty lines
|
|
|
|
|
if ($line =~ /^#/ || $line =~ /^$/) {
|
|
|
|
|
print "$line\n";
|
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
my ($statement, $parameters) = ($line =~ /([a-zA-Z._-]+)(.*)/);
|
|
|
|
|
|
|
|
|
|
# directly use lines which have not changed between 3.x and 4.x
|
|
|
|
|
if (!defined($statement) || (lc $statement ~~ @unchanged)) {
|
|
|
|
|
print "$line\n";
|
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# new_container changed only the statement name to workspace_layout
|
|
|
|
|
if ($statement eq 'new_container') {
|
|
|
|
|
# TODO: new_container stack-limit
|
|
|
|
|
print "workspace_layout$parameters\n";
|
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# workspace_bar is gone, you should use i3bar now
|
|
|
|
|
if ($statement eq 'workspace_bar') {
|
|
|
|
|
$workspace_bar = ($parameters =~ /[ \t+](yes|true|on|enable|active)/);
|
|
|
|
|
print "# XXX: REMOVED workspace_bar line. There is no internal workspace bar in v4.\n";
|
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-06 20:21:39 +02:00
|
|
|
|
# new_window changed the parameters from bb to none etc.
|
2011-07-06 13:56:58 +02:00
|
|
|
|
if ($statement eq 'new_window') {
|
|
|
|
|
if ($parameters =~ /bb/) {
|
2011-07-06 20:21:39 +02:00
|
|
|
|
print "new_window none\n";
|
2011-07-06 13:56:58 +02:00
|
|
|
|
} elsif ($parameters =~ /bp/) {
|
|
|
|
|
print "new_window 1pixel\n";
|
|
|
|
|
} elsif ($parameters =~ /bn/) {
|
|
|
|
|
print "new_window normal\n";
|
|
|
|
|
} else {
|
|
|
|
|
print "# XXX: Invalid parameter for new_window, not touching line:\n";
|
|
|
|
|
print "$line\n";
|
|
|
|
|
}
|
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# bar colors are obsolete, need to be configured in i3bar
|
|
|
|
|
if ($statement =~ /^bar\./) {
|
|
|
|
|
print "# XXX: REMOVED $statement, configure i3bar instead.\n";
|
2011-07-06 17:50:14 +02:00
|
|
|
|
print "# Old line: $line\n";
|
2011-07-06 13:56:58 +02:00
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# one form of this is still ok (workspace assignments), the other (named workspaces) isn’t
|
|
|
|
|
if ($statement eq 'workspace') {
|
|
|
|
|
my ($number, $params) = ($parameters =~ /[ \t]+([0-9]+) (.+)/);
|
|
|
|
|
if ($params =~ /^output/) {
|
|
|
|
|
print "$line\n";
|
|
|
|
|
next;
|
|
|
|
|
} else {
|
2011-07-06 17:56:09 +02:00
|
|
|
|
print "# XXX: workspace name will end up in the corresponding bindings.\n";
|
2011-07-06 13:56:58 +02:00
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($statement eq 'bind' || $statement eq 'bindsym') {
|
|
|
|
|
convert_command($line);
|
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print "# XXX: migration script could not handle line: $line\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Converts a command (after bind/bindsym)
|
|
|
|
|
#
|
|
|
|
|
sub convert_command {
|
|
|
|
|
my ($line) = @_;
|
|
|
|
|
|
|
|
|
|
my @unchanged_cmds = qw(
|
|
|
|
|
exec
|
|
|
|
|
mark
|
|
|
|
|
kill
|
|
|
|
|
restart
|
|
|
|
|
reload
|
|
|
|
|
exit
|
|
|
|
|
stack-limit
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
my ($statement, $key, $command) = ($line =~ /([a-zA-Z_-]+)[ \t]+([^ \t]+)[ \t]+(.*)/);
|
|
|
|
|
|
|
|
|
|
# turn 'bind' to 'bindcode'
|
|
|
|
|
$statement = 'bindcode' if $statement eq 'bind';
|
|
|
|
|
|
|
|
|
|
# check if it’s one of the unchanged commands
|
|
|
|
|
my ($cmd) = ($command =~ /([a-zA-Z_-]+)/);
|
|
|
|
|
if ($cmd ~~ @unchanged_cmds) {
|
|
|
|
|
print "$statement $key $command\n";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# simple replacements
|
|
|
|
|
my @replace = (
|
|
|
|
|
qr/^s/ => 'layout stacking',
|
|
|
|
|
qr/^d/ => 'layout default',
|
|
|
|
|
qr/^T/ => 'layout tabbed',
|
|
|
|
|
qr/^f($|[^go])/ => 'fullscreen',
|
|
|
|
|
qr/^fg/ => 'fullscreen global',
|
2011-07-12 21:29:30 +02:00
|
|
|
|
qr/^t/ => 'floating toggle',
|
2011-07-06 13:56:58 +02:00
|
|
|
|
qr/^h/ => 'focus left',
|
|
|
|
|
qr/^j($|[^u])/ => 'focus down',
|
|
|
|
|
qr/^k/ => 'focus up',
|
|
|
|
|
qr/^l/ => 'focus right',
|
|
|
|
|
qr/^mh/ => 'move left',
|
|
|
|
|
qr/^mj/ => 'move down',
|
|
|
|
|
qr/^mk/ => 'move up',
|
|
|
|
|
qr/^ml/ => 'move right',
|
|
|
|
|
qr/^bn/ => 'border normal',
|
|
|
|
|
qr/^bp/ => 'border 1pixel',
|
2011-07-06 20:21:39 +02:00
|
|
|
|
qr/^bb/ => 'border none',
|
2011-07-09 01:02:13 +02:00
|
|
|
|
qr/^bt/ => 'border toggle',
|
2011-07-06 13:56:58 +02:00
|
|
|
|
qr/^pw/ => 'workspace prev',
|
|
|
|
|
qr/^nw/ => 'workspace next',
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
my $replaced = 0;
|
|
|
|
|
for (my $c = 0; $c < @replace; $c += 2) {
|
|
|
|
|
if ($command =~ $replace[$c]) {
|
|
|
|
|
$command = $replace[$c+1];
|
|
|
|
|
$replaced = 1;
|
|
|
|
|
last;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# goto command is now obsolete due to criteria + focus command
|
|
|
|
|
if ($command =~ /^goto/) {
|
|
|
|
|
my ($mark) = ($command =~ /^goto (.*)/);
|
|
|
|
|
print qq|$statement $key [con_mark="$mark"] focus\n|;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# the jump command is also obsolete due to criteria + focus
|
|
|
|
|
if ($command =~ /^jump/) {
|
|
|
|
|
my ($params) = ($command =~ /^jump (.*)/);
|
|
|
|
|
if ($params =~ /^"/) {
|
|
|
|
|
# jump ["]window class[/window title]["]
|
|
|
|
|
($params) = ($params =~ /^"([^"]+)"/);
|
|
|
|
|
|
|
|
|
|
# check if a window title was specified
|
|
|
|
|
if ($params =~ m,/,) {
|
|
|
|
|
my ($class, $title) = ($params =~ m,([^/]+)/(.+),);
|
|
|
|
|
print qq|$statement $key [class="$class" title="$title"] focus\n|;
|
|
|
|
|
} else {
|
|
|
|
|
print qq|$statement $key [class="$params"] focus\n|;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
# jump <workspace> [ column row ]
|
|
|
|
|
print "# XXX: jump workspace is obsolete in 4.x: $line\n";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!$replaced && $command =~ /^focus/) {
|
|
|
|
|
my ($what) = ($command =~ /^focus (.*)/);
|
|
|
|
|
$what =~ s/[ \t]//g;
|
|
|
|
|
if ($what eq 'ft') {
|
|
|
|
|
$what = 'mode_toggle';
|
|
|
|
|
} elsif ($what eq 'floating' || $what eq 'tiling') {
|
|
|
|
|
# those are unchanged
|
|
|
|
|
} else {
|
|
|
|
|
print "# XXX: focus <number> is obsolete in 4.x: $line\n";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
print qq|$statement $key focus $what\n|;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-15 00:22:26 +02:00
|
|
|
|
if ($command =~ /^mode/) {
|
|
|
|
|
my ($parameters) = ($command =~ /^mode (.*)/);
|
|
|
|
|
print qq|$statement $key mode "$parameters"\n|;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-06 13:56:58 +02:00
|
|
|
|
# the parameters of the resize command have changed
|
|
|
|
|
if ($command =~ /^resize/) {
|
|
|
|
|
# OLD: resize <left|right|top|bottom> [+|-]<pixels>\n")
|
|
|
|
|
# NEW: resize <grow|shrink> <direction> [<px> px] [or <ppt> ppt]
|
|
|
|
|
my ($direction, $sign, $px) = ($command =~ /^resize (left|right|top|bottom) ([+-])([0-9]+)/);
|
|
|
|
|
my $cmd = 'resize ';
|
|
|
|
|
$cmd .= ($sign eq '+' ? 'grow' : 'shrink') . ' ';
|
2011-08-08 22:18:55 +02:00
|
|
|
|
if ($direction eq 'top') {
|
|
|
|
|
$direction = 'down';
|
|
|
|
|
} elsif ($direction eq 'bottom') {
|
|
|
|
|
$direction = 'up';
|
|
|
|
|
}
|
2011-07-06 13:56:58 +02:00
|
|
|
|
$cmd .= "$direction ";
|
|
|
|
|
$cmd .= "$px px";
|
|
|
|
|
print qq|$statement $key $cmd\n|;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# switch workspace
|
|
|
|
|
if ($command =~ /^[0-9]+/) {
|
|
|
|
|
my ($number) = ($command =~ /^([0-9]+)/);
|
|
|
|
|
if (exists $workspace_names{$number}) {
|
|
|
|
|
print qq|$statement $key workspace $workspace_names{$number}\n|;
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
print qq|$statement $key workspace $number\n|;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# move to workspace
|
|
|
|
|
if ($command =~ /^m[0-9]+/) {
|
|
|
|
|
my ($number) = ($command =~ /^m([0-9]+)/);
|
|
|
|
|
if (exists $workspace_names{$number}) {
|
|
|
|
|
print qq|$statement $key move workspace $workspace_names{$number}\n|;
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
print qq|$statement $key move workspace $number\n|;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# With Container-commands are now obsolete due to different abstraction
|
|
|
|
|
if ($command =~ /^wc/) {
|
2011-07-27 14:36:22 +02:00
|
|
|
|
$command =~ s/^wc//g;
|
|
|
|
|
my $wc_replaced = 0;
|
|
|
|
|
for (my $c = 0; $c < @replace; $c += 2) {
|
|
|
|
|
if ($command =~ $replace[$c]) {
|
|
|
|
|
$command = $replace[$c+1];
|
|
|
|
|
$wc_replaced = 1;
|
|
|
|
|
last;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!$wc_replaced) {
|
|
|
|
|
print "# XXX: migration script could not handle command: $line\n";
|
|
|
|
|
} else {
|
|
|
|
|
# NOTE: This is not 100% accurate, as it only works for one level
|
|
|
|
|
# of nested containers. As this is a common use case, we use 'focus
|
|
|
|
|
# parent; $command' nevertheless. For advanced use cases, the user
|
|
|
|
|
# has to modify his config.
|
|
|
|
|
print "$statement $key focus parent; $command\n";
|
|
|
|
|
}
|
2011-07-06 13:56:58 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($replaced) {
|
|
|
|
|
print "$statement $key $command\n";
|
|
|
|
|
} else {
|
|
|
|
|
print "# XXX: migration script could not handle command: $line\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# add an i3bar invocation automatically if no 'workspace_bar no' was found
|
|
|
|
|
if ($workspace_bar) {
|
|
|
|
|
print "\n";
|
|
|
|
|
print "# XXX: Automatically added a call to i3bar to provide a workspace bar\n";
|
|
|
|
|
print "exec i3status | i3bar -d\n";
|
|
|
|
|
}
|