Skip to content

Commit

Permalink
True multi-caret editing support ✅
Browse files Browse the repository at this point in the history
  • Loading branch information
martijnlaan committed Jun 14, 2024
1 parent 02abe0c commit 8be06f4
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 7 deletions.
48 changes: 43 additions & 5 deletions Components/ScintEdit.pas
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ TScintRangeList = class(TList<TScintRange>)
TScintRectangle = record
Left, Top, Right, Bottom: Integer;
end;
TScintSelectionMode = (ssmStream, ssmRectangular, ssmLines, ssmThinRectangular);
TScintStyleNumber = 0..StyleNumbers-1;
TScintVirtualSpaceOption = (svsRectangularSelection, svsUserAccessible,
svsNoWrapLineStart);
Expand All @@ -79,6 +80,8 @@ TScintRangeToFormat = record
TScintEditStrings = class;
TScintCustomStyler = class;

EScintEditError = class(Exception);

TScintEdit = class(TWinControl)
private
FAcceptDroppedFiles: Boolean;
Expand Down Expand Up @@ -135,6 +138,7 @@ TScintEdit = class(TWinControl)
function GetSelectionAnchorPosition(Selection: Integer): Integer;
function GetSelectionCaretPosition(Selection: Integer): Integer;
function GetSelectionCount: Integer;
function GetSelectionMode: TScintSelectionMode;
function GetSelText: String;
function GetTopLine: Integer;
function GetZoom: Integer;
Expand All @@ -157,6 +161,7 @@ TScintEdit = class(TWinControl)
procedure SetSelection(const Value: TScintRange);
procedure SetSelectionAnchorPosition(Selection: Integer; const AnchorPos: Integer);
procedure SetSelectionCaretPosition(Selection: Integer; const CaretPos: Integer);
procedure SetSelectionMode(const Value: TScintSelectionMode);
procedure SetSelText(const Value: String);
procedure SetStyler(const Value: TScintCustomStyler);
procedure SetTabWidth(const Value: Integer);
Expand Down Expand Up @@ -185,7 +190,8 @@ TScintEdit = class(TWinControl)
procedure CheckPosRange(const StartPos, EndPos: Integer);
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
class procedure Error(const S: String);
class function GetErrorException(const S: String): EScintEditError;
class procedure Error(const S: String); overload;
class procedure ErrorFmt(const S: String; const Args: array of const);
function GetMainSelection: Integer;
function GetTarget: TScintRange;
Expand Down Expand Up @@ -316,6 +322,7 @@ TScintEdit = class(TWinControl)
property SelectionAnchorPosition[Selection: Integer]: Integer read GetSelectionAnchorPosition write SetSelectionAnchorPosition;
property SelectionCaretPosition[Selection: Integer]: Integer read GetSelectionCaretPosition write SetSelectionCaretPosition;
property SelectionCount: Integer read GetSelectionCount;
property SelectionMode: TScintSelectionMode read GetSelectionMode write SetSelectionMode;
property SelText: String read GetSelText write SetSelText;
property Styler: TScintCustomStyler read FStyler write SetStyler;
property TopLine: Integer read GetTopLine write SetTopLine;
Expand Down Expand Up @@ -462,8 +469,6 @@ TScintPixmap = class
property Pixmap: Pointer read GetPixmap;
end;

EScintEditError = class(Exception);

function ScintRawStringIsBlank(const S: TScintRawString): Boolean;

implementation
Expand Down Expand Up @@ -743,9 +748,14 @@ procedure TScintEdit.EndUndoAction;
Call(SCI_ENDUNDOACTION, 0, 0);
end;

class function TScintEdit.GetErrorException(const S: String): EScintEditError;
begin
Result := EScintEditError.Create('TScintEdit error: ' + S);
end;

class procedure TScintEdit.Error(const S: String);
begin
raise EScintEditError.Create('TScintEdit error: ' + S);
raise GetErrorException(S);
end;

