diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0819aba8..37e50249 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,7 +3,8 @@
## Enhancements
- Dlang highlighter: added suport for HEREDOC strings literal of type `q"()"` `q"[]"`, `q"<>"` and `q"{}"`. "Custom" HEREDOC strings literal wont be handled as they might be removed as per DIP 1026.
-- Docking: added disalog to remind that docking is locked in certain scenarios. (#30)
+- Docking: added a dialog to remind that docking is locked in certain scenarios. (#30)
+- Search Replace: the result of _FindAll_ when the string to seach is a regular expression are highlighted. (#14)
- TODO list: a new option, _disableIfMoreFilesThan_, allows to disable auto refreshing of the list could be slow when the current project is huge.
## Bugs fixed
diff --git a/docs/widgets_search.md b/docs/widgets_search.md
index 11bfaadb..b3935b0e 100644
--- a/docs/widgets_search.md
+++ b/docs/widgets_search.md
@@ -12,9 +12,9 @@ The _find and replace_ widget allows to find and replace text patterns in the fo
- **whole word**: Only searches for the whole string.
- **backward**: Searches from the current position to the top.
- **from cursor**: When not checked the operation always starts from the top of the document.
-- **case sensitive**: When unchecked the characters case is ignored.
+- **case sensitive**: When unchecked the characters case is ignored. Note that this affects the way regexes are compiled.
- **prompt**: A confirmation is required to replace a match.
-- **allow regex**: When checked, the search is performed by a regex engine. Note that it doesn't mean that the pattern to find has to be a regex).
+- **allow regex**: When checked, the search is performed by a regex engine.
By default CTRL + F is used to pass the current identifier to the first field and F3 to execute a search.
The _Find all_ results are displayed in the [messages widget](widgets_messages.html), with the context and they can be clicked.
diff --git a/src/u_search.pas b/src/u_search.pas
index 6a74b256..8e834050 100644
--- a/src/u_search.pas
+++ b/src/u_search.pas
@@ -7,9 +7,9 @@ interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
Menus, StdCtrls, actnList, Buttons, SynEdit, SynEditSearch, SynEditTypes,
- u_common, u_mru, u_widget, u_synmemo, u_interfaces, u_observer, strutils,
- u_writableComponent, u_dialogs, u_sharedres, u_dsgncontrols,
- SynEditTextBuffer;
+ RegExpr, SynEditTextBuffer, strutils,
+ u_common, u_mru, u_widget, u_synmemo, u_interfaces, u_observer,
+ u_writableComponent, u_dialogs, u_sharedres, u_dsgncontrols;
type
@@ -459,7 +459,13 @@ var
msg: string;
fmt: string;
i: integer;
+ j: integer = 0;
+ k: integer;
+ o: integer = -1;
res: array of TPoint = nil;
+ r: TRegExpr;
+ s: string;
+ rStart: integer;
begin
result := 0;
search := TSynEditSearch.Create;
@@ -496,11 +502,53 @@ begin
msgs.message(msg, nil, amcMisc, amkInf);
end;
fmt := fileName + '(%d,%d): "%s"';
- for i := 0 to high(res) do
+ // highlighting
+ if ssoRegExpr in options then
begin
- msg := format(fmt, [res[i].Y, res[i].X, Trim(lines[res[i].Y-1])]);
+ r := TRegExpr.Create(fToFind);
+ try
+ r.ModifierI := not (ssoMatchCase in options);
+ for i := 0 to high(res) do
+ begin
+ msg := Trim(lines[res[i].Y-1]);
+ // current result is on same line as previous
+ if res[i].Y = o then
+ j += 1
+ else
+ j := 0;
+ rStart := 1;
+ s := '';
+ k := 0;
+ if r.Exec(msg) then
+ repeat
+ s += msg[rStart .. r.MatchPos[0]-1];
+ // count of time we got the same line as result is the nth match to highlight
+ if k = j then
+ begin
+ s += '`' + r.Match[0] + '`';
+ rStart := r.MatchPos[0] + r.MatchLen[0];
+ // dont bother with slicing trailing results once highlighting done
+ break;
+ end
+ else
+ s += r.Match[0];
+ rStart := r.MatchPos[0] + r.MatchLen[0];
+ k += 1;
+ until
+ not r.ExecNext();
+ s += msg[rStart .. msg.length];
+ msgs.message(format(fmt, [res[i].Y, res[i].X, s]), nil, amcMisc, amkInf);
+ o := res[i].Y;
+ end;
+ finally
+ r.Free;
+ end;
+ end
+ else for i := 0 to high(res) do
+ begin
+ msg := Trim(lines[res[i].Y-1]);
msg := strutils.ReplaceStr(msg, fToFind, '`' + fToFind + '`');
- msgs.message(msg, nil, amcMisc, amkInf);
+ msgs.message(format(fmt, [res[i].Y, res[i].X, msg]), nil, amcMisc, amkInf);
end;
finally
search.free;