Skip to content

Commit

Permalink
Merge branch 'multipleselectionpaste'
Browse files Browse the repository at this point in the history
  • Loading branch information
martijnlaan committed Oct 11, 2024
2 parents 3d73f01 + c9a9dc5 commit d6d8def
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 5 deletions.
25 changes: 23 additions & 2 deletions Components/ScintEdit.pas
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,10 @@ TScintEdit = class(TWinControl)
function GetSelectionAnchorVirtualSpace(Selection: Integer): Integer;
function GetSelectionCaretPosition(Selection: Integer): Integer;
function GetSelectionCaretVirtualSpace(Selection: Integer): Integer;
function GetSelectionEndPosition(Selection: Integer): Integer;
function GetSelectionCount: Integer;
function GetSelectionMode: TScintSelectionMode;
function GetSelectionStartPosition(Selection: Integer): Integer;
function GetSelText: String;
function GetTopLine: Integer;
function GetZoom: Integer;
Expand Down Expand Up @@ -252,6 +254,7 @@ TScintEdit = class(TWinControl)
procedure CancelAutoComplete;
procedure CancelAutoCompleteAndCallTip;
procedure CancelCallTip;
function CanPaste: Boolean;
function CanRedo: Boolean;
function CanUndo: Boolean;
procedure ChooseCaretX;
Expand Down Expand Up @@ -403,9 +406,12 @@ TScintEdit = class(TWinControl)
property SelectionCaretPosition[Selection: Integer]: Integer read GetSelectionCaretPosition write SetSelectionCaretPosition;
property SelectionCaretVirtualSpace[Selection: Integer]: Integer read GetSelectionCaretVirtualSpace write SetSelectionCaretVirtualSpace;
property SelectionCount: Integer read GetSelectionCount;
property SelectionEndPosition[Selection: Integer]: Integer read GetSelectionEndPosition;
property SelectionMode: TScintSelectionMode read GetSelectionMode write SetSelectionMode;
property SelectionStartPosition[Selection: Integer]: Integer read GetSelectionStartPosition;
property SelText: String read GetSelText write SetSelText;
property Styler: TScintCustomStyler read FStyler write SetStyler;
property Target: TScintRange read GetTarget;
property TopLine: Integer read GetTopLine write SetTopLine;
property WordChars: AnsiString read FWordChars;
property WordCharsAsSet: TSysCharSet read FWordCharsAsSet;
Expand Down Expand Up @@ -707,6 +713,11 @@ procedure TScintEdit.CancelCallTip;
Call(SCI_CALLTIPCANCEL, 0, 0);
end;

function TScintEdit.CanPaste: Boolean;
begin
Result := Call(SCI_CANPASTE, 0, 0) <> 0;
end;

function TScintEdit.CanRedo: Boolean;
begin
Result := Call(SCI_CANREDO, 0, 0) <> 0;
Expand Down Expand Up @@ -1295,8 +1306,8 @@ procedure TScintEdit.GetSelections(const RangeList: TScintRangeList);
begin
RangeList.Clear;
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));
end;
end;
Expand Down Expand Up @@ -1349,6 +1360,11 @@ function TScintEdit.GetSelectionCount: Integer;
Result := Call(SCI_GETSELECTIONS, 0, 0);
end;

function TScintEdit.GetSelectionEndPosition(Selection: Integer): Integer;
begin
Result := Call(SCI_GETSELECTIONNEND, Selection, 0)
end;

function TScintEdit.GetSelectionMode: TScintSelectionMode;
begin
case Call(SCI_GETSELECTIONMODE, 0, 0) of
Expand All @@ -1361,6 +1377,11 @@ function TScintEdit.GetSelectionMode: TScintSelectionMode;
end;
end;

function TScintEdit.GetSelectionStartPosition(Selection: Integer): Integer;
begin
Result := Call(SCI_GETSELECTIONNSTART, Selection, 0);
end;

function TScintEdit.GetSelText: String;
begin
Result := ConvertRawStringToString(GetRawSelText);
Expand Down
48 changes: 45 additions & 3 deletions Projects/Src/IDE.MainForm.pas
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@ TMainForm = class(TUIStateForm)
function MemoToTabIndex(const AMemo: TIDEScintEdit): Integer;
procedure MemoUpdateUI(Sender: TObject; Updated: TScintEditUpdates);
procedure MemoZoom(Sender: TObject);
function MultipleSelectionPasteFromClipboard(const AMemo: TIDESCintEdit): Boolean;
procedure UpdateReopenTabMenu(const Menu: TMenuItem);
procedure ModifyMRUMainFilesList(const AFilename: String; const AddNewItem: Boolean);
procedure ModifyMRUParametersList(const AParameter: String; const AddNewItem: Boolean);
Expand Down Expand Up @@ -1427,6 +1428,10 @@ procedure TMainForm.MemoKeyDown(Sender: TObject; var Key: Word;
HtmlHelp(GetDesktopWindow, PChar(HelpFile), HH_KEYWORD_LOOKUP, DWORD(@KLink));
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
Key := 0;
{ Based on SciTE 5.50's SciTEBase::MenuCommand IDM_SHOWCALLTIP }
Expand Down Expand Up @@ -2859,7 +2864,7 @@ procedure TMainForm.EMenuClick(Sender: TObject);
ERedo.Enabled := MemoHasFocus and FActiveMemo.CanRedo;
ECut.Enabled := MemoHasFocus and not MemoIsReadOnly 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;
ESelectAll.Enabled := MemoHasFocus;
ESelectNextOccurrence.Enabled := MemoHasFocus;
Expand Down Expand Up @@ -2901,11 +2906,48 @@ procedure TMainForm.ECopyClick(Sender: TObject);
FActiveMemo.CopyToClipboard;
end;

procedure TMainForm.EPasteClick(Sender: TObject);
function TMainForm.MultipleSelectionPasteFromClipboard(const AMemo: TIDEScintEdit): Boolean;
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;

procedure TMainForm.EPasteClick(Sender: TObject);
begin
if not MultipleSelectionPasteFromClipboard(FActiveMemo) then
FActiveMemo.PasteFromClipboard;
end;

procedure TMainForm.EDeleteClick(Sender: TObject);
begin
Expand Down
1 change: 1 addition & 0 deletions whatsnew.htm
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
<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 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>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>
Expand Down

0 comments on commit d6d8def

Please sign in to comment.