1 DrRacket support for #lang-based Languages
The simplest and best way to extend DrRacket with support for a new language is to implement the language via #lang (see Defining new #lang Languages for more details). DrRacket will then use read-language to find code and values that it uses to customize itself to the language.
If the call to read-language raises an error, DrRacket logs the error at the debug level to a logger with the name 'drracket-language (see Logging for more about how to follow specific loggers).
With the exception of the 'definitions-text-surrogate, if there is an error during a use of one of these extensions, DrRacket notices the error and removes all of the extensions for the language. It also shows the error at the bottom of the DrRacket frame (prefixed by #lang). Note that this applies only to errors that occur during the dynamic extent of a use of one of these extensions. If an extension were to, for example, create a new thread that (eventually) caused an error, DrRacket would not notice that error and would not remove the extensions.
When experimenting with changes to these extensions, use the Racket|Reload #lang Extensions menu item to cause DrRacket to remove the extensions and reload the implementations from the files on disk.
DrRacket calls the language’s read-language’s get-info procedure with the following key arguments:
1.1 Syntax Coloring
When a language’s get-info procedure responds to 'color-lexer, it is expected to return a procedure suitable to pass as the get-token argument to start-colorer.
1.2 Indentation
Added in version 1.3 of package drracket.
These are used with the framework library’s color:text<%> object; they are supplied as the pairs argument to the start-colorer method.
'((|(| |)|) (|[| |]|) (|{| |}|))
They are also used to introduce keybindings that match the parentheses, via racket:map-pairs-keybinding-functions.
Added in version 1.12 of package drracket.
These characters are used to introduce keybindings via racket:map-pairs-keybinding-functions, where the open and close arguments are both the character.
The default value is (list #\" #\|).
Added in version 1.13 of package drracket.
(-> (is-a?/c racket:text<%>) exact-nonnegative-integer? exact-nonnegative-integer? (or/c #f (listof (list/c exact-nonnegative-integer? string?))))
When both 'drracket:indentation and 'drracket:range-indentation
are available, the function for 'drracket:range-indentation is called first—
Added in version 1.10 of package drracket.
1.3 Keystrokes
The procedure’s first argument will be the definitions text, the second will be the event object supplied from the GUI system and the result of the procedure is ignored.
When a language’s get-info procedure responds to 'drracket:grouping-position, it is expected to return a function that determines where positions relevant to the nesting structure of the program appear. This function is used for a number of motion and selection operations in the editor, as well as determining where to flash to for closing parentheses.
Consider first the first and third argument. The first argument indicates a position in the editor to start from and the third argument is a direction to look. The result return the position for the corresponding direction, where the nesting structure of the program is viewed as a tree. That is, if the third argument is 'up, the function should return the position that goes up one layer in the tree from the given position to the parent. Similarly 'down should return the position going on layer deeper into that tree, going down to the first child. The 'backward and 'forward arguments correspond to position where we stay at the same level in the tree, moving between siblings. The result should be #f when there is no corresponding position to move to, e.g., when the current position has no children, no parents, or no siblings in the corresponding direction.
The second argument is a limit. Positions smaller than the limit should be ignored, so if the corresponding position appears to be before the limit, return #f.
Finally, return #t to get the default behavior, namely motion in Racket-style s-expressions.
Added in version 1.11 of package drracket.
1.4 Filename Extensions
When a language’s get-info procedure responds to 'drracket:default-filters, it is expected to return (listof (list/c string? string?)).
`(["Racket Sources" "*.rkt;*.scrbl;*.rktl;*.rktd;*.ss;*.scm"] ["Any" "*.*"])
Added in version 1.2 of package drracket.
When a language’s get-info procedure responds to 'drracket:default-extension, it is expected to return (and/c string? (not/c #rx"[.]")); the result is used as the default extension when saving files by setting finder:default-extension.
Added in version 1.2 of package drracket.
1.5 REPL Submit Predicate
For backwards compatibility reasons, DrRacket also queries the result of module->language-info for 'drracket:submit-predicate. It does this during the evaluation of the definitions (so the Racket|Reload #lang extensions menu item does not trigger a re-load). If the submit predicate is specified both ways, then the predicate supplied via read-language takes precedence.
Changed in version 1.5 of package drracket: Look for drracket:submit-predicate via read-language.
1.6 Show Big “Definitions” and “Interactions” Labels
If the read-language predicate returns #t for 'drracket:show-big-defs/ints-labels, then DrRacket shows the words “Definitions” and “Interactions” in a large font in the corresponding windows. This is intended as a help for students who are reading instructions about where to type their programs but might not have internalized this particular bit of DrRacket terminology.
1.7 Opting Out of Standard Toolbar Buttons
Some of the built-in buttons in the DrRacket button bar at the top of the window can be disabled on a per-language basis. DrRacket will invoke the get-info proc returned by read-language with 'drracket:opt-out-toolbar-buttons (and 'drscheme:opt-out-toolbar-buttons for backwards compatibility).
If the result is a list of symbols, the listed symbols are opted out. If the result is #f, all buttons are opted out. The default is the empty list, meaning that all opt-out buttons appear.
The Check Syntax button uses the symbol 'drracket:syncheck; the debugger uses the symbol 'debug-tool and the macro stepper uses 'macro-stepper.
Plugins may add more opt-out buttons via drracket:module-language-tools:add-opt-out-toolbar-button.
1.8 Opting In to Language-Specific Toolbar Buttons
Like drracket:opt-out-toolbar-buttons, but for languages to opt in to buttons that are not enabled by default.
Added in version 1.6 of package drracket.
1.9 Adding New Toolbar Buttons
DrRacket queries the result of read-language to determine if there are any new toolbar buttons to be used when editing files in this language.
(or/c (listof (list/c string? (is-a?/c bitmap%) (-> (is-a?/c drracket:unit:frame<%>) any) (or/c real? #f))) #f)
If the result is #f, then no toolbar buttons are created.
To implement functionality similar to the Run button, call the execute-callback method. You may also want to use the drracket:rep:after-expression parameter.
If 'drracket:toolbar-buttons is not recognized, DrRacket will also pass 'drscheme:toolbar-buttons; this is for backwards compatibility and new code should not use it. Similarly, if the fourth element from the list (the argument to #:number) is not present, then it is treated as #f.
1.10 Definition Popup-Menu Navigation
A popup menu in the DrRacket button bar jumps to definitions based on a heuristic search of the program text. DrRacket will invoke the get-info proc returned by read-language with 'drracket:define-popup to obtain a configuration for the menu.
The value must satisfy the contract
(non-empty-listof (or/c (list/c string? string? string?) (list/c string? string? string? (or/c #f (-> (is-a/c text%) string? exact-integer? (->* ((is-a/c text%) string? exact-integer?) (#:case-sensitive? any/c #:delimited? any/c) (or/c exact-integer? #f)) (or/c exact-integer? #f))) (or/c #f (-> (is-a/c text%) exact-integer? (-> (is-a/c text%) exact-integer? string?) string?)))))
where the first string in each nested list is literal text to search for (outside of comments and literal strings), the second string is a label to describe the category of matches, and the third string is a short form of the label. The labels from the first nested list are used for the definition-popup button itself, while all labels are used for the user to select which categories are enabled.
When a nested list contains fourth and fifth elements, they can supply replacements (when not #f) for the default functions that find a prefix and extract the subsequent name:
The prefix-finding function receives a text-editor object for the content to search, the prefix string to find, a position to start the search, and a default prefix-finding function. The result is a position in the text editor for the start of a found prefix, or #f if the prefix is not found.
The provided default finding function accepts two optional keyword arguments: a true value for #:case-sensitive? requires case-insensitive matching, and a true value for #:delimited? indicates that the matched text’s edges must coincide with forward and backward expression navigation.
The name-extracting function receives a text-editor object for the content to extract, a position after a found prefix string, and a default name-extracting function. The result must be a string for the extracted defined name.
Plugins can provide a default popup-menu configuration via drracket:language:register-capability using 'drscheme:define-popup.
Added in version 1.14 of package drracket.
1.11 Definitions Text Surrogate
Using a #lang-specific definitions text surrogate is a very powerful way to flexibly control DrRacket’s behavior when a new language is installed. It is also easy to cause DrRacket to completely misbehave with this form of extension. It is here only when one of the other forms of extension listed above are not sufficient for the kind of extension your language requires. And even in that case, it is preferable to add something to this list that is more easily controlled in the case of errors, using the definitions text surrogate only until that more easily controlled extension has been added to DrRacket.
DrRacket calls read-language’s get-info procedure with 'definitions-text-surrogate and expects it to return a value matching the contract (or/c #f module-path?), which is then passed to dynamic-require together with 'surrogate%. The result is expected to be a class implementing the interface racket:text-mode<%> (presumably derived from racket:text-mode%. That mode is installed into the definitions text, where it can change its behavior by changing how is responds to any of the methods in the mode.
One consequence of this power is that errors that happen during the dynamic extent of calls into the mode are not trapped (much as errors that occur on newly created threads are not trapped, as described in the introduction to this section).