i3/parser-specs/commands.spec
Michael Stapelberg a532f5ac39 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 21:29:57 +00:00

234 lines
5.4 KiB
Ruby

# vim:ts=2:sw=2:expandtab
#
# i3 - an improved dynamic tiling window manager
# © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE)
#
# parser-specs/commands.spec: Specification file for generate-command-parser.pl
# which will generate the appropriate header files for our C parser.
#
# Use :source highlighting.vim in vim to get syntax highlighting
# for this file.
state INITIAL:
# We have an end token here for all the commands which just call some
# function without using an explicit 'end' token.
end ->
'[' -> call cmd_criteria_init(); CRITERIA
'move' -> MOVE
'exec' -> EXEC
'exit' -> call cmd_exit()
'restart' -> call cmd_restart()
'reload' -> call cmd_reload()
'border' -> BORDER
'layout' -> LAYOUT
'append_layout' -> APPEND_LAYOUT
'workspace' -> WORKSPACE
'focus' -> FOCUS
'kill' -> KILL
'open' -> call cmd_open()
'fullscreen' -> FULLSCREEN
'split' -> SPLIT
'floating' -> FLOATING
'mark' -> MARK
'resize' -> RESIZE
'nop' -> NOP
'scratchpad' -> SCRATCHPAD
'mode' -> MODE
state CRITERIA:
ctype = 'class' -> CRITERION
ctype = 'instance' -> CRITERION
ctype = 'window_role' -> CRITERION
ctype = 'con_id' -> CRITERION
ctype = 'id' -> CRITERION
ctype = 'con_mark' -> CRITERION
ctype = 'title' -> CRITERION
']' -> call cmd_criteria_match_windows(); INITIAL
state CRITERION:
'=' -> CRITERION_STR
state CRITERION_STR:
cvalue = word
-> call cmd_criteria_add($ctype, $cvalue); CRITERIA
# exec [--no-startup-id] <command>
state EXEC:
nosn = '--no-startup-id'
->
command = string
-> call cmd_exec($nosn, $command)
# border <normal|none|1pixel|toggle>
state BORDER:
border_style = 'normal', 'none', '1pixel', 'toggle'
-> call cmd_border($border_style)
# layout <default|stacked|stacking|tabbed>
state LAYOUT:
layout_mode = 'default', 'stacked', 'stacking', 'tabbed'
-> call cmd_layout($layout_mode)
# append_layout <path>
state APPEND_LAYOUT:
path = string -> call cmd_append_layout($path)
# workspace next|prev|next_on_output|prev_on_output
# workspace back_and_forth
# workspace <name>
state WORKSPACE:
direction = 'next_on_output', 'prev_on_output', 'next', 'prev'
-> call cmd_workspace($direction)
'back_and_forth'
-> call cmd_workspace_back_and_forth()
workspace = string
-> call cmd_workspace_name($workspace)
# focus left|right|up|down
# focus output <output>
# focus tiling|floating|mode_toggle
# focus parent|child
# focus
state FOCUS:
direction = 'left', 'right', 'up', 'down'
-> call cmd_focus_direction($direction)
'output'
-> FOCUS_OUTPUT
window_mode = 'tiling', 'floating', 'mode_toggle'
-> call cmd_focus_window_mode($window_mode)
level = 'parent', 'child'
-> call cmd_focus_level($level)
end
-> call cmd_focus()
state FOCUS_OUTPUT:
output = string
-> call cmd_focus_output($output)
# kill window|client
# kill
state KILL:
kill_mode = 'window', 'client'
-> call cmd_kill($kill_mode)
end
-> call cmd_kill($kill_mode)
# fullscreen global
# fullscreen
state FULLSCREEN:
fullscreen_mode = 'global'
-> call cmd_fullscreen($fullscreen_mode)
end
-> call cmd_fullscreen($fullscreen_mode)
# split v|h|vertical|horizontal
state SPLIT:
direction = 'v', 'h', 'vertical', 'horizontal'
-> call cmd_split($direction)
# floating enable|disable|toggle
state FLOATING:
floating = 'enable', 'disable', 'toggle'
-> call cmd_floating($floating)
# mark <mark>
state MARK:
mark = string
-> call cmd_mark($mark)
# resize
state RESIZE:
way = 'grow', 'shrink'
-> RESIZE_DIRECTION
state RESIZE_DIRECTION:
direction = 'up', 'down', 'left', 'right'
-> RESIZE_PX
state RESIZE_PX:
resize_px = word
-> RESIZE_TILING
end
-> call cmd_resize($way, $direction, "10", "10")
state RESIZE_TILING:
'px'
->
'or'
-> RESIZE_TILING_OR
end
-> call cmd_resize($way, $direction, $resize_px, "10")
state RESIZE_TILING_OR:
'ppt'
->
resize_ppt = word
->
end
-> call cmd_resize($way, $direction, $resize_px, $resize_ppt)
# move <direction> [<pixels> [px]]
# move [window|container] [to] workspace <str>
# move [window|container] [to] output <str>
# move [window|container] [to] scratchpad
# move workspace to [output] <str>
# move scratchpad
state MOVE:
'window'
->
'container'
->
'to'
->
'workspace'
-> MOVE_WORKSPACE
'output'
-> MOVE_TO_OUTPUT
'scratchpad'
-> call cmd_move_scratchpad()
direction = 'left', 'right', 'up', 'down'
-> MOVE_DIRECTION
state MOVE_DIRECTION:
pixels = word
-> MOVE_DIRECTION_PX
end
-> call cmd_move_direction($direction, "10")
state MOVE_DIRECTION_PX:
'px'
-> call cmd_move_direction($direction, $pixels)
end
-> call cmd_move_direction($direction, $pixels)
state MOVE_WORKSPACE:
'to'
-> MOVE_WORKSPACE_TO_OUTPUT
workspace = 'next', 'prev', 'next_on_output', 'prev_on_output'
-> call cmd_move_con_to_workspace($workspace)
workspace = string
-> call cmd_move_con_to_workspace_name($workspace)
state MOVE_TO_OUTPUT:
output = string
-> call cmd_move_con_to_output($output)
state MOVE_WORKSPACE_TO_OUTPUT:
'output'
->
output = string
-> call cmd_move_workspace_to_output($output)
# mode <string>
state MODE:
mode = string
-> call cmd_mode($mode)
state NOP:
comment = string
-> call cmd_nop($comment)
state SCRATCHPAD:
'show'
-> call cmd_scratchpad_show()