326 lines
16 KiB
Plaintext
326 lines
16 KiB
Plaintext
|
|
[index entries: _snip_ _arrow_ _label_ ]
|
|
|
|
_snips_ and _arrows_ library
|
|
============================
|
|
|
|
Collection: mrflow
|
|
Files: snips-and-arrows.ss snips-and-arrows-view.ss snips-and-arrows-model.ss
|
|
|
|
This library allows a programmer to display information about terms in
|
|
a DrScheme text editor and its embedded sub-editors. Textual
|
|
information about a given term can be displayed using snips inserted
|
|
in the editor next to the term. Each snip is colored according to a
|
|
programmer specified type. Several snips can exist for a given term
|
|
and type. A relation between two terms can be displayed by drawing an
|
|
arrow between the two terms. Each arrow is colored using a programmer
|
|
specified color. Arrows do not carry any textual information with
|
|
them.
|
|
|
|
The library is fundamentally based on terms. It is not possible to
|
|
display snips or arrows that are not directly related to terms.
|
|
However the library does not require terms to be represented by
|
|
MzScheme syntax objects. Terms can be represented by any user-defined
|
|
data structure, called hereafter _labels_. A label represents exactly
|
|
one term and the library user is responsible for keeping track of
|
|
which term is represented by a given label (by, say, keeping a
|
|
reference to the syntax object in the label's data structure), but a
|
|
term in an editor can be represented by one or more labels and the
|
|
user doesn't have to keep track of that. This asymmetry between terms
|
|
and labels is necessary because macro expansions might duplicate some
|
|
terms.
|
|
|
|
With each label can be associated a number of snips containing textual
|
|
information. Each snip has a user-defined type that determines the
|
|
color of the snip. A label can have several snips for a given type,
|
|
and snips of different types associated with it. Mouse menus are
|
|
available to show or hide all snips of a given type for all labels
|
|
corresponding to a given term. The snips are inserted on the left of
|
|
the corresponding term, in an order that is determined by the user
|
|
(see the snip-types-and-colors argument of the
|
|
init-snips-and-arrows-gui function below for details).
|
|
|
|
The library defines two mixins that augment the text editors with
|
|
various methods, and two functions that are used to initialize the
|
|
library. Both functions return one function to register labels with
|
|
the library and one function to change terms in the editors. A term
|
|
in an editor will be recognized and colored by the library only if at
|
|
least one of its corresponding labels has been registered with the
|
|
library.
|
|
|
|
All terms corresponding to registered labels must, either directly or
|
|
indirectly through embedded sub-editors, be contained in a single
|
|
editor called hereafter the top editor. In the case of the DrScheme
|
|
definitions window and its embedded sub-editors (if any), the top
|
|
editor will be the definitions window itself.
|
|
|
|
|
|
Usage
|
|
=====
|
|
|
|
(require (lib "snips-and-arrows.ss" "mrflow"))
|
|
|
|
This will import two mixins:
|
|
|
|
extend-all-editors-mixin and
|
|
extend-top-editor-mixin
|
|
|
|
and two functions:
|
|
|
|
init-snips-and-arrows-gui and
|
|
init-snips-and-arrows-gui-for-syntax-objects
|
|
|
|
See the example at the end of this document for a quick how-to.
|
|
|
|
|
|
All text% classes that will be used to create editors that will
|
|
contain, either directly or indirectly through embedded editors, terms
|
|
to be colored by the library, must be extended using the
|
|
_extend-all-editors-mixin_ mixin. In the case of the DrScheme
|
|
definitions window and its embedded sub-editors (if any) this is
|
|
simply done by giving this mixin as argument to the
|
|
drscheme:unit:add-to-program-editor-mixin function during phase1 of
|
|
DrScheme.
|
|
|
|
The text% class that will be used to create the top editor that will
|
|
contain, either directly or indirectly through embedded sub-editors,
|
|
all the terms to be colored must be extended using the
|
|
_extend-top-editor-mixin_ mixin. This must be done even if all the
|
|
terms to be colored are contained in embedded sub-editors and the top
|
|
editor doesn't itself directly contain any terms to be colored. The
|
|
mixin extends that text% class with two methods of no arguments:
|
|
- _color-registered-labels_, to be called once all labels have been
|
|
registered (see below) in order to color the corresponding terms, to
|
|
start the automatic display of arrows as well as to make the snips
|
|
and arrows related mouse menus available to the user.
|
|
- _remove-all-snips-and-arrows-and-colors_, to be called to terminate
|
|
the automatic display of arrows, make the snips and arrows related
|
|
mouse menus unavailable to the user, remove all inserted snips, and
|
|
optionally clear all colors (see below the last argument to
|
|
init-snips-and-arrows-gui and the last optional argument to
|
|
init-snips-and-arrows-gui-for-syntax-objects for details about this
|
|
last point).
|
|
In the case of the DrScheme definitions window, using this mixin is
|
|
simply done by giving it as argument to the
|
|
drscheme:get/extend:extend-definitions-text function.
|
|
|
|
|
|
The init-snips-and-arrows-gui and
|
|
init-snips-and-arrows-gui-for-syntax-objects functions are used to
|
|
initialize the library. Exactly one of them must be called before
|
|
trying to use the library. The
|
|
init-snips-and-arrows-gui-for-syntax-objects function is a simplified
|
|
version of init-snips-and-arrows-gui.
|
|
|
|
The _init-snips-and-arrows-gui_ function has eleven arguments in the
|
|
following order (with a mnemonic name and a type between parenthesis):
|
|
1) the top editor (top-editor: text%), the editor that, either
|
|
directly or indirectly through embedded sub-editors, contains all
|
|
terms that are to be colored by the library.
|
|
2) a function from label to editor (get-editor-from-label: label ->
|
|
text%) returning the editor that directly contains the term
|
|
corresponding to the label. This function must return the same
|
|
editor for all the labels corresponding to a given term.
|
|
3) a function from label to term position
|
|
(get-mzscheme-position-from-label: label ->
|
|
non-negative-exact-integer) returning the MzScheme position of the
|
|
term corresponding to the label in the editor that directly
|
|
contains it (the editor that would be returned by the
|
|
get-editor-from-label function described just above). This
|
|
function must return the same position for all the labels
|
|
corresponding to a given term.
|
|
4) a function from label to term color span (get-span-from-label:
|
|
label -> non-negative-exact-integer) indicating the number of
|
|
characters of the term corresponding to the label that should be
|
|
colored. Coloring of a term starts with the leftmost character of
|
|
the term and continues towards the right for that number of
|
|
characters. This applies to all terms for which at least one
|
|
label has been registered with the library, regardless of whether
|
|
they are atomic or not, so care must be exercised when computing
|
|
the span for a term containing sub-terms that also have to be
|
|
colored. Arrows starting or ending at a given term will be
|
|
anchored at half the span of the term, so again care must be taken
|
|
when specifying the span of non-atomic terms. This function must
|
|
return the same span for all labels corresponding to a given term.
|
|
5) a function from label to a list of arrows data
|
|
(get-arrows-from-label: label -> (listof (list label label
|
|
string))) indicating what arrows should be drawn when the mouse
|
|
pointer is placed over the term corresponding to the label. Each
|
|
sublist in the list represents one arrow, and must contain, in
|
|
that order, a label corresponding to the starting term for the
|
|
arrow, a label corresponding to the ending term for the arrow, and
|
|
a string representing the arrow color (see color-database<%> in
|
|
the help-desk for a list of color names).
|
|
6) a function from label to style delta (get-style-delta-from-label:
|
|
label -> style-delta%) indicating how the term corresponding to
|
|
the label should be colored. This function must return the same
|
|
style delta for all the labels corresponding to a given term.
|
|
7) a function from popup menu and a list of labels to void
|
|
(extend-menu-for-labels: popup-menu% (listof label) -> void) that
|
|
can be used to add menu-item% objects to the menu that pops up
|
|
when the user clicks with the right mouse button on a term. All
|
|
the labels in the list correspond to that term (there might be
|
|
several labels in the list because of macro expansions). The
|
|
callbacks for the added menu items must not directly modify the
|
|
content of any editor that directly contains colored terms but
|
|
must instead use a function like the first one returned by the
|
|
call to init-snips-and-arrows-gui (see below for details).
|
|
8) a function from snip type (see snip-types-and-colors below) and
|
|
action symbol to string (get-menu-text-from-snip-type: symbol
|
|
symbol -> string) that takes as input a snip type represented as a
|
|
symbol as well as one of the two symbols 'show or 'hide
|
|
representing a user command and returns a string that will be used
|
|
as the text for the menu entry that will allow the user to perform
|
|
said command for the snips of that given type.
|
|
9) a function from snip type and label to a list of strings
|
|
(get-snip-text-from-snip-type-and-label: symbol label -> (listof
|
|
string)) that returns the content of all the snips of the given
|
|
type that will be inserted next to the term corresponding to the
|
|
label when the user uses the snip-related mouse menu entries
|
|
described just above.
|
|
10) a list of snip types and colors (snip-types-and-colors: (listof
|
|
(cons symbol string))) that describes all possible types of snips
|
|
and their associated color. Each sub-list in the list must
|
|
contain two elements: a snip type name represented as a symbol,
|
|
and a corresponding snip color (see color-database<%> in the
|
|
help-desk for a list of color names). For a given term, snips of
|
|
different types will be inserted from left to right on the left of
|
|
the corresponding term in the order in which their types appear in
|
|
this list.
|
|
11) a boolean (clear-colors-immediately?: (union #t #f)) that
|
|
indicates whether, once the user starts modifying the content of
|
|
the editors, the terms colored by the library should be uncolored
|
|
immediately or should be uncolored only the next time a DrScheme
|
|
tool is run or the program executed.
|
|
The init-snips-and-arrows-gui then returns two values: a function to
|
|
change terms and a function to register a label. The function to
|
|
change terms has type ((listof (cons label string)) -> void). Each
|
|
pair in the function's argument consists of a label representing a
|
|
term to be changed and a string that will be used to replace that
|
|
term. It is only necessary to give one label per term to be changed.
|
|
It is an error to give two pairs with labels representing the same
|
|
term but with different strings. The function to register a label has
|
|
type (label -> void) and is used to indicate to the library that the
|
|
corresponding term has to be colored. The same label can safely be
|
|
registered several times. Unspeakable things involving nasty crawling
|
|
bugs will happen to you, and your descendants will be cursed to the
|
|
seventh generation if you dare to call this function after having
|
|
already called the color-registered-labels method described above.
|
|
|
|
The init-snips-and-arrows-gui-for-syntax-objects function is a
|
|
simplified (yes, really) version of init-snips-and-arrows-gui that
|
|
assumes labels are in fact MzScheme syntax objects, and also provides
|
|
default values for all the menu and snip related functions that simply
|
|
assume that no snips are used at all. Also, the terms represented by
|
|
the syntax objects are assumed to be atomic, meaning they will be
|
|
colored in whole and arrows will be anchored at half the terms' spans.
|
|
Seemingly unanchored arrows and overlapping colors may result if you
|
|
try to use this function with non-atomic terms (i.e. terms containing
|
|
sub-terms). The function has only three required arguments, and five
|
|
optional arguments. The three required arguments are, in that order,
|
|
using the mnemonic names from the description of
|
|
init-snips-and-arrows-gui above, and with updated types in
|
|
parenthesis:
|
|
- top-editor (text%)
|
|
- get-arrows-from-label (syntax-object -> (listof (list syntax-object
|
|
syntax-object string)))
|
|
- get-style-delta-from-label (syntax-object -> style-delta%)
|
|
The five optional arguments are as follows, in that order, with their
|
|
default value in brackets:
|
|
- extend-menu-for-labels (popup-menu% (listof syntax-object) -> void)
|
|
[(lambda (m l) (void)))]
|
|
- get-menu-text-from-snip-type (symbol symbol -> string) [internal
|
|
error function]
|
|
- get-snip-text-from-snip-type-and-label (symbol syntax-object ->
|
|
(listof string)) [internal error function]
|
|
- snip-types-and-colors (listof (cons symbol string)) ['()]
|
|
- clear-colors-immediately? (union #t #f) [#f]
|
|
The init-snips-and-arrows-gui-for-syntax-objects returns the same two
|
|
functions as the init-snips-and-arrows-gui function.
|
|
|
|
|
|
Example
|
|
=======
|
|
|
|
This example assumes that this library is used by a DrScheme tool.
|
|
The skeleton for the tool would then look like this:
|
|
|
|
(module my-tool
|
|
...
|
|
(require (lib "snips-and-arrows.ss" "mrflow"))
|
|
...
|
|
(define tool@
|
|
(unit/sig drscheme:tool-exports^
|
|
(import drscheme:tool^)
|
|
...
|
|
(define (phase1)
|
|
...
|
|
(drscheme:unit:add-to-program-editor-mixin extend-all-editors-mixin)
|
|
...)
|
|
...
|
|
(drscheme:get/extend:extend-definitions-text extend-top-editor-mixin)
|
|
...
|
|
(drscheme:get/extend:extend-unit-frame
|
|
(lambda (super%)
|
|
(class super%
|
|
(inherit get-definitions-text)
|
|
(rename [super-clear-annotations clear-annotations])
|
|
; -> void
|
|
(define/override (clear-annotations)
|
|
...
|
|
(super-clear-annotations)
|
|
(send (get-definitions-text) remove-all-snips-and-arrows-and-colors)
|
|
...)
|
|
...
|
|
(define my-tool-button
|
|
(instantiate button%
|
|
...
|
|
(callback
|
|
(lambda (button event)
|
|
...
|
|
(letrec-values ([(user-change-terms register-label-with-gui)
|
|
; use init-snips-and-arrows-gui-for-syntax-objects
|
|
; if you only deal with syntax objects
|
|
(init-snips-and-arrows-gui
|
|
(get-definitions-text)
|
|
...
|
|
; for extend-menu-for-labels, if necessary -
|
|
; basically a callback to library-user code
|
|
(lambda (popup-menu labels)
|
|
...
|
|
(make-object menu-item%
|
|
"change stuff"
|
|
popup-menu
|
|
; menu callback
|
|
(lambda (item event)
|
|
...
|
|
(let ([label-and-new-term-pairs
|
|
(my-tool-get-stuff-to-change labels)])
|
|
...
|
|
; callback to the library from within callback to
|
|
; library-user code
|
|
(user-change-terms label-and-new-term-pairs)
|
|
...)
|
|
...)
|
|
...)
|
|
...)
|
|
...)])
|
|
...
|
|
; call to super's method to clean other tools' annotations
|
|
(super-clear-annotations)
|
|
...
|
|
(drscheme:eval:expand-program
|
|
...
|
|
(lambda (syntax-object-or-eof iter)
|
|
(if (eof-object? syntax-object-or-eof)
|
|
(begin
|
|
...
|
|
(send definitions-text color-registered-labels)
|
|
...)
|
|
(begin
|
|
...
|
|
(my-tool-process-syntax-object ... register-label-with-gui ...)
|
|
...
|
|
(iter)))))))))))))))
|
|
...)
|