Skip to content

Commit

Permalink
Now that Scintilla does proper multiple selection copy thanks to SCI_…
Browse files Browse the repository at this point in the history
…SETCOPYSEPARATOR, tie up the loose end by implementing multiple selection paste as well. Huge improvement 👍

Todo: the rectangular paste check.
  • Loading branch information
martijnlaan committed Oct 11, 2024
1 parent 3d73f01 commit a959c5a
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 5 deletions.
19 changes: 17 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 @@ -403,9 +405,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 @@ -1295,8 +1300,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 +1354,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 +1371,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
41 changes: 38 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 MultipleSelectionPaste(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 not FActiveMemo.ReadOnly and Clipboard.HasFormat(CF_TEXT) then { Also see EMenuClick }
if MultipleSelectionPaste(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 not MemoIsReadOnly and Clipboard.HasFormat(CF_TEXT); { Also see MemoKeyDown }
EDelete.Enabled := MemoHasFocus and not FActiveMemo.SelEmpty;
ESelectAll.Enabled := MemoHasFocus;
ESelectNextOccurrence.Enabled := MemoHasFocus;
Expand Down Expand Up @@ -2901,11 +2906,41 @@ procedure TMainForm.ECopyClick(Sender: TObject);
FActiveMemo.CopyToClipboard;
end;

procedure TMainForm.EPasteClick(Sender: TObject);
function TMainForm.MultipleSelectionPaste(const AMemo: TIDEScintEdit): Boolean;
begin
FActiveMemo.PasteFromClipboard;
{ Scintilla doesn't yet properly support multiple selection paste. Handle it
here, VSCode style: if there's multiple selections and the paste text has the
same amount of lines then paste 1 line per selection. Otherwise do nothing
to allow Scintilla's default behaviour (which is to paste all lines into
each selection if SC_MULTIPASTE_EACH is on). }
Result := False;
var SelectionCount := AMemo.SelectionCount;
if SelectionCount > 1 then begin
var RectangularPaste := False; {todo} { First check for the case Scintilla *does* support }
if not RectangularPaste then begin
var PasteText := Clipboard.AsText.Replace(#13#10, #13).Split([#13, #10]);
if SelectionCount = Length(PasteText) then begin
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, PasteText[I], srmMinimal);
{ Update the selection to an empty selection at the end of the inserted
text, just like SCI_REPLACESEL }
var Pos := AMemo.Target.EndPos; { SCI_REPLACETARGET* updates the target }
AMemo.SelectionCaretPosition[I] := Pos;
AMemo.SelectionAnchorPosition[I] := Pos;
end;
Result := True;
end;
end;
end;
end;

procedure TMainForm.EPasteClick(Sender: TObject);
begin
if not MultipleSelectionPaste(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 a959c5a

Please sign in to comment.