Skip to content

Commit

Permalink
+ Added "Match whole words" feature;
Browse files Browse the repository at this point in the history
* Fixed missed occurrences during case insensitive searching.
  • Loading branch information
streambot committed Sep 22, 2010
1 parent 6489bdc commit 138b5f3
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 40 deletions.
9 changes: 8 additions & 1 deletion AddinSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,13 @@ private sealed class SingletonCreator
#region Search

[Category("Search")]
[DisplayName("Case sensitive"), Description("Needs reopening of documents")]
[DisplayName("Match case"), Description("Needs reopening of documents")]
public bool CaseSensitiveSearch { get; set; }

[Category("Search")]
[DisplayName("Match whole words"), Description("Needs reopening of documents")]
public bool SearchWholeWordsOnly { get; set; }

#endregion

#region Experemental
Expand Down Expand Up @@ -95,6 +99,7 @@ public void ResetToDefaults()
FilledMarks = false;

CaseSensitiveSearch = false;
SearchWholeWordsOnly = false;
}

public void Load(SettingRepository repository)
Expand Down Expand Up @@ -124,6 +129,7 @@ public void Reload()
FilledMarks = settings.GetBoolSetting("FilledMarks", FilledMarks);

CaseSensitiveSearch = settings.GetBoolSetting("CaseSensitiveSearch", CaseSensitiveSearch);
SearchWholeWordsOnly = settings.GetBoolSetting("SearchWholeWordsOnly", SearchWholeWordsOnly);
}
}

Expand All @@ -145,6 +151,7 @@ public void Save()
settings.SetBoolSetting("FilledMarks", FilledMarks);

settings.SetBoolSetting("CaseSensitiveSearch", CaseSensitiveSearch);
settings.SetBoolSetting("SearchWholeWordsOnly", SearchWholeWordsOnly);
}
}
}
Expand Down
104 changes: 65 additions & 39 deletions Search/TextSearch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ public class TextSearch
private class SearchJob
{
public string Value { get; set; }
public int SearchStart { get; set; }
public int SearchEnd { get; set; }
public int SearchStart { get; set; }
public int SearchEnd { get; set; }
}

const int SearchDelay = 250; //ms
Expand All @@ -34,7 +34,8 @@ private class SearchJob

public event EventHandler<SearchCompletedEventArgs> SearchCompleted;

private StringComparison _comparsion;
private bool _caseSensitiveSearch;
private bool _searchWholeWordsOnly;

public TextSearch(IVsTextLines buffer)
{
Expand All @@ -49,11 +50,8 @@ public TextSearch(IVsTextLines buffer)

_asyncJobs = new Queue<SearchJob>();

_comparsion = StringComparison.InvariantCultureIgnoreCase;
if (AddinSettings.Instance.CaseSensitiveSearch)
{
_comparsion = StringComparison.InvariantCulture;
}
_caseSensitiveSearch = AddinSettings.Instance.CaseSensitiveSearch;
_searchWholeWordsOnly = AddinSettings.Instance.SearchWholeWordsOnly;
}

