<> <> <> <> <> <<>> DIRECTORY EditToolPrivate, EditToolBuilder, Atom, Buttons, EditSpan, Labels, MessageWindow, NameSymbolTable, NodeProps, NodeStyle, Process, Rope, RopeEdit, TextEdit, TextFind, TextLooks, TextNode, TreeFind, TEditDocument, TEditInput, TEditInputOps, TEditLocks, TEditOps, TEditRefresh, TEditSelection, ViewerClasses, ViewerOps; EditToolMiscImpl: CEDAR PROGRAM IMPORTS EditToolPrivate, EditToolBuilder, Atom, TEditOps, Labels, MessageWindow, NameSymbolTable, NodeProps, NodeStyle, Process, Rope, RopeEdit, TextEdit, TextFind, TextNode, TEditSelection, TEditRefresh, TEditInput, TEditInputOps, TEditLocks, TreeFind, ViewerOps EXPORTS EditToolPrivate = { OPEN EditToolPrivate, EditToolBuilder; ---------------------------- BuildPropertyButtons: PUBLIC PROC [info: Info] = { OPEN info; [,propNameArg] _ BuildDataFieldPair[layout, "Property name:", PropNameArgButton, info, 1]; VGap[layout]; [,propValueArg] _ BuildDataFieldPair[layout, "Property value:", PropValueArgButton, info, 1]; VGap[layout]; propNode _ selection; [] _ BuildButton[layout, "Get", GetPropButton, info]; [] _ BuildButton[layout, "Set", SetPropButton, info]; [] _ BuildButton[layout, "Remove", RemovePropButton, info]; [] _ BuildButton[layout, "List", ListPropsButton, info]; ToMiddle[layout]; [propNodeLabel,] _ BuildPair[layout,PropNodeButton,propNode,selectionNameRope,rootNameRope,info]; ToNext[layout]; [] _ BuildButton[layout, "Find", FindPropButton, info]; HGap[layout]; [,propPatternArg] _ BuildDataFieldPair[layout, "Value pattern:", PropPatternArgButton, info, 1]; }; ---------------------------- BuildStyleButtons: PUBLIC PROC [info: Info] = { OPEN info; [,styleNameArg] _ BuildDataFieldPair[layout, "Style name:", StyleNameArgButton, info, 1]; VGap[layout]; styleNode _ root; [] _ BuildButton[layout, "Get", GetStyleNameButton, info]; [] _ BuildButton[layout, "Set", SetStyleNameButton, info]; [] _ BuildButton[layout, "Clear", ClearStyleNameButton, info]; ToMiddle[layout]; [styleNodeLabel,] _ BuildPair[layout,StyleNameNodeButton,styleNode, selectionNameRope,rootNameRope,info]; ToNext[layout]; [] _ BuildButton[layout, "LoadStyleDefinition", LoadStyleButton, info]; [] _ BuildButton[layout, "LoadAbbreviations", LoadAbbreviationsButton, info]; }; ---------------------------- BuildTypeButtons: PUBLIC PROC [info: Info] = { OPEN info; [,typeNameArg] _ BuildDataFieldPair[layout, "Format name:", TypeNameArgButton, info, 1]; VGap[layout]; typeNode _ selection; [] _ BuildButton[layout, "Get", GetTypeNameButton, info]; [] _ BuildButton[layout, "Set", SetTypeNameButton, info]; [] _ BuildButton[layout, "Clear", ClearTypeNameButton, info]; ToMiddle[layout]; [typeNodeLabel,] _ BuildPair[layout,TypeNameNodeButton, typeNode,selectionNameRope,rootNameRope,info]; }; ---------------------------- BadName: ERROR = CODE; GetNameArg: PROC [arg: ViewerClasses.Viewer] RETURNS [name: Rope.ROPE] = { Bad: PROC = { OPEN MessageWindow; Append["Enter name consisting of one or more alphanumeric characters.", TRUE]; Blink[]; ERROR BadName }; start, end, size: INT _ 0; rope: Rope.ROPE _ TextEdit.GetRope[GetDataNode[arg]]; end _ size _ Rope.Size[rope]; FOR i:INT IN [0..size) DO -- skip to first nonblank IF ~RopeEdit.BlankChar[Rope.Fetch[rope,i]] THEN { start _ i; EXIT }; ENDLOOP; FOR i:INT IN (start..size) DO -- count the AlphaNumericChar's IF ~RopeEdit.AlphaNumericChar[Rope.Fetch[rope,i]] THEN { end _ i; EXIT }; ENDLOOP; IF end=start THEN Bad[]; name _ Rope.Substr[rope,start,end-start]; FOR i:INT IN (end..size) DO -- check that rest is blanks IF ~RopeEdit.BlankChar[Rope.Fetch[rope,i]] THEN Bad[]; ENDLOOP; }; ForEachNode: PROC [ nodeKind: NodeKind, pSel: TEditDocument.Selection, proc: PROC [TextNode.Ref]] = { SELECT nodeKind FROM root => proc[TextNode.Root[pSel.start.pos.node]]; selection => FOR node: TextNode.Ref _ pSel.start.pos.node, TextNode.StepForward[node] DO proc[node]; IF node = pSel.end.pos.node THEN EXIT; ENDLOOP; ENDCASE => ERROR }; SetNodeName: PROC [ info: Info, name: Rope.ROPE, style: BOOLEAN, pSel: TEditDocument.Selection] = { Set: PROC [node: TextNode.Ref] = { IF style THEN TEditInputOps.SetStyleName[name, node] ELSE TEditInputOps.SetTypeName[name, node] }; ForEachNode[IF style THEN info.styleNode ELSE info.typeNode, pSel, Set] }; ---------------------------- styleNameArgAtom: LIST OF REF = Register[$StyleName,StyleNameArgOp]; clearStyleNameArgAtom: LIST OF REF = Register[$ClearStyleName,ClearStyleNameArgOp]; StyleNameArgButton: Buttons.ButtonProc = { DoButton[styleNameArgAtom, clearStyleNameArgAtom, mouseButton=red] }; StyleNameArgOp: TEditInput.CommandProc = { DataFieldButton[mainToolInfo.styleNameArg,FALSE] }; ClearStyleNameArgOp: TEditInput.CommandProc = { DataFieldButton[mainToolInfo.styleNameArg,TRUE] }; ---------------------------- typeNameArgAtom: LIST OF REF = Register[$TypeName,TypeNameArgOp]; clearTypeNameArgAtom: LIST OF REF = Register[$ClearTypeName,ClearTypeNameArgOp]; TypeNameArgButton: Buttons.ButtonProc = { DoButton[typeNameArgAtom,clearTypeNameArgAtom, mouseButton=red] }; TypeNameArgOp: TEditInput.CommandProc = { DataFieldButton[mainToolInfo.typeNameArg,FALSE] }; ClearTypeNameArgOp: TEditInput.CommandProc = { DataFieldButton[mainToolInfo.typeNameArg,TRUE] }; ---------------------------- getStyleNameAtom: LIST OF REF = Register[$GetNodeStyleName,GetStyleNameOp]; GetStyleNameButton: Buttons.ButtonProc = { DoButton[getStyleNameAtom] }; GetStyleNameOp: TEditInput.CommandProc = { GetStyleNameCom[mainToolInfo] }; GetStyleNameCom: PROC [info: Info] = { GetNameCom[info,TRUE] }; getTypeNameAtom: LIST OF REF = Register[$GetNodeTypeName,GetTypeNameOp]; GetTypeNameButton: Buttons.ButtonProc = { DoButton[getTypeNameAtom] }; GetTypeNameOp: TEditInput.CommandProc = { GetTypeNameCom[mainToolInfo] }; GetTypeNameCom: PROC [info: Info] = { GetNameCom[info,FALSE] }; NotUniform: SIGNAL = CODE; GetNameCom: PROC [info: Info, style: BOOLEAN] = { OPEN info; pSel: TEditDocument.Selection = TEditOps.GetSelData[]; nodeKind: NodeKind _ IF style THEN info.styleNode ELSE info.typeNode; name: NameSymbolTable.Name _ NameSymbolTable.nullName; arg: ViewerClasses.Viewer _ IF style THEN info.styleNameArg ELSE info.typeNameArg; Get: PROC [node: TextNode.Ref] = { n: NameSymbolTable.Name _ IF style THEN NodeStyle.StyleNameForNode[node] ELSE node.typename; IF name = NameSymbolTable.nullName THEN name _ n ELSE IF name # n THEN { OPEN MessageWindow; Append[IF style THEN "Nodes don't have uniform style. Using first." ELSE "Nodes don't have uniform format. Using first.", TRUE]; Blink[]; SIGNAL NotUniform }}; IF ~CheckPSel[pSel] THEN RETURN; ForEachNode[nodeKind, pSel, Get ! NotUniform => CONTINUE]; TEditOps.SetTextContents[arg, NameSymbolTable.RopeFromName[name]]; }; ---------------------------- setStyleNameAtom: LIST OF REF = Register[$SetNodeStyleName,SetStyleNameOp]; SetStyleNameButton: Buttons.ButtonProc = { DoButton[setStyleNameAtom] }; SetStyleNameOp: TEditInput.CommandProc = { SetStyleNameCom[mainToolInfo] }; SetStyleNameCom: PROC [info: Info] = { SetNameCom[info,TRUE] }; setTypeNameAtom: LIST OF REF = Register[$SetNodeTypeName,SetTypeNameOp]; SetTypeNameButton: Buttons.ButtonProc = { DoButton[setTypeNameAtom] }; SetTypeNameOp: TEditInput.CommandProc = { SetTypeNameCom[mainToolInfo] }; SetTypeNameCom: PROC [info: Info] = { SetNameCom[info,FALSE] }; SetNameCom: PROC [info: Info, style: BOOLEAN] = { pSel: TEditDocument.Selection; arg: ViewerClasses.Viewer _ IF style THEN info.styleNameArg ELSE info.typeNameArg; name: Rope.ROPE _ GetNameArg[arg ! BadName => GOTO Bad]; TEditSelection.LockSel[primary, "SetNameCom"]; pSel _ TEditOps.GetSelData[]; IF ~CheckPSel[pSel] OR ~TEditInputOps.CheckReadonly[pSel] THEN { TEditSelection.UnlockSel[primary]; RETURN }; SetNodeName[info,name,style,pSel]; TEditSelection.UnlockSel[primary]; EXITS Bad => RETURN }; ---------------------------- clearTypeNameAtom: LIST OF REF = Register[$ClearNodeTypeName,ClearTypeNameOp]; ClearTypeNameButton: Buttons.ButtonProc = { DoButton[clearTypeNameAtom] }; ClearTypeNameOp: TEditInput.CommandProc = { ClearTypeNameCom[mainToolInfo] }; ClearTypeNameCom: PROC [info: Info] = { pSel: TEditDocument.Selection = TEditOps.GetSelData[]; IF ~CheckPSel[pSel] THEN RETURN; IF ~TEditInputOps.CheckReadonly[pSel] THEN RETURN; SetNodeName[info,NIL,FALSE,pSel] }; clearStyleNameAtom: LIST OF REF = Register[$ClearNodeStyleName,ClearStyleNameOp]; ClearStyleNameButton: Buttons.ButtonProc = { DoButton[clearStyleNameAtom] }; ClearStyleNameOp: TEditInput.CommandProc = { ClearStyleNameCom[mainToolInfo] }; ClearStyleNameCom: PROC [info: Info] = { pSel: TEditDocument.Selection = TEditOps.GetSelData[]; IF ~CheckPSel[pSel] THEN RETURN; IF ~TEditInputOps.CheckReadonly[pSel] THEN RETURN; SetNodeName[info,NIL,TRUE,pSel] }; ---------------------------- loadStyleAtom: LIST OF REF = Register[$LoadStyleDefinition,LoadStyleOp]; LoadStyleButton: Buttons.ButtonProc = { DoButton[loadStyleAtom] }; LoadStyleOp: TEditInput.CommandProc = { LoadStyle[mainToolInfo] }; LoadStyle: PROC [info: Info] = { repaint: PROC [v: ViewerClasses.Viewer] RETURNS [BOOL _ TRUE] = { SELECT v.class.flavor FROM $Text => TRUSTED {Process.Detach[FORK ViewerOps.PaintViewer[v, all]]}; $Container => ViewerOps.EnumerateChildren[v, repaint]; ENDCASE; RETURN [TRUE] }; name: Rope.ROPE _ GetNameArg[info.styleNameArg ! BadName => GOTO Bad]; TEditInputOps.ReloadStyleName[name]; ViewerOps.EnumerateViewers[repaint]; EXITS Bad => RETURN }; ---------------------------- loadAbbreviationsAtom: LIST OF REF = Register[$LoadAbbreviations,LoadAbbreviationsOp]; LoadAbbreviationsButton: Buttons.ButtonProc = { DoButton[loadAbbreviationsAtom] }; LoadAbbreviationsOp: TEditInput.CommandProc = { LoadAbbreviations[mainToolInfo] }; LoadAbbreviations: PROC [info: Info] = { name: Rope.ROPE _ GetNameArg[info.styleNameArg ! BadName => GOTO Bad]; TEditInputOps.LoadAbbreviations[name]; EXITS Bad => RETURN }; ---------------------------- rootNameRope: Rope.ROPE = "For root node"; selectionNameRope: Rope.ROPE = "For selected nodes"; rootTypeNameAtom: LIST OF REF = Register[$TypeNameForRoot,RootTypeNameOp]; selTypeNameAtom: LIST OF REF = Register[$TypeNameForSelection,SelectionTypeNameOp]; TypeNameNodeButton: Buttons.ButtonProc = { ChangeState[mainToolInfo.typeNode, selTypeNameAtom, rootTypeNameAtom] }; RootTypeNameOp: TEditInput.CommandProc = { RootTypeName[mainToolInfo] }; RootTypeName: PROC [info: Info] = { OPEN info; typeNode _ root; Labels.Set[typeNodeLabel,rootNameRope] }; SelectionTypeNameOp: TEditInput.CommandProc = { SelectionTypeName[mainToolInfo] }; SelectionTypeName: PROC [info: Info] = { OPEN info; typeNode _ selection; Labels.Set[typeNodeLabel,selectionNameRope] }; rootStyleNameAtom: LIST OF REF = Register[$StyleNameForRoot,RootStyleNameOp]; selStyleNameAtom: LIST OF REF = Register[$StyleNameForSelection,SelectionStyleNameOp]; StyleNameNodeButton: Buttons.ButtonProc = { ChangeState[mainToolInfo.styleNode, selStyleNameAtom, rootStyleNameAtom] }; RootStyleNameOp: TEditInput.CommandProc = { RootStyleName[mainToolInfo] }; RootStyleName: PROC [info: Info] = { OPEN info; styleNode _ root; Labels.Set[styleNodeLabel,rootNameRope] }; SelectionStyleNameOp: TEditInput.CommandProc = { SelectionStyleName[mainToolInfo] }; SelectionStyleName: PROC [info: Info] = { OPEN info; styleNode _ selection; Labels.Set[styleNodeLabel,selectionNameRope] }; ---------------------------- propNameArgAtom: LIST OF REF = Register[$PropName,PropNameArgOp]; clearPropNameArgAtom: LIST OF REF = Register[$ClearPropName,ClearPropNameArgOp]; PropNameArgButton: Buttons.ButtonProc = { DoButton[propNameArgAtom,clearPropNameArgAtom, mouseButton=red] }; PropNameArgOp: TEditInput.CommandProc = { PropNameArg[mainToolInfo] }; PropNameArg: PROC [info: Info] = { DataFieldButton[info.propNameArg,FALSE] }; ClearPropNameArgOp: TEditInput.CommandProc = { ClearPropNameArg[mainToolInfo] }; ClearPropNameArg: PROC [info: Info] = { DataFieldButton[info.propNameArg,TRUE] }; ---------------------------- propValueArgAtom: LIST OF REF = Register[$PropValue,PropValueArgOp]; clearPropValueArgAtom: LIST OF REF = Register[$ClearPropValue,ClearPropValueArgOp]; PropValueArgButton: Buttons.ButtonProc = { DoButton[propValueArgAtom,clearPropValueArgAtom, mouseButton=red] }; PropValueArgOp: TEditInput.CommandProc = { PropValueArg[mainToolInfo] }; PropValueArg: PROC [info: Info] = { DataFieldButton[info.propValueArg,FALSE] }; ClearPropValueArgOp: TEditInput.CommandProc = { ClearPropValueArg[mainToolInfo] }; ClearPropValueArg: PROC [info: Info] = { DataFieldButton[info.propValueArg,TRUE] }; ---------------------------- propPatternArgAtom: LIST OF REF = Register[$PropPattern,PropPatternArgOp]; clearPropPatternArgAtom: LIST OF REF = Register[$ClearPropPattern,ClearPropPatternArgOp]; PropPatternArgButton: Buttons.ButtonProc = { DoButton[propPatternArgAtom,clearPropPatternArgAtom, mouseButton=red] }; PropPatternArgOp: TEditInput.CommandProc = { PropPatternArg[mainToolInfo] }; PropPatternArg: PROC [info: Info] = { DataFieldButton[info.propPatternArg,FALSE] }; ClearPropPatternArgOp: TEditInput.CommandProc = { ClearPropPatternArg[mainToolInfo] }; ClearPropPatternArg: PROC [info: Info] = { DataFieldButton[info.propPatternArg,TRUE] }; ---------------------------- rootPropAtom: LIST OF REF = Register[$PropForRoot,RootPropOp]; selPropAtom: LIST OF REF = Register[$PropForSelection,SelectionPropOp]; PropNodeButton: Buttons.ButtonProc = { ChangeState[mainToolInfo.propNode, selPropAtom, rootPropAtom] }; RootPropOp: TEditInput.CommandProc = { RootProp[mainToolInfo] }; RootProp: PROC [info: Info] = { OPEN info; propNode _ root; Labels.Set[propNodeLabel,rootNameRope] }; SelectionPropOp: TEditInput.CommandProc = { SelectionProp[mainToolInfo] }; SelectionProp: PROC [info: Info] = { OPEN info; propNode _ selection; Labels.Set[propNodeLabel,selectionNameRope] }; ---------------------------- getPropAtom: LIST OF REF = Register[$GetNodeProp,GetPropOp]; GetPropButton: Buttons.ButtonProc = { DoButton[getPropAtom] }; GetPropOp: TEditInput.CommandProc = { GetPropCom[mainToolInfo] }; GetPropCom: PROC [info: Info] = { OPEN info; pSel: TEditDocument.Selection; root: TextNode.Ref; name: Rope.ROPE; key: ATOM; valueRope: Rope.ROPE; Get: PROC [node: TextNode.Ref] = { vrope: Rope.ROPE _ NodeProps.GetSpecs[key,TextEdit.GetProp[node,name]]; IF valueRope = NIL THEN valueRope _ vrope ELSE IF ~Rope.Equal[valueRope,vrope] THEN { OPEN MessageWindow; Append["Nodes don't have uniform property values. Using first.", TRUE]; Blink[]; SIGNAL NotUniform }}; name _ GetNameArg[info.propNameArg ! BadName => GOTO Bad]; TEditSelection.LockSel[primary, "GetPropCom"]; pSel _ TEditOps.GetSelData[]; IF ~CheckPSel[pSel] THEN { TEditSelection.UnlockSel[primary]; RETURN }; root _ TEditSelection.SelectionRoot[pSel]; [] _ TEditLocks.Lock[root, "GetPropCom", read]; key _ Atom.MakeAtom[name]; ForEachNode[info.propNode, pSel, Get ! NotUniform => CONTINUE]; TEditSelection.UnlockDocAndPSel[root]; TEditOps.SetTextContents[propValueArg, valueRope]; EXITS Bad => RETURN }; ---------------------------- setPropAtom: LIST OF REF = Register[$SetNodeProp,SetPropOp]; SetPropButton: Buttons.ButtonProc = { DoButton[setPropAtom] }; SetPropOp: TEditInput.CommandProc = { SetPropCom[mainToolInfo] }; SetPropCom: PROC [info: Info] = { OPEN info; pSel: TEditDocument.Selection; name: Rope.ROPE; key: ATOM; root: TextNode.Ref; valueRope: Rope.ROPE _ TextEdit.GetRope[GetDataNode[info.propValueArg]]; Put: PROC [node: TextNode.Ref] = { TextEdit.PutProp[node, name, NodeProps.DoSpecs[key,valueRope], TEditInput.CurrentEvent[], root] }; name _ GetNameArg[info.propNameArg ! BadName => GOTO Bad]; TEditSelection.LockSel[primary, "SetPropCom"]; pSel _ TEditOps.GetSelData[]; IF ~CheckPSel[pSel] OR ~TEditInputOps.CheckReadonly[pSel] THEN { TEditSelection.UnlockSel[primary]; RETURN }; key _ Atom.MakeAtom[name]; root _ TEditSelection.SelectionRoot[pSel]; [] _ TEditLocks.Lock[root, "SetPropCom"]; ForEachNode[info.propNode, pSel, Put]; TEditSelection.UnlockDocAndPSel[root]; EXITS Bad => RETURN }; ---------------------------- removePropAtom: LIST OF REF = Register[$RemoveNodeProp,RemovePropOp]; RemovePropButton: Buttons.ButtonProc = { DoButton[removePropAtom] }; RemovePropOp: TEditInput.CommandProc = { RemovePropCom[mainToolInfo] }; RemovePropCom: PROC [info: Info] = { OPEN info; pSel: TEditDocument.Selection; root: TextNode.Ref; name: Rope.ROPE; Rem: PROC [node: TextNode.Ref] = { TextEdit.PutProp[node, name, NIL, TEditInput.CurrentEvent[]] }; name _ GetNameArg[info.propNameArg ! BadName => GOTO Bad]; TEditSelection.LockSel[primary, "RemovePropCom"]; pSel _ TEditOps.GetSelData[]; IF ~CheckPSel[pSel] OR ~TEditInputOps.CheckReadonly[pSel] THEN { TEditSelection.UnlockSel[primary]; RETURN }; root _ TEditSelection.SelectionRoot[pSel]; [] _ TEditLocks.Lock[root, "RemovePropCom"]; ForEachNode[info.propNode, pSel, Rem]; TEditSelection.UnlockDocAndPSel[root]; EXITS Bad => RETURN }; ---------------------------- listPropsAtom: LIST OF REF = Register[$ListNodeProps,ListPropsOp]; ListPropsButton: Buttons.ButtonProc = { DoButton[listPropsAtom] }; ListPropsOp: TEditInput.CommandProc = { ListPropsCom[mainToolInfo] }; ListPropsCom: PROC [info: Info] = { OPEN info; pSel: TEditDocument.Selection; valueRope: Rope.ROPE; root: TextNode.Ref; list: LIST OF ATOM; listProp: PROC [name: ATOM, value: REF] RETURNS [BOOLEAN] = { FOR lst: LIST OF ATOM _ list, lst.rest UNTIL lst=NIL DO IF lst.first = name THEN RETURN [FALSE]; ENDLOOP; list _ CONS[name, list]; RETURN [FALSE] }; List: PROC [node: TextNode.Ref] = { [] _ NodeProps.MapProps[node, listProp] }; TEditSelection.LockSel[primary, "ListPropsCom"]; pSel _ TEditOps.GetSelData[]; IF ~CheckPSel[pSel] THEN { TEditSelection.UnlockSel[primary]; RETURN }; root _ TEditSelection.SelectionRoot[pSel]; [] _ TEditLocks.Lock[root, "ListPropsCom", read]; ForEachNode[info.propNode, pSel, List]; TEditSelection.UnlockDocAndPSel[root]; FOR lst: LIST OF ATOM _ list, lst.rest UNTIL lst=NIL DO valueRope _ Rope.Concat[valueRope, Atom.GetPName[lst.first]]; IF lst.rest # NIL THEN valueRope _ Rope.Concat[valueRope, " "]; ENDLOOP; TEditOps.SetTextContents[propNameArg, valueRope] }; ---------------------------- findPropAtom: LIST OF REF = Register[$FindNodeProp,FindPropOp]; findBackPropAtom: LIST OF REF = Register[$BackFindNodeProp,FindBackPropOp]; FindPropButton: Buttons.ButtonProc = { DoButton[findPropAtom,findBackPropAtom, mouseButton=red] }; FindPropOp: TEditInput.CommandProc = { FindPropCom[mainToolInfo,TRUE] }; FindBackPropOp: TEditInput.CommandProc = { FindPropCom[mainToolInfo,FALSE] }; FindPropCom: PROC [info: Info, forward: BOOLEAN] = { OPEN info; pSel: TEditDocument.Selection; root, node: TextNode.Ref; { pattern: Rope.ROPE; tester: TextNode.RefTextNode _ TextNode.NewTextNode[]; name: ATOM; -- property name we're looking for finder: TreeFind.Finder; -- pattern for property value Step: PROC [n: TextNode.Ref] RETURNS [TextNode.Ref] = INLINE { RETURN [IF forward THEN TextNode.StepForward[n] ELSE TextNode.StepBackward[n]] }; name _ Atom.MakeAtom[GetNameArg[info.propNameArg ! BadName => GOTO Bad]]; pattern _ TextEdit.GetRope[GetDataNode[info.propPatternArg]]; IF Rope.Size[pattern] # 0 THEN -- create a finder for the pattern finder _ TreeFind.CreateFromRope[pattern ! TextFind.MalformedPattern => { ReportPatternError[ec]; GOTO Bad }]; TEditSelection.LockSel[primary, "FindPropCom"]; pSel _ TEditOps.GetSelData[]; IF ~CheckPSel[pSel] THEN { OPEN MessageWindow; Append["Select node.", TRUE]; Blink[]; TEditSelection.UnlockSel[primary]; RETURN }; root _ TEditSelection.SelectionRoot[pSel]; [] _ TEditLocks.Lock[root, "FindPropCom", read]; node _ IF forward THEN pSel.end.pos.node ELSE pSel.start.pos.node; -- start for search IF node # NIL THEN UNTIL (node _ Step[node])=NIL DO -- check for property value: REF _ NodeProps.GetProp[node,name]; IF value # NIL THEN { -- see if matches pattern IF finder=NIL THEN EXIT; -- accept anything tester.rope _ NodeProps.GetSpecs[name,value]; IF TextFind.Try[finder,tester].found THEN EXIT }; ENDLOOP; IF node=NIL OR TextNode.Parent[node]=NIL THEN { OPEN MessageWindow; Append["Failed to find node with property matching given pattern.", TRUE]; Blink[]; TEditSelection.UnlockDocAndPSel[root]; RETURN }; tSel.start.pos _ [node,0]; tSel.end.pos _ [node,MAX[TextEdit.Size[TextNode.NarrowToTextNode[node]],1]-1]; tSel.granularity _ node; tSel.viewer _ pSel.viewer; tSel.data _ pSel.data; tSel.insertion _ after; TEditSelection.MakeSelection[new: tSel]; TEditInput.CloseEvent[]; TEditRefresh.ScrollToEndOfSel[tSel.viewer, FALSE]; TEditSelection.UnlockDocAndPSel[root]; GetPropCom[info]; EXITS Bad => { TEditSelection.UnlockDocAndPSel[root]; RETURN }}}; ReportPatternError: PUBLIC PROC [ec: TextFind.PatternErrorCode] = { msg: Rope.ROPE = SELECT ec FROM toobig => "Pattern too long", endquote => "Pattern ends with quote (')", endquote => "Pattern ends with tilda (~)", boundary => "Pattern has | inside rather than at beginning or end", missingNameEnd => "Pattern has < without matching >", unmatchedNameEnd => "Pattern has > without previous <", ENDCASE => ERROR; MessageWindow.Append[msg,TRUE]; MessageWindow.Blink[] }; ---------------------------- }. ..