Skip to content

Commit

Permalink
Perf and other improvement to the NavBar
Browse files Browse the repository at this point in the history
  • Loading branch information
madskristensen committed Jan 8, 2022
1 parent 9675153 commit 29df68d
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -1,86 +1,89 @@
using System.Collections;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Markdig.Syntax;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.Package;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Threading;

namespace MarkdownEditor2022
{
internal class MarkdownHeaderDropdownBars : TypeAndMemberDropdownBars, IDisposable
internal class DropdownBars : TypeAndMemberDropdownBars, IDisposable
{
private bool _disposed;

private readonly LanguageService _languageService;
private readonly IWpfTextView _textView;
private readonly Document _document;
private bool _disposed;
private bool _bufferHasChanged;

public MarkdownHeaderDropdownBars(IVsTextView textView, LanguageService languageService)
public DropdownBars(IVsTextView textView, LanguageService languageService)
: base(languageService)
{
_languageService = languageService;

IComponentModel compModel = (IComponentModel)languageService.GetService(typeof(SComponentModel));
IVsEditorAdaptersFactoryService adapter = compModel.GetService<IVsEditorAdaptersFactoryService>();
IVsEditorAdaptersFactoryService adapter = VS.GetMefService<IVsEditorAdaptersFactoryService>();

_textView = adapter.GetWpfTextView(textView);
_textView.Caret.PositionChanged += CaretPositionChanged;

_document = _textView.TextBuffer.GetDocument();
_document.Parsed += OnDocumentParsed;

ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
{
await TaskScheduler.Default;
OnDocumentParsed(_document);
}).FireAndForget();
SynchronizeDropdowns();
}

private void CaretPositionChanged(object sender, CaretPositionChangedEventArgs e)
private void CaretPositionChanged(object sender, CaretPositionChangedEventArgs e) => SynchronizeDropdowns();
private void OnDocumentParsed(Document document)
{
_bufferHasChanged = true;
SynchronizeDropdowns();
}

private void SynchronizeDropdowns()
{
ThreadHelper.JoinableTaskFactory.StartOnIdle(
() => _languageService.SynchronizeDropdowns(),
VsTaskRunContext.UIThreadIdlePriority).FireAndForget();
}

private void OnDocumentParsed(Document document)
{
ThreadHelper.ThrowIfOnUIThread();

if (document.IsParsing)
if (_document.IsParsing)
{
// Abort and wait for the next parse event to finish
return;
}

SynchronizeDropdowns();
ThreadHelper.JoinableTaskFactory.StartOnIdle(() =>
{
if (!_document.IsParsing)
{
_languageService.SynchronizeDropdowns();
}
}, VsTaskRunContext.UIThreadBackgroundPriority).FireAndForget();
}

public override bool OnSynchronizeDropdowns(LanguageService languageService, IVsTextView textView, int line, int col, ArrayList dropDownTypes, ArrayList dropDownMembers, ref int selectedType, ref int selectedMember)
{
dropDownTypes.Clear();
if (_bufferHasChanged || dropDownMembers.Count == 0)
{
dropDownMembers.Clear();

_document.Markdown.Descendants<HeadingBlock>()
.Select(headingBlock => CreateDropDownMember(headingBlock, textView))
.ToList()
.ForEach(ddm => dropDownTypes.Add(ddm));
_document.Markdown.Descendants<HeadingBlock>()
.Select(headingBlock => CreateDropDownMember(headingBlock, textView))
.ToList()
.ForEach(ddm => dropDownMembers.Add(ddm));
}

textView.GetCaretPos(out int caretLine, out int caretColumn);
if (dropDownTypes.Count == 0)
{
string thisExt = $"{Vsix.Name} ({Vsix.Version})";
string markdig = Path.GetFileName($"Powered by Markdig ({Markdig.Markdown.Version})");
dropDownTypes.Add(new DropDownMember(thisExt, new TextSpan(), 126, DROPDOWNFONTATTR.FONTATTR_GRAY));
dropDownTypes.Add(new DropDownMember(markdig, new TextSpan(), 126, DROPDOWNFONTATTR.FONTATTR_GRAY));
}

DropDownMember currentDropDown = dropDownTypes
DropDownMember currentDropDown = dropDownMembers
.OfType<DropDownMember>()
.Where(d => d.Span.iStartLine <= caretLine)
.Where(d => d.Span.iStartLine <= line)
.LastOrDefault();
selectedType = dropDownTypes.IndexOf(currentDropDown);

selectedMember = dropDownMembers.IndexOf(currentDropDown);
selectedType = 0;
_bufferHasChanged = false;

return true;
}
Expand All @@ -90,9 +93,11 @@ private static DropDownMember CreateDropDownMember(HeadingBlock headingBlock, IV
TextSpan textSpan = GetTextSpan(headingBlock, textView);
textView.GetTextStream(textSpan.iStartLine, textSpan.iStartIndex, textSpan.iEndLine, textSpan.iEndIndex, out string headingText);

headingText = ProcessHeadingText(headingText ?? String.Empty, headingBlock.Level, headingBlock.HeaderChar);
headingText = ProcessHeadingText(headingText ?? string.Empty, headingBlock.Level, headingBlock.HeaderChar);

return new DropDownMember(headingText, textSpan, 0, headingBlock.Level == 1 ? DROPDOWNFONTATTR.FONTATTR_BOLD : DROPDOWNFONTATTR.FONTATTR_PLAIN);
DROPDOWNFONTATTR fontAttr = headingBlock.Level == 1 ? DROPDOWNFONTATTR.FONTATTR_BOLD : DROPDOWNFONTATTR.FONTATTR_PLAIN;

return new DropDownMember(headingText, textSpan, 126, fontAttr);
}

private static TextSpan GetTextSpan(HeadingBlock headingBlock, IVsTextView textView)
Expand All @@ -113,18 +118,22 @@ private static TextSpan GetTextSpan(HeadingBlock headingBlock, IVsTextView textV
/// </summary>
private static string ProcessHeadingText(string text, int level, char headingChar)
{
string headingDeclaration = new string(headingChar, level);
string headingDeclaration = new(headingChar, level);

if (text.StartsWith(headingDeclaration))
{
text = text.Substring(headingDeclaration.Length);
}

return new string(' ', (2 * level) + 1) + text.Trim();
return new string(' ', (3 * level) + 1).Substring(4) + text.Trim();
}

public void Dispose()
{
if (_disposed) return;
if (_disposed)
{
return;
}

_disposed = true;
_textView.Caret.PositionChanged -= CaretPositionChanged;
Expand Down
11 changes: 7 additions & 4 deletions src/Language/MarkdownEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace MarkdownEditor2022
internal sealed class MarkdownEditor : LanguageBase
{
private bool _disposed = false;
private MarkdownHeaderDropdownBars? _dropdownBars;
private DropdownBars _dropdownBars;

public MarkdownEditor(object site) : base(site)
{
Expand Down Expand Up @@ -47,15 +47,18 @@ public override void SetDefaultPreferences(LanguagePreferences preferences)
public override TypeAndMemberDropdownBars CreateDropDownHelper(IVsTextView textView)
{
_dropdownBars?.Dispose();
_dropdownBars = new MarkdownHeaderDropdownBars(textView, this);
_dropdownBars = new DropdownBars(textView, this);

return _dropdownBars;
}

public override void Dispose()
{
if (_disposed) return;

if (_disposed)
{
return;
}

_disposed = true;
_dropdownBars?.Dispose();
_dropdownBars = null;
Expand Down
2 changes: 1 addition & 1 deletion src/MarkdownEditor2022.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
<Compile Include="Language\EditorFeatures.cs" />
<Compile Include="Language\MarkdownEditor.cs" />
<Compile Include="Language\MarkdownClassificationTypes.cs" />
<Compile Include="Language\MarkdownHeaderDropdownBars.cs" />
<Compile Include="Language\DropdownBars.cs" />
<Compile Include="Language\TokenTagger.cs" />
<Compile Include="Margin\Browser.cs" />
<Compile Include="Margin\BrowserMargin.cs" />
Expand Down

0 comments on commit 29df68d

Please sign in to comment.