Skip to content

Adds emphasis to Select-String default formatter #8963

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Oct 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ded4f05
[feature] Added Select-String -Color and made it work with -AllMatch …
Feb 23, 2019
64534b9
[feature] Added Select-String -Color and test cases
Feb 24, 2019
7b48805
[feature] Adds -Emphasize for Select-String
Feb 24, 2019
4732734
[feature] Adds red highlighting for matched text
Feb 24, 2019
f72f38e
[feature] Adds red highlighting for matched text
Feb 24, 2019
00e7224
Apply suggestions from code review
rjmholt Feb 24, 2019
ca39e17
[feature] Refactored code
Feb 24, 2019
665bd4f
[feature] Moved new functionality, changed formatter, fixed tests
Mar 9, 2019
439400d
[feature] Fixed style errors
Mar 9, 2019
92c92bc
[feature] Changed red escape sequence to negative escape sequence
May 1, 2019
6b97206
[feature] Removed surrounding asterisks if VT is unsupported
May 1, 2019
d299906
[feature] Changed MatchInfo's Emphasize to private
May 7, 2019
2065727
[feature] Cleaned up matchInfo and DoMatchWorker
derek-xia Jun 9, 2019
6f47e79
[feature] Changed ToEmphasizedString string creation
derek-xia Jun 14, 2019
1bc3437
[feature] Refactored ToEmphasizedString
derek-xia Jun 14, 2019
7623340
Update Select-String.Tests.ps1
TravisEz13 Jun 25, 2019
1d23b5c
readd curly brace
TylerLeonhardt Aug 8, 2019
f840d88
shouldEmphasize
derek-xia Aug 9, 2019
9395045
Formatting changes
derek-xia Aug 9, 2019
f9145bd
Changed Emphasize to NoEmphasis
derek-xia Aug 27, 2019
ccc09f8
add right }
TylerLeonhardt Sep 25, 2019
46e62fd
tab instead of spaces?
TylerLeonhardt Sep 25, 2019
40facf5
tabs to spaces
TylerLeonhardt Sep 30, 2019
52a9c0f
address steve's comments
TylerLeonhardt Oct 1, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,43 @@ public class MatchInfo
/// <value>The text of the matching line.</value>
public string Line { get; set; } = string.Empty;

/// <summary>
/// Gets or sets a value indicating whether the matched portion of the string is highlighted.
/// </summary>
/// <value>Whether the matched portion of the string is highlighted with the negative VT sequence.</value>
private readonly bool _emphasize;

/// <summary>
/// Stores the starting index of each match within the line.
/// </summary>
private readonly IReadOnlyList<int> _matchIndexes;

/// <summary>
/// Stores the length of each match within the line.
/// </summary>
private readonly IReadOnlyList<int> _matchLengths;

/// <summary>
/// Initializes a new instance of the <see cref="MatchInfo"/> class with emphasis disabled.
/// </summary>
public MatchInfo()
{
this._emphasize = false;
}

/// <summary>
/// Initializes a new instance of the <see cref="MatchInfo"/> class with emphasized matched text.
/// Used when virtual terminal sequences are supported.
/// </summary>
/// <param name="matchIndexes">Sets the matchIndexes.</param>
/// <param name="matchLengths">Sets the matchLengths.</param>
public MatchInfo(IReadOnlyList<int> matchIndexes, IReadOnlyList<int> matchLengths)
{
this._emphasize = true;
this._matchIndexes = matchIndexes;
this._matchLengths = matchLengths;
}

/// <summary>
/// Gets the base name of the file containing the matching line.
/// <remarks>
Expand Down Expand Up @@ -214,14 +251,27 @@ public override string ToString()
/// <param name="directory">Directory to use as the root when calculating the relative path.</param>
/// <returns>The string representation of the match object.</returns>
public string ToString(string directory)
{
return ToString(directory, Line);
}

