Shifting Selected Text to the right or left
This lesson shows you how to handle tabs and shift text to the right or left when the user presses the tab key.
The tabKey message
The tabKey handler
The handler shifts all lines that are completely or partially select by inserting or removing a tab character at the start of each line. If there is no selection but there is an insertion point a tab character is inserted at the insertion point. If a line is already shifted all the way to the left (in other words, if it has no leading tabs), shifting it to the left doesn't affect it.
The selectedText function
The first thing the handler does is check the selectedText function to find out whether any text is selected. If the selectedText is empty, there is an insertion point but no text is selected. In this case, the handler passes the tabKey message on to the engine, allowing the Tab key to operate normally: as long as the field's tabStops property is not empty, the Tab key inserts a tab character.
The selectedLines function
Next, the handler finds out what part of the text is selected. The selectedLines function returns one of two forms:
- If more than one line is selected, it returns an expression of the form line x to y of field x. In this case, the handler puts the first selected line ("x") into a variable called tFirstLine, and the last selected line ("y") into a variable called tLastLine.
- If one line is selected, or the selection is less than one line, or there is an insertion point but nothing is selected, it returns an expression of the form line x of field z. In this case, the handler puts the selected line number into both the tFirstLine and tLastLine variables. This simplifies the logic in the repeat loop later in the handler.
The shift key
Next, the handler checks whether the user is holding down the shift key or not. If so, the handler shifts the selected lines to the left by removing leading tabs; if not, it shifts the lines to the right by inserting tabs.
To shift left, the handler uses a repeat control structure to go through each of the lines in the selection. If the tFirstLine variable is the same as the tLastLine variable (if only one line or portion of a line is selected) the statements in the loop are executed only once.
For each line, the repeat loop checks whether the first character is a tab. If so, it removes it. If the first character isn't a tab, that line is already shifted all the way to the left, so the handler doesn't change it.
Shifting right is similar, but there is no need to check whether the first character of each line is a tab: the handler simply adds a tab to the beginning of each affected line.
Finally, the handler re-selects the lines that were selected before the user pressed the Tab key. This is not strictly necessary, but it's less disorienting and more convenient for the user to retain the selection. It also helps make it clear that the Tab key affects all lines where there is even a partial selection, because the handler selects the entire line.
Many variations on this handler are possible. For example, you might prefer to shift lines using a space, or a run of several spaces, instead of a tab character. Or you might want to add or delete leading ">" characters for use with email or Usenet applications, where quoted lines from previous messages are indicated using this convention.
The tabKey code
on tabKey local tSelectedLines, tFirstLine, tLastLine if the selectedText is empty then ## there's an insertion point, but no selection, ## allow the tab key operate normally pass tabKey else put the selectedLines into tSelectedLines put word 2 of the selectedLines into tFirstLine if word 3 of the selectedLines is "to" then ## multiple lines are selected put word 4 of the selectedLines into tLastLine else ## single line is selected put tFirstLine into tLastLine end if if the shiftKey is down then ## shift left - remove a tab repeat with tLine = tFirstLine to tLastLine if char 1 of line tLine of (the text of the selectedField) is tab then ## remove leading tab delete char 1 of line tLine of the selectedField end if end repeat else ## shift key not down, so shift right - add a tab: repeat with tLine = tFirstLine to tLastLine ## add a leading tab to each line in the selection put tab before line tLine of the selectedField end repeat end if ## (re)select all affected lines select tSelectedLines end if end tabKey