Command Flow¶
End-to-End: From Keystroke to Render¶
When a user types a command and presses Enter, here's what happens:
sequenceDiagram
participant User
participant Console
participant Window
participant Dispatcher
participant Parser
participant ToolLoader
participant Tool
participant Engine
User->>Console: types "/load 1ake" + Enter
Console->>Window: signal: command_submitted("/ load 1ake")
Window->>Dispatcher: expand_shortcut("/load 1ake")
Dispatcher-->>Window: "/io load 1ake"
Window->>Parser: parse("/io load 1ake")
Parser-->>Window: ParsedCommand(group="io", tool="load", args=["1ake"])
Window->>ToolLoader: dispatch(tools, "io", "load", ["1ake"], cmd, scope)
ToolLoader->>Tool: tools["io"]["load"].run(cmd, "1ake")
Tool->>Engine: cmd.fetch("1ake")
Engine-->>Tool: success
Tool-->>ToolLoader: "Loaded 1AKE (3816 atoms)"
ToolLoader-->>Window: result string
Window->>Console: display result
Engine->>User: 3D render updates
Step 1: Shortcut Expansion¶
expand_shortcut() in command_dispatcher.py converts user-friendly shortcuts to full /<group> <tool> form:
"/load 1ake" → "/io load 1ake"
"/rep cartoon protein" → "/representations cartoon protein"
"/color red ligand" → "/color color red ligand"
"/measure distance ..." → "/measurements distance ..."
"/show organic" → "/visibility show organic"
"/hide solvent" → "/visibility hide solvent"
"/label ligand" → "/labels smart ligand"
"/select mysel chain A" → "/selection select mysel chain A"
If no shortcut matches, the command passes through unchanged.
Step 2: Parsing¶
parse() in parser.py splits the expanded command into a structured ParsedCommand:
parse("/io load 1ake")
# → ParsedCommand(group="io", tool="load", args=["1ake"], raw="/io load 1ake")
Returns None if the text doesn't start with /.
Step 3: Dispatch¶
dispatch() in tool_loader.py executes the tool. This is the most complex step:
Argument Fitting¶
_fit_args() handles mismatches between parsed args and function parameters. If the function expects 2 args but the parser produced 4 (because a selection expression like chain A and resi 45 was split), it joins the extras into the last parameter:
# Parser produces: args = ["chain", "A", "and", "resi", "45"]
# Function expects: run(cmd, selection)
# _fit_args joins: args = ["chain A and resi 45"]
Alias Resolution¶
Selection aliases (e.g., protein → polymer.protein) are resolved via resolve() from selection_aliases.py:
Scoping¶
When multiple structures are loaded, the active scope wraps selections with a model filter:
This ensures commands only affect the active structure.
Execution¶
Finally, the tool's run() function is called:
The result string is returned to the window and displayed in the console.
Step 4: Special Command Handling¶
Some commands trigger additional logic in _handle_command():
/io load— Updates structure session, may open sidebar/io clear— Clears structure state, resets scope- Measurement tools — Register results in measurement registry
__PICK_*__signals — Activate interactive picking mode (not dispatched as regular tools)
The Full Pipeline¶
graph LR
A[Raw Input] --> B[expand_shortcut]
B --> C[parse]
C --> D{Valid?}
D -->|No| E[Error to console]
D -->|Yes| F[dispatch]
F --> G[_fit_args]
G --> H[resolve aliases]
H --> I[_scope_arg]
I --> J[tool.run]
J --> K[Result to console]