/// <summary>
/// Returns the string representation of the match object with the matched line passed
/// in as <paramref name="line"/> and trims the path to be relative to
/// the<paramref name="directory"/> argument.
/// </summary>
/// <param name="directory">Directory to use as the root when calculating the relative path.</param>
/// <param name="line">Line that the match occurs in.</param>
/// <returns>The string representation of the match object.</returns>
private string ToString(string directory, string line)
{
string displayPath = (directory != null) ? RelativePath(directory) : _path;

// Just return a single line if the user didn't
// enable context-tracking.
if (Context == null)
{
return FormatLine(Line, this.LineNumber, displayPath, EmptyPrefix);
return FormatLine(line, this.LineNumber, displayPath, EmptyPrefix);
}

// Otherwise, render the full context.
Expand All @@ -233,7 +283,7 @@ public string ToString(string directory)
lines.Add(FormatLine(contextLine, displayLineNumber++, displayPath, ContextPrefix));
}

lines.Add(FormatLine(Line, displayLineNumber++, displayPath, MatchPrefix));
lines.Add(FormatLine(line, displayLineNumber++, displayPath, MatchPrefix));

foreach (string contextLine in Context.DisplayPostContext)
{
Expand All @@ -243,6 +293,61 @@ public string ToString(string directory)
return string.Join(System.Environment.NewLine, lines.ToArray());
}

/// <summary>
/// Returns the string representation of the match object same format as ToString()
/// and inverts the color of the matched text if virtual terminal is supported.
/// </summary>
/// <param name="directory">Directory to use as the root when calculating the relative path.</param>
/// <returns>The string representation of the match object with matched text inverted.</returns>
public string ToEmphasizedString(string directory)
{
if (!_emphasize)
{
return ToString(directory);
}

return ToString(directory, EmphasizeLine());
}

/// <summary>
/// Surrounds the matched text with virtual terminal sequences to invert it's color. Used in ToEmphasizedString.
/// </summary>
/// <returns>The matched line with matched text inverted.</returns>
private string EmphasizeLine()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good candidate to be static.

Copy link
Member

@TylerLeonhardt TylerLeonhardt Oct 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it uses _matchIndexes? Or do you mean refactor it to be static that takes in _matchIndexes and _matchLengths

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can pass _matchIndexes by parameter.

Copy link
Collaborator

@rjmholt rjmholt Oct 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. Just like a whole bunch of other PowerShell code that is similarly caught up by mutated object state implicitly passed in to methods.

But I believe that pre-existed here and this contribution shouldn't be held back on the basis of code debt incurred before PowerShell was open-sourced. This PR has been open long enough and has been a good, responsive, constrained contribution and I think we really need to just accept or reject it, rather than turning it into a Ship of Theseus.

Copy link
Collaborator

@vexx32 vexx32 Oct 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think this one's gone on long enough and is a definite nice-to-have in PSv7 😁

We can always make other smaller changes later. 🙂

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR is delayed because it is in new area for PowerShell. However, the code should be clean.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this isn't a public API, we can always refactor internal code. I would suggest a separate PR if it's a concern or @iSazonov you can always add a commit to this PR if you feel strongly about this one.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I can :-) Do you ok that we have over 70 opened PR? :-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iSazonov I'll ask the team to start driving down the number of open PRs

{
const string InvertColorsVT100 = "\u001b[7m";
const string ResetVT100 = "\u001b[0m";

char[] chars = new char[(_matchIndexes.Count * (InvertColorsVT100.Length + ResetVT100.Length)) + Line.Length];
int lineIndex = 0;
int charsIndex = 0;
for (int i = 0; i < _matchIndexes.Count; i++)
{
// Adds characters before match
Line.CopyTo(lineIndex, chars, charsIndex, _matchIndexes[i] - lineIndex);
charsIndex += _matchIndexes[i] - lineIndex;
lineIndex = _matchIndexes[i];

// Adds opening vt sequence
InvertColorsVT100.CopyTo(0, chars, charsIndex, InvertColorsVT100.Length);
charsIndex += InvertColorsVT100.Length;

// Adds characters being emphasized
Line.CopyTo(lineIndex, chars, charsIndex, _matchLengths[i]);
lineIndex += _matchLengths[i];
charsIndex += _matchLengths[i];

// Adds closing vt sequence
ResetVT100.CopyTo(0, chars, charsIndex, ResetVT100.Length);
charsIndex += ResetVT100.Length;
}

// Adds remaining characters in line
Line.CopyTo(lineIndex, chars, charsIndex, Line.Length - lineIndex);

return new string(chars);
}

