DIRECTORY AMMiniModel USING [ImplementorName], BasicTime USING [GMT, nullGMT, Period], Convert USING [Error, IntFromRope], FS USING [ComponentPositions, Error, ExpandName, FileInfo, GetName, nullOpenFile, Open, OpenFile], Menus USING [Menu, MenuEntry, MenuProc, SetLine], MessageWindow USING [Append, Blink, Clear], NodeProps USING [GetProp, NullCopy, NullRead, NullWrite, PutProp, Register], Rope USING [Concat, Equal, Fetch, Flatten, Find, Match, ROPE, Size, SkipTo, Substr], TEditDisplay USING [EstablishLine], TEditDocument USING [maxClip, Selection, SpinAndLock, TEditDocumentData, Unlock], TEditDocumentPrivate USING [findMenu, FindUnsavedDocument, InitViewerDoc, InitViewerDocInternal, levelMenu, PositionHistory, RecordUnsavedDocument], TEditInput USING [FreeTree], TEditInputOps USING [WaitForInsertToFinish], TEditOps USING [FileNameProc], TEditProfile USING [DefaultMenuChoice, implExtensions, menu1, menu2, menu3, openFirstLevelOnly, sourceExtensions, tryVersionMap], TEditSelection USING [FindRope, fSel, LockSel, MakeSelection, pSel, sSel, UnlockSel], TEditSelectionOps USING [ShowGivenPosition], TextEdit USING [Size], TextNode USING [Location, LocNumber, LocWithin, NarrowToTextNode, nullLocation, Ref, RefTextNode, Root], VersionMap USING [MapList, Range, RangeList, RangeToEntry, ShortNameToRanges], VersionMapDefaults USING [GetMapList], ViewerClasses USING [Column, Viewer], ViewerForkers USING [CallBack, ForkCall, ForkPaint], ViewerGroupLocks USING [CallRootAndLinksUnderWriteLock], ViewerLocks USING [CallUnderColumnLocks], ViewerOps USING [AddProp, BlinkViewer, CloseViewer, ComputeColumn, CreateViewer, DestroyViewer, EnumerateViewers, EnumProc, EstablishViewerPosition, FetchProp, MoveBelowViewer, OpenIcon, PaintHint, PaintViewer, SaveViewer], ViewerPrivate USING [AcquireWriteLocks, ReleaseWriteLocks], ViewerTools USING [GetContents, GetSelectionContents, SelPos, SelPosRec, SetSelection], WorldVM USING [LocalWorld]; QueryTEditDocuments2Impl: CEDAR MONITOR IMPORTS AMMiniModel, BasicTime, Convert, FS, Menus, MessageWindow, NodeProps, Rope, TEditDocument, TEditDocumentPrivate, TextEdit, TextNode, TEditDisplay, TEditInput, TEditInputOps, TEditProfile, TEditSelection, TEditSelectionOps, VersionMap, VersionMapDefaults, ViewerForkers, ViewerGroupLocks, ViewerLocks, ViewerOps, ViewerPrivate, ViewerTools, WorldVM EXPORTS TEditDocument, TEditDocumentPrivate, TEditOps = BEGIN ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; Column: TYPE = ViewerClasses.Column; File: TYPE = FS.OpenFile; noFile: File = FS.nullOpenFile; initialCaret: ViewerTools.SelPos _ NEW[ViewerTools.SelPosRec _ []]; ColumnOf: PROC [parent: Viewer] RETURNS [Column] = { RETURN [IF parent # NIL THEN parent.column ELSE left] }; ForceInitialCaret: PROC [viewer: Viewer] = { ViewerTools.SetSelection[viewer, initialCaret]; }; lastRoot: TextNode.Ref; lastViewer: Viewer; GetViewerForRootI: INTERNAL PROC [root: TextNode.Ref] RETURNS [viewer: Viewer] = { IF root = NIL THEN RETURN [NIL]; IF root = lastRoot THEN RETURN [lastViewer]; lastRoot _ root; RETURN [lastViewer _ NARROW[NodeProps.GetProp[root,$Viewer]]]; }; RecordViewerForRootI: INTERNAL PROC [viewer: Viewer, root: TextNode.Ref] = { NodeProps.PutProp[root,$Viewer,viewer]; IF root = lastRoot THEN lastViewer _ viewer; -- keep the cache up to date }; GetViewerForRoot: PUBLIC ENTRY PROC [root: TextNode.Ref] RETURNS [viewer: Viewer] = { ENABLE UNWIND => NULL; RETURN [GetViewerForRootI[root]]; }; RecordViewerForRoot: PUBLIC ENTRY PROC [viewer: Viewer, root: TextNode.Ref] = { ENABLE UNWIND => NULL; RecordViewerForRootI[viewer, root]; }; ForgetViewer: PUBLIC ENTRY PROC [viewer: Viewer] = { ENABLE UNWIND => NULL; tdd: TEditDocument.TEditDocumentData = NARROW[viewer.data]; root: TextNode.Ref; IF tdd=NIL THEN RETURN; root _ tdd.text; IF GetViewerForRootI[root] # viewer THEN RETURN; IF viewer.link # NIL THEN { RecordViewerForRootI[viewer.link,root]; RETURN; }; RecordViewerForRootI[NIL,root]; }; LoadHistory: TYPE = RECORD[name: ROPE, place: INT]; CopyLoadHistory: PUBLIC PROC [from, to: Viewer] = { old: REF LoadHistory _ NARROW[ViewerOps.FetchProp[from, $LoadHistory]]; new: REF LoadHistory _ NARROW[ViewerOps.FetchProp[to, $LoadHistory]]; IF old=NIL THEN RETURN; IF new=NIL THEN { new _ NEW[LoadHistory]; ViewerOps.AddProp[to, $LoadHistory, new] }; new^ _ old^; }; AllocLoadHistory: PROC [viewer: Viewer] RETURNS [prop: REF LoadHistory] = { IF (prop _ NARROW[ViewerOps.FetchProp[viewer, $LoadHistory]]) # NIL THEN RETURN; prop _ NEW[LoadHistory]; ViewerOps.AddProp[viewer, $LoadHistory, prop]; }; SetLoadHistoryInfo: PROC [viewer: Viewer, prop: REF LoadHistory] = { tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; IF tdd = NIL THEN RETURN; prop.name _ viewer.name; prop.place _ TextNode.LocNumber[tdd.lineTable.lines[0].pos]; }; SetLoadHistory: PROC [parent, viewer: Viewer] = { prop: REF LoadHistory _ AllocLoadHistory[viewer]; SetLoadHistoryInfo[parent, prop]; }; SaveLoadHistory: PROC [viewer: Viewer] = { prop: REF LoadHistory _ AllocLoadHistory[viewer]; SetLoadHistoryInfo[viewer, prop]; }; PositionHistory: TYPE = TEditDocumentPrivate.PositionHistory; CopyPositionHistory: PUBLIC PROC [from, to: Viewer] = { old: REF PositionHistory _ NARROW[ViewerOps.FetchProp[from, $PositionHistory]]; new: REF PositionHistory _ NARROW[ViewerOps.FetchProp[to, $PositionHistory]]; IF old=NIL THEN RETURN; IF new=NIL THEN { new _ NEW[PositionHistory]; ViewerOps.AddProp[to, $PositionHistory, new]; }; new^ _ old^; }; ClearPositionHistory: PROC [viewer: Viewer] = { prop: REF PositionHistory _ NARROW[ViewerOps.FetchProp[viewer, $PositionHistory]]; IF prop = NIL THEN RETURN; prop.pos _ prop.prev _ TextNode.nullLocation; }; RememberCurrentPosition: PUBLIC PROC [viewer: Viewer] = { tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; prop: REF PositionHistory _ NARROW[ViewerOps.FetchProp[viewer, $PositionHistory]]; loc: TextNode.Location; IF tdd=NIL THEN RETURN; IF prop = NIL THEN { prop _ NEW[PositionHistory]; ViewerOps.AddProp[viewer, $PositionHistory, prop] }; [] _ TEditDocument.SpinAndLock[tdd, "RememberCurrentPosition"]; loc _ tdd.lineTable.lines[0].pos; TEditDocument.Unlock[tdd]; IF loc = prop.pos THEN RETURN; prop.prev _ prop.pos; prop.pos _ loc; }; PositionViewer: PUBLIC PROC [viewer: Viewer, loc: TextNode.Location, hint: ViewerOps.PaintHint _ client] RETURNS [ok: BOOL _ FALSE] = { ok _ PositionViewerInternal[viewer, loc]; IF ok THEN ForkViewerPainter[viewer, hint]; }; PositionViewerInternal: PROC [viewer: Viewer, loc: TextNode.Location] RETURNS [ok: BOOL _ FALSE] = { CheckPosition: PROC [viewer: Viewer, loc: TextNode.Location] RETURNS [good: BOOL, goodloc: TextNode.Location] = { root, node: TextNode.Ref; t1: TextNode.RefTextNode; tdd: TEditDocument.TEditDocumentData; IF viewer=NIL OR viewer.destroyed OR (node _ loc.node)=NIL THEN GOTO Failed; IF (tdd _ NARROW[viewer.data]) = NIL THEN GOTO Failed; IF (root _ tdd.text)=NIL THEN GOTO Failed; IF TextNode.Root[node] # root THEN GOTO Failed; -- make sure still in the tree IF (t1 _ TextNode.NarrowToTextNode[node])=NIL OR loc.where NOT IN [0..TextEdit.Size[t1]] THEN RETURN [TRUE, [node,0]]; RETURN [TRUE, loc]; EXITS Failed => RETURN [FALSE, TextNode.nullLocation]; }; WITH viewer.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { node: TextNode.RefTextNode; [ok, loc] _ CheckPosition[viewer, loc]; IF ok THEN { RememberCurrentPosition[viewer]; IF (node _ TextNode.NarrowToTextNode[loc.node]) # NIL THEN { where: INT _ MAX[0, MIN[loc.where, TextEdit.Size[node]-1]]; backStop: INT _ MAX[0, where-300]; UNTIL where<=backStop OR Rope.Fetch[node.rope, where-1]=15C DO where _ where - 1; ENDLOOP; loc.where _ where; }; TEditDisplay.EstablishLine[tdd, loc]; }; }; ENDCASE; }; CloseAndForkPaint: PROC [viewer: Viewer] = TRUSTED { ViewerOps.CloseViewer[viewer, FALSE]; ViewerForkers.ForkPaint[viewer, all]; }; ForkViewerPainter: PROC [viewer: Viewer, hint: ViewerOps.PaintHint] = TRUSTED { ViewerForkers.ForkPaint[viewer, hint]; }; ViewerPainter: PROC [viewer: Viewer, hint: ViewerOps.PaintHint] = { ENABLE ABORTED => CONTINUE; ViewerOps.PaintViewer[viewer, hint]; }; KillSelections: PUBLIC PROC [parent: Viewer] = { OPEN TEditSelection; IF pSel # NIL AND pSel.viewer = parent THEN MakeSelection[selection: primary]; IF sSel # NIL AND sSel.viewer = parent THEN MakeSelection[selection: secondary]; IF fSel # NIL AND fSel.viewer = parent THEN MakeSelection[selection: feedback]; }; CancelLinks: PUBLIC PROC [viewer: Viewer] = { ForgetViewer[viewer]; IF viewer.link.link=viewer THEN { viewer.link.link _ NIL; ForkViewerPainter[viewer.link, caption]; } ELSE FOR v: Viewer _ viewer.link.link, v.link UNTIL v.link=viewer DO REPEAT FINISHED => v.link _ viewer.link; ENDLOOP; viewer.link _ NIL; }; DefaultMenus: PUBLIC PROC [viewer: Viewer, paint: BOOL _ FALSE] = { menu: Menus.Menu _ viewer.menu; num: INTEGER _ 1; DoLine: PROC [which: TEditProfile.DefaultMenuChoice] = { entry: Menus.MenuEntry _ SELECT which FROM places => TEditDocumentPrivate.findMenu, levels => TEditDocumentPrivate.levelMenu, ENDCASE => NIL; IF entry = NIL THEN RETURN; Menus.SetLine[menu, num, entry]; num _ num+1 }; DoLine[TEditProfile.menu1]; DoLine[TEditProfile.menu2]; DoLine[TEditProfile.menu3]; ViewerOps.EstablishViewerPosition[viewer, viewer.wx, viewer.wy, viewer.ww, viewer.wh]; IF paint THEN ForkViewerPainter[viewer, all]; }; MakeNewViewer: PROC [column: Column, parent: Viewer, wDir: ROPE _ NIL] RETURNS [viewer: Viewer] = { viewer _ MakeNewIcon[column, parent, wDir]; IF parent = NIL OR parent.column # column THEN ViewerOps.OpenIcon[icon: viewer, paint: TRUE] ELSE { inner: PROC = { IF parent.destroyed THEN RETURN; IF parent.iconic THEN RETURN; IF NOT viewer.iconic THEN RETURN; IF parent.column # column THEN RETURN; -- parent.column must have changed! viewer.openHeight _ parent.openHeight; ViewerOps.OpenIcon[icon: viewer, paint: FALSE]; ViewerOps.MoveBelowViewer[static: parent, altered: viewer, paint: FALSE]; ViewerOps.ComputeColumn[column]; }; IF TEditProfile.openFirstLevelOnly THEN WITH viewer.data SELECT FROM tdd: TEditDocument.TEditDocumentData => tdd.clipLevel _ 1; ENDCASE; ViewerLocks.CallUnderColumnLocks[inner, column, static]; }; }; MakeNewIcon: PROC [column: Column, parent: Viewer _ NIL, wDir: ROPE _ NIL] RETURNS [viewer: Viewer] = { IF wDir=NIL THEN wDir _ WorkingDirectoryFromViewer[parent]; IF column=static THEN column _ left; viewer _ ViewerOps.CreateViewer[ flavor: $QueryText, info: [name: wDir, column: column, iconic: TRUE], paint: FALSE]; IF TEditProfile.openFirstLevelOnly THEN WITH viewer.data SELECT FROM tdd: TEditDocument.TEditDocumentData => tdd.clipLevel _ 1; ENDCASE; DefaultMenus[viewer]; }; ReplaceByNewViewer: PROC [parent: Viewer, wDir: ROPE _ NIL] RETURNS [viewer: Viewer] = { viewer _ MakeNewIcon[column: ColumnOf[parent], parent: parent, wDir: wDir]; SwapViewers[parent, viewer]; }; SwapViewers: PROC [parent: Viewer, icon: Viewer] = { inner: PROC = { IF parent.destroyed THEN RETURN; IF parent.iconic THEN RETURN; IF NOT icon.iconic THEN RETURN; IF parent.column # col THEN RETURN; icon.openHeight _ parent.openHeight; ViewerOps.OpenIcon[icon: icon, paint: FALSE]; ViewerOps.MoveBelowViewer[static: parent, altered: icon, paint: FALSE]; CloseAndForkPaint[parent]; ViewerOps.ComputeColumn[col]; }; col: ViewerClasses.Column = parent.column; KillSelections[parent]; -- need to deselect before making new viewer ViewerLocks.CallUnderColumnLocks[inner, col, static]; }; FindOldViewer: PROC [name: ROPE, viewer: Viewer] RETURNS [old: Viewer _ NIL] = { Match: ViewerOps.EnumProc -- PROC[v: Viewer] RETURNS[BOOL _ TRUE] -- = { IF v#viewer AND Rope.Equal[name, v.name, FALSE] THEN { old _ v; RETURN [FALSE] }; }; ViewerOps.EnumerateViewers[Match]; }; Report: PROC [m1, m2, m3, m4: ROPE _ NIL, flash: BOOL _ FALSE] = { ENABLE ABORTED => CONTINUE; MessageWindow.Append[m1, TRUE]; IF m2#NIL THEN MessageWindow.Append[m2]; IF m3#NIL THEN MessageWindow.Append[m3]; IF m4#NIL THEN MessageWindow.Append[m4]; IF flash THEN MessageWindow.Blink[]; }; Flash: PROC [m1, m2: ROPE _ NIL] = { Report[m1: m1, m2: m2, flash: TRUE]; }; PleaseSelectFileName: PROC = { Flash["Please select file name."]; }; IllegalFileName: ViewerForkers.CallBack = { Flash["Illegal file name."]; }; ReloadedMessage: ViewerForkers.CallBack = { WITH data SELECT FROM name: ROPE => Flash[name," restored with previous unsaved edits."]; ENDCASE; }; RemoveVersion: PROC [x: ROPE] RETURNS [ROPE] = { RETURN [x.Flatten[len: x.SkipTo[skip: "!"]]]; }; GetFileName: PROC [file: FS.OpenFile, removeVersion: BOOL _ FALSE] RETURNS [name: ROPE _ NIL] = { name _ FS.GetName[file ! FS.Error => CONTINUE].fullFName; IF name#NIL AND removeVersion THEN name _ RemoveVersion[name]; }; LoadOp: TYPE ~ {load, open, replace}; LookupType: TYPE ~ {source, impl}; DoGet: PROC [parent: Viewer, column: Column, file: FS.OpenFile, specificVersion: BOOL, op: LoadOp _ $load, place: INT _ 0, search: ROPE _ NIL, forceOpen: BOOL _ TRUE] RETURNS [viewer: Viewer] = { viewerIn: Viewer _ parent; needPaint: BOOL _ FALSE; loaded: BOOL _ FALSE; IF parent = NIL THEN op _ open; SELECT op FROM load => viewerIn _ parent; open => viewerIn _ MakeNewIcon[column: column, parent: parent]; replace => viewerIn _ ReplaceByNewViewer[parent]; ENDCASE => ERROR; [viewer, loaded] _ DoLoad[viewer: viewerIn, file: file, op: op, specificVersion: specificVersion, place: place]; IF viewer # NIL THEN { IF viewer # viewerIn THEN { Report[viewer.name, " was already loaded."]; ViewerOps.BlinkViewer[viewer: viewer, milliseconds: 200]; SELECT op FROM open, replace => TRUSTED { ViewerForkers.ForkCall[viewerIn, FlameOut, viewerIn]; viewerIn _ NIL}; ENDCASE; }; IF Rope.Size[search] # 0 THEN WITH viewer.data SELECT FROM ntdd: TEditDocument.TEditDocumentData => { loc: TextNode.Location _ TextNode.LocWithin[ntdd.text, 0]; sel: TEditDocument.Selection _ NIL; IF Rope.Match["|*", search] THEN { pos: INT _ Convert.IntFromRope[Rope.Flatten[search, 1] ! Convert.Error => GO TO faulty]; nloc: TextNode.Location _ TextNode.LocWithin[n: ntdd.text, count: pos, skipCommentNodes: TRUE]; [] _ PositionViewerInternal[viewer, nloc]; TEditSelectionOps.ShowGivenPosition[viewer, pos]; EXITS faulty => {}; } ELSE { TEditDisplay.EstablishLine[ntdd, loc]; TEditSelection.FindRope[ viewer: viewer, rope: search, case: TRUE, word: TRUE, def: TRUE, id: feedback]; sel _ TEditSelection.fSel; IF sel # NIL AND sel.viewer = viewer THEN loc _ sel.start.pos; TEditDisplay.EstablishLine[ntdd, loc]; }; RememberCurrentPosition[viewer]; needPaint _ TRUE; }; ENDCASE; SELECT TRUE FROM viewer.iconic AND forceOpen => { ViewerOps.OpenIcon[viewer]; IF parent # NIL AND parent # viewer AND NOT parent.destroyed THEN IF op = replace THEN CloseAndForkPaint[parent] ELSE ViewerOps.MoveBelowViewer[viewer, parent, TRUE]; }; loaded => ForkViewerPainter[viewer, all]; needPaint => ForkViewerPainter[viewer, client]; ENDCASE; }; }; DoLoad: PROC [viewer: Viewer, file: FS.OpenFile, op: LoadOp, specificVersion: BOOL _ FALSE, place: INT _ 0] RETURNS [out: Viewer, loaded: BOOL _ FALSE] = { clearMessage: BOOL _ TRUE; fileName: ROPE ~ FS.GetName[file].fullFName; name: ROPE _ fileName; out _ viewer; IF NOT specificVersion THEN name _ name.Flatten[len: name.SkipTo[skip: "!"]]; IF Rope.Equal[viewer.file, fileName, FALSE] THEN { Report[fileName, " is already loaded."]; ViewerOps.BlinkViewer[viewer: viewer, milliseconds: 200]; RETURN; }; Report["Loading ", name]; KillSelections[viewer]; WITH viewer.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { oldViewer: Viewer _ NIL; linkViewer: Viewer _ NIL; vFile: ROPE _ NIL; DO oldViewer _ FindOldViewer[name, viewer]; IF oldViewer # NIL THEN linkViewer _ oldViewer.link; ViewerPrivate.AcquireWriteLocks[viewer, oldViewer, linkViewer]; IF oldViewer = FindOldViewer[name, viewer] AND (oldViewer = NIL OR linkViewer = oldViewer.link) THEN EXIT; ViewerPrivate.ReleaseWriteLocks[viewer, oldViewer, linkViewer]; ENDLOOP; { ENABLE UNWIND => ViewerPrivate.ReleaseWriteLocks[viewer, oldViewer, linkViewer]; [] _ TEditDocument.SpinAndLock[tdd, "DoLoad"]; IF (vFile _ viewer.file) #NIL THEN SaveLoadHistory[viewer]; IF oldViewer # NIL THEN { IF NOT oldViewer.destroyed THEN WITH oldViewer.data SELECT FROM tddOld: TEditDocument.TEditDocumentData => GO TO oldCase; ENDCASE; EXITS oldCase => {}; }; SELECT TRUE FROM oldViewer = NIL => { root: TextNode.Ref ~ TEditDocumentPrivate.FindUnsavedDocument[fileName]; IF viewer.link=NIL THEN { ForgetViewer[viewer]; -- remove this from the root => viewer mapping IF viewer.newVersion AND (NOT viewer.saveInProgress) AND vFile#NIL THEN TEditDocumentPrivate.RecordUnsavedDocument[vFile, tdd.text] ELSE TEditInput.FreeTree[tdd.text]; } ELSE CancelLinks[viewer]; viewer.name _ name; viewer.file _ fileName; viewer.newVersion _ viewer.newFile _ FALSE; IF root # NIL THEN { ViewerForkers.ForkCall[NIL, ReloadedMessage, name]; clearMessage _ FALSE; }; tdd.text _ NIL; -- so InitViewerDoc won't worry about freeing it TEditDocumentPrivate.InitViewerDocInternal[viewer, file, root]; viewer.newFile _ FALSE; viewer.newVersion _ root#NIL; loaded _ TRUE; ClearPositionHistory[viewer]; [] _ PositionViewerInternal[viewer, TextNode.LocWithin[tdd.text, place]]; RememberCurrentPosition[viewer]; }; ENDCASE => { out _ oldViewer; }; TEditDocument.Unlock[tdd]; ViewerPrivate.ReleaseWriteLocks[viewer, oldViewer, linkViewer]; }; IF clearMessage THEN MessageWindow.Clear[]; }; ENDCASE; }; FlameOut: ViewerForkers.CallBack = { ENABLE ABORTED => CONTINUE; WITH data SELECT FROM v: Viewer => ViewerOps.DestroyViewer[v]; ENDCASE; }; TryToOpen: PROC [name: ROPE, wDir: ROPE _ NIL] RETURNS [file: FS.OpenFile _ FS.nullOpenFile] = { file _ FS.Open[name: name, wDir: wDir ! FS.Error => IF error.code=$unknownFile THEN CONTINUE]; }; TryExtensions: PROC [name: ROPE, wDir: ROPE, extensions: LIST OF ROPE] RETURNS [file: FS.OpenFile _ FS.nullOpenFile] = { base: ROPE ~ name.Concat["."]; FOR list: LIST OF ROPE _ extensions, list.rest UNTIL list=NIL DO file _ TryToOpen[name: base.Concat[list.first], wDir: wDir]; IF file#FS.nullOpenFile THEN EXIT; ENDLOOP; }; IsAnExtension: PROC [ext: ROPE, extensions: LIST OF ROPE] RETURNS [BOOL] = { FOR list: LIST OF ROPE _ extensions, list.rest UNTIL list=NIL DO IF Rope.Equal[ext, list.first, FALSE] THEN RETURN [TRUE]; ENDLOOP; RETURN [FALSE]; }; FileNameProc: TYPE = TEditOps.FileNameProc; fileNameProc: FileNameProc _ NIL; RegisterFileNameProc: PUBLIC PROC [proc: FileNameProc] = { fileNameProc _ proc; }; ReplaceFileNameProc: PUBLIC PROC [new: FileNameProc] RETURNS [old: FileNameProc] = { old _ fileNameProc; fileNameProc _ new; }; TryVersionMap: PROC [shortName: ROPE] RETURNS [file: FS.OpenFile _ FS.nullOpenFile] = { mapList: VersionMap.MapList ~ VersionMapDefaults.GetMapList[$Source]; ranges: VersionMap.RangeList ~ VersionMap.ShortNameToRanges[mapList, shortName]; bestName: ROPE _ NIL; bestDate: BasicTime.GMT _ BasicTime.nullGMT; FOR list: VersionMap.RangeList _ ranges, list.rest UNTIL list=NIL DO range: VersionMap.Range _ list.first; WHILE range.len # 0 DO fullName: ROPE; created: BasicTime.GMT; [name: fullName, created: created, next: range] _ VersionMap.RangeToEntry[range]; IF bestDate = BasicTime.nullGMT OR BasicTime.Period[from: bestDate, to: created] > 0 THEN {bestDate _ created; bestName _ fullName}; ENDLOOP; ENDLOOP; IF bestName # NIL THEN RETURN [FS.Open[name: bestName, wantedCreatedTime: bestDate]]; }; TryVersionMapExtensions: PROC [name: ROPE, extensions: LIST OF ROPE] RETURNS [file: FS.OpenFile _ FS.nullOpenFile] = { base: ROPE ~ name.Concat["."]; FOR list: LIST OF ROPE _ extensions, list.rest UNTIL list=NIL DO file _ TryVersionMap[base.Concat[list.first]]; IF file#FS.nullOpenFile THEN EXIT; ENDLOOP; }; FileNotFound: ERROR[fileName: ROPE] = CODE; LookupSource: PROC [sel: ROPE, wDir: ROPE, fileNameProcViewer: Viewer _ NIL] RETURNS [file: FS.OpenFile _ FS.nullOpenFile, specificVersion: BOOL _ FALSE, search: ROPE _ NIL] = { dot: INT _ 0; hasExtension, standardExtension, simpleName: BOOL _ FALSE; base, ext: ROPE _ NIL; proc: FileNameProc ~ fileNameProc; Report["Directory lookup for ", sel]; FOR i: INT DECREASING IN[0..sel.Size[]) DO SELECT sel.Fetch[i] FROM '| => {search _ Rope.Flatten[sel, i]; sel _ Rope.Flatten[sel, 0, i]; EXIT}; IN ['0..'9] => {}; ENDCASE => EXIT; ENDLOOP; FOR i: INT DECREASING IN[0..sel.Size[]) DO SELECT sel.Fetch[i] FROM '! => specificVersion _ TRUE; '. => IF hasExtension THEN NULL ELSE { dot _ i; hasExtension _ TRUE }; '], '>, '/ => EXIT; ENDCASE; REPEAT FINISHED => simpleName _ TRUE; ENDLOOP; file _ TryToOpen[name: sel, wDir: wDir]; IF file#FS.nullOpenFile THEN RETURN; IF hasExtension OR specificVersion THEN NULL ELSE { file _ TryExtensions[name: sel, wDir: wDir, extensions: TEditProfile.sourceExtensions]; IF file#FS.nullOpenFile THEN RETURN; }; IF proc#NIL THEN { pname, psearch: ROPE; [pname, psearch] _ proc[sel, fileNameProcViewer]; IF pname.Size[]#0 THEN { file _ TryToOpen[name: pname, wDir: wDir]; IF file#FS.nullOpenFile THEN { search _ psearch; RETURN }; }; }; IF specificVersion THEN RETURN; IF hasExtension THEN { base _ sel.Substr[len: dot]; ext _ sel.Substr[start: dot+1]; IF IsAnExtension[ext, TEditProfile.sourceExtensions] THEN standardExtension _ TRUE; IF NOT standardExtension THEN { file _ TryExtensions[name: base, wDir: wDir, extensions: TEditProfile.implExtensions]; IF file#FS.nullOpenFile THEN { search _ ext; RETURN }; }; }; IF simpleName AND TEditProfile.tryVersionMap THEN { Report["Get: trying version map for ", sel]; file _ TryVersionMap[sel]; -- try sel verbatim first IF file#FS.nullOpenFile THEN RETURN; IF NOT hasExtension THEN { file _ TryVersionMapExtensions[sel, TEditProfile.sourceExtensions]; IF file#FS.nullOpenFile THEN RETURN; } ELSE IF NOT standardExtension THEN { file _ TryVersionMapExtensions[base, TEditProfile.implExtensions]; IF file#FS.nullOpenFile THEN { search _ ext; RETURN }; }; }; }; LookupImpl: PROC [sel: ROPE, wDir: ROPE] RETURNS [file: FS.OpenFile _ FS.nullOpenFile, search: ROPE _ NIL] = { cp: FS.ComponentPositions; simpleName: BOOL ~ sel.SkipTo[skip: "[]<>/"]=sel.Size[]; xname, base, ext, impl: ROPE _ NIL; [fullFName: xname, cp: cp] _ FS.ExpandName[name: sel, wDir: wDir]; base _ xname.Substr[start: cp.base.start, len: cp.base.length]; -- base part is defs name ext _ xname.Substr[start: cp.ext.start, len: cp.ext.length]; -- extension part is search item IF ext.Size[]#0 THEN { Report["Model lookup for implementor of ", base, ".", ext]; TRUSTED{ impl _ AMMiniModel.ImplementorName[ defsName: base, itemName: ext, world: WorldVM.LocalWorld[]] }; }; IF impl=NIL THEN impl _ base.Concat["Impl"]; Report["Directory lookup for ", impl]; file _ TryExtensions[name: impl, wDir: xname.Substr[len: cp.base.start], extensions: TEditProfile.implExtensions]; IF file#FS.nullOpenFile THEN { search _ ext; RETURN }; IF simpleName AND TEditProfile.tryVersionMap THEN { Report["GetImpl: trying version map for ", impl]; file _ TryVersionMapExtensions[impl, TEditProfile.implExtensions]; IF file#FS.nullOpenFile THEN { search _ ext; RETURN }; }; ERROR FileNotFound[impl]; }; WorkingDirectoryFromViewer: PUBLIC PROC [parent: Viewer] RETURNS [ROPE] = { name, fname: ROPE _ NIL; cp: FS.ComponentPositions; IF parent#NIL THEN name _ parent.name; { ENABLE FS.Error => CONTINUE; IF name=NIL OR parent.file=NIL THEN [fullFName: fname, cp: cp] _ FS.ExpandName[name: "*", wDir: name ! FS.Error => CONTINUE] ELSE [fullFName: fname, cp: cp] _ FS.ExpandName[name: name ! FS.Error => CONTINUE]; RETURN [fname.Substr[len: cp.base.start]]; }; RETURN ["[]<>"]; }; IsAWorkingDirectory: PROC [name: ROPE] RETURNS [BOOL] = { RETURN [Rope.Match["*/", name] OR Rope.Match["*>", name]]; }; CanonicalWorkingDirectory: PROC [txt: ROPE, wDir: ROPE _ NIL] RETURNS [ROPE] = { fname: ROPE _ NIL; cp: FS.ComponentPositions; [fullFName: fname, cp: cp] _ FS.ExpandName[name: txt.Concat["*"], wDir: wDir ! FS.Error => CONTINUE]; IF fname=NIL THEN RETURN [NIL] ELSE RETURN [fname.Substr[len: cp.base.start]]; }; DoGetFile: PROC [txt: ROPE, column: Column, parent: Viewer, op: LoadOp _ $load, lookup: LookupType _ $source, fileNameProcViewer: Viewer _ NIL] RETURNS [viewer: Viewer _ NIL] = { parentDir: ROPE ~ WorkingDirectoryFromViewer[parent]; file: FS.OpenFile _ FS.nullOpenFile; specificVersion: BOOL _ FALSE; search: ROPE _ NIL; IF txt=NIL THEN txt _ ViewerTools.GetSelectionContents[]; IF fileNameProcViewer=NIL THEN fileNameProcViewer _ parent; IF txt.Size[]=0 THEN { PleaseSelectFileName[]; GOTO Fail }; IF IsAWorkingDirectory[txt] THEN { wDir: ROPE ~ CanonicalWorkingDirectory[txt, parentDir]; IF wDir=NIL THEN { Flash[txt, " is an illegal working directory."]; GOTO Fail }; SELECT op FROM load => DoEmptyViewer[parent: viewer _ parent, wDir: wDir]; open => viewer _ MakeNewViewer[column: column, parent: parent, wDir: wDir]; replace => viewer _ ReplaceByNewViewer[parent: parent, wDir: wDir]; ENDCASE => ERROR; RETURN [viewer]; }; { ENABLE { FS.Error => { Flash[error.explanation]; GOTO Fail }; FileNotFound => { Flash[fileName, " not found."]; GOTO Fail }; }; SELECT lookup FROM $source => [file: file, specificVersion: specificVersion, search: search] _ LookupSource[sel: txt, wDir: parentDir, fileNameProcViewer: fileNameProcViewer]; $impl => [file: file, search: search] _ LookupImpl[sel: txt, wDir: parentDir]; ENDCASE => ERROR; IF file=FS.nullOpenFile THEN { Flash[txt, " not found."]; GOTO Fail }; }; viewer _ DoGet[parent, column, file, specificVersion, op, 0, search]; EXITS Fail => RETURN [NIL]; }; DoEmptyViewer: PROC [parent: Viewer, wDir: ROPE _ NIL] = { inner: PROC [tdd: TEditDocument.TEditDocumentData] = { link1: Viewer _ parent.link; link2: Viewer _ NIL; IF wDir=NIL THEN wDir _ WorkingDirectoryFromViewer[parent]; TEditSelection.LockSel[primary, "EmptyViewer"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; prop: REF LoadHistory; [] _ TEditDocument.SpinAndLock[tdd, "EmptyViewer"]; KillSelections[parent]; SaveLoadHistory[parent]; prop _ NARROW[ViewerOps.FetchProp[parent, $LoadHistory]]; -- hang onto it SELECT TRUE FROM link1 # NIL => CancelLinks[parent]; parent.newVersion AND ~parent.saveInProgress AND parent.file # NIL => TEditDocumentPrivate.RecordUnsavedDocument[parent.file, tdd.text]; ENDCASE => TEditInput.FreeTree[tdd.text]; parent.name _ wDir; parent.file _ NIL; parent.newVersion _ parent.newFile _ FALSE; tdd.text _ NIL; -- so InitViewerDoc won't free it TEditDocumentPrivate.InitViewerDoc[parent,NIL]; TEditDocument.Unlock[tdd]; ClearPositionHistory[parent]; ViewerOps.AddProp[parent, $LoadHistory, prop]; -- restore file history ViewerPainter[parent, all]; ForceInitialCaret[parent]; }; TEditSelection.UnlockSel[primary]; }; IF parent # NIL THEN LockTheWorks[inner, parent, "EmptyViewer"]; }; EmptyViewer: PUBLIC PROC [parent: Viewer] = { DoEmptyViewer[parent]; }; DoNewViewer: PUBLIC PROC [column: Column, parent: Viewer _ NIL] RETURNS [new: Viewer] = { TEditSelection.LockSel[primary, "DoNewViewer"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; new _ MakeNewViewer[column, parent]; ForceInitialCaret[new]; }; TEditSelection.UnlockSel[primary]; }; NewViewer: PUBLIC PROC [parent: Viewer] = { [] _ DoNewViewer[column: ColumnOf[parent], parent: parent]; }; DoCloseAndNewViewer: PUBLIC PROC [parent: Viewer] RETURNS [new: Viewer] = { TEditSelection.LockSel[primary, "DoCloseAndNewViewer"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; new _ ReplaceByNewViewer[parent]; ForceInitialCaret[new]; }; TEditSelection.UnlockSel[primary]; }; CloseAndNewViewer: PUBLIC PROC [parent: Viewer] = { [] _ DoCloseAndNewViewer[parent]; }; DoLoadFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL, close: BOOL _ FALSE, fileNameProcViewer: Viewer _ NIL] RETURNS [viewer: Viewer] = { viewer _ DoGetFile[txt: fileName, column: ColumnOf[parent], parent: parent, op: IF close THEN $replace ELSE $load, lookup: $source, fileNameProcViewer: fileNameProcViewer]; }; LoadFile: PUBLIC PROC [parent: Viewer] = { [] _ DoLoadFile[parent: parent, fileName: NIL, close: FALSE]; }; DoOpenFile: PUBLIC PROC [fileName: ROPE _ NIL, column: Column, parent: Viewer _ NIL, fileNameProcViewer: Viewer _ NIL] RETURNS [viewer: Viewer] = { viewer _ DoGetFile[ txt: fileName, column: column, parent: parent, op: $open, lookup: $source, fileNameProcViewer: fileNameProcViewer]; }; OpenFile: PUBLIC PROC [parent: Viewer] = { [] _ DoOpenFile[fileName: NIL, column: ColumnOf[parent], parent: parent]; }; DoCloseAndOpenFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL] RETURNS [viewer: Viewer] = { viewer _ DoGetFile[txt: fileName, column: ColumnOf[parent], parent: parent, op: $replace, lookup: $source]; }; CloseAndOpenFile: PUBLIC PROC [parent: Viewer, fileNameProcViewer: Viewer _ NIL] = { [] _ DoGetFile[txt: NIL, column: ColumnOf[parent], parent: parent, op: $replace, lookup: $source, fileNameProcViewer: fileNameProcViewer]; }; DoLoadImplFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL, close: BOOL _ FALSE] RETURNS [viewer: Viewer] = { viewer _ DoGetFile[txt: fileName, column: ColumnOf[parent], parent: parent, op: IF close THEN $replace ELSE $load, lookup: $impl]; }; LoadImplFile: PUBLIC PROC [parent: Viewer] = { [] _ DoLoadImplFile[parent: parent, fileName: NIL]; }; DoOpenImplFile: PUBLIC PROC [fileName: ROPE _ NIL, column: Column, parent: Viewer _ NIL] RETURNS [viewer: Viewer] = { viewer _ DoGetFile[txt: fileName, column: column, parent: parent, op: $open, lookup: $impl]; }; OpenImplFile: PUBLIC PROC [parent: Viewer] = { [] _ DoOpenImplFile[fileName: NIL, column: ColumnOf[parent], parent: parent]; }; DoCloseAndOpenImplFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL] RETURNS [viewer: Viewer] = { viewer _ DoGetFile[txt: fileName, column: ColumnOf[parent], parent: parent, op: $replace, lookup: $impl]; }; CloseAndOpenImplFile: PUBLIC PROC [parent: Viewer] = { [] _ DoCloseAndOpenImplFile[parent, NIL]; }; PreLoadPrevious: PUBLIC Menus.MenuProc = { -- called when unguarding PrevFile viewer: Viewer = NARROW[parent]; tdd: TEditDocument.TEditDocumentData; prop: REF LoadHistory; propName: ROPE; tdd _ NARROW[viewer.data]; IF tdd = NIL THEN RETURN; [] _ TEditDocument.SpinAndLock[tdd, "PreLoadPrevious"]; prop _ NARROW[ViewerOps.FetchProp[viewer, $LoadHistory]]; TEditDocument.Unlock[tdd]; IF prop=NIL OR Rope.Equal[prop.name, viewer.file, FALSE] THEN { Flash["No record of previous file loaded in this viewer"]; RETURN; }; propName _ prop.name; Report[propName," ~ Click LEFT to load, MIDDLE for new, RIGHT for close & new"]; }; DoLoadPreviousFile: PROC [parent: Viewer, op: LoadOp] = { WITH parent.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { prop: REF LoadHistory; propName: ROPE; propPlace: INT; file: FS.OpenFile; [] _ TEditDocument.SpinAndLock[tdd, "DoLoadPreviousFile"]; prop _ NARROW[ViewerOps.FetchProp[parent, $LoadHistory]]; TEditDocument.Unlock[tdd]; IF prop = NIL OR Rope.Equal[prop.name, parent.file, FALSE] THEN { Flash["No record of previous file loaded in this viewer"]; RETURN }; propName _ prop.name; propPlace _ prop.place; file _ FS.Open[propName ! FS.Error => { Flash[error.explanation]; GOTO Fail }]; [] _ DoGet[parent: parent, column: ColumnOf[parent], file: file, specificVersion: (propName.Find["!"]>=0), op: op, place: propPlace, forceOpen: FALSE]; }; ENDCASE; EXITS Fail => NULL; }; LoadPreviousFile: PUBLIC PROC [parent: Viewer] = { DoLoadPreviousFile[parent: parent, op: $load]; }; OpenPreviousFile: PUBLIC PROC [parent: Viewer] = { DoLoadPreviousFile[parent: parent, op: $open]; }; CloseAndOpenPreviousFile: PUBLIC PROC [parent: Viewer] = { DoLoadPreviousFile[parent: parent, op: $replace]; }; GetCreateName: PROC [parent: Viewer, name: ROPE] RETURNS [ROPE _ NIL] = { wDir: ROPE ~ WorkingDirectoryFromViewer[parent]; fullFName: ROPE; cp: FS.ComponentPositions; [fullFName: fullFName, cp: cp] _ FS.ExpandName[name, wDir ! FS.Error => GOTO Fail]; RETURN [Rope.Flatten[base: fullFName, len: cp.ext.start+cp.ext.length]]; -- strip version EXITS Fail => ViewerForkers.ForkCall[NIL, IllegalFileName]; }; IsNewFile: PROC [name: ROPE] RETURNS [new: BOOL _ FALSE] = { [] _ FS.FileInfo[name ! FS.Error => { new _ TRUE; CONTINUE }]; }; PreStore: PUBLIC Menus.MenuProc = { -- called when unguarding Store sel: ROPE _ ViewerTools.GetSelectionContents[]; fileName: ROPE _ NIL; new: BOOL _ FALSE; IF sel.Size[]=0 THEN {PleaseSelectFileName[]; RETURN}; fileName _ GetCreateName[NARROW[parent], sel]; IF fileName=NIL THEN RETURN; new _ IsNewFile[fileName]; Report["Confirm Store to file: ", fileName, IF new THEN " [New File]" ELSE " [Old File]"]; }; DoStoreFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL] = { inner: PROC [tdd: TEditDocument.TEditDocumentData] = { linked: BOOL _ parent.link#NIL; oldName: ROPE ~ parent.name; oldFile: ROPE ~ parent.file; IF fileName=NIL THEN fileName _ ViewerTools.GetSelectionContents[]; IF fileName.Size[]=0 THEN {PleaseSelectFileName[]; RETURN}; fileName _ GetCreateName[parent, fileName]; IF fileName=NIL THEN RETURN; IF parent.file # NIL THEN SaveLoadHistory[parent]; IF linked THEN CancelLinks[parent]; -- remove viewer from link chain parent.name _ parent.file _ fileName; NodeProps.PutProp[tdd.text, $FileCreateDate, NIL]; -- remove so Save won't test ViewerOps.SaveViewer[parent ! UNWIND => { parent.name _ oldName; parent.file _ oldFile }]; IF linked THEN { loc: INT; KillSelections[parent]; loc _ TextNode.LocNumber[tdd.lineTable.lines[0].pos]; tdd.text _ NIL; -- so InitViewerDoc won't free it TEditDocumentPrivate.InitViewerDoc[parent, NIL]; RememberCurrentPosition[parent]; ForkViewerPainter[parent, caption]; }; }; LockTheWorks[inner, parent, "StoreFile"]; }; LockTheWorks: PROC [inner: PROC [tdd: TEditDocument.TEditDocumentData], viewer: Viewer, who: ROPE] = { innerWorks: PROC = { WITH viewer.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { [] _ TEditDocument.SpinAndLock[tdd, who]; inner[tdd ! UNWIND => TEditDocument.Unlock[tdd]]; TEditDocument.Unlock[tdd]; } ENDCASE }; ViewerGroupLocks.CallRootAndLinksUnderWriteLock[innerWorks, viewer]; }; StoreFile: PUBLIC PROC [parent: Viewer] = { DoStoreFile[parent: parent, fileName: NIL]; }; GetViewerContents: PROC [viewer: Viewer] RETURNS [ROPE] = { TEditInputOps.WaitForInsertToFinish[]; RETURN [ViewerTools.GetContents[viewer]]; }; DoAnonymousLoadFile: PROC [parent: Viewer, lookup: LookupType, fileNameProcViewer: Viewer _ NIL] = { IF parent.file#NIL THEN Flash["Viewer already contains a file."] ELSE { txt: ROPE ~ GetViewerContents[parent]; size: INT ~ txt.Size[]; IF size=0 THEN Flash["Enter a file name."] ELSE { v: Viewer _ DoGetFile[txt: txt, column: ColumnOf[parent], parent: parent, op: $load, lookup: lookup, fileNameProcViewer: fileNameProcViewer]; IF v#NIL AND v#parent THEN ViewerForkers.ForkCall[parent, FlameOut, parent]; }; }; }; AnonymousLoadFile: PUBLIC PROC [parent: Viewer, fileNameProcViewer: Viewer _ NIL] = { DoAnonymousLoadFile[parent: parent, lookup: $source, fileNameProcViewer: fileNameProcViewer]; }; AnonymousLoadImplFile: PUBLIC PROC [parent: Viewer] = { DoAnonymousLoadFile[parent: parent, lookup: $impl]; }; NodeProps.Register[$Viewer, NodeProps.NullRead, NodeProps.NullWrite, NodeProps.NullCopy]; NodeProps.Register[$LockedViewer, NodeProps.NullRead, NodeProps.NullWrite, NodeProps.NullCopy]; NodeProps.Register[$FileCreateDate, NodeProps.NullRead, NodeProps.NullWrite, NodeProps.NullCopy]; NodeProps.Register[$FileExtension, NodeProps.NullRead, NodeProps.NullWrite, NodeProps.NullCopy]; END. *QueryTEditDocuments2Impl.mesa Copyright Σ 1985, 1987 by Xerox Corporation. All rights reserved. Plass, April 8, 1985 5:20:37 pm PST Russ Atkinson (RRA) June 25, 1985 2:12:21 am PDT Michael Plass, March 2, 1987 5:20:04 pm PST Doug Wyatt, January 20, 1987 2:20:28 am PST Doug Terry, April 9, 1987 1:45:25 pm PDT change to a linked viewer Make viewer's load history point to current contents of parent backup to line start All calls in this module to ViewerOps.PaintViewer go through here to aid debugging. (note that calls to ComputeColumn also paint the screen) Makes a new, empty, $Text viewer, placing it under the parent viewer (if any, and in column). copy height and position info from old to new ... returns a new iconic $Text viewer with default menus, no painting done. Must lock both columns copy height and position info from old to new We were able to do the load Humph! A previous viewer existed! We created a viewer to hold the result, but we will never use it now. We need to perform a search for the given definition. This is a position spec to parse This is a definition to search for capture the location found and establish it as the place to display RRA: For some stupid reason we have to open the icon first before moving things. I wonder why? Load a file into a viewer viewer is the viewer to be loaded with the contents of the file name is the specified name for the file file is the open file Note that if anything changed while we were waiting for the lock we should release our locks, then go around and try again Can this deadlock? We hope not! An old viewer was found, so don't do the load! There is no other viewer with the same name Another viewer has this name, so return it (caller will handle this case) Adapted from VersionMapCommandsImpl.FindSource. Stops at the first name it finds, if any. The first pass is for the position specification (if any) The following are the top level procedures that implement the Tioga file operations: they are available as menu items, system buttons, or keystrokes (LF). Clear: EmptyViewer[viewer] NewViewer[viewer] CloseAndNewViewer[viewer] Reset: TEditDocuments3Impl.ResetOp[viewer] Get: [] _ DoLoadFile[viewer, selection, FALSE] [] _ DoOpenFile[selection, viewer] [] _ DoCloseAndOpenFile[viewer, selection] GetImpl: [] _ DoLoadImplFile[viewer, selection, FALSE] [] _ DoOpenImplFile[selection, viewer] [] _ DoCloseAndOpenImplFile[viewer, selection] PrevFile: LoadPreviousFile[viewer] OpenPreviousFile[viewer] CloseAndOpenPreviousFile[viewer] Store: DoStoreFile[viewer, selection] Save: TEditDocuments3Impl.SaveOp[viewer] New button: NewViewer[NIL] Open button: [] _ DoOpenFile[NIL, selection] LF keyboard command: AnonymousLoadFile[viewer] AnonymousLoadImplFile[viewer] delay until after other op completes delay until after other op completes copy tdd.text data structure Κ+Τ˜codešœ™KšœB™BKšœ Οk™#Kšœœ™0Kšœ+™+Kšœ(™+K™(—K™š ˜ Kšœ œ˜$Kšœ œœ˜'Kšœœ˜#KšœœZ˜bKšœœ&˜1Kšœœ˜+Kšœ œ=˜LKšœœ.œ˜TKšœ œ˜#Kšœœ>˜QKšœœz˜”Kšœ œ ˜Kšœœ˜,Kšœ œ˜Kšœ œo˜KšœœA˜UKšœœ˜,Kšœ œ˜Kšœ œZ˜hKšœ œ>˜NKšœœ˜&Kšœœ˜%Kšœœ!˜4Kšœœ"˜8Kšœ œ˜)Kšœ œΠ˜ίKšœœ(˜;Kšœ œF˜WKšœœ˜—K˜šΡblnœœ˜'Kšœ"œΈ˜γKšœ.˜5Kšœ˜K˜Kšœœœ˜Kšœœ˜$Kšœœ˜$Kšœœœ ˜Kšœœ˜K˜šœ#œ˜CK˜—šΟnœœœ ˜4Kš œœ œœœ˜6Kšœ˜K˜—šŸœœ˜,Kšœ/˜/Kšœ˜K˜—K˜šœ˜K˜—šŸœœœœ˜RKš œœœœœ˜ Kšœœœ˜,K˜Kšœœ#˜>Kšœ˜K˜—šŸœœœ)˜LK˜'KšœœΟc˜IK˜K˜—š Ÿœœœœœ˜UKšœœœ˜Kšœ˜!Kšœ˜K˜—šŸœœœœ)˜OKšœœœ˜K˜#K˜K˜—šŸ œœœœ˜4Kšœœœ˜Kšœ'œ˜;K˜Kšœœœœ˜K˜Kšœ"œœ˜0šœœœ˜Kšœ™K˜'Kšœ˜Kšœ˜—Kšœœ˜Kšœ˜—K˜š œ œœœ œ˜3K˜—šŸœœœ˜3Kšœœœ*˜GKšœœœ(˜EKšœœœœ˜šœœœ˜Kšœœ˜Kšœ+˜+—K˜ K˜K˜—šŸœœœœ˜KKš œ œ/œœœ˜PKšœœ˜Kšœ.˜.K˜K˜—šŸœœœ˜DKšœ'œ˜;Kšœœœœ˜Kšœ˜K˜Kšœœ(˜1Kšœ!˜!Kšœ˜K˜—šŸœœ˜*Kšœœ(˜1Kšœ!˜!Kšœ˜—K˜šœœ(˜=K˜—šŸœœœ˜7Kšœœœ.˜OKšœœœ,˜MKšœœœœ˜šœœœ˜Kšœœ˜K˜-K˜—K˜ K˜K˜—šŸœœ˜/Kšœœœ0˜RKšœœœœ˜K˜-K˜K˜—šŸœœœ˜9Kšœ'œ˜;Kšœœœ0˜RK˜Kšœœœœ˜šœœœ˜Kšœœ˜K˜4—Kšœ?˜?K˜!Kšœ˜Kšœœœ˜K˜%K˜K˜—š ŸœœœNœœœ˜‡Kšœ)˜)Kšœœ!˜+K˜K˜—š Ÿœœ*œœœ˜dšŸ œœ*œœ!˜qK˜K˜Kšœ%˜%Kšœœœœœœœ˜LKš œœœœœ˜6Kšœœœœ˜*Kšœœœ  ˜Nš œ(œœ œœ˜]Kšœœ ˜—Kšœœ˜Kšœ œœ˜6K˜—šœ œ˜šœ)˜)K˜K˜'šœœ˜ K˜ šœ0œœ˜K˜Kšœ˜—K˜K˜—K˜%K˜—K˜—Kšœ˜—K˜K˜—šŸœœœ˜4Kšœœ˜%Kšœ%˜%K˜K˜—šŸœœ/œ˜OKšœ&˜&K˜K˜—šŸ œœ0˜CKšœœœ˜šœS™SK™8—Kšœ$˜$K˜K˜—šŸœœœ˜0Kšœ˜Kšœœœœ#˜NKšœœœœ%˜PKšœœœœ$˜OKšœ˜K˜—šŸ œœœ˜-K˜šœ˜šœ˜Kšœœ˜K˜(Kšœ˜—šœœ&œ˜DKšœœ˜(Kšœ˜——Kšœœ˜Kšœ˜K˜—š Ÿ œœœœœ˜CK˜Kšœœ˜šŸœœ,˜8šœœ˜*Kšœ(˜(Kšœ)˜)Kšœœ˜—Kšœ œœœ˜K˜ K˜—K˜K˜K˜K˜VKšœœ ˜-Kšœ˜—K˜š Ÿ œœ(œœœ˜cKšœ]™]Kšœ+˜+šœ œœ˜)Kšœ)œ˜2šœ˜šœœ˜Kšœœœ˜ Kšœœœ˜Kšœœœœ˜!Kšœœœ #˜JK™-Kšœ&˜&Kšœ(œ˜/KšœBœ˜IKšœ ˜ K˜—šœ!˜'šœ œ˜Kšœ:˜:Kšœ˜——Kšœ8˜8K˜——K˜K˜—š Ÿ œœ#œœœœ˜gKšœK™KKšœœœ+˜;Kšœœ˜$šœ ˜ Kšœ˜Kšœ+œ˜1Kšœœ˜—šœ!˜'šœ œ˜Kšœ:˜:Kšœ˜——Kšœ˜K˜K˜—š Ÿœœœœœ˜XKšœK˜KKšœ˜K˜K˜—šŸ œœ#˜4K™šœœ˜Kšœœœ˜ Kšœœœ˜Kšœœ œœ˜Kšœœœ˜#K™-Kšœ$˜$Kšœ&œ˜-Kšœ@œ˜GKšœ˜Kšœ˜K˜—Kšœ*˜*Kšœ ,˜DKšœ5˜5K˜K˜—š Ÿ œœœœœ˜PšŸœ *œ˜HKš œ œœœ œœ˜QKšœ˜—K˜"Kšœ˜K˜—š Ÿœœœœ œœ˜BKšœœœ˜Kšœœ˜Kšœœœ˜(Kšœœœ˜(Kšœœœ˜(Kšœœ˜$K˜K˜—šŸœœ œœ˜$Kšœœ˜$K˜K˜—šŸœœ˜Kšœ"˜"Kšœ˜—K˜šŸœ˜+Kšœ˜Kšœ˜K˜—šŸœ˜+šœœ˜Kšœœ9˜CKšœ˜—Kšœ˜K˜—š Ÿ œœœœœ˜0Kšœ'˜-Kšœ˜K˜—šŸ œœœœœœœœ˜aKšœœœ œ ˜9Kšœœœœ˜>Kšœ˜—K˜Kšœœ˜%šœ œ˜"K˜—šŸœœ(œœœœœ œœœ˜ΓKšœ˜Kšœ œœ˜Kšœœœ˜Kšœ œœ ˜šœ˜Kšœ˜Kšœ?˜?Kšœ1˜1Kšœœ˜—Kšœp˜pšœ œœ˜Kšœ™šœœ˜Kšœ"™"Kšœ,˜,Kšœ9˜9šœ˜šœœ˜KšœE™EKšœ5˜5Kšœ œ˜—Kšœ˜—K˜—š œœœ œ˜:šœ*˜*Kšœ5™5Kšœ:˜:Kšœœ˜#šœ˜šœ˜Kšœ ™ šœœ.˜6Kšœœœ ˜!—KšœYœ˜_Kšœ*˜*Kšœ1˜1Kšœ˜K˜—šœ˜Kšœ"™"Kšœ&˜&šœ˜Kšœ$œœœ˜O—Kšœ˜šœœœ˜)KšœC™CKšœ˜—Kšœ&˜&K˜——Kšœ ˜ Kšœ œ˜K˜—Kšœ˜—šœœ˜šœœ˜ Kšœ\™_Kšœ˜š œ œœœœ˜Ašœ ˜Kšœ˜Kšœ+œ˜5——K˜—šœ ˜ Kšœ˜—šœ ˜ Kšœ"˜"—Kšœ˜—K˜—Kšœ˜K˜—šŸœœœ(œœ œœœœ˜›šœ™K™?K™'K™—Kšœœœ˜Kšœ œœ˜,Kšœœ ˜Kšœ ˜ Kšœœœ2˜Mšœ#œœ˜2Kšœ(˜(Kšœ9˜9Kšœ˜Kšœ˜—Kšœ˜Kšœ˜šœ œ˜˜)Kšœœ˜Kšœœ˜Kšœœœ˜š˜Kšœ(˜(Kšœ œœ˜4Kšœ?˜?š œ)œœœœœ˜jKšœz™z—Kšœ?˜?Kšœ˜—˜KšœœC˜Pšœ.˜.K™ —Kšœœœ˜;šœ œœ˜šœœ˜šœœœ˜$šœ+œœ ˜9Kšœ.™.—Kšœ˜——Kšœ˜K˜—šœœ˜šœ œ˜Kšœ+™+KšœH˜Hšœ ˜šœ˜Kšœ .˜Dš œœœœ˜BKšœ<˜@Kšœ˜#—Kšœ˜—š˜Kšœ˜——K˜K˜Kšœ%œ˜+šœœœ˜Kšœœ˜3Kšœœ˜Kšœ˜—Kšœ œ 0˜@Kšœ?˜?Kšœœ˜Kšœœ˜Kšœ œ˜K˜KšœI˜IKšœ ˜ K˜—šœ˜ KšœI™IKšœ˜K˜——K˜Kšœ˜Kšœ?˜?Kšœ˜K˜—Kšœœ˜+K˜—Kšœ˜—Kšœ˜K˜—šŸœ˜$Kšœœœ˜šœœ˜Kšœ(˜(Kšœ˜—K˜—K˜šŸ œœœœœœœ œ˜`šœœ˜%Kš œœ œœœ˜8—Kšœ˜K˜—šŸ œœœœœœœœœ œ˜xKšœœ˜š œœœœœœ˜@Kšœ<˜—K˜K˜—šŸœœœœœœœœ œ˜vKšœœ˜š œœœœœœ˜@Kšœ.˜.Kšœœœœ˜"Kšœ˜—K˜—K˜šŸ œœ œœ˜+K˜—šŸ œœœœœœœ œ œœ œœ˜±Kšœœ˜ Kšœ-œœ˜:Kšœ œœ˜K˜"Kšœ%˜%Kšœ9™9š œœ œœ˜*šœ˜KšœEœ˜KKšœ˜Kšœœ˜—Kšœ˜—š œœ œœ˜*šœ˜Kšœœ˜Kš œœœœœœ˜FKšœœ˜Kšœ˜—Kšœœœ˜%Kšœ˜—Kšœ(˜(Kšœœœœ˜$šœœœ˜,šœ˜K˜WKšœœœœ˜$K˜——šœœœ˜Kšœœ˜Kšœ1˜1šœœ˜Kšœ*˜*Kšœœœœ˜:Kšœ˜—K˜—Kšœœœ˜šœœ˜Kšœ˜Kšœ˜Kšœ3œœ˜Sšœœœ˜KšœV˜VKšœœœœ˜6K˜—Kšœ˜—šœ œœ˜3Kšœ,˜,Kšœ ˜4Kšœœœœ˜$šœœœ˜K˜CKšœœœœ˜$K˜—šœœœœ˜$KšœB˜BKšœœœœ˜6K˜—K˜—K˜K˜—šŸ œœœœœœ œœœ˜nKšœœ˜Kšœ œ(˜8Kšœœœ˜#Kšœœ#˜BKšœ@ ˜YKšœ=  ˜]šœœ˜Kšœ;˜;šœ%˜,Kšœ>˜>—Kšœ˜—Kšœœœ˜,Kšœ&˜&šœH˜HKšœ)˜)—Kšœœœœ˜6šœ œœ˜3Kšœ1˜1KšœB˜BKšœœœœ˜6K˜—Kšœ˜K˜K˜—š Ÿœœœœœ˜KKšœ œœœ˜3Kšœœœ˜&˜Kšœœ œ˜šœœœ ˜Kšœœ$œ œ˜]Kšœœœ œ˜S—Kšœ$˜*K˜—Kšœ ˜K˜K˜—š œŸœœœœœ˜:Kšœœ˜:K˜K˜—šŸœœœœœœœ˜PKšœœœœ˜-šœœ-˜LKšœœ œ˜—Kšœœœœœœœ$˜NK˜K˜—š Ÿ œœœqœœœ˜²Kšœ œ&˜5Kšœœ œ˜$Kšœœœ˜Kšœœœ˜Kšœœœ*˜9Kšœœœ˜;Kšœœœ˜;šœœ˜"Kšœœ-˜7Kšœœœ4œ˜Pšœ˜Kšœ;˜;KšœK˜KKšœC˜CKšœœ˜—Kšœ ˜K˜—šœ˜šœ˜Kšœ&œ˜4Kšœ2œ˜>K˜—šœ˜šœK˜KKšœP˜P—K˜NKšœœ˜—Kšœœœœ˜FK˜—KšœE˜EKšœ œœ˜K˜K™—šœ–œ™ššœ™Kšœ™Kšœ™Kšœ™—šœ™Kšœ#™#—šœ™Kšœ#œ™)Kšœ"™"Kšœ*™*—šœ™Kšœ'œ™-Kšœ&™&Kšœ.™.—šœ ™ Kšœ™Kšœ™Kšœ ™ —šœ™Kšœ™—šœ™Kšœ"™"K™—šœ ™ Kšœ œ™—šœ ™ Kšœœ ™K™—šœ™Kšœ™Kšœ™—K™—šŸ œœœœ˜:šœœ+˜6Kšœ˜Kšœœ˜Kšœœœ+˜;Kšœ/˜/šœ˜Kšœœ&˜3Kšœœ ˜Kšœ3˜3K˜K˜Kšœœ- ˜Išœœ˜Kšœœ˜#šœœœœ˜EKšœB˜B—Kšœ"˜)—Kšœ˜Kšœœ˜Kšœ%œ˜+Kšœ œ !˜2Kšœ*œ˜/Kšœ˜K˜Kšœ/ ˜FK˜K˜K˜—Kšœ"˜"K˜—Kšœ œœ,˜@Kšœ˜K˜—šŸ œœœ˜-K˜Kšœ˜K˜—š Ÿ œœœ#œœ˜YKšœ/˜/šœ˜Kšœœ&˜3Kšœ$˜$Kšœ˜Kšœ˜—Kšœ"˜"Kšœ˜K˜—šŸ œœœ˜+Kšœ;˜;Kšœ˜K˜—šŸœœœœ˜KKšœ7˜7šœœœ&˜5K˜!K˜K˜—Kšœ"˜"K˜K˜—šŸœœœ˜3Kšœ!˜!Kšœ˜K˜—šŸ œœœœœ œœ˜SKšœœœ˜>šœK˜KKšœœœ œ˜7Kšœ(˜(—Kšœ˜K˜—šŸœœœ˜*Kšœ*œ œ˜=Kšœ˜K˜—šŸ œœœ œœ#œœœ˜“Kšœ‡˜‡Kšœ˜K˜—šŸœœœ˜*Kšœœ,˜IKšœ˜K˜—š Ÿœœœœœœ˜cKšœk˜kKšœ˜K˜—šŸœœœ/œ˜TšœœJ˜aKšœ(˜(—Kšœ˜—K˜šŸœœœœœ œœœ˜tšœK˜KKšœœœ œ˜6—Kšœ˜K˜—šŸ œœœ˜.Kšœ.œ˜3Kšœ˜K˜—šŸœœœ œœ#œœ˜uKšœ\˜\Kšœ˜K˜—šŸ œœœ˜.Kšœœ,˜MKšœ˜K˜—š Ÿœœœœœœ˜gKšœi˜iKšœ˜K˜—šŸœœœ˜6Kšœ$œ˜)Kšœ˜K˜—šŸœœ "˜MKšœœ ˜ Kšœ%˜%Kšœœ ˜Kšœ œ˜Kšœœ˜Kšœœœœ˜šœ7˜7Kšœ$™$—Kšœœ,˜9Kšœ˜š œœœ$œœ˜?Kšœ:˜:Kšœ˜Kšœ˜—K˜KšœP˜PK˜K˜—šŸœœ!˜9šœ œ˜šœ)˜)Kšœœ ˜Kšœ œ˜Kšœ œ˜Kšœœ ˜šœ:˜:Kšœ$™$—Kšœœ,˜9Kšœ˜š œœœ$œœ˜AKšœ:˜:Kšœ˜ —K˜-Kšœœœ&œ ˜OKšœœ˜—K˜—Kšœ˜—Kšœ œ˜Kšœ˜K˜—šŸœœœ˜2Kšœ.˜.Kšœ˜K˜—šŸœœœ˜2Kšœ.˜.Kšœ˜K˜—šŸœœœ˜:Kšœ1˜1Kšœ˜K˜—š Ÿ œœœœœœ˜IKšœœ&˜0Kšœ œœ˜+Kšœ!œœ œ˜SKšœC ˜YKšœ œ˜;K˜K˜—š Ÿ œœœœœœ˜Kšœ˜K˜—šŸœœ ˜CKšœœ&˜/Kš œ œœœœ˜(Kšœœœ˜6Kšœœ˜.Kšœ œœœ˜K˜Kšœ,œœœ˜ZK˜K˜—š Ÿ œœœœœ˜Cšœœ+˜6Kšœœœ˜Kšœ œ˜Kšœ œ˜Kšœ œœ/˜CKšœœœ˜;K˜+Kšœ œœœ˜Kšœœœ˜2Kšœœ  ˜DK˜%Kšœ-œ ˜Ošœ˜Kšœœ6˜>—šœœ˜Kšœ™Kšœœ˜ K˜Kšœ5˜5Kšœ œ !˜1Kšœ+œ˜0Kšœ ˜ Kšœ#˜#Kšœ˜—K˜—Kšœ)˜)Kšœ˜K˜—šŸ œœ œ>œ˜fšœ œ˜šœ œ˜šœ)˜)Kšœ)˜)Kšœ œ˜1Kšœ˜K˜—Kš˜—K˜—KšœD˜DK˜K˜—šŸ œœœ˜+Kšœ&œ˜+Kšœ˜K˜—šŸœœœœ˜;Kšœ&˜&Kšœ#˜)K˜K˜—šŸœœCœ˜dšœ ˜Kšœ)˜-šœ˜Kšœœ˜&Kšœœ˜šœ˜ Kšœ˜ šœ˜Kšœ˜Kšœœœ œ2˜LK˜——K˜——K˜K˜—šŸœœœ/œ˜UKšœ]˜]K˜K˜—šŸœœœ˜7Kšœ3˜3K˜K˜—K˜šœ˜Kšœ=˜=—šœ!˜!Kšœ=˜=—šœ#˜#Kšœ=˜=—šœ"˜"Kšœ=˜=—K˜—Kšœ˜K˜K˜—…—Š Αž