MODULE PET;
IMPORT
KernelLog, KernelLogger, Modules, Commands, Options, Streams, Inputs, Files, WMRestorable, XML, XMLScanner, XMLParser, XMLObjects,
WMStandardComponents, WMGraphics, CompilerInterface, WhitespaceRemover,
WMComponents, WMRectangles, WMMessages, WMDialogs, WMDiagnostics,
WMTextView, WMEditors, Strings, TextUtilities, Texts,
WMWindowManager, WMGrids, WMMacros, WMPopups, WMDropTarget,
PETTrees, Configuration, Codecs, WMTabComponents, UndoManager, WMSearchComponents, Kernel;
CONST
WindowWidth = 800; WindowHeight = 600;
No = 0;
Yes = 1;
Paranoid = 2;
DefaultBackupOnStore = No;
DefaultBackupOnCompile = FALSE;
DefaultShowPathInTabs = FALSE;
DefaultScratchPanelHeight = 250;
DefaultEnableWhitespaceWarnings = FALSE;
DefaultShowLineNumbers = FALSE;
DefaultIndicateTabs = FALSE;
DefaultCurrentLineColor = 0;
DefaultCompilerName = "Fox";
DefaultCompilerCaption = "Compile";
DefaultCompilerOptions = "-b=AMD --warnings";
DefaultCompilerLoadModule = "Compiler";
DefaultCompilerFileExtension = "MOD";
DefaultCompilerFindPC = TRUE;
DefaultDiffCommand = "WMDiff.Open";
DefaultDiffPrefix = "";
DefaultDiffSuffix = ".Bak";
DefaultSearchWrap = FALSE;
DefaultSearchCaseSensitive = TRUE;
DefaultSearchHighlightAll = FALSE;
DisableShortcuts = FALSE;
BackupOnCompileFilename = "PETBackup.Mod.Bak";
ScratchTextFilename = "PETScratch.Text";
StateFileExtension = ".pet";
SearchStringMaxLen = 128;
MaxNbrOfTabs = 100;
MaxNbrOfCompilers = 8;
WindowTitle = "Programmer's Editing Tool v2.1";
DefaultTextFormat = "UTF-8";
EditorFocus = 1;
SplitEditorFocus = 2;
TYPE
CompilerOptions = ARRAY 256 OF CHAR;
Filename = ARRAY 256 OF CHAR;
String = ARRAY 128 OF CHAR;
SearchString = ARRAY SearchStringMaxLen OF CHAR;
TYPE
CompilerSettings = RECORD
name : ARRAY 32 OF CHAR;
caption : ARRAY 16 OF CHAR;
options : CompilerOptions;
fileExtension : ARRAY 16 OF CHAR;
loadmodule : Filename;
genTree : ARRAY 128 OF CHAR;
findPC : BOOLEAN;
END;
Settings = OBJECT
VAR
backupOnStore : LONGINT;
backupOnCompile : BOOLEAN;
showPathInTabs : BOOLEAN;
scratchPanelHeight : LONGINT;
enableWhitespaceWarnings : BOOLEAN;
showLineNumbers : BOOLEAN;
indicateTabs : BOOLEAN;
currentLineColor : LONGINT;
defaultCompilerOptions : CompilerOptions;
defaultCompilerSettings : CompilerSettings;
compilers : ARRAY MaxNbrOfCompilers OF CompilerSettings;
nofCompilers : LONGINT;
diffCommand, diffPrefix, diffSuffix : String;
searchWrap, searchHighlightAll, searchCaseSensitive : BOOLEAN;
PROCEDURE &Init*;
BEGIN
backupOnStore := DefaultBackupOnStore;
backupOnCompile := DefaultBackupOnCompile;
showPathInTabs := DefaultShowPathInTabs;
scratchPanelHeight := DefaultScratchPanelHeight;
enableWhitespaceWarnings := DefaultEnableWhitespaceWarnings;
showLineNumbers := DefaultShowLineNumbers;
indicateTabs := DefaultIndicateTabs;
currentLineColor := DefaultCurrentLineColor;
COPY(DefaultCompilerOptions, defaultCompilerOptions);
nofCompilers := 0;
defaultCompilerSettings.name := DefaultCompilerName;
defaultCompilerSettings.caption := DefaultCompilerCaption;
defaultCompilerSettings.options := DefaultCompilerOptions;
defaultCompilerSettings.fileExtension := DefaultCompilerFileExtension;
defaultCompilerSettings.loadmodule := DefaultCompilerLoadModule;
defaultCompilerSettings.genTree := "";
defaultCompilerSettings.findPC := DefaultCompilerFindPC;
diffCommand := DefaultDiffCommand; diffPrefix := DefaultDiffPrefix; diffSuffix := DefaultDiffSuffix;
searchWrap := DefaultSearchWrap; searchCaseSensitive := DefaultSearchCaseSensitive; searchHighlightAll := DefaultSearchHighlightAll;
END Init;
PROCEDURE GetCompilerSettings(CONST filename : ARRAY OF CHAR) : CompilerSettings;
VAR settings : CompilerSettings; i : LONGINT; extension : ARRAY 16 OF CHAR;
BEGIN
settings := defaultCompilerSettings;
i := 0;
LOOP
IF (i >= nofCompilers) THEN EXIT; END;
extension := ".";
Strings.Append(extension, compilers[i].fileExtension);
IF ContainsFileExtension(filename, extension) THEN EXIT; END;
INC(i);
END;
IF (i < nofCompilers) THEN
settings := compilers[i];
END;
RETURN settings;
END GetCompilerSettings;
PROCEDURE LoadCompilerSettings;
VAR
element, e : XML.Element;
sectionEnumerator : XMLObjects.Enumerator;
p : ANY; string : XML.String;
PROCEDURE GetAttributeValue(element : XML.Element; CONST attributeName : ARRAY OF CHAR; VAR value : ARRAY OF CHAR);
VAR attribute : XML.Attribute;
BEGIN
ASSERT(element # NIL);
COPY("", value);
attribute := element.GetAttribute(attributeName);
IF (attribute # NIL) THEN
string := attribute.GetValue();
IF (string # NIL) THEN
COPY(string^, value);
END;
END;
END GetAttributeValue;
PROCEDURE ParseCompilerSettings(element : XML.Element; VAR settings : CompilerSettings);
VAR enumerator : XMLObjects.Enumerator; e : XML.Element; p : ANY; string : XML.String; value : ARRAY 64OF CHAR;
BEGIN
ASSERT(element # NIL);
GetAttributeValue(element, "name", value);
IF (value # "") THEN
COPY(value, settings.name);
enumerator := element.GetContents();
WHILE enumerator.HasMoreElements() DO
p := enumerator.GetNext();
IF (p IS XML.Element) THEN
e := p (XML.Element);
string := e.GetName();
IF (string # NIL) & (string^ = "Setting") THEN
GetAttributeValue(e, "name", value);
IF (value = "caption") THEN
GetAttributeValue(e, "value", settings.caption);
IF (settings.caption = "") THEN settings.caption := "Action"; END;
ELSIF (value = "options") THEN
GetAttributeValue(e, "value", settings.options);
ELSIF (value = "fileExtension") THEN
GetAttributeValue(e, "value", settings.fileExtension);
ELSIF (value = "loadmodule") THEN
GetAttributeValue(e, "value", settings.loadmodule);
ELSIF (value = "genTree") THEN
GetAttributeValue(e, "value", value);
Strings.TrimWS(value);
COPY(value, settings.genTree);
ELSIF (value = "findPC") THEN
GetAttributeValue(e, "value", value);
Strings.UpperCase(value); Strings.TrimWS(value);
settings.findPC := (value = "TRUE");
ELSE
KernelLog.String("PET: Warning: Unknown compiler setting '");
KernelLog.String(value); KernelLog.String("'"); KernelLog.Ln;
END;
ELSE
KernelLog.String("PET: Warning: Expected 'Setting' element."); KernelLog.Ln;
END;
END;
END;
END;
END ParseCompilerSettings;
BEGIN
element := Configuration.GetSection("Applications.PET.Compilers");
IF (element # NIL) THEN
sectionEnumerator := element.GetContents();
WHILE sectionEnumerator.HasMoreElements() DO
p := sectionEnumerator.GetNext();
IF (p IS XML.Element) THEN
e := p (XML.Element);
string := e.GetName();
IF (string # NIL) & (string^ = "Section") THEN
IF (nofCompilers < LEN(compilers)) THEN
ParseCompilerSettings(e, compilers[nofCompilers]);
INC(nofCompilers);
ELSE
KernelLog.String("PET: Warning: Maximum number of compiler settings exceeded."); KernelLog.Ln;
END;
ELSE
KernelLog.String("PET: Warning: Expected 'Section' element."); KernelLog.Ln;
END;
END;
END;
END;
END LoadCompilerSettings;
PROCEDURE Load;
VAR string : String; temp, res : LONGINT;
BEGIN
Configuration.Get("Applications.PET.General.BackupOnStore", string, res);
Strings.TrimWS(string);
Strings.LowerCase(string);
IF (string = "yes") THEN backupOnStore := Yes;
ELSIF (string = "no") THEN backupOnStore := No;
ELSIF (string = "paranoid") THEN backupOnStore := Paranoid;
ELSE
KernelLog.String("Warning: PET.Settings.Load: BackupOnStore # Yes | No | Paranoid, using default."); KernelLog.Ln;
backupOnStore := DefaultBackupOnStore;
END;
IF (backupOnStore < No) OR (Paranoid < backupOnStore) THEN backupOnStore := DefaultBackupOnStore; END;
Configuration.GetBoolean("Applications.PET.General.BackupOnCompile", backupOnCompile, res);
Configuration.GetBoolean("Applications.PET.General.ShowPathInTabs", showPathInTabs, res);
Configuration.GetInteger("Applications.PET.General.ScratchPanelHeight", scratchPanelHeight, res);
Configuration.GetBoolean("Applications.PET.General.EnableWhitespaceWarnings", enableWhitespaceWarnings, res);
Configuration.GetBoolean("Applications.PET.General.ShowLineNumbers", showLineNumbers, res);
Configuration.GetBoolean("Applications.PET.General.IndicateTabs", indicateTabs, res);
Configuration.Get("Applications.PET.General.CurrentLineColor", string, res);
IF (res = Configuration.Ok) THEN
Strings.TrimWS(string);
Strings.HexStrToInt(string, temp, res);
IF (res = Strings.Ok) THEN currentLineColor := temp; END;
END;
Configuration.Get("Applications.PET.Compilers.DefaultOptions", defaultCompilerOptions, res);
LoadCompilerSettings;
Configuration.Get("Applications.PET.Diff.Command", diffCommand, res);
Configuration.Get("Applications.PET.Diff.Prefix", diffPrefix, res);
Configuration.Get("Applications.PET.Diff.Suffix", diffSuffix, res);
Configuration.GetBoolean("Applications.PET.Search.Wrap", searchWrap, res);
Configuration.GetBoolean("Applications.PET.Search.CaseSensitive", searchCaseSensitive, res);
Configuration.GetBoolean("Applications.PET.Search.HighlightAll", searchHighlightAll, res);
END Load;
END Settings;
TYPE
CaptionObject = OBJECT
VAR caption : ARRAY 128 OF CHAR;
PROCEDURE &New*(CONST caption: ARRAY OF CHAR);
BEGIN
COPY(caption, SELF.caption);
END New;
END CaptionObject;
TYPE
Position = OBJECT
VAR
marker : WMTextView.PositionMarker;
ucs, keysym : LONGINT; flags : SET;
next : Position;
PROCEDURE &Init*(ucs, keysym : LONGINT; flags : SET);
BEGIN
SELF.ucs := ucs; SELF.keysym := keysym; SELF.flags := flags;
marker := NIL; next := NIL;
END Init;
END Position;
Positions = OBJECT
VAR
textView : WMTextView.TextView;
positions : Position;
PROCEDURE &Init*(textView : WMTextView.TextView);
BEGIN
ASSERT(textView # NIL);
SELF.textView := textView;
END Init;
PROCEDURE FindPosition(ucs, keysym : LONGINT; flags : SET) : Position;
VAR p : Position;
BEGIN
p := positions;
WHILE (p # NIL) & ~((p.ucs = ucs) & (p.keysym = keysym) & (p.flags = flags)) DO
p := p.next;
END;
RETURN p;
END FindPosition;
PROCEDURE StoreCurrentPosition(ucs, keysym : LONGINT; flags : SET);
VAR newPosition : Position; intPos : LONGINT;
BEGIN
ASSERT(flags * { Inputs.Release} = {});
newPosition := FindPosition(ucs, keysym, flags);
IF (newPosition = NIL) THEN
NEW(newPosition, ucs, keysym, flags);
newPosition.marker := textView.CreatePositionMarker();
newPosition.marker.SetVisible(FALSE);
newPosition.next := positions;
positions := newPosition;
END;
intPos := textView.GetInternalPos(textView.cursor.GetPosition());
newPosition.marker.SetPosition(intPos);
END StoreCurrentPosition;
PROCEDURE RecallPosition(ucs, keysym : LONGINT; flags : SET);
VAR position : Position;
BEGIN
position := FindPosition(ucs, keysym, flags);
IF (position # NIL) THEN
textView.cursor.SetPosition(position.marker.GetPosition());
END;
END RecallPosition;
END Positions;
TYPE
ScratchPanel = OBJECT(WMComponents.VisualComponent)
VAR
editor : WMEditors.Editor;
label : WMStandardComponents.Label;
PROCEDURE &Init*;
BEGIN
Init^;
SetNameAsString(StrScratchPanel);
NEW(label); label.alignment.Set(WMComponents.AlignTop); label.bounds.SetHeight(20);
label.fillColor.Set(0CCCCCCFFH); label.caption.SetAOC(" Scratch Text");
AddContent(label);
NEW(editor); editor.alignment.Set(WMComponents.AlignClient);
editor.tv.showBorder.Set(TRUE);
AddContent(editor);
editor.SetText(scratchText)
END Init;
PROCEDURE SetText(text : Texts.Text);
BEGIN
ASSERT(text # NIL);
editor.SetText(text);
label.caption.SetAOC(" Project Text");
END SetText;
END ScratchPanel;
URLDropTarget = OBJECT(WMDropTarget.DropTarget);
VAR win : Window;
PROCEDURE &New*(win : Window);
BEGIN
SELF.win := win
END New;
PROCEDURE GetInterface(type : LONGINT) : WMDropTarget.DropInterface;
VAR di : DropURL;
BEGIN
IF type = WMDropTarget.TypeURL THEN
NEW(di, SELF.win);
RETURN di
ELSE RETURN NIL
END
END GetInterface;
END URLDropTarget;
DropURL = OBJECT(WMDropTarget.DropURLs)
VAR win : Window;
PROCEDURE &New*(win: Window);
BEGIN
SELF.win := win;
END New;
PROCEDURE URL(CONST url : ARRAY OF CHAR; VAR res : LONGINT);
BEGIN
win.Load(url, "AUTO");
res := 0
END URL;
END DropURL;
TYPE
TextWriter= OBJECT (TextUtilities.TextWriter)
VAR update: PROCEDURE {DELEGATE};
PROCEDURE Update;
BEGIN
IF update # NIL THEN update END;
Update^
END Update;
END TextWriter;
PETPanel = OBJECT(WMComponents.VisualComponent)
VAR
editor, splitEditor : WMEditors.Editor;
logEdit : WMEditors.Editor;
scratchPanel, splitPanel : WMStandardComponents.Panel;
scratch : ScratchPanel;
sidePanel : WMStandardComponents.Panel;
logPanel, editPanel: WMStandardComponents.Panel;
logWriter: TextWriter;
searchPanel: WMSearchComponents.SearchPanel;
errorGrid : WMDiagnostics.DiagnosticsView;
diagnostics : WMDiagnostics.Model;
tree : PETTrees.Tree;
modified, splitted, wrap: BOOLEAN;
focus : LONGINT;
codecFormat: ARRAY 128 OF CHAR;
autoCodecFormat: ARRAY 128 OF CHAR;
name : Filename;
filename : Filename;
options : CompilerOptions;
compilerSettings : CompilerSettings;
showErrorMarkers : BOOLEAN;
positions : Positions;
owner : Window;
settings: Settings;
PROCEDURE &InitPanel *(window: Window);
VAR
resizerH, resizerV: WMStandardComponents.Resizer;
um: UndoManager.UndoManager;
colWidths : WMGrids.Spacings;
textViews : ARRAY 2 OF WMTextView.TextView;
BEGIN
settings := GetSettings();
Init;
owner := window;
tree := NIL;
SetNameAsString(StrPETPanel);
showErrorMarkers := TRUE;
COPY("Untitled.Mod", filename);
COPY("Untitled.Mod", name);
NEW(sidePanel);
sidePanel.bounds.SetWidth(250); sidePanel.alignment.Set(WMComponents.AlignLeft);
AddContent(sidePanel);
NEW(resizerH); resizerH.alignment.Set(WMComponents.AlignRight);
resizerH.bounds.SetWidth(4);
sidePanel.AddContent(resizerH);
NEW(scratchPanel);
scratchPanel.bounds.SetHeight(250); scratchPanel.alignment.Set(WMComponents.AlignBottom);
NEW(resizerV); resizerV.alignment.Set(WMComponents.AlignTop);
resizerV.bounds.SetHeight(4);
scratchPanel.AddContent(resizerV);
NEW(logEdit); logEdit.bounds.SetHeight(100); logEdit.alignment.Set(WMComponents.AlignBottom);
logEdit.allowScrollbars.Set(TRUE);
logEdit.tv.showBorder.Set(TRUE); logEdit.visible.Set(FALSE);
NEW(logWriter, logEdit.text);
logWriter.update := OpenLogEditor;
NEW(scratch); scratch.alignment.Set(WMComponents.AlignClient);
scratch.editor.tv.commandCaller := window;
scratch.editor.tv.commandWriter := logWriter;
scratchPanel.AddContent(scratch);
sidePanel.AddContent(scratchPanel);
NEW(editPanel); editPanel.alignment.Set(WMComponents.AlignClient);
AddContent(editPanel);
NEW(logPanel);
logPanel.alignment.Set(WMComponents.AlignBottom);
logPanel.bounds.SetHeight(130);
NEW(resizerH); resizerH.alignment.Set(WMComponents.AlignTop);
resizerH.bounds.SetHeight(4);
logPanel.AddContent(resizerH);
NEW(resizerV); resizerV.alignment.Set(WMComponents.AlignTop);
resizerV.bounds.SetHeight(4);
logEdit.AddContent(resizerV);
editPanel.AddContent(logEdit);
editPanel.AddContent(logPanel);
NEW(diagnostics);
NEW(errorGrid);
errorGrid.SetModel(diagnostics);
errorGrid.alignment.Set(WMComponents.AlignClient);
errorGrid.nofCols.Set(3);
errorGrid.fixedRows.Set(1);
errorGrid.adjustFocusPosition.Set(FALSE);
NEW(colWidths, 3);
colWidths[0] := 60;
colWidths[1] := 40;
colWidths[2] := 2048;
errorGrid.SetColSpacings(colWidths);
errorGrid.onClick.Add(ErrorClick);
errorGrid.SetSelectionMode(WMGrids.GridSelectSingleRow);
errorGrid.visible.Set(FALSE);
logPanel.AddContent(errorGrid);
NEW(searchPanel);
searchPanel.alignment.Set(WMComponents.AlignBottom);
searchPanel.bounds.SetHeight(40); searchPanel.visible.Set(FALSE);
editPanel.AddContent(searchPanel);
NEW(splitPanel);
splitPanel.alignment.Set(WMComponents.AlignBottom);
splitPanel.bounds.SetHeight(400);
editPanel.AddContent(splitPanel);
NEW(editor); editor.alignment.Set(WMComponents.AlignClient); editor.tv.showBorder.Set(TRUE);
editor.tv.SetExtFocusHandler(EditorFocusHandler);
editPanel.AddContent(editor);
editor.macros.Add(WMMacros.Handle);
editor.multiLine.Set(TRUE);
editor.tv.wrapMode.Set(WMTextView.NoWrap);
editor.tv.onCursorChanged := CursorChanged;
editor.tv.commandCaller := window;
editor.tv.commandWriter := logWriter;
editor.text.onTextChanged.Add(TextChanged);
editor.tv.showLineNumbers.Set(settings.showLineNumbers);
editor.tv.indicateTabs.Set(settings.indicateTabs);
editor.tv.clBgCurrentLine.Set(settings.currentLineColor);
NEW(positions, editor.tv);
searchPanel.SetText(editor.text);
NEW(resizerV);
resizerV.bounds.SetHeight(5); resizerV.alignment.Set(WMComponents.AlignTop);
resizerV.fillColor.Set(0808080FFH);
splitPanel.AddContent(resizerV);
NEW(splitEditor); splitEditor.alignment.Set(WMComponents.AlignClient); splitEditor.tv.showBorder.Set(TRUE);
splitEditor.tv.SetExtFocusHandler(SplitEditorFocusHandler);
splitPanel.AddContent(splitEditor);
splitEditor.macros.Add(WMMacros.Handle);
splitEditor.multiLine.Set(TRUE);
splitEditor.tv.wrapMode.Set(WMTextView.NoWrap);
splitEditor.tv.commandCaller := window;
splitEditor.tv.commandWriter := logWriter;
splitEditor.SetText(editor.text);
splitEditor.tv.showLineNumbers.Set(settings.showLineNumbers);
splitEditor.tv.indicateTabs.Set(settings.indicateTabs);
splitEditor.tv.clBgCurrentLine.Set(settings.currentLineColor);
textViews[0] := editor.tv;
textViews[1] := splitEditor.tv;
errorGrid.SetTextViews(textViews);
logPanel.visible.Set(FALSE);
splitPanel.visible.Set(FALSE);
modified := FALSE;
splitted := FALSE;
wrap := FALSE;
codecFormat := "AUTO";
autoCodecFormat := DefaultTextFormat;
options := settings.defaultCompilerOptions;
NEW(um, 1001, TRUE);
editor.text.SetUndoManager(um);
editor.SetUndoManager(um);
END InitPanel;
PROCEDURE CreateSidePanel(settings : CompilerSettings);
VAR factory : PETTrees.Factory; strings : Strings.StringArray;
BEGIN
IF (tree # NIL) THEN sidePanel.RemoveContent(tree); tree := NIL END;
IF (settings.genTree # "") THEN
strings := Strings.Split(settings.genTree, ".");
IF (LEN(strings) = 2) THEN
GETPROCEDURE(strings[0]^, strings[1]^, factory);
IF (factory # NIL) THEN
tree := factory();
END;
END;
END;
IF (tree # NIL) THEN
tree.alignment.Set(WMComponents.AlignClient);
tree.SetEditor(editor);
tree.onExpandNode.Add(OnNodeExpand);
tree.onGoToFile.Add(OnGoToFile);
tree.onGoToDefinition.Add(OnGoToDefinition);
tree.onRefresh.Add(HandleTreeRefresh);
sidePanel.AddContent(tree);
tree.RefreshHandler(NIL, NIL);
sidePanel.visible.Set(TRUE);
ELSE
sidePanel.visible.Set(FALSE);
scratchPanel.alignment.Set(WMComponents.AlignClient);
scratchPanel.bounds.Set(sidePanel.bounds.Get());
END;
END CreateSidePanel;
PROCEDURE OnGoToFile(sender, data : ANY);
VAR info : PETTrees.ExternalInfo; file : Files.File; filename : Files.FileName;
BEGIN
IF (data # NIL) & (data IS PETTrees.ExternalInfo) THEN
info := data (PETTrees.ExternalInfo);
COPY(info.filename, filename); Strings.Append(filename, ".Mod");
file := Files.Old(filename);
IF (file # NIL) THEN
owner.GotoFile(filename, info.position);
END;
END;
END OnGoToFile;
PROCEDURE OnGoToDefinition(sender, data : ANY);
VAR info : PETTrees.ExternalDefinitionInfo;
BEGIN
IF (data # NIL) & (data IS PETTrees.ExternalDefinitionInfo) THEN
info := data (PETTrees.ExternalDefinitionInfo);
owner.GotoDefinition(info);
END;
END OnGoToDefinition;
PROCEDURE OnNodeExpand (sender, data: ANY);
BEGIN
IF (tree # NIL) THEN tree.SelectNodeByPos (editor.tv.cursor.GetPosition()) END
END OnNodeExpand;
PROCEDURE HandleTreeRefresh(sender, data : ANY);
BEGIN
END HandleTreeRefresh;
PROCEDURE ClearLog;
BEGIN
logEdit.text.AcquireWrite;
logEdit.text.Delete(0, logEdit.text.GetLength());
logEdit.tv.firstLine.Set(0); logEdit.tv.cursor.SetPosition(0);
logEdit.text.ReleaseWrite;
END ClearLog;
PROCEDURE DoCompile(findPC : BOOLEAN; CONST pc :ARRAY OF CHAR; options : CompilerOptions);
VAR
compiler : CompilerInterface.Compiler; tw : TextUtilities.TextWriter; errors : BOOLEAN; type: LONGINT;
positions : ARRAY 2 OF LONGINT;
BEGIN
ClearLog;
IF findPC THEN Strings.Append(options, " /f") END;
NEW(tw, logEdit.text);
diagnostics.DisableNotification;
diagnostics.Clear;
compiler := CompilerInterface.GetCompilerByName(compilerSettings.name);
IF (compiler = NIL) & (compilerSettings.loadmodule # "") THEN
LoadModule(compilerSettings.loadmodule);
compiler := CompilerInterface.GetCompilerByName(compilerSettings.name);
END;
IF (compiler # NIL) THEN
compiler.CompileText(editor.text, filename, 0, pc, options, tw, diagnostics, errors);
ELSE
tw.String("No compiler available for file '"); tw.String(filename); tw.String("'");
logPanel.visible.Set(TRUE);
END;
tw.Update;
IF settings.enableWhitespaceWarnings THEN
WhitespaceRemover.CheckWhitespace(editor.text, diagnostics);
END;
diagnostics.EnableNotification;
IF (diagnostics.nofEntries > 0) THEN
errorGrid.GetFirstPosition(positions, type);
IF (type = WMDiagnostics.TypeError) OR findPC & (type=WMDiagnostics.TypeInformation) THEN
IF (focus = EditorFocus) & (positions[0] # WMDiagnostics.Invalid) THEN
editor.tv.cursor.SetPosition(positions[0]);
editor.SetFocus;
ELSIF (focus = SplitEditorFocus) THEN
splitEditor.tv.cursor.SetPosition(positions[0]);
splitEditor.SetFocus;
END;
CursorChanged;
END;
errorGrid.visible.Set(TRUE);
logPanel.visible.Set(TRUE); logEdit.visible.Set(TRUE);
ELSE
logPanel.visible.Set(FALSE); logEdit.visible.Set(TRUE);
errorGrid.visible.Set(FALSE);
END;
END DoCompile;
PROCEDURE ErrorClick(sender, data : ANY);
VAR
focusEditor: WMEditors.Editor;
entry : WMDiagnostics.ViewEntry;
index: LONGINT;
BEGIN
IF (data # NIL) & (data IS WMDiagnostics.CellInfo) & (data(WMDiagnostics.CellInfo).entryValid) THEN
IF (focus = EditorFocus) THEN focusEditor := editor; index := 0;
ELSIF (focus = SplitEditorFocus) THEN focusEditor := splitEditor; index := 1;
ELSE
HALT(99);
END;
entry := data(WMDiagnostics.CellInfo).entry;
IF (entry.pos # NIL) & (LEN(entry.pos) = 2) & (entry.pos[index] # NIL) THEN
focusEditor.tv.selection.SetFromTo(0, 0);
focusEditor.tv.cursor.SetPosition(entry.pos[index].GetPosition());
focusEditor.SetFocus;
END;
END;
END ErrorClick;
PROCEDURE GoToNextError(forward : BOOLEAN);
VAR nearestPosition, row, index : LONGINT; focusEditor: WMEditors.Editor;
BEGIN
IF focus = EditorFocus THEN focusEditor := editor; index := 0;
ELSIF focus = SplitEditorFocus THEN focusEditor := splitEditor; index := 1;
ELSE RETURN;
END;
focusEditor.tv.selection.SetFromTo(0, 0);
errorGrid.GetNearestPosition(editor.tv.cursor.GetPosition(), index, forward, nearestPosition, row);
editor.tv.cursor.SetPosition(nearestPosition);
errorGrid.SelectEntry(row, TRUE);
END GoToNextError;
PROCEDURE EditorFocusHandler(hasFocus: BOOLEAN);
BEGIN
IF hasFocus THEN
focus := EditorFocus;
searchPanel.SetTextView(editor.tv);
IF (tree # NIL) THEN tree.SetEditor(editor) END;
END;
END EditorFocusHandler;
PROCEDURE SplitEditorFocusHandler(hasFocus: BOOLEAN);
BEGIN
IF hasFocus THEN
focus := SplitEditorFocus;
searchPanel.SetTextView(splitEditor.tv);
IF (tree # NIL) THEN tree.SetEditor(splitEditor) END;
END
END SplitEditorFocusHandler;
PROCEDURE ToggleLabels;
BEGIN
IF editor.tv.showLabels.Get() THEN
editor.tv.showLabels.Set(FALSE);
splitEditor.tv.showLabels.Set(FALSE);
ELSE
editor.tv.showLabels.Set(TRUE);
splitEditor.tv.showLabels.Set(TRUE);
END;
Invalidate;
END ToggleLabels;
PROCEDURE ToggleWrap;
BEGIN
IF (editor.tv.wrapMode.Get() = WMTextView.WrapWord) THEN
editor.tv.wrapMode.Set(WMTextView.NoWrap);
splitEditor.tv.wrapMode.Set(WMTextView.NoWrap);
ELSE
editor.tv.wrapMode.Set(WMTextView.WrapWord);
splitEditor.tv.wrapMode.Set(WMTextView.WrapWord);
END;
wrap := ~wrap;
END ToggleWrap;
PROCEDURE TextChanged(sender, data : ANY);
BEGIN
IF logPanel.visible.Get() THEN
logPanel.Invalidate
END;
IF ~modified THEN
IF (owner # NIL) THEN owner.SetModified(TRUE) END;
modified := TRUE
END;
CursorChanged
END TextChanged;
PROCEDURE CursorChanged;
VAR position : LONGINT; pos : ARRAY 16 OF CHAR;
BEGIN
position := editor.tv.cursor.GetPosition();
Strings.IntToStr(position, pos);
owner.positionEdit.SetAsString(pos);
IF (tree # NIL) THEN tree.SelectNodeByPos (position) END
END CursorChanged;
PROCEDURE OpenLogEditor;
BEGIN
IF ~logEdit.visible.Get() THEN logEdit.visible.Set(TRUE) END;
END OpenLogEditor;
PROCEDURE HandleShortcut(ucs : LONGINT; flags : SET; keysym : LONGINT) : BOOLEAN;
VAR pos : LONGINT;
PROCEDURE HandlePreviousNext(forward : BOOLEAN);
BEGIN
IF (focus = EditorFocus) THEN
editor.SetFocus;
ELSE
splitEditor.SetFocus;
END;
IF searchPanel.visible.Get() THEN
searchPanel.HandlePreviousNext(forward);
ELSIF errorGrid.visible.Get() THEN
GoToNextError(forward);
END;
CursorChanged;
END HandlePreviousNext;
PROCEDURE HandleDiff;
VAR
filename, string : Filename; context : Commands.Context; res : LONGINT;
arg : Streams.StringReader;
BEGIN
IF (settings.diffCommand = "") THEN
WMDialogs.Error(WindowTitle, "No diff command specified");
RETURN;
END;
COPY(settings.diffPrefix, filename);
Strings.Append(filename, SELF.filename);
Strings.Append(filename, settings.diffSuffix);
IF (WMDialogs.QueryString("Diff to file...", filename) = WMDialogs.ResOk) THEN
string := ""; Strings.Append(string, filename); Strings.Append(string, " "); Strings.Append(string, SELF.filename);
NEW(arg, LEN(string)); arg.SetRaw(string, 0, LEN(string));
NEW(context, NIL, arg, NIL, NIL, owner);
Commands.Activate(settings.diffCommand, context, {}, res, string);
IF (res # Commands.Ok) THEN
WMDialogs.Error(WindowTitle, string);
END;
END;
END HandleDiff;
PROCEDURE HandlePositions;
BEGIN
IF (flags * Inputs.Ctrl # {}) THEN
positions.RecallPosition(ucs, keysym, flags - Inputs.Ctrl);
ELSE
positions.StoreCurrentPosition(ucs, keysym, flags - Inputs.Shift);
END;
END HandlePositions;
PROCEDURE RemoveWhitespace;
VAR tw : TextUtilities.TextWriter; nofRemoved : LONGINT;
BEGIN
ClearLog;
NEW(tw, logEdit.text);
WhitespaceRemover.RemoveFromText(editor.text, nofRemoved);
tw.String("Removed "); tw.Int(nofRemoved, 0); tw.String(" end-of-line whitespace"); tw.Update;
logEdit.visible.Set(TRUE);
END RemoveWhitespace;
PROCEDURE HandleComments(remove : BOOLEAN);
VAR editor : WMEditors.Editor;
BEGIN
IF (focus = EditorFocus) THEN editor := SELF.editor; ELSE editor := splitEditor; END;
editor.text.AcquireWrite;
editor.tv.selection.Sort;
IF (editor.tv.selection.a # editor.tv.selection.b) THEN
IF remove THEN
UncommentSelection(editor.text, editor.tv.selection.from, editor.tv.selection.to);
ELSE
CommentSelection(editor.text, editor.tv.selection.from, editor.tv.selection.to);
END;
END;
editor.text.ReleaseWrite;
END HandleComments;
BEGIN
IF (keysym = 06H) & ControlKeyDown(flags) THEN
searchPanel.ToggleVisibility;
ELSIF (keysym = 05H) & ControlKeyDown(flags) THEN
logPanel.visible.Set(~logPanel.visible.Get());
ELSIF (keysym= 0CH) & ControlKeyDown(flags) THEN
logEdit.visible.Set(~logEdit.visible.Get());
ELSIF (keysym= 0EH) & ControlKeyDown(flags) THEN
HandlePreviousNext(TRUE);
ELSIF (keysym = 10H) & ControlKeyDown(flags) THEN
HandlePreviousNext(FALSE);
ELSIF (keysym = 0DH) & ControlKeyDown(flags) THEN
IF sidePanel.visible.Get() THEN sidePanel.visible.Set(FALSE);
ELSE sidePanel.visible.Set(TRUE);
END;
ELSIF (keysym = 04H) & ControlKeyDown(flags) THEN
HandleDiff;
ELSIF (keysym = 30H) & ControlKeyDown(flags) THEN
IF (focus = EditorFocus) THEN
editor.tv.cursor.SetPosition(0);
ELSE
splitEditor.tv.cursor.SetPosition(0);
END;
ELSIF (keysym = 39H) & ControlKeyDown(flags) THEN
IF (focus = EditorFocus) THEN
editor.text.AcquireRead; pos := editor.text.GetLength()-1; editor.text.ReleaseRead;
editor.tv.cursor.SetPosition(pos);
ELSE
splitEditor.text.AcquireRead; pos := splitEditor.text.GetLength()-1; splitEditor.text.ReleaseRead;
splitEditor.tv.cursor.SetPosition(pos);
END;
ELSIF (0FFBEH <= keysym) & (keysym <= 0FFC9H) & EitherShiftOrControlDown(flags) THEN
HandlePositions;
ELSIF (keysym = Inputs.KsTab) & (flags = {}) THEN
RETURN searchPanel.HandleTab();
ELSIF (keysym = Inputs.KsDelete) & ControlKeyDown(flags) THEN
RemoveWhitespace;
ELSIF (keysym = Inputs.KsInsert) & (flags * Inputs.Alt # {}) THEN
HandleComments(FALSE);
ELSIF (keysym = Inputs.KsDelete) & (flags * Inputs.Alt # {}) THEN
HandleComments(TRUE);
ELSE
RETURN FALSE;
END;
RETURN TRUE;
END HandleShortcut;
PROCEDURE Finalize;
BEGIN
Finalize^;
IF (editor # NIL) & (editor.text # NIL) THEN
editor.text.onTextChanged.Remove(TextChanged);
editor.tv.onCursorChanged := NIL;
IF editor.undoMgr # NIL THEN
editor.undoMgr.nrUpdatesListener := NIL;
END;
END;
END Finalize;
END PETPanel;
TYPE
KillerMsg = OBJECT
END KillerMsg;
BrowseEntry = POINTER TO RECORD
prev, next : BrowseEntry;
filename : Filename;
pos : LONGINT;
END;
Window = OBJECT (WMComponents.FormWindow)
VAR
filenameEdit, optionsEdit, positionEdit: WMEditors.Editor;
loadBtn, storeBtn, closeBtn, compileBtn, findPCBtn, undoBtn, redoBtn: WMStandardComponents.Button;
splitBtn, formatBtn, searchBtn, labelsBtn, wrapBtn, errListBtn, findBtn, logBtn, forwardBtn, backBtn : WMStandardComponents.Button;
popup: WMPopups.Popup;
tabs : WMTabComponents.Tabs;
pages : ARRAY MaxNbrOfTabs OF PETPanel;
tabList : ARRAY MaxNbrOfTabs OF WMTabComponents.Tab;
currentPage : PETPanel;
currentPageNr : LONGINT;
page : WMStandardComponents.Panel;
xmlHasErrors : BOOLEAN;
codecFormat: ARRAY 128 OF CHAR;
autoCodecFormat: ARRAY 128 OF CHAR;
projectText : Texts.Text;
projectTextFilename : Filename;
projectTextModified : BOOLEAN;
showTypeHierarchy, showImportedModules : BOOLEAN;
windowInfo : WMWindowManager.WindowInfo;
currentIcon : WMGraphics.Image;
iconIdle, iconWorking : WMGraphics.Image;
modifierFlags : SET;
browseBase, browseTOS : BrowseEntry;
settings: Settings;
PROCEDURE &New*(c : WMRestorable.Context);
VAR vc : WMComponents.VisualComponent;
BEGIN
settings := GetSettings();
IncCount;
InitCodecs;
vc := CreateForm();
currentPageNr := -1;
projectTextFilename := "";
projectText := NIL;
projectTextModified := FALSE;
tabs.onSelectTab.Add(TabSelected);
showTypeHierarchy := FALSE;
showImportedModules := FALSE;
modifierFlags := {};
IF (c # NIL) THEN
Init(c.r - c.l, c.b - c.t, FALSE);
ELSE
Init(WindowWidth, WindowHeight, FALSE);
END;
SetContent(vc);
SetTitle(Strings.NewString(WindowTitle));
currentIcon := NIL;
iconIdle := WMGraphics.LoadImage("WMIcons.tar://PETIdle.png", TRUE);
iconWorking := WMGraphics.LoadImage("WMIcons.tar://PET.png", TRUE);
IF (iconIdle = NIL) THEN
iconIdle := iconWorking;
ELSIF (iconWorking = NIL) THEN
iconWorking := iconIdle;
END;
SetIcon(iconIdle);
IF c # NIL THEN
WMRestorable.AddByContext(SELF, c);
IF c.appData # NIL THEN
DisableUpdate;
LoadPages(c.appData(XML.Element));
EnableUpdate;
END;
vc.Invalidate;
ELSE WMWindowManager.DefaultAddWindow(SELF);
codecFormat := "AUTO";
autoCodecFormat := DefaultTextFormat;
SetFormatCaption("AUTO");
END;
NEW(browseBase);
browseBase.prev := browseBase;
browseTOS := browseBase
END New;
PROCEDURE CreateForm():WMComponents.VisualComponent;
VAR
panel, resizerPanel : WMStandardComponents.Panel;
resizer : WMStandardComponents.Resizer;
posLabel : WMStandardComponents.Label;
font: WMGraphics.Font;
dx, dy: LONGINT;
PROCEDURE CreateToolbar() : WMComponents.VisualComponent;
VAR toolbar : WMStandardComponents.Panel;
BEGIN
NEW(toolbar); toolbar.bounds.SetHeight(20); toolbar.alignment.Set(WMComponents.AlignTop);
NEW(resizerPanel);
resizerPanel.alignment.Set(WMComponents.AlignLeft);
resizerPanel.bounds.SetWidth(200);
toolbar.AddContent(resizerPanel);
NEW(resizer);
resizer.alignment.Set(WMComponents.AlignRight);
resizer.bounds.SetWidth(4);
resizerPanel.AddContent(resizer);
NEW(filenameEdit); filenameEdit.alignment.Set(WMComponents.AlignClient);
filenameEdit.multiLine.Set(FALSE); filenameEdit.bounds.SetWidth(200);
filenameEdit.fillColor.Set(0FFFFFFFFH);
filenameEdit.tv.showBorder.Set(TRUE);
filenameEdit.tv.borders.Set(WMRectangles.MakeRect(3,3,1,1));
filenameEdit.tv.commandCaller := SELF;
filenameEdit.onEnter.Add(LoadHandler);
filenameEdit.onEscape.Add(FilenameEditEscapeHandler);
resizerPanel.AddContent(filenameEdit);
NEW(loadBtn); loadBtn.caption.SetAOC("Load"); loadBtn.alignment.Set(WMComponents.AlignLeft);
loadBtn.onClick.Add(LoadHandler);
toolbar.AddContent(loadBtn);
NEW(storeBtn); storeBtn.caption.SetAOC("Store"); storeBtn.alignment.Set(WMComponents.AlignLeft);
storeBtn.onClick.Add(StoreHandler);
toolbar.AddContent(storeBtn);
NEW(closeBtn); closeBtn.caption.SetAOC("Close"); closeBtn.alignment.Set(WMComponents.AlignLeft);
closeBtn.onClick.Add(CloseHandler);
toolbar.AddContent(closeBtn);
NEW(formatBtn); formatBtn.caption.SetAOC("Format : ---"); formatBtn.alignment.Set(WMComponents.AlignLeft);
formatBtn.SetExtPointerDownHandler(FormatHandler);
formatBtn.bounds.SetWidth(3 * formatBtn.bounds.GetWidth());
toolbar.AddContent(formatBtn);
NEW(searchBtn); searchBtn.caption.SetAOC("Search"); searchBtn.alignment.Set(WMComponents.AlignLeft);
searchBtn.onClick.Add(ButtonHandler);
toolbar.AddContent(searchBtn);
NEW(compileBtn); compileBtn.caption.SetAOC("Compile"); compileBtn.alignment.Set(WMComponents.AlignLeft);
compileBtn.onClick.Add(ButtonHandler);
toolbar.AddContent(compileBtn);
NEW(findPCBtn); findPCBtn.caption.SetAOC("Find PC"); findPCBtn.alignment.Set(WMComponents.AlignLeft);
findPCBtn.onClick.Add(FindPC);
toolbar.AddContent(findPCBtn);
NEW(undoBtn);
font := undoBtn.GetFont();
font.GetStringSize(" Undo (000) ", dx, dy);
undoBtn.bounds.SetWidth(dx);
undoBtn.caption.SetAOC("Undo"); undoBtn.alignment.Set(WMComponents.AlignLeft);
undoBtn.onClick.Add(ButtonHandler);
toolbar.AddContent(undoBtn);
NEW(redoBtn);
font := redoBtn.GetFont();
font.GetStringSize(" Redo (000) ", dx, dy);
redoBtn.bounds.SetWidth(dx);
redoBtn.caption.SetAOC("Redo"); redoBtn.alignment.Set(WMComponents.AlignLeft);
redoBtn.onClick.Add(ButtonHandler);
toolbar.AddContent(redoBtn);
NEW(optionsEdit); optionsEdit.tv.showBorder.Set(TRUE); optionsEdit.tv.borders.Set(WMRectangles.MakeRect(3,3,1,1));
optionsEdit.alignment.Set(WMComponents.AlignClient); optionsEdit.multiLine.Set(FALSE);
optionsEdit.bounds.SetWidth(80); optionsEdit.fillColor.Set(0FFFFFFFFH);
optionsEdit.SetAsString(settings.defaultCompilerOptions);
toolbar.AddContent(optionsEdit);
RETURN toolbar;
END CreateToolbar;
PROCEDURE CreateStatusbar() : WMComponents.VisualComponent;
VAR statusbar : WMStandardComponents.Panel;
BEGIN
NEW(statusbar); statusbar.bounds.SetHeight(20); statusbar.alignment.Set(WMComponents.AlignBottom); statusbar.fillColor.Set(0CCCCCCFFH);
NEW(posLabel); posLabel.caption.SetAOC(" Position: "); posLabel.bounds.SetWidth(60); posLabel.alignment.Set(WMComponents.AlignLeft);
statusbar.AddContent(posLabel); posLabel.textColor.Set(0000000FFH);
NEW(positionEdit); positionEdit.tv.showBorder.Set(TRUE); positionEdit.tv.borders.Set(WMRectangles.MakeRect(3,3,1,1));
positionEdit.alignment.Set(WMComponents.AlignLeft); positionEdit.multiLine.Set(FALSE);
positionEdit.bounds.SetWidth(80); positionEdit.fillColor.Set(0FFFFFFFFH); positionEdit.onEnter.Add(PositionHandler);
statusbar.AddContent(positionEdit);
NEW(splitBtn); splitBtn.caption.SetAOC("Split"); splitBtn.alignment.Set(WMComponents.AlignRight);
splitBtn.onClick.Add(SplitHandler);
splitBtn.isToggle.Set(TRUE); splitBtn.SetPressed(FALSE);
statusbar.AddContent(splitBtn);
NEW(labelsBtn); labelsBtn.caption.SetAOC("Labels"); labelsBtn.alignment.Set(WMComponents.AlignRight);
labelsBtn.isToggle.Set(TRUE); labelsBtn.SetPressed(FALSE);
labelsBtn.onClick.Add(ButtonHandler);
statusbar.AddContent(labelsBtn);
NEW(wrapBtn); wrapBtn.caption.SetAOC("Wrap"); wrapBtn.alignment.Set(WMComponents.AlignRight);
wrapBtn.isToggle.Set(TRUE); wrapBtn.SetPressed(FALSE);
wrapBtn.onClick.Add(ButtonHandler);
statusbar.AddContent(wrapBtn);
NEW(errListBtn); errListBtn.caption.SetAOC("Errors"); errListBtn.alignment.Set(WMComponents.AlignRight);
errListBtn.isToggle.Set(FALSE); errListBtn.SetPressed(FALSE);
errListBtn.onClick.Add(ButtonHandler);
statusbar.AddContent(errListBtn);
NEW(findBtn); findBtn.caption.SetAOC("Find"); findBtn.alignment.Set(WMComponents.AlignRight);
findBtn.isToggle.Set(FALSE); findBtn.SetPressed(FALSE);
findBtn.onClick.Add(ButtonHandler);
statusbar.AddContent(findBtn);
NEW(logBtn); logBtn.caption.SetAOC("Log"); logBtn.alignment.Set(WMComponents.AlignRight);
logBtn.isToggle.Set(FALSE); logBtn.SetPressed(FALSE);
logBtn.onClick.Add(ButtonHandler);
statusbar.AddContent(logBtn);
NEW(forwardBtn); forwardBtn.caption.SetAOC("-->"); forwardBtn.alignment.Set(WMComponents.AlignRight);
forwardBtn.onClick.Add(ButtonHandler);
statusbar.AddContent(forwardBtn);
NEW(backBtn); backBtn.caption.SetAOC("<--"); backBtn.alignment.Set(WMComponents.AlignRight);
backBtn.onClick.Add(ButtonHandler);
statusbar.AddContent(backBtn);
RETURN statusbar;
END CreateStatusbar;
BEGIN
NEW(panel); panel.alignment.Set(WMComponents.AlignClient); panel.fillColor.Set(0FFFFFFFFH); panel.takesFocus.Set(TRUE);
NEW(tabs); tabs.fillColor.Set(00000CCCCH); tabs.bounds.SetHeight(20); tabs.alignment.Set(WMComponents.AlignTop);
panel.AddContent(tabs); tabs.SetExtDragDroppedHandler(DragDroppedHandler);
panel.AddContent(CreateToolbar());
panel.AddContent(CreateStatusbar());
NEW(page); page.fillColor.Set(0CCCCCCFFH); page.alignment.Set(WMComponents.AlignClient);
panel.AddContent(page);
RETURN panel;
END CreateForm;
PROCEDURE ButtonHandler(sender, data : ANY);
VAR options : CompilerOptions; searchString : SearchString; res : LONGINT;
BEGIN
IF sender = undoBtn THEN
currentPage.editor.Undo;
ELSIF sender = redoBtn THEN
currentPage.editor.Redo;
ELSIF sender = searchBtn THEN
IF (currentPage # NIL) THEN
currentPage.searchPanel.visible.Set(TRUE);
currentPage.searchPanel.SetToLastSelection;
currentPage.searchPanel.searchEdit.GetAsString(searchString);
IF (searchString # "") THEN
currentPage.searchPanel.SearchHandler(NIL, NIL);
ELSE
currentPage.searchPanel.searchEdit.SetFocus;
END;
END;
ELSIF sender = labelsBtn THEN
IF (currentPage # NIL) THEN currentPage.ToggleLabels; END;
ELSIF sender = compileBtn THEN
IF currentPage # NIL THEN
IF (settings.backupOnCompile) THEN
TextUtilities.StoreOberonText(currentPage.editor.text, BackupOnCompileFilename, res);
IF (res = 0) THEN
KernelLog.String("PET: Backup stored in "); KernelLog.String(BackupOnCompileFilename); KernelLog.Ln;
ELSE
KernelLog.String("PET: Warning: Backup-on-compile file creating failed."); KernelLog.Ln;
END;
END;
optionsEdit.GetAsString(options);
currentPage.DoCompile(FALSE, "", options);
END;
ELSIF sender = wrapBtn THEN
IF (currentPage # NIL) THEN
currentPage.ToggleWrap;
END;
ELSIF sender = logBtn THEN
IF currentPage # NIL THEN currentPage.logEdit.visible.Set(~currentPage.logEdit.visible.Get()) END;
ELSIF sender = findBtn THEN
IF currentPage # NIL THEN currentPage.searchPanel.visible.Set(~currentPage.searchPanel.visible.Get()) END;
ELSIF sender = errListBtn THEN
IF currentPage # NIL THEN currentPage.logPanel.visible.Set(~currentPage.logPanel.visible.Get()) END;
ELSIF sender = backBtn THEN
BrowseBack
ELSIF sender = forwardBtn THEN
BrowseForward
END;
END ButtonHandler;
PROCEDURE NrUpdatesChanged(nrUndos, nrRedos: LONGINT);
VAR lbl, str: ARRAY 32 OF CHAR;
BEGIN
IF nrUndos = 0 THEN
undoBtn.enabled.Set(FALSE);
undoBtn.clDefault.Set(999999FFH);
ELSE
undoBtn.enabled.Set(TRUE);
undoBtn.clDefault.Reset;
END;
lbl := "Undo (";
Strings.IntToStr(nrUndos, str);
Strings.Append(lbl, str);
Strings.Append(lbl, ")");
undoBtn.caption.SetAOC(lbl);
IF nrRedos = 0 THEN
redoBtn.enabled.Set(FALSE);
redoBtn.clDefault.Set(999999FFH);
ELSE
redoBtn.enabled.Set(TRUE);
redoBtn.clDefault.Reset;
END;
lbl := "Redo (";
Strings.IntToStr(nrRedos, str);
Strings.Append(lbl, str);
Strings.Append(lbl, ")");
redoBtn.caption.SetAOC(lbl);
END NrUpdatesChanged;
PROCEDURE ProjectTextModified(sender, data : ANY);
BEGIN
projectTextModified :=TRUE;
END ProjectTextModified;
PROCEDURE InitCodecs;
VAR caption: CaptionObject;
elem: XML.Element; enum: XMLObjects.Enumerator; ptr: ANY; str : Strings.String;
BEGIN
NEW(popup);
elem := Configuration.config.GetRoot();
IF elem # NIL THEN
enum := elem.GetContents(); enum.Reset;
WHILE enum.HasMoreElements() DO
ptr := enum.GetNext();
IF ptr IS XML.Element THEN
str := ptr(XML.Element).GetAttributeValue("name");
IF (str # NIL) & (str^ = "Codecs") THEN
enum := ptr(XML.Element).GetContents(); enum.Reset;
WHILE enum.HasMoreElements() DO
ptr := enum.GetNext();
IF ptr IS XML.Element THEN
str := ptr(XML.Element).GetAttributeValue("name");
IF (str # NIL) & (str^ = "Decoder") THEN
enum := ptr(XML.Element).GetContents(); enum.Reset;
WHILE enum.HasMoreElements() DO
ptr := enum.GetNext();
IF ptr IS XML.Element THEN
str := ptr(XML.Element).GetAttributeValue("name");
IF (str # NIL) & (str^ = "Text") THEN
enum := ptr(XML.Element).GetContents(); enum.Reset;
WHILE enum.HasMoreElements() DO
ptr := enum.GetNext();
IF ptr IS XML.Element THEN
str := ptr(XML.Element).GetAttributeValue("name");
NEW(caption, str^);
popup.AddParButton(str^, FormatPopupHandler, caption);
END;
END;
END;
END;
END;
END;
END;
END;
END;
END;
END;
END;
NEW(caption, "AUTO");
popup.AddParButton("AUTO", FormatPopupHandler, caption);
END InitCodecs;
PROCEDURE SelectNextTab;
VAR i : LONGINT;
BEGIN
IF currentPageNr < 0 THEN RETURN; END;
i := currentPageNr + 1;
LOOP
IF (i >= MaxNbrOfTabs) OR (pages[i] # NIL) THEN EXIT; END;
INC(i);
END;
IF (i < MaxNbrOfTabs) THEN
SelectTab(i);
END;
END SelectNextTab;
PROCEDURE SelectPreviousTab;
VAR i : LONGINT;
BEGIN
IF currentPageNr < 0 THEN RETURN; END;
i := currentPageNr - 1;
LOOP
IF (i < 0) OR (pages[i] # NIL) THEN EXIT; END;
DEC(i);
END;
IF (i >= 0) THEN
SelectTab(i);
END;
END SelectPreviousTab;
PROCEDURE SelectTab(tabNr : LONGINT);
BEGIN
IF (tabNr >= 0) & (tabNr < LEN(SELF.pages)) & (SELF.pages[tabNr] # NIL) THEN
TabSelected(NIL, tabList[tabNr]);
tabs.Select(tabList[tabNr]);
END;
END SelectTab;
PROCEDURE RecordCurrentPos;
VAR be : BrowseEntry;
BEGIN
IF (currentPage # NIL) THEN
NEW(be);
COPY(currentPage.filename, be.filename);
be.pos := currentPage.editor.tv.cursor.GetPosition();
be.next := NIL;
be.prev := browseTOS;
browseTOS.next := be;
browseTOS := be;
END;
END RecordCurrentPos;
PROCEDURE GotoFileInternal(CONST filename : ARRAY OF CHAR; pos : LONGINT);
VAR page : PETPanel; i : LONGINT;
BEGIN
KernelLog.String("filename= "); KernelLog.String(filename); KernelLog.Ln;
KernelLog.String("pos= "); KernelLog.Int(pos, 0); KernelLog.Ln;
i := 0;
page := NIL;
WHILE (i < LEN(pages)-1) & (page = NIL) DO
IF (pages[i] # NIL) & (pages[i].filename = filename) THEN
page := pages[i];
ELSE
INC(i);
END;
END;
IF (page = NIL) THEN
Load(filename, "AUTO");
page := currentPage;
ELSE
SelectTab(i);
END;
IF (page # NIL) THEN
currentPage.editor.tv.cursor.SetPosition(pos);
IF (currentPage.tree # NIL) THEN
currentPage.tree.SelectNodeByPos(pos);
END;
END;
END GotoFileInternal;
PROCEDURE BrowseBack;
BEGIN
IF browseTOS.prev # browseBase THEN
browseTOS := browseTOS.prev;
GotoFileInternal(browseTOS.filename, browseTOS.pos);
END
END BrowseBack;
PROCEDURE BrowseForward;
BEGIN
IF browseTOS.next # NIL THEN
browseTOS := browseTOS.next;
GotoFileInternal(browseTOS.filename, browseTOS.pos)
END
END BrowseForward;
PROCEDURE GotoFile(CONST filename : ARRAY OF CHAR; pos : LONGINT);
VAR page : PETPanel; i : LONGINT;
BEGIN
IF browseTOS = browseBase THEN RecordCurrentPos END;
i := 0;
page := NIL;
WHILE (i < LEN(pages)-1) & (page = NIL) DO
IF (pages[i] # NIL) & (pages[i].name = filename) THEN
page := pages[i];
ELSE
INC(i);
END;
END;
IF (page = NIL) THEN
Load(filename, "AUTO");
page := currentPage;
ELSE
SelectTab(i);
END;
IF (page # NIL) THEN
currentPage.editor.tv.cursor.SetPosition(pos);
IF (currentPage.tree # NIL) THEN
currentPage.tree.SelectNodeByPos(pos);
END;
RecordCurrentPos
END
END GotoFile;
PROCEDURE GotoDefinition(info : PETTrees.ExternalDefinitionInfo);
VAR page : PETPanel; i : LONGINT;
BEGIN
IF info.filename = "" THEN RETURN END;
IF browseTOS = browseBase THEN RecordCurrentPos END;
i := 0;
page := NIL;
WHILE (i < LEN(pages)-1) & (page = NIL) DO
IF (pages[i] # NIL) & (pages[i].filename = info.filename) THEN
page := pages[i];
ELSE
INC(i);
END;
END;
IF (page = NIL) THEN
Load(info.filename, "AUTO");
page := currentPage;
ELSE
SelectTab(i);
END;
IF (page # NIL) THEN
IF (currentPage.tree # NIL) THEN
currentPage.tree.BrowseToDefinition(SELF, info);
END;
RecordCurrentPos
END;
END GotoDefinition;
PROCEDURE GetNrFromPage(page : PETPanel): LONGINT;
VAR i : LONGINT; found : BOOLEAN;
BEGIN
i := 0; found := FALSE;
WHILE (~found & (i < MaxNbrOfTabs)) DO
IF (page = pages[i]) THEN RETURN i END;
INC(i)
END;
RETURN -1
END GetNrFromPage;
PROCEDURE TabSelected(sender, data : ANY);
VAR tab : WMTabComponents.Tab;
BEGIN
IF (data # NIL) & (data IS WMTabComponents.Tab) THEN
DisableUpdate;
optionsEdit.GetAsString(currentPage.options);
compileBtn.caption.SetAOC(currentPage.compilerSettings.caption);
findPCBtn.visible.Set(currentPage.compilerSettings.findPC);
page.RemoveContent(currentPage);
tab := data(WMTabComponents.Tab);
IF (tab.data # NIL) & (tab.data IS WMComponents.VisualComponent) THEN
currentPage := tab.data(PETPanel);
currentPageNr := GetNrFromPage(currentPage);
page.AddContent(currentPage);
IF ~currentPage.initialized THEN currentPage.Initialize END;
currentPage.Reset(SELF, NIL);
page.AlignSubComponents;
END;
EnableUpdate;
UpdateState;
page.Invalidate
END
END TabSelected;
PROCEDURE UpdatePages;
VAR i : LONGINT;
tab : WMTabComponents.Tab;
s : Strings.String;
foundModifiedPage : BOOLEAN;
BEGIN
DisableUpdate;
tabs.RemoveAllTabs;
IF currentPage # NIL THEN page.RemoveContent(currentPage);
currentPage := NIL
END;
IF currentPageNr >= 0 THEN currentPage := pages[currentPageNr] END;
foundModifiedPage := FALSE;
FOR i := 0 TO 99 DO
tabList[i] := NIL;
IF pages[i] # NIL THEN
pages[i].alignment.Set(WMComponents.AlignClient);
tab := tabs.NewTab();
tab.attention := pages[i].modified;
foundModifiedPage := foundModifiedPage OR pages[i].modified;
tabs.AddTab(tab);
tabList[i] := tab;
s := Strings.NewString(pages[i].name);
tabs.SetTabCaption(tab, s);
tabs.SetTabData(tab, pages[i]);
END
END;
IF currentPage = NIL THEN
i := 0;
WHILE (i < MaxNbrOfTabs) & (currentPage = NIL) DO
IF pages[i] # NIL THEN currentPage := pages[i]; currentPageNr := i END;
INC(i);
END;
IF currentPage = NIL THEN SetModified(FALSE) END;
END;
IF currentPage # NIL THEN
IF ~currentPage.initialized THEN currentPage.Initialize END;
page.AddContent(currentPage);
currentPage.Reset(SELF, NIL);
page.AlignSubComponents;
page.Invalidate;
IF tabList[currentPageNr] # NIL THEN tabs.Select(tabList[currentPageNr]) END
END;
UpdateState;
EnableUpdate;
UpdateInfo;
IF foundModifiedPage THEN
SetIcon(iconWorking);
ELSE
SetIcon(iconIdle);
END;
END UpdatePages;
PROCEDURE UpdateInfo;
VAR i, j : LONGINT;
BEGIN
FOR i := 0 TO LEN(windowInfo.openDocuments)-1 DO windowInfo.openDocuments[i].name := ""; END;
windowInfo.handleDocumentInfo := HandleDocumentInfo;
windowInfo.vc.generator := NIL;
j := 0;
FOR i := 0 TO LEN(pages)-1 DO
IF (pages[i] # NIL) & (j < LEN(windowInfo.openDocuments)) THEN
windowInfo.openDocuments[j].id := i;
COPY(pages[i].name, windowInfo.openDocuments[j].name);
COPY(pages[i].filename, windowInfo.openDocuments[j].fullname);
windowInfo.openDocuments[j].modified := pages[i].modified;
windowInfo.openDocuments[j].hasFocus := pages[i] = currentPage;
INC(j);
END;
END;
SetInfo(windowInfo);
END UpdateInfo;
PROCEDURE HandleDocumentInfo(CONST info : WMWindowManager.DocumentInfo; new : BOOLEAN; VAR res : LONGINT);
BEGIN
IF (pages[info.id] # NIL) THEN SelectTab(info.id); END;
END HandleDocumentInfo;
PROCEDURE UpdateState;
VAR tInt : LONGINT; tStr : ARRAY 16 OF CHAR;
PROCEDURE SetSplitted(splitted : BOOLEAN);
BEGIN
IF splitted THEN splitBtn.SetPressed(TRUE); ELSE splitBtn.SetPressed(FALSE); END;
END SetSplitted;
PROCEDURE SetLabels(show : BOOLEAN);
BEGIN
IF show THEN labelsBtn.SetPressed(TRUE); ELSE labelsBtn.SetPressed(FALSE); END;
END SetLabels;
PROCEDURE SetWrap(wrap : BOOLEAN);
BEGIN
IF wrap THEN wrapBtn.SetPressed(TRUE); ELSE wrapBtn.SetPressed(FALSE); END;
END SetWrap;
PROCEDURE ResetUndo;
BEGIN
undoBtn.caption.Reset;
redoBtn.caption.Reset;
undoBtn.clDefault.Reset;
redoBtn.clDefault.Reset;
END ResetUndo;
BEGIN
IF (currentPage # NIL) THEN
SetModified(currentPage.modified);
SetSplitted(currentPage.splitted);
SetWrap(currentPage.wrap);
SetLabels(currentPage.editor.tv.showLabels.Get());
SetFormatCaption(currentPage.codecFormat);
filenameEdit.SetAsString(currentPage.filename);
optionsEdit.SetAsString(currentPage.options);
compileBtn.caption.SetAOC(currentPage.compilerSettings.caption);
findPCBtn.visible.Set(currentPage.compilerSettings.findPC);
currentPage.editor.tv.cursor.SetVisible(TRUE);
currentPage.editor.SetFocus;
tInt := currentPage.editor.tv.cursor.GetPosition(); Strings.IntToStr(tInt, tStr);
positionEdit.SetAsString(tStr);
IF currentPage.editor.undoMgr # NIL THEN
NrUpdatesChanged(currentPage.editor.undoMgr.nrUndoUpdates, currentPage.editor.undoMgr.nrRedoUpdates);
END;
ELSE
SetModified(FALSE);
SetSplitted(FALSE);
SetWrap(FALSE);
codecFormat := "AUTO";
autoCodecFormat := DefaultTextFormat;
SetFormatCaption("AUTO");
storeBtn.caption.SetAOC("Store");
filenameEdit.SetAsString("");
optionsEdit.SetAsString("");
compileBtn.caption.Reset;
findPCBtn.visible.Set(FALSE);
positionEdit.SetAsString("-");
ResetUndo;
END;
END UpdateState;
PROCEDURE DragDroppedHandler(x, y : LONGINT; dragInfo : WMWindowManager.DragInfo; VAR handled : BOOLEAN);
VAR dropTarget : URLDropTarget;
BEGIN
NEW(dropTarget, SELF);
dragInfo.data := dropTarget;
ConfirmDrag(TRUE, dragInfo)
END DragDroppedHandler;
PROCEDURE PositionHandler(sender, data : ANY);
VAR tempString : ARRAY 16 OF CHAR;
tempInt : LONGINT;
BEGIN
IF (currentPage # NIL) THEN
positionEdit.GetAsString(tempString);
Strings.StrToInt(tempString, tempInt);
currentPage.editor.tv.cursor.SetPosition(tempInt);
currentPage.editor.tv.cursor.SetVisible(TRUE);
currentPage.editor.SetFocus;
END
END PositionHandler;
PROCEDURE FormatHandler(x, y: LONGINT; keys: SET; VAR handled: BOOLEAN);
VAR rectangle: WMRectangles.Rectangle;
BEGIN
handled := TRUE;
rectangle := formatBtn.bounds.Get();
popup.Popup(bounds.l + rectangle.l, bounds.t + rectangle.b+ 20);
END FormatHandler;
PROCEDURE SetFormatCaption(CONST format: ARRAY OF CHAR);
VAR caption : ARRAY 100 OF CHAR;
BEGIN
caption := "Format : ";
Strings.Append(caption, format);
IF (format = "AUTO") THEN
IF (currentPage # NIL) THEN Strings.Append(caption, " "); Strings.Append(caption, currentPage.autoCodecFormat);
ELSE Strings.Append(caption, " "); Strings.Append(caption, autoCodecFormat);
END;
END;
formatBtn.caption.SetAOC(caption);
END SetFormatCaption;
PROCEDURE SetCursorPosition (position: LONGINT);
VAR string : ARRAY 16 OF CHAR;
BEGIN
IF (currentPage # NIL) THEN
Strings.IntToStr(position, string);
positionEdit.SetAsString(string);
currentPage.editor.tv.cursor.SetPosition(position);
END;
END SetCursorPosition;
PROCEDURE SetModified(modified : BOOLEAN);
BEGIN
IF currentPage # NIL THEN
tabList[currentPageNr].attention := modified;
tabs.Invalidate;
IF modified THEN
SetIcon(iconWorking);
storeBtn.caption.SetAOC("Store !")
ELSE
storeBtn.caption.SetAOC("Store");
END;
END
END SetModified;
PROCEDURE SetIcon(icon : WMGraphics.Image);
BEGIN
IF (icon # NIL) & (icon # currentIcon) THEN
currentIcon := icon;
SetIcon^(icon);
END;
END SetIcon;
PROCEDURE FormatPopupHandler(sender, data: ANY);
BEGIN
IF (data # NIL) & (data IS CaptionObject) THEN
popup.Close;
IF (currentPage # NIL) THEN
COPY(data(CaptionObject).caption, currentPage.codecFormat);
COPY(currentPage.codecFormat, codecFormat);
COPY(currentPage.autoCodecFormat, autoCodecFormat);
ELSE
COPY(data(CaptionObject).caption, codecFormat);
COPY(DefaultTextFormat, autoCodecFormat);
END;
SetFormatCaption(codecFormat);
END
END FormatPopupHandler;
PROCEDURE FilenameEditEscapeHandler(sernder, data : ANY);
BEGIN
IF (currentPage # NIL) THEN
filenameEdit.SetAsString(currentPage.filename);
END;
END FilenameEditEscapeHandler;
PROCEDURE LoadHandler(sender, data : ANY);
VAR filename : Filename; command : ARRAY 1024 OF CHAR; msg : ARRAY 64 OF CHAR; ignoreRes : LONGINT;
BEGIN
filenameEdit.GetAsString(filename);
Strings.TrimWS(filename);
IF (filename # "") THEN
IF (Inputs.LeftShift IN modifierFlags) THEN
command := "PET.Open "; Strings.AppendX(command, filename);
Commands.Call(command, {}, ignoreRes, msg);
IF (currentPage # NIL) THEN
filenameEdit.SetAsString(currentPage.filename);
ELSE
filenameEdit.SetAsString("");
END;
ELSE
Load(filename, codecFormat);
IF (currentPage # NIL) THEN
optionsEdit.GetAsString(currentPage.options);
END;
END;
END;
END LoadHandler;
PROCEDURE Load(CONST filename, format : ARRAY OF CHAR);
VAR
text : Texts.Text; res : LONGINT;
decoder : Codecs.TextDecoder;
msg : ARRAY 512 OF CHAR;
readonly : BOOLEAN;
name, fullname, archiveName, entryName, path : Filename;
syntaxHighlighterName : ARRAY 32 OF CHAR;
file : Files.File;
in: Streams.Reader;
BEGIN
DisableUpdate;
res := -1;
NewTab;
Codecs.SplitName(filename, archiveName, entryName);
IF (archiveName # "") THEN
COPY(archiveName, name);
ELSE
COPY(filename, name);
END;
COPY(name, fullname);
readonly := FALSE;
file := Files.Old(name);
IF (file # NIL) THEN
file.GetName(fullname);
readonly := Files.ReadOnly IN file.flags;
ELSE
file := Files.New(name);
IF (file # NIL) THEN
file.GetName(fullname);
file := NIL;
END;
END;
IF (archiveName # "") THEN
Codecs.JoinName(fullname, entryName, currentPage.filename);
ELSE
COPY(fullname, currentPage.filename);
END;
IF (settings.showPathInTabs) THEN
COPY(fullname, currentPage.name);
IF (archiveName # "") THEN Codecs.JoinName(currentPage.name, entryName, currentPage.name); END;
ELSE
Files.SplitPath(fullname, path, currentPage.name);
IF (archiveName # "") THEN Codecs.JoinName(currentPage.name, entryName, currentPage.name); END;
END;
IF readonly THEN Strings.Append(currentPage.name, " (R)"); END;
IF (archiveName # "") THEN Codecs.JoinName(fullname, entryName, fullname); END;
filenameEdit.SetAsString(fullname);
IF projectText # NIL THEN
currentPage.scratch.SetText(projectText);
END;
text := currentPage.editor.text;
text.AcquireWrite;
currentPage.modified := TRUE;
text.Delete(0, text.GetLength());
currentPage.editor.tv.firstLine.Set(0);
currentPage.editor.tv.onLinkClicked.Add(LinkClickedHandler);
text.ReleaseWrite;
IF (file # NIL) THEN
IF (format = "AUTO") THEN
decoder := TextUtilities.DecodeAuto(fullname, autoCodecFormat);
COPY(autoCodecFormat, currentPage.autoCodecFormat);
ELSE
decoder := Codecs.GetTextDecoder(format);
END;
IF (decoder # NIL) THEN
COPY(format, currentPage.codecFormat);
in := Codecs.OpenInputStream(fullname);
IF in # NIL THEN
decoder.Open(in, res);
IF res = 0 THEN
currentPage.editor.text.onTextChanged.Remove(currentPage.TextChanged);
currentPage.editor.SetText(decoder.GetText());
currentPage.searchPanel.SetText(decoder.GetText());
currentPage.splitEditor.SetText(currentPage.editor.text);
currentPage.editor.text.onTextChanged.Add(currentPage.TextChanged);
currentPage.editor.text.SetUndoManager(currentPage.editor.undoMgr)
END;
ELSE
msg := "Can't open input stream on file "; Strings.Append(msg, fullname);
WMDialogs.Error(WindowTitle, msg);
END;
ELSE
msg := "No decoder for file "; Strings.Append(msg, fullname);
Strings.Append(msg, " (Format: "); Strings.Append(msg, format); Strings.Append(msg, ")");
WMDialogs.Error(WindowTitle, msg);
END;
END;
SetFormatCaption(format);
currentPage.editor.tv.firstLine.Set(0);
currentPage.editor.tv.cursor.SetPosition(0);
currentPage.editor.tv.SetFocus;
currentPage.searchPanel.SetSettings(settings.searchWrap, settings.searchCaseSensitive, FALSE, settings.searchHighlightAll);
currentPage.compilerSettings := settings.GetCompilerSettings(filename);
currentPage.options := currentPage.compilerSettings.options;
GetSyntaxHighlighterName(filename, syntaxHighlighterName);
IF (syntaxHighlighterName # "") THEN
currentPage.editor.highlighting.SetAOC(syntaxHighlighterName);
currentPage.splitEditor.highlighting.SetAOC(syntaxHighlighterName);
END;
currentPage.CreateSidePanel(currentPage.compilerSettings);
COPY(currentPage.name, tabList[currentPageNr].caption^); tabs.Invalidate;
currentPage.modified := FALSE;
SetModified(FALSE);
UpdatePages;
EnableUpdate;
form.Invalidate;
END Load;
PROCEDURE StoreHandler(sender, data : ANY);
VAR filename : Filename;
BEGIN
IF (currentPage # NIL) THEN
filenameEdit.GetAsString(filename);
Strings.TrimWS(filename);
IF filename # "" THEN
Store(filename, currentPage.codecFormat);
ELSE
WMDialogs.Error(WindowTitle, "Filename invalid");
filenameEdit.SetAsString(currentPage.filename);
END;
END
END StoreHandler;
PROCEDURE Store(CONST filename, format : ARRAY OF CHAR);
VAR
res : LONGINT;
msg : ARRAY 512 OF CHAR;
name, backName, fullname, archiveName, entryName, path: Filename;
syntaxHighlighterName : ARRAY 32 OF CHAR;
backExt, t, ext: ARRAY 12 OF CHAR;
options : CompilerOptions;
encoder : Codecs.TextEncoder;
w : Streams.Writer; i : LONGINT;
file, oldFile : Files.File;
PROCEDURE FileExists(CONST filename : ARRAY OF CHAR) : BOOLEAN;
BEGIN
RETURN Files.Old(filename) # NIL
END FileExists;
PROCEDURE CreateBackupFile;
BEGIN
IF settings.backupOnStore = Paranoid THEN
Strings.Concat(filename, ".Bak", backName);
IF FileExists(backName) THEN
i := 0;
REPEAT
backExt := "."; Strings.IntToStr(i, t);
Strings.Append(backExt, t); Strings.Append(backExt, ".Bak");
Strings.Concat(filename, backExt, backName);
INC(i);
UNTIL ~FileExists(backName);
END;
ELSE
ASSERT(settings.backupOnStore = Yes);
Strings.Concat(filename, ".Bak", backName);
END;
Files.Rename(filename, backName, res);
IF res = Files.Ok THEN KernelLog.String("Backup created in "); KernelLog.String(backName); KernelLog.Ln END;
END CreateBackupFile;
BEGIN
IF currentPage # NIL THEN
filenameEdit.SetAsString(filename);
Codecs.SplitName(filename, archiveName, entryName);
IF (archiveName # "") THEN
COPY(archiveName, name);
ELSE
COPY(filename, name);
END;
COPY(name, fullname);
oldFile := Files.Old(name);
IF (oldFile # NIL) THEN
IF (Files.ReadOnly IN oldFile.flags) THEN
msg := "File is read-only: "; Strings.Append(msg, name);
WMDialogs.Error("Error", msg);
RETURN;
END;
END;
IF (archiveName = "") & (settings.backupOnStore # No) THEN CreateBackupFile; END;
IF (format = "AUTO") THEN
IF (currentPage.autoCodecFormat = "") THEN
encoder := Codecs.GetTextEncoder(DefaultTextFormat);
ELSE
encoder := Codecs.GetTextEncoder(currentPage.autoCodecFormat);
IF encoder = NIL THEN
encoder := Codecs.GetTextEncoder(DefaultTextFormat);
END;
END;
ELSE
encoder := Codecs.GetTextEncoder(format);
END;
IF (encoder # NIL) THEN
IF (archiveName # "") & (oldFile # NIL) THEN
file := oldFile;
ELSE
oldFile := NIL;
file := Files.New(name);
IF (file = NIL) THEN
msg := "Could not create file "; Strings.Append(msg, name);
WMDialogs.Error(WindowTitle, msg);
RETURN;
END;
END;
file.GetName(fullname);
IF (archiveName # "") THEN Codecs.JoinName(fullname, entryName, fullname); END;
filenameEdit.SetAsString(fullname);
w := Codecs.OpenOutputStream(fullname);
IF (w # NIL) THEN
encoder.Open(w);
currentPage.editor.text.AcquireWrite;
encoder.WriteText(currentPage.editor.text, res);
currentPage.editor.text.ReleaseWrite;
w.Update;
IF res # 0 THEN
msg := "Could not encode file "; Strings.Append(msg, fullname);
WMDialogs.Error(WindowTitle, msg);
END;
ELSE
msg := "Could not store to file "; Strings.Append(msg, fullname); Strings.Append(msg, " (Could not open output stream)");
WMDialogs.Error(WindowTitle, msg);
END;
ELSE
msg := "Could not store file "; Strings.Append(msg, fullname); Strings.Append(msg, " (No encoder found)");
WMDialogs.Error(WindowTitle, msg);
END;
IF (settings.showPathInTabs) THEN
COPY(fullname, pages[currentPageNr].name);
ELSE
IF (archiveName # "") THEN
Files.SplitPath(archiveName, path, name);
Codecs.JoinName(name, entryName, pages[currentPageNr].name);
ELSE
Files.SplitPath(fullname, path, pages[currentPageNr].name);
END;
END;
tabs.SetTabCaption(tabList[currentPageNr], Strings.NewString(currentPage.name));
tabs.Invalidate;
Files.SplitExtension (fullname, backName, ext);
Files.SplitExtension (currentPage.filename, backName, backExt);
IF ext # backExt THEN
currentPage.compilerSettings := settings.GetCompilerSettings(name);
currentPage.options := currentPage.compilerSettings.options;
optionsEdit.SetAsString(currentPage.options);
GetSyntaxHighlighterName(filename, syntaxHighlighterName);
IF (syntaxHighlighterName # "") THEN
currentPage.editor.highlighting.SetAOC(syntaxHighlighterName);
currentPage.editor.highlighting.SetAOC(syntaxHighlighterName);
END;
END;
COPY(fullname, currentPage.filename);
compileBtn.caption.SetAOC(currentPage.compilerSettings.caption);
findPCBtn.visible.Set(currentPage.compilerSettings.findPC);
optionsEdit.GetAsString(options); COPY(options, currentPage.options);
currentPage.modified := FALSE;
SetModified(FALSE);
IF HasModifiedPage() THEN
SetIcon(iconWorking);
ELSE
SetIcon(iconIdle);
END;
END
END Store;
PROCEDURE NewTab;
VAR pet : PETPanel;
i : LONGINT;
found : BOOLEAN;
BEGIN
found := FALSE;
NEW(pet, SELF); pet.alignment.Set(WMComponents.AlignClient); pet.fillColor.Set(0FFFFFFFFH); pet.takesFocus.Set(TRUE);
IF pet.editor.undoMgr # NIL THEN
pet.editor.undoMgr.nrUpdatesListener := NrUpdatesChanged;
NrUpdatesChanged(0, 0);
END;
IF (pet.scratchPanel # NIL) THEN
pet.scratchPanel.bounds.SetHeight(settings.scratchPanelHeight);
END;
i := 0;
WHILE (i < MaxNbrOfTabs) & (~found) DO
IF pages[i] = NIL THEN pages[i] := pet; currentPageNr := i; found := TRUE; END;
INC(i)
END;
UpdatePages;
END NewTab;
PROCEDURE HasModifiedPage() : BOOLEAN;
VAR modified : BOOLEAN; i : LONGINT;
BEGIN
modified := FALSE;
i := 0;
WHILE ~modified & (i < MaxNbrOfTabs) DO
IF (pages[i] # NIL) & (pages[i].modified) THEN
modified := TRUE;
END;
INC(i);
END;
RETURN modified;
END HasModifiedPage;
PROCEDURE CloseAllTabs() : BOOLEAN;
VAR res, i : LONGINT;
BEGIN
i := 0;
LOOP
IF i >= MaxNbrOfTabs THEN EXIT; END;
IF (pages[i] # NIL) & (pages[i].modified) THEN
res := WMDialogs.Confirmation(WindowTitle, "At least on page has not been stored. Continue?");
IF res = WMDialogs.ResNo THEN
RETURN FALSE;
ELSIF res = WMDialogs.ResYes THEN
EXIT;
END;
END;
INC(i);
END;
i := 0;
WHILE (i < MaxNbrOfTabs) DO
IF (pages[i] # NIL) THEN pages[i].Finalize; pages[i] := NIL; END;
INC(i);
END;
UpdatePages;
form.Invalidate;
RETURN TRUE;
END CloseAllTabs;
PROCEDURE CloseHandler(sender, data: ANY);
VAR found : BOOLEAN; i : LONGINT;
BEGIN
IF (currentPage = NIL) OR (currentPage.modified) & (
WMDialogs.Confirmation(WindowTitle, "The current text was not stored. Continue ?") = WMDialogs.ResNo)
THEN RETURN END;
found := FALSE; i := 0;
WHILE (~found & (i < MaxNbrOfTabs)) DO
IF (currentPage = pages[i]) THEN pages[i].Finalize; pages[i] := NIL; found := TRUE END;
INC(i);
END;
IF found & (i >= 2) THEN currentPageNr := i-2; END;
UpdatePages;
form.Invalidate;
END CloseHandler;
PROCEDURE SplitHandler(sender, data: ANY);
BEGIN
IF (currentPage # NIL) THEN
IF currentPage.splitted THEN
currentPage.splitPanel.visible.Set(FALSE);
currentPage.editor.SetFocus;
ELSE
currentPage.splitPanel.visible.Set(TRUE);
END;
currentPage.splitted := ~currentPage.splitted
END
END SplitHandler;
PROCEDURE LinkClickedHandler(sender, data : ANY);
BEGIN
IF data IS WMTextView.LinkWrapper THEN
KernelLog.String("Link: "); KernelLog.String(data(WMTextView.LinkWrapper).link^); KernelLog.Ln
END;
END LinkClickedHandler;
PROCEDURE FindPC(sender, data : ANY);
VAR a, b : LONGINT;
pcStr : ARRAY 128 OF CHAR;
selectionText: Texts.Text;
from, to: Texts.TextPosition;
options : CompilerOptions;
BEGIN
IF currentPage = NIL THEN RETURN; END;
IF Texts.GetLastSelection(selectionText, from, to) THEN
selectionText.AcquireRead;
a := Strings.Min(from.GetPosition(), to.GetPosition());
b := Strings.Max(from.GetPosition(), to.GetPosition());
TextUtilities.SubTextToStr(selectionText, a, b - a, pcStr);
selectionText.ReleaseRead;
Strings.Trim(pcStr, " ");
END;
optionsEdit.GetAsString(options);
IF pcStr = "" THEN
IF WMDialogs.QueryString("Enter PC to locate", pcStr) = WMDialogs.ResOk THEN
currentPage.DoCompile(TRUE, pcStr, options)
END
ELSE
currentPage.DoCompile(TRUE, pcStr, options)
END
END FindPC;
PROCEDURE UnloadModule;
VAR
path, filename : Files.FileName;
name, extension, msg : ARRAY 128 OF CHAR;
tw : TextUtilities.TextWriter; res : LONGINT;
BEGIN
ASSERT(currentPage # NIL);
Files.SplitPath(currentPage.filename, path, filename);
Strings.GetExtension(filename, name, extension);
IF (name # "PET") THEN
Modules.FreeModule(name, res, msg);
ELSE
res := -1; msg := "Unloading module PET not allowed! PET is running.";
END;
IF res = 0 THEN
msg := "Module "; Strings.Append(msg, name); Strings.Append(msg, " unloaded.");
END;
currentPage.ClearLog;
NEW(tw, currentPage.logEdit.text); tw.String (msg); tw.Update;
IF currentPage.logEdit.visible.Get() = FALSE THEN currentPage.logEdit.visible.Set(TRUE); END;
END UnloadModule;
PROCEDURE Close;
VAR page : LONGINT;
BEGIN
Close^;
FOR page := 0 TO LEN(pages)-1 DO
IF pages[page] # NIL THEN pages[page].Finalize; END;
END;
IF projectTextModified THEN
StoreText(projectTextFilename, projectText);
END;
DecCount;
END Close;
PROCEDURE Error(pos, line, row: LONGINT; CONST msg: ARRAY OF CHAR);
BEGIN
xmlHasErrors := TRUE;
END Error;
PROCEDURE LoadState(CONST filename : ARRAY OF CHAR) : BOOLEAN;
VAR
file : Files.File;
scanner : XMLScanner.Scanner;
parser : XMLParser.Parser;
reader : Files.Reader;
doc : XML.Document;
elem : XML.Element;
string : XML.String;
msg : ARRAY 128 OF CHAR;
BEGIN
xmlHasErrors := FALSE;
file := Files.Old(filename);
IF file # NIL THEN
NEW(reader, file, 0);
NEW(scanner, reader); scanner.reportError := Error;
NEW(parser, scanner); parser.reportError := Error;
doc := parser.Parse();
IF xmlHasErrors THEN
msg := "Could not load state: "; Strings.Append(msg, filename); Strings.Append(msg, " could not be parsed");
WMDialogs.Error(WindowTitle, msg);
RETURN FALSE;
END;
elem := doc.GetRoot();
IF elem # NIL THEN string := elem.GetName(); END;
IF (string # NIL) & (string^ = "PETData") THEN
DisableUpdate;
LoadPages(doc.GetRoot());
EnableUpdate;
ELSE
msg := "Could not load state: "; Strings.Append(msg, filename); Strings.Append(msg, " not valid");
WMDialogs.Error(WindowTitle, msg);
RETURN FALSE;
END;
ELSE
msg := "Could not load state: XML file "; Strings.Append(msg, filename); Strings.Append(msg, " not found");
WMDialogs.Error(WindowTitle, msg);
RETURN FALSE;
END;
RETURN TRUE;
END LoadState;
PROCEDURE StoreState(CONST filename : ARRAY OF CHAR);
VAR state : XML.Element; file : Files.File; w : Files.Writer;
BEGIN
file := Files.New(filename);
IF file # NIL THEN
Files.OpenWriter(w, file, 0);
state := StorePages();
state.Write(w, NIL, 0);
w.Update;
Files.Register(file);
KernelLog.String("PET state saved into "); KernelLog.String(filename); KernelLog.Ln;
ELSE
WMDialogs.Error(WindowTitle, "Could not create file");
END;
END StoreState;
PROCEDURE LoadPages(pages : XML.Element);
VAR
elem : XML.Element; enum : XMLObjects.Enumerator; ptr : ANY; s : XML.String;
selectedPageNr : LONGINT;
BEGIN
selectedPageNr := -1;
enum := pages.GetContents(); enum.Reset;
WHILE (enum.HasMoreElements()) DO
ptr := enum.GetNext();
IF ptr IS XML.Element THEN
elem := ptr(XML.Element);
s := elem.GetName();
IF (s # NIL) & (s^ = "Tab") THEN
LoadPage(elem);
ELSIF (s # NIL) & (s^ = "General") THEN
WMRestorable.LoadLongint(elem, "SelectedPageNr", selectedPageNr);
WMRestorable.LoadString(elem, "ProjectTextFile", projectTextFilename);
IF projectTextFilename # "" THEN
projectText := LoadText(projectTextFilename);
projectText.onTextChanged.Add(ProjectTextModified);
END;
END;
END;
END;
IF (selectedPageNr >= 0) & (selectedPageNr < LEN(SELF.pages)) & (SELF.pages[selectedPageNr] # NIL) THEN
TabSelected(NIL, tabList[selectedPageNr]);
tabs.Select(tabList[selectedPageNr]);
END;
END LoadPages;
PROCEDURE StorePages() : XML.Element;
VAR data, elem : WMRestorable.XmlElement; i : LONGINT;
BEGIN
NEW(data); data.SetName("PETData");
NEW(elem); elem.SetName("General");
WMRestorable.StoreLongint(elem, "SelectedPageNr", currentPageNr);
WMRestorable.StoreString(elem, "ProjectTextFile", projectTextFilename);
data.AddContent(elem);
WHILE (i < MaxNbrOfTabs) DO
IF (pages[i] # NIL) THEN
elem := StorePage(pages[i]);
data.AddContent(elem);
END;
INC(i)
END;
RETURN data;
END StorePages;
PROCEDURE LoadPage(page : WMRestorable.XmlElement);
VAR
entries: XMLObjects.Enumerator;
entry : XML.Element;
s : Strings.String;
firstLine, cursorPos, width, height : LONGINT;
options : CompilerOptions;
showLabels, wordWrap, visible, wrap, caseSensitive, backwards, highlightAll : BOOLEAN;
searchString, replaceString : WMSearchComponents.SearchString;
ptr : ANY;
BEGIN
WMRestorable.LoadString(page, "codecFormat", codecFormat);
WMRestorable.LoadString(page, "compilerOptions", options);
WMRestorable.LoadBoolean(page, "showLabels", showLabels);
WMRestorable.LoadBoolean(page, "wordWrap", wordWrap);
WMRestorable.LoadStringPtr(page, "file", s);
IF (s # NIL) THEN
Load(s^, codecFormat);
COPY(options, currentPage.options);
optionsEdit.SetAsString(options);
IF showLabels THEN currentPage.ToggleLabels; labelsBtn.SetPressed(TRUE); END;
IF wordWrap THEN currentPage.ToggleWrap; wrapBtn.SetPressed(TRUE); END;
entries := page.GetContents(); entries.Reset;
WHILE(entries.HasMoreElements()) DO
ptr := entries.GetNext();
IF ptr IS XML.Element THEN
entry := ptr (XML.Element);
s := entry.GetName();
IF (s # NIL) THEN
IF (s^ = "Editor") THEN
WMRestorable.LoadLongint(entry, "firstLine", firstLine);
WMRestorable.LoadLongint(entry, "cursorPos", cursorPos);
currentPage.editor.tv.firstLine.Set(firstLine);
currentPage.editor.tv.cursor.SetPosition(cursorPos);
ELSIF (s^ = "SplitEditor") THEN
WMRestorable.LoadLongint(entry, "firstLine", firstLine);
WMRestorable.LoadLongint(entry, "cursorPos", cursorPos);
WMRestorable.LoadBoolean(entry, "visible", visible);
WMRestorable.LoadLongint(entry, "height", height);
currentPage.splitEditor.tv.firstLine.Set(firstLine);
currentPage.splitEditor.tv.cursor.SetPosition(cursorPos);
currentPage.splitPanel.visible.Set(visible);
currentPage.splitted := visible;
currentPage.splitPanel.bounds.SetHeight(height);
ELSIF (s^ = "SidePanel") THEN
WMRestorable.LoadBoolean(entry, "visible", visible);
WMRestorable.LoadLongint(entry, "width", width);
WMRestorable.LoadLongint(entry, "scratchHeight", height);
currentPage.sidePanel.visible.Set(visible);
currentPage.sidePanel.bounds.SetWidth(width);
currentPage.scratchPanel.bounds.SetHeight(height);
ELSIF (s^ = "SearchPanel") THEN
WMRestorable.LoadBoolean(entry, "visible", visible);
WMRestorable.LoadBoolean(entry, "wrap", wrap);
WMRestorable.LoadBoolean(entry, "casesensitive", caseSensitive);
WMRestorable.LoadBoolean(entry, "backwards", backwards);
WMRestorable.LoadBoolean(entry, "highlight", highlightAll);
WMRestorable.LoadString(entry, "searchString", searchString);
WMRestorable.LoadString(entry, "replaceString", replaceString);
currentPage.searchPanel.visible.Set(visible);
currentPage.searchPanel.SetSettings(wrap, caseSensitive, backwards, highlightAll);
currentPage.searchPanel.searchEdit.SetAsString(searchString);
currentPage.searchPanel.replEdit.SetAsString(replaceString);
ELSIF (s^ = "LogPanel") THEN
WMRestorable.LoadLongint(entry, "height", height);
currentPage.logPanel.bounds.SetHeight(height);
END;
END;
END;
END;
END;
END LoadPage;
PROCEDURE StorePage(page : PETPanel) : WMRestorable.XmlElement;
VAR
elem, entry : WMRestorable.XmlElement;
wrap, caseSensitive, backwards, highlightAll : BOOLEAN;
string : WMSearchComponents.SearchString;
BEGIN
ASSERT(page # NIL);
NEW(elem); elem.SetName("Tab");
WMRestorable.StoreString(elem, "file", page.filename);
WMRestorable.StoreString(elem, "codecFormat", page.codecFormat);
WMRestorable.StoreString(elem, "compilerOptions", page.options);
WMRestorable.StoreBoolean(elem, "showLabels", page.editor.tv.showLabels.Get());
WMRestorable.StoreBoolean(elem, "wordWrap", page.editor.tv.wrapMode.Get() = WMTextView.WrapWord);
NEW(entry); entry.SetName("Editor");
WMRestorable.StoreLongint(entry, "firstLine", page.editor.tv.firstLine.Get());
WMRestorable.StoreLongint(entry, "cursorPos", page.editor.tv.cursor.GetPosition());
elem.AddContent(entry);
NEW(entry); entry.SetName("SplitEditor");
WMRestorable.StoreBoolean(entry, "visible", page.splitPanel.visible.Get());
WMRestorable.StoreLongint(entry, "firstLine", page.splitEditor.tv.firstLine.Get());
WMRestorable.StoreLongint(entry, "cursorPos", page.splitEditor.tv.cursor.GetPosition());
WMRestorable.StoreLongint(entry, "height", page.splitPanel.bounds.GetHeight());
elem.AddContent(entry);
NEW(entry); entry.SetName("SearchPanel");
page.searchPanel.GetSettings(wrap, caseSensitive, backwards, highlightAll);
WMRestorable.StoreBoolean(entry, "visible", page.searchPanel.visible.Get());
WMRestorable.StoreBoolean(entry, "wrap", wrap);
WMRestorable.StoreBoolean(entry, "casesensitive", caseSensitive);
WMRestorable.StoreBoolean(entry, "backwards", backwards);
WMRestorable.StoreBoolean(entry, "highlight", highlightAll);
page.searchPanel.searchEdit.GetAsString(string);
WMRestorable.StoreString(entry, "searchString", string);
page.searchPanel.replEdit.GetAsString(string);
WMRestorable.StoreString(entry, "replaceString", string);
elem.AddContent(entry);
NEW(entry); entry.SetName("LogPanel");
WMRestorable.StoreLongint(entry, "height", page.logPanel.bounds.GetHeight());
elem.AddContent(entry);
NEW(entry); entry.SetName("SidePanel");
WMRestorable.StoreBoolean(entry, "visible", page.sidePanel.visible.Get());
WMRestorable.StoreLongint(entry, "width", page.sidePanel.bounds.GetWidth());
WMRestorable.StoreLongint(entry, "scratchHeight", page.scratchPanel.bounds.GetHeight());
elem.AddContent(entry);
RETURN elem;
END StorePage;
PROCEDURE HandleShortcut(ucs : LONGINT; flags : SET; keysym : LONGINT) : BOOLEAN;
VAR filename : Filename; options : CompilerOptions;
BEGIN
modifierFlags := flags;
IF DisableShortcuts THEN RETURN FALSE; END;
IF (keysym = 13H) & ControlKeyDown(flags) THEN
StoreHandler(NIL, NIL);
ELSIF (keysym = 08H) & ControlKeyDown(flags) THEN
IF currentPage # NIL THEN
optionsEdit.GetAsString(options);
currentPage.DoCompile(FALSE, "", options);
END;
ELSIF (keysym = 0FH) & ControlKeyDown(flags) THEN
filenameEdit.SetAsString("");
filenameEdit.SetFocus;
ELSIF (keysym = Inputs.KsPageDown) & ControlKeyDown(flags) THEN
IF (WMDialogs.QueryString("Save PET state into (.pet extension is appended)", filename) = WMDialogs.ResOk) & (filename # "") THEN
Strings.Append(filename, StateFileExtension);
StoreState(filename);
END;
ELSIF (keysym = Inputs.KsPageUp) & ControlKeyDown(flags) THEN
IF (WMDialogs.QueryString("Load PET state from (.pet extension is appended)", filename) = WMDialogs.ResOk) & (filename # "") THEN
DisableUpdate;
IF CloseAllTabs() THEN
Strings.Append(filename, StateFileExtension);
IF LoadState(filename) THEN
UpdatePages;
UpdateState;
END;
END;
EnableUpdate;
form.Invalidate;
END;
ELSIF (keysym = Inputs.KsTab) & ControlKeyDown(flags) THEN
DisableUpdate; SelectNextTab; EnableUpdate;
ELSIF (keysym = Inputs.KsTab) & (flags * Inputs.Ctrl # {}) & (flags * Inputs.Shift # {}) &
(flags - Inputs.Ctrl - Inputs.Shift = {}) THEN
DisableUpdate; SelectPreviousTab; EnableUpdate;
ELSIF (keysym = 015H) & ControlKeyDown(flags) THEN
IF (currentPage # NIL) THEN UnloadModule; END;
ELSIF (currentPage = NIL) OR ((currentPage # NIL) & (~currentPage.HandleShortcut(ucs, flags, keysym))) THEN
RETURN FALSE;
END;
RETURN TRUE;
END HandleShortcut;
PROCEDURE Handle(VAR m: WMMessages.Message);
VAR data : WMRestorable.XmlElement;
BEGIN
IF m.msgType = WMMessages.MsgKey THEN
IF ~HandleShortcut(m.x, m.flags, m.y) THEN
Handle^(m);
END;
ELSIF (m.msgType = WMMessages.MsgExt) & (m.ext # NIL) THEN
IF (m.ext IS KillerMsg) THEN Close
ELSIF (m.ext IS WMRestorable.Storage) THEN
data := StorePages();
m.ext(WMRestorable.Storage).Add("PET", "PET.Restore", SELF, data)
ELSE Handle^(m)
END
ELSE Handle^(m)
END
END Handle;
END Window;
VAR
nofWindows : LONGINT;
scratchText : Texts.Text;
scratchModified : BOOLEAN;
gsettings : Settings;
StrScratchPanel, StrPETPanel : Strings.String;
timeout: BOOLEAN;
PROCEDURE Open*(context : Commands.Context);
VAR
window : Window; count, index, temp, position : LONGINT;
filename : Filename; format : ARRAY 32 OF CHAR;
options: Options.Options;
BEGIN
NEW(options);
options.Add("e","external",Options.Flag);
options.Add("f", "format", Options.String);
IF options.Parse(context.arg, context.out) THEN
IF (context.caller # NIL) & (context.caller IS Window) & ~options.GetFlag("external") THEN
window := context.caller(Window);
ELSE
NEW(window, NIL);
END;
IF ~options.GetString("format", format) THEN format := "AUTO"; END;
count := 0;
WHILE context.arg.GetString(filename) DO
position := 0; index := Strings.Find(filename, 0, '@');
IF index >= 0 THEN temp := index + 1; Strings.StrToIntPos(filename, position, temp); ASSERT (position # 0); Strings.Truncate(filename, index) END;
IF filename # "" THEN window.Load(filename, format); window.SetCursorPosition(position); INC(count) END
END;
IF count = 0 THEN window.Load("Untitled.Mod", "AUTO") END;
END;
END Open;
PROCEDURE OpenState*(context : Commands.Context);
VAR filename : Filename; window : Window;
BEGIN
context.arg.SkipWhitespace; context.arg.String(filename);
NEW(window, NIL);
IF ~window.LoadState(filename) THEN
context.error.String("PET: Could not state from file "); context.error.String(filename); context.error.Ln;
END;
END OpenState;
PROCEDURE Restore*(context : WMRestorable.Context);
VAR w : Window;
BEGIN
NEW(w, context)
END Restore;
PROCEDURE CommentSelection*(text : Texts.Text; from, to : Texts.TextPosition);
VAR a, b : LONGINT; string : ARRAY 4 OF Texts.Char32;
BEGIN
ASSERT((text # NIL) & (from # NIL) & (to # NIL));
text.AcquireWrite;
a := Strings.Min(from.GetPosition(), to.GetPosition());
b := Strings.Max(from.GetPosition(), to.GetPosition());
string[0] := ORD(" "); string[1] := ORD("*"); string[2] := ORD(")"); string[3] := 0;
text.InsertUCS32(b, string);
string[0] := ORD("("); string[1] := ORD("*"); string[2] := ORD(" "); string[3] := 0;
text.InsertUCS32(a, string);
IF (a <= b) THEN from.SetPosition(a); ELSE to.SetPosition(a); END;
text.ReleaseWrite;
Texts.SetLastSelection(text, from, to);
END CommentSelection;
PROCEDURE UncommentSelection*(text : Texts.Text; from, to : Texts.TextPosition);
VAR
reader : Texts.TextReader; ch : Texts.Char32;
a, b : LONGINT;
openPos, closePos, openLen, closeLen : LONGINT;
BEGIN
text.AcquireWrite;
a := Strings.Min(from.GetPosition(), to.GetPosition());
b := Strings.Max(from.GetPosition(), to.GetPosition());
NEW(reader, text);
openPos := -1; openLen := 2;
reader.SetPosition(a);
REPEAT reader.ReadCh(ch); UNTIL reader.eot OR ~TextUtilities.IsWhiteSpace(ch, FALSE) OR (reader.GetPosition() >= b);
IF (ch = ORD("(")) THEN
reader.ReadCh(ch);
IF (ch = ORD("*")) THEN
openPos := reader.GetPosition() - 2;
reader.ReadCh(ch);
IF (ch = ORD(" ")) THEN INC(openLen); END;
END;
END;
closePos := -1; closeLen := 2;
IF (openPos > 0) THEN
reader.SetDirection(-1);
reader.SetPosition(b - 1);
REPEAT reader.ReadCh(ch); UNTIL reader.eot OR ~TextUtilities.IsWhiteSpace(ch, FALSE) OR (reader.GetPosition() <= a);
IF (ch = ORD(")")) THEN
reader.ReadCh(ch);
IF (ch = ORD("*")) THEN
closePos := reader.GetPosition() + 1;
reader.ReadCh(ch);
IF (ch = ORD(" ")) & (openPos + openLen - 1 < closePos - closeLen + 2) THEN
INC(closeLen); DEC(closePos);
END;
END;
END;
END;
IF (openPos + openLen - 1 < closePos) THEN
text.Delete(closePos, closeLen);
text.Delete(openPos, openLen);
END;
text.ReleaseWrite;
END UncommentSelection;
PROCEDURE Comment*;
VAR text : Texts.Text; from, to : Texts.TextPosition;
BEGIN
IF Texts.GetLastSelection(text, from, to) THEN
CommentSelection(text, from, to);
END;
END Comment;
PROCEDURE Uncomment*;
VAR text : Texts.Text; from, to : Texts.TextPosition;
BEGIN
IF Texts.GetLastSelection(text, from, to) THEN
UncommentSelection(text, from, to);
END;
END Uncomment;
PROCEDURE GetSyntaxHighlighterName*(fullname : ARRAY OF CHAR; VAR name : ARRAY OF CHAR);
VAR filename, extension, config : Files.FileName; res : LONGINT;
BEGIN
name := "";
Strings.UpperCase(fullname);
Strings.GetExtension(fullname, filename, extension);
IF (extension # "") THEN
config := "Applications.PET.SyntaxHighlighter.";
Strings.AppendX(config, extension);
Configuration.Get(config, name, res);
IF (res # Configuration.Ok) THEN name := ""; END;
END;
END GetSyntaxHighlighterName;
PROCEDURE ControlKeyDown(flags : SET) : BOOLEAN;
BEGIN
RETURN (flags * Inputs.Ctrl # {}) & (flags - Inputs.Ctrl = {});
END ControlKeyDown;
PROCEDURE EitherShiftOrControlDown(flags : SET) : BOOLEAN;
BEGIN
RETURN ((flags * Inputs.Shift # {}) & (flags * Inputs.Ctrl = {})) OR ((flags * Inputs.Ctrl # {}) & (flags * Inputs.Shift = {}));
END EitherShiftOrControlDown;
PROCEDURE ContainsFileExtension(filename , extension : ARRAY OF CHAR) : BOOLEAN;
BEGIN
Strings.UpperCase(filename);
Strings.UpperCase(extension);
RETURN Strings.Pos(extension, filename) > 0;
END ContainsFileExtension;
PROCEDURE ScratchModified(sender, data : ANY);
BEGIN {EXCLUSIVE}
scratchModified := TRUE
END ScratchModified;
PROCEDURE StoreScratchText;
BEGIN
IF scratchModified THEN
StoreText(ScratchTextFilename, scratchText);
scratchModified := FALSE;
END;
END StoreScratchText;
PROCEDURE LoadScratchText;
BEGIN
scratchText := LoadText(ScratchTextFilename);
scratchText.onTextChanged.Add(ScratchModified);
END LoadScratchText;
PROCEDURE StoreText(CONST filename : ARRAY OF CHAR; text : Texts.Text);
VAR res : LONGINT;
BEGIN
text.AcquireRead;
TextUtilities.StoreOberonText(text, filename, res);
text.ReleaseRead
END StoreText;
PROCEDURE LoadText(CONST filename : ARRAY OF CHAR) : Texts.Text;
VAR text : Texts.Text; res : LONGINT;
BEGIN
NEW(text);
text.AcquireWrite;
TextUtilities.LoadOberonText(text, filename, res);
text.ReleaseWrite;
RETURN text;
END LoadText;
PROCEDURE GetSettings(): Settings;
VAR s: Settings;
BEGIN
s := gsettings;
IF s = NIL THEN
NEW(s); s.Load;
END;
RETURN s
END GetSettings;
PROCEDURE IncCount;
BEGIN {EXCLUSIVE}
INC(nofWindows);
IF (nofWindows = 1) THEN
NEW(gsettings); gsettings.Load;
LoadScratchText;
END;
END IncCount;
PROCEDURE DecCount;
BEGIN {EXCLUSIVE}
DEC(nofWindows);
IF (nofWindows = 0) THEN
StoreScratchText;
scratchText := NIL;
gsettings := NIL;
END;
END DecCount;
PROCEDURE Timeout;
BEGIN{EXCLUSIVE}
timeout := TRUE
END Timeout;
PROCEDURE Cleanup;
VAR die : KillerMsg;
msg : WMMessages.Message;
m : WMWindowManager.WindowManager;
timer: OBJECT VAR timer: Kernel.Timer; BEGIN{ACTIVE} NEW(timer); timer.Sleep(100); Timeout END;
BEGIN {EXCLUSIVE}
NEW(die);
msg.ext := die;
msg.msgType := WMMessages.MsgExt;
m := WMWindowManager.GetDefaultManager();
WHILE nofWindows >0 DO
m.Broadcast(msg);
timeout := FALSE; NEW(timer);
AWAIT (nofWindows = 0) OR timeout;
END;
END Cleanup;
PROCEDURE LoadModule(CONST moduleName : ARRAY OF CHAR);
VAR module : Modules.Module; msg : ARRAY 128 OF CHAR; res : LONGINT;
BEGIN
module := Modules.ThisModule(moduleName, res, msg);
END LoadModule;
PROCEDURE InitStrings;
BEGIN
StrScratchPanel := Strings.NewString("ScratchPanel");
StrPETPanel := Strings.NewString("PETPanel");
END InitStrings;
BEGIN
nofWindows := 0;
scratchText := NIL; scratchModified := FALSE;
Modules.InstallTermHandler(Cleanup);
InitStrings;
END PET.
SystemTools.Free PET ~
WMMacros.ReadMacros Macros.XML ~
PET2.Open ~
PET.Open PET.Mod ~
SystemTools.Free PET WMXMLTree ~
PC.Compile PET.Mod ~