Procházet zdrojové kódy

Merge branch 'multipleselectionpaste'

Martijn Laan před 11 měsíci
rodič
revize
d6d8def600
3 změnil soubory, kde provedl 69 přidání a 5 odebrání
  1. 23 2
      Components/ScintEdit.pas
  2. 45 3
      Projects/Src/IDE.MainForm.pas
  3. 1 0
      whatsnew.htm

+ 23 - 2
Components/ScintEdit.pas

@@ -166,8 +166,10 @@ type
     function GetSelectionAnchorVirtualSpace(Selection: Integer): Integer;
     function GetSelectionAnchorVirtualSpace(Selection: Integer): Integer;
     function GetSelectionCaretPosition(Selection: Integer): Integer;
     function GetSelectionCaretPosition(Selection: Integer): Integer;
     function GetSelectionCaretVirtualSpace(Selection: Integer): Integer;
     function GetSelectionCaretVirtualSpace(Selection: Integer): Integer;
+    function GetSelectionEndPosition(Selection: Integer): Integer;
     function GetSelectionCount: Integer;
     function GetSelectionCount: Integer;
     function GetSelectionMode: TScintSelectionMode;
     function GetSelectionMode: TScintSelectionMode;
+    function GetSelectionStartPosition(Selection: Integer): Integer;
     function GetSelText: String;
     function GetSelText: String;
     function GetTopLine: Integer;
     function GetTopLine: Integer;
     function GetZoom: Integer;
     function GetZoom: Integer;
@@ -252,6 +254,7 @@ type
     procedure CancelAutoComplete;
     procedure CancelAutoComplete;
     procedure CancelAutoCompleteAndCallTip;
     procedure CancelAutoCompleteAndCallTip;
     procedure CancelCallTip;
     procedure CancelCallTip;
+    function CanPaste: Boolean;
     function CanRedo: Boolean;
     function CanRedo: Boolean;
     function CanUndo: Boolean;
     function CanUndo: Boolean;
     procedure ChooseCaretX;
     procedure ChooseCaretX;
@@ -403,9 +406,12 @@ type
     property SelectionCaretPosition[Selection: Integer]: Integer read GetSelectionCaretPosition write SetSelectionCaretPosition;
     property SelectionCaretPosition[Selection: Integer]: Integer read GetSelectionCaretPosition write SetSelectionCaretPosition;
     property SelectionCaretVirtualSpace[Selection: Integer]: Integer read GetSelectionCaretVirtualSpace write SetSelectionCaretVirtualSpace;
     property SelectionCaretVirtualSpace[Selection: Integer]: Integer read GetSelectionCaretVirtualSpace write SetSelectionCaretVirtualSpace;
     property SelectionCount: Integer read GetSelectionCount;
     property SelectionCount: Integer read GetSelectionCount;
+    property SelectionEndPosition[Selection: Integer]: Integer read GetSelectionEndPosition;
     property SelectionMode: TScintSelectionMode read GetSelectionMode write SetSelectionMode;
     property SelectionMode: TScintSelectionMode read GetSelectionMode write SetSelectionMode;
+    property SelectionStartPosition[Selection: Integer]: Integer read GetSelectionStartPosition;
     property SelText: String read GetSelText write SetSelText;
     property SelText: String read GetSelText write SetSelText;
     property Styler: TScintCustomStyler read FStyler write SetStyler;
     property Styler: TScintCustomStyler read FStyler write SetStyler;
+    property Target: TScintRange read GetTarget;
     property TopLine: Integer read GetTopLine write SetTopLine;
     property TopLine: Integer read GetTopLine write SetTopLine;
     property WordChars: AnsiString read FWordChars;
     property WordChars: AnsiString read FWordChars;
     property WordCharsAsSet: TSysCharSet read FWordCharsAsSet;
     property WordCharsAsSet: TSysCharSet read FWordCharsAsSet;
@@ -707,6 +713,11 @@ begin
   Call(SCI_CALLTIPCANCEL, 0, 0);
   Call(SCI_CALLTIPCANCEL, 0, 0);
 end;
 end;
 
 
+function TScintEdit.CanPaste: Boolean;
+begin
+  Result := Call(SCI_CANPASTE, 0, 0) <> 0;
+end;
+
 function TScintEdit.CanRedo: Boolean;
 function TScintEdit.CanRedo: Boolean;
 begin
 begin
   Result := Call(SCI_CANREDO, 0, 0) <> 0;
   Result := Call(SCI_CANREDO, 0, 0) <> 0;
@@ -1295,8 +1306,8 @@ procedure TScintEdit.GetSelections(const RangeList: TScintRangeList);
 begin
 begin
   RangeList.Clear;
   RangeList.Clear;
   for var I := 0 to SelectionCount-1 do begin
   for var I := 0 to SelectionCount-1 do begin
