Tinderbox v9 Icon

Using long sections of code—code notes

NOTE: this concept pre-dates newer features like functions, and stamp notes in Built-in Hints. The concept of a note for holding code, such as export boilerplate code—i.e. not formal templates but used in generating export code, still holds true.

In code input boxes, using opt+Return will insert a line break into the code whereas Return executes the change.

The 'code note' concept

If long pieces of action code are needed, such as do not easily fit into a dialog's input box, then another note's $Text can be used to store the code. This approach is generally described as a 'code note' but note this is not a formal Tinderbox concpet. A new note is created and its text is used to just hold the code. This offers:

Use the 'Code' or 'Action' prototype

If using code notes, first add the 'Code' prototype from the built-in prototypes to the TBX and then assign the prototype to your code note(s). If using several such notes, make a codes container and set the "code" prototype via its $OnAdd. The code note sets a monospace font, removes paragraph (line break) spacing, turns off auto-lists, etc. All this makes setting and testing code much easier.

An important consideration with these 'code repository' notes is that generally it is not required to export such notes or have them appear in the content part of a document (e.g. in agents). If using a top-level split of content and utility notes, these code repository notes should definitely go into the utility.

From v9.6.0, if the code being stored is only action code, then use of the 'Action' built-in prototype may be more useful as this employs syntax colouring of action code and detection of unbalanced brackets.

Using a code note's code

The best way to deploy code in the code note is to use its rule (or edict if preferred) to set the rule/OnAdd/etc. of another note. Therefore a self-focussed action, i.e. rule or edict, in the note will set an action in another note, for example:

$Rule("Some note")=$Text; 

Assuming the $Name "some note" is unique, this will set that's note's $Rule's code to be the current note's $Text. If the $Name is not unique, consider using the $Path:

$Rule("/Stuff/examples/Some note")=$Text; 

This approach allows use of the $RuleEnabled (or $EdictEnabled) to act as a cut-off and stop propagation of code if the code in the note's $Text is being worked on, e.g. to extend or correct existing code. Once the edit is complete, re-enable and the new code will be passed to the relevant note(s). Although, it is more instinctive to use a rule in this role, unless the code will change often, an edict is a more sensible choice as it runs less often (edict execution). If using these 'enable' attributes, consider adding either/both as additional Displayed Attributes to the Code prototype.

If the reference is to more than one note, a list of offsets is possible:

$Rule("Some note;Another note")=$Text; 

But, if more than two or three matches are desired, a better approach is to use a prototype name as the match. Then, all notes using the prototype are updated.

Storing stamps

Older methods were rendered obsolete by the v9+ feature of the optional Hints container. If this is feature used every stamp (including older pre-existing stamps) is represented by a discrete notes using the 'Action' prototype which offers syntax colouring and $Text customisations pertinent writing action code.

A further useful affordance of using Hints is per-stamp notes can be opened as stand-alone note windows with action code syntax and parenthesis completion warnings.

Storing stamps - without a Hints container (legacy only)

Consider using the hints container (above), before using this legacy approach.

If a stamp's code is long, it may be more convenient to write the code in a code note and then make the actual stamp an action() task that executes the $Text of the code note. Thus if a code note 'Test-stamp' held the action code $Colour="red";, then a stamp with the code:


when run would result in the stamped note(s) turning red. The example is trivial but shows the technique. Note the offset addressing in the stamp to the code note is case sensitive and should use a unique $Name (or else cite the full, unquoted, $Path to the code note). Local attribute references, i.e. $Color or $ChildCount, are bound to the note being stamped: it is not possible to reference values in the code note using a designator.

Usage Tips

Avoid the temptation to make the code note affect itself, e.g. set its own $Rule by copying pasting code from the note's $Text into a $Rule displayed as a Displayed Attribute. Use the code note simply to store/edit the code, then use its $rule to set an attribute in a different note.

The limitation of the above is the result is to overwrite the note's own $Rule, or other action attribute, with the code from the referenced note's $Text. However, if the latter is updated, the changed code is not reflected as the note needing the code is no longer referencing it, as the $Rule has a literal copy of the old code. The fix is to reverse the reference, so the note with the code sets the attribute of note needing to use it. If note "Complex Test" needs to use the code in $Text of "code sample 1", then in "code sample 1" this $Rule is added:

$Rule("Complex Test") = $Text 

The "Complex Test" note's $Rule, if one, makes no reference to "code sample 1". If the code-holding note's $Text is edited, on the next update cycle the $Rule of "Complex Test" is updated. Another variant on this is to use the same technique to set a complex conditional $Rule or $DisplayExpression for a prototype note. Editing the 'source' code will update the prototype and the new code will be inherited by all notes using that prototype.

The context of this process does not just have to be a rule. Other examples:

$OnAdd(some note)=$Text(code sample 2); 

$AgentQuery(some agent)=$Text(code sample 3); 

Using eval() and action()

The eval() action can be used to further extend the complexity of what may be done, where an operator does not exist for the task at hand. For example, assume a code note of the above type has written, into another note's $TempString, a literal string value of:

"collect_if(all,$MyDate== '"+$MyDate+"',$Name)" 

See how the attribute value, though a string, includes enclosing quotes. This means that it is possible to delay the evaluation of $MyDate. In the note using the code, a single eval() call on $TempString, eval($TempString), returns the same string in different form. The literal string value of the current note's $MyDate is inserted into it (this example is on a system using day/month date order) and stripped of enclosing quotes:

collect_if(all,$MyDate== '23/7/2011 10:02',$Name) 

The latter is important as the value of eval($TempString) becomes a string of valid action code. To actually get the result of the collect_if(), it is still necessary to evaluate that code. Thus by nesting a second eval() call, the output of the first call is evaluated afresh. Using eval(eval($TempString)) gives:

Note A;Note C;Note_X 

which is the output of the collect_if(). As a side note, observe how in the initial string it was necessary to added enclosing single quotes around where the code reference to $MyDate occurred, ensuring the literal value, when inserted, was a properly quoted string literal. Single quotes were used as the overall initial string already used double quotes.

Sometimes the Tinderbox code parser is unclear as to user intent and over-evaluates returning a boolean true/false value (N.B. this underlies queries which under the hood resolve query terms to a boolean value). In such cases, the action() operator generally works but note a significant difference between action() and eval(): action() evaluates a complete expression—both left and right sides of the '=' assignment—as a mix of concatenated strings and and literal values. By comparison, eval() evaluates part of an expression.