Category : Pascal Source Code
Archive   : TFDD.ZIP
Filename : KBDEDIT.PAS

 
Output of file : KBDEDIT.PAS contained in archive : TFDD.ZIP

(******************************************************************************

UNIT KBDEDIT


-------------------------------------------------------------------------------
Philippe Ranger (514) 274 4653
First version 26-6-90 Present version 13-7-90
-------------------------------------------------------------------------------
SPECIFICATION
Defines a lite-line-editor TFDD class, kbdEditC, and installs and opens
one instance, ke. The text file is ke.t.
Starting value of string self.s is treated as editable starting input. Reset
to null on each read.
One option is to allow user to use Esc key. This will return an empty string
and set boolean Self.escUsed to true. Otherwise escUsed is false -- it
will become false again on next read unless Esc is used again.
Value of boolean echoCR sets whether the Enter that ends any keyboard read
will be echoed to screen.
As defined in TP, the CR itself is always recorded (but as ^M^J, as for an
ordinary text). It remains in buffer until a readln is commanded.
Convenience method StuffReadln (var srs) simply stuffs the present value
of string srs (into self.s) before doing an edited readln on it.
Editor input cannot be redirected.

EDITOR SPEC
Input from s, then kbd, read and echoed from present cursor position, to
the last column but one in the current window. If window width > 127
(??), will raise IO error 255.
User allowed to edit input using ^S, ^D, ^H, ^G and equivalent left arrow,
right arrow, backspace and Del, plus Home and End.
Input normally ended with Enter or ^M. S is nulled.
Self holds boolean toggle fields that can only be changed by clients:
If echoCR, CR written to screen; else cursor brought to end of input.
Iff doEsc, user allowed use of Esc, as specified above.
Iff sdel, default starting input is deleted if first char from user is
above #31.
EchoCR is true by default, other toggles false.

NOTE
Underline before a class element name indicates that it is private.
S and EchoCR are not private. They may be manipulated directly by class
clients. If this is found embarrassing, field-manipulation methods may
be added.
******************************************************************************)

UNIT kbdEdit;

INTERFACE

USES tfdd;

CONST
Mx = 127; (*1 less than buffer size*)
errorValue = 255;

TYPE
lineS = string[Mx];

kbdEditC = object (tfddC)
s: lineS;
escUsed: boolean;
echoCR, doEsc, sdel: boolean;
procedure stuffReadln (var srs: lineS);
function _readLine: integer;
constructor init
end;

VAR ke: kbdEditC;

IMPLEMENTATION
(******************************************************************************
METHODS

******************************************************************************)

USES crt, dos;

{$F+}


PROCEDURE initialize; BEGIN ke.init; END;


PROCEDURE kbdEditC.stuffReadln (var srs: lineS);
BEGIN
s := srs;
readln (t, srs)
END;

FUNCTION kbdEditC._readLine: integer;
(*=============================================================================
PRE
self.echoCR true iff user CR not to be echoed.
self.s holds starting feed for read.
-------------------------------------------------------------------------------
POST
See unit specification.
Self.s is edited input, without CR.
Returns error value.
-------------------------------------------------------------------------------
METHOD
All commands, including none, listed in cmdT. Char test starts with normal
chars, then sets cmd for any command char. Default cmd is none. Last,
cmd is executed.
=============================================================================*)

TYPE cmdT = (none, left, right, del, bs, home, endc, exitc);

VAR
s0: byte absolute s; (*length(s))*)
i: byte; (*cursor position in s*)
c: char;
cmd: cmdT;
Nx: byte; (*present window width*)
x, y: byte; (*whereX, whereY*)
firstTap: boolean;

procedure delAll; begin
dec (x, i-1); gotoXY (x, y);
fillchar (s[1], s0, ' ');
write (s); gotoXY (x, y);
s0 := 0; i := 1
end;

BEGIN
_readLine := 0;
escUsed := false;
firstTap := true;
Nx := lo(windMax) - lo(windMin) + 1;
if Nx > Mx then begin _readLine := errorValue; EXIT end;
x := whereX; y := whereY;
if x + s0 >= Nx then s0 := Nx - x;
write (s); i := s0+1; x := x + s0;
while true do begin
c := readkey;
if firstTap and sdel and (c >= #32) then begin
firstTap := false;
delAll
end;
cmd := none;
case c of
#32..#255: if x < Nx then begin
inc (s0);
move (s[i], s[i+1], s0 - i);
s[i] := c;
write (copy (s, i, s0+1 - i));
inc (i);
inc (x); gotoXY (x, y)
end;
#0: case readkey of
#75: cmd := left;
#77: cmd := right;
#83: cmd := del;
#71: cmd := home;
#79: cmd := endc
end;
^M: cmd := exitc;
^[: if doEsc then begin delAll; escUsed := true; cmd := exitc end;
^H: cmd := bs;
^G: cmd := del;
^S: cmd := left;
^D: cmd := right
end;
case cmd of
none: ;
exitc: begin
if echoCR then writeln
else begin inc (x, s0-i); gotoXY (x, y) end;
EXIT
end;
bs: if i > 1 then begin
delete (s, i-1, 1); dec (i);
dec (x); gotoXY (x, y);
write (copy (s, i, s0+1 - i) + ' ');
gotoXY (x, y)
end;
del: if i <= s0 then begin
delete (s, i, 1);
gotoXY (x, y);
write (copy (s, i, s0+1 - i) + ' ');
gotoXY (x, y)
end;
left: if i > 1 then begin dec(i); dec(x); gotoXY(x, y) end;
right: if i <= s0 then begin inc(i); inc(x); gotoXY(x, y) end;
home: begin dec (x, i-1); i := 1; gotoXY (x, y) end;
endc: begin inc (x, s0-i); i := s0; gotoXY (x, y) end
end
end
END; (*kbdEditC._readLine*)


FUNCTION readEdit (var t: textRec): integer;
(*=============================================================================
PRE
t open for input only;
t.userData[1..4] holds a pointer to a kbdEditC instance.
see kbdEditC._readLine.
-------------------------------------------------------------------------------
POST
User allowed to input with kbdEditO._readLine's editing facilities.
Result plus ^M^J read to t.
-------------------------------------------------------------------------------
NOTES
Under TP's read convention, no kbd input is read until Enter (^M) is hit,
and this is always read also as an eoln, ^M^J. This convention is fol-
lowed here.
It is not part of normal text file services that input should be echoed on
screen. Echoing is the device driver's responsibility. Here it is handled
within _readLine (which indeed could not work if it could not echo).
=============================================================================*)

VAR selfp: ^kbdEditC;

BEGIN
with t do begin
bufEnd := 0;
bufPos := 0;
move (userData, selfp, sizeof(selfp));
with selfp^ do begin
readEdit := _readLine;
move (s[1], bufPtr^, length(s));
bufEnd := length(s);
s := ''
end;
bufPtr^[bufEnd] := ^M; inc (bufEnd);
bufPtr^[bufEnd] := ^J; inc (bufEnd)
end
END; (*readEdit*)


CONSTRUCTOR kbdEditC.init;
BEGIN
tfddC.init;
s := '';
echoCR := true;
doEsc := false;
sdel := false;
textRec(t).inoutFunc := @readEdit;
reset (t)
END;


BEGIN INITIALIZE END.