-    var StartPos := Call(SCI_GETSELECTIONNSTART, I, 0);
-    var EndPos := Call(SCI_GETSELECTIONNEND, I, 0);
+    var StartPos := GetSelectionStartPosition(I);
+    var EndPos := GetSelectionEndPosition(I);
     RangeList.Add(TScintRange.Create(StartPos, EndPos));
     RangeList.Add(TScintRange.Create(StartPos, EndPos));
   end;
   end;
 end;
 end;
@@ -1349,6 +1360,11 @@ begin
   Result := Call(SCI_GETSELECTIONS, 0, 0);
   Result := Call(SCI_GETSELECTIONS, 0, 0);
 end;
 end;
 
 
+function TScintEdit.GetSelectionEndPosition(Selection: Integer): Integer;
+begin
+  Result := Call(SCI_GETSELECTIONNEND, Selection, 0)
+end;
+
 function TScintEdit.GetSelectionMode: TScintSelectionMode;
 function TScintEdit.GetSelectionMode: TScintSelectionMode;
 begin
 begin
   case Call(SCI_GETSELECTIONMODE, 0, 0) of
   case Call(SCI_GETSELECTIONMODE, 0, 0) of
@@ -1361,6 +1377,11 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TScintEdit.GetSelectionStartPosition(Selection: Integer): Integer;
+begin
+  Result := Call(SCI_GETSELECTIONNSTART, Selection, 0);
+end;
+
 function TScintEdit.GetSelText: String;
 function TScintEdit.GetSelText: String;
 begin
 begin
   Result := ConvertRawStringToString(GetRawSelText);
   Result := ConvertRawStringToString(GetRawSelText);

+ 45 - 3
Projects/Src/IDE.MainForm.pas

@@ -552,6 +552,7 @@ type
     function MemoToTabIndex(const AMemo: TIDEScintEdit): Integer;
     function MemoToTabIndex(const AMemo: TIDEScintEdit): Integer;
     procedure MemoUpdateUI(Sender: TObject; Updated: TScintEditUpdates);
     procedure MemoUpdateUI(Sender: TObject; Updated: TScintEditUpdates);
     procedure MemoZoom(Sender: TObject);
     procedure MemoZoom(Sender: TObject);
+    function MultipleSelectionPasteFromClipboard(const AMemo: TIDESCintEdit): Boolean;
     procedure UpdateReopenTabMenu(const Menu: TMenuItem);
     procedure UpdateReopenTabMenu(const Menu: TMenuItem);
     procedure ModifyMRUMainFilesList(const AFilename: String; const AddNewItem: Boolean);
     procedure ModifyMRUMainFilesList(const AFilename: String; const AddNewItem: Boolean);
     procedure ModifyMRUParametersList(const AParameter: String; const AddNewItem: Boolean);
     procedure ModifyMRUParametersList(const AParameter: String; const AddNewItem: Boolean);
@@ -1427,6 +1428,10 @@ begin
         HtmlHelp(GetDesktopWindow, PChar(HelpFile), HH_KEYWORD_LOOKUP, DWORD(@KLink));
         HtmlHelp(GetDesktopWindow, PChar(HelpFile), HH_KEYWORD_LOOKUP, DWORD(@KLink));
       end;
       end;
     end;
     end;
