Skip to content

Commit

Permalink
docs(developer): clarify context() offset with nul and if()
Browse files Browse the repository at this point in the history
Cleanup `context`, `index`, and `nul` documentation as well, tidy up
some examples.

Fixes: #1888
  • Loading branch information
mcdurdin committed Feb 21, 2025
1 parent 1acc311 commit 84ed132
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 101 deletions.
78 changes: 40 additions & 38 deletions developer/language/reference/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,56 @@ title: index()

## Summary

The **`index()`** statement maps a character from an input store to an
output store.
The `index()` statement maps a character from an input store to an output store.

## Syntax

```
any(inputStore) > index(outputStore,offset)
any(inputStore) index(secondStore,offset) > ...
```

### Parameters

`outputStore`
: The store from which the output character is selected. This store
should be the same length as the `inputStore`.
`outputStore`, `secondStore`
: The store from which the output character is selected. This store should be
the same length as the `inputStore`.

`offset`
: The character offset of the `any()` statement in the left hand side
of the rule to pair with, starting at `1`. The index increments for
each character or statement found, with one caveat: `outs()`
statements are expanded prior to calculating the offset. Note that
unlike the [`context()`](context) statement, the offset calculation
does include [`if()`](if) statements.

: The character offset of the `any()` statement in the left hand side of the
rule to pair with, starting at `1`. The index increments for each character or
statement found, with one caveat:

- [`outs()`](outs) statements are expanded prior to calculating the offset.

If the `index()` statement is in the context (second form above), the offset
must be less than the offset of the `index()` statement itself.

## Description

The **`index()`** statement works together with [`any()`](any) to map an
array of characters in `inputStore` to a corresponding array in
`outputStore`. **`index()`** can be used in the context and output
sections of a rule. If used in the context section, the `offset`
parameter must be less than the offset of the **`index()`** statement in
the context.
The `index()` statement works together with [`any()`](any) to map an array of
characters in `inputStore` to a corresponding array in `outputStore` (or
`secondStore`). `index()` can be used in the context and output sections of a
rule. If used in the context section, the `offset` parameter must be less than
the offset of the `index()` statement in the context.

The stores can include `deadkey()` statements, `outs()` statements and
virtual keys; the `outs()` statement is expanded prior to the
calculation of offsets within the input and output stores. When a store
contains virtual keys, it can be used only with the `any()` statement in
the key part of the rule.
The stores can include `deadkey()` statements, `outs()` statements and virtual
keys; the `outs()` statement is expanded prior to the calculation of offsets
within the input and output stores. When a store contains virtual keys, it can
be used only with the `any()` statement in the key part of the rule.

Conceptually, the **`index()`** and `any()` pairing can be expanded into
multiple rules, one for each pair of characters. If expanded, this would
grow the rule set exponentially when multiple pairs of **`index()`** and
`any()` are used in the same rule.
Conceptually, the `index()` and `any()` pairing can be expanded into multiple
rules, one for each pair of characters. If expanded, this would grow the rule
set exponentially when multiple pairs of `index()` and `any()` are used in the
same rule.

## Examples

### Example: Using `index()`

This example maps a vowel, followed by a diacritic key, to the same
vowel, and a corresponding combining diacritic mark.
This example maps a vowel, followed by a diacritic key, to the same vowel, and a
corresponding combining diacritic mark.

```
store(vowel) "aeiou"
Expand All @@ -65,9 +66,9 @@ c this could also be expressed with the context statement:
any(vowel) + any(diacritickey) > context index(diacriticCombining,2)
```

This example does the same as the previous, except it reverses the input
order: a diacritic mark first, then a vowel, and uses the **`index()`**
statement to swap the results in the output.
This example does the same as the previous, except it reverses the input order:
a diacritic mark first, then a vowel, and uses the `index()` statement to swap
the results in the output.

