Bläddra i källkod

Merge branch 'SCI_MULTIPLESELECTADD' into isscint-update

Martijn Laan 1 år sedan
förälder
incheckning
d9efeca0a4

+ 46 - 23
Components/ScintEdit.pas

@@ -121,6 +121,8 @@ type
     function GetRawSelText: TScintRawString;
     function GetRawText: TScintRawString;
     function GetReadOnly: Boolean;
+    function GetSearchFlags(const Options: TScintFindOptions): Integer; overload;
+    function GetSearchFlags(const MatchCase: Boolean): Integer; overload;
     function GetSelection: TScintRange;
     function GetSelectionAnchorPosition(Selection: Integer): Integer;
     function GetSelectionCaretPosition(Selection: Integer): Integer;
@@ -250,9 +252,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 Options: TScintFindOptions);
+    procedure SelectNextOccurrence(const Options: TScintFindOptions);
+    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);
@@ -721,17 +725,9 @@ end;
 function TScintEdit.FindRawText(const StartPos, EndPos: Integer;
   const S: TScintRawString; const Options: TScintFindOptions;
   out MatchRange: TScintRange): Boolean;
-var
-  Flags: Integer;
 begin
-  Flags := 0;
-  if sfoMatchCase in Options then
-    Flags := Flags or SCFIND_MATCHCASE;
-  if sfoWholeWord in Options then
-    Flags := Flags or SCFIND_WHOLEWORD;
-
   SetTarget(StartPos, EndPos);
-  Call(SCI_SETSEARCHFLAGS, Flags, 0);
+  Call(SCI_SETSEARCHFLAGS, GetSearchFlags(Options), 0);
   Result := Call(SCI_SEARCHINTARGET, Length(S), LPARAM(PAnsiChar(S))) >= 0;
   if Result then
     MatchRange := GetTarget;
@@ -1000,6 +996,23 @@ begin
   Result := Call(SCI_GETREADONLY, 0, 0) <> 0;
 end;
 
+function TScintEdit.GetSearchFlags(const Options: TScintFindOptions): Integer;
+begin
+  Result := 0;
+  if sfoMatchCase in Options then
+    Result := Result or SCFIND_MATCHCASE;
+  if sfoWholeWord in Options then
+    Result := Result or SCFIND_WHOLEWORD;
+end;
+
+function TScintEdit.GetSearchFlags(const MatchCase: Boolean): Integer;
+begin
+  if MatchCase then
+    Result := GetSearchFlags([sfoMatchCase])
+  else
+    Result := GetSearchFlags([]);
+end;
+
 function TScintEdit.GetSelection: TScintRange;
 begin
   Result.StartPos := Call(SCI_GETSELECTIONSTART, 0, 0);
@@ -1153,20 +1166,13 @@ end;
 
 function TScintEdit.RawSelTextEquals(const S: TScintRawString;
   const MatchCase: Boolean): Boolean;
-var
-  Flags: Integer;
-  Target, Sel: TScintRange;
 begin
-  Flags := 0;
-  if MatchCase then
-    Flags := Flags or SCFIND_MATCHCASE;
-
   Call(SCI_TARGETFROMSELECTION, 0, 0);
