ソースを参照

Add shortcut to add the next occurrence of the current word or selected text as an additional selection (Alt+Shift+.). Add shortcut to select all occurrences of the current word or selected text (Alt+Shift+;).

Behaviour of the second is same as VSCode, VS and Notepad++.

Alt+Shift+; match case behaviour is consistent with in case insensitive nature of selected text highlighting.

Not yet a big fan of the shortcuts. These are from VS. I like the ones from VSCode better (Ctrl+D and Ctrl+Shift+L) but those duplicate and delete a line already in Compil32 (and also in VS). VSCode's shortcut for duplicate line is Alt+Shift+Down but that's rectangular block select in Compil32 (and also in VS). Delete line is Ctrl +Shift+K.

Notepad++ has no shortcuts for add next/all by default (?!???). It also is opinionless about match case etc add just has 4 extra options per shortcut (?!?).

Most amazingly RAD Studio doesn't do this at all and is easily the worst and slowest editor of them all (including Compil32).
Martijn Laan 1 年間 前
コミット
bd0c3c2463

+ 36 - 12
Components/ScintEdit.pas

@@ -250,9 +250,11 @@ type
     function ReplaceTextRange(const StartPos, EndPos: Integer; const S: String): TScintRange;
     procedure RestyleLine(const Line: Integer);
     procedure ScrollCaretIntoView;
-    function SelNotEmpty: Boolean; overload;
-    function SelNotEmpty(out Sel: TScintRange): Boolean; overload;
     procedure SelectAll;
+    procedure SelectAllOccurrences(const MatchCase: Boolean);
+    procedure SelectNextOccurrence(const MatchCase: Boolean);
+    function SelEmpty: Boolean;
+    function SelNotEmpty(out Sel: TScintRange): Boolean;
     function SelTextEquals(const S: String; const MatchCase: Boolean): Boolean;
     procedure SetAutoCompleteFillupChars(const FillupChars: AnsiString);
     procedure SetAutoCompleteSeparator(const C: AnsiChar);
@@ -1153,20 +1155,17 @@ end;
 
 function TScintEdit.RawSelTextEquals(const S: TScintRawString;
   const MatchCase: Boolean): Boolean;
-var
-  Flags: Integer;
-  Target, Sel: TScintRange;
 begin
-  Flags := 0;
+  var SearchFlags := 0;
   if MatchCase then
-    Flags := Flags or SCFIND_MATCHCASE;
+    SearchFlags := SearchFlags or SCFIND_MATCHCASE;
 
   Call(SCI_TARGETFROMSELECTION, 0, 0);
-  Call(SCI_SETSEARCHFLAGS, Flags, 0);
+  Call(SCI_SETSEARCHFLAGS, SearchFlags, 0);
   Result := False;
   if Call(SCI_SEARCHINTARGET, Length(S), LPARAM(PAnsiChar(S))) >= 0 then begin
-    Target := GetTarget;
-    Sel := GetSelection;
+    var Target := GetTarget;
+    var Sel := GetSelection;
     if (Target.StartPos = Sel.StartPos) and (Target.EndPos = Sel.EndPos) then
       Result := True;
   end;
@@ -1218,10 +1217,35 @@ begin
   Call(SCI_SCROLLCARET, 0, 0);
 end;
 
-function TScintEdit.SelNotEmpty: Boolean;
+
+procedure TScintEdit.SelectAllOccurrences(const MatchCase: Boolean);
+begin
+  var SearchFlags := 0;
+  if MatchCase then
+    SearchFlags := SearchFlags or SCFIND_MATCHCASE;
+
+  Call(SCI_TARGETWHOLEDOCUMENT, 0, 0);
+  Call(SCI_SETSEARCHFLAGS, SearchFlags, 0);
+  Call(SCI_MULTIPLESELECTADDEACH, 0, 0);
+end;
+
+procedure TScintEdit.SelectNextOccurrence(const MatchCase: Boolean);
+begin
+  var SearchFlags := 0;
+  if MatchCase then
+    SearchFlags := SearchFlags or SCFIND_MATCHCASE;
+
+  Call(SCI_TARGETWHOLEDOCUMENT, 0, 0);
+  Call(SCI_SETSEARCHFLAGS, SearchFlags, 0);
+  Call(SCI_MULTIPLESELECTADDNEXT, 0, 0);
+end;
+
+function TScintEdit.SelEmpty: Boolean;
+{ Returns True if the main selection is empty even if there are additional
+  selections. }
 begin
   var Sel: TScintRange;
-  Result := SelNotEmpty(Sel);
+  Result := not SelNotEmpty(Sel);
 end;
 
 function TScintEdit.SelNotEmpty(out Sel: TScintRange): Boolean;

+ 8 - 0
Projects/Src/CompForm.dfm

@@ -460,6 +460,14 @@ object CompileForm: TCompileForm
         Caption = 'Select &All'
         OnClick = ESelectAllClick
       end
+      object ESelectNextOccurrence: TMenuItem
+        Caption = 'Add Next &Occurrence'
+        OnClick = ESelectNextOccurrenceClick
+      end
+      object ESelectAllOccurrences: TMenuItem
+        Caption = '&Select All Occurrences'
+        OnClick = ESelectAllOccurrencesClick
+      end
       object N4: TMenuItem
         Caption = '-'
       end

+ 39 - 4
Projects/Src/CompForm.pas

@@ -228,6 +228,8 @@ type
     LightMarkersImageCollection: TImageCollection;
     DarkMarkersImageCollection: TImageCollection;
     ThemedMarkersVirtualImageList: TVirtualImageList;
+    ESelectNextOccurrence: TMenuItem;
+    ESelectAllOccurrences: TMenuItem;
     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
     procedure FExitClick(Sender: TObject);
     procedure FOpenMainFileClick(Sender: TObject);
@@ -341,6 +343,8 @@ type
     procedure BackNavButtonClick(Sender: TObject);
     procedure ForwardNavButtonClick(Sender: TObject);
     procedure NavPopupMenuClick(Sender: TObject);
+    procedure ESelectNextOccurrenceClick(Sender: TObject);
+    procedure ESelectAllOccurrencesClick(Sender: TObject);
   private
     { Private declarations }
     FMemos: TList<TCompScintEdit>;                      { FMemos[0] is the main memo and FMemos[1] the preprocessor output memo - also see MemosTabSet comment above }
@@ -438,6 +442,7 @@ type
     FCurrentNavItem: TCompScintEditNavItem;
     FBackNavButtonShortCut, FForwardNavButtonShortCut: TShortCut;
     FIgnoreTabSetClick: Boolean;
+    FSelectNextOccurrenceShortCut, FSelectAllOccurrencesShortCut: TShortCut;
     class procedure AppOnException(Sender: TObject; E: Exception);
     procedure AppOnActivate(Sender: TObject);
     procedure AppOnIdle(Sender: TObject; var Done: Boolean);
@@ -825,6 +830,10 @@ begin
   SetFakeShortCut(ECopy, Ord('C'), [ssCtrl]);
   SetFakeShortCut(EPaste, Ord('V'), [ssCtrl]);
   SetFakeShortCut(ESelectAll, Ord('A'), [ssCtrl]);
+  FSelectNextOccurrenceShortCut := ShortCut(VK_OEM_PERIOD, [ssShift, ssAlt]);
+  SetFakeShortCut(ESelectNextOccurrence, FSelectNextOccurrenceShortCut);
+  FSelectAllOccurrencesShortCut := ShortCut(VK_OEM_1, [ssShift, ssAlt]);
+  SetFakeShortCut(ESelectAllOccurrences, FSelectAllOccurrencesShortCut);
   SetFakeShortCut(EDelete, VK_DELETE, []);
   SetFakeShortCut(ECompleteWord, Ord(' '), [ssCtrl]);
   SetFakeShortCutText(VZoomIn, SmkcCtrl + 'Num +');    { These zoom shortcuts are handled by Scintilla and only support the active memo, unlike the menu items which work on all memos }
@@ -1042,9 +1051,15 @@ begin
         pressed once or twice. Implement our own behaviour, same as VSCode. }
       if FActiveMemo.SelectionCount > 1 then
         FActiveMemo.RemoveAdditionalSelections
-      else if FActiveMemo.SelNotEmpty then
+      else if not FActiveMemo.SelEmpty then
         FActiveMemo.SetEmptySelection;
     end;
+  end else if AShortCut = FSelectNextOccurrenceShortCut then begin
+    if ESelectNextOccurrence.Enabled then
+      ESelectNextOccurrenceClick(Self);
+  end else if AShortCut = FSelectAllOccurrencesShortCut then begin
+    if ESelectAllOccurrences.Enabled then
+      ESelectAllOccurrencesClick(Self);
   end else if AShortCut = FBackNavButtonShortCut then begin
     if BackNavButton.Enabled then
       BackNavButtonClick(Self);
@@ -2438,11 +2453,13 @@ begin
   MemoIsReadOnly := FActiveMemo.ReadOnly;
   EUndo.Enabled := MemoHasFocus and FActiveMemo.CanUndo;
   ERedo.Enabled := MemoHasFocus and FActiveMemo.CanRedo;
