MODULE TextCmds; (* THIS IS TEXT COPY OF BlackBox Text/Mod/Cmds.odc *) (* DO NOT EDIT *) (* could eliminate ReplList/ReplOp and use Models.Begin/EndScript instead (as already done for shifting) *) (* move ListAlienViews to StdCmds and generalize accordingly? *) IMPORT Strings, Ports, Stores, Models, Views, Controllers, Properties, Dialog, Containers, TextModels, TextMappers, TextRulers, TextSetters, TextViews, TextControllers; CONST (* ShiftOp.left *) left = TRUE; right = FALSE; (* PreparePat, FindPat *) leftTerm = 3X; rightTerm = 4X; (* DoReplace mode *) replace = 0; replaceAndFind = 1; replaceAll = 2; (* FindIn first *) first = TRUE; again = FALSE; mm = Ports.mm; point = Ports.point; maxPat = 256; viewcode = TextModels.viewcode; tab = TextModels.tab; line = TextModels.line; para = TextModels.para; nbspace = TextModels.nbspace; digitspace = TextModels.digitspace; hyphen = TextModels.hyphen; nbhyphen = TextModels.nbhyphen; softhyphen = TextModels.softhyphen; posKey = "#Text:Position"; searchAliensKey = "#Text:SearchForAlienViews"; (* dormant code option *) alienTypeKey = "#Text:AlienViewType"; noAliensKey = "#Text:NoAlienViewsFound"; noRulerKey = "#Text:NoRulerSelected"; noMatchKey = "#Text:SelectionDoesNotMatch"; noTargetKey = "#Text:NoTargetFound"; noSelectionKey = "#Text:NoSelectionFound"; noPatternKey = "#Text:PatternNotSpecified"; notFoundKey = "#Text:PatternNotFound"; (* not used *) replacingKey = "#System:Replacing"; shiftingKey = "#Text:Shifting"; showMarksKey = "#Text:ShowMarks"; hideMarksKey = "#Text:HideMarks"; replaceSelectionKey = "#Text:ReplaceAllInSelection"; replaceAllKey = "#Text:ReplaceAll"; TYPE FindSpec = RECORD valid, ignoreCase, wordBeginsWith, wordEndsWith, reverse: BOOLEAN; start: INTEGER; find: ARRAY maxPat OF CHAR END; ReplList = POINTER TO RECORD next: ReplList; beg, end: INTEGER; buf: TextModels.Model END; ReplOp = POINTER TO RECORD (Stores.Operation) text: TextModels.Model; list, last: ReplList; find: FindSpec END; VAR find*: RECORD find*: ARRAY maxPat OF CHAR; replace*: ARRAY maxPat OF CHAR; ignoreCase*, wordBeginsWith*, wordEndsWith*: BOOLEAN; reverseOrientation*: BOOLEAN END; ruler*: RECORD pageBreaks*: RECORD notInside*, joinPara*: BOOLEAN END END; PROCEDURE Show (t: TextModels.Model; beg, end: INTEGER); BEGIN TextViews.ShowRange(t, beg, end, TextViews.focusOnly); IF beg = end THEN TextControllers.SetCaret(t, beg) ELSE TextControllers.SetSelection(t, beg, end) END END Show; PROCEDURE NoShow (t: TextModels.Model; pos: INTEGER); BEGIN TextControllers.SetSelection(t, pos, pos); TextControllers.SetCaret(t, pos) END NoShow; PROCEDURE Ruler (): TextRulers.Ruler; VAR r: TextRulers.Ruler; BEGIN r := TextRulers.dir.New(NIL); TextRulers.AddTab(r, 4*mm); TextRulers.AddTab(r, 20*mm); RETURN r END Ruler; (* search & replace *) PROCEDURE LeftTerminator (ch: CHAR): BOOLEAN; BEGIN IF ch < 100X THEN CASE ch OF viewcode, tab, line, para, " ", "(", "[", "{", "=", hyphen, softhyphen: RETURN TRUE ELSE RETURN FALSE END ELSE RETURN TRUE END END LeftTerminator; PROCEDURE RightTerminator (ch: CHAR): BOOLEAN; BEGIN IF ch < 100X THEN CASE ch OF 0X, viewcode, tab, line, para, " ", "!", "(", ")", ",", ".", ":", ";", "?", "[", "]", "{", "}", hyphen, softhyphen: RETURN TRUE ELSE RETURN FALSE END ELSE RETURN TRUE END END RightTerminator; PROCEDURE PreparePat (spec: FindSpec; VAR pat: ARRAY OF CHAR; VAR n: INTEGER; VAR wordBeg, wordEnd: BOOLEAN); VAR i: INTEGER; ch: CHAR; BEGIN i := 0; ch := spec.find[0]; wordBeg := spec.wordBeginsWith & ~LeftTerminator(ch); IF wordBeg THEN pat[0] := leftTerm; n := 1 ELSE n := 0 END; WHILE ch # 0X DO IF ch # softhyphen THEN IF spec.ignoreCase THEN pat[n] := Strings.Upper(ch) ELSE pat[n] := ch END; INC(n) END; INC(i); ch := spec.find[i] END; wordEnd := spec.wordEndsWith & ~RightTerminator(pat[n - 1]); IF wordEnd THEN pat[n] := rightTerm; INC(n) END END PreparePat; PROCEDURE FindPat (t: TextModels.Model; spec: FindSpec; VAR beg, end: INTEGER); (* post: beg < end => t[beg, end) = spec.find, start <= beg; else beg = end *) VAR r: TextModels.Reader; start: INTEGER; i, j, b, e, n: INTEGER; ch0, ch, ch1: CHAR; wordBeg, wordEnd, icase: BOOLEAN; pat, ref: ARRAY maxPat OF CHAR; (* ref [b..e) is readback buffer *) pos0, pos1, absStart: INTEGER; orientation: INTEGER; BEGIN IF spec.reverse THEN orientation := -1; absStart := t.Length(); PreparePat(spec, ref, n, wordEnd, wordBeg); i := n; j := 0; REPEAT DEC(i); pat[j] := ref[i]; INC(j) UNTIL i = 0 (* Just reverse the pattern... *) ELSE orientation := 1; absStart := 0; PreparePat(spec, pat, n, wordBeg, wordEnd) END; start := spec.start; icase := spec.ignoreCase; r := t.NewReader(NIL); i := 0; IF wordBeg THEN IF start # absStart THEN DEC(start, orientation) ELSE r.SetPos(absStart); IF spec.reverse THEN r.ReadPrevChar(ch) ELSE r.ReadChar(ch) END; IF ~LeftTerminator(ch) THEN i := 1 END END END; r.SetPos(start); IF spec.reverse THEN r.ReadPrevChar(ch) ELSE r.ReadChar(ch) END; pos0 := start; pos1 := start; IF icase THEN ch := Strings.Upper(ch) END; ref[0] := ch; ch0 := ch; j := 0; b := 0; e := 1; WHILE ~r.eot & (i < n) DO ch1 := pat[i]; IF (ch1 = ch) OR (ch1 = leftTerm) & LeftTerminator(ch) OR (ch1 = rightTerm) & RightTerminator(ch) THEN INC(i); j := (j + 1) MOD maxPat ELSIF ch = softhyphen THEN j := (j + 1) MOD maxPat ELSE i := 0; INC(pos0, orientation); b := (b + 1) MOD maxPat; j := b END; IF j # e THEN ch := ref[j] ELSE INC(pos1, orientation); IF spec.reverse THEN r.ReadPrevChar(ch) ELSE r.ReadChar(ch) END; IF icase THEN ch := Strings.Upper(ch) END; ref[j] := ch; e := (e + 1) MOD maxPat END END; IF wordEnd & ~((i + 1 = n) & r.eot) THEN DEC(pos1, orientation) END; IF (n > 0) & ((i = n) OR wordEnd & (i + 1 = n) & r.eot) THEN IF wordBeg & ((pos0 # absStart) OR LeftTerminator(ch0)) THEN INC(pos0, orientation) END ELSE pos0 := pos1 END; IF spec.reverse THEN beg := pos1; end := pos0 ELSE beg := pos0; end := pos1 END END FindPat; PROCEDURE OverrideSpecWithOption (VAR spec: FindSpec; option: ARRAY OF CHAR); VAR i: INTEGER; choice: BOOLEAN; ch: CHAR; BEGIN choice := TRUE; i := 0; ch := option[i]; WHILE ch # 0X DO CASE option[i] OF '~': choice := ~choice | 'I', 'i': spec.ignoreCase := choice; choice := TRUE | 'B', 'b': spec.wordBeginsWith := choice; choice := TRUE | 'E', 'e': spec.wordEndsWith := choice; choice := TRUE | 'R', 'r': spec.reverse := choice; choice := TRUE ELSE choice := TRUE END; INC(i); ch := option[i] END END OverrideSpecWithOption; PROCEDURE SetSpec (VAR spec: FindSpec; pos0, pos1: INTEGER; option: ARRAY OF CHAR); BEGIN ASSERT(find.find # "", 20); spec.valid := TRUE; spec.ignoreCase := find.ignoreCase; spec.wordBeginsWith := find.wordBeginsWith; spec.wordEndsWith := find.wordEndsWith; spec.reverse := find.reverseOrientation; OverrideSpecWithOption(spec, option); IF spec.reverse THEN spec.start := pos1 ELSE spec.start := pos0 END; spec.find := find.find$ END SetSpec; PROCEDURE SetFindSpec (c: TextControllers.Controller; first: BOOLEAN; option: ARRAY OF CHAR; VAR spec: FindSpec ); VAR (*start,*) pos0, pos1, beg, end: INTEGER; BEGIN IF first THEN pos0 := 0; pos1 := pos0 ELSIF c.HasCaret() THEN pos0 := c.CaretPos(); pos1 := pos0 ELSIF c.HasSelection() THEN c.GetSelection(beg, end); pos0 := beg + 1; pos1 := end - 1 ELSE pos0 := 0; pos1 := pos0 END; SetSpec(spec, pos0, pos1, option); IF spec.reverse THEN IF spec.start = 0 THEN spec.start := c.text.Length() END ELSE IF spec.start = c.text.Length() THEN spec.start := 0 END END END SetFindSpec; PROCEDURE ReplBuf (target: TextModels.Model; pos: INTEGER): TextModels.Model; VAR buf: TextModels.Model; attr: TextModels.Attributes; rd: TextModels.Reader; out: TextModels.Writer; i: INTEGER; BEGIN rd := target.NewReader(NIL); rd.SetPos(pos); rd.ReadRun(attr); buf := TextModels.CloneOf(target); out := buf.NewWriter(NIL); out.SetPos(0); IF attr # NIL THEN out.SetAttr(attr) END; i := 0; WHILE find.replace[i] # 0X DO out.WriteChar(find.replace[i]); INC(i) END; RETURN buf END ReplBuf; (* operations *) PROCEDURE (op: ReplOp) Do; VAR u, v: ReplList; text, save: TextModels.Model; beg, end, delta, len: INTEGER; BEGIN text := op.text; u := op.list; v := NIL; delta := 0; WHILE u # NIL DO INC(u.beg, delta); INC(u.end, delta); IF u.end > u.beg THEN save := TextModels.CloneOf(text); save.Insert(0, text, u.beg, u.end); DEC(delta, u.end - u.beg) ELSE save := NIL END; IF u.buf # NIL THEN len := u.buf.Length(); text.Insert(u.beg, u.buf, 0, len); u.end := u.beg + len; INC(delta, len) ELSE u.end := u.beg END; u.buf := save; v := u; u := u.next END; IF op.find.valid THEN FindPat(text, op.find, beg, end); op.find.valid := FALSE; IF beg = end THEN Dialog.Beep END ELSIF v # NIL THEN beg := v.beg; end := v.end ELSE beg := 0; end := 0 END; IF end > beg THEN Show(text, beg, end) ELSE NoShow(text, beg) END END Do; PROCEDURE AddRepl (op: ReplOp; beg, end: INTEGER; reverse: BOOLEAN); VAR u: ReplList; BEGIN NEW(u); u.beg := beg; u.end := end; u.buf := ReplBuf(op.text, beg); IF reverse THEN (* append *) u.next := op.list; op.list := u ELSE (* prepend *) IF op.list = NIL THEN op.list := u ELSE op.last.next := u END; op.last := u END END AddRepl; PROCEDURE DoReplaceThis ( t: TextModels.Model; mode: INTEGER; firstBeg, firstEnd: INTEGER; rngBeg, rngEnd: INTEGER; option: ARRAY OF CHAR ); VAR op: ReplOp; spec: FindSpec; beg, end, len: INTEGER; BEGIN NEW(op); op.text := t; op.list := NIL; beg := firstBeg; end := firstEnd; IF mode IN {replace, replaceAndFind} THEN AddRepl(op, firstBeg, firstEnd, spec.reverse) END; IF mode = replaceAndFind THEN SetSpec(op.find, firstBeg + (* LEN(find.replace$) *) ReplBuf(t, 0).Length(), firstBeg, option) ELSE op.find.valid := FALSE END; IF mode = replaceAll THEN len := LEN(find.find$); SetSpec(spec, 0, t.Length(), option); WHILE (rngBeg <= beg) & (beg < end) & (end <= rngEnd) DO AddRepl(op, beg, end, spec.reverse); IF spec.reverse THEN spec.start := beg ELSE spec.start := beg + len END; FindPat(t, spec, beg, end) END END; Models.Do(t, replacingKey, op) END DoReplaceThis; PROCEDURE DoReplace (c: TextControllers.Controller; mode: INTEGER; option: ARRAY OF CHAR); VAR t: TextModels.Model; spec: FindSpec; selBeg, selEnd, beg, end, len0: INTEGER; hasSel0: BOOLEAN; BEGIN IF c # NIL THEN t := c.text; len0 := t.Length(); hasSel0 := c.HasSelection(); IF hasSel0 THEN c.GetSelection(selBeg, selEnd); IF selEnd < len0 THEN SetSpec(spec, selBeg, selEnd + 1, option) ELSE SetSpec(spec, selBeg, selEnd, option) END ELSE selBeg := 0; selEnd := len0; SetFindSpec(c, (* again *) mode = replaceAll, option, spec) END; FindPat(t, spec, beg, end); IF mode = replaceAll THEN IF (selBeg <= beg) & (beg < end) & (end <= selEnd) THEN DoReplaceThis(t, mode, beg, end, selBeg, selEnd, option); IF hasSel0 THEN Show(c.text, selBeg, selEnd + t.Length() - len0) END ELSE NoShow(c.text, 0); Dialog.Beep END ELSIF hasSel0 THEN IF (beg = selBeg) & (end = selEnd) THEN DoReplaceThis(t, mode, selBeg, selEnd, 0, len0, option) ELSE Dialog.ShowParamMsg(noMatchKey, spec.find, "", "") END ELSE Dialog.ShowMsg(noSelectionKey) END ELSE Dialog.ShowMsg(noTargetKey) END END DoReplace; PROCEDURE DoShift (c: TextControllers.Controller; left: BOOLEAN); VAR script: Stores.Operation; t: TextModels.Model; st: TextSetters.Setter; rd: TextModels.Reader; wr: TextModels.Writer; box: TextSetters.LineBox; beg, pos, end: INTEGER; ch: CHAR; BEGIN IF (c # NIL) & (c.HasSelection() OR c.HasCaret()) THEN t := c.text; IF c.HasSelection() THEN c.GetSelection(beg, end) ELSE beg := c.CaretPos(); end := beg END; st := c.view.ThisSetter(); beg := st.ThisSequence(beg); pos := beg; rd := t.NewReader(NIL); rd.SetPos(pos); IF ~left THEN wr := t.NewWriter(NIL) END; Models.BeginScript(t, shiftingKey, script); REPEAT rd.ReadChar(ch); IF rd.view # NIL THEN st.GetLine(pos, box); IF box.rbox THEN ch := para END END; IF left & ((ch = tab) OR (ch = " ") OR (ch = digitspace) OR (ch = nbspace)) THEN t.Delete(pos, pos + 1); rd.SetPos(pos); DEC(end) ELSIF ~left & (ch # line) & (ch # para) THEN wr.SetPos(pos); IF (ch = " ") OR (ch = digitspace) OR (ch = nbspace) THEN wr.WriteChar(ch) ELSE wr.WriteChar(tab) END; INC(pos); INC(end) ELSE INC(pos) END; WHILE ~rd.eot & (ch # line) & (ch # para) DO INC(pos); rd.ReadChar(ch) END UNTIL rd.eot OR (pos >= end); Models.EndScript(t, script); IF end > beg THEN TextControllers.SetSelection(t, beg, end) END END END DoShift; (** commands **) PROCEDURE ListAlienViews*; VAR t: TextModels.Model; v: TextViews.View; wr: TextMappers.Formatter; rd: TextModels.Reader; view: Views.View; type: Stores.TypeName; none: BOOLEAN; BEGIN t := TextViews.FocusText(); IF t # NIL THEN wr.ConnectTo(TextModels.dir.New()); rd := t.NewReader(NIL); rd.ReadView(view); none := TRUE; WHILE view # NIL DO IF view IS Views.Alien THEN IF none THEN wr.WriteTab; wr.WriteMsg(posKey); wr.WriteTab; wr.WriteMsg(alienTypeKey); wr.WriteLn END; none := FALSE; type := view(Views.Alien).store.path[0]$; wr.WriteTab; wr.WriteIntForm(rd.Pos() - 1, TextMappers.decimal, 5, nbspace, TextMappers.hideBase); wr.WriteTab; wr.WriteString(type); wr.WriteLn END; rd.ReadView(view) END; IF none THEN wr.WriteString(noAliensKey); wr.WriteLn END; v := TextViews.dir.New(wr.rider.Base()); v.SetDefaults(Ruler(), TextViews.dir.defAttr); Views.OpenView(v) END END ListAlienViews; PROCEDURE ToggleMarksGuard* (VAR par: Dialog.Par); VAR v: TextViews.View; BEGIN v := TextViews.Focus(); IF (v # NIL) & v.HidesMarks() THEN par.label := showMarksKey ELSE par.label := hideMarksKey END END ToggleMarksGuard; PROCEDURE ToggleMarks*; VAR v: TextViews.View; BEGIN v := TextViews.Focus(); IF v # NIL THEN v.DisplayMarks(~v.HidesMarks()) END END ToggleMarks; PROCEDURE ShowMarks*; VAR v: TextViews.View; BEGIN v := TextViews.Focus(); IF (v # NIL) & v.HidesMarks() THEN v.DisplayMarks(TextViews.show) END END ShowMarks; PROCEDURE HideMarks*; VAR v: TextViews.View; BEGIN v := TextViews.Focus(); IF (v # NIL) & ~v.HidesMarks() THEN v.DisplayMarks(TextViews.hide) END END HideMarks; PROCEDURE MakeDefaultRulerGuard* (VAR par: Dialog.Par); VAR c: TextControllers.Controller; v: Views.View; BEGIN c := TextControllers.Focus(); IF c # NIL THEN v := c.Singleton(); IF (v = NIL) OR ~(v IS TextRulers.Ruler) THEN par.disabled := TRUE END ELSE par.disabled := TRUE END END MakeDefaultRulerGuard; PROCEDURE MakeDefaultRuler*; VAR c: TextControllers.Controller; rd: TextModels.Reader; r: TextRulers.Ruler; a: TextModels.Attributes; beg, end: INTEGER; BEGIN c := TextControllers.Focus(); IF c # NIL THEN IF c.HasSelection() THEN c.GetSelection(beg, end); rd := c.text.NewReader(NIL); rd.SetPos(beg); rd.Read; IF (rd.view # NIL) & (rd.view IS TextRulers.Ruler) THEN c.view.PollDefaults(r, a); c.view.SetDefaults(rd.view(TextRulers.Ruler), a) ELSE Dialog.ShowMsg(noRulerKey) END ELSE Dialog.ShowMsg(noSelectionKey) END ELSE Dialog.ShowMsg(noTargetKey) END END MakeDefaultRuler; PROCEDURE MakeDefaultAttributes*; VAR c: TextControllers.Controller; rd: TextModels.Reader; r: TextRulers.Ruler; a: TextModels.Attributes; beg, end: INTEGER; BEGIN c := TextControllers.Focus(); IF c # NIL THEN IF c.HasSelection() THEN c.GetSelection(beg, end); rd := c.text.NewReader(NIL); rd.SetPos(beg); rd.Read; c.view.PollDefaults(r, a); c.view.SetDefaults(r, rd.attr) ELSE Dialog.ShowMsg(noSelectionKey) END ELSE Dialog.ShowMsg(noTargetKey) END END MakeDefaultAttributes; PROCEDURE ShiftLeft*; BEGIN DoShift(TextControllers.Focus(), left) END ShiftLeft; PROCEDURE ShiftRight*; BEGIN DoShift(TextControllers.Focus(), right) END ShiftRight; PROCEDURE Subscript*; VAR q, p0: Properties.Property; p: TextModels.Prop; BEGIN Properties.CollectProp(q); p0 := q; WHILE (p0 # NIL) & ~(p0 IS TextModels.Prop) DO p0 := p0.next END; NEW(p); p.valid := {TextModels.offset}; IF (p0 # NIL) & (TextModels.offset IN p0.valid) THEN p.offset := p0(TextModels.Prop).offset - point ELSE p.offset := -point END; Properties.EmitProp(NIL, p) END Subscript; PROCEDURE Superscript*; VAR q, p0: Properties.Property; p: TextModels.Prop; BEGIN Properties.CollectProp(q); p0 := q; WHILE (p0 # NIL) & ~(p0 IS TextModels.Prop) DO p0 := p0.next END; NEW(p); p.valid := {TextModels.offset}; IF (p0 # NIL) & (TextModels.offset IN p0.valid) THEN p.offset := p0(TextModels.Prop).offset + point ELSE p.offset := point END; Properties.EmitProp(NIL, p) END Superscript; PROCEDURE ForceToNewLine (c: TextControllers.Controller); VAR st: TextSetters.Setter; pos, start: INTEGER; msg: Controllers.EditMsg; BEGIN IF c.HasCaret() THEN pos := c.CaretPos(); st := c.view.ThisSetter(); start := st.ThisLine(pos); IF pos # start THEN msg.op := Controllers.pasteChar; msg.char := line; Controllers.Forward(msg) END END END ForceToNewLine; PROCEDURE InsertParagraph*; VAR c: TextControllers.Controller; script: Stores.Operation; msg: Controllers.EditMsg; BEGIN c := TextControllers.Focus(); IF c # NIL THEN Models.BeginScript(c.text, "#Text:InsertParagraph", script); ForceToNewLine(c); msg.op := Controllers.pasteChar; msg.char := para; Controllers.Forward(msg); Models.EndScript(c.text, script) END END InsertParagraph; PROCEDURE InsertRuler*; VAR c: TextControllers.Controller; script: Stores.Operation; rd: TextModels.Reader; r: TextRulers.Ruler; pos, end: INTEGER; BEGIN c := TextControllers.Focus(); IF c # NIL THEN r := NIL; IF c.HasSelection() THEN c.GetSelection(pos, end); rd := c.text.NewReader(NIL); rd.SetPos(pos); rd.Read; IF (rd.view # NIL) & (rd.view IS TextRulers.Ruler) THEN r := rd.view(TextRulers.Ruler) END ELSE pos := c.CaretPos() END; IF r = NIL THEN r := TextViews.ThisRuler(c.view, pos) END; r := TextRulers.CopyOf(r, Views.deep); Models.BeginScript(c.text, "#Text:InsertRuler", script); ForceToNewLine(c); c.view.DisplayMarks(TextViews.show); Controllers.PasteView(r, Views.undefined, Views.undefined, FALSE); Models.EndScript(c.text, script) END END InsertRuler; PROCEDURE InsertSoftHyphen*; VAR msg: Controllers.EditMsg; BEGIN msg.op := Controllers.pasteChar; msg.char := softhyphen; Controllers.Forward(msg) END InsertSoftHyphen; PROCEDURE InsertNBHyphen*; VAR msg: Controllers.EditMsg; BEGIN msg.op := Controllers.pasteChar; msg.char := nbhyphen; Controllers.Forward(msg) END InsertNBHyphen; PROCEDURE InsertNBSpace*; VAR msg: Controllers.EditMsg; BEGIN msg.op := Controllers.pasteChar; msg.char := nbspace; Controllers.Forward(msg) END InsertNBSpace; PROCEDURE InsertDigitSpace*; VAR msg: Controllers.EditMsg; BEGIN msg.op := Controllers.pasteChar; msg.char := digitspace; Controllers.Forward(msg) END InsertDigitSpace; PROCEDURE GetFindPattern (c: TextControllers.Controller); VAR r: TextModels.Reader; beg, end: INTEGER; i: INTEGER; ch: CHAR; new: ARRAY maxPat OF CHAR; BEGIN IF (c # NIL) & c.HasSelection() THEN c.GetSelection(beg, end); r := c.text.NewReader(NIL); r.SetPos(beg); r.ReadChar(ch); i := 0; WHILE (r.Pos() <= end) & (i < maxPat - 1) DO new[i] := ch; INC(i); r.ReadChar(ch) END; new[i] := 0X; IF (new # "") & (new # find.find) THEN find.find := new$; find.ignoreCase := FALSE; find.wordBeginsWith := FALSE; find.wordEndsWith := FALSE; Dialog.Update(find) END END END GetFindPattern; PROCEDURE FindIn (c: TextControllers.Controller; first: BOOLEAN; option: ARRAY OF CHAR); VAR spec: FindSpec; beg, end: INTEGER; BEGIN IF c # NIL THEN IF find.find # "" THEN SetFindSpec(c, first, option, spec); FindPat(c.text, spec, beg, end); IF end > beg THEN Show(c.text, beg, end) ELSE NoShow(c.text, 0); Dialog.Beep END ELSE Dialog.ShowMsg(noPatternKey) END ELSE Dialog.ShowMsg(noTargetKey) END END FindIn; PROCEDURE FindGuard* (VAR par: Dialog.Par); VAR c: TextControllers.Controller; BEGIN c := TextControllers.Focus(); IF (c = NIL) OR (find.find = "") THEN par.disabled := TRUE END END FindGuard; PROCEDURE FindFirst* (option: ARRAY OF CHAR); BEGIN FindIn(TextControllers.Focus(), first, option) END FindFirst; PROCEDURE FindAgainGuard* (VAR par: Dialog.Par); VAR c: TextControllers.Controller; BEGIN c := TextControllers.Focus(); IF (c = NIL) OR (~c.HasSelection() & (find.find = "")) THEN par.disabled := TRUE END END FindAgainGuard; PROCEDURE FindAgain* (option: ARRAY OF CHAR); BEGIN FindIn(TextControllers.Focus(), again, option) END FindAgain; PROCEDURE ReplaceGuard* (VAR par: Dialog.Par); VAR c: TextControllers.Controller; BEGIN c := TextControllers.Focus(); IF (c = NIL) OR (Containers.noCaret IN c.opts) OR ~c.HasSelection() OR (find.find = "") THEN par.disabled := TRUE END END ReplaceGuard; PROCEDURE Replace* (option: ARRAY OF CHAR); BEGIN DoReplace(TextControllers.Focus(), replace, option) END Replace; PROCEDURE ReplaceAndFindNext* (option: ARRAY OF CHAR); BEGIN DoReplace(TextControllers.Focus(), replaceAndFind, option) END ReplaceAndFindNext; PROCEDURE ReplaceAllGuard* (VAR par: Dialog.Par); VAR c: TextControllers.Controller; BEGIN c := TextControllers.Focus(); IF (c = NIL) OR (Containers.noCaret IN c.opts) OR (find.find = "") THEN par.disabled := TRUE ELSE IF c.HasSelection() THEN par.label := replaceSelectionKey ELSE par.label := replaceAllKey END END END ReplaceAllGuard; PROCEDURE ReplaceAll* (option: ARRAY OF CHAR); BEGIN DoReplace(TextControllers.Focus(), replaceAll, option) END ReplaceAll; PROCEDURE SetNormalOrientation*; BEGIN find.reverseOrientation := FALSE; Dialog.Update(find) END SetNormalOrientation; PROCEDURE SetReverseOrientation*; BEGIN find.reverseOrientation := TRUE; Dialog.Update(find) END SetReverseOrientation; PROCEDURE InitFindDialog*; BEGIN GetFindPattern(TextControllers.Focus()) END InitFindDialog; (** ruler dialog **) PROCEDURE InitRulerDialog*; VAR v: Views.View; ra: TextRulers.Attributes; BEGIN v := Controllers.FocusView(); IF v # NIL THEN WITH v: TextRulers.Ruler DO ra := v.style.attr; ruler.pageBreaks.notInside := TextRulers.noBreakInside IN ra.opts; ruler.pageBreaks.joinPara := TextRulers.parJoin IN ra.opts ELSE END END END InitRulerDialog; PROCEDURE SetRuler*; VAR v: Views.View; p: TextRulers.Prop; BEGIN v := Controllers.FocusView(); IF v # NIL THEN WITH v: TextRulers.Ruler DO NEW(p); p.valid := {TextRulers.opts}; p.opts.mask := {TextRulers.noBreakInside, TextRulers.parJoin}; p.opts.val := {}; IF ruler.pageBreaks.notInside THEN INCL(p.opts.val, TextRulers.noBreakInside) END; IF ruler.pageBreaks.joinPara THEN INCL(p.opts.val, TextRulers.parJoin) END; Properties.EmitProp(NIL, p) ELSE END END END SetRuler; (** standard text-related guards **) PROCEDURE FocusGuard* (VAR par: Dialog.Par); (** in non-TextView menus; otherwise implied by menu type **) BEGIN IF TextViews.Focus() = NIL THEN par.disabled := TRUE END END FocusGuard; PROCEDURE EditGuard* (VAR par: Dialog.Par); (** in non-TextView menus; otherwise use "StdCmds.EditGuard" **) VAR c: TextControllers.Controller; BEGIN c := TextControllers.Focus(); IF (c = NIL) OR (Containers.noCaret IN c.opts) THEN par.disabled := TRUE END END EditGuard; PROCEDURE SelectionGuard* (VAR par: Dialog.Par); (** in non-TextView menus; otherwise use "StdCmds.SelectionGuard" **) VAR c: TextControllers.Controller; BEGIN c := TextControllers.Focus(); IF (c = NIL) OR ~c.HasSelection() THEN par.disabled := TRUE END END SelectionGuard; PROCEDURE EditSelectionGuard* (VAR par: Dialog.Par); (** in non-TextView menus; otherwise use "StdCmds.SelectionGuard" **) VAR c: TextControllers.Controller; BEGIN c := TextControllers.Focus(); IF (c = NIL) OR (Containers.noCaret IN c.opts) OR ~c.HasSelection() THEN par.disabled := TRUE END END EditSelectionGuard; PROCEDURE SingletonGuard* (VAR par: Dialog.Par); (** in non-TextView menus; otherwise use "StdCmds.SingletonGuard" **) VAR c: TextControllers.Controller; BEGIN c := TextControllers.Focus(); IF (c = NIL) OR (c.Singleton() = NIL) THEN par.disabled := TRUE END END SingletonGuard; END TextCmds.