Skip to content

Commit

Permalink
Allow to draw the current line number in different brush
Browse files Browse the repository at this point in the history
  • Loading branch information
nosami committed Mar 11, 2024
1 parent 8067489 commit 1f60cda
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 31 deletions.
30 changes: 30 additions & 0 deletions Src/VimApp/Implementation/SelectedLineNumberFormatDefinition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.ComponentModel.Composition;
using System.Windows.Media;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Utilities;

namespace VimApp.Implementation
{
// VimApp does not have a Selected Line Number FormatDefinition
// so we add it here
[Export(typeof(EditorFormatDefinition))]
[ClassificationType(ClassificationTypeNames = Name)]
[Name(Name)]
internal class SelectedLineNumberFormatDefinition : ClassificationFormatDefinition
{
internal const string Name = "Selected Line Number";

internal SelectedLineNumberFormatDefinition()
{
DisplayName = Name;
ForegroundColor = Colors.Red;
}
}

internal sealed class SelectedLineNumberClassificationType
{
[Name(SelectedLineNumberFormatDefinition.Name)]
[Export]
internal ClassificationTypeDefinition SelectedLineNumberTypeDefinition { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Microsoft.VisualStudio.Text.Editor;
using System.Windows.Media;

// Disambiguate WPF TextLine with Vim.TextLine
Expand All @@ -9,7 +10,7 @@ internal interface ILineFormatTracker
{
Brush Background { get; }

WpfTextLine MakeTextLine(int number);
WpfTextLine MakeTextLine(int number, bool isCurrentLineNumber);

double NumberWidth { get; }

Expand Down
15 changes: 15 additions & 0 deletions Src/VimWpf/Implementation/RelativeLineNumbers/Line.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,20 @@ public Line(int number, double verticalBaseline, bool isCaretLine)
Baseline = verticalBaseline;
IsCaretLine = isCaretLine;
}

public override bool Equals(object obj)
{
return obj is Line line &&
Number == line.Number &&
IsCaretLine == line.IsCaretLine;
}

public override int GetHashCode()
{
int hashCode = 17;
hashCode = hashCode * 23 + Number.GetHashCode();
hashCode = hashCode * 23 + IsCaretLine.GetHashCode();
return hashCode;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ internal sealed class LineNumberDrawer
private readonly ILineFormatTracker _formatTracker;
private readonly LineNumberVisualStore _store;

internal LineNumberDrawer(Canvas canvas, ILineFormatTracker formatTracker)
internal LineNumberDrawer(Canvas canvas, ILineFormatTracker formatTracker, bool isRelative)
{
_canvas = canvas
?? throw new ArgumentNullException(nameof(canvas));

_formatTracker = formatTracker
?? throw new ArgumentNullException(nameof(formatTracker));

_store = new LineNumberVisualStore(formatTracker);
_store = new LineNumberVisualStore(formatTracker, isRelative);
}

public void UpdateLines(IEnumerable<Line> lines)
Expand All @@ -30,12 +30,12 @@ public void UpdateLines(IEnumerable<Line> lines)
_canvas.Children.Clear();

double width = _canvas.Width;
foreach (var numberTargets in lines.GroupBy(x => x.Number))
{
var visual = _store[numberTargets.Key];

visual.ReplaceRenderTargets(numberTargets, width);

// Group by line number & caret line
foreach (var line in lines.GroupBy(x => x))
{
var visual = _store[line.Key];
visual.ReplaceRenderTargets(line, width);
_canvas.Children.Add(visual);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,22 @@ namespace Vim.UI.Wpf.Implementation.RelativeLineNumbers
internal sealed class LineNumberFormatTracker : ILineFormatTracker
{
private readonly IFormattedLineSource _formattedLineSource;
private readonly IWpfTextView _textView;
private readonly IClassificationFormatMap _classificationFormatMap;
private readonly IClassificationTypeRegistryService _classificationTypeRegistry;
private TextFormattingRunProperties _formatting;
private TextFormattingRunProperties _selectedLineNumberFormatting;
private TextFormatter _textFormatter;
private bool _formatChanged;
public Brush Background { get; private set; }

public double NumberWidth { get; private set; }

public LineNumberFormatTracker(
IWpfTextView textView,
IClassificationFormatMap classificationFormatMap,
IClassificationTypeRegistryService classificationTypeRegistry)
{
textView = textView
_textView = textView
?? throw new ArgumentNullException(nameof(textView));

_classificationFormatMap = classificationFormatMap
Expand All @@ -56,14 +57,15 @@ public bool TryClearReformatRequest()
return false;
}

public WpfTextLine MakeTextLine(int lineNumber)
public WpfTextLine MakeTextLine(int lineNumber, bool isCurrentLineNumber)
{
// Use '~' for the phantom line, otherwise the line number.
string text = lineNumber == -1 ? "~" :
lineNumber.ToString(CultureInfo.CurrentUICulture.NumberFormat);

var textSource = new LineNumberTextSource(text, _formatting);
var format = new TextFormattingParagraphProperties(_formatting);
var formatting = isCurrentLineNumber ? _selectedLineNumberFormatting : _formatting;
var textSource = new LineNumberTextSource(text, formatting);
var format = new TextFormattingParagraphProperties(formatting);

return _textFormatter.FormatLine(textSource, 0, 0, format, null);
}
Expand All @@ -73,13 +75,21 @@ private void UpdateFormat()
var lineNumberType = _classificationTypeRegistry.GetClassificationType("line number");
_formatting = _classificationFormatMap.GetTextProperties(lineNumberType);

var selectedLineNumberType = _classificationTypeRegistry.GetClassificationType("Selected Line Number");
_selectedLineNumberFormatting =
selectedLineNumberType == null ?
_formatting :
_classificationFormatMap.GetTextProperties(selectedLineNumberType);

Background = _formatting.BackgroundBrush;

_textFormatter = _formattedLineSource.UseDisplayMode
? TextFormatter.Create(TextFormattingMode.Display)
: TextFormatter.Create(TextFormattingMode.Ideal);

NumberWidth = Enumerable.Range(0, 10).Max(x => MakeTextLine(x).Width);
int currentLineNumber = _textView.Caret.Position.BufferPosition.GetContainingLine().LineNumber + 1;

NumberWidth = Enumerable.Range(0, 10).Max(x => MakeTextLine(x, x == currentLineNumber).Width);

_formatChanged = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ namespace Vim.UI.Wpf.Implementation.RelativeLineNumbers
internal class LineNumberVisual : UIElement
{
private readonly WpfTextLine _textLine;

private readonly bool _isRelative;
private readonly List<Point> _renderTargets;

internal LineNumberVisual(WpfTextLine textLine)
internal LineNumberVisual(WpfTextLine textLine, bool isRelative)
{
_textLine = textLine
?? throw new ArgumentNullException(nameof(textLine));

_isRelative = isRelative;
_renderTargets = new List<Point>();

IsHitTestVisible = false;
Expand Down Expand Up @@ -49,7 +49,7 @@ private void AddRenderTarget(Line line, double width)
{
var verticalOffset = line.Baseline - _textLine.TextBaseline;

var horizontalOffset = line.IsCaretLine
var horizontalOffset = line.IsCaretLine || !_isRelative
? 0
: width - _textLine.Width;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,31 @@ namespace Vim.UI.Wpf.Implementation.RelativeLineNumbers
{
internal sealed class LineNumberVisualStore
{
private readonly Dictionary<int, LineNumberVisual> _cache;
private readonly Dictionary<Line, LineNumberVisual> _cache;

private readonly ILineFormatTracker _formatTracker;
private readonly bool _isRelative;

internal LineNumberVisualStore(ILineFormatTracker formatTracker)
internal LineNumberVisualStore(ILineFormatTracker formatTracker, bool isRelative)
{
_formatTracker = formatTracker
?? throw new ArgumentNullException(nameof(formatTracker));

_cache = new Dictionary<int, LineNumberVisual>();
_isRelative = isRelative;
_cache = new Dictionary<Line, LineNumberVisual>();
}

public LineNumberVisual this[int lineNumber]
public LineNumberVisual this[Line line]
{
get
{
if (_cache.TryGetValue(lineNumber, out var visual))
if (_cache.TryGetValue(line, out var visual))
{
return visual;
}

var line = _formatTracker.MakeTextLine(lineNumber);
visual = new LineNumberVisual(line);
_cache[lineNumber] = visual;
var textLine = _formatTracker.MakeTextLine(line.Number, line.IsCaretLine);
visual = new LineNumberVisual(textLine, _isRelative);
_cache[line] = visual;

return visual;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ private Line MakeLine(ITextViewLine wpfLine, int distanceToCaret, bool hasValidC

bool isCaretLine = hasValidCaret && distanceToCaret == 0;

bool caretLineStyle = isCaretLine && _localSettings.RelativeNumber;
bool caretLineStyle = isCaretLine;
return new Line(numberToDisplay, verticalBaseline, caretLineStyle);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ internal sealed class RelativeLineNumbersMargin : VerticalCanvasMargin
private readonly IProtectedOperations _protectedOperations;

private readonly LineNumbersTracker _linesTracker;
private readonly LineNumberDrawer _lineNumberDrawer;
private readonly LineNumbersCalculator _lineNumbersCalculator;

private LineNumberDrawer _lineNumberDrawer;
private double _width = double.NaN;
private double _minWidth = 0.0;
private double _maxWidth = double.PositiveInfinity;
Expand Down Expand Up @@ -56,7 +56,7 @@ internal sealed class RelativeLineNumbersMargin : VerticalCanvasMargin

_lineNumbersCalculator = new LineNumbersCalculator(_textView, _localSettings);

_lineNumberDrawer = new LineNumberDrawer(Canvas, _formatTracker);
_lineNumberDrawer = new LineNumberDrawer(Canvas, _formatTracker, _localSettings.RelativeNumber);

_linesTracker = new LineNumbersTracker(_textView);

Expand Down Expand Up @@ -112,7 +112,11 @@ private void UpdateVimNumberSettings(SettingEventArgs eventArgs)
SetVisualStudioMarginVisibility(Visibility.Hidden);
if (_localSettings.Number || _localSettings.RelativeNumber)
{
RedrawLines();
if (eventArgs.Setting.Name == "relativenumber" || eventArgs.Setting.Name == "number")
{
_lineNumberDrawer = new LineNumberDrawer(Canvas, _formatTracker, _localSettings.RelativeNumber);
RedrawLines();
}
}
}

Expand Down

0 comments on commit 1f60cda

Please sign in to comment.