-
-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Action Dispatcher: Actions On-Demand + Cooperative Ordering #19
Comments
The meaning of However, actions will need to be made compatible with this change. Actions will either need to obtain state or have it passed in. Passing it in would forever bind caller and callee. For an interface as important as The dispatcher will use a registry to search. This is because it cannot instantiate actions in order to ask them to search. Queries will live in the registry and the class instantiation may play some role, but more likely, let's just append the queries to a list, Some actions do care about multiple elements, such as the list item reveal action. This is a reason for actions and dispatcher to be as agnostic as possible about who is driving. Legacy style actions will work. The APIs will only get simpler as it is convenient rather than by requirement. This will be buried in methods that the user is not annoyed by and simply relies upon, but it is worth me at least thinking about. Such details find their way into the manual and code comments. |
I'm part-way through the implementation. Actions like the hide-markup action only use begin and end methods. They don't really have any specific trigger. In the action registry, their match rule will simply be
Actions do support class registries via the usual static method implementation. This can help the dispatcher without new classes requiring to be inserted into a list manually all the time. They just need a static slot or method for the search key. The question I have for the dispatcher is how to differentiate an action's slots versus its configuration for a particular element. It would feel irritating if we cannot configure an action for an entire slide, but such configuration feels like it should belong in the property drawer, which has a problem: The current form of A reasonable compromise is to search for property keys like There are two reasonable choices of configuration pattern for affiliated keywords and keywords, but only one for properties. For properties, we probably want this:
For the corresponding keyword, we want either:
or
And as we can see, the second choice is more consistent. We always write the class after the name. Well, the reason this sucks is because I have to decide what affiliated keywords and keywords and properties to look for. I cannot just pull the key and then make a decision. It does mean some extra useless calls. The properties situation is the irritating one, but if I only use one key, then all actions in this transition phase have to watch for all keys. That about decides in favor of This also means that ignoring an element can be targeted at just one action, such as I think prefixing is the way things are going. Unfortunately I need to change directions a bit. |
Actions should try to be blindly cooperative. We want any arbitrary amount of progress on a single element, but we probably don't need actions to jump around every element in the heading except during The idea that two actions work on the same element is kind of rare and will remain rare, and edge case. To handle it, we can use the affiliated keyword order:
Reversing is not a trivial problem. There are two very common and very necessary reversal behaviors. Sometimes we undo behavior on the previous element. Sometimes we go back to the previous element. The image action does both depending on its configuration. A problem I'm having to consider more deeply is that actions currently are not told where to attempt progress. Because of this, there is no equivalent to "peeking" to see if an action could do something. The action will simply move onto the next element 😱 I am concerned that the most obvious conclusion requires a change to To boil down the problem, traversing org elements and reversing over them by guessing the appropriate action, which is not decidable, requires reacting to whether the chosen action made progress. Actions currently cannot peek. Making the return values more complex is fragile, implicit communication. Making the input values more complex requires changing signatures. |
What kinds of matching rules must be expressedWe have two kinds of progress and some actions that only work on every element at begin and end. Many actions that work element-by-element also initialize by working on every element they match. At a minimum, there are independent matching rules for begin / end and forward / backward. However, if actions just pull the parse data for the current heading from a location left by the dispatcher, those that do begin / end don't need any help. It's forward & backward that require coordination, so that is also the case where the dispatcher needs a hint about when to call the action. A match configuration tells us if we need to make an action and how we need to try it when attempting to make progress. Proposed matching config structure:
Child actions require no such hand holding because even the Having any match in the heading is what tells the dispatcher to instantiate the action so it can call I don't want matching to be as crazy as font-locking, but it should be configurable. Since EIEIO is a bit foreign to many users, having both a configured function or a class method to provide a default seems right. Proposed dispatch configThis combines default action arguments and match config (setopt dslide-action-defaults
`((image dslide-action-image nil (#'custom-link-filter reverse-in-place))
(babel dslide-action-babel (:hide-results t))
(item dslide-action-item (:reveal t :inline t :direction begin)
(#custom-match-function reverse-in-place))
(propertize dslide-action-propertize)
(hide dslide-action-hide-markup nil (planning . ,dslide-hide-markup-types))
(kmacro dslide-action-kmacro :speed 0.04 :jitter 0.5))) Each value is
(cl-defmethod dslide-match ((obj action) element)
"Return ELEMENT if this action will operate on it."
element) The slide action config will be only slightly different. We always use the Cooperative Argument PassingFor the most part, if progress tracking is implicit, they will only need to handle a single bound argument,
Some data like the org element parse for the current heading and the currently matched element could be bound in the body for fast lookup, avoiding re-parsing. The contract though is that the action has to update this parse data if it makes a change. |
I'm considering this mixed style of markup again:
As progress tracking logic becomes centralized, this is the easier way to do things and it's just more consistent to users. Thanks to Ihor for pushing me to understand the property+ syntax for the property drawers. |
A dispatcher will interpret calls to actions before actions exist. This saves us from having to create actions. It can also solve interesting coordination problems.
In the current Dslide, these will occur out of order if you order the actions incorrectly. There is no way to have them in order going both forwards and backwards because actions are called in reverse order when going backwards.
Keyword Registry vs Longer Keywords
To simplify markup and only hydrate actions as needed, the dispatcher just needs to be configured with an affiliated keyword registry. Propertize would use
#+attr_dslide_propertize:
and images would use#+attr_dslide_image:
etc.The alternative is to use
WhereThis was decided against because actions would have to read the value into a plist instead of just looking at the keyword when deciding which elements to map over.action-class
is letting us know what to dispatch to already.Quoting & Evaluation
Function calls may be encoded in the configuration line. To support this, we would want to require quoting of lists. Vectors also differentiate lists of data versus intent to evaluate an expression at runtime.
Indeed, babel does evaluate quoted expressions for parameters. It seems we are to treat unquoted forms in org as liable to be evaluated (a bad idea if you ask me, but it is what it is).
The Slide is the Dispatcher?
Just like how the babel blocks are labelled with directions and called in order, the dispatcher should be able to alternate between actions, selecting the right action when going the right direction, to encode the forwards-backwards ordering in a decidable way.
The slide class might just become the dispatcher. It would make sense because slide's live on top of their actions. Currently, the slide is the dispatcher, just a rather limited one. Because state in dslide is anticipated to go away when slides go away, this design would completely make sense.
The text was updated successfully, but these errors were encountered: