home *** CD-ROM | disk | FTP | other *** search
- {$S-,R-,V-,I-,B-,F+}
-
- {$IFNDEF Ver40}
- {$I OPLUS.INC}
- {$I AMINUS.INC}
- {$ENDIF}
-
- {$I TPDEFINE.INC}
-
- {*********************************************************}
- {* TPMEMO.PAS 1.0 *}
- {* Copyright (c) TurboPower Software 1988. *}
- {* Portions copyright (c) Sunny Hill Software 1985, 1986 *}
- {* and used under license to TurboPower Software *}
- {* All rights reserved. *}
- {*********************************************************}
-
- unit TpMemo;
- {-Memo field editor}
-
- interface
-
- uses
- TpCrt,
- {$IFDEF UseMouse}
- TpMouse,
- {$ENDIF}
- TpCmd,
- TpString;
-
- {.F-}
- const
- EMnone = 00; {Not a command}
- EMchar = 01; {A character to enter the string}
- EMctrlChar = 02; {Accept control character}
- EMenter = 03; {New line}
- EMquit = 04; {Quit editing}
- EMrestore = 05; {Restore line and continue}
- EMhome = 06; {Cursor to beginning of line}
- EMend = 07; {Cursor to end of line}
- EMleft = 08; {Cursor left by one character}
- EMright = 09; {Cursor right by one character}
- EMup = 10; {Cursor up one line}
- EMdown = 11; {Cursor down one line}
- EMscrollUp = 12; {Scroll display up one line}
- EMscrollDown = 13; {Scroll display down one line}
- EMpageUp = 14; {Scroll display up one page}
- EMpageDown = 15; {Scroll display down one page}
- EMscreenTop = 16; {Cursor to top of screen}
- EMscreenBot = 17; {Cursor to bottom of screen}
- EMtopOfFile = 18; {Cursor to top of file}
- EMendOfFile = 19; {Cursor to bottom of file}
- EMwordLeft = 20; {Cursor left one word}
- EMwordRight = 21; {Cursor right one word}
- EMback = 22; {Backspace one character}
- EMdel = 23; {Delete current character}
- EMdelEol = 24; {Delete from cursor to end of line}
- EMdelLine = 25; {Delete entire line}
- EMdelWord = 26; {Delete word to right of cursor}
- EMtab = 27; {Tab}
- EMins = 28; {Toggle insert mode}
- EMindent = 29; {Toggle auto-indent mode}
- EMwordWrap = 30; {Toggle word wrap}
- EMreformatP = 31; {Reformat paragraph}
- EMreformatG = 32; {Global reformat}
- EMhelp = 33; {Invoke help routine}
- EMmouse = 34; {Mouse select}
- EMuser0 = 35; {user-defined exit commands}
- EMuser1 = 36;
- EMuser2 = 37;
- EMuser3 = 38;
- EMuser4 = 39;
- EMuser5 = 40;
- EMuser6 = 41;
- EMuser7 = 42;
- EMuser8 = 43;
- EMuser9 = 44;
- EMuser10 = 45;
- EMuser11 = 46;
- EMuser12 = 47;
- EMuser13 = 48;
- EMuser14 = 49;
- EMuser15 = 50;
- EMuser16 = 51;
- EMuser17 = 52;
- EMuser18 = 53;
- EMuser19 = 54;
- {.F+}
-
- const
- MaxLineLength : Byte = 127; {!do not make larger than 127!}
-
- {error message codes}
- tmBufferFull = 1; {edit buffer is full}
- tmLineTooLong = 2; {line too long, CRLF inserted}
- tmTooManyLines = 3; {max line limit would be exceeded}
- tmOverLineLimit = 4; {max line limit already exceeded}
-
- {if True, reformatting routine treats blank space at start of line as
- signalling the start of a new paragraph}
- IndentStartsParagraph : Boolean = False;
-
- const
- AllowTruncation : Boolean = True; {read partial files?}
-
- type
- EMtype = EMnone..EMuser19;
- EMbuffer = array[1..65521] of Char;
- EMcontrolBlock =
- record
- UserData : Pointer; {reserved for user (ID number perhaps)}
- XL, YL, XH, YH : Byte; {coordinates for edit window}
- BufPtr : ^EMbuffer; {pointer to text buffer}
- BufSize : Word; {size of buffer}
- MaxLines : Integer; {maximum number of lines}
- TotalBytes : Word; {bytes in buffer}
- TotalLines : Integer; {lines in buffer}
- LineAtTop : Integer; {line at top of edit window}
- BufPosTop : Word; {index into buffer for start of line at top}
- CurLine : Integer; {line number of current line}
- BufPos : Word; {index into buffer for start of current line}
- CurCol : Byte; {position of cursor within current line}
- ColDelta : Byte; {for horizontal scrolling}
- KnownLine : Integer; {used to speed up scrolling/searching}
- KnownOfs : Word; {" " " " "}
- TAttr : Byte; {attribute for normal text}
- CAttr : Byte; {attribute for control characters}
- InsertMode : Boolean; {True if in insert mode}
- IndentMode : Boolean; {True if in auto-indent mode}
- ReadOnlyMode : Boolean;{True if in read-only mode}
- WordWrap : Boolean; {True if word wrap is on}
- Modified : Boolean; {True if edits have been made}
- TabDelta : Byte; {distance between tab stops}
- Margin : Byte; {right margin}
- HelpTopic : Word; {help topic}
- end;
-
- MemoStatusType = (
- mstOK, mstNotFound, mstInvalidName, mstReadError, mstTooLarge,
- mstTruncated, mstCreationError, mstWriteError, mstCloseError);
-
- const
- MemoKeyPtr : Pointer = nil; {pointer to routine to return next keystroke}
- MemoHelpPtr : Pointer = nil; {pointer to routine to display help}
- MemoStatusPtr : Pointer = nil; {pointer to routine to display status line}
- MemoErrorPtr : Pointer = nil; {pointer to routine to display error messages}
- HelpForMemo = HelpForXXXX1; {special code for help routine calls}
-
- const
- {the commands in this set are disallowed in read-only mode}
- DisallowedInReadOnlyMode : set of EMtype =
- [EMchar..EMenter, EMrestore, EMback..EMreformatG];
-
- const
- {used only by MemoStatus}
- StatusRow : Byte = 2; {default to second line of screen for status line}
- StatusAttr : Byte = $F; {attribute for status line}
- const
- {used only by MemoError}
- ErrorRow : Byte = 1; {default to top line of screen for error messages}
- ErrorAttr : Byte = $F; {attribute for error message line}
-
- {$IFDEF UseMouse}
- const
- {True if mouse support is enabled}
- MemoMouseEnabled : Boolean = False;
- {$ENDIF}
- {.F+}
-
- procedure InitControlBlock(var EMCB : EMcontrolBlock;
- XLow, YLow, XHigh, YHigh : Byte;
- TextAttr, CtrlAttr : Byte;
- InsertOn, IndentOn, WordWrapOn : Boolean;
- TabSize : Byte; HelpIndex : Word;
- RightMargin : Byte; LineLimit : Integer;
- BufferSize : Word; var Buffer);
- {-Initialize a memo editor control block}
-
- function EditMemo(var EMCB : EMcontrolBlock;
- ReadOnly : Boolean;
- var CmdList) : EMtype;
- {-Edit a buffer filled with text}
-
- procedure MemoStatus(var EMCB : EMcontrolBlock);
- {-Display status line}
-
- procedure MemoError(var EMCB : EMcontrolBlock; ErrorCode : Word);
- {-Display error message and wait for key press}
-
- function AddMemoCommand(Cmd : EMtype; NumKeys : Byte; Key1, Key2 : Word) : Boolean;
- {-Add a new command key assignment or change an existing one}
-
- {$IFDEF UseMouse}
-
- procedure EnableMemoMouse;
- {-Enable mouse support in TPMEMO}
-
- procedure DisableMemoMouse;
- {-Disable mouse support in TPMEMO}
-
- {$ENDIF}
-
- {file handling routines}
-
- function ReadMemoFile(var Buffer; BufferSize : Word;
- FName : string; var FSize : LongInt) : MemoStatusType;
- {-Read a file into Buffer, returning a status code}
-
- function SaveMemoFile(var EMCB : EMcontrolBlock; FName : string;
- MakeBackup : Boolean) : MemoStatusType;
- {-Save the current file in the text buffer associated with EMCB}
-
- {.F-}
- const
- {Keystroke to command mapping}
- MemoKeyMax = 250; {last available slot in MemoKeySet}
-
- {ID string for installation programs}
- MemoKeyID : string[16] = 'tpmemo key array';
-
- {default key assignments}
- MemoKeySet : array[0..MemoKeyMax] of Byte = (
- {length keys command type key sequence}
- 3, $00, $00, EMquit, {^Break}
- 3, $00, $13, EMreformatG, {AltR}
- 3, $00, $3B, EMhelp, {F1}
- 3, $00, $47, EMhome, {Home}
- 3, $00, $48, EMup, {Up}
- 3, $00, $49, EMpageUp, {PgUp}
- 3, $00, $4B, EMleft, {Left}
- 3, $00, $4D, EMright, {Right}
- 3, $00, $4F, EMend, {End}
- 3, $00, $50, EMdown, {Down}
- 3, $00, $51, EMpageDown, {PgDn}
- 3, $00, $52, EMins, {Ins}
- 3, $00, $53, EMdel, {Del}
- 3, $00, $73, EMwordLeft, {^Left}
- 3, $00, $74, EMwordRight, {^Right}
- 3, $00, $75, EMscreenBot, {^End}
- 3, $00, $76, EMendOfFile, {^PgDn}
- 3, $00, $77, EMscreenTop, {^Home}
- 3, $00, $84, EMtopOfFile, {^PgUp}
- 2, $01, EMwordLeft, {^A}
- 2, $02, EMreformatP, {^B}
- 2, $03, EMpageDown, {^C}
- 2, $04, EMright, {^D}
- 2, $05, EMup, {^E}
- 2, $06, EMwordRight, {^F}
- 2, $07, EMdel, {^G}
- 2, $08, EMback, {^H, Bksp}
- 2, $09, EMtab, {^I, Tab}
- 2, $0D, EMenter, {^M, Enter}
- 2, $10, EMctrlChar, {^P}
- 2, $12, EMpageUp, {^R}
- 2, $13, EMleft, {^S}
- 2, $14, EMdelWord, {^T}
- 2, $16, EMins, {^V}
- 2, $17, EMscrollUp, {^W}
- 2, $18, EMdown, {^X}
- 2, $19, EMdelLine, {^Y}
- 2, $1A, EMscrollDown, {^Z}
- 2, $1B, EMquit, {Esc}
- 2, $7F, EMback, {^Bksp}
- 3, $0F, $09, EMindent, {^O^I}
- 3, $0F, $17, EMwordWrap, {^O^W}
- 3, $11, $03, EMendOfFile, {^Q^C}
- 3, $11, $04, EMend, {^Q^D}
- 3, $11, $05, EMscreenTop, {^Q^E}
- 3, $11, $0C, EMrestore, {^Q^L}
- 3, $11, $12, EMtopOfFile, {^Q^R}
- 3, $11, $13, EMhome, {^Q^S}
- 3, $11, $18, EMscreenBot, {^Q^X}
- 3, $11, $19, EMdelEol, {^Q^Y}
- {$IFDEF UseMouse}
- 3, $00, $EF, EMmouse, {click left = mouse select}
- 3, $00, $EE, EMquit, {click right = ESC}
- 3, $00, $ED, EMhelp, {click both = help}
- {$ELSE}
- 0, 0, {180}
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {190}
- {$ENDIF}
- {-----------pad to end of array----------}
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {200}
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {210}
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {220}
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {230}
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {240}
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); {250}
- {.F+}
-
- {routines intended primarily for internal use, but which might be used to
- implement user-defined commands or for other purposes}
-
- function FindLineIndex(var EMCB : EMcontrolBlock; LineNum : Integer) : Word;
- {-Return the index into the edit buffer for the specified line number.
- LineNum must be <= EMCB.TotalLines.}
-
- function FindLineLength(var EMCB : EMcontrolBlock; LineNum : Integer) : Word;
- {-Find the length of the specified line}
-
- procedure InitBufferState(var EMCB : EMcontrolBlock;
- BufferSize : Word; var Buffer);
- {-Initialize the edit buffer status fields in a control block}
-
- procedure GetLine(var EMCB : EMcontrolBlock; var S : string; LineNum : Integer);
- {-Get the LineNum'th line from the buffer for the specified control block
- and store it in S. If line is longer than 255 characters, only the first
- 255 characters will be loaded into S.}
-
- procedure DrawLine(var EMCB : EMcontrolBlock; St : String; LineNum : Integer);
- {-Draw the string St, which represents the specified line number}
-
- procedure FastWriteCtrl(St : String; Row, Col, Attr, Ctrl : Byte);
- {-Write St at Row,Col in Attr (video attribute) without snow.
- Control characters displayed in Ctrl as upper-case letters}
-
- {==========================================================================}
-
- implementation
-
- const
- SafetyMargin = 2;
- CtrlZ : Char = ^Z;
- CRLF : array[1..2] of Char = ^M^J;
- SearchFailed = $FFFF;
-
- {$L TPMEMO}
-
- procedure FastWriteCtrl(St : String; Row, Col, Attr, Ctrl : Byte);
- {-Write St at Row,Col in Attr (video attribute) without snow.
- Control characters displayed in Ctrl as upper-case letters}
- external;
-
- function Scan(Limit : Integer; Ch : Char; T : Pointer) : Integer;
- {-Scan limit chars for Ch; Ch not found if Result=Limit}
- external;
-
- procedure HelpRoutine(UnitCode : Byte; IdPtr : Pointer; HelpIndex : Word);
- {-Call routine pointed to by MemoHelpPtr}
- inline(
- $FF/$1E/>MemoHelpPtr); {call dword ptr [>MemoHelpPtr]}
-
- procedure StatusRoutine(var EMCB : EMcontrolBlock);
- {-Call routine pointed to by MemoStatusPtr}
- inline(
- $FF/$1E/>MemoStatusPtr); {call dword ptr [>MemoStatusPtr]}
-
- procedure ErrorRoutine(var EMCB : EMcontrolBlock; ErrorCode : Word);
- {-Call routine pointed to by MemoErrorPtr}
- inline(
- $FF/$1E/>MemoErrorPtr); {call dword ptr [>MemoErrorPtr]}
-
- function GetKey : Word;
- {-Call routine pointed to by MemoKeyPtr}
- inline(
- $FF/$1E/>MemoKeyPtr); {call dword ptr [>MemoKeyPtr]}
-
- {$IFDEF UseMouse}
-
- procedure HideMousePrim(var MouseState : Boolean);
- {-Save state of mouse cursor in MouseState and hide it}
- begin
- MouseState := MouseCursorOn;
- HideMouse;
- end;
-
- procedure ShowMousePrim(MouseOn : Boolean);
- {-Hide or unhide the mouse cursor}
- begin
- if MouseOn then
- ShowMouse
- else
- HideMouse;
- end;
-
- {$ENDIF}
-
- procedure InitBufferState(var EMCB : EMcontrolBlock;
- BufferSize : Word; var Buffer);
- {-Initialize the edit buffer status fields in a control block}
- var
- I, J : Word;
- Buf : EMbuffer absolute Buffer;
- begin
- with EMCB do begin
- {reset edit buffer state variables}
- Modified := False;
- BufSize := BufferSize;
- BufPtr := @Buffer;
- BufPos := 1;
- BufPosTop := 1;
- KnownLine := 1;
- KnownOfs := 1;
- CurLine := 1;
- CurCol := 1;
- ColDelta := 0;
- LineAtTop := 1;
-
- {find end of text buffer}
- I := Search(Buffer, BufferSize, CtrlZ, 1);
-
- if (I = SearchFailed) or (I = 0) then begin
- {buffer is empty}
- TotalBytes := 1;
- TotalLines := 1;
- Buf[1] := CtrlZ;
- end
- else begin
- TotalBytes := I+1;
-
- {count total number of rows}
- TotalLines := 1;
- I := 1;
- repeat
- J := Search(Buf[I], Succ(TotalBytes-I), CRLF, 2);
- if J <> SearchFailed then begin
- Inc(TotalLines);
- Inc(I, J+2);
- end;
- until (J = SearchFailed) or (I >= TotalBytes);
- end;
- end;
- end;
-
- procedure InitControlBlock(var EMCB : EMcontrolBlock;
- XLow, YLow, XHigh, YHigh : Byte;
- TextAttr, CtrlAttr : Byte;
- InsertOn, IndentOn, WordWrapOn : Boolean;
- TabSize : Byte; HelpIndex : Word;
- RightMargin : Byte; LineLimit : Integer;
- BufferSize : Word; var Buffer);
- {-Initialize a memo editor control block}
- begin
- with EMCB do begin
- XL := XLow;
- YL := YLow;
- XH := XHigh;
- YH := YHigh;
- TAttr := TextAttr;
- CAttr := CtrlAttr;
- InsertMode := InsertOn;
- IndentMode := IndentOn;
- ReadOnlyMode := False;
- WordWrap := WordWrapOn;
- TabDelta := TabSize;
- if RightMargin = 0 then
- Margin := Succ(XH-XL)
- else if RightMargin > MaxLineLength then
- Margin := MaxLineLength
- else
- Margin := RightMargin;
- if LineLimit <= 0 then
- MaxLines := MaxInt
- else
- MaxLines := LineLimit;
- HelpTopic := HelpIndex;
-
- {initialize TotalLines, TotalBytes, etc.}
- InitBufferState(EMCB, BufferSize, Buffer);
- end;
- end;
-
- procedure MemoStatus(var EMCB : EMcontrolBlock);
- {-Display status line}
- const
- OnOff : array[Boolean] of string[3] = ('Off', 'On ');
- Save : array[Boolean] of string[4] = (' ', 'SAVE');
- StatusLine : string[80] =
- { 1 2 3 4 5 6 7 8}
- {12345678901234567890123456789012345678901234567890123456789012345678901234567890}
- ' Line: xxxxx Column: xxx 100% Insert: Off Indent: Off Word wrap: Off SAVE ';
- var
- S : string[5];
- {$IFDEF UseMouse}
- SaveMouse : Boolean;
- {$ENDIF}
- begin
- with EMCB do begin
- {insert line number}
- S := Long2Str(CurLine);
- S := Pad(S, 5);
- Move(S[1], StatusLine[8], 5);
-
- {insert column number}
- S := Long2Str(CurCol);
- S := Pad(S, 3);
- Move(S[1], StatusLine[23], 3);
-
- {insert percentage of buffer used}
- S := Real2Str(Trunc((TotalBytes*100.0)/(BufSize-SafetyMargin)), 3, 0);
- Move(S[1], StatusLine[28], 3);
-
- {insert remaining fields}
- Move(OnOff[InsertMode][1], StatusLine[42], 3);
- Move(OnOff[IndentMode][1], StatusLine[55], 3);
- Move(OnOff[WordWrap][1], StatusLine[71], 3);
- Move(Save[Modified][1], StatusLine[76], 4);
-
- {$IFDEF UseMouse}
- HideMousePrim(SaveMouse);
- {$ENDIF}
-
- {display status line}
- FastWrite(StatusLine, StatusRow, 1, StatusAttr);
-
- {$IFDEF UseMouse}
- ShowMousePrim(SaveMouse);
- {$ENDIF}
- end;
- end;
-
- procedure MemoError(var EMCB : EMcontrolBlock; ErrorCode : Word);
- {-Display error message and wait for key press}
- var
- S : string[80];
- I : Word;
- {$IFDEF UseMouse}
- SaveMouse : Boolean;
- {$ENDIF}
- begin
- case ErrorCode of
- tmBufferFull :
- S := 'Edit buffer is full';
- tmLineTooLong :
- S := 'Line too long, carriage return inserted';
- tmTooManyLines :
- S := 'Limit on number of lines has been reached';
- tmOverLineLimit :
- S := 'Limit on number of lines has been exceeded';
- else
- S := 'Unknown error';
- end;
- S := S+'. Press any key...';
-
- {$IFDEF UseMouse}
- HideMousePrim(SaveMouse);
- {$ENDIF}
-
- {display error message}
- FastWrite(Pad(S, ScreenWidth), ErrorRow, 1, ErrorAttr);
-
- {$IFDEF UseMouse}
- ShowMousePrim(SaveMouse);
- {$ENDIF}
-
- {flush the keyboard buffer}
- while KeyPressed do
- I := GetKey;
-
- {wait for key press}
- I := GetKey;
-
- {clear error message line}
- FastWrite(CharStr(' ', ScreenWidth), ErrorRow, 1, ErrorAttr);
- end;
-
- function FindLineIndex(var EMCB : EMcontrolBlock; LineNum : Integer) : Word;
- {-Return the index into the edit buffer for the specified line number}
- var
- I : Integer;
- begin
- with EMCB do begin
- if LineNum = 1 then begin
- KnownLine := 1;
- KnownOfs := 1;
- end
- else if LineNum >= KnownLine then
- while KnownLine < LineNum do begin
- I := Succ(TotalBytes-KnownOfs);
- if I < 0 then
- I := MaxInt;
- Inc(KnownOfs, Succ(Scan(I, ^J, @BufPtr^[KnownOfs])));
- Inc(KnownLine);
- end
- else begin
- {linenum < knownline, search backwards}
- Dec(KnownOfs, 2);
- while KnownLine > LineNum do begin
- I := KnownOfs;
- if I < 0 then
- I := MaxInt;
- Inc(Integer(KnownOfs), Pred(Scan(-I, ^J, @BufPtr^[KnownOfs])));
- Dec(KnownLine);
- end;
-
- {point to start of next line}
- Inc(KnownOfs, 2);
- end;
-
- FindLineIndex := KnownOfs;
- end;
- end;
-
- function FindLineLength(var EMCB : EMcontrolBlock; LineNum : Integer) : Word;
- {-Find the length of the specified line}
- var
- I, J : Word;
- begin
- with EMCB do
- if LineNum > TotalLines then
- FindLineLength := 0
- else begin
- {find starting index for line}
- J := FindLineIndex(EMCB, LineNum);
-
- {calculate length}
- I := Search(BufPtr^[J], Succ(TotalBytes-J), CRLF, 2);
- if I = SearchFailed then
- FindLineLength := TotalBytes-J
- else
- FindLineLength := I;
- end;
- end;
-
- procedure GetLine(var EMCB : EMcontrolBlock; var S : string; LineNum : Integer);
- {-Get the LineNum'th line from the buffer for the specified control block,
- and store it in S}
- var
- I, J : Word;
- SLen : Byte absolute S;
- begin
- with EMCB do
- if LineNum > TotalLines then
- SLen := 0
- else begin
- {find starting index and length for line}
- J := FindLineIndex(EMCB, LineNum);
- I := FindLineLength(EMCB, LineNum);
-
- {truncate if line is too long}
- if I > 255 then
- SLen := 255
- else
- SLen := I;
-
- Move(BufPtr^[J], S[1], SLen);
- end;
- end;
-
- procedure DrawLine(var EMCB : EMcontrolBlock; St : String; LineNum : Integer);
- {-Draw the string St, which represents the specified line number}
- var
- StLen : Byte absolute St;
- WinWidth : Byte;
- begin
- {calculate screen row}
- Dec(LineNum, Pred(EMCB.LineAtTop));
- Inc(LineNum, Pred(EMCB.YL));
-
- with EMCB do begin
- WinWidth := Succ(XH-XL);
-
- {adjust for ColDelta}
- if (ColDelta > 0) and (StLen > 0) then
- if ColDelta >= StLen then
- StLen := 0
- else begin
- Move(St[ColDelta+1], St[1], StLen-ColDelta);
- Dec(StLen, ColDelta);
- end;
- end;
-
- {pad the end of the string}
- if StLen < WinWidth then
- FillChar(St[Succ(StLen)], WinWidth-StLen, ' ');
-
- {change the length}
- StLen := WinWidth;
-
- {draw the string}
- with EMCB do
- if CAttr = TAttr then
- FastWrite(St, LineNum, XL, TAttr)
- else
- FastWriteCtrl(St, LineNum, XL, TAttr, CAttr);
- end;
-
- function EditMemo(var EMCB : EMcontrolBlock;
- ReadOnly : Boolean;
- var CmdList) : EMtype;
- {-Edit a buffer filled with text}
- type
- CmdListType = array[1..100] of EMtype;
- var
- ChWord : Word;
- Ch : Char absolute ChWord;
- OldSt, St : string; {text of current line}
- OldCol : Byte;
- OldModified : Boolean;
- StLen : Byte absolute St;
- I, J : Word;
- CursorSL : Word;
- CursorXY : Word;
- SaveBreak : Boolean;
- ForceRedraw : Boolean;
- DoingChars : Boolean;
- Done, OK : Boolean;
- WinWidth : Byte;
- EMC : EMtype;
- UserCmdList : CmdListType absolute CmdList;
- NextUserCmd : Word;
- {$IFDEF UseMouse}
- SaveWaitState : Boolean;
- SaveMouse : Boolean;
- {$ENDIF}
-
- procedure CallErrorRoutine(Code : Integer);
- {-Call the user-defined error routine}
- begin
- if MemoErrorPtr <> nil then
- ErrorRoutine(EMCB, Code);
- end;
-
- procedure TrimSpaces;
- {-Trim trailing blanks from current line}
- begin
- while St[StLen] = ' ' do
- Dec(StLen);
- end;
-
- function InsertOK(N : Integer) : Boolean;
- {-Return True if OK to insert N bytes into the edit buffer. Calls user
- error handler if not OK.}
- var
- I : LongInt;
- begin
- with EMCB do begin
- {allow a safety margin}
- I := TotalBytes+SafetyMargin;
-
- {calculate actual TotalBytes+N}
- Inc(I, LongInt(N)+(LongInt(StLen)-Length(OldSt)));
-
- if I <= BufSize then
- InsertOK := True
- else begin
- InsertOK := False;
- CallErrorRoutine(tmBufferFull);
- end;
- end;
- end;
-
- procedure ToggleInsertMode;
- {-Toggle between insert and overtype mode, keeping BIOS keyboard flag up
- to date}
- var
- BiosKbdFlag : Byte absolute $0040 : $0017;
- begin
- with EMCB do begin
- {toggle insert flag}
- InsertMode := not InsertMode;
-
- {use fat cursor if inserting}
- if InsertMode then begin
- FatCursor;
- BiosKbdFlag := BiosKbdFlag or $80;
- end
- else begin
- NormalCursor;
- BiosKbdFlag := BiosKbdFlag and $7F;
- end;
- end;
- end;
-
- procedure DrawCurrentLine;
- {-Draw the current line}
- {$IFDEF UseMouse}
- var
- SaveMouse : Boolean;
- {$ENDIF}
- begin
- {$IFDEF UseMouse}
- HideMousePrim(SaveMouse);
- {$ENDIF}
-
- {draw the current line}
- DrawLine(EMCB, St, EMCB.CurLine);
-
- {$IFDEF UseMouse}
- ShowMousePrim(SaveMouse);
- {$ENDIF}
- end;
-
- procedure RedrawScreen;
- {-Redraw entire screen}
- var
- I, J : Integer;
- S : String;
- {$IFDEF UseMouse}
- SaveMouse : Boolean;
- {$ENDIF}
- begin
- {$IFDEF UseMouse}
- HideMousePrim(SaveMouse);
- {$ENDIF}
-
- with EMCB do begin
- J := LineAtTop+(YH-YL);
- for I := LineAtTop to J do begin
- if (I = CurLine) then
- DrawLine(EMCB, St, I)
- else begin
- GetLine(EMCB, S, I);
- DrawLine(EMCB, S, I);
- end;
- end;
- end;
-
- {$IFDEF UseMouse}
- ShowMousePrim(SaveMouse);
- {$ENDIF}
-
- ForceRedraw := False;
- end;
-
- procedure SaveCurrentLine(Trim : Boolean);
- {-Patch the current line back into place}
- var
- I, J : Word;
- K : Integer;
- begin
- with EMCB do begin
- if Trim then
- TrimSpaces;
- if St = OldSt then
- Exit;
-
- {find the actual length of the current line}
- I := BufPos;
- J := FindLineLength(EMCB, CurLine);
-
- {calculate difference in size}
- K := Integer(StLen)-J;
-
- if K > 0 then
- {make room for new text}
- Move(BufPtr^[I], BufPtr^[I+K], Succ(TotalBytes-I))
- else
- {delete excess characters}
- Move(BufPtr^[I-K], BufPtr^[I], Succ(TotalBytes-I)+K);
-
- {insert the text}
- Move(St[1], BufPtr^[I], StLen);
- Inc(TotalBytes, K);
-
- KnownLine := LineAtTop;
- KnownOfs := BufPosTop;
- OldSt := St;
- Modified := True;
- OldModified := True;
- end;
- end;
-
- procedure ScrollDisplay(Lines : Integer);
- {-Scroll the editing window up or down}
- var
- S : string;
- SaveTextAttr : Byte;
- I, J, K : Integer;
- {$IFDEF UseMouse}
- SaveMouse : Boolean;
- {$ENDIF}
- begin
- if Lines = 0 then
- Exit;
- with EMCB do begin
- SaveTextAttr := TextAttr;
- TextAttr := TAttr;
-
- {$IFDEF UseMouse}
- HideMousePrim(SaveMouse);
- {$ENDIF}
-
- if Lines < 0 then
- ScrollWindowDown(XL, YL, XH, YH, -Lines)
- else
- ScrollWindowUp(XL, YL, XH, YH, Lines);
-
- BufPosTop := FindLineIndex(EMCB, LineAtTop+Lines);
- Inc(LineAtTop, Lines);
-
- if Lines < 0 then begin
- J := LineAtTop;
- K := Pred(J-Lines);
- end
- else begin
- J := LineAtTop+(YH-YL)-Pred(Lines);
- K := Pred(J+Lines);
- end;
-
- {draw the line(s) replacing the one(s) that scrolled off}
- for I := J to K do begin
- GetLine(EMCB, S, I);
- DrawLine(EMCB, S, I);
- end;
-
- {$IFDEF UseMouse}
- ShowMousePrim(SaveMouse);
- {$ENDIF}
-
- TextAttr := SaveTextAttr;
- end;
- end;
-
- function TooManyLinesCheck : Boolean;
- {-Check to see if there are too many lines}
- begin
- with EMCB do
- if Word(TotalLines) >= Word(MaxLines) then begin
- CallErrorRoutine(tmTooManyLines);
- OK := False;
- TooManyLinesCheck := True;
- end
- else
- TooManyLinesCheck := False;
- end;
-
- procedure InsLinePrim(LineNum, Col : Integer);
- {-Primitive routine to insert a line break}
- var
- I, J : Word;
- begin
- with EMCB do begin
- if TooManyLinesCheck then
- Exit;
-
- {find the place to insert the line break}
- I := FindLineIndex(EMCB, LineNum)+Pred(Col);
-
- {see if we need to trim some blanks}
- J := Pred(I);
- while (J > 0) and (BufPtr^[J] = ' ') do
- Dec(J);
- Inc(J);
-
- if J <> I then begin
- {see if there's room}
- OK := InsertOK(2-(I-J));
- if not OK then
- Exit;
-
- {make room for a CRLF}
- Move(BufPtr^[I], BufPtr^[J+2], Succ(TotalBytes-I));
-
- {insert the CRLF}
- Move(CRLF, BufPtr^[J], 2);
-
- {adjust counters}
- Inc(TotalLines);
- TotalBytes := (TotalBytes+2)-(I-J);
- end
- else begin
- {see if there's room}
- OK := InsertOK(2);
- if not OK then
- Exit;
-
- {make room for a CRLF}
- Move(BufPtr^[I], BufPtr^[I+2], Succ(TotalBytes-I));
-
- {insert the CRLF}
- Move(CRLF, BufPtr^[I], 2);
-
- {adjust counters}
- Inc(TotalLines);
- Inc(TotalBytes, 2);
- end;
-
- Modified := True;
- end;
- end;
-
- procedure LoadLine(LineNum : Integer; Truncate : Boolean);
- {-Load the specified line}
- var
- I, J, K, N, Max : Word;
- begin
- with EMCB do begin
- {find the line we're moving to}
- BufPos := FindLineIndex(EMCB, LineNum);
- CurLine := LineNum;
-
- {find the length of the line}
- I := FindLineLength(EMCB, LineNum);
-
- {calc max length of line}
- if Truncate then
- Max := MaxLineLength
- else
- Max := 255;
-
- {insert carriage return if line is too long}
- if I > Max then begin
- {determine where to break the line}
- K := Max;
- N := FindLineIndex(EMCB, LineNum);
- J := N+Pred(K);
- while (J > N) and (BufPtr^[J] <> ' ') do begin
- Dec(J);
- Dec(K);
- end;
- if J = N then
- K := Max;
-
- {try to break the line}
- Inc(MaxLines);
- InsLinePrim(LineNum, K);
- Dec(MaxLines);
-
- if not OK then begin
- {something overflowed--force the line break}
- Inc(N, K);
- BufPtr^[N] := ^M;
- BufPtr^[N+1] := ^J;
- Inc(TotalLines);
- end;
-
- {report the break}
- CallErrorRoutine(tmLineTooLong);
-
- {force screen to be redrawn}
- ForceRedraw := True;
-
- {recalculate the length}
- I := FindLineLength(EMCB, LineNum);
- end;
-
- {load the line into St and OldSt}
- StLen := I;
- Move(BufPtr^[BufPos], St[1], StLen);
- OldSt := St;
- OldCol := CurCol;
- Modified := OldModified;
- end;
- end;
-
- procedure GotoLine(LineNum : Integer; Trim : Boolean);
- {-Save the current line and move the cursor to the LineNum'th line}
- var
- I : Word;
- begin
- with EMCB do begin
- {don't go too far}
- if LineNum > TotalLines then
- LineNum := TotalLines;
-
- {save the line we've been editing}
- SaveCurrentLine(Trim);
-
- {scroll the display if necessary}
- if LineNum < LineAtTop then
- ScrollDisplay(LineNum-LineAtTop)
- else begin
- I := LineAtTop+(YH-YL);
- if LineNum > I then
- ScrollDisplay(LineNum-I);
- end;
-
- {load the line}
- LoadLine(LineNum, Trim);
- end;
- end;
-
- procedure DelLinePrim(LineNum : Integer);
- {-Primitive routine to delete a line}
- var
- I, J : Word;
- begin
- with EMCB do begin
- {find the line we're deleting}
- I := FindLineIndex(EMCB, LineNum);
-
- {find the length of the line}
- J := Search(BufPtr^[I], Succ(TotalBytes-I), CRLF, 2);
- if J = SearchFailed then
- J := TotalBytes-BufPos
- else
- Inc(J, 2);
-
- {delete it}
- Move(BufPtr^[I+J], BufPtr^[I], Succ(TotalBytes-I)-J);
- Dec(TotalLines);
- if TotalLines = 0 then begin
- TotalLines := 1;
- TotalBytes := 1;
- BufPtr^[1] := ^Z;
- end
- else
- Dec(TotalBytes, J);
-
- Modified := True;
- OldModified := True;
- end;
- end;
-
- procedure JoinLinePrim(LineNum : Integer);
- {-Primitive routine to join two lines}
- var
- I : Word;
- begin
- with EMCB do begin
- {find the place to join the lines}
- I := FindLineIndex(EMCB, LineNum);
-
- {make room for a CRLF}
- Move(BufPtr^[I], BufPtr^[I-2], Succ(TotalBytes-I));
-
- Dec(TotalLines);
- Dec(TotalBytes, 2);
- BufPtr^[TotalBytes+1] := ^Z;
-
- Modified := True;
- OldModified := True;
- end;
- end;
-
- procedure PutLineAtTop(LineNum : Integer);
- {-Position the specified line at top of editing window}
- begin
- with EMCB do begin
- if LineNum < 1 then
- LineNum := 1
- else if LineNum > TotalLines then
- LineNum := TotalLines;
- BufPosTop := FindLineIndex(EMCB, LineNum);
- LineAtTop := LineNum;
- RedrawScreen;
- end;
- end;
-
- function GetIndent(S : string) : Byte;
- {-Get the indentation level of S}
- var
- I : Word;
- SLen : Byte absolute S;
- begin
- I := 0;
- while S[SLen] = ' ' do
- Dec(SLen);
- while (I < SLen) and (S[I+1] = ' ') do
- Inc(I);
- GetIndent := I;
- end;
-
- procedure WrapLine(Trim : Boolean);
- {-Word wrap the current line}
- var
- I, J : Integer;
- Temp, SaveSt : string;
- begin
- with EMCB do begin
- if TooManyLinesCheck then
- Exit;
- SaveSt := St;
- TpString.WordWrap(St, St, Temp, Margin, False);
- if IndentMode then begin
- I := GetIndent(St);
- if I <> 0 then
- Insert(CharStr(' ', I), Temp, 1);
- end;
- I := Length(Temp)-(Length(SaveSt)-CurCol);
- if I < 1 then
- I := 1;
- SaveCurrentLine(True);
- DrawCurrentLine;
- InsLinePrim(CurLine, StLen+1);
- if OK then begin
- GotoLine(CurLine+1, Trim);
- St := Temp;
- SaveCurrentLine(True);
- ColDelta := 0;
- CurCol := I;
- OldCol := I;
- end
- else begin
- St := SaveSt;
- SaveCurrentLine(True);
- end;
- end;
- end;
-
- procedure ReformatParagraph;
- {-Reformat a paragraph starting at the current line}
- var
- SaveMax, I : Integer;
- Temp : string;
- begin
- with EMCB do begin
- SaveCurrentLine(True);
-
- if StLen = 0 then begin
- GotoLine(CurLine+1, True);
- Exit;
- end;
-
- {ignore line limit when reformatting}
- SaveMax := MaxLines;
- MaxLines := MaxInt;
-
- while (CurLine < TotalLines) and (OK = True) do begin
- while (StLen > Margin) and OK do
- WrapLine(False);
- if OK then
- OK := FindLineLength(EMCB, CurLine+1) <> 0;
- if OK and IndentStartsParagraph then
- OK := BufPtr^[KnownOfs] <> ' ';
-
- if OK then begin
- Inc(StLen);
- St[StLen] := ' ';
- I := Succ(StLen);
- SaveCurrentLine(False);
- JoinLinePrim(CurLine+1);
- LoadLine(CurLine, False);
- while (I < StLen) and (St[I] = ' ') do
- Delete(St, I, 1);
- TrimSpaces;
- end;
- end;
-
- OK := True;
- while (StLen > Margin) and OK do
- WrapLine(False);
-
- RedrawScreen;
- GotoLine(CurLine+1, True);
- if CurLine = TotalLines then
- CurCol := Succ(StLen)
- else
- CurCol := 1;
- OldCol := CurCol;
- MaxLines := SaveMax;
- end;
- end;
-
- procedure DeleteWordPrim;
- {-Primitive routine to delete a word}
- var
- DelEnd : Word;
- begin
- with EMCB do begin
- if CurCol > StLen then
- Exit;
-
- {start deleting at the cursor}
- DelEnd := CurCol;
-
- {delete all of the current word, if any}
- if St[CurCol] <> ' ' then
- while (St[DelEnd] <> ' ') and (DelEnd <= StLen) do
- Inc(DelEnd);
-
- {delete any spaces prior to the next word, if any}
- while (St[DelEnd] = ' ') and (DelEnd <= StLen) do
- Inc(DelEnd);
-
- Delete(St, CurCol, DelEnd-CurCol);
- end;
- end;
-
- {$IFDEF UseMouse}
-
- procedure MouseSelect;
- {-Move cursor to position of mouse}
- var
- CurRow, TargetLine : Integer;
- TargetRow, TargetCol : Integer;
- begin
- {convert mouse X and Y coordinates to absolute row and col}
- TargetRow := MouseKeyWordY+MouseYLo;
- TargetCol := MouseKeyWordX+MouseXLo;
-
- with EMCB do
- {make sure mouse is within edit window}
- if (TargetCol >= XL) and (TargetCol <= XH)
- and (TargetRow >= YL) and (TargetRow <= YH) then begin
- {calculate current screen row}
- CurRow := Word(YL)+(CurLine-LineAtTop);
-
- {calculate target line number}
- TargetLine := CurLine+(TargetRow-CurRow);
-
- if TargetLine <= TotalLines then begin
- {move cursor to desired location}
- CurCol := TargetCol-Pred(XL)-ColDelta;
- GotoLine(TargetLine, True);
- end;
- end;
- end;
-
- {$ENDIF}
-
- procedure TopOfFile;
- {-Reset for top of file}
- begin
- with EMCB do begin
- PutLineAtTop(1);
- GotoLine(1, True);
- CurCol := 1;
- OldCol := 1;
- RedrawScreen;
- end;
- end;
-
- procedure ReformatGlobally;
- {-Reformat entire file}
- begin
- with EMCB do begin
- {skip all this if the file is empty}
- if TotalBytes = 1 then
- Exit;
-
- {go to top of file}
- TopOfFile;
-
- {while not at last line, reformat paragraphs}
- while CurLine < TotalLines do
- ReformatParagraph;
- end;
- end;
-
- procedure CheckLineLimit;
- {-Display error message if line limit exceeded}
- begin
- with EMCB do
- if TotalLines > MaxLines then begin
- RedrawScreen;
- CallErrorRoutine(tmOverLineLimit);
- end;
- end;
-
- begin
- with EMCB do begin
- {Store cursor position and shape}
- GetCursorState(CursorXY, CursorSL);
-
- {Save break checking state}
- SaveBreak := CheckBreak;
- CheckBreak := False;
-
- {set cursor shape}
- InsertMode := not InsertMode;
- ToggleInsertMode;
-
- {initialize miscellaneous variables}
- WinWidth := Succ(XH-XL);
- NextUserCmd := 1;
- KnownLine := 1;
- KnownOfs := 1;
- OldModified := Modified;
- ReadOnlyMode := ReadOnly;
-
- {$IFDEF UseMouse}
- SaveMouse := MouseCursorOn;
- {$ENDIF}
-
- {get the first line}
- LoadLine(EMCB.CurLine, True);
-
- {draw whole screen}
- ForceRedraw := True;
-
- {see if we exceeded the line limit}
- CheckLineLimit;
-
- {loop while reading keys}
- Done := False;
- DoingChars := False;
- repeat
- OK := True;
-
- {update screen}
- if CurCol > MaxLineLength+1 then
- CurCol := MaxLineLength+1;
- if CurCol > WinWidth+ColDelta then begin
- ColDelta := CurCol-WinWidth;
- RedrawScreen;
- end
- else if CurCol < Succ(ColDelta) then begin
- ColDelta := Pred(CurCol);
- RedrawScreen;
- end
- else if ForceRedraw then
- RedrawScreen
- else
- DrawCurrentLine;
-
- {position cursor}
- GoToXYAbs(XL+Pred(CurCol)-ColDelta, YL+(CurLine-LineAtTop));
-
- {set modified flag}
- TrimSpaces;
- Modified := OldModified or (St <> OldSt);
-
- {display status line}
- if MemoStatusPtr <> nil then begin
- {update TotalBytes field for status routine}
- J := TotalBytes;
- Inc(TotalBytes, Integer(StLen)-Length(OldSt));
-
- {call status routine}
- StatusRoutine(EMCB);
-
- {reset TotalBytes field}
- TotalBytes := J;
- end;
-
- {$IFDEF UseMouse}
- if MemoMouseEnabled then begin
- SaveWaitState := WaitForButtonRelease;
- WaitForButtonRelease := True;
- end;
- {$ENDIF}
-
- {see if there is a user command left to process}
- EMC := UserCmdList[NextUserCmd];
- if DoingChars then begin
- if EMC = EMchar then begin
- {EMchar acts as toggle}
- EMC := EMnone;
- DoingChars := False;
- end
- else begin
- {treat the command as a character}
- Ch := Char(EMC);
- EMC := EMchar;
- end;
- Inc(NextUserCmd);
- end
- else if EMC = EMnone then
- {read from the keyboard}
- EMC := GetCommand(MemoKeySet, MemoKeyPtr, ChWord)
- else begin
- {process next user command}
- Inc(NextUserCmd);
- if EMC = EMchar then begin
- DoingChars := True;
- EMC := EMnone;
- end;
- end;
-
- {make sure command is allowable if in read-only mode}
- if ReadOnlyMode then
- if EMC in DisallowedInReadOnlyMode then
- EMC := EMnone;
-
- {reinterpret potentially troublesome control characters}
- if EMC = EMchar then
- case Ch of
- ^M : EMC := EMenter;
- ^J, ^Z : EMC := EMnone;
- end;
-
- {$IFDEF UseMouse}
- if MemoMouseEnabled then
- WaitForButtonRelease := SaveWaitState;
- {$ENDIF}
-
- {deal with control characters if desired}
- if EMC = EMctrlChar then
- {don't allow control characters if attributes are the same}
- if (CAttr = TAttr) then
- EMC := EMnone
- else begin
- BlockCursor;
- ChWord := GetKey;
- EMC := EMchar;
- if InsertMode then
- FatCursor
- else
- NormalCursor;
- end;
-
- case EMC of
- EMchar : {A character to enter the string}
- if CurCol <= MaxLineLength then begin
- if CurCol > StLen then
- FillChar(St[Succ(StLen)], CurCol-StLen, ' ');
-
- if not InsertMode then begin
- {overtype mode}
- if (CurCol <= MaxLineLength) then begin
- St[CurCol] := Ch;
- if (Ch <> ' ') and (CurCol > StLen) and InsertOK(CurCol-StLen) then
- StLen := CurCol;
- Inc(CurCol);
- end;
- end
- else if StLen < MaxLineLength then begin
- {insert mode}
- if CurCol > StLen then begin
- if Ch = ' ' then
- Inc(CurCol)
- else if InsertOK(CurCol-StLen) then begin
- StLen := CurCol;
- St[CurCol] := Ch;
- Inc(CurCol);
- end;
- end
- else if InsertOK(1) then begin
- Insert(Ch, St, CurCol);
- Inc(CurCol);
- end;
- end;
-
- if WordWrap and (CurCol > Margin) and (StLen > Margin) then begin
- WrapLine(True);
- ForceRedraw := True;
- end;
- end;
-
- EMenter : {new line}
- begin
- I := GetIndent(St);
- if InsertMode then begin
- if IndentMode and (CurCol <= StLen) and (I > 0) then
- Insert(CharStr(' ', I), St, CurCol);
- SaveCurrentLine(True);
- if CurCol > StLen then
- CurCol := Succ(StLen);
- InsLinePrim(CurLine, CurCol);
- end;
-
- if OK then begin
- GotoLine(CurLine+1, True);
- if IndentMode and InsertMode then
- CurCol := Succ(I)
- else
- CurCol := 1;
- OldCol := CurCol;
- if InsertMode then
- ForceRedraw := True;
- end;
- end;
-
- EMuser0..EMuser9, {user-defined exit commands}
- EMquit : {exit from editor}
- begin
- SaveCurrentLine(True);
- Done := True;
- end;
-
- EMhome : {Cursor to beginning of line}
- CurCol := 1;
-
- EMend : {Cursor to end of line}
- CurCol := Succ(StLen);
-
- EMdelEol : {Delete from cursor to end of line}
- if StLen > CurCol then
- StLen := Pred(CurCol);
-
- EMdelLine : {Delete entire line}
- if CurLine = TotalLines then begin
- StLen := 0;
- CurCol := 1;
- SaveCurrentLine(True);
- end
- else begin
- DelLinePrim(CurLine);
- CurCol := 1;
- LoadLine(CurLine, True);
- ForceRedraw := True;
- end;
-
- EMrestore : {Restore default and continue}
- begin
- St := OldSt;
- CurCol := OldCol;
- end;
-
- EMleft : {Cursor left by one character}
- if CurCol > 1 then
- Dec(CurCol);
-
- EMright : {Cursor right by one character}
- Inc(CurCol);
-
- EMup : {Cursor up one line}
- if CurLine > 1 then
- GotoLine(CurLine-1, True);
-
- EMdown : {Cursor down one line}
- if CurLine < TotalLines then
- GotoLine(CurLine+1, True);
-
- EMscrollUp : {Scroll display up one line}
- if LineAtTop > 1 then begin
- ScrollDisplay(-1);
- I := LineAtTop+(YH-YL);
- if CurLine > I then
- GotoLine(I, True);
- end;
-
- EMscrollDown : {Scroll display down one line}
- if LineAtTop < TotalLines then begin
- ScrollDisplay(1);
- if CurLine < LineAtTop then
- GotoLine(LineAtTop, True);
- end;
-
- EMpageUp : {Scroll display up one page}
- if LineAtTop > 1 then begin
- I := (YH-YL);
- if I > CurLine then begin
- PutLineAtTop(1);
- GotoLine(1, True);
- end
- else begin
- J := CurLine-LineAtTop;
- PutLineAtTop(LineAtTop-I);
- GotoLine(LineAtTop+J, True);
- end;
- end
- else
- GotoLine(1, True);
-
- EMpageDown : {Scroll display down one page}
- if LineAtTop < TotalLines then begin
- I := (YH-YL);
- if TotalLines <= Succ(I) then begin
- PutLineAtTop(TotalLines);
- GotoLine(TotalLines, True);
- end
- else begin
- J := CurLine-LineAtTop;
- PutLineAtTop(LineAtTop+I);
- GotoLine(LineAtTop+J, True);
- end;
- end;
-
- EMscreenTop : {Cursor to top of screen}
- GotoLine(LineAtTop, True);
-
- EMscreenBot : {Cursor to bottom of screen}
- GotoLine(LineAtTop+(YH-YL), True);
-
- EMtopOfFile : {Cursor to top of file}
- TopOfFile;
-
- EMendOfFile : {Cursor to bottom of file}
- begin
- I := YH-YL;
- if CurLine < TotalLines-I then
- PutLineAtTop(TotalLines-I);
- GotoLine(TotalLines, True);
- CurCol := Succ(StLen);
- OldCol := CurCol;
- end;
-
- EMtab : {Tab}
- begin
- I := Succ(Succ(CurCol div TabDelta) * TabDelta);
- if (not InsertMode) or (CurCol > StLen) then
- CurCol := I
- else if (CurCol <= StLen) then begin
- if InsertOK(I-CurCol) and (Margin-StLen > I-CurCol) then begin
- Insert(CharStr(' ', I-CurCol), St, CurCol);
- CurCol := I;
- end;
- end
- end;
-
- EMwordLeft : {Cursor left one word}
- if CurCol > 1 then begin
- Dec(CurCol);
- while (CurCol >= 1) and ((CurCol > StLen) or (St[CurCol] = ' ')) do
- Dec(CurCol);
- while (CurCol >= 1) and (St[CurCol] <> ' ') do
- Dec(CurCol);
- Inc(CurCol);
- end
- else if CurLine > 1 then begin
- GotoLine(CurLine-1, True);
- CurCol := Succ(StLen);
- OldCol := CurCol;
- end;
-
- EMwordRight : {Cursor right one word}
- begin
- if CurCol < StLen then begin
- Inc(CurCol);
- while (CurCol <= StLen) and (St[CurCol] <> ' ') do
- Inc(CurCol);
- while (CurCol <= StLen) and (St[CurCol] = ' ') do
- Inc(CurCol);
- end
- else if CurLine < TotalLines then begin
- GotoLine(CurLine+1, True);
- CurCol := 1;
- OldCol := 1;
- end;
- end;
-
- EMdel : {Delete current character}
- if CurCol <= StLen then
- Delete(St, CurCol, 1);
-
- EMback : {Backspace one character}
- if CurCol > 1 then begin
- Dec(CurCol);
- Delete(St, CurCol, 1);
- end
- else if CurLine > 1 then begin
- GotoLine(CurLine-1, True);
- CurCol := Succ(StLen);
- JoinLinePrim(CurLine+1);
- LoadLine(CurLine, True);
- ForceRedraw := True;
- OldCol := CurCol;
- end;
-
- EMdelWord : {Delete word to right of cursor}
- begin
- if CurCol <= StLen then
- DeleteWordPrim
- else if CurLine < TotalLines then
- if InsertOK(CurCol-StLen) then begin
- FillChar(St[Succ(StLen)], CurCol-StLen, ' ');
- StLen := Pred(CurCol);
- I := CurCol;
- SaveCurrentLine(False);
- JoinLinePrim(CurLine+1);
- LoadLine(CurLine, True);
- CurCol := I;
- ForceRedraw := True;
- OldCol := CurCol;
- end;
- end;
-
- EMins : {Toggle insert mode}
- ToggleInsertMode;
-
- EMindent : {Toggle auto-indent mode}
- IndentMode := not IndentMode;
-
- EMwordWrap : {Toggle word wrap}
- WordWrap := not WordWrap;
-
- EMreformatP : {Reformat paragraph}
- begin
- ReformatParagraph;
- CheckLineLimit;
- end;
-
- EMreformatG : {Global reformat}
- begin
- ReformatGlobally;
- CheckLineLimit;
- end;
-
- {$IFDEF UseMouse}
-
- EMmouse : {Mouse select}
- if MemoMouseEnabled then
- MouseSelect;
-
- {$ENDIF}
-
- EMhelp : {Help}
- if MemoHelpPtr <> nil then
- HelpRoutine(HelpForMemo, @EMCB, HelpTopic);
- end;
-
- until Done;
-
- {redraw the screen one last time}
- RedrawScreen;
-
- {restore break checking status}
- CheckBreak := SaveBreak;
-
- {Restore cursor position and shape}
- RestoreCursorState(CursorXY, CursorSL);
-
- {$IFDEF UseMouse}
- ShowMousePrim(SaveMouse);
- {$ENDIF}
-
- {return exit code}
- EditMemo := EMC;
- end;
- end;
-
- function AddMemoCommand(Cmd : EMtype; NumKeys : Byte; Key1, Key2 : Word) : Boolean;
- {-Add a new command key assignment or change an existing one}
- begin
- AddMemoCommand :=
- AddCommandPrim(MemoKeySet, MemoKeyMax, Cmd, NumKeys, Key1, Key2);
- end;
-
- {$IFDEF UseMouse}
- procedure EnableMemoMouse;
- {-Enable mouse support in TPMEMO}
- begin
- if MouseInstalled and not MemoMouseEnabled then begin
- MemoKeyPtr := @ReadKeyOrButton;
- EnableEventHandling;
- MemoMouseEnabled := True;
- end;
- end;
-
- procedure DisableMemoMouse;
- {-Disable mouse support in TPMEMO}
- begin
- if MemoMouseEnabled then begin
- MemoKeyPtr := @ReadKeyWord;
- DisableEventHandling;
- MemoMouseEnabled := False;
- end;
- end;
- {$ENDIF}
-
- function ReadMemoFile(var Buffer; BufferSize : Word;
- FName : string; var FSize : LongInt) : MemoStatusType;
- {-Read a file into Buffer, returning a status code}
- var
- Buf : array[1..65521] of Char absolute Buffer;
- F : file;
- I, BytesRead, BytesToRead : Word;
- MaxSize : LongInt;
- begin
- ReadMemoFile := mstNotFound;
- FSize := 0;
- Buf[1] := ^Z;
- if Length(FName) = 0 then
- Exit;
-
- {try to open file}
- Assign(F, FName);
- Reset(F, 1);
- I := IoResult;
-
- {check for invalid pathname}
- if I = 3 then
- ReadMemoFile := mstInvalidName;
-
- if I <> 0 then
- Exit;
-
- {check the file size}
- FSize := FileSize(F);
- MaxSize := LongInt(BufferSize)-Succ(SafetyMargin);
- if (FSize <= MaxSize) then
- BytesToRead := FSize
- else if AllowTruncation then
- BytesToRead := MaxSize
- else begin
- {file too big}
- ReadMemoFile := mstTooLarge;
- Close(F);
- I := IoResult;
- Exit;
- end;
-
- {read the file into the buffer}
- BlockRead(F, Buf, BytesToRead, BytesRead);
- if (BytesRead <> BytesToRead) then begin
- ReadMemoFile := mstReadError;
- Close(F);
- I := IoResult;
- end
- else begin
- Close(F);
- if IoResult = 0 then
- if FSize > MaxSize then
- ReadMemoFile := mstTruncated
- else
- ReadMemoFile := mstOK
- else
- ReadMemoFile := mstCloseError;
- end;
-
- {make sure there's a ^Z at the end of the buffer}
- Buf[FSize+1] := ^Z;
- end;
-
- function SaveMemoFile(var EMCB : EMcontrolBlock; FName : string;
- MakeBackup : Boolean) : MemoStatusType;
- {-Save the current file in the text buffer associated with EMCB}
- var
- F : file;
- I, BytesWritten : Word;
-
- function Exist(FName : string; var F : file) : Boolean;
- {-Return true and assigned file handle if file exists}
- var
- I : Word;
- begin
- Assign(F, FName);
- Reset(F);
- Exist := (IoResult = 0);
- Close(F);
- I := IoResult;
- end;
-
- procedure MakeBakFile(NewName : string);
- {-Make a backup file}
- var
- NF, BF : file;
- BakName : string;
- begin
- if Exist(NewName, NF) then begin
- BakName := ForceExtension(NewName, 'BAK');
- if Exist(BakName, BF) then
- Erase(BF);
- Rename(NF, BakName);
- end;
- end;
-
- begin
- with EMCB do begin
- if MakeBackup then
- MakeBakFile(FName);
-
- Assign(F, FName);
- Rewrite(F, 1);
- if IoResult <> 0 then begin
- SaveMemoFile := mstCreationError;
- Close(F);
- I := IoResult;
- Exit;
- end;
-
- BlockWrite(F, BufPtr^, TotalBytes, BytesWritten);
- if (BytesWritten <> TotalBytes) or (IoResult <> 0) then begin
- SaveMemoFile := mstWriteError;
- Close(F);
- Exit;
- end;
-
- Close(F);
- if IoResult <> 0 then begin
- SaveMemoFile := mstCloseError;
- Exit;
- end;
-
- {reset modified flag}
- Modified := False;
-
- SaveMemoFile := mstOK;
- end;
- end;
-
- begin
- {initialize pointer to keyboard input routine}
- MemoKeyPtr := @ReadKeyWord;
- end.