/// <summary>
/// Formats a line for use in ToString.
/// </summary>
Expand Down Expand Up @@ -1062,6 +1167,12 @@ public string[] LiteralPath
[Parameter]
public SwitchParameter List { get; set; }

/// <summary>
/// Gets or sets a value indicating if highlighting should be disabled.
/// </summary>
[Parameter]
public SwitchParameter NoEmphasis { get; set; }

/// <summary>
/// Gets or sets files to include. Files matching
/// one of these (if specified) are included.
Expand Down Expand Up @@ -1541,6 +1652,20 @@ private bool DoMatchWorker(string operandString, MatchInfo matchInfo, out MatchI
int patternIndex = 0;
matchResult = null;

List<int> indexes = null;
List<int> lengths = null;

bool shouldEmphasize = !NoEmphasis && Host.UI.SupportsVirtualTerminal;

// If Emphasize is set and VT is supported,
// the lengths and starting indexes of regex matches
// need to be passed in to the matchInfo object.
if (shouldEmphasize)
{
indexes = new List<int>();
lengths = new List<int>();
}

if (!SimpleMatch)
{
while (patternIndex < Pattern.Length)
Expand All @@ -1557,6 +1682,16 @@ private bool DoMatchWorker(string operandString, MatchInfo matchInfo, out MatchI
{
matches = new Match[mc.Count];
((ICollection)mc).CopyTo(matches, 0);

if (shouldEmphasize)
{
foreach (Match match in matches)
{
indexes.Add(match.Index);
lengths.Add(match.Length);
}
}

gotMatch = true;
}
}
Expand All @@ -1567,6 +1702,12 @@ private bool DoMatchWorker(string operandString, MatchInfo matchInfo, out MatchI

if (match.Success)
{
if (shouldEmphasize)
{
indexes.Add(match.Index);
lengths.Add(match.Length);
}

matches = new Match[] { match };
}
}
Expand All @@ -1587,8 +1728,15 @@ private bool DoMatchWorker(string operandString, MatchInfo matchInfo, out MatchI
{
string pat = Pattern[patternIndex];

if (operandString.IndexOf(pat, compareOption) >= 0)
int index = operandString.IndexOf(pat, compareOption);
if (index >= 0)
{
if (shouldEmphasize)
{
indexes.Add(index);
lengths.Add(pat.Length);
}

gotMatch = true;
break;
}
Expand Down Expand Up @@ -1637,12 +1785,12 @@ private bool DoMatchWorker(string operandString, MatchInfo matchInfo, out MatchI
}

// otherwise construct and populate a new MatchInfo object
matchResult = new MatchInfo
{
IgnoreCase = !CaseSensitive,
Line = operandString,
Pattern = Pattern[patternIndex]
};
matchResult = shouldEmphasize
? new MatchInfo(indexes, lengths)
: new MatchInfo();
matchResult.IgnoreCase = !CaseSensitive;
matchResult.Line = operandString;
matchResult.Pattern = Pattern[patternIndex];

if (_preContext > 0 || _postContext > 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ private static IEnumerable<FormatViewDefinition> ViewsOf_Microsoft_PowerShell_Co
yield return new FormatViewDefinition("MatchInfo",
CustomControl.Create()
.StartEntry()
.AddScriptBlockExpressionBinding(@"$_.ToString(((get-location).path))")
.AddScriptBlockExpressionBinding(@"$_.ToEmphasizedString(((get-location).path))")
.EndEntry()
.EndControl());
}
Expand Down
Loading