-  Call(SCI_SETSEARCHFLAGS, Flags, 0);
+  Call(SCI_SETSEARCHFLAGS, GetSearchFlags(MatchCase), 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 +1224,27 @@ begin
   Call(SCI_SCROLLCARET, 0, 0);
 end;
 
-function TScintEdit.SelNotEmpty: Boolean;
+
+procedure TScintEdit.SelectAllOccurrences(const Options: TScintFindOptions);
+begin
+  Call(SCI_TARGETWHOLEDOCUMENT, 0, 0);
+  Call(SCI_SETSEARCHFLAGS, GetSearchFlags(Options), 0);
+  Call(SCI_MULTIPLESELECTADDEACH, 0, 0);
+end;
+
+procedure TScintEdit.SelectNextOccurrence(const Options: TScintFindOptions);
+begin
+  Call(SCI_TARGETWHOLEDOCUMENT, 0, 0);
+  Call(SCI_SETSEARCHFLAGS, GetSearchFlags(Options), 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;

+ 6 - 0
ISHelp/isetup.xml

@@ -3203,6 +3203,12 @@ Filename: "{win}\MYPROG.INI"; Section: "InstallSettings"; Key: "InstallPath"; St
 <tr>
   <td>Add line as additional selection.</td><td>Ctrl+Triple Click</td>
 </tr>
+<tr>
+  <td>Add the next occurrence of the current word or selected text as an additional selection.</td><td>Alt+Shift+.</td>
+</tr>
+<tr>
+  <td>Select all occurrences of the current word or selected text.</td><td>Alt+Shift+;</td>
+</tr>
 <tr>
   <td>Perform rectangular block selection.</td><td>Alt+Shift+Arrow or Alt+Drag</td>
 </tr>

+ 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

+ 43 - 7
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 }
@@ -1039,12 +1048,19 @@ begin
     else begin
       { The built in Esc (SCI_CANCEL) simply drops all additional selections
         and does not empty the main selection, It doesn't matter if Esc is
-        pressed once or twice. Implement our own behaviour, same as VSCode. }
+        pressed once or twice. Implement our own behaviour, same as VSCode.
+        Also see https://github.com/microsoft/vscode/issues/118835. }
       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 +2454,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 +2507,24 @@ begin
   FActiveMemo.SelectAll;
 end;
 
+procedure TCompileForm.ESelectAllOccurrencesClick(Sender: TObject);
+begin
+  var Options := GetSelTextOccurrenceFindOptions;
+  if FActiveMemo.SelEmpty then begin
+    var Range := FActiveMemo.WordAtCursorRange;
+    if Range.StartPos <> Range.EndPos then begin
+      FActiveMemo.SetSingleSelection(Range.EndPos, Range.StartPos);
+      Options := GetWordOccurrenceFindOptions;
+    end;
+  end;
+  FActiveMemo.SelectAllOccurrences(Options);
+end;
+
+procedure TCompileForm.ESelectNextOccurrenceClick(Sender: TObject);
+begin
+  FActiveMemo.SelectNextOccurrence(GetWordOccurrenceFindOptions);
+end;
+
 procedure TCompileForm.ECompleteWordClick(Sender: TObject);
 begin
   InitiateAutoComplete(#0);
@@ -3295,7 +3331,7 @@ begin
       var Word := AMemo.WordAtCursorRange;
       if (Word.StartPos <> Word.EndPos) and Selection.Within(Word) then begin
         var TextToIndicate := AMemo.GetRawTextRange(Word.StartPos, Word.EndPos);
-        FindTextAndAddRanges(AMemo, TextToIndicate, [sfoMatchCase, sfoWholeWord], SelNotEmpty, Selection, RangeList);
+        FindTextAndAddRanges(AMemo, TextToIndicate, GetWordOccurrenceFindOptions, SelNotEmpty, Selection, RangeList);
       end;
     end;
     AMemo.UpdateIndicators(RangeList, inWordAtCursorOccurrence);
@@ -3303,7 +3339,7 @@ begin
     RangeList.Clear;
     if FOptions.HighlightSelTextOccurrences and SelNotEmpty and SelSingleLine then begin
       var TextToIndicate := AMemo.RawSelText;
-      FindTextAndAddRanges(AMemo, TextToIndicate, [], SelNotEmpty, Selection, RangeList);
+      FindTextAndAddRanges(AMemo, TextToIndicate, GetSelTextOccurrenceFindOptions, SelNotEmpty, Selection, RangeList);
     end;
     AMemo.UpdateIndicators(RangeList, inSelTextOccurrence);
   finally

+ 19 - 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);
@@ -68,6 +69,8 @@ function GetSourcePath(const AFilename: String): String;
 function ReadScriptLines(const ALines: TStringList; const ReadFromFile: Boolean;
   const ReadFromFileFilename: String; const NotReadFromFileMemo: TScintEdit): Integer;
 function CreateBitmapInfo(const Width, Height, BitCount: Integer): TBitmapInfo;
+function GetWordOccurrenceFindOptions: TScintFindOptions;
+function GetSelTextOccurrenceFindOptions: TScintFindOptions;
 
 implementation
 
@@ -455,6 +458,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
@@ -703,6 +711,16 @@ begin
   Result.bmiHeader.biCompression := BI_RGB;
 end;
 
+function GetWordOccurrenceFindOptions: TScintFindOptions;
+begin
+  Result := [sfoMatchCase, sfoWholeWord];
+end;
+
+function GetSelTextOccurrenceFindOptions: TScintFindOptions;
+begin
+  Result := [];
+end;
+
 initialization
   var OSVersionInfo: TOSVersionInfo;
   OSVersionInfo.dwOSVersionInfoSize := SizeOf(OSVersionInfo);

+ 2 - 8
Projects/Src/CompScintEdit.pas

@@ -139,18 +139,12 @@ begin
   inherited;
 
   { Some notes about future Scintilla versions:
+    -Does it at some point become possible to change mouse shortcut Ctrl+Click
+     to Alt+Click?
     -At some point the documentation will say:
      "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/

+ 9 - 3
whatsnew.htm

@@ -32,15 +32,21 @@ For conditions of distribution and use, see <a href="files/is/license.txt">LICEN
 
 <p><a name="6.4.0"></a><span class="ver">6.4.0-dev </span><span class="date">(?)</span></p>
 <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>
+<p>The editor component used by the Compiler IDE has been updated from an old version of Scintilla to the latest version.</p>
+<p>Multiple selection editing has been improved:</p>
 <ul>
-  <li>Added shortcuts to move selected lines up or down (Alt+Up and Alt+Down).</li>
+  <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 word and line deletion commands, and line end insertion.</li>
   <li>When autocompleting with multiple selections present, the autocompleted text now goes into each selection.</li>
-  <li>The icons used by the editor's gutter are now supported even at very high DPI.</li>
+</ul>
+<p>Other changes:</p>
+<ul>
+  <li>Added shortcuts to move selected lines up or down (Alt+Up and Alt+Down).</li>
+  <li>Minor tweaks and documentation improvements.</li>
 </ul>
 
 <p><a name="6.3.1"></a><span class="ver">6.3.1 </span><span class="date">(2024-06-10)</span></p>