paneman/src/IOPaneMan.m3


 Copyright (c) 2000 California Institute of Technology 
 All rights reserved. See the file COPYRIGHT for a full description. 
 $Id: IOPaneMan.m3,v 1.2 2001-09-19 14:22:13 wagner Exp $ 

MODULE IOPaneMan;
IMPORT TextPane;
IMPORT PaneManOp;
IMPORT Thread;
IMPORT KeyChan;
IMPORT StarterList;
IMPORT StarterScanList;
IMPORT VBT;
IMPORT PaneManVBT;
IMPORT TermIO;

TYPE
  PrivateIO = TermIO.T OBJECT
    paneMan: T;
    callback: PrivateCallback;
    keyChan: KeyChan.T;
  OVERRIDES
    getChar := GetChar;
    getLine := GetLine;
    putLine := PutLine;
    putText := PutText;
  END;

  PrivateCallback = PaneManOp.InputCallback OBJECT
    mu: MUTEX;
    cond: Thread.Condition;
    result: TEXT;
  OVERRIDES
    accept := Accept;
    complete := Complete;
  END;

PROCEDURE Accept(self: PrivateCallback; result: TEXT) =
  BEGIN
    LOCK self.mu DO
      self.result := result;
      Thread.Signal(self.cond);
    END;
  END Accept;

PROCEDURE Complete(<*UNUSED*>self: PrivateCallback;
                   <*UNUSED*>VAR t: TEXT) =
  BEGIN
  END Complete;

REVEAL
  T = Public BRANDED OBJECT
    io: PrivateIO;
  OVERRIDES
    getIO := GetIO;
    init := Init;
    cookedKey := CookedKey;
  END;

PROCEDURE GetIO(self: T): TermIO.T =
  BEGIN
    RETURN self.io;
  END GetIO;

PROCEDURE Init(self: T; s: StarterList.T;
               startingStarters: StarterScanList.T := NIL): PaneManVBT.T =
  VAR
    callback := NEW(PrivateCallback,
                    mu := NEW(MUTEX),
                    cond := NEW(Thread.Condition));
  BEGIN
    self.io := NEW(PrivateIO,
                   paneMan := self,
                   callback := callback,
                   keyChan := NEW(KeyChan.T).init());
    RETURN Public.init(self, s, startingStarters);
  END Init;

PROCEDURE CookedKey(self: T; READONLY key: VBT.KeyRec) =
  BEGIN
    IF key.wentDown AND
      NOT VBT.Modifier.Control IN key.modifiers AND
      key.whatChanged < 256 THEN
      IF NOT ISTYPE(self.getSelectedPane(), TextPane.T) THEN
        self.io.keyChan.send(key);
      END;
    END;
    Public.cookedKey(self, key);
  END CookedKey;
PrivateIO methods

PROCEDURE GetChar(self: PrivateIO): CHAR =
  VAR
    key := self.keyChan.recv();
  BEGIN
    <* ASSERT key.wentDown *>
    RETURN VAL(key.whatChanged, CHAR);
  END GetChar;

PROCEDURE GetLine(self: PrivateIO; prompt := ">"): TEXT =
  BEGIN
    LOCK self.callback.mu DO
      LOCK self.paneMan.mu DO
        self.paneMan.input(prompt, "", self.callback);
      END;
      Thread.Wait(self.callback.mu, self.callback.cond);
      RETURN self.callback.result;
    END;
  END GetLine;

PROCEDURE PutLine(self: PrivateIO; t: TEXT) =
  BEGIN
    LOCK self.paneMan.mu DO
      self.paneMan.print(t);
    END;
  END PutLine;

PROCEDURE PutText(<*UNUSED*>self: PrivateIO; <*UNUSED*>t: TEXT) =
  BEGIN
  END PutText;

BEGIN
END IOPaneMan.