Browse Source

* more files

peter 24 years ago
parent
commit
569a1dde72
8 changed files with 9096 additions and 0 deletions
  1. 432 0
      fv/callspec.pas
  2. 3733 0
      fv/editors.pas
  3. 189 0
      fv/str.inc
  4. 194 0
      fv/strtxt.inc
  5. 432 0
      fvision/callspec.pas
  6. 3733 0
      fvision/editors.pas
  7. 189 0
      fvision/str.inc
  8. 194 0
      fvision/strtxt.inc

+ 432 - 0
fv/callspec.pas

@@ -0,0 +1,432 @@
+{
+   $Id$
+
+   This unit provides compiler-independent mechanisms to call special
+   functions, i.e. local functions/procedures, constructors, methods,
+   destructors, etc. As there are no procedural variables for these
+   special functions, there is no Pascal way to call them directly.
+
+   Copyright (c) 1997 Matthias K"oppe <[email protected]>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************}
+unit CallSpec;
+
+{
+  As of this version, the following compilers are supported. Please
+  port CallSpec to other compilers (including earlier versions) and
+  send your code to the above address.
+
+  Compiler                    Comments
+  --------------------------- -------------------------------------
+  Turbo Pascal 6.0
+  Borland/Turbo Pascal 7.0
+  FPC Pascal 0.99.8
+}
+
+interface
+
+{$i platform.inc}
+
+{
+  The frame pointer points to the local variables of a procedure.
+  Use CurrentFramePointer to address the locals of the current procedure;
+  use PreviousFramePointer to addess the locals of the calling procedure.
+}
+type
+{$ifdef BIT_16}
+   FramePointer = Word;
+{$endif}
+{$ifdef BIT_32}
+   FramePointer = pointer;
+{$endif}
+
+function CurrentFramePointer: FramePointer;
+function PreviousFramePointer: FramePointer;
+
+{ This version of CallSpec supports four classes of special functions.
+  (Please write if you need other classes.)
+  For each, two types of argument lists are allowed:
+
+  `Void' indicates special functions with no explicit arguments.
+    Sample: constructor T.Init;
+  `Pointer' indicates special functions with one explicit pointer argument.
+    Sample: constructor T.Load(var S: TStream);
+}
+
+{ Constructor calls.
+
+  Ctor     Pointer to the constructor.
+  Obj      Pointer to the instance. NIL if new instance to be allocated.
+  VMT      Pointer to the VMT (obtained by TypeOf()).
+  returns  Pointer to the instance.
+}
+function CallVoidConstructor(Ctor: pointer; Obj: pointer; VMT: pointer): pointer;
+function CallPointerConstructor(Ctor: pointer; Obj: pointer; VMT: pointer; Param1: pointer): pointer;
+
+{ Method calls.
+
+  Method   Pointer to the method.
+  Obj      Pointer to the instance. NIL if new instance to be allocated.
+  returns  Pointer to the instance.
+}
+function CallVoidMethod(Method: pointer; Obj: pointer): pointer;
+function CallPointerMethod(Method: pointer; Obj: pointer; Param1: pointer): pointer;
+
+{ Local-function/procedure calls.
+
+  Func     Pointer to the local function (which must be far-coded).
+  Frame    Frame pointer of the wrapping function.
+}
+
+function CallVoidLocal(Func: pointer; Frame: FramePointer): pointer;
+function CallPointerLocal(Func: pointer; Frame: FramePointer; Param1: pointer): pointer;
+
+{ Calls of functions/procedures local to methods.
+
+  Func     Pointer to the local function (which must be far-coded).
+  Frame    Frame pointer of the wrapping method.
+  Obj      Pointer to the object that the method belongs to.
+}
+function CallVoidMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer): pointer;
+function CallPointerMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer; Param1: pointer): pointer;
+
+
+implementation
+
+{$ifdef PPC_FPC}
+
+{$ifdef CPUI386}
+{$ASMMODE ATT}
+{$endif CPUI386}
+
+{ This indicates an FPC version which uses the same call scheme for
+  method-local and procedure-local procedures, but which expects the
+  ESI register be loaded with the Self pointer in method-local procs. }
+
+type
+  VoidLocal = function(_EBP: FramePointer): pointer;
+  PointerLocal = function(_EBP: FramePointer; Param1: pointer): pointer;
+  VoidMethodLocal = function(_EBP: FRAMEPOINTER): pointer;
+  PointerMethodLocal = function(_EBP: FRAMEPOINTER; Param1: pointer): pointer;
+  VoidConstructor = function(VMT: pointer; Obj: pointer): pointer;
+  PointerConstructor = function(VMT: pointer; Obj: pointer; Param1: pointer): pointer;
+  VoidMethod = function(Obj: pointer): pointer;
+  PointerMethod = function(Obj: pointer; Param1: pointer): pointer;
+
+
+function CallVoidConstructor(Ctor: pointer; Obj: pointer; VMT: pointer): pointer;
+begin
+  { load the object pointer }
+{$ifdef CPUI386}
+  asm
+        movl Obj, %esi
+  end;
+{$endif CPUI386}
+{$ifdef CPU68K}
+  asm
+        move.l Obj, a5
+  end;
+{$endif CPU68K}
+
+  CallVoidConstructor := VoidConstructor(Ctor)(VMT, Obj)
+end;
+
+
+function CallPointerConstructor(Ctor: pointer; Obj: pointer; VMT: pointer; Param1: pointer): pointer;
+begin
+  { load the object pointer }
+{$ifdef CPUI386}
+  asm
+        movl Obj, %esi
+  end;
+{$endif CPUI386}
+{$ifdef CPU68K}
+  asm
+        move.l Obj, a5
+  end;
+{$endif CPU68K}
+  CallPointerConstructor := PointerConstructor(Ctor)(VMT, Obj, Param1)
+end;
+
+
+function CallVoidMethod(Method: pointer; Obj: pointer): pointer;
+begin
+  { load the object pointer }
+{$ifdef CPUI386}
+  asm
+        movl Obj, %esi
+  end;
+{$endif CPUI386}
+{$ifdef CPU68K}
+  asm
+        move.l Obj, a5
+  end;
+{$endif CPU68K}
+  CallVoidMethod := VoidMethod(Method)(Obj)
+end;
+
+
+function CallPointerMethod(Method: pointer; Obj: pointer; Param1: pointer): pointer;
+begin
+  { load the object pointer }
+{$ifdef CPUI386}
+  asm
+        movl Obj, %esi
+  end;
+{$endif CPUI386}
+{$ifdef CPU68K}
+  asm
+        move.l Obj, a5
+  end;
+{$endif CPU68K}
+  CallPointerMethod := PointerMethod(Method)(Obj, Param1)
+end;
+
+
+function CallVoidLocal(Func: pointer; Frame: FramePointer): pointer;
+begin
+  CallVoidLocal := VoidLocal(Func)(Frame)
+end;
+
+
+function CallPointerLocal(Func: pointer; Frame: FramePointer; Param1: pointer): pointer;
+begin
+  CallPointerLocal := PointerLocal(Func)(Frame, Param1)
+end;
+
+
+function CallVoidMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer): pointer;
+begin
+  { load the object pointer }
+{$ifdef CPUI386}
+  asm
+        movl Obj, %esi
+  end;
+{$endif CPUI386}
+{$ifdef CPU68K}
+  asm
+        move.l Obj, a5
+  end;
+{$endif CPU68K}
+  CallVoidMethodLocal := VoidMethodLocal(Func)(Frame)
+end;
+
+
+function CallPointerMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer; Param1: pointer): pointer;
+begin
+  { load the object pointer }
+{$ifdef CPUI386}
+  asm
+        movl Obj, %esi
+  end;
+{$endif CPUI386}
+{$ifdef CPU68K}
+  asm
+        move.l Obj, a5
+  end;
+{$endif CPU68K}
+  CallPointerMethodLocal := PointerMethodLocal(Func)(Frame, Param1)
+end;
+
+
+function CurrentFramePointer: FramePointer;assembler;
+{$ifdef CPUI386}
+asm
+    movl %ebp,%eax
+end ['EAX'];
+{$endif CPUI386}
+{$ifdef CPU68K}
+asm
+    move.l a6, d0
+end['D0'];
+{$endif CPU68K}
+
+
+function PreviousFramePointer: FramePointer;assembler;
+{$ifdef CPUI386}
+asm
+    movl (%ebp),%eax
+end ['EAX'];
+{$endif CPUI386}
+{$ifdef CPU68K}
+asm
+    move.l (a6), d0
+end['D0'];
+{$endif CPU68K}
+
+{$endif PPC_FPC}
+
+
+{$ifdef PPC_BP}
+type
+  VoidConstructor = function(VmtOfs: Word; Obj: pointer): pointer;
+  PointerConstructor = function(Param1: pointer; VmtOfs: Word; Obj: pointer): pointer;
+  VoidMethod = function(Obj: pointer): pointer;
+  PointerMethod = function(Param1: pointer; Obj: pointer): pointer;
+
+function CallVoidConstructor(Ctor: pointer; Obj: pointer; VMT: pointer): pointer;
+begin
+  CallVoidConstructor := VoidConstructor(Ctor)(Ofs(VMT^), Obj)
+end;
+
+
+function CallPointerConstructor(Ctor: pointer; Obj: pointer; VMT: pointer; Param1: pointer): pointer;
+begin
+  CallPointerConstructor := PointerConstructor(Ctor)(Param1, Ofs(VMT^), Obj)
+end;
+
+
+function CallVoidMethod(Method: pointer; Obj: pointer): pointer;
+begin
+  CallVoidMethod := VoidMethod(Method)(Obj)
+end;
+
+
+function CallPointerMethod(Method: pointer; Obj: pointer; Param1: pointer): pointer;
+begin
+  CallPointerMethod := PointerMethod(Method)(Param1, Obj)
+end;
+
+
+function CallVoidLocal(Func: pointer; Frame: FramePointer): pointer; assembler;
+asm
+{$IFDEF Windows}
+        MOV     AX,[Frame]
+        AND     AL,0FEH
+        PUSH    AX
+{$ELSE}
+        push    [Frame]
+{$ENDIF}
+        call    dword ptr Func
+end;
+
+
+function CallPointerLocal(Func: pointer; Frame: FramePointer; Param1: pointer): pointer; assembler;
+asm
+        mov     ax, word ptr Param1
+        mov     dx, word ptr Param1+2
+        push    dx
+        push    ax
+{$IFDEF Windows}
+        MOV     AX,[Frame]
+        AND     AL,0FEH
+        PUSH    AX
+{$ELSE}
+        push    [Frame]
+{$ENDIF}
+        call    dword ptr Func
+end;
+
+
+function CallVoidMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer): pointer; assembler;
+asm
+{$IFDEF Windows}
+        MOV     AX,[Frame]
+        AND     AL,0FEH
+        PUSH    AX
+{$ELSE}
+        push    [Frame]
+{$ENDIF}
+        call    dword ptr Func
+end;
+
+
+function CallPointerMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer; Param1: pointer): pointer; assembler;
+asm
+        mov     ax, word ptr Param1
+        mov     dx, word ptr Param1+2
+        push    dx
+        push    ax
+{$IFDEF Windows}
+        MOV     AX,[Frame]
+        AND     AL,0FEH
+        PUSH    AX
+{$ELSE}
+        push    [Frame]
+{$ENDIF}
+        call    dword ptr Func
+end;
+
+
+function CurrentFramePointer: FramePointer; assembler;
+asm
+        mov     ax, bp
+end;
+
+
+function PreviousFramePointer: FramePointer; assembler;
+asm
+        mov     ax, ss:[bp]
+end;
+
+{$endif PPC_BP}
+
+
+end.
+{
+  $Log$
+  Revision 1.1  2001-08-05 02:10:26  peter
+    * more files
+
+  Revision 1.3  2001/07/30 08:27:58  pierre
+   * fix I386 compilation problem
+
+  Revision 1.2  2001/07/29 20:23:18  pierre
+   * support for m68k cpu
+
+  Revision 1.1  2001/01/29 21:56:04  peter
+    * updates for new fpcmake
+
+  Revision 1.1  2001/01/29 11:31:26  marco
+   * added from API. callspec renamed to .pp
+
+  Revision 1.1  2000/07/13 06:29:38  michael
+  + Initial import
+
+  Revision 1.1  2000/01/06 01:20:30  peter
+    * moved out of packages/ back to topdir
+
+  Revision 1.1  1999/12/23 19:36:47  peter
+    * place unitfiles in target dirs
+
+  Revision 1.1  1999/11/24 23:36:37  peter
+    * moved to packages dir
+
+  Revision 1.2  1998/12/16 21:57:16  peter
+    * fixed currentframe,previousframe
+    + testcall to test the callspec unit
+
+  Revision 1.1  1998/12/04 12:48:24  peter
+    * moved some dirs
+
+  Revision 1.5  1998/12/04 09:53:44  peter
+    * removed objtemp global var
+
+  Revision 1.4  1998/11/24 17:14:24  peter
+    * fixed esi loading
+
+
+  Date       Version  Who     Comments
+  ---------- -------- ------- -------------------------------------
+  19-Sep-97  0.1      mkoeppe Initial version.
+  22-Sep-97  0.11     fk      0.9.3 support added, self isn't expected
+                              on the stack in local procedures of methods
+  23-Sep-97  0.12     mkoeppe Cleaned up 0.9.3 conditionals.
+  03-Oct-97  0.13     mkoeppe Fixed esi load in FPC 0.9
+  22-Oct-98  0.14     pfv     0.99.8 support for FPC
+}

+ 3733 - 0
fv/editors.pas

@@ -0,0 +1,3733 @@
+unit Editors;
+
+{$i platform.inc}
+
+{$ifdef PPC_FPC}
+  {$H-}
+{$else}
+  {$F+,O+,E+,N+}
+{$endif}
+{$X+,R-,I-,Q-,V-}
+{$ifndef OS_LINUX}
+  {$S-}
+{$endif}
+
+
+{$define UNIXLF}
+
+interface
+
+uses
+  Objects, Drivers,Views,Dialogs,FVCommon,FVConsts;
+
+const
+  { Length constants. }
+  Tab_Stop_Length = 74;
+
+{$ifdef PPC_BP}
+  MaxLineLength  = 1024;
+  MinBufLength   = $1000;
+  MaxBufLength   = $ff00;
+  NotFoundValue  = $ffff;
+  LineInfoGrow   = 256;
+  MaxLines       = 16000;
+{$else}
+  MaxLineLength  = 4096;
+  MinBufLength   = $1000;
+  MaxBufLength   = $7fffff00;
+  NotFoundValue  = $ffffffff;
+  LineInfoGrow   = 1024;
+  MaxLines       = $7ffffff;
+{$endif}
+
+
+  { Editor constants for dialog boxes. }
+  edOutOfMemory   = 0;
+  edReadError     = 1;
+  edWriteError    = 2;
+  edCreateError   = 3;
+  edSaveModify    = 4;
+  edSaveUntitled  = 5;
+  edSaveAs        = 6;
+  edFind          = 7;
+  edSearchFailed  = 8;
+  edReplace       = 9;
+  edReplacePrompt = 10;
+
+  edJumpToLine         = 11;
+  edPasteNotPossible   = 12;
+  edReformatDocument   = 13;
+  edReformatNotAllowed = 14;
+  edReformNotPossible  = 15;
+  edReplaceNotPossible = 16;
+  edRightMargin        = 17;
+  edSetTabStops        = 18;
+  edWrapNotPossible    = 19;
+
+  { Editor flag constants for dialog options. }
+  efCaseSensitive   = $0001;
+  efWholeWordsOnly  = $0002;
+  efPromptOnReplace = $0004;
+  efReplaceAll      = $0008;
+  efDoReplace       = $0010;
+  efBackupFiles     = $0100;
+
+  { Constants for object palettes. }
+  CIndicator = #2#3;
+  CEditor    = #6#7;
+  CMemo      = #26#27;
+
+type
+  TEditorDialog = function (Dialog : Integer; Info : Pointer) : Word;
+
+  PIndicator = ^TIndicator;
+  TIndicator = object (TView)
+    Location   : Objects.TPoint;
+    Modified   : Boolean;
+    AutoIndent : Boolean;          { Added boolean for AutoIndent mode. }
+    WordWrap   : Boolean;          { Added boolean for WordWrap mode.   }
+    constructor Init (var Bounds : TRect);
+    procedure   Draw; virtual;
+    function    GetPalette : PPalette; virtual;
+    procedure   SetState (AState : Word; Enable : Boolean); virtual;
+    procedure   SetValue (ALocation : Objects.TPoint; IsAutoIndent : Boolean;
+                                                      IsModified   : Boolean;
+                                                      IsWordWrap   : Boolean);
+  end;
+
+  TLineInfoRec = record
+    Len,Attr : Sw_word;
+  end;
+  TLineInfoArr = array[0..MaxLines] of TLineInfoRec;
+  PLineInfoArr = ^TLineInfoArr;
+
+  PLineInfo = ^TLineInfo;
+  TLineInfo = object
+    Info : PLineInfoArr;
+    MaxPos : Sw_Word;
+    constructor Init;
+    destructor Done;
+    procedure Grow(pos:Sw_word);
+    procedure SetLen(pos,val:Sw_Word);
+    procedure SetAttr(pos,val:Sw_Word);
+    function  GetLen(pos:Sw_Word):Sw_Word;
+    function  GetAttr(pos:Sw_Word):Sw_Word;
+  end;
+
+
+  PEditBuffer = ^TEditBuffer;
+  TEditBuffer = array[0..MaxBufLength] of Char;
+
+  PEditor = ^TEditor;
+  TEditor = object (TView)
+    HScrollBar         : PScrollBar;
+    VScrollBar         : PScrollBar;
+    Indicator          : PIndicator;
+    Buffer             : PEditBuffer;
+    BufSize            : Sw_Word;
+    BufLen             : Sw_Word;
+    GapLen             : Sw_Word;
+    SelStart           : Sw_Word;
+    SelEnd             : Sw_Word;
+    CurPtr             : Sw_Word;
+    CurPos             : Objects.TPoint;
+    Delta              : Objects.TPoint;
+    Limit              : Objects.TPoint;
+    DrawLine           : Sw_Integer;
+    DrawPtr            : Sw_Word;
+    DelCount           : Sw_Word;
+    InsCount           : Sw_Word;
+    Flags              : Longint;
+    IsReadOnly         : Boolean;
+    IsValid            : Boolean;
+    CanUndo            : Boolean;
+    Modified           : Boolean;
+    Selecting          : Boolean;
+    Overwrite          : Boolean;
+    AutoIndent         : Boolean;
+    NoSelect           : Boolean;
+    TabSize            : Sw_Word; { tabsize for displaying }
+    BlankLine          : Sw_Word; { First blank line after a paragraph. }
+    Word_Wrap          : Boolean; { Added boolean to toggle wordwrap on/off. }
+    Line_Number        : string[8]; { Holds line number to jump to. }
+    Right_Margin       : Sw_Integer; { Added integer to set right margin. }
+    Tab_Settings       : String[Tab_Stop_Length]; { Added string to hold tab stops. }
+
+    constructor Init (var Bounds : TRect; AHScrollBar, AVScrollBar : PScrollBar;
+                          AIndicator : PIndicator; ABufSize : Sw_Word);
+    constructor Load (var S : Objects.TStream);
+    destructor Done; virtual;
+    function   BufChar (P : Sw_Word) : Char;
+    function   BufPtr (P : Sw_Word) : Sw_Word;
+    procedure  ChangeBounds (var Bounds : TRect); virtual;
+    procedure  ConvertEvent (var Event : Drivers.TEvent); virtual;
+    function   CursorVisible : Boolean;
+    procedure  DeleteSelect;
+    procedure  DoneBuffer; virtual;
+    procedure  Draw; virtual;
+    procedure  FormatLine (var DrawBuf; LinePtr : Sw_Word; Width : Sw_Integer; Colors : Word);virtual;
+    function   GetPalette : PPalette; virtual;
+    procedure  HandleEvent (var Event : Drivers.TEvent); virtual;
+    procedure  InitBuffer; virtual;
+    function   InsertBuffer (var P : PEditBuffer; Offset, Length : Sw_Word;AllowUndo, SelectText : Boolean) : Boolean;
+    function   InsertFrom (Editor : PEditor) : Boolean; virtual;
+    function   InsertText (Text : Pointer; Length : Sw_Word; SelectText : Boolean) : Boolean;
+    procedure  ScrollTo (X, Y : Sw_Integer);
+    function   Search (const FindStr : String; Opts : Word) : Boolean;
+    function   SetBufSize (NewSize : Sw_Word) : Boolean; virtual;
+    procedure  SetCmdState (Command : Word; Enable : Boolean);
+    procedure  SetSelect (NewStart, NewEnd : Sw_Word; CurStart : Boolean);
+    procedure  SetCurPtr (P : Sw_Word; SelectMode : Byte);
+    procedure  SetState (AState : Word; Enable : Boolean); virtual;
+    procedure  Store (var S : Objects.TStream);
+    procedure  TrackCursor (Center : Boolean);
+    procedure  Undo;
+    procedure  UpdateCommands; virtual;
+    function   Valid (Command : Word) : Boolean; virtual;
+
+  private
+    KeyState       : Integer;
+    LockCount      : Byte;
+    UpdateFlags    : Byte;
+    Place_Marker   : Array [1..10] of Sw_Word; { Inserted array to hold place markers. }
+    Search_Replace : Boolean; { Added boolean to test for Search and Replace insertions. }
+
+    procedure  Center_Text (Select_Mode : Byte);
+    function   CharPos (P, Target : Sw_Word) : Sw_Integer;
+    function   CharPtr (P : Sw_Word; Target : Sw_Integer) : Sw_Word;
+    procedure  Check_For_Word_Wrap (Select_Mode : Byte; Center_Cursor : Boolean);
+    function   ClipCopy : Boolean;
+    procedure  ClipCut;
+    procedure  ClipPaste;
+    procedure  DeleteRange (StartPtr, EndPtr : Sw_Word; DelSelect : Boolean);
+    procedure  DoSearchReplace;
+    procedure  DoUpdate;
+    function   Do_Word_Wrap (Select_Mode : Byte; Center_Cursor : Boolean) : Boolean;
+    procedure  DrawLines (Y, Count : Sw_Integer; LinePtr : Sw_Word);
+    procedure  Find;
+    function   GetMousePtr (Mouse : Objects.TPoint) : Sw_Word;
+    function   HasSelection : Boolean;
+    procedure  HideSelect;
+    procedure  Insert_Line (Select_Mode : Byte);
+    function   IsClipboard : Boolean;
+    procedure  Jump_Place_Marker (Element : Byte; Select_Mode : Byte);
+    procedure  Jump_To_Line  (Select_Mode : Byte);
+    function   LineEnd (P : Sw_Word) : Sw_Word;
+    function   LineMove (P : Sw_Word; Count : Sw_Integer) : Sw_Word;
+    function   LineStart (P : Sw_Word) : Sw_Word;
+    function   LineNr (P : Sw_Word) : Sw_Word;
+    procedure  Lock;
+    function   NewLine (Select_Mode : Byte) : Boolean;
+    function   NextChar (P : Sw_Word) : Sw_Word;
+    function   NextLine (P : Sw_Word) : Sw_Word;
+    function   NextWord (P : Sw_Word) : Sw_Word;
+    function   PrevChar (P : Sw_Word) : Sw_Word;
+    function   PrevLine (P : Sw_Word) : Sw_Word;
+    function   PrevWord (P : Sw_Word) : Sw_Word;
+    procedure  Reformat_Document (Select_Mode : Byte; Center_Cursor : Boolean);
+    function   Reformat_Paragraph (Select_Mode : Byte; Center_Cursor : Boolean) : Boolean;
+    procedure  Remove_EOL_Spaces (Select_Mode : Byte);
+    procedure  Replace;
+    procedure  Scroll_Down;
+    procedure  Scroll_Up;
+    procedure  Select_Word;
+    procedure  SetBufLen (Length : Sw_Word);
+    procedure  Set_Place_Marker (Element : Byte);
+    procedure  Set_Right_Margin;
+    procedure  Set_Tabs;
+    procedure  StartSelect;
+    procedure  Tab_Key (Select_Mode : Byte);
+    procedure  ToggleInsMode;
+    procedure  Unlock;
+    procedure  Update (AFlags : Byte);
+    procedure  Update_Place_Markers (AddCount : Word; KillCount : Word; StartPtr,EndPtr : Sw_Word);
+  end;
+
+  TMemoData = record
+    Length : Sw_Word;
+    Buffer : TEditBuffer;
+  end;
+
+  PMemo = ^TMemo;
+  TMemo = object (TEditor)
+    constructor Load (var S : Objects.TStream);
+    function    DataSize : Sw_Word; virtual;
+    procedure   GetData (var Rec); virtual;
+    function    GetPalette : PPalette; virtual;
+    procedure   HandleEvent (var Event : Drivers.TEvent); virtual;
+    procedure   SetData (var Rec); virtual;
+    procedure   Store (var S : Objects.TStream);
+  end;
+
+  PFileEditor = ^TFileEditor;
+  TFileEditor = object (TEditor)
+    FileName : FNameStr;
+    constructor Init (var Bounds : TRect; AHScrollBar, AVScrollBar : PScrollBar;
+                          AIndicator : PIndicator; AFileName : FNameStr);
+    constructor Load (var S : Objects.TStream);
+    procedure   DoneBuffer; virtual;
+    procedure   HandleEvent (var Event : Drivers.TEvent); virtual;
+    procedure   InitBuffer; virtual;
+    function    LoadFile : Boolean;
+    function    Save : Boolean;
+    function    SaveAs : Boolean;
+    function    SaveFile : Boolean;
+    function    SetBufSize (NewSize : Sw_Word) : Boolean; virtual;
+    procedure   Store (var S : Objects.TStream);
+    procedure   UpdateCommands; virtual;
+    function    Valid (Command : Word) : Boolean; virtual;
+  end;
+
+  PEditWindow = ^TEditWindow;
+  TEditWindow = object (TWindow)
+    Editor : PFileEditor;
+    constructor Init (var Bounds : TRect; FileName : FNameStr; ANumber : Integer);
+    constructor Load (var S : Objects.TStream);
+    procedure   Close; virtual;
+    function    GetTitle (MaxSize : Sw_Integer) : TTitleStr; virtual;
+    procedure   HandleEvent (var Event : Drivers.TEvent); virtual;
+    procedure   SizeLimits(var Min, Max: TPoint); virtual;
+    procedure   Store (var S : Objects.TStream);
+  end;
+
+
+function DefEditorDialog (Dialog : Integer; Info : Pointer) : Word;
+function CreateFindDialog: PDialog;
+function CreateReplaceDialog: PDialog;
+function JumpLineDialog : PDialog;
+function ReformDocDialog : PDialog;
+function RightMarginDialog : PDialog;
+function TabStopDialog : Dialogs.PDialog;
+function StdEditorDialog(Dialog: Integer; Info: Pointer): Word;
+
+const
+  WordChars    : set of Char = ['!'..#255];
+
+  LineBreak    : string[2]=
+{$ifdef UNIXLF}
+    #10;
+{$else}
+    #13#10;
+{$endif}
+
+
+  { The Allow_Reformat boolean is a programmer hook.  }
+  { I've placed this here to allow programmers to     }
+  { determine whether or not paragraph and document   }
+  { reformatting are allowed if Word_Wrap is not      }
+  { active.  Some people say don't allow, and others  }
+  { say allow it.  I've left it up to the programmer. }
+  { Set to FALSE if not allowed, or TRUE if allowed.  }
+  Allow_Reformat : Boolean = True;
+
+  EditorDialog   : TEditorDialog = {$ifdef fpc}@{$endif}DefEditorDialog;
+  EditorFlags    : Word = efBackupFiles + efPromptOnReplace;
+  FindStr        : String[80] = '';
+  ReplaceStr     : String[80] = '';
+  Clipboard      : PEditor = nil;
+
+  ToClipCmds     : TCommandSet = ([cmCut,cmCopy,cmClear]);
+  FromClipCmds   : TCommandSet = ([cmPaste]);
+  UndoCmds       : TCommandSet = ([cmUndo,cmRedo]);
+
+TYPE
+  TFindDialogRec = packed record
+    Find    : String[80];
+    Options : Word;
+  end;
+
+  TReplaceDialogRec = packed record
+       Find : String[80];
+    Replace : String[80];
+    Options : Word;
+  end;
+
+  TRightMarginRec = packed record
+    Margin_Position : String[3];
+  end;
+
+  TTabStopRec = packed record
+    Tab_String : String [Tab_Stop_Length];
+  end;
+
+CONST
+  { VMT constants. }
+  REditor   : TStreamRec = (ObjType : 70;
+                            VmtLink : Ofs (TypeOf (TEditor)^);
+                               Load : @TEditor.Load;
+                              Store : @TEditor.Store);
+
+  RMemo     : TStreamRec = (ObjType : 71;
+                            VmtLink : Ofs (TypeOf (TMemo)^);
+                               Load : @TMemo.Load;
+                              Store : @TMemo.Store);
+
+  RFileEditor : TStreamRec = (ObjType : 72;
+                              VmtLink : Ofs (TypeOf (TFileEditor)^);
+                                 Load : @TFileEditor.Load;
+                                Store : @TFileEditor.Store);
+
+  RIndicator : TStreamRec = (ObjType : 73;
+                             VmtLink : Ofs (TypeOf (TIndicator)^);
+                                Load : @TIndicator.Load;
+                               Store : @TIndicator.Store);
+
+  REditWindow : TStreamRec = (ObjType : 74;
+                              VmtLink : Ofs (TypeOf (TEditWindow)^);
+                                 Load : @TEditWindow.Load;
+                                Store : @TEditWindow.Store);
+
+procedure RegisterEditors;
+
+
+{****************************************************************************
+                              Implementation
+****************************************************************************}
+
+implementation
+
+uses
+  Memory, Dos, App, StdDlg, MsgBox, Resource;
+
+type
+  pword = ^word;
+
+CONST
+  { Update flag constants. }
+  ufUpdate = $01;
+  ufLine   = $02;
+  ufView   = $04;
+  ufStats  = $05;
+
+  { SelectMode constants. }
+  smExtend = $01;
+  smDouble = $02;
+
+  sfSearchFailed = NotFoundValue;
+
+  { Arrays that hold all the command keys and options. }
+  FirstKeys : array[0..46 * 2] of Word = (46, Ord (^A),    cmWordLeft,
+                                              Ord (^B),    cmReformPara,
+                                              Ord (^C),    cmPageDown,
+                                              Ord (^D),    cmCharRight,
+                                              Ord (^E),    cmLineUp,
+                                              Ord (^F),    cmWordRight,
+                                              Ord (^G),    cmDelChar,
+                                              Ord (^H),    cmBackSpace,
+                                              Ord (^I),    cmTabKey,
+                                              Ord (^J),    $FF04,
+                                              Ord (^K),    $FF02,
+                                              Ord (^L),    cmSearchAgain,
+                                              Ord (^M),    cmNewLine,
+                                              Ord (^N),    cmInsertLine,
+                                              Ord (^O),    $FF03,
+                                              Ord (^Q),    $FF01,
+                                              Ord (^R),    cmPageUp,
+                                              Ord (^S),    cmCharLeft,
+                                              Ord (^T),    cmDelWord,
+                                              Ord (^U),    cmUndo,
+                                              Ord (^V),    cmInsMode,
+                                              Ord (^W),    cmScrollUp,
+                                              Ord (^X),    cmLineDown,
+                                              Ord (^Y),    cmDelLine,
+                                              Ord (^Z),    cmScrollDown,
+                                              kbLeft,      cmCharLeft,
+                                              kbRight,     cmCharRight,
+                                              kbCtrlLeft,  cmWordLeft,
+                                              kbCtrlRight, cmWordRight,
+                                              kbHome,      cmLineStart,
+                                              kbEnd,       cmLineEnd,
+                                              kbCtrlHome,  cmHomePage,
+                                              kbCtrlEnd,   cmEndPage,
+                                              kbUp,        cmLineUp,
+                                              kbDown,      cmLineDown,
+                                              kbPgUp,      cmPageUp,
+                                              kbPgDn,      cmPageDown,
+                                              kbCtrlPgUp,  cmTextStart,
+                                              kbCtrlPgDn,  cmTextEnd,
+                                              kbIns,       cmInsMode,
+                                              kbDel,       cmDelChar,
+                                              kbCtrlBack,  cmDelStart,
+                                              kbShiftIns,  cmPaste,
+                                              kbShiftDel,  cmCut,
+                                              kbCtrlIns,   cmCopy,
+                                              kbCtrlDel,   cmClear);
+
+  { SCRLUP - Stop. } { Added ^W to scroll screen up.         }
+  { SCRLDN - Stop. } { Added ^Z to scroll screen down.       }
+  { REFORM - Stop. } { Added ^B for paragraph reformatting.  }
+  { PRETAB - Stop. } { Added ^I for preset tabbing.          }
+  { JLINE  - Stop. } { Added ^J to jump to a line number.    }
+  { INSLIN - Stop. } { Added ^N to insert line at cursor.    }
+  { INDENT - Stop. } { Removed ^O and put it into ^QI.       }
+  { HOMEND - Stop. } { Added kbCtrlHome and kbCtrlEnd pages. }
+  { CTRLBK - Stop. } { Added kbCtrlBack same as ^QH.         }
+
+  QuickKeys : array[0..21 * 2] of Word = (21, Ord ('0'), cmJumpMark0,
+                                              Ord ('1'), cmJumpMark1,
+                                              Ord ('2'), cmJumpMark2,
+                                              Ord ('3'), cmJumpMark3,
+                                              Ord ('4'), cmJumpMark4,
+                                              Ord ('5'), cmJumpMark5,
+                                              Ord ('6'), cmJumpMark6,
+                                              Ord ('7'), cmJumpMark7,
+                                              Ord ('8'), cmJumpMark8,
+                                              Ord ('9'), cmJumpMark9,
+                                              Ord ('A'), cmReplace,
+                                              Ord ('C'), cmTextEnd,
+                                              Ord ('D'), cmLineEnd,
+                                              Ord ('F'), cmFind,
+                                              Ord ('H'), cmDelStart,
+                                              Ord ('I'), cmIndentMode,
+                                              Ord ('L'), cmUndo,
+                                              Ord ('R'), cmTextStart,
+                                              Ord ('S'), cmLineStart,
+                                              Ord ('U'), cmReformDoc,
+                                              Ord ('Y'), cmDelEnd);
+
+  { UNDO   - Stop. } { Added IDE undo feature of ^QL.                  }
+  { REFDOC - Stop. } { Added document reformat feature if ^QU pressed. }
+  { MARK   - Stop. } { Added cmJumpMark# to allow place marking.       }
+  { INDENT - Stop. } { Moved IndentMode here from Firstkeys.           }
+
+  BlockKeys : array[0..20 * 2] of Word = (20, Ord ('0'), cmSetMark0,
+                                              Ord ('1'), cmSetMark1,
+                                              Ord ('2'), cmSetMark2,
+                                              Ord ('3'), cmSetMark3,
+                                              Ord ('4'), cmSetMark4,
+                                              Ord ('5'), cmSetMark5,
+                                              Ord ('6'), cmSetMark6,
+                                              Ord ('7'), cmSetMark7,
+                                              Ord ('8'), cmSetMark8,
+                                              Ord ('9'), cmSetMark9,
+                                              Ord ('B'), cmStartSelect,
+                                              Ord ('C'), cmPaste,
+                                              Ord ('D'), cmSave,
+                                              Ord ('F'), cmSaveAs,
+                                              Ord ('H'), cmHideSelect,
+                                              Ord ('K'), cmCopy,
+                                              Ord ('S'), cmSave,
+                                              Ord ('T'), cmSelectWord,
+                                              Ord ('Y'), cmCut,
+                                              Ord ('X'), cmSaveDone);
+
+  { SELWRD - Stop. } { Added ^KT to select word only. }
+  { SAVE   - Stop. } { Added ^KD, ^KF, ^KS, ^KX key commands.   }
+  { MARK   - Stop. } { Added cmSetMark# to allow place marking. }
+
+  FormatKeys : array[0..5 * 2] of Word = (5,  Ord ('C'), cmCenterText,
+                                              Ord ('T'), cmCenterText,
+                                              Ord ('I'), cmSetTabs,
+                                              Ord ('R'), cmRightMargin,
+                                              Ord ('W'), cmWordWrap);
+
+  { WRAP   - Stop. } { Added Wordwrap feature if ^OW pressed.          }
+  { RMSET  - Stop. } { Added set right margin feature if ^OR pressed.  }
+  { PRETAB - Stop. } { Added preset tab feature if ^OI pressed.        }
+  { CENTER - Stop. } { Added center text option ^OC for a line.        }
+
+  JumpKeys : array[0..1 * 2] of Word = (1, Ord ('L'), cmJumpLine);
+
+  { JLINE - Stop. } { Added jump to line number feature if ^JL pressed. }
+
+  KeyMap : array[0..4] of Pointer = (@FirstKeys,
+                                     @QuickKeys,
+                                     @BlockKeys,
+                                     @FormatKeys,
+                                     @JumpKeys);
+
+  { WRAP   - Stop. } { Added @FormatKeys for new ^O? keys. }
+  { PRETAB - Stop. } { Added @FormatKeys for new ^O? keys. }
+  { JLINE  - Stop. } { Added @JumpKeys for new ^J? keys.   }
+  { CENTER - Stop. } { Added @FormatKeys for new ^O? keys. }
+
+
+{****************************************************************************
+                                 Dialogs
+****************************************************************************}
+
+function DefEditorDialog (Dialog : Integer; Info : Pointer) : Word;
+begin
+  DefEditorDialog := cmCancel;
+end; { DefEditorDialog }
+
+
+function CreateFindDialog: PDialog;
+var
+  D: PDialog;
+  Control: PView;
+  R: TRect;
+begin
+  R.Assign(0, 0, 38, 12);
+  D := New(PDialog, Init(R, strings^.get(sFind)));
+  with D^ do
+  begin
+    Options := Options or ofCentered;
+
+    R.Assign(3, 3, 32, 4);
+    Control := New(PInputLine, Init(R, 80));
+    Control^.HelpCtx := hcDFindText;
+    Insert(Control);
+    R.Assign(2, 2, 15, 3);
+    Insert(New(PLabel, Init(R, labels^.get(slTextToFind), Control)));
+    R.Assign(32, 3, 35, 4);
+    Insert(New(PHistory, Init(R, PInputLine(Control), 10)));
+
+    R.Assign(3, 5, 35, 7);
+    Control := New(PCheckBoxes, Init(R,
+        NewSItem (labels^.get(slCaseSensitive),
+        NewSItem (labels^.get(slWholeWordsOnly),nil))));
+    Control^.HelpCtx := hcCCaseSensitive;
+    Insert(Control);
+
+    R.Assign(14, 9, 24, 11);
+    Control := New (PButton, Init(R,labels^.get(slOK),cmOk,bfDefault));
+    Control^.HelpCtx := hcDOk;
+    Insert (Control);
+
+    Inc(R.A.X, 12); Inc(R.B.X, 12);
+    Control := New (PButton, Init(R,labels^.get(slCancel),cmCancel, bfNormal));
+    Control^.HelpCtx := hcDCancel;
+    Insert (Control);
+
+    SelectNext(False);
+  end;
+  CreateFindDialog := D;
+end;
+
+
+function CreateReplaceDialog: PDialog;
+var
+  D: PDialog;
+  Control: PView;
+  R: TRect;
+begin
+  R.Assign(0, 0, 40, 16);
+  D := New(PDialog, Init(R,labels^.get(slReplace)));
+  with D^ do
+  begin
+    Options := Options or ofCentered;
+
+    R.Assign(3, 3, 34, 4);
+    Control := New(PInputLine, Init(R, 80));
+    Control^.HelpCtx := hcDFindText;
+    Insert(Control);
+    R.Assign(2, 2, 15, 3);
+    Insert(New(PLabel, Init(R,labels^.get(slTextToFind), Control)));
+    R.Assign(34, 3, 37, 4);
+    Insert(New(PHistory, Init(R, PInputLine(Control), 10)));
+
+    R.Assign(3, 6, 34, 7);
+    Control := New(PInputLine, Init(R, 80));
+    Control^.HelpCtx := hcDReplaceText;
+    Insert(Control);
+    R.Assign(2, 5, 12, 6);
+    Insert(New(PLabel, Init(R,labels^.get(slNewText), Control)));
+    R.Assign(34, 6, 37, 7);
+    Insert(New(PHistory, Init(R, PInputLine(Control), 11)));
+
+    R.Assign(3, 8, 37, 12);
+    Control := New (Dialogs.PCheckBoxes, Init (R,
+      NewSItem (labels^.get(slCasesensitive),
+      NewSItem (labels^.get(slWholewordsonly),
+      NewSItem (labels^.get(slPromptonreplace),
+      NewSItem (labels^.get(slReplaceall), nil))))));
+    Control^.HelpCtx := hcCCaseSensitive;
+    Insert (Control);
+
+    R.Assign (8, 13, 18, 15);
+    Control := New (PButton, Init (R,labels^.get(slOK), cmOk, bfDefault));
+    Control^.HelpCtx := hcDOk;
+    Insert (Control);
+
+    R.Assign (22, 13, 32, 15);
+    Control := New (PButton, Init (R,labels^.get(slCancel), cmCancel, bfNormal));
+    Control^.HelpCtx := hcDCancel;
+    Insert (Control);
+
+    SelectNext(False);
+  end;
+  CreateReplaceDialog := D;
+end;
+
+
+function JumpLineDialog : PDialog;
+VAR
+  D      : PDialog;
+  R      : TRect;
+  Control: PView;
+Begin
+  R.Assign (0, 0, 26, 8);
+  D := New(PDialog, Init(R,strings^.get(sJumpTo)));
+  with D^ do
+    begin
+      Options := Options or ofCentered;
+
+      R.Assign (3, 2, 15, 3);
+      Control := New (Dialogs.PStaticText, Init (R,labels^.get(slLineNumber)));
+      Insert (Control);
+
+      R.Assign (15, 2, 21, 3);
+      Control := New (Dialogs.PInputLine, Init (R, 4));
+      Control^.HelpCtx := hcDLineNumber;
+      Insert (Control);
+
+      R.Assign (21, 2, 24, 3);
+      Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 12)));
+
+      R.Assign (2, 5, 12, 7);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault));
+      Control^.HelpCtx := hcDOk;
+      Insert (Control);
+
+      R.Assign (14, 5, 24, 7);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal));
+      Control^.HelpCtx := hcDCancel;
+      Insert (Control);
+
+      SelectNext (False);
+    end;
+  JumpLineDialog := D;
+end; { JumpLineDialog }
+
+
+function ReformDocDialog : Dialogs.PDialog;
+  { This is a local function that brings up a dialog box  }
+  { that asks where to start reformatting the document.   }
+VAR
+  R            : TRect;
+  D            : Dialogs.PDialog;
+  Control      : PView;
+Begin
+  R.Assign (0, 0, 32, 11);
+  D := New (Dialogs.PDialog, Init (R, strings^.get(sReformatDocument)));
+  with D^ do
+    begin
+      Options := Options or ofCentered;
+
+      R.Assign (2, 2, 30, 3);
+      Control := New (Dialogs.PStaticText, Init (R, strings^.get(sSelectWhereToBegin)));
+      Insert (Control);
+
+      R.Assign (3, 3, 29, 4);
+      Control := New (Dialogs.PStaticText, Init (R, strings^.get(sReformattingTheDocument)));
+      Insert (Control);
+
+      R.Assign (50, 5, 68, 6);
+      Control := New (Dialogs.PLabel, Init (R, strings^.get(sReformatDocument), Control));
+      Insert (Control);
+
+      R.Assign (5, 5, 26, 7);
+      Control := New (Dialogs.PRadioButtons, Init (R,
+        NewSItem (labels^.get(slCurrentLine),
+        NewSItem (labels^.get(slEntireDocument), Nil))));
+      Control^.HelpCtx := hcDReformDoc;
+      Insert (Control);
+
+      R.Assign (4, 8, 14, 10);
+      Control := New (Dialogs.PButton, Init (R,labels^.get(slOK), cmOK, Dialogs.bfDefault));
+      Control^.HelpCtx := hcDOk;
+      Insert (Control);
+
+      R.Assign (17, 8, 27, 10);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal));
+      Control^.HelpCtx := hcDCancel;
+      Insert (Control);
+
+      SelectNext (False);
+    end;
+    ReformDocDialog := D;
+end; { ReformDocDialog }
+
+
+function RightMarginDialog : Dialogs.PDialog;
+  { This is a local function that brings up a dialog box }
+  { that allows the user to change the Right_Margin.     }
+VAR
+  R        : TRect;
+  D        : PDialog;
+  Control  : PView;
+Begin
+  R.Assign (0, 0, 26, 8);
+  D := New (Dialogs.PDialog, Init (R, strings^.get(sRightMargin)));
+  with D^ do
+    begin
+      Options := Options or ofCentered;
+
+      R.Assign (5, 2, 13, 3);
+      Control := New (Dialogs.PStaticText, Init (R, strings^.get(sSetting)));
+      Insert (Control);
+
+      R.Assign (13, 2, 18, 3);
+      Control := New (Dialogs.PInputLine, Init (R, 3));
+      Control^.HelpCtx := hcDRightMargin;
+      Insert (Control);
+
+      R.Assign (18, 2, 21, 3);
+      Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 13)));
+
+      R.Assign (2, 5, 12, 7);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault));
+      Control^.HelpCtx := hcDOk;
+      Insert (Control);
+
+      R.Assign (14, 5, 24, 7);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal));
+      Control^.HelpCtx := hcDCancel;
+      Insert (Control);
+
+      SelectNext (False);
+    end;
+  RightMarginDialog := D;
+end; { RightMarginDialog; }
+
+
+function TabStopDialog : Dialogs.PDialog;
+  { This is a local function that brings up a dialog box }
+  { that allows the user to set their own tab stops.     }
+VAR
+  Index      : Sw_Integer;       { Local Indexing variable.                 }
+  R          : TRect;
+  D          : PDialog;
+  Control    : PView;
+  Tab_Stop   : String[2];        { Local string to print tab column number. }
+Begin
+  R.Assign (0, 0, 80, 8);
+  D := New (Dialogs.PDialog, Init (R, strings^.get(sTabSettings)));
+  with D^ do
+    begin
+      Options := Options or ofCentered;
+
+      R.Assign (2, 2, 77, 3);
+      Control := New (Dialogs.PStaticText, Init (R,
+                  ' ....|....|....|....|....|....|....|....|....|....|....|....|....|....|....'));
+      Insert (Control);
+
+      for Index := 1 to 7 do
+        begin
+          R.Assign (Index * 10 + 1, 1, Index * 10 + 3, 2);
+          Str (Index * 10, Tab_Stop);
+          Control := New (Dialogs.PStaticText, Init (R, Tab_Stop));
+          Insert (Control);
+        end;
+
+      R.Assign (2, 3, 78, 4);
+      Control := New (Dialogs.PInputLine, Init (R, 74));
+      Control^.HelpCtx := hcDTabStops;
+      Insert (Control);
+
+      R.Assign (38, 5, 41, 6);
+      Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 14)));
+
+      R.Assign (27, 5, 37, 7);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault));
+      Control^.HelpCtx := hcDOk;
+      Insert (Control);
+
+      R.Assign (42, 5, 52, 7);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal));
+      Control^.HelpCtx := hcDCancel;
+      Insert (Control);
+      SelectNext (False);
+    end;
+  TabStopDialog := D;
+end { TabStopDialog };
+
+
+function StdEditorDialog(Dialog: Integer; Info: Pointer): Word;
+var
+  R: TRect;
+  T: TPoint;
+begin
+  case Dialog of
+    edOutOfMemory:
+      StdEditorDialog := MessageBox(strings^.get(sOutOfMemory), nil, mfError + mfOkButton);
+    edReadError:
+      StdEditorDialog := MessageBox(strings^.get(sFileReadError), @Info, mfError + mfOkButton);
+    edWriteError:
+      StdEditorDialog := MessageBox(strings^.get(sFileWriteError), @Info, mfError + mfOkButton);
+    edCreateError:
+      StdEditorDialog := MessageBox(strings^.get(sFileCreateError), @Info, mfError + mfOkButton);
+    edSaveModify:
+      StdEditorDialog := MessageBox(strings^.get(sModified), @Info, mfInformation + mfYesNoCancel);
+    edSaveUntitled:
+      StdEditorDialog := MessageBox(strings^.get(sFileUntitled), nil, mfInformation + mfYesNoCancel);
+    edSaveAs:
+      StdEditorDialog := Application^.ExecuteDialog(New(PFileDialog, Init('*.*',
+        labels^.get(slSaveFileAs), labels^.get(slName), fdOkButton, 101)), Info);
+    edFind:
+      StdEditorDialog := Application^.ExecuteDialog(CreateFindDialog, Info);
+    edSearchFailed:
+      StdEditorDialog := MessageBox(strings^.get(sSearchStringNotFound), nil, mfError + mfOkButton);
+    edReplace:
+      StdEditorDialog := Application^.ExecuteDialog(CreateReplaceDialog, Info);
+    edReplacePrompt:
+      begin
+        { Avoid placing the dialog on the same line as the cursor }
+        R.Assign(0, 1, 40, 8);
+        R.Move((Desktop^.Size.X - R.B.X) div 2, 0);
+        Desktop^.MakeGlobal(R.B, T);
+        Inc(T.Y);
+        if PPoint(Info)^.Y <= T.Y then
+          R.Move(0, Desktop^.Size.Y - R.B.Y - 2);
+        StdEditorDialog := MessageBoxRect(R, strings^.get(sReplaceThisOccurence),
+          nil, mfYesNoCancel + mfInformation);
+      end;
+    edJumpToLine:
+      StdEditorDialog := Application^.ExecuteDialog(JumpLineDialog, Info);
+    edSetTabStops:
+      StdEditorDialog := Application^.ExecuteDialog(TabStopDialog, Info);
+    edPasteNotPossible:
+      StdEditorDialog := MessageBox (strings^.get(sPasteNotPossible), nil, mfError + mfOkButton);
+    edReformatDocument:
+      StdEditorDialog := Application^.ExecuteDialog(ReformDocDialog, Info);
+    edReformatNotAllowed:
+      StdEditorDialog := MessageBox (strings^.get(sWordWrapOff), nil, mfError + mfOkButton);
+    edReformNotPossible:
+      StdEditorDialog := MessageBox (strings^.get(sReformatNotPossible), nil, mfError + mfOkButton);
+    edReplaceNotPossible:
+      StdEditorDialog := MessageBox (strings^.get(sReplaceNotPossible), nil, mfError + mfOkButton);
+    edRightMargin:
+      StdEditorDialog := Application^.ExecuteDialog(RightMarginDialog, Info);
+    edWrapNotPossible:
+      StdEditorDialog := MessageBox (strings^.get(sWordWrapNotPossible), nil, mfError + mfOKButton);
+  else
+    StdEditorDialog := MessageBox (strings^.get(sUnknownDialog), nil, mfError + mfOkButton);
+  end;
+end;
+
+
+{****************************************************************************
+                                 Helpers
+****************************************************************************}
+
+function CountLines(var Buf; Count: sw_Word): sw_Integer;
+var
+  p : pchar;
+  lines : sw_word;
+begin
+  p:=pchar(@buf);
+  lines:=0;
+  while (count>0) do
+   begin
+     if p^ in [#10,#13] then
+      begin
+        inc(lines);
+        if ord((p+1)^)+ord(p^)=23 then
+         begin
+           inc(p);
+           dec(count);
+           if count=0 then
+            break;
+         end;
+      end;
+     inc(p);
+     dec(count);
+   end;
+  CountLines:=Lines;
+end;
+
+
+procedure GetLimits(var Buf; Count: sw_Word;var lim:objects.TPoint);
+{ Get the limits needed for Buf, its an extended version of countlines (lim.y),
+  which also gets the maximum line length in lim.x }
+var
+  p : pchar;
+  len : sw_word;
+begin
+  lim.x:=0;
+  lim.y:=0;
+  len:=0;
+  p:=pchar(@buf);
+  while (count>0) do
+   begin
+     if p^ in [#10,#13] then
+      begin
+        if len>lim.x then
+         lim.x:=len;
+        inc(lim.y);
+        if ord((p+1)^)+ord(p^)=23 then
+         begin
+           inc(p);
+           dec(count);
+         end;
+        len:=0;
+      end
+     else
+      inc(len);
+     inc(p);
+     dec(count);
+   end;
+end;
+
+
+function ScanKeyMap(KeyMap: Pointer; KeyCode: Word): Word;
+var
+  p : pword;
+  count : sw_word;
+begin
+  p:=keymap;
+  count:=p^;
+  inc(p);
+  while (count>0) do
+   begin
+     if (lo(p^)=lo(keycode)) and
+        ((hi(p^)=0) or (hi(p^)=hi(keycode))) then
+      begin
+        inc(p);
+        scankeymap:=p^;
+        exit;
+      end;
+     inc(p,2);
+     dec(count);
+   end;
+  scankeymap:=0;
+end;
+
+
+Type
+  Btable = Array[0..255] of Byte;
+Procedure BMMakeTable(const s:string; Var t : Btable);
+{ Makes a Boyer-Moore search table. s = the search String t = the table }
+Var
+  x : sw_integer;
+begin
+  FillChar(t,sizeof(t),length(s));
+  For x := length(s) downto 1 do
+   if (t[ord(s[x])] = length(s)) then
+    t[ord(s[x])] := length(s) - x;
+end;
+
+
+function Scan(var Block; Size: Sw_Word;const Str: String): Sw_Word;
+Var
+  buffer : Array[0..MaxBufLength-1] of Byte Absolute block;
+  s2     : String;
+  len,
+  numb   : Sw_Word;
+  found  : Boolean;
+  bt     : Btable;
+begin
+  BMMakeTable(str,bt);
+  len:=length(str);
+  s2[0]:=chr(len);       { sets the length to that of the search String }
+  found:=False;
+  numb:=pred(len);
+  While (not found) and (numb<(size-len)) do
+   begin
+     { partial match }
+     if buffer[numb] = ord(str[len]) then
+      begin
+        { less partial! }
+        if buffer[numb-pred(len)] = ord(str[1]) then
+         begin
+           move(buffer[numb-pred(len)],s2[1],len);
+           if (str=s2) then
+            begin
+              found:=true;
+              break;
+            end;
+         end;
+        inc(numb);
+     end
+    else
+     inc(numb,Bt[buffer[numb]]);
+  end;
+  if not found then
+    Scan := NotFoundValue
+  else
+    Scan := numb - pred(len);
+end;
+
+
+function IScan(var Block; Size: Sw_Word;const Str: String): Sw_Word;
+Var
+  buffer : Array[0..MaxBufLength-1] of Char Absolute block;
+  s      : String;
+  len,
+  numb,
+  x      : Sw_Word;
+  found  : Boolean;
+  bt     : Btable;
+  p      : pchar;
+  c      : char;
+begin
+  len:=length(str);
+  { create uppercased string }
+  s[0]:=chr(len);
+  for x:=1to len do
+   begin
+     if str[x] in ['a'..'z'] then
+      s[x]:=chr(ord(str[x])-32)
+     else
+      s[x]:=str[x];
+   end;
+  BMMakeTable(s,bt);
+  found:=False;
+  numb:=pred(len);
+  While (not found) and (numb<(size-len)) do
+   begin
+     { partial match }
+     c:=buffer[numb];
+     if c in ['a'..'z'] then
+      c:=chr(ord(c)-32);
+     if (c=s[len]) then
+      begin
+        { less partial! }
+        p:=@buffer[numb-pred(len)];
+        x:=1;
+        while (x<=len) do
+         begin
+           if not(((p^ in ['a'..'z']) and (chr(ord(p^)-32)=s[x])) or
+                  (p^=s[x])) then
+            break;
+           inc(p);
+           inc(x);
+         end;
+        if (x>len) then
+         begin
+           found:=true;
+           break;
+         end;
+        inc(numb);
+     end
+    else
+     inc(numb,Bt[ord(c)]);
+  end;
+  if not found then
+    IScan := NotFoundValue
+  else
+    IScan := numb - pred(len);
+end;
+
+
+{****************************************************************************
+                                 TIndicator
+****************************************************************************}
+
+constructor TIndicator.Init (var Bounds : TRect);
+begin
+  Inherited Init (Bounds);
+  GrowMode := gfGrowLoY + gfGrowHiY;
+end; { TIndicator.Init }
+
+
+procedure TIndicator.Draw;
+VAR
+  Color : Byte;
+  Frame : Char;
+  L     : array[0..1] of Longint;
+  S     : String[15];
+  B     : TDrawBuffer;
+begin
+  if State and sfDragging = 0 then
+    begin
+      Color := GetColor (1);
+      Frame := #205;
+    end
+  else
+    begin
+      Color := GetColor (2);
+      Frame := #196;
+    end;
+  MoveChar (B, Frame, Color, Size.X);
+  { If the text has been modified, put an 'M' in the TIndicator display. }
+  if Modified then
+    WordRec (B[1]).Lo := 77;
+  { If WordWrap is active put a 'W' in the TIndicator display. }
+  if WordWrap then
+    WordRec (B[2]).Lo := 87
+  else
+    WordRec (B[2]).Lo := Byte (Frame);
+  { If AutoIndent is active put an 'I' in TIndicator display. }
+  if AutoIndent then
+    WordRec (B[0]).Lo := 73
+  else
+    WordRec (B[0]).Lo := Byte (Frame);
+  L[0] := Location.Y + 1;
+  L[1] := Location.X + 1;
+  FormatStr (S, ' %d:%d ', L);
+  MoveStr (B[9 - Pos (':', S)], S, Color);       { Changed original 8 to 9. }
+  WriteBuf (0, 0, Size.X, 1, B);
+end; { TIndicator.Draw }
+
+
+function TIndicator.GetPalette : PPalette;
+const
+  P : string[Length (CIndicator)] = CIndicator;
+begin
+  GetPalette := @P;
+end; { TIndicator.GetPalette }
+
+
+procedure TIndicator.SetState (AState : Word; Enable : Boolean);
+begin
+  Inherited SetState (AState, Enable);
+  if AState = sfDragging then
+    DrawView;
+end; { TIndicator.SetState }
+
+
+procedure TIndicator.SetValue (ALocation : Objects.TPoint; IsAutoIndent : Boolean;
+                                                           IsModified   : Boolean;
+                                                           IsWordWrap   : Boolean);
+begin
+  if (Location.X<>ALocation.X) or
+     (Location.Y<>ALocation.Y) or
+     (AutoIndent <> IsAutoIndent) or
+     (Modified <> IsModified) or
+     (WordWrap <> IsWordWrap) then
+   begin
+     Location   := ALocation;
+     AutoIndent := IsAutoIndent;    { Added provisions to show AutoIndent. }
+     Modified   := IsModified;
+     WordWrap   := IsWordWrap;      { Added provisions to show WordWrap.   }
+     DrawView;
+   end;
+end; { TIndicator.SetValue }
+
+
+{****************************************************************************
+                                 TLineInfo
+****************************************************************************}
+
+constructor TLineInfo.Init;
+begin
+  MaxPos:=0;
+  Grow(1);
+end;
+
+
+destructor TLineInfo.Done;
+begin
+  FreeMem(Info,MaxPos*sizeof(TLineInfoRec));
+end;
+
+
+procedure TLineInfo.Grow(pos:Sw_word);
+var
+  NewSize : Sw_word;
+  P : pointer;
+begin
+  NewSize:=(Pos+LineInfoGrow-(Pos mod LineInfoGrow));
+  GetMem(P,NewSize*sizeof(TLineInfoRec));
+  FillChar(P^,NewSize*sizeof(TLineInfoRec),0);
+  Move(Info^,P^,MaxPos*sizeof(TLineInfoRec));
+  Freemem(Info,MaxPos*sizeof(TLineInfoRec));
+  Info:=P;
+end;
+
+
+procedure TLineInfo.SetLen(pos,val:Sw_Word);
+begin
+  if pos>=MaxPos then
+   Grow(Pos);
+  Info^[Pos].Len:=val
+end;
+
+
+procedure TLineInfo.SetAttr(pos,val:Sw_Word);
+begin
+  if pos>=MaxPos then
+   Grow(Pos);
+  Info^[Pos].Attr:=val
+end;
+
+
+function TLineInfo.GetLen(pos:Sw_Word):Sw_Word;
+begin
+  GetLen:=Info^[Pos].Len;
+end;
+
+
+function TLineInfo.GetAttr(pos:Sw_Word):Sw_Word;
+begin
+  GetAttr:=Info^[Pos].Attr;
+end;
+
+
+
+{****************************************************************************
+                                 TEditor
+****************************************************************************}
+
+constructor TEditor.Init (var Bounds : TRect;
+                              AHScrollBar, AVScrollBar : PScrollBar;
+                              AIndicator : PIndicator; ABufSize : Sw_Word);
+var
+  Element : Byte;      { Place_Marker array element to initialize array with. }
+begin
+  Inherited Init (Bounds);
+  GrowMode := gfGrowHiX + gfGrowHiY;
+  Options := Options or ofSelectable;
+  Flags := EditorFlags;
+  EventMask := evMouseDown + evKeyDown + evCommand + evBroadcast;
+  ShowCursor;
+
+  HScrollBar := AHScrollBar;
+  VScrollBar := AVScrollBar;
+
+  Indicator := AIndicator;
+  BufSize := ABufSize;
+  CanUndo := True;
+  InitBuffer;
+
+  if assigned(Buffer) then
+    IsValid := True
+  else
+    begin
+      EditorDialog (edOutOfMemory, nil);
+      BufSize := 0;
+    end;
+
+  SetBufLen (0);
+
+  for Element := 1 to 10 do
+    Place_Marker[Element] := 0;
+
+  Element := 1;
+  while Element <= 70 do
+    begin
+      if Element mod 5 = 0 then
+        Insert ('x', Tab_Settings, Element)
+      else
+        Insert (#32, Tab_Settings, Element);
+      Inc (Element);
+    end;
+  { Default Right_Margin value.  Change it if you want another. }
+  Right_Margin := 76;
+  TabSize:=8;
+end; { TEditor.Init }
+
+
+constructor TEditor.Load (var S : Objects.TStream);
+begin
+  Inherited Load (S);
+  GetPeerViewPtr (S, HScrollBar);
+  GetPeerViewPtr (S, VScrollBar);
+  GetPeerViewPtr (S, Indicator);
+  S.Read (BufSize, SizeOf (Sw_Word));
+  S.Read (CanUndo, SizeOf (Boolean));
+  S.Read (AutoIndent,   SizeOf (AutoIndent));
+  S.Read (Line_Number,  SizeOf (Line_Number));
+  S.Read (Place_Marker, SizeOf (Place_Marker));
+  S.Read (Right_Margin, SizeOf (Right_Margin));
+  S.Read (Tab_Settings, SizeOf (Tab_Settings));
+  S.Read (Word_Wrap,    SizeOf (Word_Wrap));
+  InitBuffer;
+  if Assigned(Buffer) then
+    IsValid := True
+  else
+    begin
+      EditorDialog (edOutOfMemory, nil);
+      BufSize := 0;
+    end;
+  Lock;
+  SetBufLen (0);
+end; { TEditor.Load }
+
+
+destructor TEditor.Done;
+begin
+  DoneBuffer;
+  Inherited Done;
+end; { TEditor.Done }
+
+
+function TEditor.BufChar(P: Sw_Word): Char;
+begin
+  if P>=CurPtr then
+   inc(P,Gaplen);
+  BufChar:=Buffer^[P];
+end;
+
+
+function TEditor.BufPtr(P: Sw_Word): Sw_Word;
+begin
+  if P>=CurPtr then
+   BufPtr:=P+GapLen
+  else
+   BufPtr:=P;
+end;
+
+
+procedure TEditor.Center_Text (Select_Mode : Byte);
+{ This procedure will center the current line of text. }
+{ Centering is based on the current Right_Margin.      }
+{ If the Line_Length exceeds the Right_Margin, or the  }
+{ line is just a blank line, we exit and do nothing.   }
+VAR
+  Spaces      : array [1..80] of Char;  { Array to hold spaces we'll insert. }
+  Index       : Byte;                   { Index into Spaces array.           }
+  Line_Length : Sw_Integer;             { Holds the length of the line.      }
+  E,S : Sw_Word;                        { End of the current line.           }
+begin
+  E := LineEnd (CurPtr);
+  S := LineStart (CurPtr);
+  { If the line is blank (only a CR/LF on it) then do noting. }
+  if E = S then
+    Exit;
+  { Set CurPtr to start of line.  Check if line begins with a space.  }
+  { We must strip out any spaces from the beginning, or end of lines. }
+  { If line does not start with space, make sure line length does not }
+  { exceed the Right_Margin.  If it does, then do nothing.            }
+  SetCurPtr (S, Select_Mode);
+  Remove_EOL_Spaces (Select_Mode);
+  if Buffer^[CurPtr] = #32 then
+    begin
+      { If the next word is greater than the end of line then do nothing. }
+      { If the line length is greater than Right_Margin then do nothing.  }
+      { Otherwise, delete all spaces at the start of line.                }
+      { Then reset end of line and put CurPtr at start of modified line.  }
+      E := LineEnd (CurPtr);
+      if NextWord (CurPtr) > E then
+        Exit;
+      if E - NextWord (CurPtr) > Right_Margin then
+        Exit;
+      DeleteRange (CurPtr, NextWord (CurPtr), True);
+      E := LineEnd (CurPtr);
+      SetCurPtr (LineStart (CurPtr), Select_Mode);
+    end
+  else
+    if E - CurPtr > Right_Margin then
+      Exit;
+  { Now we determine the real length of the line.       }
+  { Then we subtract the Line_Length from Right_Margin. }
+  { Dividing the result by two tells us how many spaces }
+  { must be inserted at start of line to center it.     }
+  { When we're all done, set the CurPtr to end of line. }
+  Line_Length := E - CurPtr;
+  for Index := 1 to ((Right_Margin - Line_Length) shr 1) do
+    Spaces[Index] := #32;
+  InsertText (@Spaces, Index, False);
+  SetCurPtr (LineEnd (CurPtr), Select_Mode);
+end; { TEditor.Center_Text }
+
+
+procedure TEditor.ChangeBounds (var Bounds : TRect);
+begin
+  SetBounds (Bounds);
+  Delta.X := Max (0, Min (Delta.X, Limit.X - Size.X));
+  Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y));
+  Update (ufView);
+end; { TEditor.ChangeBounds }
+
+
+function TEditor.CharPos (P, Target : Sw_Word) : Sw_Integer;
+VAR
+  Pos : Sw_Integer;
+begin
+  Pos := 0;
+  while P < Target do
+   begin
+     if BufChar (P) = #9 then
+       Pos := Pos or 7;
+     Inc (Pos);
+     Inc (P);
+   end;
+  CharPos := Pos;
+end; { TEditor.CharPos }
+
+
+function TEditor.CharPtr (P : Sw_Word; Target : Sw_Integer) : Sw_Word;
+VAR
+  Pos : Sw_Integer;
+begin
+  Pos := 0;
+  while (Pos < Target) and (P < BufLen) and  not(BufChar (P) in [#10,#13]) do
+  begin
+    if BufChar (P) = #9 then
+      Pos := Pos or 7;
+    Inc (Pos);
+    Inc (P);
+  end;
+  if Pos > Target then
+    Dec (P);
+  CharPtr := P;
+end; { TEditor.CharPtr }
+
+
+procedure TEditor.Check_For_Word_Wrap (Select_Mode   : Byte;
+                                       Center_Cursor : Boolean);
+{ This procedure checks if CurPos.X > Right_Margin. }
+{ If it is, then we Do_Word_Wrap.  Simple, eh?      }
+begin
+  if CurPos.X > Right_Margin then
+    Do_Word_Wrap (Select_Mode, Center_Cursor);
+end; {Check_For_Word_Wrap}
+
+
+function TEditor.ClipCopy : Boolean;
+begin
+  ClipCopy := False;
+  if Assigned(Clipboard) and (Clipboard <> @Self) then
+   begin
+     ClipCopy := Clipboard^.InsertFrom (@Self);
+     Selecting := False;
+     Update (ufUpdate);
+  end;
+end; { TEditor.ClipCopy }
+
+
+procedure TEditor.ClipCut;
+begin
+  if ClipCopy then
+  begin
+    Update_Place_Markers (0,
+                          Self.SelEnd - Self.SelStart,
+                          Self.SelStart,
+                          Self.SelEnd);
+    DeleteSelect;
+  end;
+end; { TEditor.ClipCut }
+
+
+procedure TEditor.ClipPaste;
+begin
+  if Assigned(Clipboard) and (Clipboard <> @Self) then
+    begin
+      { Do not allow paste operations that will exceed }
+      { the Right_Margin when Word_Wrap is active and  }
+      { cursor is at EOL.                              }
+      if Word_Wrap and (CurPos.X > Right_Margin) then
+        begin
+          EditorDialog (edPasteNotPossible, nil);
+          Exit;
+        end;
+      { The editor will not copy selected text if the CurPtr }
+      { is not the same value as the SelStart.  However, it  }
+      { does return an InsCount.  This may, or may not, be a }
+      { bug.  We don't want to update the Place_Marker if    }
+      { there's no text copied.                              }
+      if CurPtr = SelStart then
+        Update_Place_Markers (Clipboard^.SelEnd - Clipboard^.SelStart,
+                              0,
+                              Clipboard^.SelStart,
+                              Clipboard^.SelEnd);
+      InsertFrom (Clipboard);
+    end;
+end; { TEditor.ClipPaste }
+
+
+procedure TEditor.ConvertEvent (var Event : Drivers.TEvent);
+VAR
+  ShiftState : Byte;
+  Key        : Word;
+begin
+  ShiftState:=GetShiftState;
+  if Event.What = evKeyDown then
+  begin
+    if (ShiftState and $03 <> 0)
+                   and (Event.ScanCode >= $47)
+                   and (Event.ScanCode <= $51) then
+      Event.CharCode := #0;
+    Key := Event.KeyCode;
+    if KeyState <> 0 then
+    begin
+      if (Lo (Key) >= $01) and (Lo (Key) <= $1A) then
+        Inc (Key, $40);
+      if (Lo (Key) >= $61) and (Lo (Key) <= $7A) then
+        Dec (Key, $20);
+    end;
+    Key := ScanKeyMap (KeyMap[KeyState], Key);
+    KeyState := 0;
+    if Key <> 0 then
+      if Hi (Key) = $FF then
+        begin
+          KeyState := Lo (Key);
+          ClearEvent (Event);
+        end
+      else
+        begin
+          Event.What := evCommand;
+          Event.Command := Key;
+        end;
+  end;
+end; { TEditor.ConvertEvent }
+
+
+function TEditor.CursorVisible : Boolean;
+begin
+  CursorVisible := (CurPos.Y >= Delta.Y) and (CurPos.Y < Delta.Y + Size.Y);
+end; { TEditor.CursorVisible }
+
+
+procedure TEditor.DeleteRange (StartPtr, EndPtr : Sw_Word; DelSelect : Boolean);
+begin
+  { This will update Place_Marker for all deletions. }
+  { EXCEPT the Remove_EOL_Spaces deletion.           }
+  Update_Place_Markers (0, EndPtr - StartPtr, StartPtr, EndPtr);
+  if HasSelection and DelSelect then
+    DeleteSelect
+  else
+    begin
+      SetSelect (CurPtr, EndPtr, True);
+      DeleteSelect;
+      SetSelect (StartPtr, CurPtr, False);
+      DeleteSelect;
+    end;
+end; { TEditor.DeleteRange }
+
+
+procedure TEditor.DeleteSelect;
+begin
+  InsertText (nil, 0, False);
+end; { TEditor.DeleteSelect }
+
+
+procedure TEditor.DoneBuffer;
+begin
+  if assigned(Buffer) then
+  begin
+    FreeMem (Buffer, BufSize);
+    Buffer := nil;
+  end;
+end; { TEditor.DoneBuffer }
+
+
+procedure TEditor.DoSearchReplace;
+VAR
+  I : Sw_Word;
+  C : Objects.TPoint;
+begin
+  repeat
+    I := cmCancel;
+    if not Search (FindStr, Flags) then
+      begin
+        if Flags and (efReplaceAll + efDoReplace) <> (efReplaceAll + efDoReplace) then
+          EditorDialog (edSearchFailed, nil)
+      end
+    else
+      if Flags and efDoReplace <> 0 then
+      begin
+        I := cmYes;
+        if Flags and efPromptOnReplace <> 0 then
+        begin
+          MakeGlobal (Cursor, C);
+          I := EditorDialog (edReplacePrompt, Pointer(@C));
+        end;
+        if I = cmYes then
+          begin
+            { If Word_Wrap is active and we are at EOL }
+            { disallow replace by bringing up a dialog }
+            { stating that replace is not possible.    }
+            if Word_Wrap and
+               ((CurPos.X + (Length (ReplaceStr) - Length (FindStr))) > Right_Margin) then
+              EditorDialog (edReplaceNotPossible, nil)
+            else
+              begin
+                Lock;
+                Search_Replace := True;
+                if length (ReplaceStr) < length (FindStr) then
+                  Update_Place_Markers (0,
+                                        Length (FindStr) - Length (ReplaceStr),
+                                        CurPtr - Length (FindStr) + Length (ReplaceStr),
+                                        CurPtr)
+                else
+                  if length (ReplaceStr) > length (FindStr) then
+                    Update_Place_Markers (Length (ReplaceStr) - Length (FindStr),
+                                          0,
+                                          CurPtr,
+                                          CurPtr + (Length (ReplaceStr) - Length (FindStr)));
+                InsertText (@ReplaceStr[1], Length (ReplaceStr), False);
+                Search_Replace := False;
+                TrackCursor (False);
+                Unlock;
+             end;
+          end;
+      end;
+  until (I = cmCancel) or (Flags and efReplaceAll = 0);
+end; { TEditor.DoSearchReplace }
+
+
+procedure TEditor.DoUpdate;
+begin
+  if UpdateFlags <> 0 then
+  begin
+    SetCursor (CurPos.X - Delta.X, CurPos.Y - Delta.Y);
+    if UpdateFlags and ufView <> 0 then
+      DrawView
+    else
+      if UpdateFlags and ufLine <> 0 then
+        DrawLines (CurPos.Y - Delta.Y, 1, LineStart (CurPtr));
+    if assigned(HScrollBar) then
+      HScrollBar^.SetParams (Delta.X, 0, Limit.X - Size.X, Size.X div 2, 1);
+    if assigned(VScrollBar) then
+      VScrollBar^.SetParams (Delta.Y, 0, Limit.Y - Size.Y, Size.Y - 1, 1);
+    if assigned(Indicator) then
+      Indicator^.SetValue (CurPos, AutoIndent, Modified, Word_Wrap);
+    if State and sfActive <> 0 then
+      UpdateCommands;
+    UpdateFlags := 0;
+  end;
+end; { TEditor.DoUpdate }
+
+
+function TEditor.Do_Word_Wrap (Select_Mode   : Byte;
+                               Center_Cursor : Boolean) : Boolean;
+{ This procedure does the actual wordwrap.  It always assumes the CurPtr }
+{ is at Right_Margin + 1.  It makes several tests for special conditions }
+{ and processes those first.  If they all fail, it does a normal wrap.   }
+VAR
+  A : Sw_Word;          { Distance between line start and first word on line. }
+  C : Sw_Word;          { Current pointer when we come into procedure.        }
+  L : Sw_Word;          { BufLen when we come into procedure.                 }
+  P : Sw_Word;          { Position of pointer at any given moment.            }
+  S : Sw_Word;          { Start of a line.                                    }
+begin
+  Do_Word_Wrap := False;
+  Select_Mode := 0;
+  if BufLen >= (BufSize - 1) then
+    exit;
+  C := CurPtr;
+  L := BufLen;
+  S := LineStart (CurPtr);
+  { If first character in the line is a space and autoindent mode is on  }
+  { then we check to see if NextWord(S) exceeds the CurPtr.  If it does, }
+  { we set CurPtr as the AutoIndent marker.  If it doesn't, we will set  }
+  { NextWord(S) as the AutoIndent marker.  If neither, we set it to S.   }
+  if AutoIndent and (Buffer^[S] = ' ') then
+    begin
+      if NextWord (S) > CurPtr then
+        A := CurPtr
+      else
+        A := NextWord (S);
+    end
+  else
+    A := NextWord (S);
+  { Though NewLine will remove EOL spaces, we do it here too. }
+  { This catches the instance where a user may try to space   }
+  { completely across the line, in which case CurPtr.X = 0.   }
+  Remove_EOL_Spaces (Select_Mode);
+  if CurPos.X = 0 then
+    begin
+      NewLine (Select_Mode);
+      Do_Word_Wrap := True;
+      Exit;
+    end;
+  { At this point we have one of five situations:                               }
+  {                                                                             }
+  { 1)  AutoIndent is on and this line is all spaces before CurPtr.             }
+  { 2)  AutoIndent is off and this line is all spaces before CurPtr.            }
+  { 3)  AutoIndent is on and this line is continuous characters before CurPtr.  }
+  { 4)  AutoIndent is off and this line is continuous characters before CurPtr. }
+  { 5)  This is just a normal line of text.                                     }
+  {                                                                             }
+  { Conditions 1 through 4 have to be taken into account before condition 5.    }
+  { First, we see if there are all spaces and/or all characters. }
+  { Then we determine which one it really is.  Finally, we take  }
+  { a course of action based on the state of AutoIndent.         }
+  if PrevWord (CurPtr) <= S then
+    begin
+      P := CurPtr - 1;
+      while ((Buffer^[P] <> ' ') and (P > S)) do
+        Dec (P);
+      { We found NO SPACES.  Conditions 4 and 5 are treated the same.  }
+      { We can NOT do word wrap and put up a dialog box stating such.  }
+      { Delete character just entered so we don't exceed Right_Margin. }
+      if P = S then
+        begin
+          EditorDialog (edWrapNotPossible, nil);
+          DeleteRange (PrevChar (CurPtr), CurPtr, True);
+          Exit;
+        end
+      else
+        begin
+          { There are spaces.  Now find out if they are all spaces. }
+          { If so, see if AutoIndent is on.  If it is, turn it off, }
+          { do a NewLine, and turn it back on.  Otherwise, just do  }
+          { the NewLine.  We go through all of these gyrations for  }
+          { AutoIndent.  Being way out here with a preceding line   }
+          { of spaces and wrapping with AutoIndent on is real dumb! }
+          { However, the user expects something.  The wrap will NOT }
+          { autoindent, but they had no business being here anyway! }
+          P := CurPtr - 1;
+          while ((Buffer^[P] = ' ') and (P > S)) do
+            Dec (P);
+          if P = S then
+            begin
+              if Autoindent then
+                begin
+                  AutoIndent := False;
+                  NewLine (Select_Mode);
+                  AutoIndent := True;
+                end
+              else
+                NewLine (Select_Mode);
+              end; { AutoIndent }
+            end; { P = S for spaces }
+        end { P = S for no spaces }
+    else { PrevWord (CurPtr) <= S }
+      begin
+        { Hooray!  We actually had a plain old line of text to wrap!       }
+        { Regardless if we are pushing out a line beyond the Right_Margin, }
+        { or at the end of a line itself, the following will determine     }
+        { exactly where to do the wrap and re-set the cursor accordingly.  }
+        { However, if P = A then we can't wrap.  Show dialog and exit.     }
+        P := CurPtr;
+        while P - S > Right_Margin do
+          P := PrevWord (P);
+        if (P = A) then
+          begin
+            EditorDialog (edReformNotPossible, nil);
+            SetCurPtr (P, Select_Mode);
+            Exit;
+          end;
+        SetCurPtr (P, Select_Mode);
+        NewLine (Select_Mode);
+    end; { PrevWord (CurPtr <= S }
+  { Track the cursor here (it is at CurPos.X = 0) so the view  }
+  { will redraw itself at column 0.  This eliminates having it }
+  { redraw starting at the current cursor and not being able   }
+  { to see text before the cursor.  Of course, we also end up  }
+  { redrawing the view twice, here and back in HandleEvent.    }
+  {                                                            }
+  { Reposition cursor so user can pick up where they left off. }
+  TrackCursor (Center_Cursor);
+  SetCurPtr (C - (L - BufLen), Select_Mode);
+  Do_Word_Wrap := True;
+end; { TEditor.Do_Word_Wrap }
+
+
+procedure TEditor.Draw;
+begin
+  if DrawLine <> Delta.Y then
+  begin
+    DrawPtr := LineMove (DrawPtr, Delta.Y - DrawLine);
+    DrawLine := Delta.Y;
+  end;
+  DrawLines (0, Size.Y, DrawPtr);
+end; { TEditor.Draw }
+
+
+procedure TEditor.DrawLines (Y, Count : Sw_Integer; LinePtr : Sw_Word);
+VAR
+  Color : Word;
+  B     : array[0..MaxLineLength - 1] of Sw_Word;
+begin
+  Color := GetColor ($0201);
+  while Count > 0 do
+  begin
+    FormatLine (B, LinePtr, Delta.X + Size.X, Color);
+    WriteBuf (0, Y, Size.X, 1, B[Delta.X]);
+    LinePtr := NextLine (LinePtr);
+    Inc (Y);
+    Dec (Count);
+  end;
+end; { TEditor.DrawLines }
+
+
+procedure TEditor.Find;
+VAR
+  FindRec : TFindDialogRec;
+begin
+  with FindRec do
+  begin
+    Find := FindStr;
+    Options := Flags;
+    if EditorDialog (edFind, @FindRec) <> cmCancel then
+    begin
+      FindStr := Find;
+      Flags := Options and not efDoReplace;
+      DoSearchReplace;
+    end;
+  end;
+end; { TEditor.Find }
+
+
+procedure TEditor.FormatLine (var DrawBuf; LinePtr : Sw_Word;
+                                  Width  : Sw_Integer;
+                                  Colors : Word);
+var
+  outptr : pword;
+  outcnt,
+  idxpos : Sw_Word;
+  attr   : Word;
+
+  procedure FillSpace(i:Sw_Word);
+  var
+    w : word;
+  begin
+    inc(OutCnt,i);
+    w:=32 or attr;
+    while (i>0) do
+     begin
+       OutPtr^:=w;
+       inc(OutPtr);
+       dec(i);
+     end;
+  end;
+
+  function FormatUntil(endpos:Sw_word):boolean;
+  var
+    p : pchar;
+  begin
+    FormatUntil:=false;
+    p:=pchar(Buffer)+idxpos;
+    while endpos>idxpos do
+     begin
+       if OutCnt>=Width then
+        exit;
+       case p^ of
+         #9 :
+           FillSpace(Tabsize-(outcnt mod Tabsize));
+         #10,#13 :
+           begin
+             FillSpace(Width-OutCnt);
+             FormatUntil:=true;
+             exit;
+           end;
+         else
+           begin
+             inc(OutCnt);
+             OutPtr^:=ord(p^) or attr;
+             inc(OutPtr);
+           end;
+       end; { case }
+       inc(p);
+       inc(idxpos);
+     end;
+  end;
+
+begin
+  OutCnt:=0;
+  OutPtr:=@DrawBuf;
+  idxPos:=LinePtr;
+  attr:=lo(Colors) shl 8;
+  if FormatUntil(SelStart) then
+   exit;
+  attr:=hi(Colors) shl 8;
+  if FormatUntil(CurPtr) then
+   exit;
+  inc(idxPos,GapLen);
+  if FormatUntil(SelEnd+GapLen) then
+   exit;
+  attr:=lo(Colors) shl 8;
+  if FormatUntil(BufSize) then
+   exit;
+{ fill up until width }
+  FillSpace(Width-OutCnt);
+end; {TEditor.FormatLine}
+
+
+function TEditor.GetMousePtr (Mouse : Objects.TPoint) : Sw_Word;
+begin
+  MakeLocal (Mouse, Mouse);
+  Mouse.X := Max (0, Min (Mouse.X, Size.X - 1));
+  Mouse.Y := Max (0, Min (Mouse.Y, Size.Y - 1));
+  GetMousePtr := CharPtr (LineMove (DrawPtr, Mouse.Y + Delta.Y - DrawLine),
+                          Mouse.X + Delta.X);
+end; { TEditor.GetMousePtr }
+
+
+function TEditor.GetPalette : PPalette;
+CONST
+  P : String[Length (CEditor)] = CEditor;
+begin
+  GetPalette := @P;
+end; { TEditor.GetPalette }
+
+
+procedure TEditor.HandleEvent (var Event : Drivers.TEvent);
+VAR
+  ShiftState   : Byte;
+  CenterCursor : Boolean;
+  SelectMode   : Byte;
+  D            : Objects.TPoint;
+  Mouse        : Objects.TPoint;
+
+  function CheckScrollBar (P : PScrollBar; var D : Sw_Integer) : Boolean;
+  begin
+    CheckScrollBar := FALSE;
+    if (Event.InfoPtr = P) and (P^.Value <> D) then
+    begin
+      D := P^.Value;
+      Update (ufView);
+      CheckScrollBar := TRUE;
+    end;
+  end; {CheckScrollBar}
+
+begin
+  Inherited HandleEvent (Event);
+  ConvertEvent (Event);
+  CenterCursor := not CursorVisible;
+  SelectMode := 0;
+  ShiftState:=GetShiftState;
+  if Selecting or (ShiftState and $03 <> 0) then
+    SelectMode := smExtend;
+  case Event.What of
+    Drivers.evMouseDown:
+      begin
+        if Event.Double then
+          SelectMode := SelectMode or smDouble;
+        repeat
+          Lock;
+          if Event.What = evMouseAuto then
+          begin
+            MakeLocal (Event.Where, Mouse);
+            D := Delta;
+            if Mouse.X < 0 then
+              Dec (D.X);
+            if Mouse.X >= Size.X then
+              Inc (D.X);
+            if Mouse.Y < 0 then
+              Dec (D.Y);
+            if Mouse.Y >= Size.Y then
+              Inc (D.Y);
+            ScrollTo (D.X, D.Y);
+          end;
+          SetCurPtr (GetMousePtr (Event.Where), SelectMode);
+          SelectMode := SelectMode or smExtend;
+          Unlock;
+        until not MouseEvent (Event, evMouseMove + evMouseAuto);
+      end; { Drivers.evMouseDown }
+
+    Drivers.evKeyDown:
+      case Event.CharCode of
+        #32..#255:
+          begin
+            Lock;
+            if Overwrite and not HasSelection then
+              if CurPtr <> LineEnd (CurPtr) then
+                SelEnd := NextChar (CurPtr);
+            InsertText (@Event.CharCode, 1, False);
+            if Word_Wrap then
+              Check_For_Word_Wrap (SelectMode, CenterCursor);
+            TrackCursor (CenterCursor);
+            Unlock;
+          end;
+
+      else
+        Exit;
+      end; { Drivers.evKeyDown }
+
+    Drivers.evCommand:
+      case Event.Command of
+        cmFind        : Find;
+        cmReplace     : Replace;
+        cmSearchAgain : DoSearchReplace;
+      else
+        begin
+          Lock;
+          case Event.Command of
+            cmCut         : ClipCut;
+            cmCopy        : ClipCopy;
+            cmPaste       : ClipPaste;
+            cmUndo        : Undo;
+            cmClear       : DeleteSelect;
+            cmCharLeft    : SetCurPtr (PrevChar  (CurPtr), SelectMode);
+            cmCharRight   : SetCurPtr (NextChar  (CurPtr), SelectMode);
+            cmWordLeft    : SetCurPtr (PrevWord  (CurPtr), SelectMode);
+            cmWordRight   : SetCurPtr (NextWord  (CurPtr), SelectMode);
+            cmLineStart   : SetCurPtr (LineStart (CurPtr), SelectMode);
+            cmLineEnd     : SetCurPtr (LineEnd   (CurPtr), SelectMode);
+            cmLineUp      : SetCurPtr (LineMove  (CurPtr, -1), SelectMode);
+            cmLineDown    : SetCurPtr (LineMove  (CurPtr, 1),  SelectMode);
+            cmPageUp      : SetCurPtr (LineMove  (CurPtr, - (Size.Y - 1)), SelectMode);
+            cmPageDown    : SetCurPtr (LineMove  (CurPtr, Size.Y - 1), SelectMode);
+            cmTextStart   : SetCurPtr (0, SelectMode);
+            cmTextEnd     : SetCurPtr (BufLen, SelectMode);
+            cmNewLine     : NewLine (SelectMode);
+            cmBackSpace   : DeleteRange (PrevChar (CurPtr), CurPtr, True);
+            cmDelChar     : DeleteRange (CurPtr, NextChar (CurPtr), True);
+            cmDelWord     : DeleteRange (CurPtr, NextWord (CurPtr), False);
+            cmDelStart    : DeleteRange (LineStart (CurPtr), CurPtr, False);
+            cmDelEnd      : DeleteRange (CurPtr, LineEnd (CurPtr), False);
+            cmDelLine     : DeleteRange (LineStart (CurPtr), NextLine (CurPtr), False);
+            cmInsMode     : ToggleInsMode;
+            cmStartSelect : StartSelect;
+            cmHideSelect  : HideSelect;
+            cmIndentMode  : begin
+                              AutoIndent := not AutoIndent;
+                              Update (ufStats);
+                            end; { Added provision to update TIndicator if ^QI pressed. }
+            cmCenterText  : Center_Text (SelectMode);
+            cmEndPage     : SetCurPtr (LineMove  (CurPtr, Delta.Y - CurPos.Y + Size.Y - 1), SelectMode);
+            cmHomePage    : SetCurPtr (LineMove  (CurPtr, -(CurPos.Y - Delta.Y)), SelectMode);
+            cmInsertLine  : Insert_Line (SelectMode);
+            cmJumpLine    : Jump_To_Line (SelectMode);
+            cmReformDoc   : Reformat_Document (SelectMode, CenterCursor);
+            cmReformPara  : Reformat_Paragraph (SelectMode, CenterCursor);
+            cmRightMargin : Set_Right_Margin;
+            cmScrollDown  : Scroll_Down;
+            cmScrollUp    : Scroll_Up;
+            cmSelectWord  : Select_Word;
+            cmSetTabs     : Set_Tabs;
+            cmTabKey      : Tab_Key (SelectMode);
+            cmWordWrap    : begin
+                              Word_Wrap := not Word_Wrap;
+                              Update (ufStats);
+                            end; { Added provision to update TIndicator if ^OW pressed. }
+            cmSetMark0    : Set_Place_Marker (10);
+            cmSetMark1    : Set_Place_Marker  (1);
+            cmSetMark2    : Set_Place_Marker  (2);
+            cmSetMark3    : Set_Place_Marker  (3);
+            cmSetMark4    : Set_Place_Marker  (4);
+            cmSetMark5    : Set_Place_Marker  (5);
+            cmSetMark6    : Set_Place_Marker  (6);
+            cmSetMark7    : Set_Place_Marker  (7);
+            cmSetMark8    : Set_Place_Marker  (8);
+            cmSetMark9    : Set_Place_Marker  (9);
+            cmJumpMark0   : Jump_Place_Marker (10, SelectMode);
+            cmJumpMark1   : Jump_Place_Marker  (1, SelectMode);
+            cmJumpMark2   : Jump_Place_Marker  (2, SelectMode);
+            cmJumpMark3   : Jump_Place_Marker  (3, SelectMode);
+            cmJumpMark4   : Jump_Place_Marker  (4, SelectMode);
+            cmJumpMark5   : Jump_Place_Marker  (5, SelectMode);
+            cmJumpMark6   : Jump_Place_Marker  (6, SelectMode);
+            cmJumpMark7   : Jump_Place_Marker  (7, SelectMode);
+            cmJumpMark8   : Jump_Place_Marker  (8, SelectMode);
+            cmJumpMark9   : Jump_Place_Marker  (9, SelectMode);
+          else
+            Unlock;
+            Exit;
+          end; { Event.Command (Inner) }
+          TrackCursor (CenterCursor);
+          { If the user presses any key except cmNewline or cmBackspace  }
+          { we need to check if the file has been modified yet.  There   }
+          { can be no spaces at the end of a line, or wordwrap doesn't   }
+          { work properly.  We don't want to do this if the file hasn't  }
+          { been modified because the user could be bringing in an ASCII }
+          { file from an editor that allows spaces at the EOL.  If we    }
+          { took them out in that scenario the "M" would appear on the   }
+          { TIndicator line and the user would get upset or confused.    }
+          if (Event.Command <> cmNewLine)   and
+             (Event.Command <> cmBackSpace) and
+             (Event.Command <> cmTabKey)    and
+              Modified then
+            Remove_EOL_Spaces (SelectMode);
+          Unlock;
+        end; { Event.Command (Outer) }
+      end; { Drivers.evCommand }
+
+    Drivers.evBroadcast:
+      case Event.Command of
+        cmScrollBarChanged:
+          if (Event.InfoPtr = HScrollBar) or
+            (Event.InfoPtr = VScrollBar) then
+          begin
+            CheckScrollBar (HScrollBar, Delta.X);
+            CheckScrollBar (VScrollBar, Delta.Y);
+          end
+          else
+            exit;
+      else
+        Exit;
+      end; { Drivers.evBroadcast }
+
+  end;
+  ClearEvent (Event);
+end; { TEditor.HandleEvent }
+
+
+function TEditor.HasSelection : Boolean;
+begin
+  HasSelection := SelStart <> SelEnd;
+end; { TEditor.HasSelection }
+
+
+procedure TEditor.HideSelect;
+begin
+  Selecting := False;
+  SetSelect (CurPtr, CurPtr, False);
+end; { TEditor.HideSelect }
+
+
+procedure TEditor.InitBuffer;
+begin
+  Buffer := MemAlloc (BufSize);
+end; { TEditor.InitBuffer }
+
+
+function TEditor.InsertBuffer (var P : PEditBuffer;
+                               Offset,    Length     : Sw_Word;
+                               AllowUndo, SelectText : Boolean) : Boolean;
+VAR
+  SelLen   : Sw_Word;
+  DelLen   : Sw_Word;
+  SelLines : Sw_Word;
+  Lines    : Sw_Word;
+  NewSize  : Longint;
+begin
+  InsertBuffer := True;
+  Selecting := False;
+  SelLen := SelEnd - SelStart;
+  if (SelLen = 0) and (Length = 0) then
+    Exit;
+  DelLen := 0;
+  if AllowUndo then
+    if CurPtr = SelStart then
+      DelLen := SelLen
+    else
+      if SelLen > InsCount then
+        DelLen := SelLen - InsCount;
+  NewSize := Longint (BufLen + DelCount - SelLen + DelLen) + Length;
+  if NewSize > BufLen + DelCount then
+    if (NewSize > MaxBufLength) or not SetBufSize (NewSize) then
+      begin
+        EditorDialog (edOutOfMemory, nil);
+        InsertBuffer := False;
+        SelEnd := SelStart;
+        Exit;
+      end;
+  SelLines := CountLines (Buffer^[BufPtr (SelStart)], SelLen);
+  if CurPtr = SelEnd then
+  begin
+    if AllowUndo then
+    begin
+      if DelLen > 0 then
+        Move (Buffer^[SelStart], Buffer^[CurPtr + GapLen - DelCount - DelLen], DelLen);
+      Dec (InsCount, SelLen - DelLen);
+    end;
+    CurPtr := SelStart;
+    Dec (CurPos.Y, SelLines);
+  end;
+  if Delta.Y > CurPos.Y then
+    begin
+      Dec (Delta.Y, SelLines);
+      if Delta.Y < CurPos.Y then
+        Delta.Y := CurPos.Y;
+    end;
+  if Length > 0 then
+    Move (P^[Offset], Buffer^[CurPtr], Length);
+  Lines := CountLines (Buffer^[CurPtr], Length);
+  Inc (CurPtr, Length);
+  Inc (CurPos.Y, Lines);
+  DrawLine := CurPos.Y;
+  DrawPtr := LineStart (CurPtr);
+  CurPos.X := CharPos (DrawPtr, CurPtr);
+  if not SelectText then
+    SelStart := CurPtr;
+  SelEnd := CurPtr;
+  if Length>Sellen then
+   begin
+     Inc (BufLen, Length - SelLen);
+     Dec (GapLen, Length - SelLen);
+   end
+  else
+   begin
+     Dec (BufLen, Sellen - Length);
+     Inc (GapLen, Sellen - Length);
+   end;
+  if AllowUndo then
+    begin
+      Inc (DelCount, DelLen);
+      Inc (InsCount, Length);
+    end;
+  Inc (Limit.Y, Lines - SelLines);
+  Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y));
+  if not IsClipboard then
+    Modified := True;
+  SetBufSize (BufLen + DelCount);
+  if (SelLines = 0) and (Lines = 0) then
+    Update (ufLine)
+  else
+    Update (ufView);
+end; { TEditor.InsertBuffer }
+
+
+function TEditor.InsertFrom (Editor : PEditor) : Boolean;
+begin
+  InsertFrom := InsertBuffer (Editor^.Buffer,
+    Editor^.BufPtr (Editor^.SelStart),
+    Editor^.SelEnd - Editor^.SelStart, CanUndo, IsClipboard);
+end; { TEditor.InsertFrom }
+
+
+procedure TEditor.Insert_Line (Select_Mode : Byte);
+{ This procedure inserts a newline at the current cursor position }
+{ if a ^N is pressed.  Unlike cmNewLine, the cursor will return   }
+{ to its original position.  If the cursor was at the end of a    }
+{ line, and its spaces were removed, the cursor returns to the    }
+{ end of the line instead.                                        }
+begin
+  NewLine (Select_Mode);
+  SetCurPtr (LineEnd (LineMove (CurPtr, -1)), Select_Mode);
+end; { TEditor.Insert_Line }
+
+
+function TEditor.InsertText (Text       : Pointer;
+                             Length     : Sw_Word;
+                             SelectText : Boolean) : Boolean;
+begin
+  if assigned(Text) and not Search_Replace then
+    Update_Place_Markers (Length, 0, Self.SelStart, Self.SelEnd);
+  InsertText := InsertBuffer (PEditBuffer (Text),
+                0, Length, CanUndo, SelectText);
+end; { TEditor.InsertText }
+
+
+function TEditor.IsClipboard : Boolean;
+begin
+  IsClipboard := Clipboard = @Self;
+end; { TEditor.IsClipboard }
+
+
+procedure TEditor.Jump_Place_Marker (Element : Byte; Select_Mode : Byte);
+{ This procedure jumps to a place marker if ^Q# is pressed.  }
+{ We don't go anywhere if Place_Marker[Element] is not zero. }
+begin
+  if (not IsClipboard) and (Place_Marker[Element] <> 0) then
+    SetCurPtr (Place_Marker[Element], Select_Mode);
+end; { TEditor.Jump_Place_Marker }
+
+
+procedure TEditor.Jump_To_Line (Select_Mode : Byte);
+{ This function brings up a dialog box that allows }
+{ the user to select a line number to jump to.     }
+VAR
+  Code       : Integer;         { Used for Val conversion.      }
+  Temp_Value : Longint;         { Holds converted dialog value. }
+begin
+  if EditorDialog (edJumpToLine, @Line_Number) <> cmCancel then
+    begin
+      { Convert the Line_Number string to an interger. }
+      { Put it into Temp_Value.  If the number is not  }
+      { in the range 1..9999 abort.  If the number is  }
+      { our current Y position, abort.  Otherwise,     }
+      { go to top of document, and jump to the line.   }
+      { There are faster methods.  This one's easy.    }
+      { Note that CurPos.Y is always 1 less than what  }
+      { the TIndicator line says.                      }
+      val (Line_Number, Temp_Value, Code);
+      if (Temp_Value < 1) or (Temp_Value > 9999999) then
+        Exit;
+      if Temp_Value = CurPos.Y + 1 then
+        Exit;
+      SetCurPtr (0, Select_Mode);
+      SetCurPtr (LineMove (CurPtr, Temp_Value - 1), Select_Mode);
+    end;
+end; {TEditor.Jump_To_Line}
+
+
+function TEditor.LineEnd (P : Sw_Word) : Sw_Word;
+var
+  start,
+  i  : Sw_word;
+  pc : pchar;
+begin
+  if P<CurPtr then
+   begin
+     i:=CurPtr-P;
+     pc:=pchar(Buffer)+P;
+     while (i>0) do
+      begin
+        if pc^ in [#10,#13] then
+         begin
+           LineEnd:=pc-pchar(Buffer);
+           exit;
+         end;
+        inc(pc);
+        dec(i);
+      end;
+     start:=CurPtr;
+   end
+  else
+   start:=P;
+  i:=BufLen-Start;
+  pc:=pchar(Buffer)+GapLen+start;
+  while (i>0) do
+   begin
+     if pc^ in [#10,#13] then
+      begin
+        LineEnd:=pc-(pchar(Buffer)+Gaplen);
+        exit;
+      end;
+     inc(pc);
+     dec(i);
+   end;
+  LineEnd:=pc-(pchar(Buffer)+Gaplen);
+end; { TEditor.LineEnd }
+
+
+function TEditor.LineMove (P : Sw_Word; Count : Sw_Integer) : Sw_Word;
+VAR
+  Pos : Sw_Integer;
+  I   : Sw_Word;
+begin
+  I := P;
+  P := LineStart (P);
+  Pos := CharPos (P, I);
+  while Count <> 0 do
+   begin
+     I := P;
+     if Count < 0 then
+       begin
+         P := PrevLine (P);
+         Inc (Count);
+       end
+     else
+       begin
+         P := NextLine (P);
+         Dec (Count);
+       end;
+   end;
+  if P <> I then
+    P := CharPtr (P, Pos);
+  LineMove := P;
+end; { TEditor.LineMove }
+
+
+function TEditor.LineStart (P : Sw_Word) : Sw_Word;
+var
+  i  : Sw_word;
+  start,pc : pchar;
+  oc : char;
+begin
+  if P>CurPtr then
+   begin
+     start:=pchar(Buffer)+GapLen;
+     pc:=start;
+     i:=P-CurPtr;
+     dec(pc);
+     while (i>0) do
+      begin
+        if pc^ in [#10,#13] then
+         break;
+        dec(pc);
+        dec(i);
+      end;
+   end
+  else
+   i:=0;
+  if i=0 then
+   begin
+     start:=pchar(Buffer);
+     i:=P;
+     pc:=start+p;
+     dec(pc);
+     while (i>0) do
+      begin
+        if pc^ in [#10,#13] then
+         break;
+        dec(pc);
+        dec(i);
+      end;
+     if i=0 then
+      begin
+        LineStart:=0;
+        exit;
+      end;
+   end;
+  oc:=pc^;
+  LineStart:=pc-start+1;
+end; { TEditor.LineStart }
+
+
+function TEditor.LineNr (P : Sw_Word) : Sw_Word;
+var
+  pc,endp : pchar;
+  lines : sw_word;
+begin
+  endp:=pchar(Buffer)+BufPtr(P);
+  pc:=pchar(Buffer);
+  lines:=0;
+  while (pc<endp) do
+   begin
+     if pc^ in [#10,#13] then
+      begin
+        inc(lines);
+        if ord((pc+1)^)+ord(pc^)=23 then
+         begin
+           inc(pc);
+           if (pc>=endp) then
+            break;
+         end;
+      end;
+     inc(pc);
+   end;
+  LineNr:=Lines;
+end;
+
+
+procedure TEditor.Lock;
+begin
+  Inc (LockCount);
+end; { TEditor.Lock }
+
+
+function TEditor.NewLine (Select_Mode : Byte) : Boolean;
+VAR
+  I : Sw_Word;          { Used to track spaces for AutoIndent.                 }
+  P : Sw_Word;          { Position of Cursor when we arrive and after Newline. }
+begin
+  P := LineStart (CurPtr);
+  I := P;
+  { The first thing we do is remove any End Of Line spaces.  }
+  { Then we check to see how many spaces are on beginning    }
+  { of a line.   We need this check to add them after CR/LF  }
+  { if AutoIndenting.  Last of all we insert spaces required }
+  { for the AutoIndenting, if it was on.                     }
+  Remove_EOL_Spaces (Select_Mode);
+  while (I < CurPtr) and ((Buffer^[I] in [#9,' '])) do
+    Inc (I);
+  if InsertText (@LineBreak[1], length(LineBreak), False) = FALSE then
+    exit;
+  if AutoIndent then
+    InsertText (@Buffer^[P], I - P, False);
+  { Remember where the CurPtr is at this moment.     }
+  { Remember the length of the buffer at the moment. }
+  { Go to the previous line and remove EOL spaces.   }
+  { Once removed, re-set the cursor to where we were }
+  { minus any spaces that might have been removed.   }
+  I := BufLen;
+  P := CurPtr;
+  SetCurPtr (LineMove (CurPtr, - 1), Select_Mode);
+  Remove_EOL_Spaces (Select_Mode);
+  if I - BufLen <> 0 then
+    SetCurPtr (P - (I - BufLen), Select_Mode)
+  else
+    SetCurPtr (P, Select_Mode);
+  NewLine:=true;
+end; { TEditor.NewLine }
+
+
+function TEditor.NextChar (P : Sw_Word) : Sw_Word;
+var
+  pc : pchar;
+begin
+  if P<>BufLen then
+   begin
+     inc(P);
+     if P<>BufLen then
+      begin
+        pc:=pchar(Buffer);
+        if P>=CurPtr then
+         inc(pc,GapLen);
+        inc(pc,P-1);
+        if ord(pc^)+ord((pc+1)^)=23 then
+         inc(p);
+      end;
+   end;
+  NextChar:=P;
+end; { TEditor.NextChar }
+
+
+function TEditor.NextLine (P : Sw_Word) : Sw_Word;
+begin
+  NextLine := NextChar (LineEnd (P));
+end; { TEditor.NextLine }
+
+
+function TEditor.NextWord (P : Sw_Word) : Sw_Word;
+begin
+  { skip word }
+  while (P < BufLen) and (BufChar (P) in WordChars) do
+    P := NextChar (P);
+  { skip spaces }
+  while (P < BufLen) and not (BufChar (P) in WordChars) do
+    P := NextChar (P);
+  NextWord := P;
+end; { TEditor.NextWord }
+
+
+function TEditor.PrevChar (P : Sw_Word) : Sw_Word;
+var
+  pc : pchar;
+begin
+  if p<>0 then
+   begin
+     dec(p);
+     if p<>0 then
+      begin
+        pc:=pchar(Buffer);
+        if P>=CurPtr then
+         inc(pc,GapLen);
+        inc(pc,P-1);
+        if ord(pc^)+ord((pc+1)^)=23 then
+         dec(p);
+      end;
+   end;
+  PrevChar:=P;
+end; { TEditor.PrevChar }
+
+
+function TEditor.PrevLine (P : Sw_Word) : Sw_Word;
+begin
+  PrevLine := LineStart (PrevChar (P));
+end; { TEditor.PrevLine }
+
+
+function TEditor.PrevWord (P : Sw_Word) : Sw_Word;
+begin
+  { skip spaces }
+  while (P > 0) and not (BufChar (PrevChar (P)) in WordChars) do
+    P := PrevChar (P);
+  { skip word }
+  while (P > 0) and (BufChar (PrevChar (P)) in WordChars) do
+    P := PrevChar (P);
+  PrevWord := P;
+end; { TEditor.PrevWord }
+
+
+procedure TEditor.Reformat_Document (Select_Mode : Byte; Center_Cursor : Boolean);
+{ This procedure will do a reformat of the entire document, or just    }
+{ from the current line to the end of the document, if ^QU is pressed. }
+{ It simply brings up the correct dialog box, and then calls the       }
+{ TEditor.Reformat_Paragraph procedure to do the actual reformatting.  }
+CONST
+  efCurrentLine   = $0000;  { Radio button #1 selection for dialog box.  }
+  efWholeDocument = $0001;  { Radio button #2 selection for dialog box.  }
+VAR
+  Reformat_Options : Word;  { Holds the dialog options for reformatting. }
+begin
+  { Check if Word_Wrap is toggled on.  If NOT on, check if programmer }
+  { allows reformatting of document and if not show user dialog that  }
+  { says reformatting is not permissable.                             }
+  if not Word_Wrap then
+    begin
+      if not Allow_Reformat then
+        begin
+          EditorDialog (edReformatNotAllowed, nil);
+          Exit;
+        end;
+      Word_Wrap := True;
+      Update (ufStats);
+    end;
+  { Default radio button option to 1st one.  Bring up dialog box. }
+  Reformat_Options := efCurrentLine;
+  if EditorDialog (edReformatDocument, @Reformat_Options) <> cmCancel then
+    begin
+      { If the option to reformat the whole document was selected   }
+      { we need to go back to start of document.  Otherwise we stay }
+      { on the current line.  Call Reformat_Paragraph until we get  }
+      { to the end of the document to do the reformatting.          }
+      if Reformat_Options and efWholeDocument <> 0 then
+        SetCurPtr (0, Select_Mode);
+      Unlock;
+      repeat
+        Lock;
+        if NOT Reformat_Paragraph (Select_Mode, Center_Cursor) then
+          Exit;
+        TrackCursor (False);
+        Unlock;
+      until CurPtr = BufLen;
+    end;
+end; { TEditor.Reformat_Document }
+
+
+function TEditor.Reformat_Paragraph (Select_Mode   : Byte;
+                                     Center_Cursor : Boolean) : Boolean;
+{ This procedure will do a reformat of the current paragraph if ^B pressed. }
+{ The feature works regardless if wordrap is on or off.  It also supports   }
+{ the AutoIndent feature.  Reformat is not possible if the CurPos exceeds   }
+{ the Right_Margin.  Right_Margin is where the EOL is considered to be.     }
+CONST
+  Space : array [1..2] of Char = #32#32;
+VAR
+  C : Sw_Word;  { Position of CurPtr when we come into procedure. }
+  E : Sw_Word;  { End of a line.                                  }
+  S : Sw_Word;  { Start of a line.                                }
+begin
+  Reformat_Paragraph := False;
+  { Check if Word_Wrap is toggled on.  If NOT on, check if programmer }
+  { allows reformatting of paragraph and if not show user dialog that }
+  { says reformatting is not permissable.                             }
+  if not Word_Wrap then
+    begin
+      if not Allow_Reformat then
+        begin
+          EditorDialog (edReformatNotAllowed, nil);
+          Exit;
+        end;
+      Word_Wrap := True;
+      Update (ufStats);
+    end;
+  C := CurPtr;
+  E := LineEnd (CurPtr);
+  S := LineStart (CurPtr);
+  { Reformat possible only if current line is NOT blank! }
+  if E <> S then
+    begin
+      { Reformat is NOT possible if the first word }
+      { on the line is beyond the Right_Margin.    }
+      S := LineStart (CurPtr);
+      if NextWord (S) - S >= Right_Margin - 1 then
+        begin
+          EditorDialog (edReformNotPossible, nil);
+          Exit;
+        end;
+      { First objective is to find the first blank line }
+      { after this paragraph so we know when to stop.   }
+      { That could be the end of the document.          }
+      Repeat
+        SetCurPtr (LineMove (CurPtr, 1), Select_Mode);
+        E := LineEnd (CurPtr);
+        S := LineStart (CurPtr);
+        BlankLine := E;
+      until ((CurPtr = BufLen) or (E = S));
+      SetCurPtr (C, Select_Mode);
+      repeat
+        { Set CurPtr to LineEnd and remove the EOL spaces. }
+        { Pull up the next line and remove its EOL space.  }
+        { First make sure the next line is not BlankLine!  }
+        { Insert spaces as required between the two lines. }
+        SetCurPtr (LineEnd (CurPtr), Select_Mode);
+        Remove_EOL_Spaces (Select_Mode);
+        if CurPtr <> Blankline - 2 then
+          DeleteRange (CurPtr, Nextword (CurPtr), True);
+        Remove_EOL_Spaces (Select_Mode);
+        case Buffer^[CurPtr-1] of
+          '!' : InsertText (@Space, 2, False);
+          '.' : InsertText (@Space, 2, False);
+          ':' : InsertText (@Space, 2, False);
+          '?' : InsertText (@Space, 2, False);
+        else
+          InsertText (@Space, 1, False);
+        end;
+        { Reset CurPtr to EOL.  While line length is > Right_Margin }
+        { go Do_Word_Wrap.  If wordrap failed, exit routine.        }
+        SetCurPtr (LineEnd (CurPtr), Select_Mode);
+        while LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin do
+          if not Do_Word_Wrap (Select_Mode, Center_Cursor) then
+              Exit;
+        { If LineEnd - LineStart > Right_Margin then set CurPtr    }
+        { to Right_Margin on current line.  Otherwise we set the   }
+        { CurPtr to LineEnd.  This gyration sets up the conditions }
+        { to test for time of loop exit.                           }
+        if LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin then
+          SetCurPtr (LineStart (CurPtr) + Right_Margin, Select_Mode)
+        else
+          SetCurPtr (LineEnd (CurPtr), Select_Mode);
+      until ((CurPtr >= BufLen) or (CurPtr >= BlankLine - 2));
+    end;
+  { If not at the end of the document reset CurPtr to start of next line. }
+  { This should be a blank line between paragraphs.                       }
+  if CurPtr < BufLen then
+    SetCurPtr (LineMove (CurPtr, 1), Select_Mode);
+  Reformat_Paragraph := True;
+end; { TEditor.Reformat_Paragraph }
+
+
+procedure TEditor.Remove_EOL_Spaces (Select_Mode : Byte);
+{ This procedure tests to see if there are consecutive spaces }
+{ at the end of a line (EOL).  If so, we delete all spaces    }
+{ after the last non-space character to the end of line.      }
+{ We then reset the CurPtr to where we ended up at.           }
+VAR
+  C : Sw_Word;           { Current pointer when we come into procedure. }
+  E : Sw_Word;           { End of line.                                 }
+  P : Sw_Word;           { Position of pointer at any given moment.     }
+  S : Sw_Word;           { Start of a line.                             }
+begin
+  C := CurPtr;
+  E := LineEnd (CurPtr);
+  P := E;
+  S := LineStart (CurPtr);
+  { Start at the end of a line and move towards the start. }
+  { Find first non-space character in that direction.      }
+  while (P > S) and (BufChar (PrevChar (P)) = #32) do
+    P := PrevChar (P);
+  { If we found any spaces then delete them. }
+  if P < E then
+    begin
+      SetSelect (P, E, True);
+      DeleteSelect;
+      Update_Place_Markers (0, E - P, P, E);
+    end;
+  { If C, our pointer when we came into this procedure, }
+  { is less than the CurPtr then reset CurPtr to C so   }
+  { cursor is where we started.  Otherwise, set it to   }
+  { the new CurPtr, for we have deleted characters.     }
+  if C < CurPtr then
+    SetCurPtr (C, Select_Mode)
+  else
+    SetCurPtr (CurPtr, Select_Mode);
+end; { TEditor.Remove_EOL_Spaces }
+
+
+procedure TEditor.Replace;
+VAR
+  ReplaceRec : TReplaceDialogRec;
+begin
+  with ReplaceRec do
+  begin
+    Find := FindStr;
+    Replace := ReplaceStr;
+    Options := Flags;
+    if EditorDialog (edReplace, @ReplaceRec) <> cmCancel then
+    begin
+      FindStr := Find;
+      ReplaceStr := Replace;
+      Flags := Options or efDoReplace;
+      DoSearchReplace;
+    end;
+  end;
+end; { TEditor.Replace }
+
+
+procedure TEditor.Scroll_Down;
+{ This procedure will scroll the screen up, and always keep      }
+{ the cursor on the CurPos.Y position, but not necessarily on    }
+{ the CurPos.X.  If CurPos.Y scrolls off the screen, the cursor  }
+{ will stay in the upper left corner of the screen.  This will   }
+{ simulate the same process in the IDE.  The CurPos.X coordinate }
+{ only messes up if we are on long lines and we then encounter   }
+{ a shorter or blank line beneath the current one as we scroll.  }
+{ In that case, it goes to the end of the new line.              }
+VAR
+  C : Sw_Word;           { Position of CurPtr when we enter procedure. }
+  P : Sw_Word;           { Position of CurPtr at any given time.       }
+  W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y).     }
+begin
+  { Remember current cursor position.  Remember current CurPos.Y position. }
+  { Now issue the equivalent of a [Ctrl]-[End] command so the cursor will  }
+  { go to the bottom of the current screen.  Reset the cursor to this new  }
+  { position and then send FALSE to TrackCursor so we fool it into         }
+  { incrementing Delta.Y by only +1.  If we didn't do this it would try    }
+  { to center the cursor on the screen by fiddling with Delta.Y.           }
+  C := CurPtr;
+  W.X := CurPos.Y;
+  P := LineMove (CurPtr, Delta.Y - CurPos.Y + Size.Y);
+  SetCurPtr (P, 0);
+  TrackCursor (False);
+  { Now remember where the new CurPos.Y is.  See if distance between new }
+  { CurPos.Y and old CurPos.Y are greater than the current screen size.  }
+  { If they are, we need to move cursor position itself down by one.     }
+  { Otherwise, send the cursor back to our original CurPtr.              }
+  W.Y := CurPos.Y;
+  if W.Y - W.X > Size.Y - 1 then
+    SetCurPtr (LineMove (C, 1), 0)
+  else
+    SetCurPtr (C, 0);
+end; { TEditor.Scroll_Down }
+
+
+procedure TEditor.Scroll_Up;
+{ This procedure will scroll the screen down, and always keep    }
+{ the cursor on the CurPos.Y position, but not necessarily on    }
+{ the CurPos.X.  If CurPos.Y scrolls off the screen, the cursor  }
+{ will stay in the bottom left corner of the screen.  This will  }
+{ simulate the same process in the IDE.  The CurPos.X coordinate }
+{ only messes up if we are on long lines and we then encounter   }
+{ a shorter or blank line beneath the current one as we scroll.  }
+{ In that case, it goes to the end of the new line.              }
+VAR
+  C : Sw_Word;           { Position of CurPtr when we enter procedure. }
+  P : Sw_Word;           { Position of CurPtr at any given time.       }
+  W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y).     }
+begin
+  { Remember current cursor position.  Remember current CurPos.Y position. }
+  { Now issue the equivalent of a [Ctrl]-[Home] command so the cursor will }
+  { go to the top of the current screen.  Reset the cursor to this new     }
+  { position and then send FALSE to TrackCursor so we fool it into         }
+  { decrementing Delta.Y by only -1.  If we didn't do this it would try    }
+  { to center the cursor on the screen by fiddling with Delta.Y.           }
+  C := CurPtr;
+  W.Y := CurPos.Y;
+  P := LineMove (CurPtr, -(CurPos.Y - Delta.Y + 1));
+  SetCurPtr (P, 0);
+  TrackCursor (False);
+  { Now remember where the new CurPos.Y is.  See if distance between new }
+  { CurPos.Y and old CurPos.Y are greater than the current screen size.  }
+  { If they are, we need to move the cursor position itself up by one.   }
+  { Otherwise, send the cursor back to our original CurPtr.              }
+  W.X := CurPos.Y;
+  if W.Y - W.X > Size.Y - 1 then
+    SetCurPtr (LineMove (C, -1), 0)
+  else
+    SetCurPtr (C, 0);
+end; { TEditor.Scroll_Up }
+
+
+procedure TEditor.ScrollTo (X, Y : Sw_Integer);
+begin
+  X := Max (0, Min (X, Limit.X - Size.X));
+  Y := Max (0, Min (Y, Limit.Y - Size.Y));
+  if (X <> Delta.X) or (Y <> Delta.Y) then
+  begin
+    Delta.X := X;
+    Delta.Y := Y;
+    Update (ufView);
+  end;
+end; { TEditor.ScrollTo }
+
+
+function TEditor.Search (const FindStr : String; Opts : Word) : Boolean;
+VAR
+  I,Pos : Sw_Word;
+begin
+  Search := False;
+  Pos := CurPtr;
+  repeat
+    if Opts and efCaseSensitive <> 0 then
+      I := Scan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr)
+    else
+      I := IScan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr);
+    if (I <> sfSearchFailed) then
+    begin
+      Inc (I, Pos);
+      if (Opts and efWholeWordsOnly = 0) or
+         not (((I <> 0) and (BufChar (I - 1) in WordChars)) or
+              ((I + Length (FindStr) <> BufLen) and
+               (BufChar (I + Length (FindStr)) in WordChars))) then
+        begin
+          Lock;
+          SetSelect (I, I + Length (FindStr), False);
+          TrackCursor (not CursorVisible);
+          Unlock;
+          Search := True;
+          Exit;
+        end
+      else
+        Pos := I + 1;
+    end;
+  until I = sfSearchFailed;
+end; { TEditor.Search }
+
+
+procedure TEditor.Select_Word;
+{ This procedure will select the a word to put into the clipboard.   }
+{ I've added it just to maintain compatibility with the IDE editor.  }
+{ Note that selection starts at the current cursor position and ends }
+{ when a space or the end of line is encountered.                    }
+VAR
+  E : Sw_Word;         { End of the current line.                           }
+  Select_Mode : Byte;  { Allows us to turn select mode on inside procedure. }
+begin
+  E := LineEnd (CurPtr);
+  { If the cursor is on a space or at the end of a line, abort. }
+  { Stupid action on users part for you can't select blanks!    }
+  if (BufChar (CurPtr) = #32) or (CurPtr = E) then
+    Exit;
+  { Turn on select mode and tell editor to start selecting text. }
+  { As long as we have a character > a space (this is done to    }
+  { exclude CR/LF pairs at end of a line) and we are NOT at the  }
+  { end of a line, set the CurPtr to the next character.         }
+  { Once we find a space or CR/LF, selection is done and we      }
+  { automatically put the selected word into the Clipboard.      }
+  Select_Mode := smExtend;
+  StartSelect;
+  while (BufChar (NextChar (CurPtr)) > #32) and (CurPtr < E) do
+    SetCurPtr (NextChar (CurPtr), Select_Mode);
+  SetCurPtr (NextChar (CurPtr), Select_Mode);
+  ClipCopy;
+end; {TEditor.Select_Word }
+
+
+procedure TEditor.SetBufLen (Length : Sw_Word);
+begin
+  BufLen := Length;
+  GapLen := BufSize - Length;
+  SelStart := 0;
+  SelEnd := 0;
+  CurPtr := 0;
+  CurPos.X:=0;
+  CurPos.Y:=0;
+  Delta.X:=0;
+  Delta.Y:=0;
+  GetLimits(Buffer^[GapLen], BufLen,Limit);
+  inc(Limit.X);
+  inc(Limit.Y);
+  DrawLine := 0;
+  DrawPtr := 0;
+  DelCount := 0;
+  InsCount := 0;
+  Modified := False;
+  Update (ufView);
+end; { TEditor.SetBufLen }
+
+
+function TEditor.SetBufSize (NewSize : Sw_Word) : Boolean;
+begin
+  SetBufSize := NewSize <= BufSize;
+end; { TEditor.SetBufSize }
+
+
+procedure TEditor.SetCmdState (Command : Word; Enable : Boolean);
+VAR
+  S : TCommandSet;
+begin
+  S := [Command];
+  if Enable and (State and sfActive <> 0) then
+    EnableCommands (S)
+  else
+    DisableCommands (S);
+end; { TEditor.SetCmdState }
+
+
+procedure TEditor.SetCurPtr (P : Sw_Word; SelectMode : Byte);
+VAR
+  Anchor : Sw_Word;
+begin
+  if SelectMode and smExtend = 0 then
+    Anchor := P
+  else
+    if CurPtr = SelStart then
+      Anchor := SelEnd
+    else
+      Anchor := SelStart;
+  if P < Anchor then
+    begin
+      if SelectMode and smDouble <> 0 then
+      begin
+        P := PrevLine (NextLine (P));
+        Anchor := NextLine (PrevLine (Anchor));
+      end;
+      SetSelect (P, Anchor, True);
+    end
+  else
+    begin
+      if SelectMode and smDouble <> 0 then
+      begin
+        P := NextLine (P);
+        Anchor := PrevLine (NextLine (Anchor));
+      end;
+      SetSelect (Anchor, P, False);
+    end;
+end; { TEditor.SetCurPtr }
+
+
+procedure TEditor.Set_Place_Marker (Element : Byte);
+{ This procedure sets a place marker for the CurPtr if ^K# is pressed. }
+begin
+  if not IsClipboard then
+    Place_Marker[Element] := CurPtr;
+end; { TEditor.Set_Place_Marker }
+
+
+procedure TEditor.Set_Right_Margin;
+{ This procedure will bring up a dialog box }
+{ that allows the user to set Right_Margin. }
+{ Values must be < MaxLineLength and > 9.   }
+VAR
+  Code        : Integer;          { Used for Val conversion.      }
+  Margin_Data : TRightMarginRec;  { Holds dialog results.         }
+  Temp_Value  : Sw_Integer;       { Holds converted dialog value. }
+begin
+  with Margin_Data do
+    begin
+      Str (Right_Margin, Margin_Position);
+      if EditorDialog (edRightMargin, @Margin_Position) <> cmCancel then
+        begin
+          val (Margin_Position, Temp_Value, Code);
+          if (Temp_Value <= MaxLineLength) and (Temp_Value > 9) then
+            Right_Margin := Temp_Value;
+        end;
+    end;
+end; { TEditor.Set_Right_Margin }
+
+
+procedure TEditor.SetSelect (NewStart, NewEnd : Sw_Word; CurStart : Boolean);
+VAR
+  UFlags : Byte;
+  P     : Sw_Word;
+  L     : Sw_Word;
+begin
+  if CurStart then
+    P := NewStart
+  else
+    P := NewEnd;
+  UFlags := ufUpdate;
+  if (NewStart <> SelStart) or (NewEnd <> SelEnd) then
+    if (NewStart <> NewEnd) or (SelStart <> SelEnd) then
+      UFlags := ufView;
+  if P <> CurPtr then
+  begin
+    if P > CurPtr then
+      begin
+        L := P - CurPtr;
+        Move (Buffer^[CurPtr + GapLen], Buffer^[CurPtr], L);
+        Inc (CurPos.Y, CountLines (Buffer^[CurPtr], L));
+        CurPtr := P;
+      end
+    else
+      begin
+        L := CurPtr - P;
+        CurPtr := P;
+        Dec (CurPos.Y, CountLines (Buffer^[CurPtr], L));
+        Move (Buffer^[CurPtr], Buffer^[CurPtr + GapLen], L);
+      end;
+    DrawLine := CurPos.Y;
+    DrawPtr := LineStart (P);
+    CurPos.X := CharPos (DrawPtr, P);
+    DelCount := 0;
+    InsCount := 0;
+    SetBufSize (BufLen);
+  end;
+  SelStart := NewStart;
+  SelEnd := NewEnd;
+  Update (UFlags);
+end; { TEditor.Select }
+
+
+procedure TEditor.SetState (AState : Word; Enable : Boolean);
+begin
+  Inherited SetState (AState, Enable);
+  case AState of
+    sfActive: begin
+                      if assigned(HScrollBar) then
+                        HScrollBar^.SetState (sfVisible, Enable);
+                      if assigned(VScrollBar) then
+                        VScrollBar^.SetState (sfVisible, Enable);
+                      if assigned(Indicator) then
+                        Indicator^.SetState (sfVisible, Enable);
+                      UpdateCommands;
+                    end;
+    sfExposed: if Enable then Unlock;
+  end;
+end; { TEditor.SetState }
+
+
+procedure TEditor.Set_Tabs;
+{ This procedure will bring up a dialog box }
+{ that allows the user to set tab stops.    }
+VAR
+  Index    : Sw_Integer;   { Index into string array. }
+  Tab_Data : TTabStopRec;  { Holds dialog results.    }
+begin
+  with Tab_Data do
+    begin
+      { Assign current Tab_Settings to Tab_String.    }
+      { Bring up the tab dialog so user can set tabs. }
+      Tab_String := Copy (Tab_Settings, 1, Tab_Stop_Length);
+      if EditorDialog (edSetTabStops, @Tab_String) <> cmCancel then
+        begin
+          { If Tab_String comes back as empty then set Tab_Settings to nil. }
+          { Otherwise, find the last character in Tab_String that is not    }
+          { a space and copy Tab_String into Tab_Settings up to that spot.  }
+          if Length (Tab_String) = 0 then
+            begin
+              FillChar (Tab_Settings, SizeOf (Tab_Settings), #0);
+              Tab_Settings[0] := #0;
+              Exit;
+            end
+          else
+            begin
+              Index := Length (Tab_String);
+              while Tab_String[Index] <= #32 do
+                Dec (Index);
+              Tab_Settings := Copy (Tab_String, 1, Index);
+            end;
+        end;
+  end;
+end; { TEditor.Set_Tabs }
+
+
+procedure TEditor.StartSelect;
+begin
+  HideSelect;
+  Selecting := True;
+end; { TEditor.StartSelect }
+
+
+procedure TEditor.Store (var S : Objects.TStream);
+begin
+  Inherited Store (S);
+  PutPeerViewPtr (S, HScrollBar);
+  PutPeerViewPtr (S, VScrollBar);
+  PutPeerViewPtr (S, Indicator);
+  S.Write (BufSize, SizeOf (Sw_Word));
+  S.Write (Canundo, SizeOf (Boolean));
+  S.Write (AutoIndent,   SizeOf (AutoIndent));
+  S.Write (Line_Number,  SizeOf (Line_Number));
+  S.Write (Place_Marker, SizeOf (Place_Marker));
+  S.Write (Right_Margin, SizeOf (Right_Margin));
+  S.Write (Tab_Settings, SizeOf (Tab_Settings));
+  S.Write (Word_Wrap,    SizeOf (Word_Wrap));
+end; { Editor.Store }
+
+
+procedure TEditor.Tab_Key (Select_Mode : Byte);
+{ This function determines if we are in overstrike or insert mode,   }
+{ and then moves the cursor if overstrike, or adds spaces if insert. }
+VAR
+  E        : Sw_Word;                { End of current line.                }
+  Index    : Sw_Integer;             { Loop counter.                       }
+  Position : Sw_Integer;             { CurPos.X position.                  }
+  S        : Sw_Word;                { Start of current line.              }
+  Spaces   : array [1..80] of Char;  { Array to hold spaces for insertion. }
+begin
+  E := LineEnd (CurPtr);
+  S := LineStart (CurPtr);
+  { Find the current horizontal cursor position. }
+  { Now loop through the Tab_Settings string and }
+  { find the next available tab stop.            }
+  Position := CurPos.X + 1;
+  repeat
+    Inc (Position);
+  until (Tab_Settings[Position] <> #32) or (Position >= Ord (Tab_Settings[0]));
+  E := CurPos.X;
+  Index := 1;
+  { Now we enter a loop to go to the next tab position.  }
+  { If we are in overwrite mode, we just move the cursor }
+  { through the text to the next tab stop.  If we are in }
+  { insert mode, we add spaces to the Spaces array for   }
+  { the number of times we loop.                         }
+  while Index < Position - E do
+    begin
+      if Overwrite then
+        begin
+          if (Position > LineEnd (CurPtr) - LineStart (CurPtr))
+              or (Position > Ord (Tab_Settings[0])) then
+            begin
+              SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode);
+              Exit;
+            end
+          else
+            if CurPtr < BufLen then
+              SetCurPtr (NextChar (CurPtr), Select_Mode);
+        end
+      else
+        begin
+          if (Position > Right_Margin) or (Position > Ord (Tab_Settings[0])) then
+            begin
+              SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode);
+              Exit;
+            end
+          else
+            Spaces[Index] := #32;
+        end;
+      Inc (Index);
+  end;
+  { If we are insert mode, we insert spaces to the next tab stop.        }
+  { When we're all done, the cursor will be sitting on the new tab stop. }
+  if not OverWrite then
+    InsertText (@Spaces, Index - 1, False);
+end; { TEditor.Tab_Key }
+
+
+procedure TEditor.ToggleInsMode;
+begin
+  Overwrite := not Overwrite;
+  SetState (sfCursorIns, not GetState (sfCursorIns));
+end; { TEditor.ToggleInsMode }
+
+
+procedure TEditor.TrackCursor (Center : Boolean);
+begin
+  if Center then
+    ScrollTo (CurPos.X - Size.X + 1, CurPos.Y - Size.Y div 2)
+  else
+    ScrollTo (Max (CurPos.X - Size.X + 1, Min (Delta.X, CurPos.X)),
+              Max (CurPos.Y - Size.Y + 1, Min (Delta.Y, CurPos.Y)));
+end; { TEditor.TrackCursor }
+
+
+procedure TEditor.Undo;
+VAR
+  Length : Sw_Word;
+begin
+  if (DelCount <> 0) or (InsCount <> 0) then
+  begin
+    Update_Place_Markers (DelCount, 0, CurPtr, CurPtr + DelCount);
+    SelStart := CurPtr - InsCount;
+    SelEnd := CurPtr;
+    Length := DelCount;
+    DelCount := 0;
+    InsCount := 0;
+    InsertBuffer (Buffer, CurPtr + GapLen - Length, Length, False, True);
+  end;
+end; { TEditor.Undo }
+
+
+procedure TEditor.Unlock;
+begin
+  if LockCount > 0 then
+  begin
+    Dec (LockCount);
+    if LockCount = 0 then
+      DoUpdate;
+  end;
+end; { TEditor.Unlock }
+
+
+procedure TEditor.Update (AFlags : Byte);
+begin
+  UpdateFlags := UpdateFlags or AFlags;
+  if LockCount = 0 then
+    DoUpdate;
+end; { TEditor.Update }
+
+
+procedure TEditor.UpdateCommands;
+begin
+  SetCmdState (cmUndo, (DelCount <> 0) or (InsCount <> 0));
+  if not IsClipboard then
+    begin
+      SetCmdState (cmCut, HasSelection);
+      SetCmdState (cmCopy, HasSelection);
+      SetCmdState (cmPaste, assigned(Clipboard) and (Clipboard^.HasSelection));
+    end;
+  SetCmdState (cmClear, HasSelection);
+  SetCmdState (cmFind, True);
+  SetCmdState (cmReplace, True);
+  SetCmdState (cmSearchAgain, True);
+end; { TEditor.UpdateCommands }
+
+
+procedure TEditor.Update_Place_Markers (AddCount : Word; KillCount : Word;
+                                        StartPtr,EndPtr : Sw_Word);
+{ This procedure updates the position of the place markers }
+{ as the user inserts and deletes text in the document.    }
+VAR
+  Element : Byte;     { Place_Marker array element to traverse array with. }
+begin
+  for Element := 1 to 10 do
+    begin
+      if AddCount > 0 then
+        begin
+          if (Place_Marker[Element] >= Curptr)
+              and (Place_Marker[Element] <> 0) then
+            Place_Marker[Element] := Place_Marker[Element] + AddCount;
+        end
+      else
+        begin
+          if Place_Marker[Element] >= StartPtr then
+            begin
+              if (Place_Marker[Element] >= StartPtr) and
+                 (Place_Marker[Element] < EndPtr) then
+                Place_marker[Element] := 0
+              else
+                begin
+                  if integer (Place_Marker[Element]) - integer (KillCount) > 0 then
+                    Place_Marker[Element] := Place_Marker[Element] - KillCount
+                  else
+                    Place_Marker[Element] := 0;
+                end;
+            end;
+        end;
+    end;
+  if AddCount > 0 then
+    BlankLine := BlankLine + AddCount
+  else
+    begin
+      if integer (BlankLine) - Integer (KillCount) > 0 then
+        BlankLine := BlankLine - KillCount
+      else
+        BlankLine := 0;
+    end;
+end; { TEditor.Update_Place_Markers }
+
+
+function TEditor.Valid (Command : Word) : Boolean;
+begin
+  Valid := IsValid;
+end; { TEditor.Valid }
+
+
+{****************************************************************************
+                                   TMEMO
+****************************************************************************}
+
+constructor TMemo.Load (var S : Objects.TStream);
+VAR
+  Length : Sw_Word;
+begin
+  Inherited Load (S);
+  S.Read (Length, SizeOf (Sw_Word));
+  if IsValid then
+    begin
+      S.Read (Buffer^[BufSize - Length], Length);
+      SetBufLen (Length);
+    end
+  else
+    S.Seek (S.GetPos + Length);
+end; { TMemo.Load }
+
+
+function TMemo.DataSize : Sw_Word;
+begin
+  DataSize := BufSize + SizeOf (Sw_Word);
+end; { TMemo.DataSize }
+
+
+procedure TMemo.GetData (var Rec);
+VAR
+  Data : TMemoData absolute Rec;
+begin
+  Data.Length := BufLen;
+  Move (Buffer^, Data.Buffer, CurPtr);
+  Move (Buffer^[CurPtr + GapLen], Data.Buffer[CurPtr], BufLen - CurPtr);
+  FillChar (Data.Buffer[BufLen], BufSize - BufLen, 0);
+end; { TMemo.GetData }
+
+
+function TMemo.GetPalette : PPalette;
+CONST
+  P : String[Length (CMemo)] = CMemo;
+begin
+  GetPalette := @P;
+end; { TMemo.GetPalette }
+
+
+procedure TMemo.HandleEvent (var Event : Drivers.TEvent);
+begin
+  if (Event.What <> Drivers.evKeyDown) or (Event.KeyCode <> Drivers.kbTab) then
+    Inherited HandleEvent (Event);
+end; { TMemo.HandleEvent }
+
+
+procedure TMemo.SetData (var Rec);
+VAR
+  Data : TMemoData absolute Rec;
+begin
+  Move (Data.Buffer, Buffer^[BufSize - Data.Length], Data.Length);
+  SetBufLen (Data.Length);
+end; { TMemo.SetData }
+
+
+procedure TMemo.Store (var S : Objects.TStream);
+begin
+  Inherited Store (S);
+  S.Write (BufLen, SizeOf (Sw_Word));
+  S.Write (Buffer^, CurPtr);
+  S.Write (Buffer^[CurPtr + GapLen], BufLen - CurPtr);
+end; { TMemo.Store }
+
+
+{****************************************************************************
+                               TFILEEDITOR
+****************************************************************************}
+
+
+constructor TFileEditor.Init (var Bounds : TRect;
+                              AHScrollBar, AVScrollBar : PScrollBar;
+                              AIndicator : PIndicator;
+                              AFileName  : FNameStr);
+begin
+  Inherited Init (Bounds, AHScrollBar, AVScrollBar, AIndicator, 0);
+  if AFileName <> '' then
+    begin
+      FileName := FExpand (AFileName);
+      if IsValid then
+        IsValid := LoadFile;
+    end;
+end; { TFileEditor.Init }
+
+
+constructor TFileEditor.Load (var S : Objects.TStream);
+VAR
+  SStart,SEnd,Curs : Sw_Word;
+begin
+  Inherited Load (S);
+  BufSize := 0;
+  S.Read (FileName[0], SizeOf (Char));
+  S.Read (Filename[1], Length (FileName));
+  if IsValid then
+    IsValid := LoadFile;
+  S.Read (SStart, SizeOf (Sw_Word));
+  S.Read (SEnd, SizeOf (Sw_Word));
+  S.Read (Curs, SizeOf (Sw_Word));
+  if IsValid and (SEnd <= BufLen) then
+    begin
+      SetSelect (SStart, SEnd, Curs = SStart);
+      TrackCursor (True);
+    end;
+end; { TFileEditor.Load }
+
+
+procedure TFileEditor.DoneBuffer;
+begin
+  if assigned(Buffer) then
+    DisposeBuffer (Buffer);
+end; { TFileEditor.DoneBuffer }
+
+
+procedure TFileEditor.HandleEvent (var Event : Drivers.TEvent);
+begin
+  Inherited HandleEvent (Event);
+  case Event.What of
+    Drivers.evCommand:
+      case Event.Command of
+        cmSave   : Save;
+        cmSaveAs : SaveAs;
+        cmSaveDone : if Save then
+                       Message (Owner, Drivers.evCommand, cmClose, nil);
+      else
+        Exit;
+      end;
+  else
+    Exit;
+  end;
+  ClearEvent (Event);
+end; { TFileEditor.HandleEvent }
+
+
+procedure TFileEditor.InitBuffer;
+begin
+  NewBuffer(Pointer(Buffer), MinBufLength);
+end; { TFileEditor.InitBuffer }
+
+
+function TFileEditor.LoadFile: Boolean;
+VAR
+  Length : Sw_Word;
+  FSize : Longint;
+  FRead : Sw_Integer;
+  F : File;
+begin
+  LoadFile := False;
+  Length := 0;
+  Assign(F, FileName);
+  Reset(F, 1);
+  if IOResult <> 0 then
+    EditorDialog(edReadError, @FileName)
+  else
+    begin
+      FSize := FileSize(F);
+      if (FSize > MaxBufLength) or not SetBufSize(FSize) then
+        EditorDialog(edOutOfMemory, nil)
+      else
+        begin
+          BlockRead(F, Buffer^[BufSize-FSize], FSize, FRead);
+          if (IOResult <> 0) or (FRead<>FSize) then
+            EditorDialog(edReadError, @FileName)
+          else
+            begin
+              LoadFile := True;
+              Length := FRead;
+            end;
+        end;
+      Close(F);
+    end;
+  SetBufLen(Length);
+end; { TFileEditor.LoadFile }
+
+
+function TFileEditor.Save : Boolean;
+begin
+  if FileName = '' then
+    Save := SaveAs
+  else
+    Save := SaveFile;
+end; { TFileEditor.Save }
+
+
+function TFileEditor.SaveAs : Boolean;
+begin
+  SaveAs := False;
+  if EditorDialog (edSaveAs, @FileName) <> cmCancel then
+  begin
+    FileName := FExpand (FileName);
+    Message (Owner, Drivers.evBroadcast, cmUpdateTitle, nil);
+    SaveAs := SaveFile;
+    if IsClipboard then
+      FileName := '';
+  end;
+end; { TFileEditor.SaveAs }
+
+
+function TFileEditor.SaveFile : Boolean;
+VAR
+  F          : File;
+  BackupName : Objects.FNameStr;
+  D          : DOS.DirStr;
+  N          : DOS.NameStr;
+  E          : DOS.ExtStr;
+begin
+  SaveFile := False;
+  if Flags and efBackupFiles <> 0 then
+  begin
+    FSplit (FileName, D, N, E);
+    BackupName := D + N + '.bak';
+    Assign (F, BackupName);
+    Erase (F);
+    Assign (F, FileName);
+    Rename (F, BackupName);
+    InOutRes := 0;
+  end;
+  Assign (F, FileName);
+  Rewrite (F, 1);
+  if IOResult <> 0 then
+    EditorDialog (edCreateError, @FileName)
+  else
+    begin
+      BlockWrite (F, Buffer^, CurPtr);
+      BlockWrite (F, Buffer^[CurPtr + GapLen], BufLen - CurPtr);
+      if IOResult <> 0 then
+        EditorDialog (edWriteError, @FileName)
+      else
+        begin
+          Modified := False;
+          Update (ufUpdate);
+          SaveFile := True;
+        end;
+        Close (F);
+   end;
+end; { TFileEditor.SaveFile }
+
+
+function TFileEditor.SetBufSize (NewSize : Sw_Word) : Boolean;
+VAR
+  N : Sw_Word;
+begin
+  SetBufSize := False;
+  if NewSize = 0 then
+    NewSize := MinBufLength
+  else
+    if NewSize > (MaxBufLength-MinBufLength) then
+      NewSize := MaxBufLength
+    else
+      NewSize := (NewSize + (MinBufLength-1)) and (MaxBufLength and (not (MinBufLength-1)));
+  if NewSize <> BufSize then
+   begin
+     if NewSize > BufSize then
+      if not SetBufferSize(pointer(Buffer), NewSize) then
+       Exit;
+     N := BufLen - CurPtr + DelCount;
+     Move(Buffer^[BufSize - N], Buffer^[NewSize - N], N);
+     if NewSize < BufSize then
+       SetBufferSize(pointer(Buffer), NewSize);
+     BufSize := NewSize;
+     GapLen := BufSize - BufLen;
+   end;
+  SetBufSize := True;
+end; { TFileEditor.SetBufSize }
+
+
+procedure TFileEditor.Store (var S : Objects.TStream);
+begin
+  Inherited Store (S);
+  S.Write (FileName, Length (FileName) + 1);
+  S.Write (SelStart, SizeOf (Sw_Word) * 3);
+end; { TFileEditor.Store }
+
+
+procedure TFileEditor.UpdateCommands;
+begin
+  Inherited UpdateCommands;
+  SetCmdState (cmSave, True);
+  SetCmdState (cmSaveAs, True);
+  SetCmdState (cmSaveDone, True);
+end; { TFileEditor.UpdateCommands }
+
+
+function TFileEditor.Valid (Command : Word) : Boolean;
+VAR
+  D : Integer;
+begin
+  if Command = cmValid then
+    Valid := IsValid
+  else
+    begin
+      Valid := True;
+      if Modified then
+        begin
+          if FileName = '' then
+            D := edSaveUntitled
+          else
+            D := edSaveModify;
+          case EditorDialog (D, @FileName) of
+            cmYes    : Valid := Save;
+            cmNo     : Modified := False;
+            cmCancel : Valid := False;
+          end;
+        end;
+    end;
+end; { TFileEditor.Valid }
+
+
+{****************************************************************************
+                             TEDITWINDOW
+****************************************************************************}
+
+constructor TEditWindow.Init (var Bounds   : TRect;
+                                  FileName : Objects.FNameStr;
+                                  ANumber  : Integer);
+var
+  HScrollBar : PScrollBar;
+  VScrollBar : PScrollBar;
+  Indicator  : PIndicator;
+  R          : TRect;
+begin
+  Inherited Init (Bounds, '', ANumber);
+  Options := Options or ofTileable;
+
+  R.Assign (18, Size.Y - 1, Size.X - 2, Size.Y);
+  HScrollBar := New (PScrollBar, Init (R));
+  HScrollBar^.Hide;
+  Insert (HScrollBar);
+
+  R.Assign (Size.X - 1, 1, Size.X, Size.Y - 1);
+  VScrollBar := New (PScrollBar, Init (R));
+  VScrollBar^.Hide;
+  Insert (VScrollBar);
+
+  R.Assign (2, Size.Y - 1, 16, Size.Y);
+  Indicator := New (PIndicator, Init (R));
+  Indicator^.Hide;
+  Insert (Indicator);
+
+  GetExtent (R);
+  R.Grow (-1, -1);
+  Editor := New (PFileEditor, Init (R, HScrollBar, VScrollBar, Indicator, FileName));
+  Insert (Editor);
+end; { TEditWindow.Init }
+
+
+constructor TEditWindow.Load (var S : Objects.TStream);
+begin
+  Inherited Load (S);
+  GetSubViewPtr (S, Editor);
+end; { TEditWindow.Load }
+
+
+procedure TEditWindow.Close;
+begin
+  if Editor^.IsClipboard then
+    Hide
+  else
+    Inherited Close;
+end; { TEditWindow.Close }
+
+
+function TEditWindow.GetTitle (MaxSize : Sw_Integer) : TTitleStr;
+begin
+  if Editor^.IsClipboard then
+    GetTitle := strings^.get(sClipboard)
+  else
+    if Editor^.FileName = '' then
+      GetTitle := strings^.get(sUntitled)
+    else
+      GetTitle := Editor^.FileName;
+end; { TEditWindow.GetTile }
+
+
+procedure TEditWindow.HandleEvent (var Event : Drivers.TEvent);
+begin
+  Inherited HandleEvent (Event);
+  if (Event.What = Drivers.evBroadcast) then
+    { and (Event.Command = cmUpdateTitle) then }
+    { Changed if statement above so I could test for cmBlugeonStats.       }
+    { Stats would not show up when loading a file until a key was pressed. }
+    case Event.Command of
+      cmUpdateTitle :
+        begin
+          Frame^.DrawView;
+          ClearEvent (Event);
+        end;
+      cmBludgeonStats :
+        begin
+          Editor^.Update (ufStats);
+          ClearEvent (Event);
+        end;
+    end;
+end; { TEditWindow.HandleEvent }
+
+
+procedure TEditWindow.SizeLimits(var Min, Max: TPoint);
+begin
+  inherited SizeLimits(Min, Max);
+  Min.X := 23;
+end;
+
+
+procedure TEditWindow.Store (var S : Objects.TStream);
+begin
+  Inherited Store (S);
+  PutSubViewPtr (S, Editor);
+end; { TEditWindow.Store }
+
+
+procedure RegisterEditors;
+begin
+  RegisterType (REditor);
+  RegisterType (RMemo);
+  RegisterType (RFileEditor);
+  RegisterType (RIndicator);
+  RegisterType (REditWindow);
+end; { RegisterEditors }
+
+
+end. { Unit NewEdit }

+ 189 - 0
fv/str.inc

@@ -0,0 +1,189 @@
+{ Strings }
+sButtonDefault = 1; { Button default }
+sButtonDisabled = 2; { Button disabled }
+sButtonNormal = 3; { Button normal }
+sButtonSelected = 4; { Button selected }
+sButtonShadow = 5; { Button shadow }
+sButtonShortcut = 6; { Button shortcut }
+sChangeDirectory = 7; { Change Directory }
+sClipboard = 8; { Clipboard }
+sClusterNormal = 9; { Cluster normal }
+sClusterSelected = 10; { Cluster selected }
+sClusterShortcut = 11; { Cluster shortcut }
+sColor = 12; { Color }
+sColors = 13; { Colors }
+sConfirm = 14; { Confirm }
+sDeleteFile = 15; { Delete file?#13#10#13#3%s }
+sDirectory = 16; { Directory }
+sDisabled = 17; { Disabled }
+sDrives = 18; { Drives }
+sError = 19; { Error }
+sFileAlreadyOpen = 20; { #3%s#13#10#13#3is already open in window %d. }
+sFileCreateError = 21; { Error creating file %s }
+sFileReadError = 22; { Error reading file %s }
+sFileUntitled = 23; { Save untitled file? }
+sFileWriteError = 24; { Error writing to file %s }
+sFind = 25; { Find }
+sFrameActive = 26; { Frame active }
+sFrameBackground = 27; { Frame/background }
+sFrameIcons = 28; { Frame icons }
+sFramePassive = 29; { Frame passive }
+sHighlight = 30; { Highlight }
+sHistoryBarIcons = 31; { History bar icons }
+sHistoryBarPage = 32; { History bar page }
+sHistoryButton = 33; { History button }
+sHistorySides = 34; { History sides }
+sInformation = 35; { Information }
+sInformationPane = 36; { Information pane }
+sInputArrow = 37; { Input arrow }
+sInputNormal = 38; { Input normal }
+sInputSelected = 39; { Input selected }
+sInvalidCharacter = 40; { Invalid character in input }
+sInvalidDirectory = 41; { Invalid directory. }
+sInvalidDriveOrDir = 42; { Invalid drive or directory. }
+sInvalidFileName = 43; { Invalid file name. }
+sInvalidPicture = 44; { Input does not conform to picture: %s }
+sInvalidValue = 45; { Value not in the range %d to %d }
+sInverse = 46; { Inverse }
+sJumpTo = 47; { Jump To }
+sLabelNormal = 48; { Label normal }
+sLabelSelected = 49; { Label selected }
+sLabelShortcut = 50; { Label shortcut }
+sListDivider = 51; { List divider }
+sListFocused = 52; { List focused }
+sListNormal = 53; { List normal }
+sListSelected = 54; { List selected }
+sModified = 55; { #3%s#13#10#13#3has been modified.  Save? }
+sNoName = 56; { NONAME }
+sNormal = 57; { Normal }
+sNormalText = 58; { Normal text }
+sNotInList = 59; { Input not in valid-list }
+sOpen = 60; { Open }
+sOutOfMemory = 61; { Not enough memory for this operation. }
+sOutOfUnNamedWindows = 62; { Out of unnamed window numbers.  Save or discard some unnamed files and try again. }
+sPasteNotPossible = 63; { Wordwrap on:  Paste not possible in current margins when at end of line. }
+sReformatDocument = 64; { Reformat Document }
+sReformatNotPossible = 65; { Paragraph reformat not possible while trying to wrap current line with current margins. }
+sReformattingTheDocument = 66; { Reformatting the document: }
+sReplace = 67; { Replace }
+sReplaceFile = 68; { Replace file?#13#10#13#3%s }
+sReplaceNotPossible = 69; { Wordwrap on:  Replace not possible in current margins when at end of line. }
+sReplaceThisOccurence = 70; { Replace this occurence? }
+sRightMargin = 71; { Right Margin }
+sSaveAs = 72; { Save As }
+sScrollbarIcons = 73; { Scroll bar icons }
+sScrollbarPage = 74; { Scroll bar page }
+sSearchStringNotFound = 75; { Search string not found. }
+sSelectFormatStart = 76; { Select Format Start }
+sSelectWhereToBegin = 77; { Please select where to begin. }
+sSelected = 78; { Selected }
+sSelectedDisabled = 79; { Selected disabled }
+sSetting = 80; { Setting: }
+sShortcut = 81; { Shortcut }
+sShortcutSelected = 82; { ShortcutSelected }
+sStaticText = 83; { Static text }
+sTabSettings = 84; { Tab Settings }
+sText = 85; { Text }
+sTooManyFiles = 86; { Too many files. }
+sTypeExitOnReturn = 87; { Type EXIT to return... }
+sUnderline = 88; { Underline }
+sUnknownDialog = 89; { Unknown dialog requested! }
+sUntitled = 90; { Untitled }
+sWarning = 91; { Warning }
+sWindowList = 92; { Window List }
+sWordWrapNotPossible = 93; { Wordwrap on:  Wordwrap not possible in current margins with continuous line. }
+sWordWrapOff = 94; { You must turn on wordwrap before you can reformat. }
+smApr = 95; { Apr }
+smAug = 96; { Aug }
+smDec = 97; { Dec }
+smFeb = 98; { Feb }
+smJan = 99; { Jan }
+smJul = 100; { Jul }
+smJun = 101; { Jun }
+smMar = 102; { Mar }
+smMay = 103; { May }
+smNov = 104; { Nov }
+smOct = 105; { Oct }
+smSep = 106; { Sep }
+{ Labels }
+slAbout = 107;  { ~A~bout }
+slAltF1 = 108;  { Alt+F1 }
+slAltF3Close = 109;  { ~Alt+F3~ Close }
+slAltXExit = 110; { ~Alt-X~ Exit }
+slBackground = 111; { ~B~ackground }
+slCancel = 112; { Cancel }
+slCascade = 113; { C~a~scade }
+slCaseSensitive = 114; { ~C~ase sensitive }
+slChDir = 115; { ~C~hdir }
+slChangeDir = 116; { ~C~hange dir... }
+slClear = 117; { C~l~ear }
+slClose = 118; { ~C~lose }
+slCloseAll = 119; { Cl~o~se all }
+slColor = 120; { ~C~olor }
+slContents = 121;  { ~C~ontents }
+slCopy = 122; { ~C~opy }
+slCtrlF1 = 123;  { Ctrl+F1 }
+slCurrentLine = 124; { ~C~urrent line }
+slCut = 125; { Cu~t~ }
+slDOSShell = 126; { ~D~OS shell }
+slDelete = 127; { ~D~elete }
+slDirectoryName = 128; { Directory ~n~ame }
+slDirectoryTree = 129; { Directory ~t~ree }
+slEdit = 130; { ~E~dit }
+slEntireDocument = 131; { ~E~ntire document }
+slExit = 132; { E~x~it }
+slF10Menu = 133; { ~F10~ Menu }
+slF1Help = 134; { ~F1~ Help }
+slF3Open = 135; { ~F3~ Open }
+slFile = 136; { ~F~ile }
+slFiles = 137; { ~F~iles }
+slForeground = 138; { ~F~oreground }
+slGroup = 139; { ~G~roup }
+slHelp = 140; { ~H~elp }
+slIndex = 141;  { ~I~ndex }
+slItem = 142; { ~I~tem }
+slLineNumber = 143; { ~L~ine number }
+slName = 144; { ~N~ame }
+slNew = 145; { ~N~ew }
+slNewText = 146; { ~N~ew text }
+slNext = 147; { ~N~ext }
+slNo = 148; { ~N~o }
+slOk = 149; { O~k~ }
+slOpen = 150; { ~O~pen }
+slOpenDots = 151; { ~O~pen... }
+slPaste = 152; { ~P~aste }
+slPrevious = 153; { ~P~revious }
+slPreviousTopic = 154;  { ~P~revious topic }
+slPromptOnReplace = 155; { ~P~rompt on replace }
+slReformatDocument = 156; { ~R~eformat document }
+slReplace = 157; { ~R~eplace }
+slReplaceAll = 158; { ~R~eplace all }
+slRevert = 159; { ~R~evert }
+slSave = 160; { ~S~ave }
+slSaveAll = 161; { Save a~l~l }
+slSaveAs = 162; { S~a~ve as... }
+slSaveFileAs = 163; { ~S~ave file as }
+slShiftF1 = 164;  { Shift+F1 }
+slSizeMove = 165; { ~S~ize/Move }
+slTextToFind = 166; { ~T~ext to find }
+slTile = 167; { ~T~ile }
+slTopicSearch = 168;  { ~T~opic search }
+slUndo = 169; { ~U~ndo }
+slUsingHelp = 170;  { ~U~sing help }
+slWholeWordsOnly = 171; { ~W~hole words only }
+slWindow = 172;  { ~W~indow }
+slWindows = 173; { ~W~indows }
+slYes = 174; { ~Y~es }
+slZoom = 175; { ~Z~oom }
+slAltF3 = 176; { Alt+F3 }
+slAltX = 177; { Alt+X }
+slF2 = 178; { F2 }
+slF3 = 179; { F3 }
+slF5 = 180; { F5 }
+slF6 = 181; { F6 }
+slCtrlDel = 182; { Ctrl+Del }
+slCtrlF5 = 183; { Ctrl+F5 }
+slCtrlIns = 184; { Ctrl+Ins }
+slShiftDel = 185; { Shift+Del }
+slShiftF6 = 186; { Shift+F6 }
+slShiftIns = 187; { Shift+Ins }

+ 194 - 0
fv/strtxt.inc

@@ -0,0 +1,194 @@
+procedure InitResStrings;
+begin
+  Strings^.Put(sButtonDefault,'Button default');
+  Strings^.Put(sButtonDisabled,'Button disabled');
+  Strings^.Put(sButtonNormal,'Button normal');
+  Strings^.Put(sButtonSelected,'Button selected');
+  Strings^.Put(sButtonShadow,'Button shadow');
+  Strings^.Put(sButtonShortcut,'Button shortcut');
+  Strings^.Put(sChangeDirectory,'Change Directory');
+  Strings^.Put(sClipboard,'Clipboard');
+  Strings^.Put(sClusterNormal,'Cluster normal');
+  Strings^.Put(sClusterSelected,'Cluster selected');
+  Strings^.Put(sClusterShortcut,'Cluster shortcut');
+  Strings^.Put(sColor,'Color');
+  Strings^.Put(sColors,'Colors');
+  Strings^.Put(sConfirm,'Confirm');
+  Strings^.Put(sDeleteFile,'Delete file?'#13#10#13#3'%s');
+  Strings^.Put(sDirectory,'Directory');
+  Strings^.Put(sDisabled,'Disabled');
+  Strings^.Put(sDrives,'Drives');
+  Strings^.Put(sError,'Error');
+  Strings^.Put(sFileAlreadyOpen,''#3'%s'#13#10#13#3'is already open in window %d.');
+  Strings^.Put(sFileCreateError,'Error creating file %s');
+  Strings^.Put(sFileReadError,'Error reading file %s');
+  Strings^.Put(sFileUntitled,'Save untitled file?');
+  Strings^.Put(sFileWriteError,'Error writing to file %s');
+  Strings^.Put(sFind,'Find');
+  Strings^.Put(sFrameActive,'Frame active');
+  Strings^.Put(sFrameBackground,'Frame/background');
+  Strings^.Put(sFrameIcons,'Frame icons');
+  Strings^.Put(sFramePassive,'Frame passive');
+  Strings^.Put(sHighlight,'Highlight');
+  Strings^.Put(sHistoryBarIcons,'History bar icons');
+  Strings^.Put(sHistoryBarPage,'History bar page');
+  Strings^.Put(sHistoryButton,'History button');
+  Strings^.Put(sHistorySides,'History sides');
+  Strings^.Put(sInformation,'Information');
+  Strings^.Put(sInformationPane,'Information pane');
+  Strings^.Put(sInputArrow,'Input arrow');
+  Strings^.Put(sInputNormal,'Input normal');
+  Strings^.Put(sInputSelected,'Input selected');
+  Strings^.Put(sInvalidCharacter,'Invalid character in input');
+  Strings^.Put(sInvalidDirectory,'Invalid directory.');
+  Strings^.Put(sInvalidDriveOrDir,'Invalid drive or directory.');
+  Strings^.Put(sInvalidFileName,'Invalid file name.');
+  Strings^.Put(sInvalidPicture,'Input does not conform to picture: %s');
+  Strings^.Put(sInvalidValue,'Value not in the range %d to %d');
+  Strings^.Put(sInverse,'Inverse');
+  Strings^.Put(sJumpTo,'Jump To');
+  Strings^.Put(sLabelNormal,'Label normal');
+  Strings^.Put(sLabelSelected,'Label selected');
+  Strings^.Put(sLabelShortcut,'Label shortcut');
+  Strings^.Put(sListDivider,'List divider');
+  Strings^.Put(sListFocused,'List focused');
+  Strings^.Put(sListNormal,'List normal');
+  Strings^.Put(sListSelected,'List selected');
+  Strings^.Put(sModified,''#3'%s'#13#10#13#3'has been modified.  Save?');
+  Strings^.Put(sNoName,'NONAME');
+  Strings^.Put(sNormal,'Normal');
+  Strings^.Put(sNormalText,'Normal text');
+  Strings^.Put(sNotInList,'Input not in valid-list');
+  Strings^.Put(sOpen,'Open');
+  Strings^.Put(sOutOfMemory,'Not enough memory for this operation.');
+  Strings^.Put(sOutOfUnNamedWindows,'Out of unnamed window numbers.  Save or discard some unnamed files and try again.');
+  Strings^.Put(sPasteNotPossible,'Wordwrap on:  Paste not possible in current margins when at end of line.');
+  Strings^.Put(sReformatDocument,'Reformat Document');
+  Strings^.Put(sReformatNotPossible,'Paragraph reformat not possible while trying to wrap current line with current margins.');
+  Strings^.Put(sReformattingTheDocument,'Reformatting the document:');
+  Strings^.Put(sReplace,'Replace');
+  Strings^.Put(sReplaceFile,'Replace file?'#13#10#13#3'%s');
+  Strings^.Put(sReplaceNotPossible,'Wordwrap on:  Replace not possible in current margins when at end of line.');
+  Strings^.Put(sReplaceThisOccurence,'Replace this occurence?');
+  Strings^.Put(sRightMargin,'Right Margin');
+  Strings^.Put(sSaveAs,'Save As');
+  Strings^.Put(sScrollbarIcons,'Scroll bar icons');
+  Strings^.Put(sScrollbarPage,'Scroll bar page');
+  Strings^.Put(sSearchStringNotFound,'Search string not found.');
+  Strings^.Put(sSelectFormatStart,'Select Format Start');
+  Strings^.Put(sSelectWhereToBegin,'Please select where to begin.');
+  Strings^.Put(sSelected,'Selected');
+  Strings^.Put(sSelectedDisabled,'Selected disabled');
+  Strings^.Put(sSetting,'Setting:');
+  Strings^.Put(sShortcut,'Shortcut');
+  Strings^.Put(sShortcutSelected,'ShortcutSelected');
+  Strings^.Put(sStaticText,'Static text');
+  Strings^.Put(sTabSettings,'Tab Settings');
+  Strings^.Put(sText,'Text');
+  Strings^.Put(sTooManyFiles,'Too many files.');
+  Strings^.Put(sTypeExitOnReturn,'Type EXIT to return...');
+  Strings^.Put(sUnderline,'Underline');
+  Strings^.Put(sUnknownDialog,'Unknown dialog requested!');
+  Strings^.Put(sUntitled,'Untitled');
+  Strings^.Put(sWarning,'Warning');
+  Strings^.Put(sWindowList,'Window List');
+  Strings^.Put(sWordWrapNotPossible,'Wordwrap on:  Wordwrap not possible in current margins with continuous line.');
+  Strings^.Put(sWordWrapOff,'You must turn on wordwrap before you can reformat.');
+  Strings^.Put(smApr,'Apr');
+  Strings^.Put(smAug,'Aug');
+  Strings^.Put(smDec,'Dec');
+  Strings^.Put(smFeb,'Feb');
+  Strings^.Put(smJan,'Jan');
+  Strings^.Put(smJul,'Jul');
+  Strings^.Put(smJun,'Jun');
+  Strings^.Put(smMar,'Mar');
+  Strings^.Put(smMay,'May');
+  Strings^.Put(smNov,'Nov');
+  Strings^.Put(smOct,'Oct');
+  Strings^.Put(smSep,'Sep');
+end;
+
+procedure InitResLabels;
+begin
+  Labels^.Put(slAbout,'~A~bout');
+  Labels^.Put(slAltF1,'Alt+F1');
+  Labels^.Put(slAltF3Close,'~Alt+F3~ Close');
+  Labels^.Put(slAltXExit,'~Alt-X~ Exit');
+  Labels^.Put(slBackground,'~B~ackground');
+  Labels^.Put(slCancel,'Cancel');
+  Labels^.Put(slCascade,'C~a~scade');
+  Labels^.Put(slCaseSensitive,'~C~ase sensitive');
+  Labels^.Put(slChDir,'~C~hdir');
+  Labels^.Put(slChangeDir,'~C~hange dir...');
+  Labels^.Put(slClear,'C~l~ear');
+  Labels^.Put(slClose,'~C~lose');
+  Labels^.Put(slCloseAll,'Cl~o~se all');
+  Labels^.Put(slColor,'~C~olor');
+  Labels^.Put(slContents,'~C~ontents');
+  Labels^.Put(slCopy,'~C~opy');
+  Labels^.Put(slCtrlF1,'Ctrl+F1');
+  Labels^.Put(slCurrentLine,'~C~urrent line');
+  Labels^.Put(slCut,'Cu~t~');
+  Labels^.Put(slDOSShell,'~D~OS shell');
+  Labels^.Put(slDelete,'~D~elete');
+  Labels^.Put(slDirectoryName,'Directory ~n~ame');
+  Labels^.Put(slDirectoryTree,'Directory ~t~ree');
+  Labels^.Put(slEdit,'~E~dit');
+  Labels^.Put(slEntireDocument,'~E~ntire document');
+  Labels^.Put(slExit,'E~x~it');
+  Labels^.Put(slF10Menu,'~F10~ Menu');
+  Labels^.Put(slF1Help,'~F1~ Help');
+  Labels^.Put(slF3Open,'~F3~ Open');
+  Labels^.Put(slFile,'~F~ile');
+  Labels^.Put(slFiles,'~F~iles');
+  Labels^.Put(slForeground,'~F~oreground');
+  Labels^.Put(slGroup,'~G~roup');
+  Labels^.Put(slHelp,'~H~elp');
+  Labels^.Put(slIndex,'~I~ndex');
+  Labels^.Put(slItem,'~I~tem');
+  Labels^.Put(slLineNumber,'~L~ine number');
+  Labels^.Put(slName,'~N~ame');
+  Labels^.Put(slNew,'~N~ew');
+  Labels^.Put(slNewText,'~N~ew text');
+  Labels^.Put(slNext,'~N~ext');
+  Labels^.Put(slNo,'~N~o');
+  Labels^.Put(slOk,'O~k~');
+  Labels^.Put(slOpen,'~O~pen');
+  Labels^.Put(slOpenDots,'~O~pen...');
+  Labels^.Put(slPaste,'~P~aste');
+  Labels^.Put(slPrevious,'~P~revious');
+  Labels^.Put(slPreviousTopic,'~P~revious topic');
+  Labels^.Put(slPromptOnReplace,'~P~rompt on replace');
+  Labels^.Put(slReformatDocument,'~R~eformat document');
+  Labels^.Put(slReplace,'~R~eplace');
+  Labels^.Put(slReplaceAll,'~R~eplace all');
+  Labels^.Put(slRevert,'~R~evert');
+  Labels^.Put(slSave,'~S~ave');
+  Labels^.Put(slSaveAll,'Save a~l~l');
+  Labels^.Put(slSaveAs,'S~a~ve as...');
+  Labels^.Put(slSaveFileAs,'~S~ave file as');
+  Labels^.Put(slShiftF1,'Shift+F1');
+  Labels^.Put(slSizeMove,'~S~ize/Move');
+  Labels^.Put(slTextToFind,'~T~ext to find');
+  Labels^.Put(slTile,'~T~ile');
+  Labels^.Put(slTopicSearch,'~T~opic search');
+  Labels^.Put(slUndo,'~U~ndo');
+  Labels^.Put(slUsingHelp,'~U~sing help');
+  Labels^.Put(slWholeWordsOnly,'~W~hole words only');
+  Labels^.Put(slWindow,'~W~indow');
+  Labels^.Put(slWindows,'~W~indows');
+  Labels^.Put(slYes,'~Y~es');
+  Labels^.Put(slZoom,'~Z~oom');
+  Labels^.Put(slAltF3,'Alt+F3');
+  Labels^.Put(slAltX,'Alt+X');
+  Labels^.Put(slF2,'F2');
+  Labels^.Put(slF3,'F3');
+  Labels^.Put(slF5,'F5');
+  Labels^.Put(slF6,'F6');
+  Labels^.Put(slCtrlDel,'Ctrl+Del');
+  Labels^.Put(slCtrlF5,'Ctrl+F5');
+  Labels^.Put(slCtrlIns,'Ctrl+Ins');
+  Labels^.Put(slShiftDel,'Shift+Del');
+  Labels^.Put(slShiftF6,'Shift+F6');
+  Labels^.Put(slShiftIns,'Shift+Ins');
+end;

+ 432 - 0
fvision/callspec.pas

@@ -0,0 +1,432 @@
+{
+   $Id$
+
+   This unit provides compiler-independent mechanisms to call special
+   functions, i.e. local functions/procedures, constructors, methods,
+   destructors, etc. As there are no procedural variables for these
+   special functions, there is no Pascal way to call them directly.
+
+   Copyright (c) 1997 Matthias K"oppe <[email protected]>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************}
+unit CallSpec;
+
+{
+  As of this version, the following compilers are supported. Please
+  port CallSpec to other compilers (including earlier versions) and
+  send your code to the above address.
+
+  Compiler                    Comments
+  --------------------------- -------------------------------------
+  Turbo Pascal 6.0
+  Borland/Turbo Pascal 7.0
+  FPC Pascal 0.99.8
+}
+
+interface
+
+{$i platform.inc}
+
+{
+  The frame pointer points to the local variables of a procedure.
+  Use CurrentFramePointer to address the locals of the current procedure;
+  use PreviousFramePointer to addess the locals of the calling procedure.
+}
+type
+{$ifdef BIT_16}
+   FramePointer = Word;
+{$endif}
+{$ifdef BIT_32}
+   FramePointer = pointer;
+{$endif}
+
+function CurrentFramePointer: FramePointer;
+function PreviousFramePointer: FramePointer;
+
+{ This version of CallSpec supports four classes of special functions.
+  (Please write if you need other classes.)
+  For each, two types of argument lists are allowed:
+
+  `Void' indicates special functions with no explicit arguments.
+    Sample: constructor T.Init;
+  `Pointer' indicates special functions with one explicit pointer argument.
+    Sample: constructor T.Load(var S: TStream);
+}
+
+{ Constructor calls.
+
+  Ctor     Pointer to the constructor.
+  Obj      Pointer to the instance. NIL if new instance to be allocated.
+  VMT      Pointer to the VMT (obtained by TypeOf()).
+  returns  Pointer to the instance.
+}
+function CallVoidConstructor(Ctor: pointer; Obj: pointer; VMT: pointer): pointer;
+function CallPointerConstructor(Ctor: pointer; Obj: pointer; VMT: pointer; Param1: pointer): pointer;
+
+{ Method calls.
+
+  Method   Pointer to the method.
+  Obj      Pointer to the instance. NIL if new instance to be allocated.
+  returns  Pointer to the instance.
+}
+function CallVoidMethod(Method: pointer; Obj: pointer): pointer;
+function CallPointerMethod(Method: pointer; Obj: pointer; Param1: pointer): pointer;
+
+{ Local-function/procedure calls.
+
+  Func     Pointer to the local function (which must be far-coded).
+  Frame    Frame pointer of the wrapping function.
+}
+
+function CallVoidLocal(Func: pointer; Frame: FramePointer): pointer;
+function CallPointerLocal(Func: pointer; Frame: FramePointer; Param1: pointer): pointer;
+
+{ Calls of functions/procedures local to methods.
+
+  Func     Pointer to the local function (which must be far-coded).
+  Frame    Frame pointer of the wrapping method.
+  Obj      Pointer to the object that the method belongs to.
+}
+function CallVoidMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer): pointer;
+function CallPointerMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer; Param1: pointer): pointer;
+
+
+implementation
+
+{$ifdef PPC_FPC}
+
+{$ifdef CPUI386}
+{$ASMMODE ATT}
+{$endif CPUI386}
+
+{ This indicates an FPC version which uses the same call scheme for
+  method-local and procedure-local procedures, but which expects the
+  ESI register be loaded with the Self pointer in method-local procs. }
+
+type
+  VoidLocal = function(_EBP: FramePointer): pointer;
+  PointerLocal = function(_EBP: FramePointer; Param1: pointer): pointer;
+  VoidMethodLocal = function(_EBP: FRAMEPOINTER): pointer;
+  PointerMethodLocal = function(_EBP: FRAMEPOINTER; Param1: pointer): pointer;
+  VoidConstructor = function(VMT: pointer; Obj: pointer): pointer;
+  PointerConstructor = function(VMT: pointer; Obj: pointer; Param1: pointer): pointer;
+  VoidMethod = function(Obj: pointer): pointer;
+  PointerMethod = function(Obj: pointer; Param1: pointer): pointer;
+
+
+function CallVoidConstructor(Ctor: pointer; Obj: pointer; VMT: pointer): pointer;
+begin
+  { load the object pointer }
+{$ifdef CPUI386}
+  asm
+        movl Obj, %esi
+  end;
+{$endif CPUI386}
+{$ifdef CPU68K}
+  asm
+        move.l Obj, a5
+  end;
+{$endif CPU68K}
+
+  CallVoidConstructor := VoidConstructor(Ctor)(VMT, Obj)
+end;
+
+
+function CallPointerConstructor(Ctor: pointer; Obj: pointer; VMT: pointer; Param1: pointer): pointer;
+begin
+  { load the object pointer }
+{$ifdef CPUI386}
+  asm
+        movl Obj, %esi
+  end;
+{$endif CPUI386}
+{$ifdef CPU68K}
+  asm
+        move.l Obj, a5
+  end;
+{$endif CPU68K}
+  CallPointerConstructor := PointerConstructor(Ctor)(VMT, Obj, Param1)
+end;
+
+
+function CallVoidMethod(Method: pointer; Obj: pointer): pointer;
+begin
+  { load the object pointer }
+{$ifdef CPUI386}
+  asm
+        movl Obj, %esi
+  end;
+{$endif CPUI386}
+{$ifdef CPU68K}
+  asm
+        move.l Obj, a5
+  end;
+{$endif CPU68K}
+  CallVoidMethod := VoidMethod(Method)(Obj)
+end;
+
+
+function CallPointerMethod(Method: pointer; Obj: pointer; Param1: pointer): pointer;
+begin
+  { load the object pointer }
+{$ifdef CPUI386}
+  asm
+        movl Obj, %esi
+  end;
+{$endif CPUI386}
+{$ifdef CPU68K}
+  asm
+        move.l Obj, a5
+  end;
+{$endif CPU68K}
+  CallPointerMethod := PointerMethod(Method)(Obj, Param1)
+end;
+
+
+function CallVoidLocal(Func: pointer; Frame: FramePointer): pointer;
+begin
+  CallVoidLocal := VoidLocal(Func)(Frame)
+end;
+
+
+function CallPointerLocal(Func: pointer; Frame: FramePointer; Param1: pointer): pointer;
+begin
+  CallPointerLocal := PointerLocal(Func)(Frame, Param1)
+end;
+
+
+function CallVoidMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer): pointer;
+begin
+  { load the object pointer }
+{$ifdef CPUI386}
+  asm
+        movl Obj, %esi
+  end;
+{$endif CPUI386}
+{$ifdef CPU68K}
+  asm
+        move.l Obj, a5
+  end;
+{$endif CPU68K}
+  CallVoidMethodLocal := VoidMethodLocal(Func)(Frame)
+end;
+
+
+function CallPointerMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer; Param1: pointer): pointer;
+begin
+  { load the object pointer }
+{$ifdef CPUI386}
+  asm
+        movl Obj, %esi
+  end;
+{$endif CPUI386}
+{$ifdef CPU68K}
+  asm
+        move.l Obj, a5
+  end;
+{$endif CPU68K}
+  CallPointerMethodLocal := PointerMethodLocal(Func)(Frame, Param1)
+end;
+
+
+function CurrentFramePointer: FramePointer;assembler;
+{$ifdef CPUI386}
+asm
+    movl %ebp,%eax
+end ['EAX'];
+{$endif CPUI386}
+{$ifdef CPU68K}
+asm
+    move.l a6, d0
+end['D0'];
+{$endif CPU68K}
+
+
+function PreviousFramePointer: FramePointer;assembler;
+{$ifdef CPUI386}
+asm
+    movl (%ebp),%eax
+end ['EAX'];
+{$endif CPUI386}
+{$ifdef CPU68K}
+asm
+    move.l (a6), d0
+end['D0'];
+{$endif CPU68K}
+
+{$endif PPC_FPC}
+
+
+{$ifdef PPC_BP}
+type
+  VoidConstructor = function(VmtOfs: Word; Obj: pointer): pointer;
+  PointerConstructor = function(Param1: pointer; VmtOfs: Word; Obj: pointer): pointer;
+  VoidMethod = function(Obj: pointer): pointer;
+  PointerMethod = function(Param1: pointer; Obj: pointer): pointer;
+
+function CallVoidConstructor(Ctor: pointer; Obj: pointer; VMT: pointer): pointer;
+begin
+  CallVoidConstructor := VoidConstructor(Ctor)(Ofs(VMT^), Obj)
+end;
+
+
+function CallPointerConstructor(Ctor: pointer; Obj: pointer; VMT: pointer; Param1: pointer): pointer;
+begin
+  CallPointerConstructor := PointerConstructor(Ctor)(Param1, Ofs(VMT^), Obj)
+end;
+
+
+function CallVoidMethod(Method: pointer; Obj: pointer): pointer;
+begin
+  CallVoidMethod := VoidMethod(Method)(Obj)
+end;
+
+
+function CallPointerMethod(Method: pointer; Obj: pointer; Param1: pointer): pointer;
+begin
+  CallPointerMethod := PointerMethod(Method)(Param1, Obj)
+end;
+
+
+function CallVoidLocal(Func: pointer; Frame: FramePointer): pointer; assembler;
+asm
+{$IFDEF Windows}
+        MOV     AX,[Frame]
+        AND     AL,0FEH
+        PUSH    AX
+{$ELSE}
+        push    [Frame]
+{$ENDIF}
+        call    dword ptr Func
+end;
+
+
+function CallPointerLocal(Func: pointer; Frame: FramePointer; Param1: pointer): pointer; assembler;
+asm
+        mov     ax, word ptr Param1
+        mov     dx, word ptr Param1+2
+        push    dx
+        push    ax
+{$IFDEF Windows}
+        MOV     AX,[Frame]
+        AND     AL,0FEH
+        PUSH    AX
+{$ELSE}
+        push    [Frame]
+{$ENDIF}
+        call    dword ptr Func
+end;
+
+
+function CallVoidMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer): pointer; assembler;
+asm
+{$IFDEF Windows}
+        MOV     AX,[Frame]
+        AND     AL,0FEH
+        PUSH    AX
+{$ELSE}
+        push    [Frame]
+{$ENDIF}
+        call    dword ptr Func
+end;
+
+
+function CallPointerMethodLocal(Func: pointer; Frame: FramePointer; Obj: pointer; Param1: pointer): pointer; assembler;
+asm
+        mov     ax, word ptr Param1
+        mov     dx, word ptr Param1+2
+        push    dx
+        push    ax
+{$IFDEF Windows}
+        MOV     AX,[Frame]
+        AND     AL,0FEH
+        PUSH    AX
+{$ELSE}
+        push    [Frame]
+{$ENDIF}
+        call    dword ptr Func
+end;
+
+
+function CurrentFramePointer: FramePointer; assembler;
+asm
+        mov     ax, bp
+end;
+
+
+function PreviousFramePointer: FramePointer; assembler;
+asm
+        mov     ax, ss:[bp]
+end;
+
+{$endif PPC_BP}
+
+
+end.
+{
+  $Log$
+  Revision 1.1  2001-08-05 02:10:26  peter
+    * more files
+
+  Revision 1.3  2001/07/30 08:27:58  pierre
+   * fix I386 compilation problem
+
+  Revision 1.2  2001/07/29 20:23:18  pierre
+   * support for m68k cpu
+
+  Revision 1.1  2001/01/29 21:56:04  peter
+    * updates for new fpcmake
+
+  Revision 1.1  2001/01/29 11:31:26  marco
+   * added from API. callspec renamed to .pp
+
+  Revision 1.1  2000/07/13 06:29:38  michael
+  + Initial import
+
+  Revision 1.1  2000/01/06 01:20:30  peter
+    * moved out of packages/ back to topdir
+
+  Revision 1.1  1999/12/23 19:36:47  peter
+    * place unitfiles in target dirs
+
+  Revision 1.1  1999/11/24 23:36:37  peter
+    * moved to packages dir
+
+  Revision 1.2  1998/12/16 21:57:16  peter
+    * fixed currentframe,previousframe
+    + testcall to test the callspec unit
+
+  Revision 1.1  1998/12/04 12:48:24  peter
+    * moved some dirs
+
+  Revision 1.5  1998/12/04 09:53:44  peter
+    * removed objtemp global var
+
+  Revision 1.4  1998/11/24 17:14:24  peter
+    * fixed esi loading
+
+
+  Date       Version  Who     Comments
+  ---------- -------- ------- -------------------------------------
+  19-Sep-97  0.1      mkoeppe Initial version.
+  22-Sep-97  0.11     fk      0.9.3 support added, self isn't expected
+                              on the stack in local procedures of methods
+  23-Sep-97  0.12     mkoeppe Cleaned up 0.9.3 conditionals.
+  03-Oct-97  0.13     mkoeppe Fixed esi load in FPC 0.9
+  22-Oct-98  0.14     pfv     0.99.8 support for FPC
+}

+ 3733 - 0
fvision/editors.pas

@@ -0,0 +1,3733 @@
+unit Editors;
+
+{$i platform.inc}
+
+{$ifdef PPC_FPC}
+  {$H-}
+{$else}
+  {$F+,O+,E+,N+}
+{$endif}
+{$X+,R-,I-,Q-,V-}
+{$ifndef OS_LINUX}
+  {$S-}
+{$endif}
+
+
+{$define UNIXLF}
+
+interface
+
+uses
+  Objects, Drivers,Views,Dialogs,FVCommon,FVConsts;
+
+const
+  { Length constants. }
+  Tab_Stop_Length = 74;
+
+{$ifdef PPC_BP}
+  MaxLineLength  = 1024;
+  MinBufLength   = $1000;
+  MaxBufLength   = $ff00;
+  NotFoundValue  = $ffff;
+  LineInfoGrow   = 256;
+  MaxLines       = 16000;
+{$else}
+  MaxLineLength  = 4096;
+  MinBufLength   = $1000;
+  MaxBufLength   = $7fffff00;
+  NotFoundValue  = $ffffffff;
+  LineInfoGrow   = 1024;
+  MaxLines       = $7ffffff;
+{$endif}
+
+
+  { Editor constants for dialog boxes. }
+  edOutOfMemory   = 0;
+  edReadError     = 1;
+  edWriteError    = 2;
+  edCreateError   = 3;
+  edSaveModify    = 4;
+  edSaveUntitled  = 5;
+  edSaveAs        = 6;
+  edFind          = 7;
+  edSearchFailed  = 8;
+  edReplace       = 9;
+  edReplacePrompt = 10;
+
+  edJumpToLine         = 11;
+  edPasteNotPossible   = 12;
+  edReformatDocument   = 13;
+  edReformatNotAllowed = 14;
+  edReformNotPossible  = 15;
+  edReplaceNotPossible = 16;
+  edRightMargin        = 17;
+  edSetTabStops        = 18;
+  edWrapNotPossible    = 19;
+
+  { Editor flag constants for dialog options. }
+  efCaseSensitive   = $0001;
+  efWholeWordsOnly  = $0002;
+  efPromptOnReplace = $0004;
+  efReplaceAll      = $0008;
+  efDoReplace       = $0010;
+  efBackupFiles     = $0100;
+
+  { Constants for object palettes. }
+  CIndicator = #2#3;
+  CEditor    = #6#7;
+  CMemo      = #26#27;
+
+type
+  TEditorDialog = function (Dialog : Integer; Info : Pointer) : Word;
+
+  PIndicator = ^TIndicator;
+  TIndicator = object (TView)
+    Location   : Objects.TPoint;
+    Modified   : Boolean;
+    AutoIndent : Boolean;          { Added boolean for AutoIndent mode. }
+    WordWrap   : Boolean;          { Added boolean for WordWrap mode.   }
+    constructor Init (var Bounds : TRect);
+    procedure   Draw; virtual;
+    function    GetPalette : PPalette; virtual;
+    procedure   SetState (AState : Word; Enable : Boolean); virtual;
+    procedure   SetValue (ALocation : Objects.TPoint; IsAutoIndent : Boolean;
+                                                      IsModified   : Boolean;
+                                                      IsWordWrap   : Boolean);
+  end;
+
+  TLineInfoRec = record
+    Len,Attr : Sw_word;
+  end;
+  TLineInfoArr = array[0..MaxLines] of TLineInfoRec;
+  PLineInfoArr = ^TLineInfoArr;
+
+  PLineInfo = ^TLineInfo;
+  TLineInfo = object
+    Info : PLineInfoArr;
+    MaxPos : Sw_Word;
+    constructor Init;
+    destructor Done;
+    procedure Grow(pos:Sw_word);
+    procedure SetLen(pos,val:Sw_Word);
+    procedure SetAttr(pos,val:Sw_Word);
+    function  GetLen(pos:Sw_Word):Sw_Word;
+    function  GetAttr(pos:Sw_Word):Sw_Word;
+  end;
+
+
+  PEditBuffer = ^TEditBuffer;
+  TEditBuffer = array[0..MaxBufLength] of Char;
+
+  PEditor = ^TEditor;
+  TEditor = object (TView)
+    HScrollBar         : PScrollBar;
+    VScrollBar         : PScrollBar;
+    Indicator          : PIndicator;
+    Buffer             : PEditBuffer;
+    BufSize            : Sw_Word;
+    BufLen             : Sw_Word;
+    GapLen             : Sw_Word;
+    SelStart           : Sw_Word;
+    SelEnd             : Sw_Word;
+    CurPtr             : Sw_Word;
+    CurPos             : Objects.TPoint;
+    Delta              : Objects.TPoint;
+    Limit              : Objects.TPoint;
+    DrawLine           : Sw_Integer;
+    DrawPtr            : Sw_Word;
+    DelCount           : Sw_Word;
+    InsCount           : Sw_Word;
+    Flags              : Longint;
+    IsReadOnly         : Boolean;
+    IsValid            : Boolean;
+    CanUndo            : Boolean;
+    Modified           : Boolean;
+    Selecting          : Boolean;
+    Overwrite          : Boolean;
+    AutoIndent         : Boolean;
+    NoSelect           : Boolean;
+    TabSize            : Sw_Word; { tabsize for displaying }
+    BlankLine          : Sw_Word; { First blank line after a paragraph. }
+    Word_Wrap          : Boolean; { Added boolean to toggle wordwrap on/off. }
+    Line_Number        : string[8]; { Holds line number to jump to. }
+    Right_Margin       : Sw_Integer; { Added integer to set right margin. }
+    Tab_Settings       : String[Tab_Stop_Length]; { Added string to hold tab stops. }
+
+    constructor Init (var Bounds : TRect; AHScrollBar, AVScrollBar : PScrollBar;
+                          AIndicator : PIndicator; ABufSize : Sw_Word);
+    constructor Load (var S : Objects.TStream);
+    destructor Done; virtual;
+    function   BufChar (P : Sw_Word) : Char;
+    function   BufPtr (P : Sw_Word) : Sw_Word;
+    procedure  ChangeBounds (var Bounds : TRect); virtual;
+    procedure  ConvertEvent (var Event : Drivers.TEvent); virtual;
+    function   CursorVisible : Boolean;
+    procedure  DeleteSelect;
+    procedure  DoneBuffer; virtual;
+    procedure  Draw; virtual;
+    procedure  FormatLine (var DrawBuf; LinePtr : Sw_Word; Width : Sw_Integer; Colors : Word);virtual;
+    function   GetPalette : PPalette; virtual;
+    procedure  HandleEvent (var Event : Drivers.TEvent); virtual;
+    procedure  InitBuffer; virtual;
+    function   InsertBuffer (var P : PEditBuffer; Offset, Length : Sw_Word;AllowUndo, SelectText : Boolean) : Boolean;
+    function   InsertFrom (Editor : PEditor) : Boolean; virtual;
+    function   InsertText (Text : Pointer; Length : Sw_Word; SelectText : Boolean) : Boolean;
+    procedure  ScrollTo (X, Y : Sw_Integer);
+    function   Search (const FindStr : String; Opts : Word) : Boolean;
+    function   SetBufSize (NewSize : Sw_Word) : Boolean; virtual;
+    procedure  SetCmdState (Command : Word; Enable : Boolean);
+    procedure  SetSelect (NewStart, NewEnd : Sw_Word; CurStart : Boolean);
+    procedure  SetCurPtr (P : Sw_Word; SelectMode : Byte);
+    procedure  SetState (AState : Word; Enable : Boolean); virtual;
+    procedure  Store (var S : Objects.TStream);
+    procedure  TrackCursor (Center : Boolean);
+    procedure  Undo;
+    procedure  UpdateCommands; virtual;
+    function   Valid (Command : Word) : Boolean; virtual;
+
+  private
+    KeyState       : Integer;
+    LockCount      : Byte;
+    UpdateFlags    : Byte;
+    Place_Marker   : Array [1..10] of Sw_Word; { Inserted array to hold place markers. }
+    Search_Replace : Boolean; { Added boolean to test for Search and Replace insertions. }
+
+    procedure  Center_Text (Select_Mode : Byte);
+    function   CharPos (P, Target : Sw_Word) : Sw_Integer;
+    function   CharPtr (P : Sw_Word; Target : Sw_Integer) : Sw_Word;
+    procedure  Check_For_Word_Wrap (Select_Mode : Byte; Center_Cursor : Boolean);
+    function   ClipCopy : Boolean;
+    procedure  ClipCut;
+    procedure  ClipPaste;
+    procedure  DeleteRange (StartPtr, EndPtr : Sw_Word; DelSelect : Boolean);
+    procedure  DoSearchReplace;
+    procedure  DoUpdate;
+    function   Do_Word_Wrap (Select_Mode : Byte; Center_Cursor : Boolean) : Boolean;
+    procedure  DrawLines (Y, Count : Sw_Integer; LinePtr : Sw_Word);
+    procedure  Find;
+    function   GetMousePtr (Mouse : Objects.TPoint) : Sw_Word;
+    function   HasSelection : Boolean;
+    procedure  HideSelect;
+    procedure  Insert_Line (Select_Mode : Byte);
+    function   IsClipboard : Boolean;
+    procedure  Jump_Place_Marker (Element : Byte; Select_Mode : Byte);
+    procedure  Jump_To_Line  (Select_Mode : Byte);
+    function   LineEnd (P : Sw_Word) : Sw_Word;
+    function   LineMove (P : Sw_Word; Count : Sw_Integer) : Sw_Word;
+    function   LineStart (P : Sw_Word) : Sw_Word;
+    function   LineNr (P : Sw_Word) : Sw_Word;
+    procedure  Lock;
+    function   NewLine (Select_Mode : Byte) : Boolean;
+    function   NextChar (P : Sw_Word) : Sw_Word;
+    function   NextLine (P : Sw_Word) : Sw_Word;
+    function   NextWord (P : Sw_Word) : Sw_Word;
+    function   PrevChar (P : Sw_Word) : Sw_Word;
+    function   PrevLine (P : Sw_Word) : Sw_Word;
+    function   PrevWord (P : Sw_Word) : Sw_Word;
+    procedure  Reformat_Document (Select_Mode : Byte; Center_Cursor : Boolean);
+    function   Reformat_Paragraph (Select_Mode : Byte; Center_Cursor : Boolean) : Boolean;
+    procedure  Remove_EOL_Spaces (Select_Mode : Byte);
+    procedure  Replace;
+    procedure  Scroll_Down;
+    procedure  Scroll_Up;
+    procedure  Select_Word;
+    procedure  SetBufLen (Length : Sw_Word);
+    procedure  Set_Place_Marker (Element : Byte);
+    procedure  Set_Right_Margin;
+    procedure  Set_Tabs;
+    procedure  StartSelect;
+    procedure  Tab_Key (Select_Mode : Byte);
+    procedure  ToggleInsMode;
+    procedure  Unlock;
+    procedure  Update (AFlags : Byte);
+    procedure  Update_Place_Markers (AddCount : Word; KillCount : Word; StartPtr,EndPtr : Sw_Word);
+  end;
+
+  TMemoData = record
+    Length : Sw_Word;
+    Buffer : TEditBuffer;
+  end;
+
+  PMemo = ^TMemo;
+  TMemo = object (TEditor)
+    constructor Load (var S : Objects.TStream);
+    function    DataSize : Sw_Word; virtual;
+    procedure   GetData (var Rec); virtual;
+    function    GetPalette : PPalette; virtual;
+    procedure   HandleEvent (var Event : Drivers.TEvent); virtual;
+    procedure   SetData (var Rec); virtual;
+    procedure   Store (var S : Objects.TStream);
+  end;
+
+  PFileEditor = ^TFileEditor;
+  TFileEditor = object (TEditor)
+    FileName : FNameStr;
+    constructor Init (var Bounds : TRect; AHScrollBar, AVScrollBar : PScrollBar;
+                          AIndicator : PIndicator; AFileName : FNameStr);
+    constructor Load (var S : Objects.TStream);
+    procedure   DoneBuffer; virtual;
+    procedure   HandleEvent (var Event : Drivers.TEvent); virtual;
+    procedure   InitBuffer; virtual;
+    function    LoadFile : Boolean;
+    function    Save : Boolean;
+    function    SaveAs : Boolean;
+    function    SaveFile : Boolean;
+    function    SetBufSize (NewSize : Sw_Word) : Boolean; virtual;
+    procedure   Store (var S : Objects.TStream);
+    procedure   UpdateCommands; virtual;
+    function    Valid (Command : Word) : Boolean; virtual;
+  end;
+
+  PEditWindow = ^TEditWindow;
+  TEditWindow = object (TWindow)
+    Editor : PFileEditor;
+    constructor Init (var Bounds : TRect; FileName : FNameStr; ANumber : Integer);
+    constructor Load (var S : Objects.TStream);
+    procedure   Close; virtual;
+    function    GetTitle (MaxSize : Sw_Integer) : TTitleStr; virtual;
+    procedure   HandleEvent (var Event : Drivers.TEvent); virtual;
+    procedure   SizeLimits(var Min, Max: TPoint); virtual;
+    procedure   Store (var S : Objects.TStream);
+  end;
+
+
+function DefEditorDialog (Dialog : Integer; Info : Pointer) : Word;
+function CreateFindDialog: PDialog;
+function CreateReplaceDialog: PDialog;
+function JumpLineDialog : PDialog;
+function ReformDocDialog : PDialog;
+function RightMarginDialog : PDialog;
+function TabStopDialog : Dialogs.PDialog;
+function StdEditorDialog(Dialog: Integer; Info: Pointer): Word;
+
+const
+  WordChars    : set of Char = ['!'..#255];
+
+  LineBreak    : string[2]=
+{$ifdef UNIXLF}
+    #10;
+{$else}
+    #13#10;
+{$endif}
+
+
+  { The Allow_Reformat boolean is a programmer hook.  }
+  { I've placed this here to allow programmers to     }
+  { determine whether or not paragraph and document   }
+  { reformatting are allowed if Word_Wrap is not      }
+  { active.  Some people say don't allow, and others  }
+  { say allow it.  I've left it up to the programmer. }
+  { Set to FALSE if not allowed, or TRUE if allowed.  }
+  Allow_Reformat : Boolean = True;
+
+  EditorDialog   : TEditorDialog = {$ifdef fpc}@{$endif}DefEditorDialog;
+  EditorFlags    : Word = efBackupFiles + efPromptOnReplace;
+  FindStr        : String[80] = '';
+  ReplaceStr     : String[80] = '';
+  Clipboard      : PEditor = nil;
+
+  ToClipCmds     : TCommandSet = ([cmCut,cmCopy,cmClear]);
+  FromClipCmds   : TCommandSet = ([cmPaste]);
+  UndoCmds       : TCommandSet = ([cmUndo,cmRedo]);
+
+TYPE
+  TFindDialogRec = packed record
+    Find    : String[80];
+    Options : Word;
+  end;
+
+  TReplaceDialogRec = packed record
+       Find : String[80];
+    Replace : String[80];
+    Options : Word;
+  end;
+
+  TRightMarginRec = packed record
+    Margin_Position : String[3];
+  end;
+
+  TTabStopRec = packed record
+    Tab_String : String [Tab_Stop_Length];
+  end;
+
+CONST
+  { VMT constants. }
+  REditor   : TStreamRec = (ObjType : 70;
+                            VmtLink : Ofs (TypeOf (TEditor)^);
+                               Load : @TEditor.Load;
+                              Store : @TEditor.Store);
+
+  RMemo     : TStreamRec = (ObjType : 71;
+                            VmtLink : Ofs (TypeOf (TMemo)^);
+                               Load : @TMemo.Load;
+                              Store : @TMemo.Store);
+
+  RFileEditor : TStreamRec = (ObjType : 72;
+                              VmtLink : Ofs (TypeOf (TFileEditor)^);
+                                 Load : @TFileEditor.Load;
+                                Store : @TFileEditor.Store);
+
+  RIndicator : TStreamRec = (ObjType : 73;
+                             VmtLink : Ofs (TypeOf (TIndicator)^);
+                                Load : @TIndicator.Load;
+                               Store : @TIndicator.Store);
+
+  REditWindow : TStreamRec = (ObjType : 74;
+                              VmtLink : Ofs (TypeOf (TEditWindow)^);
+                                 Load : @TEditWindow.Load;
+                                Store : @TEditWindow.Store);
+
+procedure RegisterEditors;
+
+
+{****************************************************************************
+                              Implementation
+****************************************************************************}
+
+implementation
+
+uses
+  Memory, Dos, App, StdDlg, MsgBox, Resource;
+
+type
+  pword = ^word;
+
+CONST
+  { Update flag constants. }
+  ufUpdate = $01;
+  ufLine   = $02;
+  ufView   = $04;
+  ufStats  = $05;
+
+  { SelectMode constants. }
+  smExtend = $01;
+  smDouble = $02;
+
+  sfSearchFailed = NotFoundValue;
+
+  { Arrays that hold all the command keys and options. }
+  FirstKeys : array[0..46 * 2] of Word = (46, Ord (^A),    cmWordLeft,
+                                              Ord (^B),    cmReformPara,
+                                              Ord (^C),    cmPageDown,
+                                              Ord (^D),    cmCharRight,
+                                              Ord (^E),    cmLineUp,
+                                              Ord (^F),    cmWordRight,
+                                              Ord (^G),    cmDelChar,
+                                              Ord (^H),    cmBackSpace,
+                                              Ord (^I),    cmTabKey,
+                                              Ord (^J),    $FF04,
+                                              Ord (^K),    $FF02,
+                                              Ord (^L),    cmSearchAgain,
+                                              Ord (^M),    cmNewLine,
+                                              Ord (^N),    cmInsertLine,
+                                              Ord (^O),    $FF03,
+                                              Ord (^Q),    $FF01,
+                                              Ord (^R),    cmPageUp,
+                                              Ord (^S),    cmCharLeft,
+                                              Ord (^T),    cmDelWord,
+                                              Ord (^U),    cmUndo,
+                                              Ord (^V),    cmInsMode,
+                                              Ord (^W),    cmScrollUp,
+                                              Ord (^X),    cmLineDown,
+                                              Ord (^Y),    cmDelLine,
+                                              Ord (^Z),    cmScrollDown,
+                                              kbLeft,      cmCharLeft,
+                                              kbRight,     cmCharRight,
+                                              kbCtrlLeft,  cmWordLeft,
+                                              kbCtrlRight, cmWordRight,
+                                              kbHome,      cmLineStart,
+                                              kbEnd,       cmLineEnd,
+                                              kbCtrlHome,  cmHomePage,
+                                              kbCtrlEnd,   cmEndPage,
+                                              kbUp,        cmLineUp,
+                                              kbDown,      cmLineDown,
+                                              kbPgUp,      cmPageUp,
+                                              kbPgDn,      cmPageDown,
+                                              kbCtrlPgUp,  cmTextStart,
+                                              kbCtrlPgDn,  cmTextEnd,
+                                              kbIns,       cmInsMode,
+                                              kbDel,       cmDelChar,
+                                              kbCtrlBack,  cmDelStart,
+                                              kbShiftIns,  cmPaste,
+                                              kbShiftDel,  cmCut,
+                                              kbCtrlIns,   cmCopy,
+                                              kbCtrlDel,   cmClear);
+
+  { SCRLUP - Stop. } { Added ^W to scroll screen up.         }
+  { SCRLDN - Stop. } { Added ^Z to scroll screen down.       }
+  { REFORM - Stop. } { Added ^B for paragraph reformatting.  }
+  { PRETAB - Stop. } { Added ^I for preset tabbing.          }
+  { JLINE  - Stop. } { Added ^J to jump to a line number.    }
+  { INSLIN - Stop. } { Added ^N to insert line at cursor.    }
+  { INDENT - Stop. } { Removed ^O and put it into ^QI.       }
+  { HOMEND - Stop. } { Added kbCtrlHome and kbCtrlEnd pages. }
+  { CTRLBK - Stop. } { Added kbCtrlBack same as ^QH.         }
+
+  QuickKeys : array[0..21 * 2] of Word = (21, Ord ('0'), cmJumpMark0,
+                                              Ord ('1'), cmJumpMark1,
+                                              Ord ('2'), cmJumpMark2,
+                                              Ord ('3'), cmJumpMark3,
+                                              Ord ('4'), cmJumpMark4,
+                                              Ord ('5'), cmJumpMark5,
+                                              Ord ('6'), cmJumpMark6,
+                                              Ord ('7'), cmJumpMark7,
+                                              Ord ('8'), cmJumpMark8,
+                                              Ord ('9'), cmJumpMark9,
+                                              Ord ('A'), cmReplace,
+                                              Ord ('C'), cmTextEnd,
+                                              Ord ('D'), cmLineEnd,
+                                              Ord ('F'), cmFind,
+                                              Ord ('H'), cmDelStart,
+                                              Ord ('I'), cmIndentMode,
+                                              Ord ('L'), cmUndo,
+                                              Ord ('R'), cmTextStart,
+                                              Ord ('S'), cmLineStart,
+                                              Ord ('U'), cmReformDoc,
+                                              Ord ('Y'), cmDelEnd);
+
+  { UNDO   - Stop. } { Added IDE undo feature of ^QL.                  }
+  { REFDOC - Stop. } { Added document reformat feature if ^QU pressed. }
+  { MARK   - Stop. } { Added cmJumpMark# to allow place marking.       }
+  { INDENT - Stop. } { Moved IndentMode here from Firstkeys.           }
+
+  BlockKeys : array[0..20 * 2] of Word = (20, Ord ('0'), cmSetMark0,
+                                              Ord ('1'), cmSetMark1,
+                                              Ord ('2'), cmSetMark2,
+                                              Ord ('3'), cmSetMark3,
+                                              Ord ('4'), cmSetMark4,
+                                              Ord ('5'), cmSetMark5,
+                                              Ord ('6'), cmSetMark6,
+                                              Ord ('7'), cmSetMark7,
+                                              Ord ('8'), cmSetMark8,
+                                              Ord ('9'), cmSetMark9,
+                                              Ord ('B'), cmStartSelect,
+                                              Ord ('C'), cmPaste,
+                                              Ord ('D'), cmSave,
+                                              Ord ('F'), cmSaveAs,
+                                              Ord ('H'), cmHideSelect,
+                                              Ord ('K'), cmCopy,
+                                              Ord ('S'), cmSave,
+                                              Ord ('T'), cmSelectWord,
+                                              Ord ('Y'), cmCut,
+                                              Ord ('X'), cmSaveDone);
+
+  { SELWRD - Stop. } { Added ^KT to select word only. }
+  { SAVE   - Stop. } { Added ^KD, ^KF, ^KS, ^KX key commands.   }
+  { MARK   - Stop. } { Added cmSetMark# to allow place marking. }
+
+  FormatKeys : array[0..5 * 2] of Word = (5,  Ord ('C'), cmCenterText,
+                                              Ord ('T'), cmCenterText,
+                                              Ord ('I'), cmSetTabs,
+                                              Ord ('R'), cmRightMargin,
+                                              Ord ('W'), cmWordWrap);
+
+  { WRAP   - Stop. } { Added Wordwrap feature if ^OW pressed.          }
+  { RMSET  - Stop. } { Added set right margin feature if ^OR pressed.  }
+  { PRETAB - Stop. } { Added preset tab feature if ^OI pressed.        }
+  { CENTER - Stop. } { Added center text option ^OC for a line.        }
+
+  JumpKeys : array[0..1 * 2] of Word = (1, Ord ('L'), cmJumpLine);
+
+  { JLINE - Stop. } { Added jump to line number feature if ^JL pressed. }
+
+  KeyMap : array[0..4] of Pointer = (@FirstKeys,
+                                     @QuickKeys,
+                                     @BlockKeys,
+                                     @FormatKeys,
+                                     @JumpKeys);
+
+  { WRAP   - Stop. } { Added @FormatKeys for new ^O? keys. }
+  { PRETAB - Stop. } { Added @FormatKeys for new ^O? keys. }
+  { JLINE  - Stop. } { Added @JumpKeys for new ^J? keys.   }
+  { CENTER - Stop. } { Added @FormatKeys for new ^O? keys. }
+
+
+{****************************************************************************
+                                 Dialogs
+****************************************************************************}
+
+function DefEditorDialog (Dialog : Integer; Info : Pointer) : Word;
+begin
+  DefEditorDialog := cmCancel;
+end; { DefEditorDialog }
+
+
+function CreateFindDialog: PDialog;
+var
+  D: PDialog;
+  Control: PView;
+  R: TRect;
+begin
+  R.Assign(0, 0, 38, 12);
+  D := New(PDialog, Init(R, strings^.get(sFind)));
+  with D^ do
+  begin
+    Options := Options or ofCentered;
+
+    R.Assign(3, 3, 32, 4);
+    Control := New(PInputLine, Init(R, 80));
+    Control^.HelpCtx := hcDFindText;
+    Insert(Control);
+    R.Assign(2, 2, 15, 3);
+    Insert(New(PLabel, Init(R, labels^.get(slTextToFind), Control)));
+    R.Assign(32, 3, 35, 4);
+    Insert(New(PHistory, Init(R, PInputLine(Control), 10)));
+
+    R.Assign(3, 5, 35, 7);
+    Control := New(PCheckBoxes, Init(R,
+        NewSItem (labels^.get(slCaseSensitive),
+        NewSItem (labels^.get(slWholeWordsOnly),nil))));
+    Control^.HelpCtx := hcCCaseSensitive;
+    Insert(Control);
+
+    R.Assign(14, 9, 24, 11);
+    Control := New (PButton, Init(R,labels^.get(slOK),cmOk,bfDefault));
+    Control^.HelpCtx := hcDOk;
+    Insert (Control);
+
+    Inc(R.A.X, 12); Inc(R.B.X, 12);
+    Control := New (PButton, Init(R,labels^.get(slCancel),cmCancel, bfNormal));
+    Control^.HelpCtx := hcDCancel;
+    Insert (Control);
+
+    SelectNext(False);
+  end;
+  CreateFindDialog := D;
+end;
+
+
+function CreateReplaceDialog: PDialog;
+var
+  D: PDialog;
+  Control: PView;
+  R: TRect;
+begin
+  R.Assign(0, 0, 40, 16);
+  D := New(PDialog, Init(R,labels^.get(slReplace)));
+  with D^ do
+  begin
+    Options := Options or ofCentered;
+
+    R.Assign(3, 3, 34, 4);
+    Control := New(PInputLine, Init(R, 80));
+    Control^.HelpCtx := hcDFindText;
+    Insert(Control);
+    R.Assign(2, 2, 15, 3);
+    Insert(New(PLabel, Init(R,labels^.get(slTextToFind), Control)));
+    R.Assign(34, 3, 37, 4);
+    Insert(New(PHistory, Init(R, PInputLine(Control), 10)));
+
+    R.Assign(3, 6, 34, 7);
+    Control := New(PInputLine, Init(R, 80));
+    Control^.HelpCtx := hcDReplaceText;
+    Insert(Control);
+    R.Assign(2, 5, 12, 6);
+    Insert(New(PLabel, Init(R,labels^.get(slNewText), Control)));
+    R.Assign(34, 6, 37, 7);
+    Insert(New(PHistory, Init(R, PInputLine(Control), 11)));
+
+    R.Assign(3, 8, 37, 12);
+    Control := New (Dialogs.PCheckBoxes, Init (R,
+      NewSItem (labels^.get(slCasesensitive),
+      NewSItem (labels^.get(slWholewordsonly),
+      NewSItem (labels^.get(slPromptonreplace),
+      NewSItem (labels^.get(slReplaceall), nil))))));
+    Control^.HelpCtx := hcCCaseSensitive;
+    Insert (Control);
+
+    R.Assign (8, 13, 18, 15);
+    Control := New (PButton, Init (R,labels^.get(slOK), cmOk, bfDefault));
+    Control^.HelpCtx := hcDOk;
+    Insert (Control);
+
+    R.Assign (22, 13, 32, 15);
+    Control := New (PButton, Init (R,labels^.get(slCancel), cmCancel, bfNormal));
+    Control^.HelpCtx := hcDCancel;
+    Insert (Control);
+
+    SelectNext(False);
+  end;
+  CreateReplaceDialog := D;
+end;
+
+
+function JumpLineDialog : PDialog;
+VAR
+  D      : PDialog;
+  R      : TRect;
+  Control: PView;
+Begin
+  R.Assign (0, 0, 26, 8);
+  D := New(PDialog, Init(R,strings^.get(sJumpTo)));
+  with D^ do
+    begin
+      Options := Options or ofCentered;
+
+      R.Assign (3, 2, 15, 3);
+      Control := New (Dialogs.PStaticText, Init (R,labels^.get(slLineNumber)));
+      Insert (Control);
+
+      R.Assign (15, 2, 21, 3);
+      Control := New (Dialogs.PInputLine, Init (R, 4));
+      Control^.HelpCtx := hcDLineNumber;
+      Insert (Control);
+
+      R.Assign (21, 2, 24, 3);
+      Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 12)));
+
+      R.Assign (2, 5, 12, 7);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault));
+      Control^.HelpCtx := hcDOk;
+      Insert (Control);
+
+      R.Assign (14, 5, 24, 7);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal));
+      Control^.HelpCtx := hcDCancel;
+      Insert (Control);
+
+      SelectNext (False);
+    end;
+  JumpLineDialog := D;
+end; { JumpLineDialog }
+
+
+function ReformDocDialog : Dialogs.PDialog;
+  { This is a local function that brings up a dialog box  }
+  { that asks where to start reformatting the document.   }
+VAR
+  R            : TRect;
+  D            : Dialogs.PDialog;
+  Control      : PView;
+Begin
+  R.Assign (0, 0, 32, 11);
+  D := New (Dialogs.PDialog, Init (R, strings^.get(sReformatDocument)));
+  with D^ do
+    begin
+      Options := Options or ofCentered;
+
+      R.Assign (2, 2, 30, 3);
+      Control := New (Dialogs.PStaticText, Init (R, strings^.get(sSelectWhereToBegin)));
+      Insert (Control);
+
+      R.Assign (3, 3, 29, 4);
+      Control := New (Dialogs.PStaticText, Init (R, strings^.get(sReformattingTheDocument)));
+      Insert (Control);
+
+      R.Assign (50, 5, 68, 6);
+      Control := New (Dialogs.PLabel, Init (R, strings^.get(sReformatDocument), Control));
+      Insert (Control);
+
+      R.Assign (5, 5, 26, 7);
+      Control := New (Dialogs.PRadioButtons, Init (R,
+        NewSItem (labels^.get(slCurrentLine),
+        NewSItem (labels^.get(slEntireDocument), Nil))));
+      Control^.HelpCtx := hcDReformDoc;
+      Insert (Control);
+
+      R.Assign (4, 8, 14, 10);
+      Control := New (Dialogs.PButton, Init (R,labels^.get(slOK), cmOK, Dialogs.bfDefault));
+      Control^.HelpCtx := hcDOk;
+      Insert (Control);
+
+      R.Assign (17, 8, 27, 10);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal));
+      Control^.HelpCtx := hcDCancel;
+      Insert (Control);
+
+      SelectNext (False);
+    end;
+    ReformDocDialog := D;
+end; { ReformDocDialog }
+
+
+function RightMarginDialog : Dialogs.PDialog;
+  { This is a local function that brings up a dialog box }
+  { that allows the user to change the Right_Margin.     }
+VAR
+  R        : TRect;
+  D        : PDialog;
+  Control  : PView;
+Begin
+  R.Assign (0, 0, 26, 8);
+  D := New (Dialogs.PDialog, Init (R, strings^.get(sRightMargin)));
+  with D^ do
+    begin
+      Options := Options or ofCentered;
+
+      R.Assign (5, 2, 13, 3);
+      Control := New (Dialogs.PStaticText, Init (R, strings^.get(sSetting)));
+      Insert (Control);
+
+      R.Assign (13, 2, 18, 3);
+      Control := New (Dialogs.PInputLine, Init (R, 3));
+      Control^.HelpCtx := hcDRightMargin;
+      Insert (Control);
+
+      R.Assign (18, 2, 21, 3);
+      Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 13)));
+
+      R.Assign (2, 5, 12, 7);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault));
+      Control^.HelpCtx := hcDOk;
+      Insert (Control);
+
+      R.Assign (14, 5, 24, 7);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal));
+      Control^.HelpCtx := hcDCancel;
+      Insert (Control);
+
+      SelectNext (False);
+    end;
+  RightMarginDialog := D;
+end; { RightMarginDialog; }
+
+
+function TabStopDialog : Dialogs.PDialog;
+  { This is a local function that brings up a dialog box }
+  { that allows the user to set their own tab stops.     }
+VAR
+  Index      : Sw_Integer;       { Local Indexing variable.                 }
+  R          : TRect;
+  D          : PDialog;
+  Control    : PView;
+  Tab_Stop   : String[2];        { Local string to print tab column number. }
+Begin
+  R.Assign (0, 0, 80, 8);
+  D := New (Dialogs.PDialog, Init (R, strings^.get(sTabSettings)));
+  with D^ do
+    begin
+      Options := Options or ofCentered;
+
+      R.Assign (2, 2, 77, 3);
+      Control := New (Dialogs.PStaticText, Init (R,
+                  ' ....|....|....|....|....|....|....|....|....|....|....|....|....|....|....'));
+      Insert (Control);
+
+      for Index := 1 to 7 do
+        begin
+          R.Assign (Index * 10 + 1, 1, Index * 10 + 3, 2);
+          Str (Index * 10, Tab_Stop);
+          Control := New (Dialogs.PStaticText, Init (R, Tab_Stop));
+          Insert (Control);
+        end;
+
+      R.Assign (2, 3, 78, 4);
+      Control := New (Dialogs.PInputLine, Init (R, 74));
+      Control^.HelpCtx := hcDTabStops;
+      Insert (Control);
+
+      R.Assign (38, 5, 41, 6);
+      Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 14)));
+
+      R.Assign (27, 5, 37, 7);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault));
+      Control^.HelpCtx := hcDOk;
+      Insert (Control);
+
+      R.Assign (42, 5, 52, 7);
+      Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal));
+      Control^.HelpCtx := hcDCancel;
+      Insert (Control);
+      SelectNext (False);
+    end;
+  TabStopDialog := D;
+end { TabStopDialog };
+
+
+function StdEditorDialog(Dialog: Integer; Info: Pointer): Word;
+var
+  R: TRect;
+  T: TPoint;
+begin
+  case Dialog of
+    edOutOfMemory:
+      StdEditorDialog := MessageBox(strings^.get(sOutOfMemory), nil, mfError + mfOkButton);
+    edReadError:
+      StdEditorDialog := MessageBox(strings^.get(sFileReadError), @Info, mfError + mfOkButton);
+    edWriteError:
+      StdEditorDialog := MessageBox(strings^.get(sFileWriteError), @Info, mfError + mfOkButton);
+    edCreateError:
+      StdEditorDialog := MessageBox(strings^.get(sFileCreateError), @Info, mfError + mfOkButton);
+    edSaveModify:
+      StdEditorDialog := MessageBox(strings^.get(sModified), @Info, mfInformation + mfYesNoCancel);
+    edSaveUntitled:
+      StdEditorDialog := MessageBox(strings^.get(sFileUntitled), nil, mfInformation + mfYesNoCancel);
+    edSaveAs:
+      StdEditorDialog := Application^.ExecuteDialog(New(PFileDialog, Init('*.*',
+        labels^.get(slSaveFileAs), labels^.get(slName), fdOkButton, 101)), Info);
+    edFind:
+      StdEditorDialog := Application^.ExecuteDialog(CreateFindDialog, Info);
+    edSearchFailed:
+      StdEditorDialog := MessageBox(strings^.get(sSearchStringNotFound), nil, mfError + mfOkButton);
+    edReplace:
+      StdEditorDialog := Application^.ExecuteDialog(CreateReplaceDialog, Info);
+    edReplacePrompt:
+      begin
+        { Avoid placing the dialog on the same line as the cursor }
+        R.Assign(0, 1, 40, 8);
+        R.Move((Desktop^.Size.X - R.B.X) div 2, 0);
+        Desktop^.MakeGlobal(R.B, T);
+        Inc(T.Y);
+        if PPoint(Info)^.Y <= T.Y then
+          R.Move(0, Desktop^.Size.Y - R.B.Y - 2);
+        StdEditorDialog := MessageBoxRect(R, strings^.get(sReplaceThisOccurence),
+          nil, mfYesNoCancel + mfInformation);
+      end;
+    edJumpToLine:
+      StdEditorDialog := Application^.ExecuteDialog(JumpLineDialog, Info);
+    edSetTabStops:
+      StdEditorDialog := Application^.ExecuteDialog(TabStopDialog, Info);
+    edPasteNotPossible:
+      StdEditorDialog := MessageBox (strings^.get(sPasteNotPossible), nil, mfError + mfOkButton);
+    edReformatDocument:
+      StdEditorDialog := Application^.ExecuteDialog(ReformDocDialog, Info);
+    edReformatNotAllowed:
+      StdEditorDialog := MessageBox (strings^.get(sWordWrapOff), nil, mfError + mfOkButton);
+    edReformNotPossible:
+      StdEditorDialog := MessageBox (strings^.get(sReformatNotPossible), nil, mfError + mfOkButton);
+    edReplaceNotPossible:
+      StdEditorDialog := MessageBox (strings^.get(sReplaceNotPossible), nil, mfError + mfOkButton);
+    edRightMargin:
+      StdEditorDialog := Application^.ExecuteDialog(RightMarginDialog, Info);
+    edWrapNotPossible:
+      StdEditorDialog := MessageBox (strings^.get(sWordWrapNotPossible), nil, mfError + mfOKButton);
+  else
+    StdEditorDialog := MessageBox (strings^.get(sUnknownDialog), nil, mfError + mfOkButton);
+  end;
+end;
+
+
+{****************************************************************************
+                                 Helpers
+****************************************************************************}
+
+function CountLines(var Buf; Count: sw_Word): sw_Integer;
+var
+  p : pchar;
+  lines : sw_word;
+begin
+  p:=pchar(@buf);
+  lines:=0;
+  while (count>0) do
+   begin
+     if p^ in [#10,#13] then
+      begin
+        inc(lines);
+        if ord((p+1)^)+ord(p^)=23 then
+         begin
+           inc(p);
+           dec(count);
+           if count=0 then
+            break;
+         end;
+      end;
+     inc(p);
+     dec(count);
+   end;
+  CountLines:=Lines;
+end;
+
+
+procedure GetLimits(var Buf; Count: sw_Word;var lim:objects.TPoint);
+{ Get the limits needed for Buf, its an extended version of countlines (lim.y),
+  which also gets the maximum line length in lim.x }
+var
+  p : pchar;
+  len : sw_word;
+begin
+  lim.x:=0;
+  lim.y:=0;
+  len:=0;
+  p:=pchar(@buf);
+  while (count>0) do
+   begin
+     if p^ in [#10,#13] then
+      begin
+        if len>lim.x then
+         lim.x:=len;
+        inc(lim.y);
+        if ord((p+1)^)+ord(p^)=23 then
+         begin
+           inc(p);
+           dec(count);
+         end;
+        len:=0;
+      end
+     else
+      inc(len);
+     inc(p);
+     dec(count);
+   end;
+end;
+
+
+function ScanKeyMap(KeyMap: Pointer; KeyCode: Word): Word;
+var
+  p : pword;
+  count : sw_word;
+begin
+  p:=keymap;
+  count:=p^;
+  inc(p);
+  while (count>0) do
+   begin
+     if (lo(p^)=lo(keycode)) and
+        ((hi(p^)=0) or (hi(p^)=hi(keycode))) then
+      begin
+        inc(p);
+        scankeymap:=p^;
+        exit;
+      end;
+     inc(p,2);
+     dec(count);
+   end;
+  scankeymap:=0;
+end;
+
+
+Type
+  Btable = Array[0..255] of Byte;
+Procedure BMMakeTable(const s:string; Var t : Btable);
+{ Makes a Boyer-Moore search table. s = the search String t = the table }
+Var
+  x : sw_integer;
+begin
+  FillChar(t,sizeof(t),length(s));
+  For x := length(s) downto 1 do
+   if (t[ord(s[x])] = length(s)) then
+    t[ord(s[x])] := length(s) - x;
+end;
+
+
+function Scan(var Block; Size: Sw_Word;const Str: String): Sw_Word;
+Var
+  buffer : Array[0..MaxBufLength-1] of Byte Absolute block;
+  s2     : String;
+  len,
+  numb   : Sw_Word;
+  found  : Boolean;
+  bt     : Btable;
+begin
+  BMMakeTable(str,bt);
+  len:=length(str);
+  s2[0]:=chr(len);       { sets the length to that of the search String }
+  found:=False;
+  numb:=pred(len);
+  While (not found) and (numb<(size-len)) do
+   begin
+     { partial match }
+     if buffer[numb] = ord(str[len]) then
+      begin
+        { less partial! }
+        if buffer[numb-pred(len)] = ord(str[1]) then
+         begin
+           move(buffer[numb-pred(len)],s2[1],len);
+           if (str=s2) then
+            begin
+              found:=true;
+              break;
+            end;
+         end;
+        inc(numb);
+     end
+    else
+     inc(numb,Bt[buffer[numb]]);
+  end;
+  if not found then
+    Scan := NotFoundValue
+  else
+    Scan := numb - pred(len);
+end;
+
+
+function IScan(var Block; Size: Sw_Word;const Str: String): Sw_Word;
+Var
+  buffer : Array[0..MaxBufLength-1] of Char Absolute block;
+  s      : String;
+  len,
+  numb,
+  x      : Sw_Word;
+  found  : Boolean;
+  bt     : Btable;
+  p      : pchar;
+  c      : char;
+begin
+  len:=length(str);
+  { create uppercased string }
+  s[0]:=chr(len);
+  for x:=1to len do
+   begin
+     if str[x] in ['a'..'z'] then
+      s[x]:=chr(ord(str[x])-32)
+     else
+      s[x]:=str[x];
+   end;
+  BMMakeTable(s,bt);
+  found:=False;
+  numb:=pred(len);
+  While (not found) and (numb<(size-len)) do
+   begin
+     { partial match }
+     c:=buffer[numb];
+     if c in ['a'..'z'] then
+      c:=chr(ord(c)-32);
+     if (c=s[len]) then
+      begin
+        { less partial! }
+        p:=@buffer[numb-pred(len)];
+        x:=1;
+        while (x<=len) do
+         begin
+           if not(((p^ in ['a'..'z']) and (chr(ord(p^)-32)=s[x])) or
+                  (p^=s[x])) then
+            break;
+           inc(p);
+           inc(x);
+         end;
+        if (x>len) then
+         begin
+           found:=true;
+           break;
+         end;
+        inc(numb);
+     end
+    else
+     inc(numb,Bt[ord(c)]);
+  end;
+  if not found then
+    IScan := NotFoundValue
+  else
+    IScan := numb - pred(len);
+end;
+
+
+{****************************************************************************
+                                 TIndicator
+****************************************************************************}
+
+constructor TIndicator.Init (var Bounds : TRect);
+begin
+  Inherited Init (Bounds);
+  GrowMode := gfGrowLoY + gfGrowHiY;
+end; { TIndicator.Init }
+
+
+procedure TIndicator.Draw;
+VAR
+  Color : Byte;
+  Frame : Char;
+  L     : array[0..1] of Longint;
+  S     : String[15];
+  B     : TDrawBuffer;
+begin
+  if State and sfDragging = 0 then
+    begin
+      Color := GetColor (1);
+      Frame := #205;
+    end
+  else
+    begin
+      Color := GetColor (2);
+      Frame := #196;
+    end;
+  MoveChar (B, Frame, Color, Size.X);
+  { If the text has been modified, put an 'M' in the TIndicator display. }
+  if Modified then
+    WordRec (B[1]).Lo := 77;
+  { If WordWrap is active put a 'W' in the TIndicator display. }
+  if WordWrap then
+    WordRec (B[2]).Lo := 87
+  else
+    WordRec (B[2]).Lo := Byte (Frame);
+  { If AutoIndent is active put an 'I' in TIndicator display. }
+  if AutoIndent then
+    WordRec (B[0]).Lo := 73
+  else
+    WordRec (B[0]).Lo := Byte (Frame);
+  L[0] := Location.Y + 1;
+  L[1] := Location.X + 1;
+  FormatStr (S, ' %d:%d ', L);
+  MoveStr (B[9 - Pos (':', S)], S, Color);       { Changed original 8 to 9. }
+  WriteBuf (0, 0, Size.X, 1, B);
+end; { TIndicator.Draw }
+
+
+function TIndicator.GetPalette : PPalette;
+const
+  P : string[Length (CIndicator)] = CIndicator;
+begin
+  GetPalette := @P;
+end; { TIndicator.GetPalette }
+
+
+procedure TIndicator.SetState (AState : Word; Enable : Boolean);
+begin
+  Inherited SetState (AState, Enable);
+  if AState = sfDragging then
+    DrawView;
+end; { TIndicator.SetState }
+
+
+procedure TIndicator.SetValue (ALocation : Objects.TPoint; IsAutoIndent : Boolean;
+                                                           IsModified   : Boolean;
+                                                           IsWordWrap   : Boolean);
+begin
+  if (Location.X<>ALocation.X) or
+     (Location.Y<>ALocation.Y) or
+     (AutoIndent <> IsAutoIndent) or
+     (Modified <> IsModified) or
+     (WordWrap <> IsWordWrap) then
+   begin
+     Location   := ALocation;
+     AutoIndent := IsAutoIndent;    { Added provisions to show AutoIndent. }
+     Modified   := IsModified;
+     WordWrap   := IsWordWrap;      { Added provisions to show WordWrap.   }
+     DrawView;
+   end;
+end; { TIndicator.SetValue }
+
+
+{****************************************************************************
+                                 TLineInfo
+****************************************************************************}
+
+constructor TLineInfo.Init;
+begin
+  MaxPos:=0;
+  Grow(1);
+end;
+
+
+destructor TLineInfo.Done;
+begin
+  FreeMem(Info,MaxPos*sizeof(TLineInfoRec));
+end;
+
+
+procedure TLineInfo.Grow(pos:Sw_word);
+var
+  NewSize : Sw_word;
+  P : pointer;
+begin
+  NewSize:=(Pos+LineInfoGrow-(Pos mod LineInfoGrow));
+  GetMem(P,NewSize*sizeof(TLineInfoRec));
+  FillChar(P^,NewSize*sizeof(TLineInfoRec),0);
+  Move(Info^,P^,MaxPos*sizeof(TLineInfoRec));
+  Freemem(Info,MaxPos*sizeof(TLineInfoRec));
+  Info:=P;
+end;
+
+
+procedure TLineInfo.SetLen(pos,val:Sw_Word);
+begin
+  if pos>=MaxPos then
+   Grow(Pos);
+  Info^[Pos].Len:=val
+end;
+
+
+procedure TLineInfo.SetAttr(pos,val:Sw_Word);
+begin
+  if pos>=MaxPos then
+   Grow(Pos);
+  Info^[Pos].Attr:=val
+end;
+
+
+function TLineInfo.GetLen(pos:Sw_Word):Sw_Word;
+begin
+  GetLen:=Info^[Pos].Len;
+end;
+
+
+function TLineInfo.GetAttr(pos:Sw_Word):Sw_Word;
+begin
+  GetAttr:=Info^[Pos].Attr;
+end;
+
+
+
+{****************************************************************************
+                                 TEditor
+****************************************************************************}
+
+constructor TEditor.Init (var Bounds : TRect;
+                              AHScrollBar, AVScrollBar : PScrollBar;
+                              AIndicator : PIndicator; ABufSize : Sw_Word);
+var
+  Element : Byte;      { Place_Marker array element to initialize array with. }
+begin
+  Inherited Init (Bounds);
+  GrowMode := gfGrowHiX + gfGrowHiY;
+  Options := Options or ofSelectable;
+  Flags := EditorFlags;
+  EventMask := evMouseDown + evKeyDown + evCommand + evBroadcast;
+  ShowCursor;
+
+  HScrollBar := AHScrollBar;
+  VScrollBar := AVScrollBar;
+
+  Indicator := AIndicator;
+  BufSize := ABufSize;
+  CanUndo := True;
+  InitBuffer;
+
+  if assigned(Buffer) then
+    IsValid := True
+  else
+    begin
+      EditorDialog (edOutOfMemory, nil);
+      BufSize := 0;
+    end;
+
+  SetBufLen (0);
+
+  for Element := 1 to 10 do
+    Place_Marker[Element] := 0;
+
+  Element := 1;
+  while Element <= 70 do
+    begin
+      if Element mod 5 = 0 then
+        Insert ('x', Tab_Settings, Element)
+      else
+        Insert (#32, Tab_Settings, Element);
+      Inc (Element);
+    end;
+  { Default Right_Margin value.  Change it if you want another. }
+  Right_Margin := 76;
+  TabSize:=8;
+end; { TEditor.Init }
+
+
+constructor TEditor.Load (var S : Objects.TStream);
+begin
+  Inherited Load (S);
+  GetPeerViewPtr (S, HScrollBar);
+  GetPeerViewPtr (S, VScrollBar);
+  GetPeerViewPtr (S, Indicator);
+  S.Read (BufSize, SizeOf (Sw_Word));
+  S.Read (CanUndo, SizeOf (Boolean));
+  S.Read (AutoIndent,   SizeOf (AutoIndent));
+  S.Read (Line_Number,  SizeOf (Line_Number));
+  S.Read (Place_Marker, SizeOf (Place_Marker));
+  S.Read (Right_Margin, SizeOf (Right_Margin));
+  S.Read (Tab_Settings, SizeOf (Tab_Settings));
+  S.Read (Word_Wrap,    SizeOf (Word_Wrap));
+  InitBuffer;
+  if Assigned(Buffer) then
+    IsValid := True
+  else
+    begin
+      EditorDialog (edOutOfMemory, nil);
+      BufSize := 0;
+    end;
+  Lock;
+  SetBufLen (0);
+end; { TEditor.Load }
+
+
+destructor TEditor.Done;
+begin
+  DoneBuffer;
+  Inherited Done;
+end; { TEditor.Done }
+
+
+function TEditor.BufChar(P: Sw_Word): Char;
+begin
+  if P>=CurPtr then
+   inc(P,Gaplen);
+  BufChar:=Buffer^[P];
+end;
+
+
+function TEditor.BufPtr(P: Sw_Word): Sw_Word;
+begin
+  if P>=CurPtr then
+   BufPtr:=P+GapLen
+  else
+   BufPtr:=P;
+end;
+
+
+procedure TEditor.Center_Text (Select_Mode : Byte);
+{ This procedure will center the current line of text. }
+{ Centering is based on the current Right_Margin.      }
+{ If the Line_Length exceeds the Right_Margin, or the  }
+{ line is just a blank line, we exit and do nothing.   }
+VAR
+  Spaces      : array [1..80] of Char;  { Array to hold spaces we'll insert. }
+  Index       : Byte;                   { Index into Spaces array.           }
+  Line_Length : Sw_Integer;             { Holds the length of the line.      }
+  E,S : Sw_Word;                        { End of the current line.           }
+begin
+  E := LineEnd (CurPtr);
+  S := LineStart (CurPtr);
+  { If the line is blank (only a CR/LF on it) then do noting. }
+  if E = S then
+    Exit;
+  { Set CurPtr to start of line.  Check if line begins with a space.  }
+  { We must strip out any spaces from the beginning, or end of lines. }
+  { If line does not start with space, make sure line length does not }
+  { exceed the Right_Margin.  If it does, then do nothing.            }
+  SetCurPtr (S, Select_Mode);
+  Remove_EOL_Spaces (Select_Mode);
+  if Buffer^[CurPtr] = #32 then
+    begin
+      { If the next word is greater than the end of line then do nothing. }
+      { If the line length is greater than Right_Margin then do nothing.  }
+      { Otherwise, delete all spaces at the start of line.                }
+      { Then reset end of line and put CurPtr at start of modified line.  }
+      E := LineEnd (CurPtr);
+      if NextWord (CurPtr) > E then
+        Exit;
+      if E - NextWord (CurPtr) > Right_Margin then
+        Exit;
+      DeleteRange (CurPtr, NextWord (CurPtr), True);
+      E := LineEnd (CurPtr);
+      SetCurPtr (LineStart (CurPtr), Select_Mode);
+    end
+  else
+    if E - CurPtr > Right_Margin then
+      Exit;
+  { Now we determine the real length of the line.       }
+  { Then we subtract the Line_Length from Right_Margin. }
+  { Dividing the result by two tells us how many spaces }
+  { must be inserted at start of line to center it.     }
+  { When we're all done, set the CurPtr to end of line. }
+  Line_Length := E - CurPtr;
+  for Index := 1 to ((Right_Margin - Line_Length) shr 1) do
+    Spaces[Index] := #32;
+  InsertText (@Spaces, Index, False);
+  SetCurPtr (LineEnd (CurPtr), Select_Mode);
+end; { TEditor.Center_Text }
+
+
+procedure TEditor.ChangeBounds (var Bounds : TRect);
+begin
+  SetBounds (Bounds);
+  Delta.X := Max (0, Min (Delta.X, Limit.X - Size.X));
+  Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y));
+  Update (ufView);
+end; { TEditor.ChangeBounds }
+
+
+function TEditor.CharPos (P, Target : Sw_Word) : Sw_Integer;
+VAR
+  Pos : Sw_Integer;
+begin
+  Pos := 0;
+  while P < Target do
+   begin
+     if BufChar (P) = #9 then
+       Pos := Pos or 7;
+     Inc (Pos);
+     Inc (P);
+   end;
+  CharPos := Pos;
+end; { TEditor.CharPos }
+
+
+function TEditor.CharPtr (P : Sw_Word; Target : Sw_Integer) : Sw_Word;
+VAR
+  Pos : Sw_Integer;
+begin
+  Pos := 0;
+  while (Pos < Target) and (P < BufLen) and  not(BufChar (P) in [#10,#13]) do
+  begin
+    if BufChar (P) = #9 then
+      Pos := Pos or 7;
+    Inc (Pos);
+    Inc (P);
+  end;
+  if Pos > Target then
+    Dec (P);
+  CharPtr := P;
+end; { TEditor.CharPtr }
+
+
+procedure TEditor.Check_For_Word_Wrap (Select_Mode   : Byte;
+                                       Center_Cursor : Boolean);
+{ This procedure checks if CurPos.X > Right_Margin. }
+{ If it is, then we Do_Word_Wrap.  Simple, eh?      }
+begin
+  if CurPos.X > Right_Margin then
+    Do_Word_Wrap (Select_Mode, Center_Cursor);
+end; {Check_For_Word_Wrap}
+
+
+function TEditor.ClipCopy : Boolean;
+begin
+  ClipCopy := False;
+  if Assigned(Clipboard) and (Clipboard <> @Self) then
+   begin
+     ClipCopy := Clipboard^.InsertFrom (@Self);
+     Selecting := False;
+     Update (ufUpdate);
+  end;
+end; { TEditor.ClipCopy }
+
+
+procedure TEditor.ClipCut;
+begin
+  if ClipCopy then
+  begin
+    Update_Place_Markers (0,
+                          Self.SelEnd - Self.SelStart,
+                          Self.SelStart,
+                          Self.SelEnd);
+    DeleteSelect;
+  end;
+end; { TEditor.ClipCut }
+
+
+procedure TEditor.ClipPaste;
+begin
+  if Assigned(Clipboard) and (Clipboard <> @Self) then
+    begin
+      { Do not allow paste operations that will exceed }
+      { the Right_Margin when Word_Wrap is active and  }
+      { cursor is at EOL.                              }
+      if Word_Wrap and (CurPos.X > Right_Margin) then
+        begin
+          EditorDialog (edPasteNotPossible, nil);
+          Exit;
+        end;
+      { The editor will not copy selected text if the CurPtr }
+      { is not the same value as the SelStart.  However, it  }
+      { does return an InsCount.  This may, or may not, be a }
+      { bug.  We don't want to update the Place_Marker if    }
+      { there's no text copied.                              }
+      if CurPtr = SelStart then
+        Update_Place_Markers (Clipboard^.SelEnd - Clipboard^.SelStart,
+                              0,
+                              Clipboard^.SelStart,
+                              Clipboard^.SelEnd);
+      InsertFrom (Clipboard);
+    end;
+end; { TEditor.ClipPaste }
+
+
+procedure TEditor.ConvertEvent (var Event : Drivers.TEvent);
+VAR
+  ShiftState : Byte;
+  Key        : Word;
+begin
+  ShiftState:=GetShiftState;
+  if Event.What = evKeyDown then
+  begin
+    if (ShiftState and $03 <> 0)
+                   and (Event.ScanCode >= $47)
+                   and (Event.ScanCode <= $51) then
+      Event.CharCode := #0;
+    Key := Event.KeyCode;
+    if KeyState <> 0 then
+    begin
+      if (Lo (Key) >= $01) and (Lo (Key) <= $1A) then
+        Inc (Key, $40);
+      if (Lo (Key) >= $61) and (Lo (Key) <= $7A) then
+        Dec (Key, $20);
+    end;
+    Key := ScanKeyMap (KeyMap[KeyState], Key);
+    KeyState := 0;
+    if Key <> 0 then
+      if Hi (Key) = $FF then
+        begin
+          KeyState := Lo (Key);
+          ClearEvent (Event);
+        end
+      else
+        begin
+          Event.What := evCommand;
+          Event.Command := Key;
+        end;
+  end;
+end; { TEditor.ConvertEvent }
+
+
+function TEditor.CursorVisible : Boolean;
+begin
+  CursorVisible := (CurPos.Y >= Delta.Y) and (CurPos.Y < Delta.Y + Size.Y);
+end; { TEditor.CursorVisible }
+
+
+procedure TEditor.DeleteRange (StartPtr, EndPtr : Sw_Word; DelSelect : Boolean);
+begin
+  { This will update Place_Marker for all deletions. }
+  { EXCEPT the Remove_EOL_Spaces deletion.           }
+  Update_Place_Markers (0, EndPtr - StartPtr, StartPtr, EndPtr);
+  if HasSelection and DelSelect then
+    DeleteSelect
+  else
+    begin
+      SetSelect (CurPtr, EndPtr, True);
+      DeleteSelect;
+      SetSelect (StartPtr, CurPtr, False);
+      DeleteSelect;
+    end;
+end; { TEditor.DeleteRange }
+
+
+procedure TEditor.DeleteSelect;
+begin
+  InsertText (nil, 0, False);
+end; { TEditor.DeleteSelect }
+
+
+procedure TEditor.DoneBuffer;
+begin
+  if assigned(Buffer) then
+  begin
+    FreeMem (Buffer, BufSize);
+    Buffer := nil;
+  end;
+end; { TEditor.DoneBuffer }
+
+
+procedure TEditor.DoSearchReplace;
+VAR
+  I : Sw_Word;
+  C : Objects.TPoint;
+begin
+  repeat
+    I := cmCancel;
+    if not Search (FindStr, Flags) then
+      begin
+        if Flags and (efReplaceAll + efDoReplace) <> (efReplaceAll + efDoReplace) then
+          EditorDialog (edSearchFailed, nil)
+      end
+    else
+      if Flags and efDoReplace <> 0 then
+      begin
+        I := cmYes;
+        if Flags and efPromptOnReplace <> 0 then
+        begin
+          MakeGlobal (Cursor, C);
+          I := EditorDialog (edReplacePrompt, Pointer(@C));
+        end;
+        if I = cmYes then
+          begin
+            { If Word_Wrap is active and we are at EOL }
+            { disallow replace by bringing up a dialog }
+            { stating that replace is not possible.    }
+            if Word_Wrap and
+               ((CurPos.X + (Length (ReplaceStr) - Length (FindStr))) > Right_Margin) then
+              EditorDialog (edReplaceNotPossible, nil)
+            else
+              begin
+                Lock;
+                Search_Replace := True;
+                if length (ReplaceStr) < length (FindStr) then
+                  Update_Place_Markers (0,
+                                        Length (FindStr) - Length (ReplaceStr),
+                                        CurPtr - Length (FindStr) + Length (ReplaceStr),
+                                        CurPtr)
+                else
+                  if length (ReplaceStr) > length (FindStr) then
+                    Update_Place_Markers (Length (ReplaceStr) - Length (FindStr),
+                                          0,
+                                          CurPtr,
+                                          CurPtr + (Length (ReplaceStr) - Length (FindStr)));
+                InsertText (@ReplaceStr[1], Length (ReplaceStr), False);
+                Search_Replace := False;
+                TrackCursor (False);
+                Unlock;
+             end;
+          end;
+      end;
+  until (I = cmCancel) or (Flags and efReplaceAll = 0);
+end; { TEditor.DoSearchReplace }
+
+
+procedure TEditor.DoUpdate;
+begin
+  if UpdateFlags <> 0 then
+  begin
+    SetCursor (CurPos.X - Delta.X, CurPos.Y - Delta.Y);
+    if UpdateFlags and ufView <> 0 then
+      DrawView
+    else
+      if UpdateFlags and ufLine <> 0 then
+        DrawLines (CurPos.Y - Delta.Y, 1, LineStart (CurPtr));
+    if assigned(HScrollBar) then
+      HScrollBar^.SetParams (Delta.X, 0, Limit.X - Size.X, Size.X div 2, 1);
+    if assigned(VScrollBar) then
+      VScrollBar^.SetParams (Delta.Y, 0, Limit.Y - Size.Y, Size.Y - 1, 1);
+    if assigned(Indicator) then
+      Indicator^.SetValue (CurPos, AutoIndent, Modified, Word_Wrap);
+    if State and sfActive <> 0 then
+      UpdateCommands;
+    UpdateFlags := 0;
+  end;
+end; { TEditor.DoUpdate }
+
+
+function TEditor.Do_Word_Wrap (Select_Mode   : Byte;
+                               Center_Cursor : Boolean) : Boolean;
+{ This procedure does the actual wordwrap.  It always assumes the CurPtr }
+{ is at Right_Margin + 1.  It makes several tests for special conditions }
+{ and processes those first.  If they all fail, it does a normal wrap.   }
+VAR
+  A : Sw_Word;          { Distance between line start and first word on line. }
+  C : Sw_Word;          { Current pointer when we come into procedure.        }
+  L : Sw_Word;          { BufLen when we come into procedure.                 }
+  P : Sw_Word;          { Position of pointer at any given moment.            }
+  S : Sw_Word;          { Start of a line.                                    }
+begin
+  Do_Word_Wrap := False;
+  Select_Mode := 0;
+  if BufLen >= (BufSize - 1) then
+    exit;
+  C := CurPtr;
+  L := BufLen;
+  S := LineStart (CurPtr);
+  { If first character in the line is a space and autoindent mode is on  }
+  { then we check to see if NextWord(S) exceeds the CurPtr.  If it does, }
+  { we set CurPtr as the AutoIndent marker.  If it doesn't, we will set  }
+  { NextWord(S) as the AutoIndent marker.  If neither, we set it to S.   }
+  if AutoIndent and (Buffer^[S] = ' ') then
+    begin
+      if NextWord (S) > CurPtr then
+        A := CurPtr
+      else
+        A := NextWord (S);
+    end
+  else
+    A := NextWord (S);
+  { Though NewLine will remove EOL spaces, we do it here too. }
+  { This catches the instance where a user may try to space   }
+  { completely across the line, in which case CurPtr.X = 0.   }
+  Remove_EOL_Spaces (Select_Mode);
+  if CurPos.X = 0 then
+    begin
+      NewLine (Select_Mode);
+      Do_Word_Wrap := True;
+      Exit;
+    end;
+  { At this point we have one of five situations:                               }
+  {                                                                             }
+  { 1)  AutoIndent is on and this line is all spaces before CurPtr.             }
+  { 2)  AutoIndent is off and this line is all spaces before CurPtr.            }
+  { 3)  AutoIndent is on and this line is continuous characters before CurPtr.  }
+  { 4)  AutoIndent is off and this line is continuous characters before CurPtr. }
+  { 5)  This is just a normal line of text.                                     }
+  {                                                                             }
+  { Conditions 1 through 4 have to be taken into account before condition 5.    }
+  { First, we see if there are all spaces and/or all characters. }
+  { Then we determine which one it really is.  Finally, we take  }
+  { a course of action based on the state of AutoIndent.         }
+  if PrevWord (CurPtr) <= S then
+    begin
+      P := CurPtr - 1;
+      while ((Buffer^[P] <> ' ') and (P > S)) do
+        Dec (P);
+      { We found NO SPACES.  Conditions 4 and 5 are treated the same.  }
+      { We can NOT do word wrap and put up a dialog box stating such.  }
+      { Delete character just entered so we don't exceed Right_Margin. }
+      if P = S then
+        begin
+          EditorDialog (edWrapNotPossible, nil);
+          DeleteRange (PrevChar (CurPtr), CurPtr, True);
+          Exit;
+        end
+      else
+        begin
+          { There are spaces.  Now find out if they are all spaces. }
+          { If so, see if AutoIndent is on.  If it is, turn it off, }
+          { do a NewLine, and turn it back on.  Otherwise, just do  }
+          { the NewLine.  We go through all of these gyrations for  }
+          { AutoIndent.  Being way out here with a preceding line   }
+          { of spaces and wrapping with AutoIndent on is real dumb! }
+          { However, the user expects something.  The wrap will NOT }
+          { autoindent, but they had no business being here anyway! }
+          P := CurPtr - 1;
+          while ((Buffer^[P] = ' ') and (P > S)) do
+            Dec (P);
+          if P = S then
+            begin
+              if Autoindent then
+                begin
+                  AutoIndent := False;
+                  NewLine (Select_Mode);
+                  AutoIndent := True;
+                end
+              else
+                NewLine (Select_Mode);
+              end; { AutoIndent }
+            end; { P = S for spaces }
+        end { P = S for no spaces }
+    else { PrevWord (CurPtr) <= S }
+      begin
+        { Hooray!  We actually had a plain old line of text to wrap!       }
+        { Regardless if we are pushing out a line beyond the Right_Margin, }
+        { or at the end of a line itself, the following will determine     }
+        { exactly where to do the wrap and re-set the cursor accordingly.  }
+        { However, if P = A then we can't wrap.  Show dialog and exit.     }
+        P := CurPtr;
+        while P - S > Right_Margin do
+          P := PrevWord (P);
+        if (P = A) then
+          begin
+            EditorDialog (edReformNotPossible, nil);
+            SetCurPtr (P, Select_Mode);
+            Exit;
+          end;
+        SetCurPtr (P, Select_Mode);
+        NewLine (Select_Mode);
+    end; { PrevWord (CurPtr <= S }
+  { Track the cursor here (it is at CurPos.X = 0) so the view  }
+  { will redraw itself at column 0.  This eliminates having it }
+  { redraw starting at the current cursor and not being able   }
+  { to see text before the cursor.  Of course, we also end up  }
+  { redrawing the view twice, here and back in HandleEvent.    }
+  {                                                            }
+  { Reposition cursor so user can pick up where they left off. }
+  TrackCursor (Center_Cursor);
+  SetCurPtr (C - (L - BufLen), Select_Mode);
+  Do_Word_Wrap := True;
+end; { TEditor.Do_Word_Wrap }
+
+
+procedure TEditor.Draw;
+begin
+  if DrawLine <> Delta.Y then
+  begin
+    DrawPtr := LineMove (DrawPtr, Delta.Y - DrawLine);
+    DrawLine := Delta.Y;
+  end;
+  DrawLines (0, Size.Y, DrawPtr);
+end; { TEditor.Draw }
+
+
+procedure TEditor.DrawLines (Y, Count : Sw_Integer; LinePtr : Sw_Word);
+VAR
+  Color : Word;
+  B     : array[0..MaxLineLength - 1] of Sw_Word;
+begin
+  Color := GetColor ($0201);
+  while Count > 0 do
+  begin
+    FormatLine (B, LinePtr, Delta.X + Size.X, Color);
+    WriteBuf (0, Y, Size.X, 1, B[Delta.X]);
+    LinePtr := NextLine (LinePtr);
+    Inc (Y);
+    Dec (Count);
+  end;
+end; { TEditor.DrawLines }
+
+
+procedure TEditor.Find;
+VAR
+  FindRec : TFindDialogRec;
+begin
+  with FindRec do
+  begin
+    Find := FindStr;
+    Options := Flags;
+    if EditorDialog (edFind, @FindRec) <> cmCancel then
+    begin
+      FindStr := Find;
+      Flags := Options and not efDoReplace;
+      DoSearchReplace;
+    end;
+  end;
+end; { TEditor.Find }
+
+
+procedure TEditor.FormatLine (var DrawBuf; LinePtr : Sw_Word;
+                                  Width  : Sw_Integer;
+                                  Colors : Word);
+var
+  outptr : pword;
+  outcnt,
+  idxpos : Sw_Word;
+  attr   : Word;
+
+  procedure FillSpace(i:Sw_Word);
+  var
+    w : word;
+  begin
+    inc(OutCnt,i);
+    w:=32 or attr;
+    while (i>0) do
+     begin
+       OutPtr^:=w;
+       inc(OutPtr);
+       dec(i);
+     end;
+  end;
+
+  function FormatUntil(endpos:Sw_word):boolean;
+  var
+    p : pchar;
+  begin
+    FormatUntil:=false;
+    p:=pchar(Buffer)+idxpos;
+    while endpos>idxpos do
+     begin
+       if OutCnt>=Width then
+        exit;
+       case p^ of
+         #9 :
+           FillSpace(Tabsize-(outcnt mod Tabsize));
+         #10,#13 :
+           begin
+             FillSpace(Width-OutCnt);
+             FormatUntil:=true;
+             exit;
+           end;
+         else
+           begin
+             inc(OutCnt);
+             OutPtr^:=ord(p^) or attr;
+             inc(OutPtr);
+           end;
+       end; { case }
+       inc(p);
+       inc(idxpos);
+     end;
+  end;
+
+begin
+  OutCnt:=0;
+  OutPtr:=@DrawBuf;
+  idxPos:=LinePtr;
+  attr:=lo(Colors) shl 8;
+  if FormatUntil(SelStart) then
+   exit;
+  attr:=hi(Colors) shl 8;
+  if FormatUntil(CurPtr) then
+   exit;
+  inc(idxPos,GapLen);
+  if FormatUntil(SelEnd+GapLen) then
+   exit;
+  attr:=lo(Colors) shl 8;
+  if FormatUntil(BufSize) then
+   exit;
+{ fill up until width }
+  FillSpace(Width-OutCnt);
+end; {TEditor.FormatLine}
+
+
+function TEditor.GetMousePtr (Mouse : Objects.TPoint) : Sw_Word;
+begin
+  MakeLocal (Mouse, Mouse);
+  Mouse.X := Max (0, Min (Mouse.X, Size.X - 1));
+  Mouse.Y := Max (0, Min (Mouse.Y, Size.Y - 1));
+  GetMousePtr := CharPtr (LineMove (DrawPtr, Mouse.Y + Delta.Y - DrawLine),
+                          Mouse.X + Delta.X);
+end; { TEditor.GetMousePtr }
+
+
+function TEditor.GetPalette : PPalette;
+CONST
+  P : String[Length (CEditor)] = CEditor;
+begin
+  GetPalette := @P;
+end; { TEditor.GetPalette }
+
+
+procedure TEditor.HandleEvent (var Event : Drivers.TEvent);
+VAR
+  ShiftState   : Byte;
+  CenterCursor : Boolean;
+  SelectMode   : Byte;
+  D            : Objects.TPoint;
+  Mouse        : Objects.TPoint;
+
+  function CheckScrollBar (P : PScrollBar; var D : Sw_Integer) : Boolean;
+  begin
+    CheckScrollBar := FALSE;
+    if (Event.InfoPtr = P) and (P^.Value <> D) then
+    begin
+      D := P^.Value;
+      Update (ufView);
+      CheckScrollBar := TRUE;
+    end;
+  end; {CheckScrollBar}
+
+begin
+  Inherited HandleEvent (Event);
+  ConvertEvent (Event);
+  CenterCursor := not CursorVisible;
+  SelectMode := 0;
+  ShiftState:=GetShiftState;
+  if Selecting or (ShiftState and $03 <> 0) then
+    SelectMode := smExtend;
+  case Event.What of
+    Drivers.evMouseDown:
+      begin
+        if Event.Double then
+          SelectMode := SelectMode or smDouble;
+        repeat
+          Lock;
+          if Event.What = evMouseAuto then
+          begin
+            MakeLocal (Event.Where, Mouse);
+            D := Delta;
+            if Mouse.X < 0 then
+              Dec (D.X);
+            if Mouse.X >= Size.X then
+              Inc (D.X);
+            if Mouse.Y < 0 then
+              Dec (D.Y);
+            if Mouse.Y >= Size.Y then
+              Inc (D.Y);
+            ScrollTo (D.X, D.Y);
+          end;
+          SetCurPtr (GetMousePtr (Event.Where), SelectMode);
+          SelectMode := SelectMode or smExtend;
+          Unlock;
+        until not MouseEvent (Event, evMouseMove + evMouseAuto);
+      end; { Drivers.evMouseDown }
+
+    Drivers.evKeyDown:
+      case Event.CharCode of
+        #32..#255:
+          begin
+            Lock;
+            if Overwrite and not HasSelection then
+              if CurPtr <> LineEnd (CurPtr) then
+                SelEnd := NextChar (CurPtr);
+            InsertText (@Event.CharCode, 1, False);
+            if Word_Wrap then
+              Check_For_Word_Wrap (SelectMode, CenterCursor);
+            TrackCursor (CenterCursor);
+            Unlock;
+          end;
+
+      else
+        Exit;
+      end; { Drivers.evKeyDown }
+
+    Drivers.evCommand:
+      case Event.Command of
+        cmFind        : Find;
+        cmReplace     : Replace;
+        cmSearchAgain : DoSearchReplace;
+      else
+        begin
+          Lock;
+          case Event.Command of
+            cmCut         : ClipCut;
+            cmCopy        : ClipCopy;
+            cmPaste       : ClipPaste;
+            cmUndo        : Undo;
+            cmClear       : DeleteSelect;
+            cmCharLeft    : SetCurPtr (PrevChar  (CurPtr), SelectMode);
+            cmCharRight   : SetCurPtr (NextChar  (CurPtr), SelectMode);
+            cmWordLeft    : SetCurPtr (PrevWord  (CurPtr), SelectMode);
+            cmWordRight   : SetCurPtr (NextWord  (CurPtr), SelectMode);
+            cmLineStart   : SetCurPtr (LineStart (CurPtr), SelectMode);
+            cmLineEnd     : SetCurPtr (LineEnd   (CurPtr), SelectMode);
+            cmLineUp      : SetCurPtr (LineMove  (CurPtr, -1), SelectMode);
+            cmLineDown    : SetCurPtr (LineMove  (CurPtr, 1),  SelectMode);
+            cmPageUp      : SetCurPtr (LineMove  (CurPtr, - (Size.Y - 1)), SelectMode);
+            cmPageDown    : SetCurPtr (LineMove  (CurPtr, Size.Y - 1), SelectMode);
+            cmTextStart   : SetCurPtr (0, SelectMode);
+            cmTextEnd     : SetCurPtr (BufLen, SelectMode);
+            cmNewLine     : NewLine (SelectMode);
+            cmBackSpace   : DeleteRange (PrevChar (CurPtr), CurPtr, True);
+            cmDelChar     : DeleteRange (CurPtr, NextChar (CurPtr), True);
+            cmDelWord     : DeleteRange (CurPtr, NextWord (CurPtr), False);
+            cmDelStart    : DeleteRange (LineStart (CurPtr), CurPtr, False);
+            cmDelEnd      : DeleteRange (CurPtr, LineEnd (CurPtr), False);
+            cmDelLine     : DeleteRange (LineStart (CurPtr), NextLine (CurPtr), False);
+            cmInsMode     : ToggleInsMode;
+            cmStartSelect : StartSelect;
+            cmHideSelect  : HideSelect;
+            cmIndentMode  : begin
+                              AutoIndent := not AutoIndent;
+                              Update (ufStats);
+                            end; { Added provision to update TIndicator if ^QI pressed. }
+            cmCenterText  : Center_Text (SelectMode);
+            cmEndPage     : SetCurPtr (LineMove  (CurPtr, Delta.Y - CurPos.Y + Size.Y - 1), SelectMode);
+            cmHomePage    : SetCurPtr (LineMove  (CurPtr, -(CurPos.Y - Delta.Y)), SelectMode);
+            cmInsertLine  : Insert_Line (SelectMode);
+            cmJumpLine    : Jump_To_Line (SelectMode);
+            cmReformDoc   : Reformat_Document (SelectMode, CenterCursor);
+            cmReformPara  : Reformat_Paragraph (SelectMode, CenterCursor);
+            cmRightMargin : Set_Right_Margin;
+            cmScrollDown  : Scroll_Down;
+            cmScrollUp    : Scroll_Up;
+            cmSelectWord  : Select_Word;
+            cmSetTabs     : Set_Tabs;
+            cmTabKey      : Tab_Key (SelectMode);
+            cmWordWrap    : begin
+                              Word_Wrap := not Word_Wrap;
+                              Update (ufStats);
+                            end; { Added provision to update TIndicator if ^OW pressed. }
+            cmSetMark0    : Set_Place_Marker (10);
+            cmSetMark1    : Set_Place_Marker  (1);
+            cmSetMark2    : Set_Place_Marker  (2);
+            cmSetMark3    : Set_Place_Marker  (3);
+            cmSetMark4    : Set_Place_Marker  (4);
+            cmSetMark5    : Set_Place_Marker  (5);
+            cmSetMark6    : Set_Place_Marker  (6);
+            cmSetMark7    : Set_Place_Marker  (7);
+            cmSetMark8    : Set_Place_Marker  (8);
+            cmSetMark9    : Set_Place_Marker  (9);
+            cmJumpMark0   : Jump_Place_Marker (10, SelectMode);
+            cmJumpMark1   : Jump_Place_Marker  (1, SelectMode);
+            cmJumpMark2   : Jump_Place_Marker  (2, SelectMode);
+            cmJumpMark3   : Jump_Place_Marker  (3, SelectMode);
+            cmJumpMark4   : Jump_Place_Marker  (4, SelectMode);
+            cmJumpMark5   : Jump_Place_Marker  (5, SelectMode);
+            cmJumpMark6   : Jump_Place_Marker  (6, SelectMode);
+            cmJumpMark7   : Jump_Place_Marker  (7, SelectMode);
+            cmJumpMark8   : Jump_Place_Marker  (8, SelectMode);
+            cmJumpMark9   : Jump_Place_Marker  (9, SelectMode);
+          else
+            Unlock;
+            Exit;
+          end; { Event.Command (Inner) }
+          TrackCursor (CenterCursor);
+          { If the user presses any key except cmNewline or cmBackspace  }
+          { we need to check if the file has been modified yet.  There   }
+          { can be no spaces at the end of a line, or wordwrap doesn't   }
+          { work properly.  We don't want to do this if the file hasn't  }
+          { been modified because the user could be bringing in an ASCII }
+          { file from an editor that allows spaces at the EOL.  If we    }
+          { took them out in that scenario the "M" would appear on the   }
+          { TIndicator line and the user would get upset or confused.    }
+          if (Event.Command <> cmNewLine)   and
+             (Event.Command <> cmBackSpace) and
+             (Event.Command <> cmTabKey)    and
+              Modified then
+            Remove_EOL_Spaces (SelectMode);
+          Unlock;
+        end; { Event.Command (Outer) }
+      end; { Drivers.evCommand }
+
+    Drivers.evBroadcast:
+      case Event.Command of
+        cmScrollBarChanged:
+          if (Event.InfoPtr = HScrollBar) or
+            (Event.InfoPtr = VScrollBar) then
+          begin
+            CheckScrollBar (HScrollBar, Delta.X);
+            CheckScrollBar (VScrollBar, Delta.Y);
+          end
+          else
+            exit;
+      else
+        Exit;
+      end; { Drivers.evBroadcast }
+
+  end;
+  ClearEvent (Event);
+end; { TEditor.HandleEvent }
+
+
+function TEditor.HasSelection : Boolean;
+begin
+  HasSelection := SelStart <> SelEnd;
+end; { TEditor.HasSelection }
+
+
+procedure TEditor.HideSelect;
+begin
+  Selecting := False;
+  SetSelect (CurPtr, CurPtr, False);
+end; { TEditor.HideSelect }
+
+
+procedure TEditor.InitBuffer;
+begin
+  Buffer := MemAlloc (BufSize);
+end; { TEditor.InitBuffer }
+
+
+function TEditor.InsertBuffer (var P : PEditBuffer;
+                               Offset,    Length     : Sw_Word;
+                               AllowUndo, SelectText : Boolean) : Boolean;
+VAR
+  SelLen   : Sw_Word;
+  DelLen   : Sw_Word;
+  SelLines : Sw_Word;
+  Lines    : Sw_Word;
+  NewSize  : Longint;
+begin
+  InsertBuffer := True;
+  Selecting := False;
+  SelLen := SelEnd - SelStart;
+  if (SelLen = 0) and (Length = 0) then
+    Exit;
+  DelLen := 0;
+  if AllowUndo then
+    if CurPtr = SelStart then
+      DelLen := SelLen
+    else
+      if SelLen > InsCount then
+        DelLen := SelLen - InsCount;
+  NewSize := Longint (BufLen + DelCount - SelLen + DelLen) + Length;
+  if NewSize > BufLen + DelCount then
+    if (NewSize > MaxBufLength) or not SetBufSize (NewSize) then
+      begin
+        EditorDialog (edOutOfMemory, nil);
+        InsertBuffer := False;
+        SelEnd := SelStart;
+        Exit;
+      end;
+  SelLines := CountLines (Buffer^[BufPtr (SelStart)], SelLen);
+  if CurPtr = SelEnd then
+  begin
+    if AllowUndo then
+    begin
+      if DelLen > 0 then
+        Move (Buffer^[SelStart], Buffer^[CurPtr + GapLen - DelCount - DelLen], DelLen);
+      Dec (InsCount, SelLen - DelLen);
+    end;
+    CurPtr := SelStart;
+    Dec (CurPos.Y, SelLines);
+  end;
+  if Delta.Y > CurPos.Y then
+    begin
+      Dec (Delta.Y, SelLines);
+      if Delta.Y < CurPos.Y then
+        Delta.Y := CurPos.Y;
+    end;
+  if Length > 0 then
+    Move (P^[Offset], Buffer^[CurPtr], Length);
+  Lines := CountLines (Buffer^[CurPtr], Length);
+  Inc (CurPtr, Length);
+  Inc (CurPos.Y, Lines);
+  DrawLine := CurPos.Y;
+  DrawPtr := LineStart (CurPtr);
+  CurPos.X := CharPos (DrawPtr, CurPtr);
+  if not SelectText then
+    SelStart := CurPtr;
+  SelEnd := CurPtr;
+  if Length>Sellen then
+   begin
+     Inc (BufLen, Length - SelLen);
+     Dec (GapLen, Length - SelLen);
+   end
+  else
+   begin
+     Dec (BufLen, Sellen - Length);
+     Inc (GapLen, Sellen - Length);
+   end;
+  if AllowUndo then
+    begin
+      Inc (DelCount, DelLen);
+      Inc (InsCount, Length);
+    end;
+  Inc (Limit.Y, Lines - SelLines);
+  Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y));
+  if not IsClipboard then
+    Modified := True;
+  SetBufSize (BufLen + DelCount);
+  if (SelLines = 0) and (Lines = 0) then
+    Update (ufLine)
+  else
+    Update (ufView);
+end; { TEditor.InsertBuffer }
+
+
+function TEditor.InsertFrom (Editor : PEditor) : Boolean;
+begin
+  InsertFrom := InsertBuffer (Editor^.Buffer,
+    Editor^.BufPtr (Editor^.SelStart),
+    Editor^.SelEnd - Editor^.SelStart, CanUndo, IsClipboard);
+end; { TEditor.InsertFrom }
+
+
+procedure TEditor.Insert_Line (Select_Mode : Byte);
+{ This procedure inserts a newline at the current cursor position }
+{ if a ^N is pressed.  Unlike cmNewLine, the cursor will return   }
+{ to its original position.  If the cursor was at the end of a    }
+{ line, and its spaces were removed, the cursor returns to the    }
+{ end of the line instead.                                        }
+begin
+  NewLine (Select_Mode);
+  SetCurPtr (LineEnd (LineMove (CurPtr, -1)), Select_Mode);
+end; { TEditor.Insert_Line }
+
+
+function TEditor.InsertText (Text       : Pointer;
+                             Length     : Sw_Word;
+                             SelectText : Boolean) : Boolean;
+begin
+  if assigned(Text) and not Search_Replace then
+    Update_Place_Markers (Length, 0, Self.SelStart, Self.SelEnd);
+  InsertText := InsertBuffer (PEditBuffer (Text),
+                0, Length, CanUndo, SelectText);
+end; { TEditor.InsertText }
+
+
+function TEditor.IsClipboard : Boolean;
+begin
+  IsClipboard := Clipboard = @Self;
+end; { TEditor.IsClipboard }
+
+
+procedure TEditor.Jump_Place_Marker (Element : Byte; Select_Mode : Byte);
+{ This procedure jumps to a place marker if ^Q# is pressed.  }
+{ We don't go anywhere if Place_Marker[Element] is not zero. }
+begin
+  if (not IsClipboard) and (Place_Marker[Element] <> 0) then
+    SetCurPtr (Place_Marker[Element], Select_Mode);
+end; { TEditor.Jump_Place_Marker }
+
+
+procedure TEditor.Jump_To_Line (Select_Mode : Byte);
+{ This function brings up a dialog box that allows }
+{ the user to select a line number to jump to.     }
+VAR
+  Code       : Integer;         { Used for Val conversion.      }
+  Temp_Value : Longint;         { Holds converted dialog value. }
+begin
+  if EditorDialog (edJumpToLine, @Line_Number) <> cmCancel then
+    begin
+      { Convert the Line_Number string to an interger. }
+      { Put it into Temp_Value.  If the number is not  }
+      { in the range 1..9999 abort.  If the number is  }
+      { our current Y position, abort.  Otherwise,     }
+      { go to top of document, and jump to the line.   }
+      { There are faster methods.  This one's easy.    }
+      { Note that CurPos.Y is always 1 less than what  }
+      { the TIndicator line says.                      }
+      val (Line_Number, Temp_Value, Code);
+      if (Temp_Value < 1) or (Temp_Value > 9999999) then
+        Exit;
+      if Temp_Value = CurPos.Y + 1 then
+        Exit;
+      SetCurPtr (0, Select_Mode);
+      SetCurPtr (LineMove (CurPtr, Temp_Value - 1), Select_Mode);
+    end;
+end; {TEditor.Jump_To_Line}
+
+
+function TEditor.LineEnd (P : Sw_Word) : Sw_Word;
+var
+  start,
+  i  : Sw_word;
+  pc : pchar;
+begin
+  if P<CurPtr then
+   begin
+     i:=CurPtr-P;
+     pc:=pchar(Buffer)+P;
+     while (i>0) do
+      begin
+        if pc^ in [#10,#13] then
+         begin
+           LineEnd:=pc-pchar(Buffer);
+           exit;
+         end;
+        inc(pc);
+        dec(i);
+      end;
+     start:=CurPtr;
+   end
+  else
+   start:=P;
+  i:=BufLen-Start;
+  pc:=pchar(Buffer)+GapLen+start;
+  while (i>0) do
+   begin
+     if pc^ in [#10,#13] then
+      begin
+        LineEnd:=pc-(pchar(Buffer)+Gaplen);
+        exit;
+      end;
+     inc(pc);
+     dec(i);
+   end;
+  LineEnd:=pc-(pchar(Buffer)+Gaplen);
+end; { TEditor.LineEnd }
+
+
+function TEditor.LineMove (P : Sw_Word; Count : Sw_Integer) : Sw_Word;
+VAR
+  Pos : Sw_Integer;
+  I   : Sw_Word;
+begin
+  I := P;
+  P := LineStart (P);
+  Pos := CharPos (P, I);
+  while Count <> 0 do
+   begin
+     I := P;
+     if Count < 0 then
+       begin
+         P := PrevLine (P);
+         Inc (Count);
+       end
+     else
+       begin
+         P := NextLine (P);
+         Dec (Count);
+       end;
+   end;
+  if P <> I then
+    P := CharPtr (P, Pos);
+  LineMove := P;
+end; { TEditor.LineMove }
+
+
+function TEditor.LineStart (P : Sw_Word) : Sw_Word;
+var
+  i  : Sw_word;
+  start,pc : pchar;
+  oc : char;
+begin
+  if P>CurPtr then
+   begin
+     start:=pchar(Buffer)+GapLen;
+     pc:=start;
+     i:=P-CurPtr;
+     dec(pc);
+     while (i>0) do
+      begin
+        if pc^ in [#10,#13] then
+         break;
+        dec(pc);
+        dec(i);
+      end;
+   end
+  else
+   i:=0;
+  if i=0 then
+   begin
+     start:=pchar(Buffer);
+     i:=P;
+     pc:=start+p;
+     dec(pc);
+     while (i>0) do
+      begin
+        if pc^ in [#10,#13] then
+         break;
+        dec(pc);
+        dec(i);
+      end;
+     if i=0 then
+      begin
+        LineStart:=0;
+        exit;
+      end;
+   end;
+  oc:=pc^;
+  LineStart:=pc-start+1;
+end; { TEditor.LineStart }
+
+
+function TEditor.LineNr (P : Sw_Word) : Sw_Word;
+var
+  pc,endp : pchar;
+  lines : sw_word;
+begin
+  endp:=pchar(Buffer)+BufPtr(P);
+  pc:=pchar(Buffer);
+  lines:=0;
+  while (pc<endp) do
+   begin
+     if pc^ in [#10,#13] then
+      begin
+        inc(lines);
+        if ord((pc+1)^)+ord(pc^)=23 then
+         begin
+           inc(pc);
+           if (pc>=endp) then
+            break;
+         end;
+      end;
+     inc(pc);
+   end;
+  LineNr:=Lines;
+end;
+
+
+procedure TEditor.Lock;
+begin
+  Inc (LockCount);
+end; { TEditor.Lock }
+
+
+function TEditor.NewLine (Select_Mode : Byte) : Boolean;
+VAR
+  I : Sw_Word;          { Used to track spaces for AutoIndent.                 }
+  P : Sw_Word;          { Position of Cursor when we arrive and after Newline. }
+begin
+  P := LineStart (CurPtr);
+  I := P;
+  { The first thing we do is remove any End Of Line spaces.  }
+  { Then we check to see how many spaces are on beginning    }
+  { of a line.   We need this check to add them after CR/LF  }
+  { if AutoIndenting.  Last of all we insert spaces required }
+  { for the AutoIndenting, if it was on.                     }
+  Remove_EOL_Spaces (Select_Mode);
+  while (I < CurPtr) and ((Buffer^[I] in [#9,' '])) do
+    Inc (I);
+  if InsertText (@LineBreak[1], length(LineBreak), False) = FALSE then
+    exit;
+  if AutoIndent then
+    InsertText (@Buffer^[P], I - P, False);
+  { Remember where the CurPtr is at this moment.     }
+  { Remember the length of the buffer at the moment. }
+  { Go to the previous line and remove EOL spaces.   }
+  { Once removed, re-set the cursor to where we were }
+  { minus any spaces that might have been removed.   }
+  I := BufLen;
+  P := CurPtr;
+  SetCurPtr (LineMove (CurPtr, - 1), Select_Mode);
+  Remove_EOL_Spaces (Select_Mode);
+  if I - BufLen <> 0 then
+    SetCurPtr (P - (I - BufLen), Select_Mode)
+  else
+    SetCurPtr (P, Select_Mode);
+  NewLine:=true;
+end; { TEditor.NewLine }
+
+
+function TEditor.NextChar (P : Sw_Word) : Sw_Word;
+var
+  pc : pchar;
+begin
+  if P<>BufLen then
+   begin
+     inc(P);
+     if P<>BufLen then
+      begin
+        pc:=pchar(Buffer);
+        if P>=CurPtr then
+         inc(pc,GapLen);
+        inc(pc,P-1);
+        if ord(pc^)+ord((pc+1)^)=23 then
+         inc(p);
+      end;
+   end;
+  NextChar:=P;
+end; { TEditor.NextChar }
+
+
+function TEditor.NextLine (P : Sw_Word) : Sw_Word;
+begin
+  NextLine := NextChar (LineEnd (P));
+end; { TEditor.NextLine }
+
+
+function TEditor.NextWord (P : Sw_Word) : Sw_Word;
+begin
+  { skip word }
+  while (P < BufLen) and (BufChar (P) in WordChars) do
+    P := NextChar (P);
+  { skip spaces }
+  while (P < BufLen) and not (BufChar (P) in WordChars) do
+    P := NextChar (P);
+  NextWord := P;
+end; { TEditor.NextWord }
+
+
+function TEditor.PrevChar (P : Sw_Word) : Sw_Word;
+var
+  pc : pchar;
+begin
+  if p<>0 then
+   begin
+     dec(p);
+     if p<>0 then
+      begin
+        pc:=pchar(Buffer);
+        if P>=CurPtr then
+         inc(pc,GapLen);
+        inc(pc,P-1);
+        if ord(pc^)+ord((pc+1)^)=23 then
+         dec(p);
+      end;
+   end;
+  PrevChar:=P;
+end; { TEditor.PrevChar }
+
+
+function TEditor.PrevLine (P : Sw_Word) : Sw_Word;
+begin
+  PrevLine := LineStart (PrevChar (P));
+end; { TEditor.PrevLine }
+
+
+function TEditor.PrevWord (P : Sw_Word) : Sw_Word;
+begin
+  { skip spaces }
+  while (P > 0) and not (BufChar (PrevChar (P)) in WordChars) do
+    P := PrevChar (P);
+  { skip word }
+  while (P > 0) and (BufChar (PrevChar (P)) in WordChars) do
+    P := PrevChar (P);
+  PrevWord := P;
+end; { TEditor.PrevWord }
+
+
+procedure TEditor.Reformat_Document (Select_Mode : Byte; Center_Cursor : Boolean);
+{ This procedure will do a reformat of the entire document, or just    }
+{ from the current line to the end of the document, if ^QU is pressed. }
+{ It simply brings up the correct dialog box, and then calls the       }
+{ TEditor.Reformat_Paragraph procedure to do the actual reformatting.  }
+CONST
+  efCurrentLine   = $0000;  { Radio button #1 selection for dialog box.  }
+  efWholeDocument = $0001;  { Radio button #2 selection for dialog box.  }
+VAR
+  Reformat_Options : Word;  { Holds the dialog options for reformatting. }
+begin
+  { Check if Word_Wrap is toggled on.  If NOT on, check if programmer }
+  { allows reformatting of document and if not show user dialog that  }
+  { says reformatting is not permissable.                             }
+  if not Word_Wrap then
+    begin
+      if not Allow_Reformat then
+        begin
+          EditorDialog (edReformatNotAllowed, nil);
+          Exit;
+        end;
+      Word_Wrap := True;
+      Update (ufStats);
+    end;
+  { Default radio button option to 1st one.  Bring up dialog box. }
+  Reformat_Options := efCurrentLine;
+  if EditorDialog (edReformatDocument, @Reformat_Options) <> cmCancel then
+    begin
+      { If the option to reformat the whole document was selected   }
+      { we need to go back to start of document.  Otherwise we stay }
+      { on the current line.  Call Reformat_Paragraph until we get  }
+      { to the end of the document to do the reformatting.          }
+      if Reformat_Options and efWholeDocument <> 0 then
+        SetCurPtr (0, Select_Mode);
+      Unlock;
+      repeat
+        Lock;
+        if NOT Reformat_Paragraph (Select_Mode, Center_Cursor) then
+          Exit;
+        TrackCursor (False);
+        Unlock;
+      until CurPtr = BufLen;
+    end;
+end; { TEditor.Reformat_Document }
+
+
+function TEditor.Reformat_Paragraph (Select_Mode   : Byte;
+                                     Center_Cursor : Boolean) : Boolean;
+{ This procedure will do a reformat of the current paragraph if ^B pressed. }
+{ The feature works regardless if wordrap is on or off.  It also supports   }
+{ the AutoIndent feature.  Reformat is not possible if the CurPos exceeds   }
+{ the Right_Margin.  Right_Margin is where the EOL is considered to be.     }
+CONST
+  Space : array [1..2] of Char = #32#32;
+VAR
+  C : Sw_Word;  { Position of CurPtr when we come into procedure. }
+  E : Sw_Word;  { End of a line.                                  }
+  S : Sw_Word;  { Start of a line.                                }
+begin
+  Reformat_Paragraph := False;
+  { Check if Word_Wrap is toggled on.  If NOT on, check if programmer }
+  { allows reformatting of paragraph and if not show user dialog that }
+  { says reformatting is not permissable.                             }
+  if not Word_Wrap then
+    begin
+      if not Allow_Reformat then
+        begin
+          EditorDialog (edReformatNotAllowed, nil);
+          Exit;
+        end;
+      Word_Wrap := True;
+      Update (ufStats);
+    end;
+  C := CurPtr;
+  E := LineEnd (CurPtr);
+  S := LineStart (CurPtr);
+  { Reformat possible only if current line is NOT blank! }
+  if E <> S then
+    begin
+      { Reformat is NOT possible if the first word }
+      { on the line is beyond the Right_Margin.    }
+      S := LineStart (CurPtr);
+      if NextWord (S) - S >= Right_Margin - 1 then
+        begin
+          EditorDialog (edReformNotPossible, nil);
+          Exit;
+        end;
+      { First objective is to find the first blank line }
+      { after this paragraph so we know when to stop.   }
+      { That could be the end of the document.          }
+      Repeat
+        SetCurPtr (LineMove (CurPtr, 1), Select_Mode);
+        E := LineEnd (CurPtr);
+        S := LineStart (CurPtr);
+        BlankLine := E;
+      until ((CurPtr = BufLen) or (E = S));
+      SetCurPtr (C, Select_Mode);
+      repeat
+        { Set CurPtr to LineEnd and remove the EOL spaces. }
+        { Pull up the next line and remove its EOL space.  }
+        { First make sure the next line is not BlankLine!  }
+        { Insert spaces as required between the two lines. }
+        SetCurPtr (LineEnd (CurPtr), Select_Mode);
+        Remove_EOL_Spaces (Select_Mode);
+        if CurPtr <> Blankline - 2 then
+          DeleteRange (CurPtr, Nextword (CurPtr), True);
+        Remove_EOL_Spaces (Select_Mode);
+        case Buffer^[CurPtr-1] of
+          '!' : InsertText (@Space, 2, False);
+          '.' : InsertText (@Space, 2, False);
+          ':' : InsertText (@Space, 2, False);
+          '?' : InsertText (@Space, 2, False);
+        else
+          InsertText (@Space, 1, False);
+        end;
+        { Reset CurPtr to EOL.  While line length is > Right_Margin }
+        { go Do_Word_Wrap.  If wordrap failed, exit routine.        }
+        SetCurPtr (LineEnd (CurPtr), Select_Mode);
+        while LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin do
+          if not Do_Word_Wrap (Select_Mode, Center_Cursor) then
+              Exit;
+        { If LineEnd - LineStart > Right_Margin then set CurPtr    }
+        { to Right_Margin on current line.  Otherwise we set the   }
+        { CurPtr to LineEnd.  This gyration sets up the conditions }
+        { to test for time of loop exit.                           }
+        if LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin then
+          SetCurPtr (LineStart (CurPtr) + Right_Margin, Select_Mode)
+        else
+          SetCurPtr (LineEnd (CurPtr), Select_Mode);
+      until ((CurPtr >= BufLen) or (CurPtr >= BlankLine - 2));
+    end;
+  { If not at the end of the document reset CurPtr to start of next line. }
+  { This should be a blank line between paragraphs.                       }
+  if CurPtr < BufLen then
+    SetCurPtr (LineMove (CurPtr, 1), Select_Mode);
+  Reformat_Paragraph := True;
+end; { TEditor.Reformat_Paragraph }
+
+
+procedure TEditor.Remove_EOL_Spaces (Select_Mode : Byte);
+{ This procedure tests to see if there are consecutive spaces }
+{ at the end of a line (EOL).  If so, we delete all spaces    }
+{ after the last non-space character to the end of line.      }
+{ We then reset the CurPtr to where we ended up at.           }
+VAR
+  C : Sw_Word;           { Current pointer when we come into procedure. }
+  E : Sw_Word;           { End of line.                                 }
+  P : Sw_Word;           { Position of pointer at any given moment.     }
+  S : Sw_Word;           { Start of a line.                             }
+begin
+  C := CurPtr;
+  E := LineEnd (CurPtr);
+  P := E;
+  S := LineStart (CurPtr);
+  { Start at the end of a line and move towards the start. }
+  { Find first non-space character in that direction.      }
+  while (P > S) and (BufChar (PrevChar (P)) = #32) do
+    P := PrevChar (P);
+  { If we found any spaces then delete them. }
+  if P < E then
+    begin
+      SetSelect (P, E, True);
+      DeleteSelect;
+      Update_Place_Markers (0, E - P, P, E);
+    end;
+  { If C, our pointer when we came into this procedure, }
+  { is less than the CurPtr then reset CurPtr to C so   }
+  { cursor is where we started.  Otherwise, set it to   }
+  { the new CurPtr, for we have deleted characters.     }
+  if C < CurPtr then
+    SetCurPtr (C, Select_Mode)
+  else
+    SetCurPtr (CurPtr, Select_Mode);
+end; { TEditor.Remove_EOL_Spaces }
+
+
+procedure TEditor.Replace;
+VAR
+  ReplaceRec : TReplaceDialogRec;
+begin
+  with ReplaceRec do
+  begin
+    Find := FindStr;
+    Replace := ReplaceStr;
+    Options := Flags;
+    if EditorDialog (edReplace, @ReplaceRec) <> cmCancel then
+    begin
+      FindStr := Find;
+      ReplaceStr := Replace;
+      Flags := Options or efDoReplace;
+      DoSearchReplace;
+    end;
+  end;
+end; { TEditor.Replace }
+
+
+procedure TEditor.Scroll_Down;
+{ This procedure will scroll the screen up, and always keep      }
+{ the cursor on the CurPos.Y position, but not necessarily on    }
+{ the CurPos.X.  If CurPos.Y scrolls off the screen, the cursor  }
+{ will stay in the upper left corner of the screen.  This will   }
+{ simulate the same process in the IDE.  The CurPos.X coordinate }
+{ only messes up if we are on long lines and we then encounter   }
+{ a shorter or blank line beneath the current one as we scroll.  }
+{ In that case, it goes to the end of the new line.              }
+VAR
+  C : Sw_Word;           { Position of CurPtr when we enter procedure. }
+  P : Sw_Word;           { Position of CurPtr at any given time.       }
+  W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y).     }
+begin
+  { Remember current cursor position.  Remember current CurPos.Y position. }
+  { Now issue the equivalent of a [Ctrl]-[End] command so the cursor will  }
+  { go to the bottom of the current screen.  Reset the cursor to this new  }
+  { position and then send FALSE to TrackCursor so we fool it into         }
+  { incrementing Delta.Y by only +1.  If we didn't do this it would try    }
+  { to center the cursor on the screen by fiddling with Delta.Y.           }
+  C := CurPtr;
+  W.X := CurPos.Y;
+  P := LineMove (CurPtr, Delta.Y - CurPos.Y + Size.Y);
+  SetCurPtr (P, 0);
+  TrackCursor (False);
+  { Now remember where the new CurPos.Y is.  See if distance between new }
+  { CurPos.Y and old CurPos.Y are greater than the current screen size.  }
+  { If they are, we need to move cursor position itself down by one.     }
+  { Otherwise, send the cursor back to our original CurPtr.              }
+  W.Y := CurPos.Y;
+  if W.Y - W.X > Size.Y - 1 then
+    SetCurPtr (LineMove (C, 1), 0)
+  else
+    SetCurPtr (C, 0);
+end; { TEditor.Scroll_Down }
+
+
+procedure TEditor.Scroll_Up;
+{ This procedure will scroll the screen down, and always keep    }
+{ the cursor on the CurPos.Y position, but not necessarily on    }
+{ the CurPos.X.  If CurPos.Y scrolls off the screen, the cursor  }
+{ will stay in the bottom left corner of the screen.  This will  }
+{ simulate the same process in the IDE.  The CurPos.X coordinate }
+{ only messes up if we are on long lines and we then encounter   }
+{ a shorter or blank line beneath the current one as we scroll.  }
+{ In that case, it goes to the end of the new line.              }
+VAR
+  C : Sw_Word;           { Position of CurPtr when we enter procedure. }
+  P : Sw_Word;           { Position of CurPtr at any given time.       }
+  W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y).     }
+begin
+  { Remember current cursor position.  Remember current CurPos.Y position. }
+  { Now issue the equivalent of a [Ctrl]-[Home] command so the cursor will }
+  { go to the top of the current screen.  Reset the cursor to this new     }
+  { position and then send FALSE to TrackCursor so we fool it into         }
+  { decrementing Delta.Y by only -1.  If we didn't do this it would try    }
+  { to center the cursor on the screen by fiddling with Delta.Y.           }
+  C := CurPtr;
+  W.Y := CurPos.Y;
+  P := LineMove (CurPtr, -(CurPos.Y - Delta.Y + 1));
+  SetCurPtr (P, 0);
+  TrackCursor (False);
+  { Now remember where the new CurPos.Y is.  See if distance between new }
+  { CurPos.Y and old CurPos.Y are greater than the current screen size.  }
+  { If they are, we need to move the cursor position itself up by one.   }
+  { Otherwise, send the cursor back to our original CurPtr.              }
+  W.X := CurPos.Y;
+  if W.Y - W.X > Size.Y - 1 then
+    SetCurPtr (LineMove (C, -1), 0)
+  else
+    SetCurPtr (C, 0);
+end; { TEditor.Scroll_Up }
+
+
+procedure TEditor.ScrollTo (X, Y : Sw_Integer);
+begin
+  X := Max (0, Min (X, Limit.X - Size.X));
+  Y := Max (0, Min (Y, Limit.Y - Size.Y));
+  if (X <> Delta.X) or (Y <> Delta.Y) then
+  begin
+    Delta.X := X;
+    Delta.Y := Y;
+    Update (ufView);
+  end;
+end; { TEditor.ScrollTo }
+
+
+function TEditor.Search (const FindStr : String; Opts : Word) : Boolean;
+VAR
+  I,Pos : Sw_Word;
+begin
+  Search := False;
+  Pos := CurPtr;
+  repeat
+    if Opts and efCaseSensitive <> 0 then
+      I := Scan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr)
+    else
+      I := IScan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr);
+    if (I <> sfSearchFailed) then
+    begin
+      Inc (I, Pos);
+      if (Opts and efWholeWordsOnly = 0) or
+         not (((I <> 0) and (BufChar (I - 1) in WordChars)) or
+              ((I + Length (FindStr) <> BufLen) and
+               (BufChar (I + Length (FindStr)) in WordChars))) then
+        begin
+          Lock;
+          SetSelect (I, I + Length (FindStr), False);
+          TrackCursor (not CursorVisible);
+          Unlock;
+          Search := True;
+          Exit;
+        end
+      else
+        Pos := I + 1;
+    end;
+  until I = sfSearchFailed;
+end; { TEditor.Search }
+
+
+procedure TEditor.Select_Word;
+{ This procedure will select the a word to put into the clipboard.   }
+{ I've added it just to maintain compatibility with the IDE editor.  }
+{ Note that selection starts at the current cursor position and ends }
+{ when a space or the end of line is encountered.                    }
+VAR
+  E : Sw_Word;         { End of the current line.                           }
+  Select_Mode : Byte;  { Allows us to turn select mode on inside procedure. }
+begin
+  E := LineEnd (CurPtr);
+  { If the cursor is on a space or at the end of a line, abort. }
+  { Stupid action on users part for you can't select blanks!    }
+  if (BufChar (CurPtr) = #32) or (CurPtr = E) then
+    Exit;
+  { Turn on select mode and tell editor to start selecting text. }
+  { As long as we have a character > a space (this is done to    }
+  { exclude CR/LF pairs at end of a line) and we are NOT at the  }
+  { end of a line, set the CurPtr to the next character.         }
+  { Once we find a space or CR/LF, selection is done and we      }
+  { automatically put the selected word into the Clipboard.      }
+  Select_Mode := smExtend;
+  StartSelect;
+  while (BufChar (NextChar (CurPtr)) > #32) and (CurPtr < E) do
+    SetCurPtr (NextChar (CurPtr), Select_Mode);
+  SetCurPtr (NextChar (CurPtr), Select_Mode);
+  ClipCopy;
+end; {TEditor.Select_Word }
+
+
+procedure TEditor.SetBufLen (Length : Sw_Word);
+begin
+  BufLen := Length;
+  GapLen := BufSize - Length;
+  SelStart := 0;
+  SelEnd := 0;
+  CurPtr := 0;
+  CurPos.X:=0;
+  CurPos.Y:=0;
+  Delta.X:=0;
+  Delta.Y:=0;
+  GetLimits(Buffer^[GapLen], BufLen,Limit);
+  inc(Limit.X);
+  inc(Limit.Y);
+  DrawLine := 0;
+  DrawPtr := 0;
+  DelCount := 0;
+  InsCount := 0;
+  Modified := False;
+  Update (ufView);
+end; { TEditor.SetBufLen }
+
+
+function TEditor.SetBufSize (NewSize : Sw_Word) : Boolean;
+begin
+  SetBufSize := NewSize <= BufSize;
+end; { TEditor.SetBufSize }
+
+
+procedure TEditor.SetCmdState (Command : Word; Enable : Boolean);
+VAR
+  S : TCommandSet;
+begin
+  S := [Command];
+  if Enable and (State and sfActive <> 0) then
+    EnableCommands (S)
+  else
+    DisableCommands (S);
+end; { TEditor.SetCmdState }
+
+
+procedure TEditor.SetCurPtr (P : Sw_Word; SelectMode : Byte);
+VAR
+  Anchor : Sw_Word;
+begin
+  if SelectMode and smExtend = 0 then
+    Anchor := P
+  else
+    if CurPtr = SelStart then
+      Anchor := SelEnd
+    else
+      Anchor := SelStart;
+  if P < Anchor then
+    begin
+      if SelectMode and smDouble <> 0 then
+      begin
+        P := PrevLine (NextLine (P));
+        Anchor := NextLine (PrevLine (Anchor));
+      end;
+      SetSelect (P, Anchor, True);
+    end
+  else
+    begin
+      if SelectMode and smDouble <> 0 then
+      begin
+        P := NextLine (P);
+        Anchor := PrevLine (NextLine (Anchor));
+      end;
+      SetSelect (Anchor, P, False);
+    end;
+end; { TEditor.SetCurPtr }
+
+
+procedure TEditor.Set_Place_Marker (Element : Byte);
+{ This procedure sets a place marker for the CurPtr if ^K# is pressed. }
+begin
+  if not IsClipboard then
+    Place_Marker[Element] := CurPtr;
+end; { TEditor.Set_Place_Marker }
+
+
+procedure TEditor.Set_Right_Margin;
+{ This procedure will bring up a dialog box }
+{ that allows the user to set Right_Margin. }
+{ Values must be < MaxLineLength and > 9.   }
+VAR
+  Code        : Integer;          { Used for Val conversion.      }
+  Margin_Data : TRightMarginRec;  { Holds dialog results.         }
+  Temp_Value  : Sw_Integer;       { Holds converted dialog value. }
+begin
+  with Margin_Data do
+    begin
+      Str (Right_Margin, Margin_Position);
+      if EditorDialog (edRightMargin, @Margin_Position) <> cmCancel then
+        begin
+          val (Margin_Position, Temp_Value, Code);
+          if (Temp_Value <= MaxLineLength) and (Temp_Value > 9) then
+            Right_Margin := Temp_Value;
+        end;
+    end;
+end; { TEditor.Set_Right_Margin }
+
+
+procedure TEditor.SetSelect (NewStart, NewEnd : Sw_Word; CurStart : Boolean);
+VAR
+  UFlags : Byte;
+  P     : Sw_Word;
+  L     : Sw_Word;
+begin
+  if CurStart then
+    P := NewStart
+  else
+    P := NewEnd;
+  UFlags := ufUpdate;
+  if (NewStart <> SelStart) or (NewEnd <> SelEnd) then
+    if (NewStart <> NewEnd) or (SelStart <> SelEnd) then
+      UFlags := ufView;
+  if P <> CurPtr then
+  begin
+    if P > CurPtr then
+      begin
+        L := P - CurPtr;
+        Move (Buffer^[CurPtr + GapLen], Buffer^[CurPtr], L);
+        Inc (CurPos.Y, CountLines (Buffer^[CurPtr], L));
+        CurPtr := P;
+      end
+    else
+      begin
+        L := CurPtr - P;
+        CurPtr := P;
+        Dec (CurPos.Y, CountLines (Buffer^[CurPtr], L));
+        Move (Buffer^[CurPtr], Buffer^[CurPtr + GapLen], L);
+      end;
+    DrawLine := CurPos.Y;
+    DrawPtr := LineStart (P);
+    CurPos.X := CharPos (DrawPtr, P);
+    DelCount := 0;
+    InsCount := 0;
+    SetBufSize (BufLen);
+  end;
+  SelStart := NewStart;
+  SelEnd := NewEnd;
+  Update (UFlags);
+end; { TEditor.Select }
+
+
+procedure TEditor.SetState (AState : Word; Enable : Boolean);
+begin
+  Inherited SetState (AState, Enable);
+  case AState of
+    sfActive: begin
+                      if assigned(HScrollBar) then
+                        HScrollBar^.SetState (sfVisible, Enable);
+                      if assigned(VScrollBar) then
+                        VScrollBar^.SetState (sfVisible, Enable);
+                      if assigned(Indicator) then
+                        Indicator^.SetState (sfVisible, Enable);
+                      UpdateCommands;
+                    end;
+    sfExposed: if Enable then Unlock;
+  end;
+end; { TEditor.SetState }
+
+
+procedure TEditor.Set_Tabs;
+{ This procedure will bring up a dialog box }
+{ that allows the user to set tab stops.    }
+VAR
+  Index    : Sw_Integer;   { Index into string array. }
+  Tab_Data : TTabStopRec;  { Holds dialog results.    }
+begin
+  with Tab_Data do
+    begin
+      { Assign current Tab_Settings to Tab_String.    }
+      { Bring up the tab dialog so user can set tabs. }
+      Tab_String := Copy (Tab_Settings, 1, Tab_Stop_Length);
+      if EditorDialog (edSetTabStops, @Tab_String) <> cmCancel then
+        begin
+          { If Tab_String comes back as empty then set Tab_Settings to nil. }
+          { Otherwise, find the last character in Tab_String that is not    }
+          { a space and copy Tab_String into Tab_Settings up to that spot.  }
+          if Length (Tab_String) = 0 then
+            begin
+              FillChar (Tab_Settings, SizeOf (Tab_Settings), #0);
+              Tab_Settings[0] := #0;
+              Exit;
+            end
+          else
+            begin
+              Index := Length (Tab_String);
+              while Tab_String[Index] <= #32 do
+                Dec (Index);
+              Tab_Settings := Copy (Tab_String, 1, Index);
+            end;
+        end;
+  end;
+end; { TEditor.Set_Tabs }
+
+
+procedure TEditor.StartSelect;
+begin
+  HideSelect;
+  Selecting := True;
+end; { TEditor.StartSelect }
+
+
+procedure TEditor.Store (var S : Objects.TStream);
+begin
+  Inherited Store (S);
+  PutPeerViewPtr (S, HScrollBar);
+  PutPeerViewPtr (S, VScrollBar);
+  PutPeerViewPtr (S, Indicator);
+  S.Write (BufSize, SizeOf (Sw_Word));
+  S.Write (Canundo, SizeOf (Boolean));
+  S.Write (AutoIndent,   SizeOf (AutoIndent));
+  S.Write (Line_Number,  SizeOf (Line_Number));
+  S.Write (Place_Marker, SizeOf (Place_Marker));
+  S.Write (Right_Margin, SizeOf (Right_Margin));
+  S.Write (Tab_Settings, SizeOf (Tab_Settings));
+  S.Write (Word_Wrap,    SizeOf (Word_Wrap));
+end; { Editor.Store }
+
+
+procedure TEditor.Tab_Key (Select_Mode : Byte);
+{ This function determines if we are in overstrike or insert mode,   }
+{ and then moves the cursor if overstrike, or adds spaces if insert. }
+VAR
+  E        : Sw_Word;                { End of current line.                }
+  Index    : Sw_Integer;             { Loop counter.                       }
+  Position : Sw_Integer;             { CurPos.X position.                  }
+  S        : Sw_Word;                { Start of current line.              }
+  Spaces   : array [1..80] of Char;  { Array to hold spaces for insertion. }
+begin
+  E := LineEnd (CurPtr);
+  S := LineStart (CurPtr);
+  { Find the current horizontal cursor position. }
+  { Now loop through the Tab_Settings string and }
+  { find the next available tab stop.            }
+  Position := CurPos.X + 1;
+  repeat
+    Inc (Position);
+  until (Tab_Settings[Position] <> #32) or (Position >= Ord (Tab_Settings[0]));
+  E := CurPos.X;
+  Index := 1;
+  { Now we enter a loop to go to the next tab position.  }
+  { If we are in overwrite mode, we just move the cursor }
+  { through the text to the next tab stop.  If we are in }
+  { insert mode, we add spaces to the Spaces array for   }
+  { the number of times we loop.                         }
+  while Index < Position - E do
+    begin
+      if Overwrite then
+        begin
+          if (Position > LineEnd (CurPtr) - LineStart (CurPtr))
+              or (Position > Ord (Tab_Settings[0])) then
+            begin
+              SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode);
+              Exit;
+            end
+          else
+            if CurPtr < BufLen then
+              SetCurPtr (NextChar (CurPtr), Select_Mode);
+        end
+      else
+        begin
+          if (Position > Right_Margin) or (Position > Ord (Tab_Settings[0])) then
+            begin
+              SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode);
+              Exit;
+            end
+          else
+            Spaces[Index] := #32;
+        end;
+      Inc (Index);
+  end;
+  { If we are insert mode, we insert spaces to the next tab stop.        }
+  { When we're all done, the cursor will be sitting on the new tab stop. }
+  if not OverWrite then
+    InsertText (@Spaces, Index - 1, False);
+end; { TEditor.Tab_Key }
+
+
+procedure TEditor.ToggleInsMode;
+begin
+  Overwrite := not Overwrite;
+  SetState (sfCursorIns, not GetState (sfCursorIns));
+end; { TEditor.ToggleInsMode }
+
+
+procedure TEditor.TrackCursor (Center : Boolean);
+begin
+  if Center then
+    ScrollTo (CurPos.X - Size.X + 1, CurPos.Y - Size.Y div 2)
+  else
+    ScrollTo (Max (CurPos.X - Size.X + 1, Min (Delta.X, CurPos.X)),
+              Max (CurPos.Y - Size.Y + 1, Min (Delta.Y, CurPos.Y)));
+end; { TEditor.TrackCursor }
+
+
+procedure TEditor.Undo;
+VAR
+  Length : Sw_Word;
+begin
+  if (DelCount <> 0) or (InsCount <> 0) then
+  begin
+    Update_Place_Markers (DelCount, 0, CurPtr, CurPtr + DelCount);
+    SelStart := CurPtr - InsCount;
+    SelEnd := CurPtr;
+    Length := DelCount;
+    DelCount := 0;
+    InsCount := 0;
+    InsertBuffer (Buffer, CurPtr + GapLen - Length, Length, False, True);
+  end;
+end; { TEditor.Undo }
+
+
+procedure TEditor.Unlock;
+begin
+  if LockCount > 0 then
+  begin
+    Dec (LockCount);
+    if LockCount = 0 then
+      DoUpdate;
+  end;
+end; { TEditor.Unlock }
+
+
+procedure TEditor.Update (AFlags : Byte);
+begin
+  UpdateFlags := UpdateFlags or AFlags;
+  if LockCount = 0 then
+    DoUpdate;
+end; { TEditor.Update }
+
+
+procedure TEditor.UpdateCommands;
+begin
+  SetCmdState (cmUndo, (DelCount <> 0) or (InsCount <> 0));
+  if not IsClipboard then
+    begin
+      SetCmdState (cmCut, HasSelection);
+      SetCmdState (cmCopy, HasSelection);
+      SetCmdState (cmPaste, assigned(Clipboard) and (Clipboard^.HasSelection));
+    end;
+  SetCmdState (cmClear, HasSelection);
+  SetCmdState (cmFind, True);
+  SetCmdState (cmReplace, True);
+  SetCmdState (cmSearchAgain, True);
+end; { TEditor.UpdateCommands }
+
+
+procedure TEditor.Update_Place_Markers (AddCount : Word; KillCount : Word;
+                                        StartPtr,EndPtr : Sw_Word);
+{ This procedure updates the position of the place markers }
+{ as the user inserts and deletes text in the document.    }
+VAR
+  Element : Byte;     { Place_Marker array element to traverse array with. }
+begin
+  for Element := 1 to 10 do
+    begin
+      if AddCount > 0 then
+        begin
+          if (Place_Marker[Element] >= Curptr)
+              and (Place_Marker[Element] <> 0) then
+            Place_Marker[Element] := Place_Marker[Element] + AddCount;
+        end
+      else
+        begin
+          if Place_Marker[Element] >= StartPtr then
+            begin
+              if (Place_Marker[Element] >= StartPtr) and
+                 (Place_Marker[Element] < EndPtr) then
+                Place_marker[Element] := 0
+              else
+                begin
+                  if integer (Place_Marker[Element]) - integer (KillCount) > 0 then
+                    Place_Marker[Element] := Place_Marker[Element] - KillCount
+                  else
+                    Place_Marker[Element] := 0;
+                end;
+            end;
+        end;
+    end;
+  if AddCount > 0 then
+    BlankLine := BlankLine + AddCount
+  else
+    begin
+      if integer (BlankLine) - Integer (KillCount) > 0 then
+        BlankLine := BlankLine - KillCount
+      else
+        BlankLine := 0;
+    end;
+end; { TEditor.Update_Place_Markers }
+
+
+function TEditor.Valid (Command : Word) : Boolean;
+begin
+  Valid := IsValid;
+end; { TEditor.Valid }
+
+
+{****************************************************************************
+                                   TMEMO
+****************************************************************************}
+
+constructor TMemo.Load (var S : Objects.TStream);
+VAR
+  Length : Sw_Word;
+begin
+  Inherited Load (S);
+  S.Read (Length, SizeOf (Sw_Word));
+  if IsValid then
+    begin
+      S.Read (Buffer^[BufSize - Length], Length);
+      SetBufLen (Length);
+    end
+  else
+    S.Seek (S.GetPos + Length);
+end; { TMemo.Load }
+
+
+function TMemo.DataSize : Sw_Word;
+begin
+  DataSize := BufSize + SizeOf (Sw_Word);
+end; { TMemo.DataSize }
+
+
+procedure TMemo.GetData (var Rec);
+VAR
+  Data : TMemoData absolute Rec;
+begin
+  Data.Length := BufLen;
+  Move (Buffer^, Data.Buffer, CurPtr);
+  Move (Buffer^[CurPtr + GapLen], Data.Buffer[CurPtr], BufLen - CurPtr);
+  FillChar (Data.Buffer[BufLen], BufSize - BufLen, 0);
+end; { TMemo.GetData }
+
+
+function TMemo.GetPalette : PPalette;
+CONST
+  P : String[Length (CMemo)] = CMemo;
+begin
+  GetPalette := @P;
+end; { TMemo.GetPalette }
+
+
+procedure TMemo.HandleEvent (var Event : Drivers.TEvent);
+begin
+  if (Event.What <> Drivers.evKeyDown) or (Event.KeyCode <> Drivers.kbTab) then
+    Inherited HandleEvent (Event);
+end; { TMemo.HandleEvent }
+
+
+procedure TMemo.SetData (var Rec);
+VAR
+  Data : TMemoData absolute Rec;
+begin
+  Move (Data.Buffer, Buffer^[BufSize - Data.Length], Data.Length);
+  SetBufLen (Data.Length);
+end; { TMemo.SetData }
+
+
+procedure TMemo.Store (var S : Objects.TStream);
+begin
+  Inherited Store (S);
+  S.Write (BufLen, SizeOf (Sw_Word));
+  S.Write (Buffer^, CurPtr);
+  S.Write (Buffer^[CurPtr + GapLen], BufLen - CurPtr);
+end; { TMemo.Store }
+
+
+{****************************************************************************
+                               TFILEEDITOR
+****************************************************************************}
+
+
+constructor TFileEditor.Init (var Bounds : TRect;
+                              AHScrollBar, AVScrollBar : PScrollBar;
+                              AIndicator : PIndicator;
+                              AFileName  : FNameStr);
+begin
+  Inherited Init (Bounds, AHScrollBar, AVScrollBar, AIndicator, 0);
+  if AFileName <> '' then
+    begin
+      FileName := FExpand (AFileName);
+      if IsValid then
+        IsValid := LoadFile;
+    end;
+end; { TFileEditor.Init }
+
+
+constructor TFileEditor.Load (var S : Objects.TStream);
+VAR
+  SStart,SEnd,Curs : Sw_Word;
+begin
+  Inherited Load (S);
+  BufSize := 0;
+  S.Read (FileName[0], SizeOf (Char));
+  S.Read (Filename[1], Length (FileName));
+  if IsValid then
+    IsValid := LoadFile;
+  S.Read (SStart, SizeOf (Sw_Word));
+  S.Read (SEnd, SizeOf (Sw_Word));
+  S.Read (Curs, SizeOf (Sw_Word));
+  if IsValid and (SEnd <= BufLen) then
+    begin
+      SetSelect (SStart, SEnd, Curs = SStart);
+      TrackCursor (True);
+    end;
+end; { TFileEditor.Load }
+
+
+procedure TFileEditor.DoneBuffer;
+begin
+  if assigned(Buffer) then
+    DisposeBuffer (Buffer);
+end; { TFileEditor.DoneBuffer }
+
+
+procedure TFileEditor.HandleEvent (var Event : Drivers.TEvent);
+begin
+  Inherited HandleEvent (Event);
+  case Event.What of
+    Drivers.evCommand:
+      case Event.Command of
+        cmSave   : Save;
+        cmSaveAs : SaveAs;
+        cmSaveDone : if Save then
+                       Message (Owner, Drivers.evCommand, cmClose, nil);
+      else
+        Exit;
+      end;
+  else
+    Exit;
+  end;
+  ClearEvent (Event);
+end; { TFileEditor.HandleEvent }
+
+
+procedure TFileEditor.InitBuffer;
+begin
+  NewBuffer(Pointer(Buffer), MinBufLength);
+end; { TFileEditor.InitBuffer }
+
+
+function TFileEditor.LoadFile: Boolean;
+VAR
+  Length : Sw_Word;
+  FSize : Longint;
+  FRead : Sw_Integer;
+  F : File;
+begin
+  LoadFile := False;
+  Length := 0;
+  Assign(F, FileName);
+  Reset(F, 1);
+  if IOResult <> 0 then
+    EditorDialog(edReadError, @FileName)
+  else
+    begin
+      FSize := FileSize(F);
+      if (FSize > MaxBufLength) or not SetBufSize(FSize) then
+        EditorDialog(edOutOfMemory, nil)
+      else
+        begin
+          BlockRead(F, Buffer^[BufSize-FSize], FSize, FRead);
+          if (IOResult <> 0) or (FRead<>FSize) then
+            EditorDialog(edReadError, @FileName)
+          else
+            begin
+              LoadFile := True;
+              Length := FRead;
+            end;
+        end;
+      Close(F);
+    end;
+  SetBufLen(Length);
+end; { TFileEditor.LoadFile }
+
+
+function TFileEditor.Save : Boolean;
+begin
+  if FileName = '' then
+    Save := SaveAs
+  else
+    Save := SaveFile;
+end; { TFileEditor.Save }
+
+
+function TFileEditor.SaveAs : Boolean;
+begin
+  SaveAs := False;
+  if EditorDialog (edSaveAs, @FileName) <> cmCancel then
+  begin
+    FileName := FExpand (FileName);
+    Message (Owner, Drivers.evBroadcast, cmUpdateTitle, nil);
+    SaveAs := SaveFile;
+    if IsClipboard then
+      FileName := '';
+  end;
+end; { TFileEditor.SaveAs }
+
+
+function TFileEditor.SaveFile : Boolean;
+VAR
+  F          : File;
+  BackupName : Objects.FNameStr;
+  D          : DOS.DirStr;
+  N          : DOS.NameStr;
+  E          : DOS.ExtStr;
+begin
+  SaveFile := False;
+  if Flags and efBackupFiles <> 0 then
+  begin
+    FSplit (FileName, D, N, E);
+    BackupName := D + N + '.bak';
+    Assign (F, BackupName);
+    Erase (F);
+    Assign (F, FileName);
+    Rename (F, BackupName);
+    InOutRes := 0;
+  end;
+  Assign (F, FileName);
+  Rewrite (F, 1);
+  if IOResult <> 0 then
+    EditorDialog (edCreateError, @FileName)
+  else
+    begin
+      BlockWrite (F, Buffer^, CurPtr);
+      BlockWrite (F, Buffer^[CurPtr + GapLen], BufLen - CurPtr);
+      if IOResult <> 0 then
+        EditorDialog (edWriteError, @FileName)
+      else
+        begin
+          Modified := False;
+          Update (ufUpdate);
+          SaveFile := True;
+        end;
+        Close (F);
+   end;
+end; { TFileEditor.SaveFile }
+
+
+function TFileEditor.SetBufSize (NewSize : Sw_Word) : Boolean;
+VAR
+  N : Sw_Word;
+begin
+  SetBufSize := False;
+  if NewSize = 0 then
+    NewSize := MinBufLength
+  else
+    if NewSize > (MaxBufLength-MinBufLength) then
+      NewSize := MaxBufLength
+    else
+      NewSize := (NewSize + (MinBufLength-1)) and (MaxBufLength and (not (MinBufLength-1)));
+  if NewSize <> BufSize then
+   begin
+     if NewSize > BufSize then
+      if not SetBufferSize(pointer(Buffer), NewSize) then
+       Exit;
+     N := BufLen - CurPtr + DelCount;
+     Move(Buffer^[BufSize - N], Buffer^[NewSize - N], N);
+     if NewSize < BufSize then
+       SetBufferSize(pointer(Buffer), NewSize);
+     BufSize := NewSize;
+     GapLen := BufSize - BufLen;
+   end;
+  SetBufSize := True;
+end; { TFileEditor.SetBufSize }
+
+
+procedure TFileEditor.Store (var S : Objects.TStream);
+begin
+  Inherited Store (S);
+  S.Write (FileName, Length (FileName) + 1);
+  S.Write (SelStart, SizeOf (Sw_Word) * 3);
+end; { TFileEditor.Store }
+
+
+procedure TFileEditor.UpdateCommands;
+begin
+  Inherited UpdateCommands;
+  SetCmdState (cmSave, True);
+  SetCmdState (cmSaveAs, True);
+  SetCmdState (cmSaveDone, True);
+end; { TFileEditor.UpdateCommands }
+
+
+function TFileEditor.Valid (Command : Word) : Boolean;
+VAR
+  D : Integer;
+begin
+  if Command = cmValid then
+    Valid := IsValid
+  else
+    begin
+      Valid := True;
+      if Modified then
+        begin
+          if FileName = '' then
+            D := edSaveUntitled
+          else
+            D := edSaveModify;
+          case EditorDialog (D, @FileName) of
+            cmYes    : Valid := Save;
+            cmNo     : Modified := False;
+            cmCancel : Valid := False;
+          end;
+        end;
+    end;
+end; { TFileEditor.Valid }
+
+
+{****************************************************************************
+                             TEDITWINDOW
+****************************************************************************}
+
+constructor TEditWindow.Init (var Bounds   : TRect;
+                                  FileName : Objects.FNameStr;
+                                  ANumber  : Integer);
+var
+  HScrollBar : PScrollBar;
+  VScrollBar : PScrollBar;
+  Indicator  : PIndicator;
+  R          : TRect;
+begin
+  Inherited Init (Bounds, '', ANumber);
+  Options := Options or ofTileable;
+
+  R.Assign (18, Size.Y - 1, Size.X - 2, Size.Y);
+  HScrollBar := New (PScrollBar, Init (R));
+  HScrollBar^.Hide;
+  Insert (HScrollBar);
+
+  R.Assign (Size.X - 1, 1, Size.X, Size.Y - 1);
+  VScrollBar := New (PScrollBar, Init (R));
+  VScrollBar^.Hide;
+  Insert (VScrollBar);
+
+  R.Assign (2, Size.Y - 1, 16, Size.Y);
+  Indicator := New (PIndicator, Init (R));
+  Indicator^.Hide;
+  Insert (Indicator);
+
+  GetExtent (R);
+  R.Grow (-1, -1);
+  Editor := New (PFileEditor, Init (R, HScrollBar, VScrollBar, Indicator, FileName));
+  Insert (Editor);
+end; { TEditWindow.Init }
+
+
+constructor TEditWindow.Load (var S : Objects.TStream);
+begin
+  Inherited Load (S);
+  GetSubViewPtr (S, Editor);
+end; { TEditWindow.Load }
+
+
+procedure TEditWindow.Close;
+begin
+  if Editor^.IsClipboard then
+    Hide
+  else
+    Inherited Close;
+end; { TEditWindow.Close }
+
+
+function TEditWindow.GetTitle (MaxSize : Sw_Integer) : TTitleStr;
+begin
+  if Editor^.IsClipboard then
+    GetTitle := strings^.get(sClipboard)
+  else
+    if Editor^.FileName = '' then
+      GetTitle := strings^.get(sUntitled)
+    else
+      GetTitle := Editor^.FileName;
+end; { TEditWindow.GetTile }
+
+
+procedure TEditWindow.HandleEvent (var Event : Drivers.TEvent);
+begin
+  Inherited HandleEvent (Event);
+  if (Event.What = Drivers.evBroadcast) then
+    { and (Event.Command = cmUpdateTitle) then }
+    { Changed if statement above so I could test for cmBlugeonStats.       }
+    { Stats would not show up when loading a file until a key was pressed. }
+    case Event.Command of
+      cmUpdateTitle :
+        begin
+          Frame^.DrawView;
+          ClearEvent (Event);
+        end;
+      cmBludgeonStats :
+        begin
+          Editor^.Update (ufStats);
+          ClearEvent (Event);
+        end;
+    end;
+end; { TEditWindow.HandleEvent }
+
+
+procedure TEditWindow.SizeLimits(var Min, Max: TPoint);
+begin
+  inherited SizeLimits(Min, Max);
+  Min.X := 23;
+end;
+
+
+procedure TEditWindow.Store (var S : Objects.TStream);
+begin
+  Inherited Store (S);
+  PutSubViewPtr (S, Editor);
+end; { TEditWindow.Store }
+
+
+procedure RegisterEditors;
+begin
+  RegisterType (REditor);
+  RegisterType (RMemo);
+  RegisterType (RFileEditor);
+  RegisterType (RIndicator);
+  RegisterType (REditWindow);
+end; { RegisterEditors }
+
+
+end. { Unit NewEdit }

+ 189 - 0
fvision/str.inc

@@ -0,0 +1,189 @@
+{ Strings }
+sButtonDefault = 1; { Button default }
+sButtonDisabled = 2; { Button disabled }
+sButtonNormal = 3; { Button normal }
+sButtonSelected = 4; { Button selected }
+sButtonShadow = 5; { Button shadow }
+sButtonShortcut = 6; { Button shortcut }
+sChangeDirectory = 7; { Change Directory }
+sClipboard = 8; { Clipboard }
+sClusterNormal = 9; { Cluster normal }
+sClusterSelected = 10; { Cluster selected }
+sClusterShortcut = 11; { Cluster shortcut }
+sColor = 12; { Color }
+sColors = 13; { Colors }
+sConfirm = 14; { Confirm }
+sDeleteFile = 15; { Delete file?#13#10#13#3%s }
+sDirectory = 16; { Directory }
+sDisabled = 17; { Disabled }
+sDrives = 18; { Drives }
+sError = 19; { Error }
+sFileAlreadyOpen = 20; { #3%s#13#10#13#3is already open in window %d. }
+sFileCreateError = 21; { Error creating file %s }
+sFileReadError = 22; { Error reading file %s }
+sFileUntitled = 23; { Save untitled file? }
+sFileWriteError = 24; { Error writing to file %s }
+sFind = 25; { Find }
+sFrameActive = 26; { Frame active }
+sFrameBackground = 27; { Frame/background }
+sFrameIcons = 28; { Frame icons }
+sFramePassive = 29; { Frame passive }
+sHighlight = 30; { Highlight }
+sHistoryBarIcons = 31; { History bar icons }
+sHistoryBarPage = 32; { History bar page }
+sHistoryButton = 33; { History button }
+sHistorySides = 34; { History sides }
+sInformation = 35; { Information }
+sInformationPane = 36; { Information pane }
+sInputArrow = 37; { Input arrow }
+sInputNormal = 38; { Input normal }
+sInputSelected = 39; { Input selected }
+sInvalidCharacter = 40; { Invalid character in input }
+sInvalidDirectory = 41; { Invalid directory. }
+sInvalidDriveOrDir = 42; { Invalid drive or directory. }
+sInvalidFileName = 43; { Invalid file name. }
+sInvalidPicture = 44; { Input does not conform to picture: %s }
+sInvalidValue = 45; { Value not in the range %d to %d }
+sInverse = 46; { Inverse }
+sJumpTo = 47; { Jump To }
+sLabelNormal = 48; { Label normal }
+sLabelSelected = 49; { Label selected }
+sLabelShortcut = 50; { Label shortcut }
+sListDivider = 51; { List divider }
+sListFocused = 52; { List focused }
+sListNormal = 53; { List normal }
+sListSelected = 54; { List selected }
+sModified = 55; { #3%s#13#10#13#3has been modified.  Save? }
+sNoName = 56; { NONAME }
+sNormal = 57; { Normal }
+sNormalText = 58; { Normal text }
+sNotInList = 59; { Input not in valid-list }
+sOpen = 60; { Open }
+sOutOfMemory = 61; { Not enough memory for this operation. }
+sOutOfUnNamedWindows = 62; { Out of unnamed window numbers.  Save or discard some unnamed files and try again. }
+sPasteNotPossible = 63; { Wordwrap on:  Paste not possible in current margins when at end of line. }
+sReformatDocument = 64; { Reformat Document }
+sReformatNotPossible = 65; { Paragraph reformat not possible while trying to wrap current line with current margins. }
+sReformattingTheDocument = 66; { Reformatting the document: }
+sReplace = 67; { Replace }
+sReplaceFile = 68; { Replace file?#13#10#13#3%s }
+sReplaceNotPossible = 69; { Wordwrap on:  Replace not possible in current margins when at end of line. }
+sReplaceThisOccurence = 70; { Replace this occurence? }
+sRightMargin = 71; { Right Margin }
+sSaveAs = 72; { Save As }
+sScrollbarIcons = 73; { Scroll bar icons }
+sScrollbarPage = 74; { Scroll bar page }
+sSearchStringNotFound = 75; { Search string not found. }
+sSelectFormatStart = 76; { Select Format Start }
+sSelectWhereToBegin = 77; { Please select where to begin. }
+sSelected = 78; { Selected }
+sSelectedDisabled = 79; { Selected disabled }
+sSetting = 80; { Setting: }
+sShortcut = 81; { Shortcut }
+sShortcutSelected = 82; { ShortcutSelected }
+sStaticText = 83; { Static text }
+sTabSettings = 84; { Tab Settings }
+sText = 85; { Text }
+sTooManyFiles = 86; { Too many files. }
+sTypeExitOnReturn = 87; { Type EXIT to return... }
+sUnderline = 88; { Underline }
+sUnknownDialog = 89; { Unknown dialog requested! }
+sUntitled = 90; { Untitled }
+sWarning = 91; { Warning }
+sWindowList = 92; { Window List }
+sWordWrapNotPossible = 93; { Wordwrap on:  Wordwrap not possible in current margins with continuous line. }
+sWordWrapOff = 94; { You must turn on wordwrap before you can reformat. }
+smApr = 95; { Apr }
+smAug = 96; { Aug }
+smDec = 97; { Dec }
+smFeb = 98; { Feb }
+smJan = 99; { Jan }
+smJul = 100; { Jul }
+smJun = 101; { Jun }
+smMar = 102; { Mar }
+smMay = 103; { May }
+smNov = 104; { Nov }
+smOct = 105; { Oct }
+smSep = 106; { Sep }
+{ Labels }
+slAbout = 107;  { ~A~bout }
+slAltF1 = 108;  { Alt+F1 }
+slAltF3Close = 109;  { ~Alt+F3~ Close }
+slAltXExit = 110; { ~Alt-X~ Exit }
+slBackground = 111; { ~B~ackground }
+slCancel = 112; { Cancel }
+slCascade = 113; { C~a~scade }
+slCaseSensitive = 114; { ~C~ase sensitive }
+slChDir = 115; { ~C~hdir }
+slChangeDir = 116; { ~C~hange dir... }
+slClear = 117; { C~l~ear }
+slClose = 118; { ~C~lose }
+slCloseAll = 119; { Cl~o~se all }
+slColor = 120; { ~C~olor }
+slContents = 121;  { ~C~ontents }
+slCopy = 122; { ~C~opy }
+slCtrlF1 = 123;  { Ctrl+F1 }
+slCurrentLine = 124; { ~C~urrent line }
+slCut = 125; { Cu~t~ }
+slDOSShell = 126; { ~D~OS shell }
+slDelete = 127; { ~D~elete }
+slDirectoryName = 128; { Directory ~n~ame }
+slDirectoryTree = 129; { Directory ~t~ree }
+slEdit = 130; { ~E~dit }
+slEntireDocument = 131; { ~E~ntire document }
+slExit = 132; { E~x~it }
+slF10Menu = 133; { ~F10~ Menu }
+slF1Help = 134; { ~F1~ Help }
+slF3Open = 135; { ~F3~ Open }
+slFile = 136; { ~F~ile }
+slFiles = 137; { ~F~iles }
+slForeground = 138; { ~F~oreground }
+slGroup = 139; { ~G~roup }
+slHelp = 140; { ~H~elp }
+slIndex = 141;  { ~I~ndex }
+slItem = 142; { ~I~tem }
+slLineNumber = 143; { ~L~ine number }
+slName = 144; { ~N~ame }
+slNew = 145; { ~N~ew }
+slNewText = 146; { ~N~ew text }
+slNext = 147; { ~N~ext }
+slNo = 148; { ~N~o }
+slOk = 149; { O~k~ }
+slOpen = 150; { ~O~pen }
+slOpenDots = 151; { ~O~pen... }
+slPaste = 152; { ~P~aste }
+slPrevious = 153; { ~P~revious }
+slPreviousTopic = 154;  { ~P~revious topic }
+slPromptOnReplace = 155; { ~P~rompt on replace }
+slReformatDocument = 156; { ~R~eformat document }
+slReplace = 157; { ~R~eplace }
+slReplaceAll = 158; { ~R~eplace all }
+slRevert = 159; { ~R~evert }
+slSave = 160; { ~S~ave }
+slSaveAll = 161; { Save a~l~l }
+slSaveAs = 162; { S~a~ve as... }
+slSaveFileAs = 163; { ~S~ave file as }
+slShiftF1 = 164;  { Shift+F1 }
+slSizeMove = 165; { ~S~ize/Move }
+slTextToFind = 166; { ~T~ext to find }
+slTile = 167; { ~T~ile }
+slTopicSearch = 168;  { ~T~opic search }
+slUndo = 169; { ~U~ndo }
+slUsingHelp = 170;  { ~U~sing help }
+slWholeWordsOnly = 171; { ~W~hole words only }
+slWindow = 172;  { ~W~indow }
+slWindows = 173; { ~W~indows }
+slYes = 174; { ~Y~es }
+slZoom = 175; { ~Z~oom }
+slAltF3 = 176; { Alt+F3 }
+slAltX = 177; { Alt+X }
+slF2 = 178; { F2 }
+slF3 = 179; { F3 }
+slF5 = 180; { F5 }
+slF6 = 181; { F6 }
+slCtrlDel = 182; { Ctrl+Del }
+slCtrlF5 = 183; { Ctrl+F5 }
+slCtrlIns = 184; { Ctrl+Ins }
+slShiftDel = 185; { Shift+Del }
+slShiftF6 = 186; { Shift+F6 }
+slShiftIns = 187; { Shift+Ins }

+ 194 - 0
fvision/strtxt.inc

@@ -0,0 +1,194 @@
+procedure InitResStrings;
+begin
+  Strings^.Put(sButtonDefault,'Button default');
+  Strings^.Put(sButtonDisabled,'Button disabled');
+  Strings^.Put(sButtonNormal,'Button normal');
+  Strings^.Put(sButtonSelected,'Button selected');
+  Strings^.Put(sButtonShadow,'Button shadow');
+  Strings^.Put(sButtonShortcut,'Button shortcut');
+  Strings^.Put(sChangeDirectory,'Change Directory');
+  Strings^.Put(sClipboard,'Clipboard');
+  Strings^.Put(sClusterNormal,'Cluster normal');
+  Strings^.Put(sClusterSelected,'Cluster selected');
+  Strings^.Put(sClusterShortcut,'Cluster shortcut');
+  Strings^.Put(sColor,'Color');
+  Strings^.Put(sColors,'Colors');
+  Strings^.Put(sConfirm,'Confirm');
+  Strings^.Put(sDeleteFile,'Delete file?'#13#10#13#3'%s');
+  Strings^.Put(sDirectory,'Directory');
+  Strings^.Put(sDisabled,'Disabled');
+  Strings^.Put(sDrives,'Drives');
+  Strings^.Put(sError,'Error');
+  Strings^.Put(sFileAlreadyOpen,''#3'%s'#13#10#13#3'is already open in window %d.');
+  Strings^.Put(sFileCreateError,'Error creating file %s');
+  Strings^.Put(sFileReadError,'Error reading file %s');
+  Strings^.Put(sFileUntitled,'Save untitled file?');
+  Strings^.Put(sFileWriteError,'Error writing to file %s');
+  Strings^.Put(sFind,'Find');
+  Strings^.Put(sFrameActive,'Frame active');
+  Strings^.Put(sFrameBackground,'Frame/background');
+  Strings^.Put(sFrameIcons,'Frame icons');
+  Strings^.Put(sFramePassive,'Frame passive');
+  Strings^.Put(sHighlight,'Highlight');
+  Strings^.Put(sHistoryBarIcons,'History bar icons');
+  Strings^.Put(sHistoryBarPage,'History bar page');
+  Strings^.Put(sHistoryButton,'History button');
+  Strings^.Put(sHistorySides,'History sides');
+  Strings^.Put(sInformation,'Information');
+  Strings^.Put(sInformationPane,'Information pane');
+  Strings^.Put(sInputArrow,'Input arrow');
+  Strings^.Put(sInputNormal,'Input normal');
+  Strings^.Put(sInputSelected,'Input selected');
+  Strings^.Put(sInvalidCharacter,'Invalid character in input');
+  Strings^.Put(sInvalidDirectory,'Invalid directory.');
+  Strings^.Put(sInvalidDriveOrDir,'Invalid drive or directory.');
+  Strings^.Put(sInvalidFileName,'Invalid file name.');
+  Strings^.Put(sInvalidPicture,'Input does not conform to picture: %s');
+  Strings^.Put(sInvalidValue,'Value not in the range %d to %d');
+  Strings^.Put(sInverse,'Inverse');
+  Strings^.Put(sJumpTo,'Jump To');
+  Strings^.Put(sLabelNormal,'Label normal');
+  Strings^.Put(sLabelSelected,'Label selected');
+  Strings^.Put(sLabelShortcut,'Label shortcut');
+  Strings^.Put(sListDivider,'List divider');
+  Strings^.Put(sListFocused,'List focused');
+  Strings^.Put(sListNormal,'List normal');
+  Strings^.Put(sListSelected,'List selected');
+  Strings^.Put(sModified,''#3'%s'#13#10#13#3'has been modified.  Save?');
+  Strings^.Put(sNoName,'NONAME');
+  Strings^.Put(sNormal,'Normal');
+  Strings^.Put(sNormalText,'Normal text');
+  Strings^.Put(sNotInList,'Input not in valid-list');
+  Strings^.Put(sOpen,'Open');
+  Strings^.Put(sOutOfMemory,'Not enough memory for this operation.');
+  Strings^.Put(sOutOfUnNamedWindows,'Out of unnamed window numbers.  Save or discard some unnamed files and try again.');
+  Strings^.Put(sPasteNotPossible,'Wordwrap on:  Paste not possible in current margins when at end of line.');
+  Strings^.Put(sReformatDocument,'Reformat Document');
+  Strings^.Put(sReformatNotPossible,'Paragraph reformat not possible while trying to wrap current line with current margins.');
+  Strings^.Put(sReformattingTheDocument,'Reformatting the document:');
+  Strings^.Put(sReplace,'Replace');
+  Strings^.Put(sReplaceFile,'Replace file?'#13#10#13#3'%s');
+  Strings^.Put(sReplaceNotPossible,'Wordwrap on:  Replace not possible in current margins when at end of line.');
+  Strings^.Put(sReplaceThisOccurence,'Replace this occurence?');
+  Strings^.Put(sRightMargin,'Right Margin');
+  Strings^.Put(sSaveAs,'Save As');
+  Strings^.Put(sScrollbarIcons,'Scroll bar icons');
+  Strings^.Put(sScrollbarPage,'Scroll bar page');
+  Strings^.Put(sSearchStringNotFound,'Search string not found.');
+  Strings^.Put(sSelectFormatStart,'Select Format Start');
+  Strings^.Put(sSelectWhereToBegin,'Please select where to begin.');
+  Strings^.Put(sSelected,'Selected');
+  Strings^.Put(sSelectedDisabled,'Selected disabled');
+  Strings^.Put(sSetting,'Setting:');
+  Strings^.Put(sShortcut,'Shortcut');
+  Strings^.Put(sShortcutSelected,'ShortcutSelected');
+  Strings^.Put(sStaticText,'Static text');
+  Strings^.Put(sTabSettings,'Tab Settings');
+  Strings^.Put(sText,'Text');
+  Strings^.Put(sTooManyFiles,'Too many files.');
+  Strings^.Put(sTypeExitOnReturn,'Type EXIT to return...');
+  Strings^.Put(sUnderline,'Underline');
+  Strings^.Put(sUnknownDialog,'Unknown dialog requested!');
+  Strings^.Put(sUntitled,'Untitled');
+  Strings^.Put(sWarning,'Warning');
+  Strings^.Put(sWindowList,'Window List');
+  Strings^.Put(sWordWrapNotPossible,'Wordwrap on:  Wordwrap not possible in current margins with continuous line.');
+  Strings^.Put(sWordWrapOff,'You must turn on wordwrap before you can reformat.');
+  Strings^.Put(smApr,'Apr');
+  Strings^.Put(smAug,'Aug');
+  Strings^.Put(smDec,'Dec');
+  Strings^.Put(smFeb,'Feb');
+  Strings^.Put(smJan,'Jan');
+  Strings^.Put(smJul,'Jul');
+  Strings^.Put(smJun,'Jun');
+  Strings^.Put(smMar,'Mar');
+  Strings^.Put(smMay,'May');
+  Strings^.Put(smNov,'Nov');
+  Strings^.Put(smOct,'Oct');
+  Strings^.Put(smSep,'Sep');
+end;
+
+procedure InitResLabels;
+begin
+  Labels^.Put(slAbout,'~A~bout');
+  Labels^.Put(slAltF1,'Alt+F1');
+  Labels^.Put(slAltF3Close,'~Alt+F3~ Close');
+  Labels^.Put(slAltXExit,'~Alt-X~ Exit');
+  Labels^.Put(slBackground,'~B~ackground');
+  Labels^.Put(slCancel,'Cancel');
+  Labels^.Put(slCascade,'C~a~scade');
+  Labels^.Put(slCaseSensitive,'~C~ase sensitive');
+  Labels^.Put(slChDir,'~C~hdir');
+  Labels^.Put(slChangeDir,'~C~hange dir...');
+  Labels^.Put(slClear,'C~l~ear');
+  Labels^.Put(slClose,'~C~lose');
+  Labels^.Put(slCloseAll,'Cl~o~se all');
+  Labels^.Put(slColor,'~C~olor');
+  Labels^.Put(slContents,'~C~ontents');
+  Labels^.Put(slCopy,'~C~opy');
+  Labels^.Put(slCtrlF1,'Ctrl+F1');
+  Labels^.Put(slCurrentLine,'~C~urrent line');
+  Labels^.Put(slCut,'Cu~t~');
+  Labels^.Put(slDOSShell,'~D~OS shell');
+  Labels^.Put(slDelete,'~D~elete');
+  Labels^.Put(slDirectoryName,'Directory ~n~ame');
+  Labels^.Put(slDirectoryTree,'Directory ~t~ree');
+  Labels^.Put(slEdit,'~E~dit');
+  Labels^.Put(slEntireDocument,'~E~ntire document');
+  Labels^.Put(slExit,'E~x~it');
+  Labels^.Put(slF10Menu,'~F10~ Menu');
+  Labels^.Put(slF1Help,'~F1~ Help');
+  Labels^.Put(slF3Open,'~F3~ Open');
+  Labels^.Put(slFile,'~F~ile');
+  Labels^.Put(slFiles,'~F~iles');
+  Labels^.Put(slForeground,'~F~oreground');
+  Labels^.Put(slGroup,'~G~roup');
+  Labels^.Put(slHelp,'~H~elp');
+  Labels^.Put(slIndex,'~I~ndex');
+  Labels^.Put(slItem,'~I~tem');
+  Labels^.Put(slLineNumber,'~L~ine number');
+  Labels^.Put(slName,'~N~ame');
+  Labels^.Put(slNew,'~N~ew');
+  Labels^.Put(slNewText,'~N~ew text');
+  Labels^.Put(slNext,'~N~ext');
+  Labels^.Put(slNo,'~N~o');
+  Labels^.Put(slOk,'O~k~');
+  Labels^.Put(slOpen,'~O~pen');
+  Labels^.Put(slOpenDots,'~O~pen...');
+  Labels^.Put(slPaste,'~P~aste');
+  Labels^.Put(slPrevious,'~P~revious');
+  Labels^.Put(slPreviousTopic,'~P~revious topic');
+  Labels^.Put(slPromptOnReplace,'~P~rompt on replace');
+  Labels^.Put(slReformatDocument,'~R~eformat document');
+  Labels^.Put(slReplace,'~R~eplace');
+  Labels^.Put(slReplaceAll,'~R~eplace all');
+  Labels^.Put(slRevert,'~R~evert');
+  Labels^.Put(slSave,'~S~ave');
+  Labels^.Put(slSaveAll,'Save a~l~l');
+  Labels^.Put(slSaveAs,'S~a~ve as...');
+  Labels^.Put(slSaveFileAs,'~S~ave file as');
+  Labels^.Put(slShiftF1,'Shift+F1');
+  Labels^.Put(slSizeMove,'~S~ize/Move');
+  Labels^.Put(slTextToFind,'~T~ext to find');
+  Labels^.Put(slTile,'~T~ile');
+  Labels^.Put(slTopicSearch,'~T~opic search');
+  Labels^.Put(slUndo,'~U~ndo');
+  Labels^.Put(slUsingHelp,'~U~sing help');
+  Labels^.Put(slWholeWordsOnly,'~W~hole words only');
+  Labels^.Put(slWindow,'~W~indow');
+  Labels^.Put(slWindows,'~W~indows');
+  Labels^.Put(slYes,'~Y~es');
+  Labels^.Put(slZoom,'~Z~oom');
+  Labels^.Put(slAltF3,'Alt+F3');
+  Labels^.Put(slAltX,'Alt+X');
+  Labels^.Put(slF2,'F2');
+  Labels^.Put(slF3,'F3');
+  Labels^.Put(slF5,'F5');
+  Labels^.Put(slF6,'F6');
+  Labels^.Put(slCtrlDel,'Ctrl+Del');
+  Labels^.Put(slCtrlF5,'Ctrl+F5');
+  Labels^.Put(slCtrlIns,'Ctrl+Ins');
+  Labels^.Put(slShiftDel,'Shift+Del');
+  Labels^.Put(slShiftF6,'Shift+F6');
+  Labels^.Put(slShiftIns,'Shift+Ins');
+end;