HFL ADVANCED SCOPES
- Scope-list functions are functions that allow the application to locate scopes relative to the current scope, by specifying the scope as a string or one or more cell numbers.
- They are optional-scope functions which means that they can be invoked as either normal scopes, or they can be used as functions in an expression.
- When scope-list functions are called as normal functions in an expression (expression context), they return an array containing the cell numbers of the cells that matched the scope. This array can be manipulated and modified if needed, and then used in the same manner as a normal scope by passing the array as the argument in a call another scope-list function.
- When scope-list functions are invoked with code blocks, that is, where the function call is followed by code inside braces (scope context), they behave in the same way as normal scopes, executing the code inside of the code blocks constrained by the scope range.
- All of the scope-list functions can both generate scope-lists, and receive them as one or more scope-specification arguments.
- The scope-specification arguments can be any combination of a scope-specification string, a single number specifying a cell number, or an array containing cell numbers. These specifications do not have to follow the sequential order of cells within the cell hierarchy. This allows the application to refer to content and apply effects to cells in any order.
-
where:<scope-refs>:=<scope-ref> [, <scope-ref>]*<scope-ref>:=<scope-string> | <cell-num> | <cell-array><cell-array>:=an array of <cell-num><cell-num>:=an integer index number of a cell
- Sets the scope to the range of cells identified by the scope specifications in the <scope-refs>. This is the primary scope-list function.
- As a special case, a single scope reference can be specified without an enclosing 'scope()' function when used as a value in an expression (in expression context). This generates an implicit call to 'scope()', and returns a list of matching cells.
-
EXAMPLES:
-
IN SCOPE CONTEXT:
-
scope(header, body, footnote) { ... }
cut#js($js_cells);
cut#discard{scope($cell_num){}}
scope($scope_type:$scStart - last) { ... }
-
-
IN EXPRESSION CONTEXT:
-
if (scope(photo_gallery)) {
...
}
$js_cells = scope(js:1, js:5, js:9);
-
-
IMPLICIT SCOPE CALL IN EXPRESSION CONTEXT:
-
$div_cells = div:..all;
-
-
IN SCOPE CONTEXT:
-
- Sets the scope to the range of cells in the parent scope that are after the scope identified by the <scope-refs> if specified, or after the current scope if not.
-
- Sets the scope to the range of cells in the parent scope that are before the scope identified by the <scope-refs> if specified, or before the current scope if not.
-
- Sets the scope to the range of cells in the parent scope that are after and including the scope identified by the <scope-refs> if specified, or after and including the current scope if not.
-
- Sets the scope to the range of cells in the parent scope that are before and including the scope identified by the <scope-refs> if specified, or before and including the current scope if not.
-
- Parses text in <code-block> into a range of cells, generating a new cell hierarchy in its place. This function provides the application with control over what is treated as HFL content and what is not.
- If the 'tag' option is specified, it interprets the current scope cell as containing the name of an HFL tag, and parses the cell range of that cell's parent past the current cell until it fully parses for that tag. If the tag is a normal paired tag, it will parse until it finds the matching tag. If it is a pattern-based tag, it will parse until it fully matches the pattern.
- If the 'tag' option is not specified, it fully parses the cell of the current scope itself. If that cell is a container, it loops through each child cell of the current scope, treating each as a text cell. If the cell is just a text cell, it parses all of the text of that cell. If the 'raw' option is specified, it converts the contents of the current cell to a single text cell, thereby flattening the cell structure within the current scope.
-
Background
- HFL allows certain ranges of text or entire files to be treated as 'raw' text, either through marking a scope tag as 'raw', or by loading the file as 'raw'. The cells created are not parsed for either HTML tags or HFL syntax, and are just plain text cells.
- A common use for raw tags are to treat an HTML open tag as text to prevent HFL from searching for the matching close tag. Entire files are often read when their purpose is to just be text, such as for creating a source listing.
- But there are times when it is desirable to treat part or all of a text cell as HFL or HTML code. An example might be to allow certain text ranges that have HTML tag syntax to actually be treated as HTML tags, while leaving the rest of the text as just text.
- In such cases, the desired range of text cells must be parsed as they would have been if not treated as raw text. The parse_scope() function can be called to scan just that range of text to be treated as HFL, and the rest of the text will remain unmodified.
Other Positional (Non-Hierarchical) Scopes
- Almost all scope types locate cells that are descendents of the cells of the current enclosing scope. The inner scopes are thus relative to the outer scopes.
- There are also non-hierarchical scopes, which are not relative to the enclosing outer scope, but rather can jump outside of the hierarchical nesting of the enclosing scopes. In effect, they reset the top-level starting scope.
-
- If the scope-range is specified as ':curr', sets the scope to the page-level scope cell of the current scope, or the current scope if it is already at page level. All inner scopes will now be relative to the page scope.
- If a scope-range is specified, locates the pages specified by the range by counting pages starting from the first page. Thus 'page:2' will be the scope of the second page, even if invoked from a scope in another page. All inner scopes will now be relative to the located page scopes.
- NOTE: if there is only one page total, 'page', 'page:1' and 'page:curr' will all behave the same. But if there can be more than one page and you wish to refer to the current containing page, always use 'page:curr' to avoid unexpected results.
- If the 'page' scope is used inside of a constructor modal scope ('create', 'insert' or 'append'), it will create one page for each value in its scope-range. Thus 'insert{page:2-4{}}' would create 3 pages inserted at the front as new pages 1-3.
- EXAMPLES
-
// If have a nav bar, paste into page of current scope
if ($fHaveNav) { page:curr { paste_contents { clip#_navbar_cutbuf } } }
// Append two pages to end of page list and assign filenames to them
var $n = 3;
create { page:1-2 { setFilename("pic$n.html"); $n++;}}
// Apply format "page.V1.hfmt" to all pages
page:all { applyFormat("page.V1.hfmt"); }
-
- Sets the scope to the parent scope cell of the current scope. All inner scopes will now be relative to the parent scope.
- EXAMPLE
-
table:1 {
tr:2 {
td:4 {
// Set class of tr:2 to "4-column" if have a 4th column
parent { class="4-column" }
}}}
-
- The 'rest' scope is a bit unusual.
- It sets the current scope to the range of cells between the currently executing format cell and the last cell of the ancestor cell defined by the <parent-level>, if any.
- If the <parent-level> is not specified, the ancestor cell will be the parent of the current scope cell.
- If the <parent-level> is an integer, it sets the end parent cell to the nth parent cell above the current scope cell. So for example, if <parent-level> is 1, then the ancestor cell would be the parent of the current scope cell. And if it is 2, it would the parent of the parent, and so on. This allows the end of the range to extend outside of the current scope.
- If the <parent-level> is a tag name, it climbs the cell hierarchy until it finds a cell with a matching tag name, and it is used as the ancestor cell.
-
For example, the following would set the color of the word 'good' to red.
The 'rest' scope range would be all characters from the
words 'good' through 'countrymen'.
Within that scope, the scope 'word:1' would match the
word 'good'.
-
<p>
Now is the time for all <\ rest{word:1{red;}} \>good men to come
to the aid of their countrymen
</p>
-
- Without the enclosing 'rest' scope, the scope 'word:1' would match the word 'Now' because the outer scope would be the cell for '<p>'.
-
- Sets the scope to the specified clip pool, or to the default clip pool for the page if no qualifier specified.
- For more details on clip pools see the section on "Clip Pools"
- EXAMPLE
-
clip {
bottom_links? {
create {
txt{" | "}
a {href="$href" text="$label" class="bottom_link"} } } }
Conditional-Create Scope List Functions
- Conditional-create scope-list functions are versions of 'scope()' that create cells for any scopes not found.
-
- Finds the cells of the scope range, creating cells for any scope references that have no match. When this function returns, all scope references in the range will have a matching cells.
- If running in scope context, applies the code block to all of the cells of the range. If running in expression context, returns a scope list consisting of both the existing cells and the ones it created.
-
- Finds the cells of the scope range, creating cells for any scope references that have no match. When this function returns, all scope references in the range will have a matching cells.
- If running in scope context, applies the code block only to the cells that it created. If running in expression context, returns a scope list consisting of only the cells it created.
- Either function can be used as a scope.
-
For example, suppose cells that match scope 'fubar:1-4' already exist.
Then when we execute the following code:
-
scope_or_new(fubar:1-5) {
text="THIS SETS TEXT OF FUBAR:1-5"
}
scope_if_new(fubar:1-6) {
text="THIS SETS TEXT OF FUBAR:6 ONLY"
}
- The first statement would create a cell for 'fubar:5' because it does not yet exist, then it would set the text of all 5 'fubar' scopes.
- The second statement would create a cell for 'fubar:6' because it does not yet exist, but only sets the text of that cell, because it only applies the code block to cells that it creates.
-
Cell-tree Modification Scope Functions
- These scope-list functions can eidt the structure of cell trees, inserting or deleting cells. Unlike modal scopes, the behavior of the scopes inside of their scope blocks are not modified. Like other scope-list functions, they can be used as either scopes or as functions.
-
- Constructs a new cell tree around the current scope. Builds one enclosing cell for each scope specfication in the <scope-levels>.
-
where:<f-full-move>:=a boolean value, e.g. 1
- Constructs one or more new cells around the contents of the current scope, one for each scope specfication level in <scope-levels>.
- If flag <f-full-move> is specified, moves all of the properties of the current scope into the first cell of the constructed inner 'contents' cells.
-
where:<split-opts>:=<copy-to-scope> [, <move-lowest>]<move-lowest>:='before' | 'delete'
- Splits a parent cell given by <scope-string> into two cells. The new parent cell will contain a copy of the cell tree structure of the original parent cell down to the level of the current scope. All of the content at all levels before the split point will remain in the original cell tree. All of the content at all levels after the split point will be moved into the new cell tree.
- If the original parent cell is a <page> cell, the result will be that the original page is split into two pages.
- If invoked as a scope, the scope inside of the code block will be that of the new split-off parent cell. If invoked as a function, returns the new split-off parent cell.
- If the <copy-to-scope> argument is specified, the contents of all cells inside of the parent cell will be copied into the new parent cell tree, level by level, up to the specified scope. Then all levels from that cell down that will be split as before.
- The <move-lowest> option specifies what to do with the lowest-level cell. If the 'before' is specified, moves the final cell to the new parent tree, instead of leaving it in the original parent tree. If 'delete' is specified, deletes the final cell.
-
EXAMPLES:
-
// Split page in two, duplicating everything above <body_content>
if ($new_page_cell = split_parent(page, body_content)) {
...
}
// Split the div in two, moving current cell into the new half
split_parent(div#descrip, 0, 'before') {
...
}
-