class procedure TScintEdit.ErrorFmt(const S: String; const Args: array of const);
Expand Down Expand Up @@ -856,8 +866,9 @@ function TScintEdit.GetLineEndings: TScintLineEndings;
case Call(SCI_GETEOLMODE, 0, 0) of
SC_EOL_CR: Result := sleCR;
SC_EOL_LF: Result := sleLF;
SC_EOL_CRLF: Result := sleCRLF;
else
Result := sleCRLF;
raise GetErrorException('Unexpected SCI_GETEOLMODE result');
end;
end;

Expand Down Expand Up @@ -1077,6 +1088,18 @@ function TScintEdit.GetSelectionCount: Integer;
Result := Call(SCI_GETSELECTIONS, 0, 0);
end;

function TScintEdit.GetSelectionMode: TScintSelectionMode;
begin
case Call(SCI_GETSELECTIONMODE, 0, 0) of
SC_SEL_STREAM: Result := ssmStream;
SC_SEL_RECTANGLE: Result := ssmRectangular;
SC_SEL_LINES: Result := ssmLines;
SC_SEL_THIN: Result := ssmThinRectangular;
else
raise GetErrorException('Unexpected SCI_GETSELECTIONMODE result');
end;
end;

function TScintEdit.GetSelText: String;
begin
Result := ConvertRawStringToString(GetRawSelText);
Expand Down Expand Up @@ -1536,6 +1559,21 @@ procedure TScintEdit.SetSelectionCaretPosition(Selection: Integer;
Call(SCI_SETSELECTIONNCARET, Selection, CaretPos);
end;

procedure TScintEdit.SetSelectionMode(const Value: TScintSelectionMode);
begin
var Mode: Integer;
if Value = ssmStream then
Mode := SC_SEL_STREAM
else if Value = ssmRectangular then
Mode := SC_SEL_RECTANGLE
else if Value = ssmLines then
Mode := SC_SEL_LINES
else
Mode := SC_SEL_THIN;
{ Note this uses *CHANGE* and not *SET* }
Call(SCI_CHANGESELECTIONMODE, Mode, 0);
end;

procedure TScintEdit.SetSelText(const Value: String);
begin
SetRawSelText(ConvertStringToRawString(Value));
Expand Down
12 changes: 12 additions & 0 deletions Projects/Src/CompForm.pas
Original file line number Diff line number Diff line change
Expand Up @@ -2807,6 +2807,18 @@ procedure TCompileForm.HDocClick(Sender: TObject);
procedure TCompileForm.MemoKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if Key in [VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_HOME, VK_END] then begin
var Memo := Sender as TScintEdit;
if Memo.SelectionMode in [ssmRectangular, ssmThinRectangular] then begin
{ Allow left/right/etc. navigation with rectangular selection, see
https://sourceforge.net/p/scintilla/feature-requests/1275/ and
https://sourceforge.net/p/scintilla/bugs/2412/#cb37
Notepad++ calls this "Enable Column Selection to Multi-editing" which
is on by default and in VSCode and VS it's also on by default. }
Memo.SelectionMode := ssmStream;
end;
end;

if Key = VK_F1 then begin
var HelpFile := GetHelpFile;
if Assigned(HtmlHelp) then begin
Expand Down
4 changes: 2 additions & 2 deletions whatsnew.htm
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@
<li>Added shortcut to add the next occurrence of the current word or selected text as an additional selection (Alt+Shift+.).</li>
<li>Added shortcut to select all occurrences of the current word or selected text (Alt+Shift+;).</li>
<li>Added shortcuts to add a word or line as an additional selection (Ctrl+Double Click and Ctrl+Triple Click).</li>
<li>Multiple selection now works over horizontal movement and selection commands.</li>
<li>Multiple selection now works over line up and down movement 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>Left, Right, etc. navigation with rectangular selection is now allowed which completes "true" multi-caret editing support.</li>
<li>When autocompleting with multiple selections present, the autocompleted text now goes into each selection.</li>
</ul>
<p>Other changes:</p>
Expand Down

0 comments on commit 8be06f4

Please sign in to comment.