/// <remarks>
Expand All @@ -63,49 +61,77 @@ public TextSearch(IVsTextLines buffer)
private TextOccurences SearchOccurrencesInText(string text, string value, int searchStart, int searchEnd)
{
var positions = new TreapBuilder();

/* Preprocessing */
int valueLength = value.Length;
var badChars = new Dictionary<int, int>(valueLength);

int textLength = text.Length;
int valueLength = value.Length;
var badChars = new Dictionary<int, int>(valueLength);

for (int i = 0; i < valueLength; i++)
{
int key = value[i];
badChars[key] = valueLength - i;
char c = value[i];

if (_caseSensitiveSearch)
badChars[c] = valueLength - i;
else
{
badChars[char.ToLower(c)] = valueLength - i;
badChars[char.ToUpper(c)] = valueLength - i;
}
}

/* Searching */
searchEnd = Math.Min(searchEnd, text.Length) - (valueLength - 1);
var comparsion = (_caseSensitiveSearch ?
StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase);

searchEnd = Math.Min(searchEnd, text.Length) - (valueLength - 1);
for (int i = searchStart; i < searchEnd; )
{
if (text.Substring(i, valueLength).StartsWith(value, _comparsion))
positions.Add(i);
if (text.Substring(i, valueLength).StartsWith(value, comparsion))
{
if (!_searchWholeWordsOnly)
{
positions.Add(i);
}
else
{
if (
(i - 1 < 0 || !char.IsLetterOrDigit(text[i - 1]))
&& (i + valueLength >= textLength || !char.IsLetterOrDigit(text[i + valueLength]))
)
positions.Add(i);
}
}

if (i + valueLength >= searchEnd)
break;
if (i + valueLength >= searchEnd)
break;

int key = text[i + valueLength];
if (badChars.ContainsKey(key))
i += badChars[key];
else
i += valueLength + 1;
int key = text[i + valueLength];
if (badChars.ContainsKey(key))
i += badChars[key];
else
i += valueLength + 1;
}

return new TextOccurences(value, positions);
}

public TextOccurences SearchOccurrences(string value, int searchStart, int searchEnd)
public TextOccurences SearchOccurrences(string value, int searchStart, int searchEnd)
{
if (!string.IsNullOrEmpty(value))
{
string text = _buffer.GetText();
if (!string.IsNullOrEmpty(text))
//Disabled searching of multi line text
if (!value.Contains('\n'))
{
int length = value.Length;

if (searchEnd >= searchStart && length > 0)
string text = _buffer.GetText();
if (!string.IsNullOrEmpty(text))
{
return SearchOccurrencesInText(text, value, searchStart, searchEnd);
int length = value.Length;

if (searchEnd >= searchStart && length > 0)
{
return SearchOccurrencesInText(text, value, searchStart, searchEnd);
}
}
}
}
Expand All @@ -115,7 +141,7 @@ public TextOccurences SearchOccurrences(string value, int searchStart, int searc

#region Delayed searching

public void SearchOccurrencesDelayed(string value, int searchStart, int searchEnd)
public void SearchOccurrencesDelayed(string value, int searchStart, int searchEnd)
{
_searchTimer.Stop();

Expand All @@ -124,8 +150,8 @@ public void SearchOccurrencesDelayed(string value, int searchStart, int searchEn
lock (_delayedSearchSyncLock)
{
_delayedJob.Value = value;
_delayedJob.SearchStart = searchStart;
_delayedJob.SearchEnd = searchEnd;
_delayedJob.SearchStart = searchStart;
_delayedJob.SearchEnd = searchEnd;
}
_searchTimer.Start();
}
Expand All @@ -135,23 +161,23 @@ private void SearchTimer_Elapsed(object sender, ElapsedEventArgs e)
{
string value;
int searchStart;
int searchEnd;
int searchEnd;

lock (_delayedSearchSyncLock)
{
value = _delayedJob.Value;
searchStart = _delayedJob.SearchStart;
searchEnd = _delayedJob.SearchEnd;
searchEnd = _delayedJob.SearchEnd;
}

SearchOccurrencesAsync(value, searchStart, searchEnd);
SearchOccurrencesAsync(value, searchStart, searchEnd);
}

#endregion

#region Async searching

public void SearchOccurrencesAsync(string value, int searchStart, int searchEnd)
public void SearchOccurrencesAsync(string value, int searchStart, int searchEnd)
{
lock (_asyncJobsSyncRoot)
{
Expand Down Expand Up @@ -191,7 +217,7 @@ private void SearchThreadWorker(object stateInfo)
EventHandler<SearchCompletedEventArgs> evt = SearchCompleted;
if (evt != null)
{
evt(this, new SearchCompletedEventArgs(occurences));
evt(this, new SearchCompletedEventArgs(occurences));
}
}
}
Expand Down

0 comments on commit 138b5f3

Please sign in to comment.