```
store(vowel) "aeiou"
Expand All @@ -77,10 +78,9 @@ store(diacriticCombining) U+0300 U+0301 U+0302
any(diacritickey) + any(vowel) > index(vowel,2) index(diacriticCombining,1)
```

The following example shows how the index statement can be used in the
left hand side of a rule. If a repeating vowel is found, then this rule
puts a circumflex on top of both vowels when <key>^</key>
is pressed.
The following example shows how the index statement can be used in the left hand
side of a rule. If a repeating vowel is found, then this rule puts a circumflex
on top of both vowels when <key>^</key> is pressed.

```
store(vowel) "aeiou"
Expand All @@ -97,12 +97,14 @@ The `index()` statement can be used in keyboards on all platforms.
||||||||

> ### Note
For **mobile** and **mobile web**, the statement is **only** accessible as the output section of the rule.
For **mobile** and **mobile web**, the statement is **only** accessible as the
output section of the rule.

## Version history

The **`index()`** statement was introduced in Keyman 3.0. As of version
6.0, it can also be used in the left-hand side of a rule.
The `index()` statement was introduced in Keyman 3.0.

As of version 6.0, `index()` can also be used in the left-hand side of a rule.

## See also

Expand Down
67 changes: 35 additions & 32 deletions developer/language/reference/_nul.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ title: nul

## Summary

The **`nul`** statement has two purposes: in the output of a rule, it
signifies deleting context and keystroke, and at the start of the
context it signifies that the context buffer in the application must be
empty (or no longer than the context of the rule) in order for the rule
to match.
The `nul` statement has two purposes: in the output of a rule, it signifies
deleting context and keystroke, and at the start of the context it signifies
that the context buffer in the application must be empty (or no longer than the
context of the rule) in order for the rule to match.

## Syntax

Expand All @@ -19,31 +18,31 @@ nul [...] [+ key] > output

## Description

The `nul` statement will delete the context and key on the left hand
side of the rule from the output; it is equivalent to having an empty
output (which is not allowed). The `nul` statement probably will not be
used often, because there are not many times you would want to delete
the context and keystroke. The `nul` command must be the only character
or command on the right hand side of the rule.

`nul` can be used in the context in one special situation. It is used at
the start of the context to tell Keyman to find a match only if the
`nul` statement is before the start of the context buffer. For example,
you may use this to test if the user is typing a character at the start
of a paragraph, and use a different character in this situation.

Be careful when using `nul` in the context. In legacy environments, such
as many Windows applications, the context buffer will be empty after
cursor movement, menu access, or many other situations. This means that
the `nul` keyword may match in situations where you are not expecting
it, for example in the middle of a word.

In modern environments, such as touch devices, web keyboards, macOS, and
some modern Windows applications, the `nul` keyword will match at the
start of a text buffer, and nowhere else. For example, in Microsoft
Word, it will match at the start of the document, after a page, column
or section break, at the start of a header or footer, at the start of a
table cell and other similar situations.
The `nul` statement will delete the context and key on the left hand side of the
rule from the output; it is equivalent to having an empty output (which is not
allowed). The `nul` statement probably will not be used often, because there are
not many times you would want to delete the context and keystroke. The `nul`
command must be the only character or command on the right hand side of the
rule.

`nul` can be used in the context in one special situation. It is used at the
start of the context to tell Keyman to find a match only if the `nul` statement
is before the start of the context buffer. For example, you may use this to test
if the user is typing a character at the start of a paragraph, and use a
different character in this situation.

Be careful when using `nul` in the context. In legacy environments, such as many
Windows applications, the context buffer will be empty after cursor movement,
menu access, or many other situations. This means that the `nul` keyword may
match in situations where you are not expecting it, for example in the middle of
a word.

In modern environments, such as touch devices, web keyboards, and some modern
Linux, macOS, and Windows applications, the `nul` keyword will match at the
start of a text buffer, and nowhere else. For example, in Microsoft Word, it
will match at the start of the document, after a page, column or section break,
at the start of a header or footer, at the start of a table cell and other
similar situations.

## Note

Expand All @@ -62,13 +61,17 @@ U+0D4D + 'a' > nul

### Example: Using `nul` on the left hand side of the context

This example will capitalize a letter at the start of a buffer (hint:
this not really recommended!)
This example will capitalize a letter at the start of a buffer.

``` keyman
nul + 'a' > 'A'
```

> [!Hint]
> This is not the recommended approach to casing. See
> [Casing Support](../guide/casing-support.md) for better ways to implement
> this.
## Platforms

The `nul` statement can be used in keyboards on all platforms.
Expand Down
71 changes: 40 additions & 31 deletions developer/language/reference/context.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
---
title: context
---

## Summary

The **`context`** statement reproduces part or all of the context
buffer.
The `context` statement reproduces part or all of the context buffer.

## Syntax

Expand All @@ -18,60 +17,70 @@ buffer.
### Parameters

`offset`
: The character offset in the context from which the output character
is selected, starting at `1`. The index increments for each
character or statement found, with two caveats:
- [`outs()`](outs) statements are expanded prior to calculating
the offset.
- [`if()`](if) statements are not included in the calculation of
the offset, which is different to how [`index()`](index)
statements calculate offset.

This offset must be less than the offset of the `context()`
statement itself, if the `context()` statement is in the context
(third form above).

: The character offset in the context from which the output character is
selected, starting at `1`. The index increments for each character or
statement found, with one caveat:

- [`outs()`](outs) statements are expanded prior to calculating the offset.

If the `context()` statement is in the context (third form above), the offset
must be less than the offset of the `context()` statement itself.

The offset cannot reference a [`nul`](nul) or [`if`](if) statement, as both of
these are non-character statements.

## Description

The `context` statement reproduces the context stored from the rule
match, or a single character of it, into the output. Use the `context`
statement as much as possible as it is significantly faster than using
the index statement.
The `context` statement reproduces the context stored from the rule match, or a
single character of it, into the output. If you do not need to change the context,
then use the `context` statement as the first element of your rule output, as
this allows Keyman to skip deletion and re-insertion of the context into the
text store of the active document.

A single character from the context can be output (on the right-hand
side of a rule) or matched (on the left-hand side of a rule) using the
`context()` form.
A single character from the context can be output (on the right-hand side of a
rule) or matched (on the left-hand side of a rule) using the `context()` form.

Note that although the `context()` form can be used in the left-hand
side of a rule, the `context` form cannot.
Note that although the `context()` form can be used in the left-hand side of a
rule, the `context` form cannot.

## Examples

### Example: Using `context`

```
c match a char from the 'cons' store, 'W' and any 'key', don't change the output
any(cons) "W" + any(key) > context index(keyout,3)
c when the user types 'context', change it to 'ox'
"contex" + "t" > context(2) context(6) c outputs "ox"
c when a user types two identical consonants, delete one of them,
c on the next matching key from the 'key' store
any(cons) context(1) + any(key) > context(1) index(keyout, 3)
```

## Platforms

The `context` statement can be used in keyboards on all platforms.

| Windows | macOS | Linux | Desktop web | Mobile web | iOS | Android |
|---------|-------|-------|-------------|------------|-----|---------|
| ------- | ----- | ----- | ----------- | ---------- | --- | ------- |
||||||||

## Version history

Support for [`notany()`](notany) together with `context()` added in
KeymanWeb 14.0.
- Offset calculations for `nul` were documented in 18.0 along with bug fixes in
Keyman Core.

- Support for [`notany()`](notany) together with `context()` added in KeymanWeb
14.0.

The context(n) form was introduced in version 6.0.
- The `context(n)` form was introduced in version 6.0.

The context statement was introduced in Keyman 3.0.
- The `context` statement was introduced in Keyman 3.0.

## See also

- `if()` statement
- `outs()` statement
- `if()` statement
- `outs()` statement

0 comments on commit 84ed132

Please sign in to comment.