Browse Source

Sync editor to recent TInputLine improvements:

- Ctrl+arrows should use punctuation as word separators also
- OSC52 copy to clipboard support
- Ctrl+letters should not type letters

Also, added Ctrl+A as "select all" hotkey
Ivan Sorokin 5 days ago
parent
commit
604769dd86
1 changed files with 99 additions and 55 deletions
  1. 99 55
      packages/fv/src/editors.inc

+ 99 - 55
packages/fv/src/editors.inc

@@ -246,6 +246,7 @@ type
     PendingWChar   : Sw_Char;  { hold first part of double wide char until next InsertChar }
 {$endif FV_UNICODE}
 
+    function   IsDelimiter(Ch: AnsiChar): Boolean;
     function   BuildLookups(LinePtr : Sw_Word; lookUpCharToPosX, lookUpPosXToChar : PLineLookup):Sw_Word;
     procedure  Center_Text (Select_Mode : Byte);
     function   CharPos (P, Target : Sw_Word) : Sw_Integer;
@@ -486,17 +487,17 @@ implementation
 uses
   TP.DOS,
 {$ifdef FV_UNICODE}
-  System.Console.Video, System.Unicode.Graphemebreakproperty, FreeVision.Uapp, FreeVision.Ustddlg, FreeVision.Umsgbox;
+  System.Console.Video, System.Unicode.Graphemebreakproperty, FreeVision.Uapp, FreeVision.Ustddlg, FreeVision.Umsgbox, FreeVision.Ufvclip;
 {$else FV_UNICODE}
-  FreeVision.App, FreeVision.Stddlg, FreeVision.Msgbox;
+  FreeVision.App, FreeVision.Stddlg, FreeVision.Msgbox, FreeVision.Fvclip;
 {$ENDIF}
 {$ELSE FPC_DOTTEDUNITS}
 uses
   Dos,
 {$ifdef FV_UNICODE}
-  Video, Graphemebreakproperty, uApp, uStdDlg, uMsgBox;
+  Video, Graphemebreakproperty, uApp, uStdDlg, uMsgBox, UFVClip;
 {$else FV_UNICODE}
-  App, StdDlg, MsgBox;
+  App, StdDlg, MsgBox, FVClip;
 {$ENDIF}
 {$ENDIF FPC_DOTTEDUNITS}
 
@@ -555,7 +556,9 @@ CONST
   sfSearchFailed = NotFoundValue;
 
   { Arrays that hold all the command keys and options. }
