3.3 Keyboard Shortcuts
Most key presses simply insert a character into the editor, such as a, 3, or (. Other keys and key combinations act as keyboard shortcuts that move the blinking caret, delete a line, copy the selection, etc. Keyboard shortcuts are usually trigger by key combinations using the Control, Meta, or Command key.
Many of the key-binding actions can also be performed with menu items.
C-‹key› means press the Control key, hold it down and then press ‹key› and then release them both. For example: C-e (Control-E) moves the blinking caret to the end of the current line.
M-‹key› is the same as C-‹key›, except with the Meta key. Depending on your keyboard, Meta may be called “Left,” “Right,” or have a diamond symbol, but it’s usually on the bottom row next to the space bar. M-‹key› can also be performed as a two-character sequence: first, strike and release the Escape key, then strike ‹key›. On Windows and Mac OS X, Meta is only available through the Escape key.
DEL is the Delete key.
SPACE is the Space bar.
On most keyboards, “<” and “>” are shifted characters. So, to get M->, you actually have to type Meta-Shift->. That is, press and hold down both the Meta and Shift keys, and then strike “>”.
On Windows (and sometimes under Unix) some of these keybindings are actually standard menu items. Those keybindings will behave according to the menus, unless the Enable keybindings in menus preference is unchecked. For example, the C-e keybinding mentioned above actually toggles the visibility of the interactions window.
If you are most familiar with Emacs-style key bindings (especially on windows or some linux installations where the control key is, by default, for the menu shortcuts), you should uncheck the Enable keybindings in menus preference. Many of the keybindings below are inspired by Emacs. See also Defining Custom Shortcuts for suggestions on how to bind keys to menu items on a selective basis.
And finally, the authoritative source for keybindings is the Edit menu’s Show Active Keybindings menu item. Keybindings in DrRacket are often sensitive to the window that has the keyboard focus, so the contents of the window that Show Active Keybindings opens will depend where the keyboard focus was when the menu was selected.
3.3.1 Moving Around
C-F6 : move the cursor between different windows (usually the interactions and definitions windows, but also the search window and other editable portions of DrRacket). Also, search for “shift-focus” in the Show Active Keybindings menu’s window for more, platform-specific keybindings that have this functionality
3.3.2 Editing Operations
M-S-L : wrap selection in (lambda () ...) and put the insertion point in the argument list of the lambda
C-c C-o : the sexpression following the insertion point is put in place of its containing sexpression
C-c C-e : the first and last characters (usually parentheses) of the containing expression are removed
C-c C-l : wraps a let around the sexpression following the insertion point and puts a printf in at that point (useful for debugging).
C-x r a : Adjust nearby ASCII art rectangles (that use +, -, or |) to use Unicode characters.
For example, if the insertion point is next to this rectangle:+-+
| |
+-+
then the keystroke will turn it into this one:╔═╗
║ ║
╚═╝
Similarly, if the rectangle near the insertion point has mixed Unicode and ASCII, it will all be converted to the Unicode characters.C-x r w : Widen the nearby ASCII art rectangles.
For example, if the insertion point is just to the left of the middle line of this rectangle:╔═╦══╗
║ ║ ║
╠═╬══╣
║ ║ ║
╚═╩══╝
then the keystroke will turn it into this one:╔══╦══╗
║ ║ ║
╠══╬══╣
║ ║ ║
╚══╩══╝
C-x r c : Centers the contents of the current line inside the enclosing cell of the enclosing ASCII art rectangle.
3.3.3 File Operations
3.3.4 Search
3.3.5 Evaluation
3.3.6 Documentation
f1 : Search in the documentation for the words near the insertion point
f2 : Reveal the blue box for the identifier at the insertion point (requires background check syntax to be enabled, or normal check syntax to have been run).
3.3.7 Interactions
The interactions window has all of the same keyboard shortcuts as the definitions window plus a few more:
M-p : bring the previously entered expression down to the prompt
M-n : bring the expression after the current expression in the expression history down to the prompt
M-h : Show the current expression history in a separate window
3.3.8 LaTeX and TeX inspired keybindings
C-\ M-\ c:x;l : traces backwards from the insertion point, looking for a backslash followed by a LaTeX macro name or a prefix of such a name. If a macro name is found, it replaces the backslash and the name with the corresponding key in the table below; if a (proper) prefix p is found, it replaces p with the longest common prefix of all macro names that have p as a prefix (unless there is only one such name, in which case it behaves as if p were a complete macro name).
These are the currently supported macro names and the keys they map into:⇓
↖
↓
⇒
→
↦
↘
↙
←
↑
⇐
−
⇑
⇔
↕
↔
↗
⇕
א
′
∅
∇
♦
♠
♣
♥
♯
♭
♮
√
¬
△
∀
∃
∞
∘
α
θ
τ
β
θ
π
υ
γ
π
φ
δ
κ
ρ
φ
ε
λ
ρ
χ
ε
μ
σ
ψ
ζ
ν
ς
ω
η
ξ
ι
Γ
Λ
Σ
Ψ
Δ
Ξ
Υ
Ω
Θ
Π
Φ
±
∩
◇
⊕
∓
∪
△
⊖
×
⊎
▽
⊗
÷
⊓
▹
⊘
∗
⊔
∨
∧
◃
⊙
★
†
•
‡
≀
⨿
≤
≥
≡
⊨
≺
≻
∼
⊥
⊥
⊤
≼
≽
≃
≪
≫
≍
∥
⊂
⊃
≈
⋈
⊆
⊇
≌
⊏
⊐
≠
⌣
⊑
⊒
≐
⌢
∈
∋
∝
⊢
⊣
·
∑
∏
∐
∫
∮
√
☠
☺
☻
☹
§
⋮
⋱
⋯
⋯
3.3.9 Defining Custom Shortcuts
The Add User-defined Keybindings... menu item in the Keybindings sub-menu of Edit selects a file containing Racket definitions of keybindings. The file must contain a module that uses a special keybindings language, framework/keybinding-lang. To do so, begin your file with this line:
The framework/keybinding-lang languages provides all of the bindings from racket, racket/class, and drracket/tool-lib, except that it adjusts #%module-begin to introduce a keybinding form:
(keybinding string-expr proc-expr) Declares a keybinding, where string-expr must produce a suitable first argument for map-function in keymap%, and the proc-expr must produce a suitable second argument for add-function in keymap%.
For example, this remaps the key combination “control-a” key to “!”.
#lang s-exp framework/keybinding-lang (keybinding "c:a" (λ (editor evt) (send editor insert "!")))
Since the file contains plain Racket code, you can write keybindings files that use DrRacket’s Extension API. For example, the following file binds “control-t” and “control-=” to a execute the program and open a new tab respectively, as they were used before version 5.2.
#lang s-exp framework/keybinding-lang (define modifiers (apply string-append (map (λ (p) (case p [(ctl) "c:"] [(cmd) "d:"] [(alt meta) "~c:m:"] [(shift) "s:"] [(option) "a:"])) (get-default-shortcut-prefix)))) (define-syntax-rule (frame-key key command) (keybinding (string-append modifiers key) (λ (ed evt) (when (is-a? ed text:basic<%>) (define fr (send ed get-top-level-window)) ; note: fr could be #f (when fr (send fr command)))))) (frame-key "t" execute-callback) (frame-key "=" create-new-tab)
Another example, this file rebinds “control-w” to delete the word behind the insertion point, but it does it by setting a new key to be an existing keyboard shortcut. If you see a key in the Show Active Keybindings dialog (in the Keybindings submenu of the Edit menu), then you can use its name with the new keystroke you want, like this:
#lang s-exp framework/keybinding-lang (define (rebind key command) (keybinding key (λ (ed evt) (send (send ed get-keymap) call-function command ed evt #t)))) (rebind "c:w" "backward-kill-word")
This example shows how to bind a menu item (based on its name) to a particular key. The call at the end of the example binds “control-a” to the Run menu item.
#lang s-exp framework/keybinding-lang (define (menu-bind key menu-item) (keybinding key (λ (ed evt) (define canvas (send ed get-canvas)) (when canvas (define menu-bar (find-menu-bar canvas)) (when menu-bar (define item (find-item menu-bar menu-item)) (when item (define menu-evt (new control-event% [event-type 'menu] [time-stamp (send evt get-time-stamp)])) (send item command menu-evt))))))) (define/contract (find-menu-bar c) (-> (is-a?/c area<%>) (or/c #f (is-a?/c menu-bar%))) (let loop ([c c]) (cond [(is-a? c frame%) (send c get-menu-bar)] [(is-a? c area<%>) (loop (send c get-parent))] [else #f]))) (define/contract (find-item menu-bar label) (-> (is-a?/c menu-bar%) string? (or/c (is-a?/c selectable-menu-item<%>) #f)) (let loop ([o menu-bar]) (cond [(is-a? o selectable-menu-item<%>) (and (equal? (send o get-plain-label) label) o)] [(is-a? o menu-item-container<%>) (for/or ([i (in-list (send o get-items))]) (loop i))] [else #f]))) (menu-bind "c:a" "Run")
Note that DrRacket does not reload keybindings files automatically when you make changes, so you’ll need to restart DrRacket to see changes to the file.
3.3.10 Sending Program Fragments to the REPL
Users comfortable with Emacs and the conventional Lisp/Scheme-style of interaction with an “inferior process” commonly request keybindings in DrRacket that send program fragments to be evaluated at the prompt. This style of interaction is fraught with difficulty, especially for beginners, and so DrRacket, by default, does not support it. Instead, clicking DrRacket’s “Run” button starts with a clean slate and sends the entire contents of the definitions window, ensuring that the state in the REPL matches what you would expect by reading the source code of the program.
Based on years of experience with Emacs modes, some of the authors consider this mode of interaction also appropriate for experienced programmers. Indeed, they go through great effort to mimic this behavior in Emacs.
That said, some people may wish to use such incremental keystroke modes anyway. Therefore the remainder of this section illustrates how to add such an incremental mode for your personal use with an example keybindings file. Specifically, the file shows how to add the ability to send expressions piecemeal to the interactions window. It also demonstrates how to pull together a bunch of pieces of DrRacket’s implementation and its libraries to implement keystrokes.
#lang s-exp framework/keybinding-lang (require drracket/tool-lib) (keybinding "c:c;c:e" (lambda (ed evt) (send-toplevel-form ed #f))) (keybinding "c:c;c:r" (lambda (ed evt) (send-selection ed #f))) (keybinding "c:c;~c:m:e" (lambda (ed evt) (send-toplevel-form ed #t))) (keybinding "c:c;~c:m:r" (lambda (ed evt) (send-selection ed #t))) (define/contract (send-toplevel-form defs shift-focus?) (-> any/c boolean? any) (when (is-a? defs drracket:unit:definitions-text<%>) (define sp (send defs get-start-position)) (when (= sp (send defs get-end-position)) (cond [(send defs find-up-sexp sp) ;; we are inside some top-level expression; ;; find the enclosing expression (let loop ([pos sp]) (define next-up (send defs find-up-sexp pos)) (cond [next-up (loop next-up)] [else (send-range-to-repl defs pos (send defs get-forward-sexp pos) shift-focus?)]))] [else ;; we are at the top-level (define fw (send defs get-forward-sexp sp)) (define bw (send defs get-backward-sexp sp)) (cond [(and (not fw) (not bw)) ;; no expressions in the file, give up (void)] [(not fw) ;; no expression after the insertion point; ;; send the one before it (send-range-to-repl defs bw (send defs get-forward-sexp bw) shift-focus?)] [else ;; send the expression after the insertion point (send-range-to-repl defs (send defs get-backward-sexp fw) fw shift-focus?)])])))) (define/contract (send-selection defs shift-focus?) (-> any/c boolean? any) (when (is-a? defs drracket:unit:definitions-text<%>) (send-range-to-repl defs (send defs get-start-position) (send defs get-end-position) shift-focus?))) (define/contract (send-range-to-repl defs start end shift-focus?) (->i ([defs (is-a?/c drracket:unit:definitions-text<%>)] [start exact-positive-integer?] [end (start) (and/c exact-positive-integer? (>=/c start))] [shift-focus? boolean?]) any) (unless (= start end) ;; don't send empty regions (define ints (send (send defs get-tab) get-ints)) (define frame (send (send defs get-tab) get-frame)) ;; copy the expression over to the interactions window (send defs move/copy-to-edit ints start end (send ints last-position) #:try-to-move? #f) ;; erase any trailing whitespace (let loop () (define last-pos (- (send ints last-position) 1)) (when (last-pos . > . 0) (define last-char (send ints get-character last-pos)) (when (char-whitespace? last-char) (send ints delete last-pos (+ last-pos 1)) (loop)))) ;; put back a single newline (send ints insert "\n" (send ints last-position) (send ints last-position)) ;; make sure the interactions is visible ;; and run the submitted expression (send frame ensure-rep-shown ints) (when shift-focus? (send (send ints get-canvas) focus)) (send ints do-submission)))
Others may wish to use the above example to invent other keystrokes for making work in DrRacket convenient.