(* Copyright (C) 1992, Digital Equipment Corporation *) (* All rights reserved. *) (* See the file COPYRIGHT for a full description. *) (* *) (* Last modified on Tue Jan 5 21:41:24 PST 1993 by meehan *) (* modified on Tue Jun 16 13:08:09 PDT 1992 by muller *) (* modified on Wed Jul 10 13:21:41 PDT 1991 by mhb *) (* modified on Tue Feb 26 15:11:39 PST 1991 by brooks *) (* modified on Fri Sep 28 13:47:30 PDT 1990 by birrell *) <* PRAGMA LL *> (* The "TextPortClass" interface contains the information needed to implement a variety of models for keybinding and text-selection. Four models are currently implemented: Ivy, Emacs, Mac, and Xterm. "TextPort.Model" is an enumeration type for the four names, but "TextPortClass.Model" is the type of the actual object attached to a "TextPort", to which user-events (keys, mouse clicks, position reports) are sent. The model is responsible for all highlighting. Unless otherwise noted, the locking level of all procedures in this interface is "TextPort.T.mu". *) INTERFACE TextPortClass; IMPORT Font, KeyboardKey, PaintOp, TextPort, VBT, VTDef, VText; CONST Primary = TextPort.SelectionType.Primary; Secondary = TextPort.SelectionType.Secondary; REVEAL TextPort.T <: T; TYPE Pixels = CARDINAL; T = TextPort.Public OBJECT mu: MUTEX; (* VBT.mu < v.mu *) <* LL = v.mu *> m : Model := NIL; vtext : VText.T; font : Font.T; scrollBar : TextPort.Scroller; singleLine : BOOLEAN; readOnly : BOOLEAN; expandOnDemand: BOOLEAN; visible : BOOLEAN; linesShown : CARDINAL; charWidth : Pixels := 0; fontHeight : Pixels := 0; typeinStart : CARDINAL; cur : UndoRec; lastCmdKind : CommandKind; thisCmdKind : CommandKind; wishCol : CARDINAL; hasFocus := FALSE; METHODS <* LL = SELF.mu *> getText (begin, end: CARDINAL): TEXT; index (): CARDINAL; length (): CARDINAL; normalize (to := -1); replace (begin, end: CARDINAL; newText: TEXT): TextPort.Extent; unsafeReplace (begin, end: CARDINAL; newText: TEXT): TextPort.Extent; insert (t: TEXT); unsafeInsert (t: TEXT); getKFocus (time: VBT.TimeStamp): BOOLEAN; newlineAndIndent (); (* All of these call SELF.error. *) vbterror (msg: TEXT; ec: VBT.ErrorCode); vterror (msg: TEXT; ec: VTDef.ErrorCode); rdfailure (msg: TEXT; ec: REFANY); rdeoferror (msg: TEXT); (* We release SELF.mu around the following callbacks. *) ULreturnAction (READONLY cd: VBT.KeyRec); ULtabAction (READONLY cd: VBT.KeyRec); ULdefaultAction (READONLY cd: VBT.KeyRec); ULfocus (gaining: BOOLEAN; time: VBT.TimeStamp); ULmodified (); ULerror (msg: TEXT); END; (* "v.font" is a local copy of "v.vtext.vOptions.vFontxxx.vFont.font". "v.charwidth" is the width of a (maximal) character. "v.fontHeight" is the height of a (maximal) character. "v.typeinStart" is meaningful only for typescripts, where it indicates the point that divides the ``history'' part of the transcript, which is read-only, from the current command line, which is not. See the "TypescriptVBT" interface. For non-typescripts, this field is always zero. "v.thisCmdKind" and "v.lastCmdKind" allow the interpretation of a command to depend on the previous command. Currently, the only commands that depend on context are the ``vertical'' commands that call "UpOneLine" and "DownOneLine". "v.hasFocus" is "TRUE" when "v" has acquired the keyboard focus. The keyboard focus and primary selection are always acquired and released together. "v.replace" tests "v.readOnly"; if that is "TRUE", then it returns "TextPort.NotFound". Otherwise it calls "v.unsafeReplace", which is the only routine that actually alters the underlying text. "v.insert" calls "v.replace"; i.e., it is safe. *) TYPE CommandKind = {VertCommand, OtherCommand}; TYPE Arrow = [KeyboardKey.Left .. KeyboardKey.Down]; Model <: PublicModel; PublicModel = OBJECT v : T; fixed : CARDINAL; (* Fixed pivot for highlighting *) dragging := FALSE; METHODS <* LL = SELF.v.mu *> init (cs: PaintOp.ColorScheme): Model; close (); mouse (READONLY cd: VBT.MouseRec); position (READONLY cd: VBT.PositionRec); misc (READONLY cd: VBT.MiscRec); read (READONLY s: VBT.Selection; time: VBT.TimeStamp): TEXT RAISES {VBT.Error}; write (READONLY s: VBT.Selection; time: VBT.TimeStamp; t: TEXT) RAISES {VBT.Error}; cut (time: VBT.TimeStamp); copy (time: VBT.TimeStamp); paste (time: VBT.TimeStamp); clear (); filter (VAR cd: VBT.KeyRec); controlChord (ch: CHAR; READONLY cd: VBT.KeyRec); optionChord (ch: CHAR; READONLY cd: VBT.KeyRec); arrowKey (ch: Arrow; READONLY cd: VBT.KeyRec); getSelection (sel := Primary): TextPort.Extent; getSelectedText (sel := Primary): TEXT; putSelectedText (t: TEXT; sel := Primary); hasVBTselection (sel := Primary): BOOLEAN; seek (position: CARDINAL); select (time : VBT.TimeStamp; begin, end : CARDINAL; sel := Primary; replaceMode := FALSE; caretEnd := VText.WhichEnd.Right); isReplaceMode (): BOOLEAN; takeSelection (sel : TextPort.SelectionType; time : VBT.TimeStamp; highlight := FALSE): BOOLEAN; walkIntervals (p: IProc) RAISES {VTDef.Error}; END; (* "m.init(...)" initializes a Model "m". The default method is a no-op and simply returns "m". "m.close()" releases "VBT" selections and deletes highlighting intervals. The type "TextPort.T" overrides the "VBT" "mouse", "position", "misc", "read", and "write" methods with procedures that lock "v.mu" and call "v.m.mouse", "v.m.position", etc. Note that the signatures are not identical to their Trestle counterparts. Clients must override the "read" method with a procedure that returns a text if "m" owns the selection "s"; otherwise it should call the default method, which calls "VBT.Read(s, time)". "time" is valid when the caller is a user-event procedure such as "Paste"; it will be 0 when called from "TextPort.T.read", but in that case, "m" owns the selection, so "time" is not needed. Similarly, clients must override the "write" method. "write" is called by "TextPort.T.write", which ensures that "m.v.readOnly" is "FALSE" before calling this. If there is a primary selection, then "m.copy(time)" arranges for that text to become the source selection. Otherwise, it is a no-op; in particular, if the selection is empty, it will not acquire the source selection. The default for "m.cut(time)" is "m.copy(time); m.clear()". The default for "m.paste(time)" is "m.insert(m.read(VBT.Source, time))". "m.clear()" deletes the primary selection. Its default method is | m.putSelectedText ("", TextPort.SelectionType.Primary) "m.insert(t)" implements "TextPort.Insert". The default method replaces the primary selection, if there is one, with "t"; otherwise, it inserts "t" at the type-in point. Clients may wish to override this in order to alter the highlighting. "m.filter(cd)" is called by the default method for "TextPort.T.key". The default for "filter" is a no-op. The "controlChord", "optionChord", and "arrowKey" methods are described in the "TextPort" interface. The interfaces for the specific models override "controlChord" and "optionChord", for which there are no defaults. The default method for "arrowKey" dispatches to "ToPrevChar", "ToNextChar", "UpOneLine", and "DownOneLine". "m.seek(position)" sets the type-in point. *) TYPE IProc = PROCEDURE (i: VText.Interval) RAISES {VTDef.Error}; TYPE SelectionRecord = RECORD owned := FALSE; interval: VText.Interval; mode : VText.SelectionMode END; TYPE UndoRec <: ROOT; TYPE IRange = RECORD left, middle, right: CARDINAL END; PROCEDURE GetRange ( v : T; READONLY cp : VBT.CursorPosition; mode: VText.SelectionMode ): IRange; <* LL = v.mu *> (* Return an "IRange" indicating the boundaries of the character, word, paragraph, etc., that contains the position "cp". The "middle" field will be equal to either the "left" field or the "right" field, depending on which end the cursor was closer to. *) CONST VBTErrorCodeTexts = ARRAY VBT.ErrorCode OF TEXT { "event not current", "timeout", "uninstalled", "unreadable", "unwritable", "unowned selection", "wrong type"}; (* \subsubsection {Cursor-motion} *) PROCEDURE ToPrevChar (v: T); PROCEDURE ToNextChar (v: T); (* Move cursor (type-in point, caret) left or right one char. *) PROCEDURE ToStartOfLine (v: T); PROCEDURE ToEndOfLine (v: T); (* Move cursor to start or end of line. *) PROCEDURE ToOtherEnd (v: T); (* Move cursor to other end of the primary selection. *) PROCEDURE FindNextWord (v: T): TextPort.Extent; (* Locate the ``next'' word: from the current position, we scan right until we reach an alphanumeric character. Then we continue scanning right until we reach the first non-alphanumeric character; that position defines the right end of the extent. Then we scan left until we find a non-alphanumeric character. That position, plus 1, defines the left end of the extent. If the initial position is in the middle of a word, then the extent actually covers the {\it current} word, but on successive calls, it covers each following word in turn. *) PROCEDURE FindPrevWord (v: T): TextPort.Extent; (* Locate the ``previous'' word. This is the same as "ToNextWord", except that all the scanning directions are reversed. *) PROCEDURE UpOneLine (v: T); PROCEDURE DownOneLine(v: T); (* Move cursor up or down one line. *) (* \subsubsection {Deletion commands} All these procedures return an "Extent" indicating the range of characters that were deleted, or "TextPort.NotFound" if no characters were deleted. *) PROCEDURE DeletePrevChar (v: T): TextPort.Extent; PROCEDURE DeleteNextChar (v: T): TextPort.Extent; PROCEDURE DeleteToEndOfWord (v: T): TextPort.Extent; (* Delete from the current position to the end of the ``next'' word (as defined in "ToNextWord"). *) PROCEDURE DeleteToStartOfWord (v: T): TextPort.Extent; (* Delete from the current position to the start of the ``previous'' word (as defined in "ToPrevWord"). *) PROCEDURE DeleteToStartOfLine (v: T): TextPort.Extent; (* Delete to start of line, or delete the preceding newline if the cursor is at the start of line. *) PROCEDURE DeleteToEndOfLine (v: T): TextPort.Extent; (* Delete to end of line. If cursor is at the end, delete the newline. *) PROCEDURE DeleteCurrentWord (v: T): TextPort.Extent; (* Delete the word containing the cursor. *) PROCEDURE DeleteCurrentLine (v: T): TextPort.Extent; (* Delete line containing the cursor. *) (* \subsubsection {Other modification commands} *) PROCEDURE SwapChars(v: T); (* Swap the two characters to the left of the cursor. *) PROCEDURE InsertNewline(v: T); (* Insert a newline without moving the cursor. *) (* \subsubsection {Searching} *) TYPE Direction = {Forward, Backward}; Where = {Here, Beginning}; PROCEDURE Find (v : T; pattern : TEXT; direction := Direction.Forward; fromWhere := Where.Here; ignoreCase := TRUE ): TextPort.Extent; (* Search for a pattern. The search proceeds either forward or backward ("direction") from either the current location or the beginning of the buffer ("fromWhere"). If "ignoreCase" is "TRUE", the case of letters is not significant in the search. *) (* \subsubsection {Scrolling the display} *) PROCEDURE ScrollOneLineUp (v: T); PROCEDURE ScrollOneLineDown (v: T); PROCEDURE ScrollOneScreenUp (v: T); PROCEDURE ScrollOneScreenDown (v: T); (* Move the displayed text up or down by either a line or screen. This doesn't move the selections or cursor, so the "TextPort" may not be normalized when done. A ``screen'' contains "MAX(1, n-2)" lines, where "n" is the number of diplayed lines. *) (* \subsubsection {Managing the ``Undo'' stack} *) (* The ``Undo'' stack records all the editing changes made to the "TextPort". These changes can be undone; once undone, they can be redone. There is no built-in limit to the number of changes that are recorded. A sequence of insertions of graphic characters (i.e., plain typing) counts as one ``edit''. *) PROCEDURE AddToUndo (v: T; begin, end: CARDINAL; newText: TEXT); <* LL = v.mu *> (* This is called by "v.unsafeReplace(begin, end, newText)" to record a change to the underlying text. *) PROCEDURE Undo (v: T); <* LL = v.mu *> (* Reverse the effect of the last editing command. *) PROCEDURE Redo (v: T); <* LL = v.mu *> (* Reinstate the effect of the last editing command. *) PROCEDURE ResetUndo (v: T); <* LL < v.mu *> (* Clear the ``Undo'' stack. (Nothing in the implementation calls this procedure.) *) PROCEDURE UndoCount (v: T): CARDINAL; <* LL < v.mu *> (* Return the number of changes that can be undone. *) PROCEDURE RedoCount (v: T): CARDINAL; <* LL < v.mu *> (* Return the number of undone changes that can be redone. *) END TextPortClass.