home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 16 / 16.iso / w / w048 / 2.ddi / MSSRC.ARC / MSEDIT.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1987-12-21  |  33.1 KB  |  1,169 lines

  1. {                            MSEDIT.PAS
  2.                                MS 4.0
  3.                 Copyright (c) 1985, 87 by Borland International, Inc.         }
  4.  
  5. {$I msdirect.inc}
  6.  
  7. unit MsEdit;
  8.   {-Basic text editing commands}
  9.  
  10. interface
  11.  
  12. uses
  13.   Crt,                       {Basic video operations - standard unit}
  14.   Dos,                       {DOS interface - standard unit}
  15.   Errors,                    {Runtime error handler}
  16.   MsVars,                    {Global types and declarations}
  17.   MsScrn1,                   {Fast screen writing routines}
  18.   MsString,                  {String primitives}
  19.   MsPtrOp,                   {Primitive pointer operations}
  20.   EscSeq,                    {Returns text string for extended scan codes}
  21.   MsCmds,                    {Maps keystrokes to commands}
  22.   Int24,                     {DOS critical error handler}
  23.   Message,                   {Message system}
  24.   MsUser,                    {User keyboard input, line editing and error reporting}
  25.   MsMemOp,                   {Text buffer allocation and deallocation}
  26.   MsBack,                    {Background processes}
  27.   MsScrn2;                   {Editor screen updating}
  28.  
  29. procedure EdUpLine;
  30.   {-Process up line command}
  31.  
  32. procedure EdDownLine;
  33.   {-Process down line command}
  34.  
  35. procedure EdLeftLine;
  36.   {-Move cursor to left edge of line}
  37.  
  38. procedure EdRightLine;
  39.   {-Move cursor to right edge of line}
  40.  
  41. procedure EdWindowBottomFile;
  42.   {-Move cursor to bottom of file}
  43.  
  44. procedure EdDeleteRightChar;
  45.   {-Process delete right character command}
  46.  
  47. procedure EdDeleteLeftChar;
  48.   {-Process delete left character command}
  49.  
  50. procedure EdNewLine;
  51.   {-Process <Enter> key}
  52.  
  53. procedure EdInsertLine;
  54.   {-Process insert line command}
  55.  
  56. procedure EdJumpMarker(M : BlockMarker);
  57.   {-Move cursor to marker at line,column}
  58.  
  59. procedure EdLeftChar;
  60.   {-Process left character command}
  61.  
  62. procedure EdRightChar;
  63.   {-Process right character command}
  64.  
  65. procedure EdScrollUp;
  66.   {-Process scroll up command}
  67.  
  68. procedure EdScrollDown;
  69.   {-Process scroll down command}
  70.  
  71. procedure EdUpPage;
  72.   {-Process up page command}
  73.  
  74. procedure EdDownPage;
  75.   {-Process down page command}
  76.  
  77. procedure EdGotoPage(Pno : Integer);
  78.   {-Go to specified page number, assumes pagination is on}
  79.  
  80. procedure EdLeftWord;
  81.   {-Move cursor to previous word}
  82.  
  83. procedure EdRightWord;
  84.   {-Advance cursor to next word}
  85.  
  86. procedure EdDeleteRightWord;
  87.   {-Process delete right word command}
  88.  
  89. procedure EdRightJustify(P : PlineDesc; Lmargin, Rmargin : Integer);
  90.   {-Insert spaces in line to make it fill rmargin}
  91.  
  92. procedure EdProcesstext(Ch : Char; ImmediateUpdate : Boolean);
  93.   {-Process text input}
  94.  
  95. procedure EdInsertCtrlChar;
  96.   {-Insert literal character as text into file}
  97.  
  98. procedure EdUndo;
  99.   {-Process UNDO command}
  100.  
  101. procedure EdRestoreCurrentLine;
  102.   {-Restore text and flags of current line}
  103.  
  104. procedure EdDeleteLine;
  105.   {-Process delete line command}
  106.  
  107. procedure EdDeleteLineRight;
  108.   {-Kill text to right of cursor}
  109.  
  110.   {==========================================================================}
  111.  
  112. implementation
  113.  
  114.   procedure EdUpLine;
  115.     {-Process up line command}
  116.  
  117.   begin                      {EdUpLine}
  118.     with Curwin^ do
  119.       if EdPtrNotNil(Curline^.Backlink) then begin
  120.         Dec(Clineno);
  121.         EdBackPtr(Curline);
  122.         if Lineno = 1 then begin
  123.           EdBackPtr(TopLine);
  124.           TempScroll := 1;
  125.         end else begin
  126.           TempScroll := 0;
  127.           Dec(Lineno);
  128.         end;
  129.         if AT then
  130.           {Adjust current column number to match appearance of previous line}
  131.           Colno := EdAdjustColno(Curline, Curline^.Fwdlink, Colno);
  132.       end else
  133.         TempScroll := 0;
  134.   end;                       {EdUpLine}
  135.  
  136.   procedure EdDownLine;
  137.     {-Process down line command}
  138.  
  139.   begin                      {EdDownLine}
  140.     with Curwin^ do
  141.       if EdPtrNotNil(Curline^.Fwdlink) then begin
  142.         Inc(Clineno);
  143.         EdFwdPtr(Curline);
  144.         if Lineno > (Lastlineno-Firsttextno) then begin
  145.           EdFwdPtr(TopLine);
  146.           TempScroll := -1;
  147.         end else begin
  148.           TempScroll := 0;
  149.           Inc(Lineno);
  150.         end;
  151.         if AT then
  152.           {Adjust current column number to match appearance of previous line}
  153.           Colno := EdAdjustColno(Curline, Curline^.Backlink, Colno);
  154.       end else
  155.         TempScroll := 0;
  156.   end;                       {EdDownLine}
  157.  
  158.   procedure EdRightLine;
  159.     {-Move cursor to right edge of line}
  160.  
  161.   begin                      {EdRightLine}
  162.     with Curwin^ do begin
  163.       Colno := Succ(EdTextLength(Curline));
  164.       if Colno > Maxlinelength then
  165.         Colno := Maxlinelength;
  166.     end;
  167.   end;                       {EdRightLine}
  168.  
  169.   procedure EdDeleteRightChar;
  170.     {-Process delete right character command}
  171.  
  172.   begin                      {EdDeleteRightChar}
  173.     with Curwin^ do begin
  174.  
  175.       if Colno > Curline^.Bufflen then
  176.         Exit;
  177.  
  178.       Modified := True;
  179.  
  180.       with Curline^ do begin
  181.         if Colno < Bufflen then
  182.           Move(Txt^[Succ(Colno)], Txt^[Colno], Bufflen-Colno);
  183.         Txt^[Bufflen] := Blank;
  184.       end;
  185.  
  186.       {Fix up markers}
  187.       EdFixBlockInsertedSpace(Curline, Colno, -1);
  188.       EdCheckNoMarker;
  189.       EdFixMarkInsertedSpace(Curline, Colno-1, -1);
  190.     end;
  191.   end;                       {EdDeleteRightChar}
  192.  
  193.   procedure EdDeleteLeftChar;
  194.     {-Process delete left character command}
  195.  
  196.   begin                      {EdDeleteLeftChar}
  197.     with Curwin^ do begin
  198.  
  199.       if Colno = 1 then begin
  200.  
  201.         {Beginning of line}
  202.         if EdPtrNotNil(Curline^.Backlink) then begin
  203.           Modified := True;
  204.           {Move to end of previous line and join}
  205.           EdUpLine;
  206.           EdRightLine;
  207.           EdJoinline;
  208.           EdResetPageLine(Curwin);
  209.           EdRealign;
  210.           {Force screen to be fully updated}
  211.           Intrflag := NoInterr;
  212.         end;
  213.  
  214.       end else begin
  215.  
  216.         {Middle or end of line}
  217.         Dec(Colno);
  218.         EdDeleteRightChar;
  219.  
  220.       end;
  221.     end;
  222.   end;                       {EdDeleteLeftChar}
  223.  
  224.   procedure EdNewLine;
  225.     {-Process <Enter> key}
  226.  
  227.   begin                      {EdNewLine}
  228.     with Curwin^ do begin
  229.       if Insertflag or EdPtrIsNil(Curline^.Fwdlink) then begin
  230.         EdNewLinePrimitive;
  231.         EdRealign;
  232.       end else begin
  233.         EdDownLine;
  234.         Colno := 1;
  235.       end;
  236.       Leftedge := 1;
  237.     end;
  238.   end;                       {EdNewLine}
  239.  
  240.   procedure EdInsertLine;
  241.     {-Process insert line command}
  242.   var
  243.     CurL : PlineDesc;
  244.     CurC : Integer;
  245.  
  246.   begin                      {EdInsertLine}
  247.  
  248.     {Save cursor position}
  249.     with Curwin^ do begin
  250.       CurL := Curline;
  251.       CurC := Colno;
  252.     end;
  253.  
  254.     {Use Newline to do the work}
  255.     EdNewLinePrimitive;
  256.     if Goterror then
  257.       Exit;
  258.  
  259.     {Restore cursor position}
  260.     with Curwin^ do begin
  261.       Curline := CurL;
  262.       Colno := CurC;
  263.     end;
  264.  
  265.     EdRealign;
  266.  
  267.   end;                       {EdInsertLine}
  268.  
  269.   procedure EdJumpMarker(M : BlockMarker);
  270.     {-Move cursor to marker at line,column}
  271.   var
  272.     W : Pwindesc;
  273.     Mline : PlineDesc;
  274.     Rezoom : Boolean;
  275.  
  276.   begin                      {Edjumpmarker}
  277.  
  278.     Mline := M.Line;
  279.     if EdPtrIsNil(Mline) then begin
  280.       EdErrormsg(29);
  281.       Exit;
  282.     end;
  283.  
  284.     {Determine which window holds the marked line}
  285.     W := EdFindWindow(Mline);
  286.     if EdPtrIsNil(W) then begin
  287.       {Mark is not in displayable text}
  288.       EdErrormsg(30);
  289.       Exit;
  290.     end;
  291.  
  292.     Rezoom := Zoomed and (W <> Curwin);
  293.     if Rezoom then
  294.       {toggle zoom off}
  295.       EdZoomWindow(False);
  296.     Curwin := W;
  297.     if Rezoom then
  298.       {toggle zoom back on}
  299.       EdZoomWindow(False);
  300.  
  301.     with Curwin^ do begin
  302.  
  303.       {See if marker is towards top of file, but on current screen}
  304.       while EdPtrNotNil(Curline^.Backlink) and (Curline <> TopLine) and (Curline <> Mline) do
  305.         EdUpLine;
  306.  
  307.       {See if marker is towards end of file}
  308.       while EdPtrNotNil(Curline^.Fwdlink) and (Curline <> Mline) do
  309.         EdDownLine;
  310.  
  311.       if Curline <> Mline then begin
  312.         {Marker must be above top of screen}
  313.         TopLine := Mline;
  314.         Curline := Mline;
  315.         Lineno := 1;
  316.       end;
  317.  
  318.       {Set column number}
  319.       Colno := M.Col;
  320.  
  321.     end;
  322.   end;                       {Edjumpmarker}
  323.  
  324.   procedure EdLeftChar;
  325.     {-Process left character command}
  326.  
  327.   begin                      {EdLeftChar}
  328.     with Curwin^ do
  329.       if Colno > 1 then begin
  330.         Dec(Colno);
  331.         if EditUsercommandInput = 0 then begin
  332.           EdHscrollOne(Curwin);
  333.           EdUpdateCursor;
  334.           EdUpdateStatusLine(Curwin);
  335.         end;
  336.       end;
  337.   end;                       {EdLeftChar}
  338.  
  339.   procedure EdRightChar;
  340.     {-Process right character command}
  341.  
  342.   begin                      {EdRightChar}
  343.     with Curwin^ do
  344.       if Colno < Maxlinelength then begin
  345.         Inc(Colno);
  346.         if EditUsercommandInput = 0 then begin
  347.           EdHscrollOne(Curwin);
  348.           EdUpdateCursor;
  349.           EdUpdateStatusLine(Curwin);
  350.         end;
  351.       end;
  352.   end;                       {EdRightChar}
  353.  
  354.   procedure EdScrollUp;
  355.     {-Process scroll up command}
  356.  
  357.   begin                      {EdScrollUp}
  358.     with Curwin^ do
  359.       if EdPtrNotNil(TopLine^.Backlink) then begin
  360.         EdBackPtr(TopLine);
  361.         if Lineno > (Lastlineno-Firsttextno) then begin
  362.           Dec(Clineno);
  363.           EdBackPtr(Curline);
  364.           if AT then
  365.             {Adjust current column number to match appearance of previous line}
  366.             Colno := EdAdjustColno(Curline, Curline^.Fwdlink, Colno);
  367.         end else
  368.           Inc(Lineno);
  369.         Inc(FullScroll);
  370.       end;
  371.   end;                       {EdScrollUp}
  372.  
  373.   procedure EdScrollDown;
  374.     {-Process scroll down command}
  375.  
  376.   begin                      {EdScrollDown}
  377.     with Curwin^ do
  378.       if EdPtrNotNil(TopLine^.Fwdlink) then begin
  379.         EdFwdPtr(TopLine);
  380.         if Lineno = 1 then begin
  381.           Inc(Clineno);
  382.           EdFwdPtr(Curline);
  383.           if AT then
  384.             {Adjust current column number to match appearance of previous line}
  385.             Colno := EdAdjustColno(Curline, Curline^.Backlink, Colno);
  386.         end else
  387.           Dec(Lineno);
  388.         Dec(FullScroll);
  389.       end;
  390.   end;                       {EdScrollDown}
  391.  
  392.   procedure EdUpPage;
  393.     {-Process up page command}
  394.   var
  395.     PageSize, I : Integer;
  396.     P : PlineDesc;
  397.  
  398.   begin                      {EdUpPage}
  399.     with Curwin^ do begin
  400.       PageSize := Succ(Lastlineno-Firsttextno);
  401.       I := 1;
  402.       P := Curline;
  403.       while (I < PageSize) and EdPtrNotNil(TopLine^.Backlink) do begin
  404.         {Back the screen up}
  405.         EdBackPtr(TopLine);
  406.         EdBackPtr(Curline);
  407.         Dec(Clineno);
  408.         Inc(I);
  409.       end;
  410.       while (I < PageSize) do begin
  411.         {Back the cursor up if needed}
  412.         EdUpLine;
  413.         Inc(I);
  414.       end;
  415.       if AT then
  416.         {Adjust current column number to match appearance of previous line}
  417.         Colno := EdAdjustColno(Curline, P, Colno);
  418.     end;
  419.   end;                       {EdUpPage}
  420.  
  421.   procedure EdDownPage;
  422.     {-Process down page command}
  423.   var
  424.     PageSize, I : Integer;
  425.     P : PlineDesc;
  426.  
  427.   begin                      {EdDownPage}
  428.     with Curwin^ do begin
  429.       PageSize := Succ(Lastlineno-Firsttextno);
  430.       I := 1;
  431.       P := Curline;
  432.       while (I < PageSize) and EdPtrNotNil(TopLine^.Fwdlink) do begin
  433.         EdFwdPtr(TopLine);
  434.         Inc(I);
  435.         if EdPtrIsNil(Curline^.Fwdlink) then
  436.           Dec(Lineno)
  437.         else begin
  438.           Inc(Clineno);
  439.           EdFwdPtr(Curline);
  440.         end;
  441.       end;
  442.       if AT then
  443.         {Adjust current column number to match appearance of previous line}
  444.         Colno := EdAdjustColno(Curline, P, Colno);
  445.     end;
  446.   end;                       {EdDownPage}
  447.  
  448.   procedure EdGotoPage(Pno : Integer);
  449.     {-Go to specified page number, assumes pagination is on}
  450.  
  451.   begin                      {EdGotoPage}
  452.     with Curwin^ do begin
  453.       if EdGetPageNum(Curline) >= Pno then
  454.         {Scan backwards to top of specified page}
  455.         while EdPtrNotNil(Curline^.Backlink) and (EdGetPageNum(Curline) >= Pno) do
  456.           EdUpLine;
  457.       {Scan forward to top of specified page}
  458.       while EdPtrNotNil(Curline^.Fwdlink) and (EdGetPageNum(Curline) < Pno) do
  459.         EdDownLine;
  460.       Colno := 1;
  461.     end;
  462.   end;                       {EdGotoPage}
  463.  
  464.   procedure EdLeftWord;
  465.     {-Move cursor to previous word}
  466.  
  467.     procedure EdBackOneLine;
  468.       {-Move cursor up to the end of the previous line}
  469.  
  470.     begin                    {EdBackOneLine}
  471.       if EdPtrNotNil(Curwin^.Curline^.Backlink) then begin
  472.         EdUpLine;
  473.         EdRightLine;
  474.       end;
  475.     end;                     {EdBackOneLine}
  476.  
  477.   begin                      {EdLeftWord}
  478.     with Curwin^ do
  479.  
  480.       if Colno <= 1 then
  481.  
  482.         {Beginning of line, move to end of previous line}
  483.         EdBackOneLine
  484.  
  485.       else
  486.         with Curline^ do begin
  487.  
  488.           {Work within the current line}
  489.           EdMoveCursorIntoLine;
  490.  
  491.           if (Txt^[Colno] in Alphas) then begin
  492.  
  493.             {Currently within a word}
  494.             Dec(Colno);
  495.             if not(Txt^[Colno] in Alphas) then
  496.               {Go to end of previous word}
  497.               while (Colno > 0) and not(Txt^[Colno] in Alphas) do
  498.                 Dec(Colno);
  499.  
  500.             {Go to beginning of this word}
  501.             while (Colno > 0) and (Txt^[Colno] in Alphas) do
  502.               Dec(Colno);
  503.  
  504.             {Forward to next Alpha}
  505.             Inc(Colno);
  506.  
  507.           end else begin
  508.  
  509.             {Currently between words}
  510.             {Go to end of previous word}
  511.             while (Colno > 0) and not(Txt^[Colno] in Alphas) do
  512.               Dec(Colno);
  513.             if Colno <> 0 then
  514.               {Go to begin of previous word}
  515.               while (Colno > 0) and (Txt^[Colno] in Alphas) do
  516.                 Dec(Colno);
  517.             Inc(Colno);
  518.  
  519.           end;
  520.  
  521.           {Up to previous line if within left margin}
  522.           if WW then
  523.             if (Colno <= 1) and (Wmargin > 1) and (Txt^[Colno] = Blank) then
  524.               EdBackOneLine;
  525.  
  526.         end;
  527.   end;                       {EdLeftWord}
  528.  
  529.   procedure EdRightWord;
  530.     {-Advance cursor to next word}
  531.  
  532.   begin                      {EdRightWord}
  533.     with Curwin^ do begin
  534.  
  535.       if EdPtrIsNil(Curline^.Fwdlink) and (Colno >= EdTextLength(Curline)) then
  536.         Exit;
  537.  
  538.       {Work within the current line buffer}
  539.       EdMoveCursorIntoLine;
  540.  
  541.       with Curline^ do
  542.         if (Txt^[Colno] in Alphas) then begin
  543.  
  544.           {Starting within a word}
  545.           while (Colno <= Bufflen) and (Txt^[Colno] in Alphas) do
  546.             {Advance to next non-alpha}
  547.             Inc(Colno);
  548.  
  549.           if (Colno <= Bufflen) then begin
  550.             {Skip over spaces after the word}
  551.             while (Colno <= Bufflen) and not(Txt^[Colno] in Alphas) do
  552.               Inc(Colno);
  553.             if Colno > Bufflen then
  554.               {Rest of line was non-alpha, stop after last word}
  555.               EdRightLine;
  556.           end;
  557.  
  558.         end else begin
  559.  
  560.           {Starting in white space, get to next non-blank}
  561.           while (Colno <= Bufflen) and not(Txt^[Colno] in Alphas) do
  562.             {Advance to next non-space on this line}
  563.             Inc(Colno);
  564.  
  565.           if (Colno <= Bufflen) then
  566.             {Found a non-blank}
  567.             Exit;
  568.  
  569.           EdDownLine;
  570.           Colno := 1;
  571.           if WW then
  572.             while (Colno < Wmargin) and (Curline^.Txt^[Colno] = Blank) do
  573.               {Advance to next non-space or to left margin}
  574.               Inc(Colno);
  575.  
  576.         end;
  577.     end;
  578.   end;                       {EdRightWord}
  579.  
  580.   procedure EdDeleteRightWord;
  581.     {-Delete word to right of cursor}
  582.   type
  583.     CharClass = (InBlank, InAlphas, InElse);
  584.   var
  585.     Startclass : CharClass;
  586.  
  587.     function EdClass : CharClass;
  588.     var
  589.       Ch : Char;
  590.  
  591.     begin                    {EdClass}
  592.       with Curwin^ do
  593.         Ch := Curline^.Txt^[Colno];
  594.       if Ch = Blank then
  595.         EdClass := InBlank
  596.       else if Ch in Alphas then
  597.         EdClass := InAlphas
  598.       else
  599.         EdClass := InElse;
  600.     end;                     {EdClass}
  601.  
  602.   begin                      {EdDeleteRightWord}
  603.  
  604.     with Curwin^ do begin
  605.       if Colno > EdTextLength(Curline) then begin
  606.  
  607.         {Join next line to end of this one}
  608.         Modified := True;
  609.         EdJoinline;
  610.         {Flag forces the newly joined line to be rebuffered for ^QL}
  611.         Blockop := True;
  612.  
  613.       end else begin
  614.  
  615.         if Curline^.Txt^[Colno] <> Blank then begin
  616.           {In a word - delete to next space}
  617.           Startclass := EdClass;
  618.           while (EdClass = Startclass) and (Colno <= Curline^.Bufflen) do
  619.             EdDeleteRightChar;
  620.         end;
  621.         {In white space - delete spaces}
  622.         while (Curline^.Txt^[Colno] = Blank) and (Colno <= EdTextLength(Curline)) do
  623.           EdDeleteRightChar;
  624.  
  625.       end;
  626.  
  627.       {Reset pagination}
  628.       EdResetPageLine(Curwin);
  629.     end;
  630.  
  631.     {Force screen to be fully updated}
  632.     Intrflag := NoInterr;
  633.  
  634.   end;                       {EdDeleteRightWord}
  635.  
  636.   procedure EdRightJustify(P : PlineDesc; Lmargin, Rmargin : Integer);
  637.     {-Insert spaces in line to make it fill rmargin}
  638.   var
  639.     EffLen, Len, I, J, Lptr, Tptr, Emargin,
  640.     Nspaces, Espaces, Ispaces, Delta, Next : Integer;
  641.     Template : array[1..Maxlinelength] of Integer;
  642.     Tline : TextLine;
  643.  
  644.   begin                      {EdRightjustify}
  645.  
  646.     Len := EdTextLength(P);
  647.     {Correct for effect of font toggle characters}
  648.     EffLen := EdComputeEffectiveColNo(True, P, Len);
  649.     Emargin := Rmargin+Len-EffLen;
  650.  
  651.     {Check length, leave line unchanged if empty or too long}
  652.     if (EffLen > 0) and (EffLen < Rmargin) then begin
  653.  
  654.       with P^ do begin
  655.         Lptr := 1;
  656.  
  657.         {Pass on leading spaces and characters left of left margin without change}
  658.         while (Txt^[Lptr] = Blank) or (PrintMap[Txt^[Lptr]] <> PrtNone) or (Lptr <= Lmargin) do begin
  659.           Tline[Lptr] := Txt^[Lptr];
  660.           Inc(Lptr);
  661.         end;
  662.         Tptr := Pred(Lptr);
  663.  
  664.         {Initialize the space template}
  665.         Nspaces := 0;
  666.         for I := Lptr to Len do
  667.           if Txt^[I] = Blank then begin
  668.             Inc(Nspaces);
  669.             Template[Nspaces] := 1;
  670.           end;
  671.  
  672.         if Nspaces > 0 then begin
  673.  
  674.           {Compute the actual spaces in each position of the template}
  675.           Espaces := Emargin-Len;
  676.  
  677.           while (Espaces > 0) do begin
  678.  
  679.             {Number of template locations to increment}
  680.             Delta := Nspaces div Espaces;
  681.             if (Nspaces mod Espaces) > (Espaces shr 1) then
  682.               Inc(Delta);
  683.             if Delta = 0 then
  684.               Delta := 1;
  685.  
  686.             {Number of spaces to increment each template location chosen}
  687.             if Espaces > Nspaces then
  688.               Ispaces := Espaces div Nspaces
  689.             else
  690.               Ispaces := 1;
  691.  
  692.             {First template position to increment}
  693.             Next := Succ(Delta) shr 1;
  694.  
  695.             {Increment each selected space location}
  696.             while (Next <= Nspaces) and (Espaces > 0) do begin
  697.               Template[Next] := Template[Next]+Ispaces;
  698.               Next := Next+Delta;
  699.               Espaces := Espaces-Ispaces;
  700.             end;
  701.  
  702.           end;               {While espaces>0}
  703.         end;                 {If nspaces>0}
  704.  
  705.         {Write the justified line to the buffer}
  706.         Nspaces := 0;
  707.         for I := Lptr to Len do
  708.           if Txt^[I] = Blank then begin
  709.             Inc(Nspaces);
  710.             {Fix up markers}
  711.             EdFixBlockInsertedSpace(P, Succ(Tptr), Pred(Template[Nspaces]));
  712.             EdFixMarkInsertedSpace(P, Succ(Tptr), Pred(Template[Nspaces]));
  713.             {Insert the spaces}
  714.             for J := 1 to Template[Nspaces] do begin
  715.               Inc(Tptr);
  716.               Tline[Tptr] := Blank;
  717.             end;
  718.           end else begin
  719.             Inc(Tptr);
  720.             Tline[Tptr] := Txt^[I];
  721.           end;
  722.  
  723.       end;                   {with p^}
  724.  
  725.       {Copy output back to input}
  726.       if not(EdSizeline(P, Tptr, False)) then
  727.         Exit;
  728.       Move(Tline[1], P^.Txt^[1], Tptr);
  729.       FillChar(P^.Txt^[Succ(Tptr)], P^.Bufflen-Tptr, Blank);
  730.  
  731.     end;                     {Len>0 and len<=rmargin}
  732.   end;                       {EdRightjustify}
  733.  
  734.   procedure EdProcesstext(Ch : Char; ImmediateUpdate : Boolean);
  735.     {-Process text input}
  736.   label
  737.     ExitPoint;
  738.   var
  739.     Len, SaveCol, WrapCol : Integer;
  740.  
  741.   begin                      {EdProcesstext}
  742.  
  743.     with Curwin^ do begin
  744.  
  745.       if Colno >= Maxlinelength then
  746.         {Cursor sitting at maximum length, ignore further characters}
  747.         Exit;
  748.  
  749.       if WW and not(MarginRelease) then
  750.         if (Colno < Wmargin) then begin
  751.           {Cursor left of left margin, insert space to get to LM}
  752.           if not(EdInsertSpace(Curline, Colno, Wmargin-Colno)) then
  753.             Exit;
  754.           Colno := Wmargin;
  755.         end;
  756.  
  757.       with Curline^ do begin
  758.  
  759.         if Insertflag then begin
  760.           {Insert mode, shift existing characters right}
  761.  
  762.           if Colno >= Bufflen then
  763.             Len := Colno
  764.           else
  765.             Len := Succ(EdTextLength(Curline));
  766.  
  767.           if (Len >= Bufflen) then
  768.             {Text buffer is full, size it up - keep at least one blank at end}
  769.             if not EdSizeline(Curline, Succ(Len), True) then
  770.               Exit;
  771.  
  772.           {Shift existing text over one character}
  773.           Move(Txt^[Colno], Txt^[Succ(Colno)], Bufflen-Colno);
  774.  
  775.           {Fix up markers}
  776.           EdFixBlockInsertedSpace(Curline, Colno, 1);
  777.           EdFixMarkInsertedSpace(Curline, Colno, 1);
  778.  
  779.         end else
  780.           {Overwrite mode}
  781.           if Succ(Colno) >= Bufflen then
  782.             if not EdSizeline(Curline, Succ(Colno), True) then
  783.               Exit;
  784.  
  785.         {Add new character}
  786.         Txt^[Colno] := Ch;
  787.  
  788.         {Test for word wrap}
  789.         if WW and not(MarginRelease) then
  790.           if (Ch <> Blank) and (PrintMap[Ch] = PrtNone) then
  791.             if (EdComputeEffectiveColNo(True, Curline, Colno) > Rmargin) then begin
  792.  
  793.               {Remove excess blanks, perhaps from prior justification}
  794.               if CW then begin
  795.                 EdCompress(Curline, Wmargin, Colno, Len);
  796.                 if Colno > Len then
  797.                   Colno := Len;
  798.               end;
  799.  
  800.               if Colno > Rmargin then begin
  801.  
  802.                 SaveCol := Colno;
  803.  
  804.                 {Back up to first blank within right margin}
  805.                 repeat
  806.                   Dec(Colno);
  807.                 until (Colno < 1) or
  808.                 ((EdComputeEffectiveColNo(True, Curline, Colno) <= Succ(Rmargin)) and
  809.                  (Txt^[Colno] = Blank));
  810.  
  811.                 if (Colno = 0) or (EdComputeEffectiveColNo(True, Curline, Colno) < Wmargin) then begin
  812.                   {No blank found within margin}
  813.                   {Forward to first blank, if any}
  814.                   repeat
  815.                     Inc(Colno);
  816.                   until (Colno = SaveCol) or (Txt^[Colno] = Blank);
  817.                   if (Colno = SaveCol) or (EdComputeEffectiveColNo(True, Curline, Colno) <= Wmargin) then
  818.                     goto ExitPoint;
  819.                 end;
  820.  
  821.                 {Move forward to next non-blank}
  822.                 while Txt^[Colno] = Blank do
  823.                   Inc(Colno);
  824.  
  825.                 WrapCol := Colno;
  826.  
  827.                 {Break the line}
  828.                 if Insertflag then
  829.                   EdNewLine
  830.                 else begin
  831.                   {Force insert mode}
  832.                   Insertflag := True;
  833.                   EdNewLine;
  834.                   Insertflag := False;
  835.                 end;
  836.                 {Might get memory overflow in EdNewLine}
  837.                 if Goterror then
  838.                   goto ExitPoint;
  839.  
  840.                 {Justify wrapped line}
  841.                 if JU then
  842.                   EdRightJustify(Curline^.Backlink, Wmargin, Rmargin);
  843.  
  844.                 {Move cursor after the text which was wrapped}
  845.                 Colno := Colno+SaveCol-WrapCol;
  846.  
  847.               end;
  848.             end;
  849.       end;                   {with Curline^}
  850.  
  851. ExitPoint:
  852.       Inc(Colno);
  853.       Modified := True;
  854.       EdResetPageLine(Curwin);
  855.  
  856.       {Get out fast if macro is in progress}
  857.       if ImmediateUpdate and (EditUsercommandInput = 0) then begin
  858.  
  859.         {Assure that print control characters are updated on screen}
  860.         if PrintMap[Ch] <> PrtNone then
  861.           if AT then
  862.             {Note that attribute changed within line}
  863.             EdChangeFlag(Curline, True, NewAttr);
  864.  
  865.         {Assure horizontal scroll is up to date for this window}
  866.         EdHscrollOne(Curwin);
  867.  
  868.         {Update the cursor}
  869.         EdUpdateCursor;
  870.  
  871.         {Update the current line on screen}
  872.         EdUpdateLine(Curline, Pred(Firsttextno+Lineno), Leftedge, Leftcol, AT);
  873.  
  874.         {Update the status line}
  875.         EdUpdateStatusLine(Curwin);
  876.  
  877.         {Assure rest of screen updated when there is time}
  878.         UpdateScreen := True;
  879.       end;
  880.     end;
  881.   end;                       {EdProcesstext}
  882.  
  883.   procedure EdInsertCtrlChar;
  884.     {-Insert literal character as text into file}
  885.  
  886.   begin                      {EdInsertCtrlChar}
  887.     {Let us see the ^P character}
  888.     EdWritePromptLine(CtrlCharStr);
  889.     {And assure ^U will get through}
  890.     AbortEnable := False;
  891.     EdProcesstext(EdGetAnyChar, True);
  892.   end;                       {EdInsertCtrlChar}
  893.  
  894.   procedure EdLeftLine;
  895.     {-Move cursor to left edge of line}
  896.   begin                      {EdLeftLine}
  897.     EdGotoColumn(1);
  898.   end;                       {EdLeftLine}
  899.  
  900.   procedure EdWindowBottomFile;
  901.     {-Move cursor to bottom of file}
  902.  
  903.   begin                      {EdWindowBottomFile}
  904.     with Curwin^ do
  905.       while EdPtrNotNil(Curline^.Fwdlink) do begin
  906.         Inc(Clineno);
  907.         EdFwdPtr(Curline);
  908.         if Lineno > (Lastlineno-Firsttextno) then
  909.           EdFwdPtr(TopLine)
  910.         else
  911.           Inc(Lineno);
  912.       end;
  913.     {Go to end of line}
  914.     EdRightLine;
  915.   end;                       {EdWindowBottomFile}
  916.  
  917.   procedure EdUndo;
  918.     {-Process UNDO command}
  919.   var
  920.     P : PlineDesc;
  921.  
  922.   begin                      {EdUndo}
  923.  
  924.     {If either Undolimit or Undocount = 0, we don't have anything to undo}
  925.     if UndoLimit*UndoCount = 0 then
  926.       Exit;
  927.  
  928.     {Put the line back into the editing environment}
  929.  
  930.     Dec(UndoCount);
  931.     P := UndoStack;
  932.     EdFwdPtr(UndoStack);
  933.     if EdPtrIsNil(UndoStack) then
  934.       EdSetPtrNil(UndoEnd);
  935.  
  936.     {Reset all flags}
  937.     P^.Flags := NewAttr;
  938.     P^.Font := 0;
  939.  
  940.     {Insert the line into the current text stream}
  941.  
  942.     with Curwin^ do begin
  943.  
  944.       Modified := True;
  945.       {Reset pagination}
  946.       EdResetPageLine(Curwin);
  947.  
  948.       if EdPtrIsNil(TopLine^.Backlink) and EdPtrIsNil(TopLine^.Fwdlink) and (EdTextLength(Curline) = 0) then begin
  949.  
  950.         {File is empty, don't insert, just copy}
  951.         {Size up topline if needed}
  952.         if EdSizeline(TopLine, Succ(P^.Bufflen), True) then
  953.           Move(P^.Txt^[1], TopLine^.Txt^[1], P^.Bufflen);
  954.         EdDesTextDesc(P);
  955.  
  956.       end else begin
  957.  
  958.         {Really insert the buffer}
  959.         P^.Backlink := Curline^.Backlink;
  960.         if EdPtrNotNil(P^.Backlink) then
  961.           P^.Backlink^.Fwdlink := P;
  962.         P^.Fwdlink := Curline;
  963.         Curline^.Backlink := P;
  964.         if Curline = TopLine then
  965.           {Keep Topline above Curline}
  966.           TopLine := P;
  967.         {Backup current line}
  968.         Curline := P;
  969.  
  970.       end;
  971.     end;
  972.  
  973.     EdRealign;
  974.   end;                       {EdUndo}
  975.  
  976.   procedure EdRestoreCurrentLine;
  977.     {-Restore text and flags of current line}
  978.   var
  979.     M : Integer;
  980.  
  981.   begin                      {EdRestoreCurrentLine}
  982.     with Curwin^ do
  983.  
  984.       {Assure something has been stored}
  985.       if CurlineBuf^.Bufflen <> 0 then begin
  986.  
  987.         {Reset blocks and markers as needed}
  988.         if Blockfrom.Line = Curline then
  989.           Blockfrom.Col := Curlinefrom.Col;
  990.         if Blockfrom.Line <> Curlinefrom.Line then begin
  991.           Blockfrom.Line := Curlinefrom.Line;
  992.           {Reset screen attributes}
  993.           EdOffblock;
  994.         end;
  995.         if Blockto.Line = Curline then
  996.           Blockto.Col := Curlineto.Col;
  997.         if Blockto.Line <> Curlineto.Line then begin
  998.           Blockto.Line := Curlineto.Line;
  999.           EdOffblock;
  1000.         end;
  1001.  
  1002.         if EdFlagSet(Curline, InMark) and not(EdFlagSet(CurlineBuf, InMark)) then begin
  1003.           {Text mark was added - reset it}
  1004.           for M := 0 to MaxMarker do
  1005.             if Marker[M].Line = Curline then
  1006.               EdSetPtrNil(Marker[M].Line);
  1007.           {Any mark stolen from another line is lost}
  1008.         end;
  1009.  
  1010.         Curline^.Flags := CurlineBuf^.Flags;
  1011.  
  1012.         Move(CurlineBuf^.Txt^[1], Curline^.Txt^[1], CurlineBuf^.Bufflen);
  1013.         if CurlineBuf^.Bufflen < Curline^.Bufflen then
  1014.           {Line has grown in the meantime, so right fill with blanks}
  1015.           FillChar(Curline^.Txt^[Succ(CurlineBuf^.Bufflen)],
  1016.                    Curline^.Bufflen-CurlineBuf^.Bufflen, Blank);
  1017.  
  1018.         {Reset the cursor}
  1019.         Colno := Curlinecol;
  1020.         Leftedge := 1;
  1021.         EdHscrollOne(Curwin);
  1022.  
  1023.         {Restoring the line may have modified the file}
  1024.         Modified := True;
  1025.  
  1026.         {Restoring the line may have changed pagination}
  1027.         EdResetPageLine(Curwin);
  1028.  
  1029.       end;
  1030.   end;                       {EdRestoreCurrentLine}
  1031.  
  1032.   procedure EdDeleteLine;
  1033.     {-Process delete line command}
  1034.   var
  1035.     P : PlineDesc;
  1036.  
  1037.     procedure EdDelline(P : PlineDesc);
  1038.       {-Delete line from text stream}
  1039.  
  1040.     begin                    {EdDelline}
  1041.  
  1042.       {Check block limits}
  1043.       if P = Blockfrom.Line then begin
  1044.  
  1045.         if (P = Blockto.Line) then begin
  1046.           {Remove block altogether}
  1047.           EdSetPtrNil(Blockfrom.Line);
  1048.           EdSetPtrNil(Blockto.Line);
  1049.         end else begin
  1050.           {Note p^.fwdlink cannot be nil in this condition}
  1051.           Blockfrom.Line := P^.Fwdlink;
  1052.           Blockfrom.Col := 1;
  1053.         end;
  1054.  
  1055.       end else if P = Blockto.Line then begin
  1056.  
  1057.         {Blockto is being deleted}
  1058.         if EdPtrIsNil(P^.Fwdlink) then begin
  1059.           {Note that p^.backlink cannot be nil in this condition}
  1060.           Blockto.Line := P^.Backlink;
  1061.           Blockto.Col := Succ(EdTextLength(P^.Backlink));
  1062.         end else begin
  1063.           Blockto.Line := P^.Fwdlink;
  1064.           Blockto.Col := 1;
  1065.         end;
  1066.  
  1067.       end;
  1068.  
  1069.       {Fix up topline, curline, lineno of any window now pointing to the line p}
  1070.       EdFixUpWindowSpan(P);
  1071.  
  1072.  
  1073.     end;                     {EdDelline}
  1074.  
  1075.   begin                      {EdDeleteLine}
  1076.     with Curwin^ do begin
  1077.       Modified := True;
  1078.       P := Curline;
  1079.  
  1080.       if EdPtrIsNil(P^.Fwdlink) then begin
  1081.  
  1082.         {This is the only line or last line in the file}
  1083.         Curline := EdMaktextdesc(1);
  1084.         if Goterror then
  1085.           Exit;
  1086.         Curline^.Backlink := P^.Backlink;
  1087.         EdSetPtrNil(Curline^.Fwdlink);
  1088.         if EdPtrNotNil(P^.Backlink) then
  1089.           P^.Backlink^.Fwdlink := Curline;
  1090.         if P = TopLine then
  1091.           TopLine := Curline;
  1092.  
  1093.       end else if EdPtrIsNil(P^.Backlink) then begin
  1094.  
  1095.         {It's the first line in the file}
  1096.         TopLine := Curline^.Fwdlink;
  1097.         Curline := TopLine;
  1098.         EdSetPtrNil(TopLine^.Backlink);
  1099.  
  1100.       end else begin
  1101.  
  1102.         {In the middle of the file}
  1103.         if P = TopLine then
  1104.           EdFwdPtr(TopLine);
  1105.         EdFwdPtr(Curline);
  1106.         Curline^.Backlink := P^.Backlink;
  1107.         P^.Backlink^.Fwdlink := Curline;
  1108.  
  1109.       end;
  1110.  
  1111.       {Fixup any structures affected by deleting the line}
  1112.       EdDelline(P);
  1113.  
  1114.       {Put the line on undo stack if possible}
  1115.       if EdPtrNotNil(P^.Fwdlink) or (EdTextLength(P) > 0) then
  1116.         EdPushUndo(P);
  1117.  
  1118.       Colno := 1;
  1119.       EdResetPageLine(Curwin);
  1120.  
  1121.     end;
  1122.  
  1123.     EdRealign;
  1124.     {Force screen to fully update after this command}
  1125.     Intrflag := NoInterr;
  1126.  
  1127.   end;                       {EdDeleteLine}
  1128.  
  1129.   procedure EdDeleteLineRight;
  1130.     {-Kill text to right of cursor}
  1131.   var
  1132.     M : Integer;
  1133.  
  1134.   begin                      {EdDeleteLineRight}
  1135.     with Curwin^ do begin
  1136.  
  1137.       if Colno > Curline^.Bufflen then
  1138.         Exit;
  1139.  
  1140.       {Just blank out the text}
  1141.       FillChar(Curline^.Txt^[Colno], Succ(Curline^.Bufflen-Colno), Blank);
  1142.  
  1143.       Modified := True;
  1144.  
  1145.       {Fix up markers}
  1146.       if (Blockfrom.Line = Curline) and (Blockfrom.Col > Colno) then begin
  1147.         EdClrFlag(Curline, InBlock);
  1148.         if (Blockto.Line = Curline) or EdPtrIsNil(Curline^.Fwdlink) then begin
  1149.           {whole block deleted}
  1150.           EdSetPtrNil(Blockfrom.Line);
  1151.           EdSetPtrNil(Blockto.Line);
  1152.         end else begin
  1153.           Blockfrom.Line := Curline^.Fwdlink;
  1154.           Blockfrom.Col := 1;
  1155.         end;
  1156.       end;
  1157.       if (Blockto.Line = Curline) and (Blockto.Col > Colno) then
  1158.         Blockto.Col := Colno;
  1159.       if EdFlagSet(Curline, InMark) then
  1160.         for M := 0 to MaxMarker do
  1161.           with Marker[M] do
  1162.             if (Line = Curline) and (Col > Colno) then
  1163.               Col := Colno;
  1164.  
  1165.     end;
  1166.   end;                       {EdDeleteLineRight}
  1167.  
  1168. end.
  1169.