On this page:
3.3.1 Moving Around
3.3.2 Editing Operations
3.3.3 File Operations
3.3.4 Search
3.3.5 Evaluation
3.3.6 Documentation
3.3.7 Interactions
3.3.8 La  Te  X and Te  X inspired keybindings
3.3.9 Defining Custom Shortcuts
3.3.10 Sending Program Fragments to the REPL

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 Mac OS, Meta is, by default, available only through the Escape key. But the preferences dialog (in the General Editing sub-panel of the Editing panel) has check boxes that adjust the handling of the Alt key or the Command key to be meta.

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
3.3.2 Editing Operations
3.3.3 File Operations
3.3.4 Search
3.3.5 Evaluation
3.3.6 Documentation
3.3.7 Interactions

The interactions window has all of the same keyboard shortcuts as the definitions window plus a few more:

Also, in the interactions window, the return key is treated specially, in particular to determine if the expression that’s been typed at the prompt is ready to be evaluated or not. There are three cases:
  • When shift-return is typed: the expression is not submitted and instead a new line is started

  • When alt-return or control return is typed: the expression is submitted for evaluation

  • When return with no modified is typed: the language is consulted to determine which of the two previous actions makes the most sense. Typically the language’s parser is consulted to see if the expression looks complete. If so, the expression is submitted and, if not, a new line is started. (See also 'drracket:submit-predicate.)

3.3.8 LaTeX and TeX inspired keybindings
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:

#lang s-exp framework/keybinding-lang

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)
 
(module test racket/base)
 
(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.