-  FirstKeys : array[0..46 * 2] of Word = (46, Ord (^A),    cmWordLeft,
+  { Editor command constants for new features. }
+  cmSelectAll   = 250;
+  FirstKeys : array[0..47 * 2] of Word = (47, Ord (^A),    cmWordLeft,
                                               Ord (^B),    cmReformPara,
                                               Ord (^C),    cmPageDown,
                                               Ord (^D),    cmCharRight,
@@ -597,6 +600,7 @@ CONST
                                               kbIns,       cmInsMode,
                                               kbDel,       cmDelChar,
                                               kbCtrlBack,  cmDelStart,
+                                              7745,        cmSelectAll,
                                               kbShiftIns,  cmPaste,
                                               kbShiftDel,  cmCut,
                                               kbCtrlIns,   cmCopy,
@@ -1722,7 +1726,30 @@ end; {Check_For_Word_Wrap}
 
 
 function TEditor.ClipCopy : Boolean;
+var
+  SelectedTextAnsi: AnsiString;
+  Len: Sw_Word;
 begin
+  if HasSelection then
+  begin
+    Len := SelEnd - SelStart;
+    SetLength(SelectedTextAnsi, Len);
+    if Len > 0 then
+    begin
+      if SelEnd <= CurPtr then
+        Move(Buffer^[SelStart], SelectedTextAnsi[1], Len)
+      else if SelStart >= CurPtr then
+        Move(Buffer^[SelStart + GapLen], SelectedTextAnsi[1], Len)
+      else
+      begin
+        Move(Buffer^[SelStart], SelectedTextAnsi[1], CurPtr - SelStart);
+        Move(Buffer^[CurPtr + GapLen], SelectedTextAnsi[1 + (CurPtr - SelStart)], SelEnd - CurPtr);
+      end;
+      if Length(SelectedTextAnsi) > 0 then
+        SetGlobalClipboardData(PAnsiChar(SelectedTextAnsi), Length(SelectedTextAnsi));
+    end;
+  end;
+
   ClipCopy := False;
   if Assigned(Clipboard) and (Clipboard <> @Self) then
    begin
@@ -2113,6 +2140,17 @@ end; { TEditor.Find }
 { Functon have functionality only in unicode version of fv. }
 { It mimic FormatLine but instead of drawing line gather }
 { information on character posisionings }
+const
+  DelimiterChars: SET OF AnsiChar =
+    [' ', '.', ',', ';', ':', '!', '?', '-', '_', '/', '\',
+     '(', ')', '[', ']', '{', '}', '<', '>',
+     '"', '''', '`', '|', '@', '#', '$', '%', '^', '&',
+     '*', '+', '=', '~', #9, #10, #13];
+
+function TEditor.IsDelimiter(Ch: AnsiChar): Boolean;
+begin
+  Result := Ch in DelimiterChars;
+end;
 function TEditor.BuildLookups(LinePtr : Sw_Word; lookUpCharToPosX, lookUpPosXToChar : PLineLookup):Sw_Word;
 var idxpos : sw_word;
     Width  : Sw_Integer;
@@ -2595,47 +2633,50 @@ begin
       end; { evMouseDown }
 
     evKeyDown:
-{$ifdef FV_UNICODE}
-      Case Event.UnicodeChar Of
-        ' '..#$FFFF:   { Character key }
-          Begin
-            Lock;
-            if Overwrite and not HasSelection then
-              if CurPtr <> LineEnd (CurPtr) then
-                SelEnd := NextChar (CurPtr);
-            InsertChar(Event.UnicodeChar);
-            if Word_Wrap then
-              Check_For_Word_Wrap (SelectMode, CenterCursor);
-            TrackCursor (CenterCursor);
-            Unlock;
+      if (NOT (GetShiftState AND $04 <> 0)) then { Only insert if Ctrl is not pressed }
+      begin
+    {$ifdef FV_UNICODE}
+        Case Event.UnicodeChar Of
+          ' '..#$FFFF:   { Character key }
+            Begin
+              Lock;
+              if Overwrite and not HasSelection then
+                if CurPtr <> LineEnd (CurPtr) then
+                  SelEnd := NextChar (CurPtr);
+              InsertChar(Event.UnicodeChar);
+              if Word_Wrap then
+                Check_For_Word_Wrap (SelectMode, CenterCursor);
+              TrackCursor (CenterCursor);
+              Unlock;
+            End;
+     {
+          ^Y: If Data <> Sw_PString_Empty Then Begin          { Clear all data }
+             Data Sw_PString_DeRef := '';          { Set empty string }
+             CurPos := 0;                          { Cursor to start }
           End;
-   {
-        ^Y: If Data <> Sw_PString_Empty Then Begin          { Clear all data }
-           Data Sw_PString_DeRef := '';          { Set empty string }
-           CurPos := 0;                          { Cursor to start }
+      }
+          Else Exit;                               { Unused key }
         End;
-    }
-        Else Exit;                               { Unused key }
-      End;
-{$else FV_UNICODE}
-      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 FV_UNICODE}
+        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; { evKeyDown }
-{$endif}
+        else
+          Exit;
+        end; { evKeyDown }
+    {$endif}
+      end;
 
     evCommand:
       case Event.Command of
@@ -2646,6 +2687,7 @@ begin
         begin
           Lock;
           case Event.Command of
+            cmSelectAll   : begin SetSelect(0, BufLen, False); TrackCursor(True); end;
             cmCut         : ClipCut;
             cmCopy        : ClipCopy;
             cmPaste       : ClipPaste;
@@ -2731,6 +2773,7 @@ begin
           if (Event.Command <> cmNewLine)   and
              (Event.Command <> cmBackSpace) and
              (Event.Command <> cmTabKey)    and
+             (Event.Command <> cmSelectAll) and
               Modified then
             Remove_EOL_Spaces (SelectMode);
           Unlock;
@@ -3226,12 +3269,12 @@ 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);
+  // Skip the rest of the current word
+  while (P < BufLen) and not IsDelimiter(BufChar(P)) do
+    P := NextChar(P);
+  // Skip trailing delimiters
+  while (P < BufLen) and IsDelimiter(BufChar(P)) do
+    P := NextChar(P);
   NextWord := P;
 end; { TEditor.NextWord }
 
@@ -3302,12 +3345,12 @@ 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);
+  // Skip any delimiters immediately to the left
+  while (P > 0) and IsDelimiter(BufChar(PrevChar(P))) do
+    P := PrevChar(P);
+  // Skip any word characters to the left
+  while (P > 0) and not IsDelimiter(BufChar(PrevChar(P))) do
+    P := PrevChar(P);
   PrevWord := P;
 end; { TEditor.PrevWord }
 
@@ -4011,6 +4054,7 @@ begin
       SetCmdState (cmPaste, assigned(Clipboard) and (Clipboard^.HasSelection));
     end;
   SetCmdState (cmClear, HasSelection);
+  SetCmdState (cmSelectAll, True);
   SetCmdState (cmFind, True);
   SetCmdState (cmReplace, True);
   SetCmdState (cmSearchAgain, True);