From fa4a909f34f82b1027101811f4ec122cc24f5170 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 16 Jan 2012 22:44:28 +0000 Subject: [PATCH] hacking-howto: describe the new commands parser --- docs/hacking-howto | 151 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 116 insertions(+), 35 deletions(-) diff --git a/docs/hacking-howto b/docs/hacking-howto index d0f5ac3a..1d2d608d 100644 --- a/docs/hacking-howto +++ b/docs/hacking-howto @@ -672,41 +672,122 @@ floating windows: ///////////////////////////////////////////////////////////////////////////////// -== User commands / commandmode (src/cmdparse.{l,y}) - -********************************************************************************* -This section has not been updated for v4.0 yet, sorry! We wanted to release on -time, but we will update this soon. Please talk to us on IRC if you need to -know stuff *NOW* :). -********************************************************************************* - -///////////////////////////////////////////////////////////////////////////////// - - -Like in vim, you can control i3 using commands. They are intended to be a -powerful alternative to lots of shortcuts, because they can be combined. There -are a few special commands, which are the following: - -exec :: -Starts the given command by passing it to `/bin/sh`. - -restart:: -Restarts i3 by executing `argv[0]` (the path with which you started i3) without -forking. - -w:: -"With". This is used to select a bunch of windows. Currently, only selecting -the whole container in which the window is in, is supported by specifying "w". - -f, s, d:: -Toggle fullscreen, stacking, default mode for the current window/container. - -The other commands are to be combined with a direction. The directions are h, -j, k and l, like in vim (h = left, j = down, k = up, l = right). When you just -specify the direction keys, i3 will move the focus in that direction. You can -provide "m" or "s" before the direction to move a window respectively or snap. - -///////////////////////////////////////////////////////////////////////////////// +== User commands (parser-specs/commands.spec) + +In the configuration file and when using i3 interactively (with +i3-msg+, for +example), you use commands to make i3 do things, like focus a different window, +set a window to fullscreen, and so on. An example command is +floating enable+, +which enables floating mode for the currently focused window. See the +appropriate section in the link:userguide.html[User’s Guide] for a reference of +all commands. + +In earlier versions of i3, interpreting these commands was done using lex and +yacc, but experience has shown that lex and yacc are not well suited for our +command language. Therefore, starting from version 4.2, we use a custom parser. +The input specification for this parser can be found in the file ++parser-specs/commands.spec+. Should you happen to use Vim as an editor, use +:source parser-specs/highlighting.vim to get syntax highlighting for this file +(highlighting files for other editors are welcome). + +.Excerpt from commands.spec +----------------------------------------------------------------------- +state INITIAL: + '[' -> call cmd_criteria_init(); CRITERIA + 'move' -> MOVE + 'exec' -> EXEC + 'workspace' -> WORKSPACE + 'exit' -> call cmd_exit() + 'restart' -> call cmd_restart() + 'reload' -> call cmd_reload() +----------------------------------------------------------------------- + +The input specification is written in an extremely simple format. The +specification is then converted into C code by the Perl script +generate-commands-parser.pl (the output file names begin with GENERATED and the +files are stored in the +include+ directory). The parser implementation ++src/commands_parser.c+ includes the generated C code at compile-time. + +The above excerpt from commands.spec illustrates nearly all features of our +specification format: You describe different states and what can happen within +each state. State names are all-caps; the state in the above excerpt is called +INITIAL. A list of tokens and their actions (separated by an ASCII arrow) +follows. In the excerpt, all tokens are literals, that is, simple text strings +which will be compared with the input. An action is either the name of a state +in which the parser will transition into, or the keyword 'call', followed by +the name of a function (and optionally a state). + +=== Example: The WORKSPACE state + +Let’s have a look at the WORKSPACE state, which is a good example of all +features. This is its definition: + +.WORKSPACE state (commands.spec) +---------------------------------------------------------------- +# workspace next|prev|next_on_output|prev_on_output +# workspace back_and_forth +# workspace +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) +---------------------------------------------------------------- + +As you can see from the commands, there are multiple different valid variants +of the workspace command: + +workspace :: + The word 'workspace' can be followed by any of the tokens 'next', + 'prev', 'next_on_output' or 'prev_on_output'. This command will + switch to the next or previous workspace (optionally on the same + output). + + There is one function called +cmd_workspace+, which is defined + in +src/commands.c+. It will handle this kind of command. To know which + direction was specified, the direction token is stored on the stack + with the name "direction", which is what the "direction = " means in + the beginning. + + +NOTE: Note that you can specify multiple literals in the same line. This has + exactly the same effect as if you specified `direction = + 'next_on_output' -> call cmd_workspace($direction)` and so forth. + + +NOTE: Also note that the order of literals is important here: If 'next' were + ordered before 'next_on_output', then 'next_on_output' would never + match. + +workspace back_and_forth:: + This is a very simple case: When the literal 'back_and_forth' is found + in the input, the function +cmd_workspace_back_and_forth+ will be + called without parameters and the parser will return to the INITIAL + state (since no other state was specified). +workspace :: + In this case, the workspace command is followed by an arbitrary string, + possibly in quotes, for example "workspace 3" or "workspace bleh". + + This is the first time that the token is actually not a literal (not in + single quotes), but just called string. Other possible tokens are word + (the same as string, but stops matching at a whitespace) and end + (matches the end of the input). + +=== Introducing a new command + +The following steps have to be taken in order to properly introduce a new +command (or possibly extend an existing command): + +1. Define a function beginning with +cmd_+ in the file +src/commands.c+. Copy + the prototype of an existing function. +2. After adding a comment on what the function does, copy the comment and + function definition to +include/commands.h+. Make the comment in the header + file use double asterisks to make doxygen pick it up. +3. Write a test case (or extend an existing test case) for your feature, see + link:testsuite.html[i3 testsuite]. For now, it is sufficient to simply call + your command in all the various possible ways. +4. Extend the parser specification in +parser-specs/commands.spec+. Run the + testsuite and see if your new function gets called with the appropriate + arguments for the appropriate input. +5. Actually implement the feature. +6. Document the feature in the link:userguide.html[User’s Guide]. == Moving containers -- 2.39.5