Skip to content

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., proteinpolymer.protein) are resolved via resolve() from selection_aliases.py:

# User writes:   /rep cartoon protein
# After resolve: /rep cartoon polymer.protein

Scoping

When multiple structures are loaded, the active scope wraps selections with a model filter:

# scope = "1AKE"
# arg = "polymer.protein"
# After scoping: "model 1AKE and (polymer.protein)"

This ensures commands only affect the active structure.

Execution

Finally, the tool's run() function is called:

result = tool_module.run(cmd, *fitted_args, **kwargs)

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]