<< | Page list | >>
Notes on the dispatch mechanism
Disclaimer: these notes are definitely not complete. The try to describe how things are supposed to work. Of course, the world is not so simple, and some parts of the code are not as well written as they should. The description below should be seen as guidelines on how to do things right
What is a FuncCode (aka LFun)?
A FuncCode is an enum value (see FuncCode.h) that represents a given action. It can be used to bind this action to a menu entry, a toolbar icon or a key binding. It also allows for some primitive (remote) scripting.
Functions are defined through these FuncCodes instead of plain names mainly because this allows to catch mistype names at compile time.
The file LyXAction.cpp attaches to each FuncCode the following information:
- a name, which can be used to refer to the action. Here's the set of rules to apply when a new command name is introduced:
- use the object.event order. That is, use `word-forward' instead of `forward-word';
- don't introduce an alias for an already named object. Same for events;
- forward movement or focus is called `forward' (not `right'),backward movement or focus is called `backward' (not `left');
- upward movement of focus is called `up', downward movement is called `down';
- the begin of an object is called `begin' (not `start'), the end of an object is called `end';
- a flag that describes some general properties of the function. These properties are in particular useful to automatically disable functions in certain circumstances. The possible values are:
Noop: nothing special; This is used for plain functions that operate on a buffer to modify it;
NoBuffer: indicates that the function shall be kept activated when there is no buffer open;
ReadOnly: indicates that the function shall be kept activated when the document is in read-only mode. Functions that lack both the
ReadOnly and the
NoBuffer flag will automatically mark the document dirty after completion (using this mechanism is preferred over using
Argument: indicates that the function requires an argument (see below). This is rarely used and probably too crude as a syntax-checking tool to be really useful;
NoUpdate: indicates that this function usually does not require a screen update. This can be overridden for special cases by the dispatch method of the function;
SingleParUpdate: indicates that this function usually only requires to repaint the current paragraph. This can be overridden for special cases by the dispatch method of the function.
- a function type (
System) that is only used to classify functions in the key binding editor. This is not relevant to the dispatch mechanism;
What is a FuncRequest?
FuncRequest is the basic object that is sent through the dispatch mechanism. It contains:
- the FuncCode corresponding to this request;
- the argument to the FuncCode, which is a plain (unicode) string. There is currently no real syntax for these arguments, which is problematic in particular for the handling of arguments containing spaces. The two main ways of getting arguments are:
getArg method, that returns the n-th argument by considering that arguments are separated by spaces; this method also recognizes arguments enclosed by "double quotes", but does not allow to escape those quotes inside arguments. This is the most convenient getter, but it does not return the verbatim string.
- DIY parsing, which is unfortunately the prevalent solution. Many functions access the full argument string and use
split to do space-based tokenization. Some that require a single argument will take the full string as-is (including spaces). Some functions that require two arguments will get the first by splitting at first space, and consider that the remainder is the second argument (including possible spaces!). There is clearly room for improvement in this area.
- the origin of the request (menu, toolbar, keyboard, command buffer or internal) is used to tweak the response of the UI to the request (informational message in statusbar, completion mechanism).
- coordinates and mouse button can be specified when the request has been generated by the interface subsequently to a mouse action.
The process of dispatching a command
The idea of the dispatch mechanism is that each function should be handled
at the place where it makes sense, and that there should be no global idea
of who does what. What we want to achieve is firstly modularity and, to use eurotechnobabble,
subsidiarity (everything should be done at the level where it makes sense).
The main dispatch method
The dispatch chain starts in LyXFunc::dispatch:
- First, a list of functions is explicitely handled here. There are currently many of them, but this section should be cleaned up. In the end most lfun handlers should move somewhere else (see below). The only functions that clearly belong there are
- if the lfun has not been handled yet, the following things are tried in this order:
- dispatch through the frontend (Application)
- dispatch through the current view, if it exists (LyXView)
- dispatch through the buffer view, if it exists (BufferView)
- dispatch at cursor position
At each of these steps, the dispatch() methods return true if something got done, and false otherwise. The process continues until some piece of code claims responsibility for the lfun.
The Application dispatch
This method handles the functions that concern the frontend itself, like window-new, window-close (FIXME: this one belongs to LyXView), lyx-quit, screen-font-update...
The LyXView dispatch
The BufferView dispatch
The Inset dispatch
Getting to know the command status (aka getStatus)
?is there some automatical check of status before dispatch is done?
Category: Development, Misc