DIRECTORY ImplErrors USING [UserErrorQuery], InputFocus USING [GetInputFocus, SetInputFocus], Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuProc], MessageWindow USING [Append, Blink], Process USING [Detach, EnableAborts, MsecToTicks, SecondsToTicks, SetTimeout, Ticks], Rope USING [Concat, Fetch, FromProc, Length, ROPE, Size, Substr], RopeEdit USING [Concat, InsertChar], TextEdit USING [DeleteText, DocFromNode, FromRope, InsertRope, InsertString, MaxOffset, Size], TextLooks USING [Looks, LooksToRope, noLooks], TextNode USING [FirstChild, LastLocWithin, Location, NarrowToTextNode, Offset, pZone, Ref, RefTextNode, StepForward], TEditCompile USING [minAvgLineLeading], TEditDocument USING [LineTable, LineTableRec, RecordViewerForRoot, Selection, SelectionRec, SpinAndLock, TEditDocumentData, TEditDocumentDataRec, TSInfoRec, ttyChars, Unlock], TEditImpl, -- exports TEditInput USING [currentEvent, BadMouse, CommandProc, DontDoIt, FreeTree, InterpretAtom, Register, ResetInputStuff, SaveCoords], TEditInputOps, -- USING Lots TEditLocks USING [Lock, LockRef, Unlock], TEditProfile USING [editTypeScripts], TEditRefresh USING [ScrollToEndOfDoc], TEditSelection, -- USING Lots TEditSplit USING [Split], TEditTouchup USING [LockAfterScroll, UnlockAfterRefresh], TIPUser USING [RegisterTIPPredicate, TIPPredicate, TIPScreenCoords, TIPTable], TypeScript, ViewerClasses USING [InitProc, NotifyProc, Viewer, ViewerClass, ViewerClassRec, ViewerRec], ViewerOps USING [AddProp, CreateViewer, EnumerateChildren, FetchProp, FetchViewerClass, RegisterViewerClass, SetMenu], VirtualDesktops USING [EnumerateViewers]; TEditTypeScriptImpl: CEDAR MONITOR IMPORTS ImplErrors, InputFocus, Menus, MessageWindow, Process, Rope, RopeEdit, TextEdit, TextLooks, TextNode, TEditDocument, TEditImpl, TEditInput, TEditInputOps, TEditLocks, TEditProfile, TEditRefresh, TEditSelection, TEditSplit, TEditTouchup, TIPUser, ViewerOps, VirtualDesktops EXPORTS TypeScript, TEditImpl SHARES Rope, ViewerClasses = BEGIN OPEN TEditDocument, TypeScript, TEditImpl; Create: PUBLIC PROC [info: ViewerClasses.ViewerRec, paint: BOOL _ TRUE] RETURNS [ts: TS] = BEGIN OPEN TEditDocument; tdd: TEditDocumentData _ NewData[]; info.data _ tdd; ts _ ViewerOps.CreateViewer[$Typescript, info, paint]; END; NewData: PROC [self: ViewerClasses.Viewer _ NIL] RETURNS [tdd: TEditDocumentData] = BEGIN tdd _ NEW[TEditDocumentDataRec]; [] _ SpinAndLock[tdd, "TEditTypeScriptImplNewData"]; tdd.lineTable _ NEW[LineTableRec[MAX[2, (IF self=NIL THEN 0 ELSE (self.ch/TEditCompile.minAvgLineLeading))+1]] _ [lastLine: 0, lastY: 0, lines: NULL]]; tdd.tsInfo _ NEW[TSInfoRec]; tdd.text _ TextNode.NarrowToTextNode[TextEdit.DocFromNode[TextEdit.FromRope[""]]]; Unlock[tdd]; TRUSTED {Process.EnableAborts[@tdd.tsInfo.iIncr]}; TRUSTED {Process.SetTimeout[@tdd.tsInfo.iIncr, Process.SecondsToTicks[10]]}; -- so can test if destroyed END; InitTypeScriptDocument: ViewerClasses.InitProc = BEGIN OPEN TEditDocument; tdd: TEditDocumentData; InitTddText: PROC = { IF tdd.text # NIL THEN TEditInput.FreeTree[tdd.text]; tdd.text _ TextNode.NarrowToTextNode[ TextEdit.DocFromNode[TextEdit.FromRope[""]]] }; InitLineTable: PROC = { tdd.lineTable.lastLine _ 0; tdd.lineTable[0].pos _ [TextNode.NarrowToTextNode[TextNode.FirstChild[tdd.text]], 0] }; IF InputFocus.GetInputFocus[].owner=self THEN InputFocus.SetInputFocus[]; IF self.link#NIL THEN BEGIN otherInit: ViewerClasses.Viewer _ NIL; otherTdd: TEditDocumentData; tdd _ NARROW[self.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd, "InitTypeScriptDocument"]; FOR v: ViewerClasses.Viewer _ self.link, v.link UNTIL v=self DO IF ~v.newVersion THEN {otherInit _ v; EXIT}; ENDLOOP; IF otherInit=NIL OR (otherTdd _ NARROW[otherInit.data]) = NIL THEN InitTddText[] -- we're first ELSE BEGIN -- somebody else already did the init tdd.text _ otherTdd.text; END; InitLineTable[]; END ELSE IF self.data=NIL THEN { -- first time we've seen this viewer self.data _ tdd _ (IF self.parent=NIL THEN NewData[] ELSE NewData[self]); IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd, "InitTypeScriptDocument"] } ELSE BEGIN -- old viewer getting re-initialised tdd _ NARROW[self.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd, "InitTypeScriptDocument"]; InitTddText[]; InitLineTable[]; END; IF self.column#static AND self.parent=NIL THEN ViewerOps.SetMenu[self, typescriptMenu, FALSE]; TEditDocument.RecordViewerForRoot[self,tdd.text]; Unlock[tdd]; END; ------------------ TTY PUT ROUTINES ------------------ aLittleWhile: Process.Ticks = Process.MsecToTicks[50]; untilTimesOutInALittleWhile: CONDITION; PutChar: PUBLIC PROC [ts: TS, char: CHARACTER] = { IF char=1C THEN BackSpace[ts] ELSE PutCharEntry[ts, char] }; PutCharEntry: ENTRY PROC [ts: TS, char: CHARACTER] = BEGIN ENABLE UNWIND => NULL; -- release lock count: INTEGER _ 0; IF (editRepaintProcess#NIL AND currentTS#ts) THEN -- wait to flush buffer WHILE editRepaintProcess#NIL DO WAIT repaintDone; ENDLOOP; currentTS _ ts; WHILE inputBuffer.length>=bufferMaxlen DO IF (count _ count+1) > 10 THEN { -- waited long enough i: CARDINAL _ 0; Char: PROC RETURNS [c: CHAR] = { c _ inputBuffer[i]; i _ i+1 }; rope: Rope.ROPE _ Rope.FromProc[inputBuffer.length, Char]; overflowRope _ Rope.Concat[overflowRope, rope]; inputBuffer.length _ 0; EXIT }; BROADCAST untilTimesOutInALittleWhile; -- wake up the repaint process WAIT bufferClear; ENDLOOP; inputBuffer[inputBuffer.length] _ char; inputBuffer.length _ inputBuffer.length + 1; IF editRepaintProcess=NIL THEN TRUSTED {Process.Detach[editRepaintProcess _ FORK Repaint[ts]]}; END; BackSpace: PUBLIC ENTRY PROC [ts: TS, count: INT _ 1] = BEGIN OPEN TEditSelection; ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; root: TextNode.Ref; selLock: BOOL; lockRef: TEditLocks.LockRef; Cleanup: PROC = { IF lockRef # NIL THEN { TEditLocks.Unlock[root]; lockRef _ NIL }; IF selLock THEN TEditSelection.UnlockSel[primary] }; IF tdd = NIL THEN RETURN; root _ tdd.text; BEGIN ENABLE UNWIND => Cleanup; flush: TextNode.Location; node: TextNode.RefTextNode; IF count <= 0 THEN RETURN; IF tdd.tsInfo=NIL THEN RETURN; -- not a typescript WHILE editRepaintProcess#NIL DO WAIT repaintDone; ENDLOOP; TEditSelection.LockSel[primary, "TEditTypeScriptImplBackSpace"]; IF NOT (selLock _ TEditSelection.SelectionRoot[pSel]=root) THEN TEditSelection.UnlockSel[primary]; lockRef _ TEditLocks.Lock[root, "TEditTypeScriptImplBackSpace"]; flush _ TextNode.LastLocWithin[root]; IF (node _ TextNode.NarrowToTextNode[flush.node])=NIL THEN GOTO Bad; IF (count _ MIN[count,flush.where]) <= 0 THEN GOTO Bad; flush.where _ flush.where-count; TextEdit.DeleteText[root, node, flush.where, count, TEditInput.currentEvent]; IF selLock THEN FixPSel[ts, [flush.node, flush.where+count], flush]; Cleanup[]; EXITS Bad => { Cleanup[]; TEditInputOps.EditFailed[] }; END END; PutRope: PUBLIC PROC [ts: TS, rope: Rope.ROPE] = BEGIN IF rope#NIL THEN FOR n: LONG INTEGER IN [0..Rope.Length[rope]) DO PutChar[ts, Rope.Fetch[rope, n]]; ENDLOOP; END; PutText: PUBLIC PROC [ts: TS, text: REF READONLY TEXT, start: INTEGER _ 0, stopPlusOne: INTEGER _ LAST[INTEGER]] = BEGIN IF text#NIL THEN FOR n: INTEGER IN [start..MIN[text.length, stopPlusOne]) DO PutChar[ts, text[n]]; ENDLOOP; END; ChangeLooks: PUBLIC ENTRY PROC [ts: TS, look: CHAR] = { ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; IF tdd = NIL THEN RETURN; IF tdd.tsInfo=NIL THEN RETURN; -- not a typescript WHILE editRepaintProcess#NIL DO WAIT repaintDone; ENDLOOP; SELECT look FROM IN ['a..'z] => tdd.tsInfo.looks[look] _ TRUE; IN ['A..'Z] => tdd.tsInfo.looks[look] _ FALSE; = ' => tdd.tsInfo.looks _ TextLooks.noLooks; -- blank means reset ENDCASE }; AddLooks: PUBLIC ENTRY PROC [ts: TS, look: CHAR] = { ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; IF tdd = NIL THEN RETURN; IF tdd.tsInfo=NIL THEN RETURN; -- not a typescript IF look NOT IN ['a..'z] THEN { IF look = ' THEN tdd.tsInfo.looks _ TextLooks.noLooks; -- blank means reset RETURN }; WHILE editRepaintProcess#NIL DO WAIT repaintDone; ENDLOOP; tdd.tsInfo.looks[look] _ TRUE }; RemoveLooks: PUBLIC ENTRY PROC [ts: TS, look: CHAR] = { ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; IF tdd = NIL THEN RETURN; IF tdd.tsInfo=NIL THEN RETURN; -- not a typescript IF look NOT IN ['a..'z] THEN RETURN; WHILE editRepaintProcess#NIL DO WAIT repaintDone; ENDLOOP; tdd.tsInfo.looks[look] _ FALSE }; ClearLooks: PUBLIC ENTRY PROC [ts: TS] = { ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; IF tdd = NIL THEN RETURN; WHILE editRepaintProcess#NIL DO WAIT repaintDone; ENDLOOP; IF tdd.tsInfo=NIL THEN RETURN; -- not a typescript tdd.tsInfo.looks _ TextLooks.noLooks }; GetLooks: PUBLIC ENTRY PROC [ts: TS] RETURNS [looks: Rope.ROPE] = { ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; IF tdd = NIL THEN RETURN; IF tdd.tsInfo=NIL THEN RETURN; -- not a typescript RETURN [TextLooks.LooksToRope[tdd.tsInfo.looks]] }; Flush: PUBLIC ENTRY PROC [ts: TS] = { ENABLE UNWIND => NULL; -- release lock IF ts # currentTS THEN RETURN; WHILE editRepaintProcess#NIL DO WAIT repaintDone; ENDLOOP }; ------------------ BACKGROUND UPDATES ------------------ editRepaintProcess: PROCESS _ NIL; repaintDone: CONDITION; bufferClear: CONDITION; bufferMaxlen: CARDINAL = 64; inputBuffer: REF TEXT _ NEW[TEXT[bufferMaxlen]]; overflowRope: Rope.ROPE; currentTS: TS _ NIL; RepaintDone: ENTRY PROC = { BROADCAST repaintDone }; Repaint: PROC [ts: TS] = BEGIN tdd: TEditDocumentData; root: TextNode.Ref; pos: TextNode.Location; lockRef: TEditLocks.LockRef; selLock, continue: BOOL _ FALSE; CheckForAutoScroll: PROC [ts: TS] = { prop: REF BOOL; tdd: TEditDocumentData _ NARROW[ts.data]; PosIsVisible: PROC [] RETURNS [BOOL] = { lines: LineTable = tdd.lineTable; IF lines[lines.lastLine].pos.where+lines[lines.lastLine].nChars >= pos.where THEN RETURN [TRUE]; RETURN [FALSE] }; IF tdd = NIL THEN RETURN; IF ~TEditTouchup.LockAfterScroll[tdd, "TEditTypeScriptImplRepaint"] THEN RETURN; { ENABLE UNWIND => TEditTouchup.UnlockAfterRefresh[tdd]; IF (prop _ NARROW[ViewerOps.FetchProp[ts, $AutoScrollTypescript]]) = NIL THEN ViewerOps.AddProp[ts, $AutoScrollTypescript, prop _ TextNode.pZone.NEW[BOOL]]; prop^ _ PosIsVisible[] }; TEditTouchup.UnlockAfterRefresh[tdd] }; Cleanup: PROC = { IF lockRef # NIL THEN TEditLocks.Unlock[root]; lockRef _ NIL; IF selLock THEN TEditSelection.UnlockSel[primary]; selLock _ FALSE }; DoAutoScroll: PROC [ts: TS] = { prop: REF BOOL = NARROW[ViewerOps.FetchProp[ts, $AutoScrollTypescript]]; IF prop#NIL AND prop^ THEN TEditRefresh.ScrollToEndOfDoc[ts, TRUE] }; WaitForMoreInput: ENTRY PROC RETURNS [BOOL] = { ENABLE UNWIND => NULL; IF overflowRope=NIL AND inputBuffer.length Cleanup; ABORTED => GOTO Quit; ANY => IF ImplErrors.UserErrorQuery[] THEN CONTINUE; END; tdd _ NARROW[ts.data]; IF tdd = NIL THEN RETURN; IF (root _ tdd.text)=NIL THEN { RepaintDone; RETURN }; lockRef _ TEditLocks.Lock[root, "TEditTypeScriptImplRepaint", read]; pos _ TextNode.LastLocWithin[root]; CheckForAutoScroll[ts]; IF ts.link # NIL THEN FOR v: ViewerClasses.Viewer _ ts.link, v.link UNTIL v=ts DO CheckForAutoScroll[v]; ENDLOOP; TEditLocks.Unlock[root]; lockRef _ NIL; DO TEditSelection.LockSel[primary, "TEditTypeScriptImplRepaint"]; IF NOT (selLock _ TEditSelection.SelectionRoot[TEditSelection.pSel]=root) THEN TEditSelection.UnlockSel[primary]; lockRef _ TEditLocks.Lock[root, "TEditTypeScriptImplRepaint"]; continue _ MakeEdits[ts, selLock]; Cleanup; DoAutoScroll[ts]; IF ts.link # NIL THEN FOR v: ViewerClasses.Viewer _ ts.link, v.link UNTIL v=ts DO DoAutoScroll[v]; ENDLOOP; IF ~continue OR ~WaitForMoreInput[] THEN EXIT; ENDLOOP; RepaintDone; EXITS Quit => { Cleanup; RepaintDone }; END END; updateSel: Selection _ NEW[SelectionRec]; tsMaxSize: INT _ 200000; MakeEdits: ENTRY PROC [ts: TS, selLock: BOOL] RETURNS [continue: BOOL] = BEGIN OPEN TEditSelection; ENABLE UNWIND => NULL; tdd: TEditDocumentData = NARROW[ts.data]; node: TextNode.RefTextNode; pos: TextNode.Location; IF tdd=NIL THEN {overflowRope _ NIL; inputBuffer.length _ 0; editRepaintProcess _ NIL; RETURN [FALSE]}; IF overflowRope=NIL AND inputBuffer.length=0 THEN {editRepaintProcess _ NIL; RETURN [FALSE]}; pos _ TextNode.LastLocWithin[tdd.text]; node _ TextNode.NarrowToTextNode[pos.node]; IF overflowRope#NIL THEN [] _ TextEdit.InsertRope[ root: tdd.text, dest: node, rope: overflowRope, destLoc: TextEdit.MaxOffset, inherit: FALSE, looks: tdd.tsInfo.looks, event: TEditInput.currentEvent]; [] _ TextEdit.InsertString[ root: tdd.text, dest: node, inherit: FALSE, looks: tdd.tsInfo.looks, string: inputBuffer, destLoc: TextEdit.MaxOffset]; IF Rope.Size[node.rope] > tsMaxSize THEN { -- truncate the typescript half: TextNode.Offset _ tsMaxSize; head, prefix: Rope.ROPE; Reset: PROC [ts: TS] = { tdd: TEditDocumentData = NARROW[ts.data]; IF tdd = NIL THEN RETURN; tdd.lineTable[0].pos _ [node,0]; tdd.lineTable[0].valid _ FALSE }; FOR i: TextNode.Offset _ half, i-1 DO -- back up to line break IF i < tsMaxSize-100 OR Rope.Fetch[node.rope,i-1] = 15C THEN { half _ i; EXIT }; ENDLOOP; head _ Rope.Substr[node.rope,0,half]; prefix _ "*** Typescript Truncated ***\n\n"; TextEdit.DeleteText[root: tdd.text, text: node, start: 0, len: half]; [] _ TextEdit.InsertRope[root: tdd.text, dest: node, destLoc: 0, rope: prefix, inherit: FALSE]; Reset[ts]; IF ts.link # NIL THEN FOR linked: TS _ ts.link, linked.link UNTIL linked=ts DO Reset[linked]; ENDLOOP; }; IF selLock THEN FixPSel[ts, pos, TextNode.LastLocWithin[tdd.text]]; inputBuffer.length _ 0; overflowRope _ NIL; BROADCAST bufferClear; RETURN [TRUE]; END; FixPSel: PROC [ts: TS, pos, newPos: TextNode.Location] = { OPEN TEditSelection; FixSel: PROC = { tSel: Selection _ Alloc[]; Copy[source: pSel, dest: tSel]; TEditSelection.MakePointSelection[tSel, newPos]; TEditSelection.SetSelLooks[pSel]; Free[tSel] }; IF pSel.granularity=point AND pSel.end.pos.where >= pos.where THEN IF ts=pSel.viewer THEN FixSel[] ELSE IF ts.link#NIL THEN FOR v: TS _ ts.link, v.link UNTIL v=ts DO IF v=pSel.viewer THEN { FixSel[]; EXIT }; ENDLOOP }; ------------------ KEYBOARD INPUT ------------------ CaretAtEnd: PUBLIC PROC [sel: Selection] RETURNS [yes: BOOL] = { root: TextNode.Ref = TEditSelection.SelectionRoot[sel]; IF root=NIL THEN RETURN [FALSE]; -- not a valid selection IF sel.granularity # point THEN RETURN [FALSE]; -- not a point selection [] _ TEditLocks.Lock[root, "TEditTypeScriptImplCaretAtEnd", read]; { caret: TextNode.Location = TEditSelection.InsertionPoint[sel]; node: TextNode.Ref = caret.node; IF node=NIL OR TextNode.StepForward[node] # NIL THEN yes _ FALSE ELSE IF caret.where # TextEdit.Size[TextNode.NarrowToTextNode[node]] THEN yes _ FALSE ELSE yes _ TRUE; TEditLocks.Unlock[root] }}; TypeScriptNotifyProc: ViewerClasses.NotifyProc = BEGIN IF TEditProfile.editTypeScripts THEN { tdd: TEditDocumentData = NARROW[self.data]; IF tdd = NIL THEN RETURN; IF TEditSelection.SelectionRoot[TEditSelection.pSel]=tdd.text AND ~CaretAtEnd[TEditSelection.pSel] THEN { TEditImpl.TEditNotifyProc[self, input]; RETURN }}; TEditInput.ResetInputStuff; FOR params: LIST OF REF ANY _ input, params.rest UNTIL params=NIL DO WITH params.first SELECT FROM z: REF CHARACTER => {ForceInsertSel[self]; InputChar[self, z^]}; z: ATOM => { Flush[self]; InterpretAtom[self, z ! TEditInput.DontDoIt, TEditInput.BadMouse => EXIT] }; z: Rope.ROPE => {ForceInsertSel[self]; InputRope[self, z] }; z: REF INT => { tdd: TEditDocumentData = NARROW[self.data]; IF tdd # NIL THEN tdd.tsInfo.intParam _ z^ }; z: REF TEXT => {ForceInsertSel[self]; FOR n: CARDINAL IN [0..z.length) DO InputChar[self, z[n]]; ENDLOOP}; z: TIPUser.TIPScreenCoords => TEditInput.SaveCoords[z.mouseX, self.ch-z.mouseY]; ENDCASE => { MessageWindow.Append["Unknown input given to Tioga typescript interpreter.", TRUE]; MessageWindow.Blink[] }; ENDLOOP; END; ForceInsertSel: PROC [ts: TS] = BEGIN OPEN TEditSelection; IF pSel.viewer#ts OR (pSel.granularity=point AND pSel.insertion=before) THEN RETURN; LockSel[primary, "TEditTypeScriptForceInsertSel"]; BEGIN ENABLE UNWIND => UnlockSel[primary]; IF pSel.viewer=ts AND (pSel.granularity#point OR pSel.insertion#before) THEN BEGIN tSel: Selection _ Alloc[]; Copy[source: pSel, dest: tSel]; tSel.insertion _ before; tSel.granularity _ point; tSel.start.pos _ tSel.end.pos _ TextNode.LastLocWithin[tSel.data.text]; MakeSelection[new: tSel]; Free[tSel]; END; UnlockSel[primary]; END END; InterpretAtom: PROCEDURE [viewer: ViewerClasses.Viewer, atom: ATOM] = BEGIN OPEN TEditInputOps, TEditSelection; SELECT atom FROM $Abort => SetUserAbort[viewer]; $ApplyCaretLook, $ApplyLook, $RemoveCaretLook, $RemoveLook => { tdd: TEditDocumentData = NARROW[viewer.data]; IF tdd = NIL THEN RETURN; TEditImpl.TEditNotifyProc[viewer, TextNode.pZone.LIST[TextNode.pZone.NEW[INT _ tdd.tsInfo.intParam]]]; TEditInput.InterpretAtom[viewer,atom] }; $BackSpace => {ForceInsertSel[viewer]; InputChar[viewer, 1C]}; -- control A $BackWord => {ForceInsertSel[viewer]; InputChar[viewer, 27C]}; -- control W $ClearTypeScriptLooks => ClearLooks[viewer]; $Delete => {ForceInsertSel[viewer]; InputChar[viewer, 177C]}; -- DEL $Paste => {ForceInsertSel[viewer]; TEditInput.InterpretAtom[viewer,atom]}; ENDCASE => TEditInput.InterpretAtom[viewer,atom]; END; NumberToLook: PROC [viewer: ViewerClasses.Viewer] RETURNS [l: CHAR] = { tdd: TEditDocumentData = NARROW[viewer.data]; IF tdd = NIL THEN RETURN['z]; RETURN['a+tdd.tsInfo.intParam] }; ApplyTypeScriptLook: TEditInput.CommandProc = { WaitUntilIdle[viewer]; AddLooks[viewer, NumberToLook[viewer]] }; RemoveTypeScriptLook: TEditInput.CommandProc = { WaitUntilIdle[viewer]; RemoveLooks[viewer, NumberToLook[viewer]] }; InsertRopeAtFrontOfBuffer: PUBLIC ENTRY PROC [ts: TS, rope: Rope.ROPE] = BEGIN ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; IF tdd # NIL THEN {OPEN tdd.tsInfo; inputRope _ RopeEdit.Concat[rope, Rope.Substr[inputRope, inputLoc]]; inputLoc _ 0; BROADCAST iIncr; }; END; InsertCharAtFrontOfBuffer: PUBLIC ENTRY PROC [ts: TS, char: CHARACTER] = BEGIN ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; IF tdd # NIL THEN {OPEN tdd.tsInfo; inputRope _ RopeEdit.InsertChar[Rope.Substr[inputRope, inputLoc], char]; inputLoc _ 0; BROADCAST iIncr; }; END; FlushInputChars: INTERNAL PROC [tdd: TEditDocumentData] = { OPEN tdd.tsInfo; num: INT = IF iQp > oQp THEN iQp-oQp ELSE ttyChars-iQp+oQp; Char: PROC RETURNS [c: CHAR] = { c _ input[oQp]; oQp _ (oQp+1) MOD ttyChars }; rope: Rope.ROPE; rope _ Rope.FromProc[num, Char]; inputRope _ Rope.Concat[inputRope, rope]; iQp _ oQp _ 0 }; InputRope: ENTRY PROC [ts: TS, rope: Rope.ROPE] = BEGIN ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; IF tdd # NIL THEN {OPEN tdd.tsInfo; IF iQp # oQp THEN FlushInputChars[tdd]; inputRope _ RopeEdit.Concat[inputRope, rope]; BROADCAST iIncr; }; END; InputChar: ENTRY PROC [ts: TS, char: CHARACTER] = BEGIN ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; IF tdd # NIL THEN {OPEN tdd.tsInfo; newiQp: INTEGER = (iQp+1) MOD ttyChars; IF newiQp = oQp THEN FlushInputChars[tdd]; input[iQp] _ char; iQp _ newiQp; BROADCAST iIncr; }; END; ------------------ TTY GET ROUTINES ------------------ GetChar: PUBLIC ENTRY PROC [ts: TS] RETURNS [char: CHARACTER] = BEGIN ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; size: INT; IF tdd # NIL THEN {OPEN tdd.tsInfo; WHILE inputLoc >= (size _ Rope.Size[inputRope]) AND iQp = oQp DO waitingInGetChar _ TRUE; WAIT iIncr; waitingInGetChar _ FALSE; IF ts.destroyed THEN RETURN WITH ERROR ABORTED; ENDLOOP; IF inputLoc < size THEN { -- get char from rope char _ Rope.Fetch[inputRope, inputLoc]; IF (inputLoc _ inputLoc+1)=size THEN { -- have finished this rope inputLoc _ 0; inputRope _ NIL }} ELSE { -- get from buffer char _ input[oQp]; oQp _ (oQp+1) MOD ttyChars }; }; END; CharsAvailable: PUBLIC ENTRY PROC [ts: TS] RETURNS [BOOL] = BEGIN ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; IF tdd = NIL THEN RETURN [FALSE] ELSE {OPEN tdd.tsInfo; IF tdd.tsInfo=NIL THEN RETURN [FALSE]; -- not a typescript RETURN[inputLoc < Rope.Size[inputRope] OR iQp#oQp]; }; END; WaitUntilCharsAvail: PUBLIC ENTRY PROC [ts: TS] = BEGIN ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; IF tdd # NIL THEN {OPEN tdd.tsInfo; IF tdd.tsInfo=NIL THEN RETURN; -- not a typescript WHILE inputLoc >= Rope.Size[inputRope] AND iQp = oQp DO waitingInGetChar _ TRUE; WAIT iIncr; waitingInGetChar _ FALSE; IF ts.destroyed THEN RETURN WITH ERROR ABORTED; ENDLOOP; }; END; WaitUntilIdle: PUBLIC ENTRY PROC [ts: TS] = BEGIN ENABLE UNWIND => NULL; -- release lock tdd: TEditDocumentData = NARROW[ts.data]; IF tdd # NIL THEN {OPEN tdd.tsInfo; IF tdd.tsInfo=NIL THEN RETURN; -- not a typescript WHILE inputLoc < Rope.Size[inputRope] OR iQp#oQp OR ~waitingInGetChar DO WAIT untilTimesOutInALittleWhile; ENDLOOP; }; END; ------------------ Tip Table ------------------ typeScriptTIP: PUBLIC TIPUser.TIPTable; -- init below ReloadTypeScriptTipTable: PUBLIC PROC = BEGIN newTIP: TIPUser.TIPTable _ ReloadTable[typeScriptTIP, "TypeScriptTIP", IF TEditProfile.editTypeScripts THEN "/Indigo/Tioga/TEdit/EditTypeScript.tip /Indigo/Tioga/TEdit/Tioga.tip" ELSE "/Indigo/Tioga/TEdit/TypeScript.tip"]; IF newTIP # NIL THEN { changeTip: PROC [v: ViewerClasses.Viewer] RETURNS [BOOL _ TRUE] = { SELECT v.class.flavor FROM $Typescript => { tdd: TEditDocumentData _ NARROW[v.data]; v.tipTable _ typeScriptTIP }; $Container => ViewerOps.EnumerateChildren[v, changeTip]; ENDCASE; RETURN [TRUE] }; tsClass.tipTable _ typeScriptTIP _ newTIP; VirtualDesktops.EnumerateViewers[changeTip] } END; CaretAtEndOfTypescript: TIPUser.TIPPredicate --PROC RETURNS [BOOLEAN]-- = { tdd: TEditDocumentData; ts: TS _ TEditSelection.pSel.viewer; IF ts=NIL THEN RETURN [FALSE]; -- no primary selection tdd _ NARROW[ts.data]; IF tdd = NIL THEN RETURN [FALSE]; IF tdd.tsInfo=NIL THEN RETURN [FALSE]; -- not a typescript RETURN [CaretAtEnd[TEditSelection.pSel]] }; ------------------ USER ABORT ------------------ UserAbort: PUBLIC PROC [ts: TS] RETURNS [abort: BOOL] = BEGIN tdd: TEditDocumentData _ NARROW[ts.data]; IF tdd = NIL THEN RETURN; RETURN[tdd.tsInfo.abort]; END; ResetUserAbort: PUBLIC PROC [ts: TS] = BEGIN tdd: TEditDocumentData _ NARROW[ts.data]; IF tdd = NIL THEN RETURN; tdd.tsInfo.abort _ FALSE; END; SetUserAbort: PUBLIC PROC [ts: TS] = BEGIN tdd: TEditDocumentData _ NARROW[ts.data]; IF tdd = NIL THEN RETURN; tdd.tsInfo.abort _ TRUE; END; ------------------ TTY CLASS DEFN ------------------ typescriptMenu: Menus.Menu _ Menus.CreateMenu[]; Split: Menus.MenuProc = {TEditSplit.Split[NARROW[parent]]}; findNext: LIST OF REF ANY = LIST[$FindNext]; findPrev: LIST OF REF ANY = LIST[$FindPrev]; Find: Menus.MenuProc = {viewer: ViewerClasses.Viewer ~ NARROW[parent]; viewer.class.notify[viewer, IF mouseButton=red THEN findNext ELSE findPrev]}; tsClass: ViewerClasses.ViewerClass _ -- just like Tioga's NEW[ViewerClasses.ViewerClassRec _ ViewerOps.FetchViewerClass[$Text]^]; tsClass.init _ InitTypeScriptDocument; tsClass.notify _ TypeScriptNotifyProc; tsClass.icon _ typescript; ReloadTypeScriptTipTable[]; ViewerOps.RegisterViewerClass [$Typescript, tsClass]; TIPUser.RegisterTIPPredicate[$CaretAtEndOfTypescript, CaretAtEndOfTypescript]; TEditInput.Register[$ApplyTypeScriptLook, ApplyTypeScriptLook]; TEditInput.Register[$RemoveTypeScriptLook, RemoveTypeScriptLook]; Menus.AppendMenuEntry[typescriptMenu, Menus.CreateEntry["Find", Find]]; Menus.AppendMenuEntry[typescriptMenu, Menus.CreateEntry["Split", Split]]; TRUSTED {Process.SetTimeout[@untilTimesOutInALittleWhile, aLittleWhile]}; TRUSTED {Process.SetTimeout[@bufferClear, aLittleWhile]}; END. DefaultCharProc: CharProc = BEGIN SELECT char FROM 15C, 177C => RETURN [TRUE, TRUE]; ENDCASE => RETURN [TRUE, FALSE]; END; GetLine: PUBLIC PROC [ts: TS, actChar: BOOL _ FALSE, charProc: CharProc _ NIL] RETURNS [line: Rope.ROPE] = BEGIN process, activate: BOOL _ FALSE; l: Rope.Text _ NEW[Rope.TextRep[1000]]; char: CHARACTER; GetBiggerRope: PROC = BEGIN new: Rope.Text _ NEW[Rope.TextRep[2*Rope.Size[l]]]; FOR i:INT IN [0..l.length) DO new[i] _ l[i]; ENDLOOP; new.length _ l.length; l _ new; END; AppendChar: PROC = INLINE BEGIN IF l.length >= l.max THEN GetBiggerRope[]; TRUSTED {RopeInline.QStore[char, l, l.length]}; l.length _ l.length+1; END; l.length _ 0; IF charProc = NIL THEN charProc _ DefaultCharProc; UNTIL activate DO char _ GetChar[ts]; [process, activate] _ charProc[ts, char]; IF process THEN SELECT char FROM 177C => {l.length _ 0; PutRope[ts, " XXX\n"]}; 1C => IF l.length > 0 THEN BEGIN BackSpace[ts]; l.length _ l.length - 1; END; 27C => BEGIN nChars: INT _ 0; WHILE l.length>0 AND l[l.length-1]=' DO nChars _ nChars + 1; l.length _ l.length - 1; ENDLOOP; WHILE l.length>0 AND l[l.length-1]#' DO nChars _ nChars + 1; l.length _ l.length - 1; ENDLOOP; IF nChars > 0 THEN BackSpace[ts,nChars]; END; ENDCASE => {PutChar[ts, char]; IF ~activate OR actChar THEN AppendChar[]} ELSE IF ~activate OR actChar THEN AppendChar[]; ENDLOOP; RETURN [l]; END; \-- TEditTypeScriptImpl.mesa Last Edited by: Paxton, January 10, 1983 11:39 am Last Edited by: Plass, April 20, 1983 8:31 am -- make sure another link didn't already init -- and if so, copy that data see if pSel is in this typescript look char in 'a..'z means add that look; in 'A..'Z means remove; = blank means remove all looks Cannot make this an ENTRY procedure since must lock selection and document before enter the monitor. Else have deadlock with Copy to typescript which gets locks before calling InputRope. see if pSel is in this typescript need lock to synch with edits to typescript Caret in this typescript, but not at end. So treat like edit of normal Tioga doc. raise error if viewer destroyed. Timeout for condition is set above raise error if viewer destroyed. Timeout for condition is set above -- except for a couple of differences Κ σ– "Mesa" style˜JšΟc™JšΟk1™1J™-šž ˜ Jšœ žœ˜"Jšœ žœ ˜0Jšœžœ<˜GJšœžœ˜$JšœžœH˜UJšœžœ#žœ˜AJšœ žœ˜$Jšœ žœP˜^Jšœ žœ˜.Jšœ žœg˜uJšœ žœ˜'Jšœžœœ˜―Jšœ  ˜Jšœ žœq˜Jšœ ˜Jšœ žœ˜)Jšœ žœ˜%Jšœ žœ˜&Jšœ ˜Jšœ žœ ˜Jšœ žœ'˜9JšœžœA˜NJšœ ˜ JšœžœH˜[Jšœ žœg˜vJšœžœ˜)J˜—Jšœž ˜"J˜Jšžœ‘˜˜Jšžœ˜Jšžœ˜J˜Jšžœžœ&˜0J˜šΟnœžœžœ(žœžœžœžœ˜ZJšžœžœ˜J˜#J˜J˜6Jšžœ˜J˜—š Ÿœžœžœžœž˜YJšœžœ˜ J˜4šœžœžœ˜'š œžœžœžœžœ0˜HJšœžœ˜&——Jšœ žœ ˜J˜RJ˜ Jšžœ+˜2JšžœF˜hJšžœ˜J˜—šœ1žœžœ˜JJ˜J˜šŸ œžœ˜Jšžœ žœžœ˜5šœ%˜%J˜/——J˜šŸ œžœ˜J˜J˜WJ˜—Jšžœ'žœ˜Išžœ žœžœž˜Jš-™-Jš™Jšœ"žœ˜&Jšœ˜Jšœžœ ˜Jšžœžœžœžœ˜Jšœ0˜0šžœ-žœž˜?Jšžœžœžœ˜,Jšžœ˜—Jš žœ žœžœ žœžœžœ˜_šžœžœ%˜0J˜Jšžœ˜—Jšœ˜Jšž˜—š žœžœ žœžœ$˜AJš œžœ žœžœ žœ˜IJšžœžœžœžœ˜Jšœ1˜1—šžœžœ$˜/Jšœžœ ˜Jšžœžœžœžœ˜Jšœ0˜0Jšœ˜Jšœ˜Jšžœ˜—šžœžœ žœž˜.Jšœ(žœ˜/—J˜1J˜ Jšžœ˜J˜J˜—Jš6˜6J˜J˜6Jšœž œ˜'J˜š Ÿœžœžœžœž œ˜2Jšžœ žœžœ˜˜>Jš!™!šžœžœDž˜NJšœ"˜"—Jšœ>˜>Jšœ"˜"J˜J˜š žœ žœžœžœ+žœž˜QJšœž˜—Jšžœ žœžœžœ˜.Jšžœ˜—Jšœ ˜ Jšžœ"˜'Jšžœ˜J˜—Jšœžœ˜)J˜Jšœ žœ ˜J˜š Ÿ œžœžœžœ žœ˜-Jšžœ žœ˜Jšžœžœ˜Jšžœžœžœ˜Jšœžœ ˜)J˜Jšœ˜Jšžœžœžœžœ/žœžœžœ˜gJšžœžœžœžœžœžœžœ˜]Jšœ'˜'J˜+šžœžœž˜šœ˜Jšœ˜Jšœ0˜0Jšœ žœ˜(J˜ ——˜Jšœ%žœ˜DJ˜2—šžœ"žœ˜EJ˜"Jšœžœ˜šŸœžœžœ˜Jšœžœ ˜)Jšžœžœžœžœ˜J˜ Jšœžœ˜!—šžœ žœ˜>Jšžœžœ!žœ žœ˜PJšžœ˜—J˜%J˜,J˜EJšœXžœ˜_J˜ šžœ žœž˜Jš žœ žœžœ žœžœ˜P—J˜—Jšžœ žœ4˜CJšœ'žœ˜+Jšž œ ˜Jšžœžœ˜Jšžœ˜J˜—šŸœžœžœ&žœ˜OšŸœžœ˜Jšœ˜J˜Jšœ0˜0Jšœ!˜!Jšœ ˜ —šžœžœ!ž˜BJšžœžœ ˜šžœžœ žœžœžœžœžœž˜BJšžœžœ žœ˜)Jšžœ˜ ——J˜J˜—Jš4˜4J˜š Ÿ œžœžœžœžœ˜@J˜7Jš žœžœžœžœ˜9Jš žœžœžœžœ˜HšœB˜BJš+™+—J˜@J˜ Jš žœžœžœžœžœž˜@Jšžœžœ>žœž˜UJšžœžœ˜J˜—J˜šœ1ž˜6šžœžœ˜&Jšœžœ ˜+Jšžœžœžœžœ˜šžœ;˜=Jšžœ"žœ˜+J™RJšœ(žœ˜2——J˜šžœ žœžœžœžœžœžœž˜Dšžœžœž˜Jšœžœž œ0˜@šœžœ˜ J˜ JšœDžœ˜L—Jšœžœ0˜<šœžœžœ˜Jšœžœ ˜+Jšžœžœžœ˜-—šœžœžœ˜%Jš žœžœžœžœžœ˜D—J˜Pšžœ˜ JšœMžœ˜SJ˜——Jšžœ˜—Jšžœ˜J˜—š Ÿœžœžœžœžœ˜:Jš žœžœžœžœžœ˜TJšœ2˜2Jšžœžœžœ˜*š žœžœžœžœž˜RJšœ˜J˜J˜J˜J˜GJ˜Jšœ ž˜ Jšžœ˜—J˜Jšžœ˜J˜—šŸ œž œ&žœ˜EJšžœžœ˜)šžœž˜J˜šœ?˜?Jšœžœ˜-Jšžœžœžœžœ˜šœ!˜!Jšœžœžœžœ˜D—Jšœ(˜(—Jšœ? ˜KJšœ? ˜KJšœ,˜,Jšœ>˜DJ˜JJšžœ*˜1—Jšžœ˜J˜—šŸ œžœ žœžœ˜GJšœžœ˜-Jšžœžœžœžœ˜Jšžœ˜!—J˜šœ/˜/Jšœ@˜@J˜—šœ0˜0JšœC˜CJ˜—š Ÿœž œžœžœ žœž˜NJšžœžœžœ˜&Jšœžœ ˜)šžœžœžœžœ ˜#JšœD˜DJ˜ Jšž œ˜J˜—Jšžœ˜J˜—š Ÿœž œžœžœž œž˜NJšžœžœžœ˜&Jšœžœ ˜)šžœžœžœžœ ˜#JšœH˜HJ˜ Jšž œ˜J˜—Jšžœ˜J˜—šŸœžœžœžœ ˜LJš œžœžœ žœ žœ˜;šŸœžœžœžœ˜ Jšœžœ ˜-—Jšœ ž˜Jšœ ˜ Jšœ)˜)Jšœ˜J˜—š Ÿ œžœžœžœ žœž˜7Jšžœžœžœ˜&šœžœ ˜)Jšžœžœžœžœ ˜#Jšžœ žœ˜'Jšœ-˜-Jšž œ˜J˜—Jšžœ˜J˜—š Ÿ œžœžœžœž œž˜7Jšžœžœžœ˜&Jšœžœ ˜)šžœžœžœžœ ˜#Jšœžœ žœ ˜'Jšžœžœ˜*Jšœ ˜ Jšž œ˜J˜—Jšžœ˜J˜—Jš6˜6J˜šŸœžœžœžœžœžœž œž˜EJšžœžœžœ˜&Jšœžœ ˜)Jšœžœ˜ šžœžœžœžœ ˜#šžœ+žœ ž˜@Jšœžœ˜Jšžœ˜ Jšœžœ˜š žœžœžœžœžœžœ˜/JšœD™D—Jšžœ˜—šžœžœ˜/Jšœ'˜'šžœžœ˜AJšœžœ˜ ——šžœ˜Jšœ!žœ ˜0—J˜—Jšžœ˜J˜—šŸœžœžœžœžœžœžœž˜AJšžœžœžœ˜&Jšœžœ ˜)Jš žœžœžœžœžœ˜ šžœžœ ˜Jš žœ žœžœžœžœ˜:Jšžœ!žœ ˜3J˜—šžœ˜J˜——š Ÿœžœžœžœžœž˜7Jšžœžœžœ˜&Jšœžœ ˜)šžœžœžœžœ ˜#Jš žœ žœžœžœ˜2šžœ"žœ ž˜7Jšœžœ˜Jšžœ˜ Jšœžœ˜š žœžœžœžœžœžœ˜/JšœD™D—Jšžœ˜—J˜—šžœ˜J˜——š Ÿ œžœžœžœžœž˜1Jšžœžœžœ˜&Jšœžœ ˜)šžœžœžœžœ ˜#Jš žœ žœžœžœ˜2šžœ!žœ žœž˜HJšžœ˜!Jšžœ˜—J˜—šžœ˜J˜J˜——Jš/˜/J˜Jšœžœ ˜5J˜šŸœžœžœž˜-šœ˜šœ+˜+šžœž˜$JšœF˜F—Jšžœ'˜+——šžœ žœžœ˜š œ žœžœžœžœ˜Cšžœž˜˜Jšœžœ ˜(J˜—J˜8Jšžœ˜—Jšžœžœ˜—Jšœ*˜*J˜-—Jšžœ˜J˜—šœ-œ˜KJšœ˜Jšœžœ˜$Jš žœžœžœžœžœ˜6Jšœžœ ˜Jš žœžœžœžœžœ˜!Jš žœ žœžœžœžœ˜:Jšžœ%˜+J˜—Jš0˜0J˜š Ÿ œžœžœžœžœ žœž˜=Jšœžœ ˜)Jšžœžœžœžœ˜Jšžœ˜Jšžœ˜J˜—š Ÿœžœžœžœž˜,Jšœžœ ˜)Jšžœžœžœžœ˜Jšœžœ˜Jšžœ˜J˜—š Ÿ œžœžœžœž˜*Jšœžœ ˜)Jšžœžœžœžœ˜Jšœžœ˜Jšžœ˜J˜J˜—Jš4˜4J˜šœ0˜0J˜—Jšœ*žœ ˜;J˜Jš œ žœžœžœžœžœ ˜,Jš œ žœžœžœžœžœ ˜,šœ7žœ ˜FJšœžœžœ žœ ˜MJ˜—šœ%˜9JšžœD˜GJ˜—Jš%™%J˜J˜&J˜&J˜J˜J˜J˜5JšœN˜NJ˜Jšœ?˜?JšœA˜AJ˜JšœG˜GšœI˜IJ˜—JšžœB˜IJšžœ2˜9J˜Jšžœ˜J˜šœž˜!šžœž˜Jšœ žœžœžœ˜!Jšžœžœžœžœ˜!—Jšžœ˜J˜—šŸœžœžœžœ žœžœžœ˜NJšžœ žœž˜!Jšœžœžœ˜ Jšœžœ˜'Jšœž œ˜šŸ œžœž˜Jšœžœ˜3Jš žœžœžœžœžœ˜5J˜J˜Jšžœ˜—šŸ œžœžœž˜Jšžœžœ˜*Jšžœ(˜/J˜Jšžœ˜—J˜ Jšžœ žœžœ˜2šžœ ž˜J˜J˜)šžœ žœžœž˜ J˜.šœžœžœž˜ J˜J˜Jšžœ˜—šœž˜ Jšœžœ˜šžœ žœž˜(J˜J˜Jšžœ˜—šžœ žœž˜(J˜J˜Jšžœ˜—Jšžœ žœ˜(Jšžœ˜—Jšžœžœ žœ žœ˜I—Jšžœžœ žœ žœ˜/Jšžœ˜—Jšžœ˜ Jšžœ˜J˜——…—c܈+