1 Introduction
2 Installation
3 First simple example
4 Description
4.1 The .rkt file
4.2 The .rktd file
5 Usage ideas
5.1 Extended example: Turning text into slideshow picts
Version: 5.2.900.1

Script Plugin for DrRacket

1 Introduction

The Script Plugin’s purpose is to make it easy to extend DrRacket with small Racket scripts that can be used in the definition (or interaction) window.

Selected text can be transformed or text can be inserted by a simple click on a menu item, and there is direct access to some elements of DrRacket for advanced (though simplified since there is no need to create a dedicated plugin) scripting, like the frame and the current text editor. Each script is automatically added as an item to the Scripts menu, without needing to restart DrRacket. A keyboard shortcut can be assigned to a script (via the menu item).

It is similar to GEdit’s External Tools plugin (for those who know it).

2 Installation

To install, simply evaluate:

(require (planet orseau/script-plugin/tool))

Wait for the installation process to finish, and then restart DrRacket. You should now see a new Scripts menu.

3 First simple example

Click on the Scripts/New Script menu item, and enter Reverse for the script name. This creates and opens the files reverse.rkt and reverse.rktd in the script directory. Also, a new item automatically appears in the Scripts menu.

In the .rkt file, modify the item-callback function to the following:
(define (item-callback str)
  (list->string (reverse (string->list str))))

Then go to a new tab, type some text, select it, and click on Scripts/Reverse.

4 Description

This DrRacket plugin adds a Script menu to the main window. This menu has several items, followed by the (initially empty) list of active scripts.

The New Script item asks for a script name and creates 2 files:
  • a .rkt file, the script itself (with a sample program)

  • a .rktd file, the metadata of the script with the default values

These two files are automatically opened.

The script menu is rebuilt each time the user activates it, so that changes are taken into account as soon as possible.

The default location of the scripts is in a sub-folder of (find-system-path 'home-path). The directory of the user scripts can be change through DrRacket’s preferences (in Edit/Preferences/Scripts). Important: The scripts directory must have write-access for the user.

4.1 The .rkt file

This is the script file. It must provide the item-callback function, as in the sample code. It is meant to be executable by itself, to ease the testing process.

(item-callback str)  (or/c string? (is-a?/c snip%))
  str : string?
Returns the string meant to be inserted in place of the current selection, or at the cursor if there is no selection. If the returned value is not a string or a snip%, the selection is not modified (i.e., the file remains in a saved state if it was already saved).

This function also accepts (optional or mandatory) special keyword arguments (the exact signature is determined with procedure-keywords):
  • #:file : (or/c path? #f)

    The path to the current file of the definition window, or #f if there is no such file (i.e., unsaved editor).

    Example:
    (define (item-callback str #:file f)
      (string-append "(in " (if f (path->string f) "no-file") ": " str))

    See also: file-name-from-path, filename-extension, path->string, split-path.

  • #:editor : text%

    The text% editor of the current definition window.

    Example (surrounds the selection with a lambda, and places the cursor at the argument position):
    #lang racket/base
    (require racket/class)
     
    (provide item-callback)
    (define (item-callback str #:editor edit)
    (send edit begin-edit-sequence)
    (let ([selection-start (send edit get-start-position)]
          [selection-end (+ 1 (send edit get-end-position))])
    (send* edit
    (set-position selection-start)
    (insert ")")
    (set-position selection-end)
    (insert ")")
    (set-position selection-start)
    (insert "(λ(")))
    (send edit end-edit-sequence)
    #f)
    See text% for more details.

  • #:interactions : text%

    The text% editor of the current interaction window.

  • #:frame : drracket:unit:frame<%>

    DrRacket’s frame. For advanced scripting.

    Example:
    (define (item-callback str #:frame fr)
      (send fr create-new-tab)
      #f)

The name of the function can also be changed, but this requires to change it also in the functions entry of the .rktd file, and the function must be provided.

4.2 The .rktd file

This is the metadata file. It contains an association list that defines the configuration of the script.

Most options (label, shortcut, shortcut-prefix, help-string) are the same as for the menu-item% constructor. In particular, a keyboard shortcut can be assigned to an item.

There are some additional options:
  • functions : (or/c symbol? (listof (list/c symbol? string?))) = item-callback

    If a symbol, the name of the function to call (which must be provided), and must follow item-callback’s signature.

    If a list, each symbol is the name of a function, and each string is a label for that function. In this case, a sub-menu holding all these functions is created, and the label option is used as the parent menu name.

    Note that a sub-menu can be shared among scripts.

    Example:

    The following .rktd file will create a submenu named My Functions (with the letter F for keyboard access), containing 3 items, one for each function and its assoctiated letter-accessor.

    ((label . "My &Functions")
     (functions    (my-function1 "My Function #&1")
                   (my-function2 "My Function #&2")
                   (my-function3 "My Function #&3")))

    And the associated .rkt example file:
    #lang racket/base
     
    (provide my-function1)
    (define (my-function1 str) "1")
     
    (provide my-function2)
    (define (my-function2 str) "2")
     
    (provide my-function3)
    (define (my-function3 str) "3")

  • output-to : (one-of/c 'selection 'new-tab 'message-box) = 'selection

    If 'selection, the output of the transform function replaces the selection in the current tab (or insert at the cursor if there is no selection). If 'new-tab, a new tab is created and the output of the script is written to it. If 'message-box, the output is displayed in a message-box.

    Note: The quote must not be included in the .rktd file.

  • active : boolean? = #t

    If set to #f, no menu item is generated for this dictionary.

Finally, one .rktd file can contain several such dictionaries (one after the other), which allows for multiple sub-menus and menu items and in a single script. This would have roughly the same effect as splitting such a script into several script, each one with its own .rktd file and its dictionary.

5 Usage ideas

Note that racket/gui can be used to ask the user for more information and more.

Remark: Code snippets should probably be of rare usage, as one should better take advantage of Racket’s wonderful macro system. In some cases however, snippets might be useful, e.g., to require your common module where all your usual macros and functions are defined, or for automatic comments.

5.1 Extended example: Turning text into slideshow picts

The slideshow library can be used to turn DrRacket into a very rich text editor.

The following .rkt example script writes the selected words on white on black, tilted word by word.

#lang racket/base
(require racket/class
         slideshow
         racket/gui/base)
 
(define (pict->snip pic)
  (make-object image-snip% (pict->bitmap pic)))
 
(define (at pic x y)
  (vc-append (blank x) (hc-append (blank y) pic)))
 
(provide item-callback)
(define (item-callback str #:editor ed)
  (send ed insert
        (pict->snip
         (let ([p
                (apply hc-append
                       (for/list ([w (regexp-split #px"\\s+" str)])
                         (text w '() 24 (/ pi 6))))])
 
           (cc-superimpose (colorize p "black")
                           (colorize (at p 3 3) "white")))))
 
  #f)