-  ECut.Enabled := MemoHasFocus and not MemoIsReadOnly and FActiveMemo.SelNotEmpty;
-  ECopy.Enabled := MemoHasFocus and FActiveMemo.SelNotEmpty;
+  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);
-  EDelete.Enabled := MemoHasFocus and FActiveMemo.SelNotEmpty;
+  EDelete.Enabled := MemoHasFocus and not FActiveMemo.SelEmpty;
   ESelectAll.Enabled := MemoHasFocus;
+  ESelectNextOccurrence.Enabled := MemoHasFocus;
+  ESelectAllOccurrences.Enabled := MemoHasFocus;
   EFind.Enabled := MemoHasFocus;
   EFindNext.Enabled := MemoHasFocus;
   EFindPrevious.Enabled := MemoHasFocus;
@@ -2489,6 +2506,24 @@ begin
   FActiveMemo.SelectAll;
 end;
 
+procedure TCompileForm.ESelectAllOccurrencesClick(Sender: TObject);
+begin
+  var MatchCase := False;
+  if FActiveMemo.SelEmpty then begin
+    var Range := FActiveMemo.WordAtCursorRange;
+    if Range.StartPos <> Range.EndPos then begin
+      FActiveMemo.SetSingleSelection(Range.EndPos, Range.StartPos);
+      MatchCase := True;
+    end;
+  end;
+  FActiveMemo.SelectAllOccurrences(MatchCase);
+end;
+
+procedure TCompileForm.ESelectNextOccurrenceClick(Sender: TObject);
+begin
+  FActiveMemo.SelectNextOccurrence(True);
+end;
+
 procedure TCompileForm.ECompleteWordClick(Sender: TObject);
 begin
   InitiateAutoComplete(#0);

+ 7 - 1
Projects/Src/CompFunc.pas

@@ -56,7 +56,8 @@ procedure SaveBreakPointLines(const AFilename: String; const BreakPointLines: TS
 procedure DeleteBreakPointLines(const AFilename: String);
 procedure SetFakeShortCutText(const MenuItem: TMenuItem; const S: String);
 procedure SetFakeShortCut(const MenuItem: TMenuItem; const Key: Word;
-  const Shift: TShiftState);
+  const Shift: TShiftState); overload;
+procedure SetFakeShortCut(const MenuItem: TMenuItem; const ShortCut: TShortCut); overload;
 procedure SaveTextToFile(const Filename: String;
   const S: String; const SaveEncoding: TSaveEncoding);
 procedure AddLines(const ListBox: TListBox; const S: String; const AObject: TObject; const LineBreaks: Boolean; const Prefix: TAddLinesPrefix; const PrefixParam: Cardinal);
@@ -455,6 +456,11 @@ begin
   SetFakeShortCutText(MenuItem, ShortCutToText(ShortCut(Key, Shift)));
 end;
 
+procedure SetFakeShortCut(const MenuItem: TMenuItem; const ShortCut: TShortCut);
+begin
+  SetFakeShortCutText(MenuItem, ShortCutToText(ShortCut));
+end;
+
 procedure SaveTextToFile(const Filename: String;
   const S: String; const SaveEncoding: TSaveEncoding);
 var

+ 0 - 8
Projects/Src/CompScintEdit.pas

@@ -143,14 +143,6 @@ begin
      "The INDICATOR_* values used for dividing up indicators were previously
       INDIC_CONTAINER, INDIC_IME, INDIC_IME_MAX, and INDIC_MAX"
      Once it does replace our use of these INDIC_* with INDICATOR_*.
-    -3.5.7: Use SCI_MULTIPLESELECTADDEACH to implement Ctrl+Shift+L (Select All
-            Occurrences) and SCI_MULTIPLESELECTADDNEXT to implement Ctrl+D (Select
-            Next Occurrence). If the selection is empty Scintilla will use word
-            searching so call SCI_SETSEARCHFLAGS first to turn on case match and
-            whole word in that case, and turn it off otherwise. This way it
-            behaves same as TCompileForm.UpdateOccurrenceIndicators. Also requires
-            calling SCI_TARGETWHOLEDOCUMENT.
-            !!! Note https://github.com/notepad-plus-plus/notepad-plus-plus/pull/14330
     -3.6.6: Investigate SCFIND_CXX11REGEX: C++ 11 <regex> support built by default.
             Can be disabled by defining NO_CXX11_REGEX. Good (?) overview at:
             https://cplusplus.com/reference/regex/ECMAScript/

+ 2 - 0
whatsnew.htm

@@ -34,6 +34,8 @@ For conditions of distribution and use, see <a href="files/is/license.txt">LICEN
 <p><span class="head2">Compiler IDE changes</span></p>
 <p>The editor component used by the Compiler IDE has been updated from an old version of Scintilla to the latest version:</p>
 <ul>
+  <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 move selected lines up or down (Alt+Up and Alt+Down).</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>