+  end else if ((Key = Ord('V')) or (Key = VK_INSERT)) and (Shift * [ssShift, ssAlt, ssCtrl] = [ssCtrl]) then begin
+    if FActiveMemo.CanPaste then
+      if MultipleSelectionPasteFromClipboard(FActiveMemo) then
+        Key := 0;
   end else if (Key = VK_SPACE) and (Shift * [ssShift, ssAlt, ssCtrl] = [ssShift, ssCtrl]) then begin
   end else if (Key = VK_SPACE) and (Shift * [ssShift, ssAlt, ssCtrl] = [ssShift, ssCtrl]) then begin
     Key := 0;
     Key := 0;
     { Based on SciTE 5.50's SciTEBase::MenuCommand IDM_SHOWCALLTIP }
     { Based on SciTE 5.50's SciTEBase::MenuCommand IDM_SHOWCALLTIP }
@@ -2859,7 +2864,7 @@ begin
   ERedo.Enabled := MemoHasFocus and FActiveMemo.CanRedo;
   ERedo.Enabled := MemoHasFocus and FActiveMemo.CanRedo;
   ECut.Enabled := MemoHasFocus and not MemoIsReadOnly and not FActiveMemo.SelEmpty;
   ECut.Enabled := MemoHasFocus and not MemoIsReadOnly and not FActiveMemo.SelEmpty;
   ECopy.Enabled := MemoHasFocus and not FActiveMemo.SelEmpty;
   ECopy.Enabled := MemoHasFocus and not FActiveMemo.SelEmpty;
-  EPaste.Enabled := MemoHasFocus and not MemoIsReadOnly and Clipboard.HasFormat(CF_TEXT);
+  EPaste.Enabled := MemoHasFocus and FActiveMemo.CanPaste;
   EDelete.Enabled := MemoHasFocus and not FActiveMemo.SelEmpty;
   EDelete.Enabled := MemoHasFocus and not FActiveMemo.SelEmpty;
   ESelectAll.Enabled := MemoHasFocus;
   ESelectAll.Enabled := MemoHasFocus;
   ESelectNextOccurrence.Enabled := MemoHasFocus;
   ESelectNextOccurrence.Enabled := MemoHasFocus;
@@ -2901,11 +2906,48 @@ begin
   FActiveMemo.CopyToClipboard;
   FActiveMemo.CopyToClipboard;
 end;
 end;
 
 
-procedure TMainForm.EPasteClick(Sender: TObject);
+function TMainForm.MultipleSelectionPasteFromClipboard(const AMemo: TIDEScintEdit): Boolean;
 begin
 begin
-  FActiveMemo.PasteFromClipboard;
+  { Scintilla doesn't yet properly support multiple selection paste. Handle it
+    here, just like VS and VSCode do: if there's multiple selections and the paste
+    text has the same amount of lines then paste 1 line per selection. Do this even
+    if the paste text is marked as rectangular. Otherwise (so no match between
+    the selection count and the line count) paste all lines into each selection.
+    For the latter we don't need handling here: this is Scintilla's default
+    behaviour if SC_MULTIPASTE_EACH is on. }
+  Result := False;
+  var SelectionCount := AMemo.SelectionCount;
+  if SelectionCount > 1 then begin
+    var PasteLines := Clipboard.AsText.Replace(#13#10, #13).Split([#13, #10]);
+    if SelectionCount = Length(PasteLines) then begin
+      AMemo.BeginUndoAction;
+      try
+        for var I := 0 to SelectionCount-1 do begin
+          var StartPos := AMemo.SelectionStartPosition[I]; { Can't use AMemo.GetSelections because each paste can update other selections }
+          var EndPos := AMemo.SelectionEndPosition[I];
+          AMemo.ReplaceTextRange(StartPos, EndPos, PasteLines[I], srmMinimal);
+          { Update the selection to an empty selection at the end of the inserted
+            text, just like ReplaceMainSelText }
+          var Pos := AMemo.Target.EndPos; { ReplaceTextRange updates the target }
+          AMemo.SelectionCaretPosition[I] := Pos;
+          AMemo.SelectionAnchorPosition[I] := Pos;
+        end;
+        { Be like SCI_PASTE }
+        AMemo.ChooseCaretX;
+        AMemo.ScrollCaretIntoView;
+      finally
+        AMemo.EndUndoAction;
+      end;
+      Result := True;
+    end;
+  end;
 end;
 end;
 
 
+procedure TMainForm.EPasteClick(Sender: TObject);
+begin
+  if not MultipleSelectionPasteFromClipboard(FActiveMemo) then
+    FActiveMemo.PasteFromClipboard;
+end;
 
 
 procedure TMainForm.EDeleteClick(Sender: TObject);
 procedure TMainForm.EDeleteClick(Sender: TObject);
 begin
 begin

+ 1 - 0
whatsnew.htm

@@ -43,6 +43,7 @@ For conditions of distribution and use, see <a href="files/is/license.txt">LICEN
   <li>Added shortcut to remove a selection by clicking it (Ctrl+Click or Alt+Click).</li>
   <li>Added shortcut to remove a selection by clicking it (Ctrl+Click or Alt+Click).</li>
   <li>Multiple selection now works over Left, Right, Up, Down, Home and End navigation and selection commands.</li>
   <li>Multiple selection now works over Left, Right, Up, Down, Home and End navigation and selection commands.</li>
   <li>Multiple selection now works over word and line deletion commands, and line end insertion.</li>
   <li>Multiple selection now works over word and line deletion commands, and line end insertion.</li>
+  <li>Multiple selection now works better with Copy and Paste commands.</li>
   <li>Left, Right, etc. navigation with rectangular selection is now allowed.</li>
   <li>Left, Right, etc. navigation with rectangular selection is now allowed.</li>
   <li>The Find and Replace dialogs and the tools from the <i>Tools</i> menu which generate script text now all work better with multiple selections present.</li>
   <li>The Find and Replace dialogs and the tools from the <i>Tools</i> menu which generate script text now all work better with multiple selections present.</li>
 </ul>
 </ul>