MODULE WMShell;
IMPORT
Shell, Streams, Pipes, Texts, TextUtilities, Strings,
Modules, Kernel, Inputs,
WMGraphics, WMWindowManager, WMMessages, WMRestorable,
WMComponents, WMDocumentEditor;
CONST
DefaultWidth = 640; DefaultHeight = 300;
ReceiveBufferSize = 256;
Prompt = "SHELL>";
Backspace = 08X;
ESC = 1BX;
DEL = 7FX;
TYPE
ShellComponent = OBJECT(WMComponents.VisualComponent)
VAR
out : Streams.Writer;
in : Streams.Reader;
pipeOut, pipeIn : Pipes.Pipe;
w : TextUtilities.TextWriter;
text : Texts.Text;
shell : Shell.Shell;
editor : WMDocumentEditor.Editor;
running, dead : BOOLEAN;
timer : Kernel.Timer;
PROCEDURE Clear;
BEGIN
editor.Clear;
Invalidate;
END Clear;
PROCEDURE ExtPointerUp(x, y : LONGINT; keys : SET; VAR handled : BOOLEAN);
BEGIN
text.AcquireRead;
editor.editor.tv.cursor.SetPosition(text.GetLength());
text.ReleaseRead;
END ExtPointerUp;
PROCEDURE ExtKeyPressed(ucs : LONGINT; flags : SET; VAR keySym : LONGINT; VAR handled : BOOLEAN);
BEGIN
handled := FALSE;
IF editor.HandleShortcut(ucs, flags, keySym) THEN handled := TRUE; END;
IF ~handled & ~(Inputs.Release IN flags) THEN
handled := TRUE;
IF keySym = 01H THEN
editor.editor.tv.SelectAll
ELSIF keySym = 03H THEN
editor.editor.tv.CopySelection
ELSIF keySym = 16H THEN
CopyFromClipboard;
ELSIF (keySym = 0FF63H) & (flags * Inputs.Ctrl # {}) THEN
editor.editor.tv.CopySelection
ELSIF keySym = 0FF56H THEN
editor.editor.tv.PageDown(flags * Inputs.Shift # {})
ELSIF keySym = 0FF55H THEN
editor.editor.tv.PageUp(flags * Inputs.Shift # {})
ELSIF keySym = 0FF50H THEN
editor.editor.tv.Home(flags * Inputs.Ctrl # {}, flags * Inputs.Shift # {})
ELSIF keySym = 0FF57H THEN
editor.editor.tv.End(flags * Inputs.Ctrl # {}, flags * Inputs.Shift # {})
ELSIF keySym = 0FF1BH THEN
IF ~(Inputs.Release IN flags) THEN
out.Char(ESC); out.Char(ESC); out.Update;
END;
ELSE
handled := FALSE;
END
END;
IF ~handled & (ucs > 0) & (ucs < 256) THEN
IF ~(Inputs.Release IN flags) THEN
IF ucs > 127 THEN
out.Char(ESC); out.Char("["); ucs := ucs - 128;
END;
out.Char(CHR(ucs)); out.Update;
END;
handled := TRUE;
END;
END ExtKeyPressed;
PROCEDURE Wait(ms : LONGINT);
BEGIN
timer.Sleep(ms);
END Wait;
PROCEDURE InitShell;
VAR shellIn : Streams.Reader; shellOut : Streams.Writer;
BEGIN
NEW(pipeOut, 256); NEW(pipeIn, 256);
NEW(shellIn, pipeOut.Receive, 256);
NEW(shellOut, pipeIn.Send, 256);
NEW(out, pipeOut.Send, 256);
NEW(in, pipeIn.Receive, 256);
NEW(shell, shellIn,shellOut, shellOut, TRUE, Prompt);
END InitShell;
PROCEDURE CopyFromClipboard;
VAR string : POINTER TO ARRAY OF CHAR;
BEGIN
Texts.clipboard.AcquireRead;
IF Texts.clipboard.GetLength() > 0 THEN
NEW(string, Texts.clipboard.GetLength()+1);
TextUtilities.TextToStr(Texts.clipboard, string^);
END;
Texts.clipboard.ReleaseRead;
out.String(string^); out.Update;
END CopyFromClipboard;
PROCEDURE Finalize;
BEGIN
shell.Exit;
BEGIN {EXCLUSIVE}
running := FALSE;
AWAIT(dead);
END;
END Finalize;
PROCEDURE DeleteNCharacters(nbrOfCharacters : LONGINT);
VAR pos : LONGINT;
BEGIN
text.AcquireWrite;
pos := editor.editor.tv.cursor.GetPosition();
text.Delete(pos - nbrOfCharacters, nbrOfCharacters);
text.ReleaseWrite;
END DeleteNCharacters;
PROCEDURE ReceiveCharacters;
VAR ch : CHAR; buffer : ARRAY ReceiveBufferSize OF CHAR; backspaces, i, size, len : LONGINT;
BEGIN
size := in.Available();
IF size > ReceiveBufferSize THEN size := ReceiveBufferSize; END;
in.Bytes(buffer, 0, size, len);
IF in.res = Streams.Ok THEN
FOR i := 0 TO len-1 DO
ch := buffer[i];
IF (ch = DEL) OR (ch = Backspace) THEN
INC(backspaces);
ELSE
IF (backspaces > 0) THEN
w.Update;
DeleteNCharacters(backspaces);
backspaces := 0;
END;
w.Char(ch);
END;
END;
w.Update;
END;
DeleteNCharacters(backspaces);
END ReceiveCharacters;
PROCEDURE &Init*;
BEGIN
Init^;
running := TRUE;
NEW(timer);
NEW(editor); editor.alignment.Set(WMComponents.AlignClient);
editor.SetToolbar(WMDocumentEditor.StoreButton + WMDocumentEditor.WrapButton + WMDocumentEditor.SearchButton + WMDocumentEditor.ClearButton);
editor.editor.tv.SetExtKeyEventHandler(ExtKeyPressed);
editor.editor.tv.SetExtPointerUpHandler(ExtPointerUp);
AddContent(editor);
NEW(text);
NEW(w, text); w.SetFontName("Courier");
editor.SetText(text);
InitShell;
SetNameAsString(StrShellComponent);
END Init;
BEGIN {ACTIVE}
WHILE running DO
IF running & (in.Available() > 0) THEN ReceiveCharacters; END;
Wait(2);
END;
BEGIN {EXCLUSIVE} dead := TRUE; END;
END ShellComponent;
TYPE
KillerMsg = OBJECT
END KillerMsg;
Window* = OBJECT (WMComponents.FormWindow)
VAR
shell : ShellComponent;
PROCEDURE HandleUpcall(command : LONGINT);
BEGIN
IF command = Shell.Clear THEN
shell.Clear;
ELSIF command = Shell.ExitShell THEN
Close;
END;
END HandleUpcall;
PROCEDURE &New*(c : WMRestorable.Context);
BEGIN
IncCount;
NEW(shell); shell.alignment.Set(WMComponents.AlignClient);
shell.shell.SetUpcall(HandleUpcall);
Init(DefaultWidth, DefaultHeight, FALSE);
SetContent(shell);
SetTitle(Strings.NewString("BlueShell"));
SetIcon(WMGraphics.LoadImage("WMIcons.tar://WMShell.png", TRUE));
IF c # NIL THEN
WMRestorable.AddByContext(SELF, c);
Resized(GetWidth(), GetHeight());
ELSE
WMWindowManager.DefaultAddWindow(SELF);
END;
shell.editor.editor.SetFocus();
END New;
PROCEDURE Close;
BEGIN
Close^;
DecCount
END Close;
PROCEDURE Handle(VAR x : WMMessages.Message);
BEGIN
IF (x.msgType = WMMessages.MsgExt) & (x.ext # NIL) THEN
IF (x.ext IS KillerMsg) THEN
Close;
ELSIF (x.ext IS WMRestorable.Storage) THEN
x.ext(WMRestorable.Storage).Add("Shell", "WMShell.Restore", SELF, NIL);
ELSE
Handle^(x);
END;
ELSE Handle^(x)
END
END Handle;
END Window;
VAR
nofWindows : LONGINT;
StrShellComponent : Strings.String;
PROCEDURE InitStrings;
BEGIN
StrShellComponent := Strings.NewString("ShellComponent");
END InitStrings;
PROCEDURE Restore*(context : WMRestorable.Context);
VAR window : Window;
BEGIN
ASSERT(context # NIL);
NEW(window, context);
END Restore;
PROCEDURE Open*;
VAR window : Window;
BEGIN
NEW(window, NIL);
END Open;
PROCEDURE IncCount;
BEGIN {EXCLUSIVE}
INC(nofWindows)
END IncCount;
PROCEDURE DecCount;
BEGIN {EXCLUSIVE}
DEC(nofWindows)
END DecCount;
PROCEDURE Cleanup;
VAR die : KillerMsg;
msg : WMMessages.Message;
m : WMWindowManager.WindowManager;
BEGIN {EXCLUSIVE}
NEW(die);
msg.ext := die;
msg.msgType := WMMessages.MsgExt;
m := WMWindowManager.GetDefaultManager();
m.Broadcast(msg);
AWAIT(nofWindows = 0)
END Cleanup;
BEGIN
Modules.InstallTermHandler(Cleanup);
InitStrings;
END WMShell.
WMShell.Open ~
SystemTools.Free WMShell ~
SystemTools.Free WMShell Shell ~