Implement a new parser for commands. (+test)
On the rationale of using a custom parser instead of a lex/yacc one, see this
quote from src/commands_parser.c:
We use a hand-written parser instead of lex/yacc because our commands are
easy for humans, not for computers. Thus, it’s quite hard to specify a
context-free grammar for the commands. A PEG grammar would be easier, but
there’s downsides to every PEG parser generator I have come accross so far.
This parser is basically a state machine which looks for literals or strings
and can push either on a stack. After identifying a literal or string, it
will either transition to the current state, to a different state, or call a
function (like cmd_move()).
Special care has been taken that error messages are useful and the code is
well testable (when compiled with -DTEST_PARSER it will output to stdout
instead of actually calling any function).
During the migration phase (I plan to completely switch to this parser before
4.2 will be released), the new parser will parse every command you send to
i3 and save the resulting call stack. Then, the old parser will parse your
input and actually execute the commands. Afterwards, both call stacks will be
compared and any differences will be logged.
The new parser works with 100% of the test suite and produces identical call
stacks.
2012-01-14 20:53:29 +01:00
|
|
|
|
#!perl
|
|
|
|
|
# vim:ts=4:sw=4:expandtab
|
|
|
|
|
#
|
2012-09-10 14:09:01 +02:00
|
|
|
|
# Please read the following documents before working on tests:
|
|
|
|
|
# • http://build.i3wm.org/docs/testsuite.html
|
|
|
|
|
# (or docs/testsuite)
|
|
|
|
|
#
|
|
|
|
|
# • http://build.i3wm.org/docs/lib-i3test.html
|
|
|
|
|
# (alternatively: perldoc ./testcases/lib/i3test.pm)
|
|
|
|
|
#
|
|
|
|
|
# • http://build.i3wm.org/docs/ipc.html
|
|
|
|
|
# (or docs/ipc)
|
|
|
|
|
#
|
|
|
|
|
# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
|
|
|
|
|
# (unless you are already familiar with Perl)
|
|
|
|
|
#
|
Implement a new parser for commands. (+test)
On the rationale of using a custom parser instead of a lex/yacc one, see this
quote from src/commands_parser.c:
We use a hand-written parser instead of lex/yacc because our commands are
easy for humans, not for computers. Thus, it’s quite hard to specify a
context-free grammar for the commands. A PEG grammar would be easier, but
there’s downsides to every PEG parser generator I have come accross so far.
This parser is basically a state machine which looks for literals or strings
and can push either on a stack. After identifying a literal or string, it
will either transition to the current state, to a different state, or call a
function (like cmd_move()).
Special care has been taken that error messages are useful and the code is
well testable (when compiled with -DTEST_PARSER it will output to stdout
instead of actually calling any function).
During the migration phase (I plan to completely switch to this parser before
4.2 will be released), the new parser will parse every command you send to
i3 and save the resulting call stack. Then, the old parser will parse your
input and actually execute the commands. Afterwards, both call stacks will be
compared and any differences will be logged.
The new parser works with 100% of the test suite and produces identical call
stacks.
2012-01-14 20:53:29 +01:00
|
|
|
|
# Tests the standalone parser binary to see if it calls the right code when
|
|
|
|
|
# confronted with various commands, if it prints proper error messages for
|
|
|
|
|
# wrong commands and if it terminates in every case.
|
|
|
|
|
#
|
|
|
|
|
use i3test i3_autostart => 0;
|
|
|
|
|
|
|
|
|
|
sub parser_calls {
|
|
|
|
|
my ($command) = @_;
|
|
|
|
|
|
|
|
|
|
# TODO: use a timeout, so that we can error out if it doesn’t terminate
|
|
|
|
|
# TODO: better way of passing arguments
|
2012-08-02 17:43:00 +02:00
|
|
|
|
my $stdout = qx(../test.commands_parser '$command' 2>&1 >&-);
|
Implement a new parser for commands. (+test)
On the rationale of using a custom parser instead of a lex/yacc one, see this
quote from src/commands_parser.c:
We use a hand-written parser instead of lex/yacc because our commands are
easy for humans, not for computers. Thus, it’s quite hard to specify a
context-free grammar for the commands. A PEG grammar would be easier, but
there’s downsides to every PEG parser generator I have come accross so far.
This parser is basically a state machine which looks for literals or strings
and can push either on a stack. After identifying a literal or string, it
will either transition to the current state, to a different state, or call a
function (like cmd_move()).
Special care has been taken that error messages are useful and the code is
well testable (when compiled with -DTEST_PARSER it will output to stdout
instead of actually calling any function).
During the migration phase (I plan to completely switch to this parser before
4.2 will be released), the new parser will parse every command you send to
i3 and save the resulting call stack. Then, the old parser will parse your
input and actually execute the commands. Afterwards, both call stacks will be
compared and any differences will be logged.
The new parser works with 100% of the test suite and produces identical call
stacks.
2012-01-14 20:53:29 +01:00
|
|
|
|
|
|
|
|
|
# Filter out all debugging output.
|
|
|
|
|
my @lines = split("\n", $stdout);
|
|
|
|
|
@lines = grep { not /^# / } @lines;
|
|
|
|
|
|
|
|
|
|
# The criteria management calls are irrelevant and not what we want to test
|
|
|
|
|
# in the first place.
|
|
|
|
|
@lines = grep { !(/cmd_criteria_init()/ || /cmd_criteria_match_windows/) } @lines;
|
|
|
|
|
return join("\n", @lines);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################################
|
|
|
|
|
# 1: First that the parser properly recognizes commands which are ok.
|
|
|
|
|
################################################################################
|
|
|
|
|
|
2012-02-21 14:22:26 +01:00
|
|
|
|
# The first call has only a single command, the following ones are consolidated
|
|
|
|
|
# for performance.
|
Implement a new parser for commands. (+test)
On the rationale of using a custom parser instead of a lex/yacc one, see this
quote from src/commands_parser.c:
We use a hand-written parser instead of lex/yacc because our commands are
easy for humans, not for computers. Thus, it’s quite hard to specify a
context-free grammar for the commands. A PEG grammar would be easier, but
there’s downsides to every PEG parser generator I have come accross so far.
This parser is basically a state machine which looks for literals or strings
and can push either on a stack. After identifying a literal or string, it
will either transition to the current state, to a different state, or call a
function (like cmd_move()).
Special care has been taken that error messages are useful and the code is
well testable (when compiled with -DTEST_PARSER it will output to stdout
instead of actually calling any function).
During the migration phase (I plan to completely switch to this parser before
4.2 will be released), the new parser will parse every command you send to
i3 and save the resulting call stack. Then, the old parser will parse your
input and actually execute the commands. Afterwards, both call stacks will be
compared and any differences will be logged.
The new parser works with 100% of the test suite and produces identical call
stacks.
2012-01-14 20:53:29 +01:00
|
|
|
|
is(parser_calls('move workspace 3'),
|
|
|
|
|
'cmd_move_con_to_workspace_name(3)',
|
|
|
|
|
'single number (move workspace 3) ok');
|
|
|
|
|
|
2012-02-21 14:22:26 +01:00
|
|
|
|
is(parser_calls(
|
|
|
|
|
'move to workspace 3; ' .
|
|
|
|
|
'move window to workspace 3; ' .
|
|
|
|
|
'move container to workspace 3; ' .
|
|
|
|
|
'move workspace foobar; ' .
|
2013-02-19 00:27:55 +01:00
|
|
|
|
'move workspace torrent; ' .
|
|
|
|
|
'move workspace to output LVDS1; ' .
|
2012-02-21 14:22:26 +01:00
|
|
|
|
'move workspace 3: foobar; ' .
|
|
|
|
|
'move workspace "3: foobar"; ' .
|
|
|
|
|
'move workspace "3: foobar, baz"; '),
|
|
|
|
|
"cmd_move_con_to_workspace_name(3)\n" .
|
|
|
|
|
"cmd_move_con_to_workspace_name(3)\n" .
|
|
|
|
|
"cmd_move_con_to_workspace_name(3)\n" .
|
|
|
|
|
"cmd_move_con_to_workspace_name(foobar)\n" .
|
2013-02-19 00:27:55 +01:00
|
|
|
|
"cmd_move_con_to_workspace_name(torrent)\n" .
|
|
|
|
|
"cmd_move_workspace_to_output(LVDS1)\n" .
|
2012-02-21 14:22:26 +01:00
|
|
|
|
"cmd_move_con_to_workspace_name(3: foobar)\n" .
|
|
|
|
|
"cmd_move_con_to_workspace_name(3: foobar)\n" .
|
|
|
|
|
"cmd_move_con_to_workspace_name(3: foobar, baz)",
|
|
|
|
|
'move ok');
|
Implement a new parser for commands. (+test)
On the rationale of using a custom parser instead of a lex/yacc one, see this
quote from src/commands_parser.c:
We use a hand-written parser instead of lex/yacc because our commands are
easy for humans, not for computers. Thus, it’s quite hard to specify a
context-free grammar for the commands. A PEG grammar would be easier, but
there’s downsides to every PEG parser generator I have come accross so far.
This parser is basically a state machine which looks for literals or strings
and can push either on a stack. After identifying a literal or string, it
will either transition to the current state, to a different state, or call a
function (like cmd_move()).
Special care has been taken that error messages are useful and the code is
well testable (when compiled with -DTEST_PARSER it will output to stdout
instead of actually calling any function).
During the migration phase (I plan to completely switch to this parser before
4.2 will be released), the new parser will parse every command you send to
i3 and save the resulting call stack. Then, the old parser will parse your
input and actually execute the commands. Afterwards, both call stacks will be
compared and any differences will be logged.
The new parser works with 100% of the test suite and produces identical call
stacks.
2012-01-14 20:53:29 +01:00
|
|
|
|
|
|
|
|
|
is(parser_calls('move workspace 3: foobar, nop foo'),
|
|
|
|
|
"cmd_move_con_to_workspace_name(3: foobar)\n" .
|
|
|
|
|
"cmd_nop(foo)",
|
|
|
|
|
'multiple ops (move workspace 3: foobar, nop foo) ok');
|
|
|
|
|
|
2012-02-21 14:22:26 +01:00
|
|
|
|
is(parser_calls(
|
|
|
|
|
'exec i3-sensible-terminal; ' .
|
|
|
|
|
'exec --no-startup-id i3-sensible-terminal'),
|
|
|
|
|
"cmd_exec((null), i3-sensible-terminal)\n" .
|
|
|
|
|
"cmd_exec(--no-startup-id, i3-sensible-terminal)",
|
Implement a new parser for commands. (+test)
On the rationale of using a custom parser instead of a lex/yacc one, see this
quote from src/commands_parser.c:
We use a hand-written parser instead of lex/yacc because our commands are
easy for humans, not for computers. Thus, it’s quite hard to specify a
context-free grammar for the commands. A PEG grammar would be easier, but
there’s downsides to every PEG parser generator I have come accross so far.
This parser is basically a state machine which looks for literals or strings
and can push either on a stack. After identifying a literal or string, it
will either transition to the current state, to a different state, or call a
function (like cmd_move()).
Special care has been taken that error messages are useful and the code is
well testable (when compiled with -DTEST_PARSER it will output to stdout
instead of actually calling any function).
During the migration phase (I plan to completely switch to this parser before
4.2 will be released), the new parser will parse every command you send to
i3 and save the resulting call stack. Then, the old parser will parse your
input and actually execute the commands. Afterwards, both call stacks will be
compared and any differences will be logged.
The new parser works with 100% of the test suite and produces identical call
stacks.
2012-01-14 20:53:29 +01:00
|
|
|
|
'exec ok');
|
|
|
|
|
|
2012-02-21 14:22:26 +01:00
|
|
|
|
is(parser_calls(
|
|
|
|
|
'resize shrink left; ' .
|
|
|
|
|
'resize shrink left 25 px; ' .
|
|
|
|
|
'resize shrink left 25 px or 33 ppt; ' .
|
|
|
|
|
'resize shrink left 25'),
|
|
|
|
|
"cmd_resize(shrink, left, 10, 10)\n" .
|
|
|
|
|
"cmd_resize(shrink, left, 25, 10)\n" .
|
|
|
|
|
"cmd_resize(shrink, left, 25, 33)\n" .
|
|
|
|
|
"cmd_resize(shrink, left, 25, 10)",
|
Implement a new parser for commands. (+test)
On the rationale of using a custom parser instead of a lex/yacc one, see this
quote from src/commands_parser.c:
We use a hand-written parser instead of lex/yacc because our commands are
easy for humans, not for computers. Thus, it’s quite hard to specify a
context-free grammar for the commands. A PEG grammar would be easier, but
there’s downsides to every PEG parser generator I have come accross so far.
This parser is basically a state machine which looks for literals or strings
and can push either on a stack. After identifying a literal or string, it
will either transition to the current state, to a different state, or call a
function (like cmd_move()).
Special care has been taken that error messages are useful and the code is
well testable (when compiled with -DTEST_PARSER it will output to stdout
instead of actually calling any function).
During the migration phase (I plan to completely switch to this parser before
4.2 will be released), the new parser will parse every command you send to
i3 and save the resulting call stack. Then, the old parser will parse your
input and actually execute the commands. Afterwards, both call stacks will be
compared and any differences will be logged.
The new parser works with 100% of the test suite and produces identical call
stacks.
2012-01-14 20:53:29 +01:00
|
|
|
|
'simple resize ok');
|
|
|
|
|
|
|
|
|
|
is(parser_calls('resize shrink left 25 px or 33 ppt,'),
|
|
|
|
|
'cmd_resize(shrink, left, 25, 33)',
|
|
|
|
|
'trailing comma resize ok');
|
|
|
|
|
|
|
|
|
|
is(parser_calls('resize shrink left 25 px or 33 ppt;'),
|
|
|
|
|
'cmd_resize(shrink, left, 25, 33)',
|
|
|
|
|
'trailing semicolon resize ok');
|
|
|
|
|
|
|
|
|
|
is(parser_calls('[con_mark=yay] focus'),
|
|
|
|
|
"cmd_criteria_add(con_mark, yay)\n" .
|
|
|
|
|
"cmd_focus()",
|
|
|
|
|
'criteria focus ok');
|
|
|
|
|
|
|
|
|
|
is(parser_calls("[con_mark=yay con_mark=bar] focus"),
|
|
|
|
|
"cmd_criteria_add(con_mark, yay)\n" .
|
|
|
|
|
"cmd_criteria_add(con_mark, bar)\n" .
|
|
|
|
|
"cmd_focus()",
|
|
|
|
|
'criteria focus ok');
|
|
|
|
|
|
|
|
|
|
is(parser_calls("[con_mark=yay\tcon_mark=bar] focus"),
|
|
|
|
|
"cmd_criteria_add(con_mark, yay)\n" .
|
|
|
|
|
"cmd_criteria_add(con_mark, bar)\n" .
|
|
|
|
|
"cmd_focus()",
|
|
|
|
|
'criteria focus ok');
|
|
|
|
|
|
|
|
|
|
is(parser_calls("[con_mark=yay\tcon_mark=bar]\tfocus"),
|
|
|
|
|
"cmd_criteria_add(con_mark, yay)\n" .
|
|
|
|
|
"cmd_criteria_add(con_mark, bar)\n" .
|
|
|
|
|
"cmd_focus()",
|
|
|
|
|
'criteria focus ok');
|
|
|
|
|
|
|
|
|
|
is(parser_calls('[con_mark="yay"] focus'),
|
|
|
|
|
"cmd_criteria_add(con_mark, yay)\n" .
|
|
|
|
|
"cmd_focus()",
|
|
|
|
|
'quoted criteria focus ok');
|
|
|
|
|
|
2012-01-25 23:00:32 +01:00
|
|
|
|
# Make sure trailing whitespace is stripped off: While this is not an issue for
|
|
|
|
|
# commands being parsed due to the configuration, people might send IPC
|
|
|
|
|
# commands with leading or trailing newlines.
|
|
|
|
|
is(parser_calls("workspace test\n"),
|
|
|
|
|
'cmd_workspace_name(test)',
|
|
|
|
|
'trailing whitespace stripped off ok');
|
|
|
|
|
|
|
|
|
|
is(parser_calls("\nworkspace test"),
|
|
|
|
|
'cmd_workspace_name(test)',
|
|
|
|
|
'trailing whitespace stripped off ok');
|
|
|
|
|
|
Implement a new parser for commands. (+test)
On the rationale of using a custom parser instead of a lex/yacc one, see this
quote from src/commands_parser.c:
We use a hand-written parser instead of lex/yacc because our commands are
easy for humans, not for computers. Thus, it’s quite hard to specify a
context-free grammar for the commands. A PEG grammar would be easier, but
there’s downsides to every PEG parser generator I have come accross so far.
This parser is basically a state machine which looks for literals or strings
and can push either on a stack. After identifying a literal or string, it
will either transition to the current state, to a different state, or call a
function (like cmd_move()).
Special care has been taken that error messages are useful and the code is
well testable (when compiled with -DTEST_PARSER it will output to stdout
instead of actually calling any function).
During the migration phase (I plan to completely switch to this parser before
4.2 will be released), the new parser will parse every command you send to
i3 and save the resulting call stack. Then, the old parser will parse your
input and actually execute the commands. Afterwards, both call stacks will be
compared and any differences will be logged.
The new parser works with 100% of the test suite and produces identical call
stacks.
2012-01-14 20:53:29 +01:00
|
|
|
|
################################################################################
|
|
|
|
|
# 2: Verify that the parser spits out the right error message on commands which
|
|
|
|
|
# are not ok.
|
|
|
|
|
################################################################################
|
|
|
|
|
|
|
|
|
|
is(parser_calls('unknown_literal'),
|
introduced i3 command for changing the hidden state and the mode of i3bar
The hidden_state and mode of each i3bar instance can now be controlled from within i3.
Therefore, two new i3 command were introduced:
_
bar hidden_state show|hide|toggle [<bar_id>]
show: always show the bar
hide: normal hide mode
toggle: toggle between show and hide (individually for each bar)
_
bar mode dock|hide|invisible|toggle [<bar_id>]
hide,dock: like before
invisible: always keep the bar hidden
toggle: toggle between dock and hide (individually for each bar)
This patch introduces a hidden_state ("hidden_state hide|show") in the
barconfig, which indicates the current hidden_state of each i3bar
instance. It only affects the bar when in hide mode. Additionally, a new
invisible mode was introduced. In order to change the hidden_state or
mode of the bar from i3, a barconfig-update event was introduced, for
which a bar can subscribe and the bar then gets notified about the
currently set hidden_state and mode in its barconfig.
For convenience, an id field ("id <bar_id>") was added to the barconfig, where one can
set the desired id for the corresponding bar. If the id is not specified, i3 will
deterministically choose an id; otherwise, with the previous random approach for finding
a new id, which is actually not shared with i3bar, as it would determine its id on
startup, the event-subscription would be destroyed on reload. Still, this issue remains
when manually changing the bar_id in the config and then reloading.
fixes #833, #651
2013-05-25 14:30:00 +02:00
|
|
|
|
"ERROR: 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', 'bar'\n" .
|
2012-08-02 17:43:00 +02:00
|
|
|
|
"ERROR: Your command: unknown_literal\n" .
|
|
|
|
|
"ERROR: ^^^^^^^^^^^^^^^",
|
Implement a new parser for commands. (+test)
On the rationale of using a custom parser instead of a lex/yacc one, see this
quote from src/commands_parser.c:
We use a hand-written parser instead of lex/yacc because our commands are
easy for humans, not for computers. Thus, it’s quite hard to specify a
context-free grammar for the commands. A PEG grammar would be easier, but
there’s downsides to every PEG parser generator I have come accross so far.
This parser is basically a state machine which looks for literals or strings
and can push either on a stack. After identifying a literal or string, it
will either transition to the current state, to a different state, or call a
function (like cmd_move()).
Special care has been taken that error messages are useful and the code is
well testable (when compiled with -DTEST_PARSER it will output to stdout
instead of actually calling any function).
During the migration phase (I plan to completely switch to this parser before
4.2 will be released), the new parser will parse every command you send to
i3 and save the resulting call stack. Then, the old parser will parse your
input and actually execute the commands. Afterwards, both call stacks will be
compared and any differences will be logged.
The new parser works with 100% of the test suite and produces identical call
stacks.
2012-01-14 20:53:29 +01:00
|
|
|
|
'error for unknown literal ok');
|
|
|
|
|
|
|
|
|
|
is(parser_calls('move something to somewhere'),
|
2012-08-02 17:43:00 +02:00
|
|
|
|
"ERROR: Expected one of these tokens: 'window', 'container', 'to', 'workspace', 'output', 'scratchpad', 'left', 'right', 'up', 'down', 'position', 'absolute'\n" .
|
|
|
|
|
"ERROR: Your command: move something to somewhere\n" .
|
|
|
|
|
"ERROR: ^^^^^^^^^^^^^^^^^^^^^^",
|
Implement a new parser for commands. (+test)
On the rationale of using a custom parser instead of a lex/yacc one, see this
quote from src/commands_parser.c:
We use a hand-written parser instead of lex/yacc because our commands are
easy for humans, not for computers. Thus, it’s quite hard to specify a
context-free grammar for the commands. A PEG grammar would be easier, but
there’s downsides to every PEG parser generator I have come accross so far.
This parser is basically a state machine which looks for literals or strings
and can push either on a stack. After identifying a literal or string, it
will either transition to the current state, to a different state, or call a
function (like cmd_move()).
Special care has been taken that error messages are useful and the code is
well testable (when compiled with -DTEST_PARSER it will output to stdout
instead of actually calling any function).
During the migration phase (I plan to completely switch to this parser before
4.2 will be released), the new parser will parse every command you send to
i3 and save the resulting call stack. Then, the old parser will parse your
input and actually execute the commands. Afterwards, both call stacks will be
compared and any differences will be logged.
The new parser works with 100% of the test suite and produces identical call
stacks.
2012-01-14 20:53:29 +01:00
|
|
|
|
'error for unknown literal ok');
|
|
|
|
|
|
2012-01-30 17:55:06 +01:00
|
|
|
|
################################################################################
|
|
|
|
|
# 3: Verify that escaping of double quotes works correctly
|
|
|
|
|
################################################################################
|
|
|
|
|
|
|
|
|
|
is(parser_calls('workspace "foo"'),
|
|
|
|
|
'cmd_workspace_name(foo)',
|
|
|
|
|
'Command with simple double quotes ok');
|
|
|
|
|
|
2012-02-10 20:49:38 +01:00
|
|
|
|
is(parser_calls('workspace "foo'),
|
|
|
|
|
'cmd_workspace_name(foo)',
|
|
|
|
|
'Command without ending double quotes ok');
|
|
|
|
|
|
2012-01-30 17:55:06 +01:00
|
|
|
|
is(parser_calls('workspace "foo \"bar"'),
|
|
|
|
|
'cmd_workspace_name(foo "bar)',
|
|
|
|
|
'Command with escaped double quotes ok');
|
|
|
|
|
|
Implement a new parser for commands. (+test)
On the rationale of using a custom parser instead of a lex/yacc one, see this
quote from src/commands_parser.c:
We use a hand-written parser instead of lex/yacc because our commands are
easy for humans, not for computers. Thus, it’s quite hard to specify a
context-free grammar for the commands. A PEG grammar would be easier, but
there’s downsides to every PEG parser generator I have come accross so far.
This parser is basically a state machine which looks for literals or strings
and can push either on a stack. After identifying a literal or string, it
will either transition to the current state, to a different state, or call a
function (like cmd_move()).
Special care has been taken that error messages are useful and the code is
well testable (when compiled with -DTEST_PARSER it will output to stdout
instead of actually calling any function).
During the migration phase (I plan to completely switch to this parser before
4.2 will be released), the new parser will parse every command you send to
i3 and save the resulting call stack. Then, the old parser will parse your
input and actually execute the commands. Afterwards, both call stacks will be
compared and any differences will be logged.
The new parser works with 100% of the test suite and produces identical call
stacks.
2012-01-14 20:53:29 +01:00
|
|
|
|
done_testing;
|