Write and Reload a Personal Command
This chapter defines one useful Racket text command, publishes it into the shared command registry, binds and invokes it, replaces its implementation without restarting, inspects its provenance and execution limits, and recovers from a rejected generation.
Before You Begin
If you enter this chapter directly, first complete Prepare the User Guide Exercises.
Complete Compose Keymaps and Profiles.
Keep the isolated modular configuration and the personal-direct interaction
profile from that chapter.
Personal commands use public copied editor values and checked text transactions. They do not receive native pointers or mutate buffer storage directly.
Define a Text Command
Create ~/odra-guide/config/odra/modules/text-commands.rkt by pasting this
complete chapter-owned file:
(module text-commands racket/base
(require odra/commands)
(provide odra-personal-commands)
(define (uppercase-line context)
(define line (command-context-current-line context))
(define text (command-context-read context line))
(command-context-replace! context line (string-upcase text)))
(define odra-personal-commands
(list
(make-command
'personal-uppercase-line
uppercase-line
#:description "Uppercase the current line."
#:requirements '(active-buffer)
#:effects '(buffer view text-mutation)
#:source "modules/text-commands.rkt"))))
make-command constructs an immutable definition; it does not register an
arbitrary procedure by side effect. The exported list is the sole command
contribution selected by personal configuration.
Bind the Semantic Command
In settings/keys.rkt, add this operation to the personal-map binding list:
(keymap-bind
(key-sequence (control #\c) (plain #\u))
"personal-uppercase-line"
source)
The profile refers to the command by semantic identity. Configuration admission verifies that the command and binding arrive in the same complete generation.
Update init.rkt:
#lang racket/base
(require "settings/interface.rkt"
"settings/keys.rkt"
"modules/text-commands.rkt")
(provide odra-status-bar-configuration
odra-gutter-configuration
odra-interaction-profile
odra-personal-commands)
Run M-x reload-personal-commands. A successful reload publishes the command
catalog and interaction profile together.
Invoke and Undo
Open ~/odra-guide/work/dirs/notes/editing-practice.txt, place point on a
mixed-case line, and run M-x personal-uppercase-line. The complete logical
line becomes uppercase.
Press C-/ once. The original line returns because the personal command
publishes its replacement as one ordinary history unit.
Repeat with C-c u, then undo again. Command navigation and the keybinding
reach the same registered command; the binding is not a second implementation.
Inspect the Active Definition
Run M-x where-is and enter personal-uppercase-line. The result shows
C-c u and personal provenance. Run M-x describe-key, capture C-c u, and
inspect the effective map, profile, command identity, and source.
Open M-x and search for the command. Its row shows the description,
implementation provider, availability, and binding without exposing the
absolute configuration root.
Replace the Implementation Live
Change uppercase-line to use string-downcase and update the command
description accordingly. Run M-x reload-personal-commands.
Invoke the same semantic command and binding. The new confirmed procedure runs without restarting Odra. A command turn already in progress retains its owned generation until it finishes; later invocations cannot call a retired procedure.
Restore the uppercase implementation and reload before continuing.
Observe the Execution Bound
Temporarily add (sleep 3) before command-context-replace!, reload, and
invoke the command. The default personal-command deadline ends the turn before
the delayed replacement can publish. The buffer and undo history remain
unchanged, and a bounded diagnostic reports the rejected invocation.
Restore the immediate implementation and reload. The execution deadline, custodian memory, copied text, replacement text, splice count, transaction memory, nested operations, and diagnostic size all have explicit ceilings. Personal code may choose smaller limits but cannot raise the maintained native maximums.
Reject a Command Generation
Change the command identity from personal-uppercase-line to save-buffer
without changing the personal binding. Run M-x reload-personal-commands.
Personal code cannot replace a factory command, and the mismatched binding
cannot resolve to the rejected definition. The complete candidate is rejected
while the last confirmed personal command and C-c u behavior remain active.
Restore the personal identity and reload. Factory M-x, C-g, and
reload-personal-commands remain available throughout recovery.
Stay Inside the Verified Authoring Surface
Use core forms, ordinary racket/base procedures, explicit recursion or
runtime combinators such as map, and public odra/commands and
odra/keymaps modules. A non-core macro that requires an unavailable
transformer phase may reject in the embedded namespace even if it works in a
separate Racket process.
That loader boundary does not reduce Racket's text-processing model. It marks which source forms and editor capabilities are currently verified for live personal generations. Rejection always preserves the last confirmed generation.
Previous: Compose Keymaps and Profiles · User Guide · Next: Extend Ksawery