diff --git a/Editor.Tests/Commands/SmartIndentTests.cs b/Editor.Tests/Commands/SmartIndentTests.cs index 13ce1f8..a947279 100644 --- a/Editor.Tests/Commands/SmartIndentTests.cs +++ b/Editor.Tests/Commands/SmartIndentTests.cs @@ -8,6 +8,7 @@ using MonoDevelop.Xml.Editor.Parsing; using MonoDevelop.Xml.Editor.SmartIndent; +using MonoDevelop.Xml.Tests; using NUnit.Framework; @@ -41,47 +42,13 @@ public void TestSmartIndent (string doc, int expectedIndent) var line = textView.TextBuffer.CurrentSnapshot.GetLineFromPosition (caretPos); GetParser (textView.TextBuffer); - var options = new TestEditorOptions (); - options.SetOptionValue (DefaultOptions.ConvertTabsToSpacesOptionId, true); - options.SetOptionValue (DefaultOptions.IndentSizeOptionId, 4); - options.SetOptionValue (DefaultOptions.TabSizeOptionId, 4); + textView.Options.SetOptionValue (DefaultOptions.ConvertTabsToSpacesOptionId, true); + textView.Options.SetOptionValue (DefaultOptions.IndentSizeOptionId, 4); + textView.Options.SetOptionValue (DefaultOptions.TabSizeOptionId, 4); - var smartIndent = new XmlSmartIndent (textView, Catalog.GetService (), options); + var smartIndent = new XmlSmartIndent (textView, Catalog.GetService (), TestLoggerFactory.CreateTestMethodLogger ()); var indent = smartIndent.GetDesiredIndentation (line); Assert.AreEqual (expectedIndent, indent); } } - - class TestEditorOptions : IEditorOptions - { - Dictionary storage = new Dictionary (); - - public IEnumerable SupportedOptions => throw new NotImplementedException (); - - public IEditorOptions GlobalOptions => throw new NotImplementedException (); - - public IEditorOptions Parent { get => throw new NotImplementedException (); set => throw new NotImplementedException (); } - - #pragma warning disable 67 - public event EventHandler OptionChanged; - #pragma warning restore 67 - - public bool ClearOptionValue (string optionId) => throw new NotImplementedException (); - - public bool ClearOptionValue (EditorOptionKey key) => throw new NotImplementedException (); - - public T GetOptionValue (string optionId) => (T)storage[optionId]; - - public T GetOptionValue (EditorOptionKey key) => (T)storage[key.Name]; - - public object GetOptionValue (string optionId) => storage[optionId]; - - public bool IsOptionDefined (string optionId, bool localScopeOnly) => throw new NotImplementedException (); - - public bool IsOptionDefined (EditorOptionKey key, bool localScopeOnly) => throw new NotImplementedException (); - - public void SetOptionValue (string optionId, object value) => storage[optionId] = value; - - public void SetOptionValue (EditorOptionKey key, T value) => storage[key.Name] = value; - } } \ No newline at end of file diff --git a/Editor/BraceCompletion/XmlBraceCompletionCommandHandler.cs b/Editor/BraceCompletion/XmlBraceCompletionCommandHandler.cs index 60a0d68..6881f15 100644 --- a/Editor/BraceCompletion/XmlBraceCompletionCommandHandler.cs +++ b/Editor/BraceCompletion/XmlBraceCompletionCommandHandler.cs @@ -14,7 +14,9 @@ using Microsoft.VisualStudio.Utilities; using MonoDevelop.Xml.Dom; +using MonoDevelop.Xml.Editor.Logging; using MonoDevelop.Xml.Editor.Parsing; +using MonoDevelop.Xml.Logging; using MonoDevelop.Xml.Parser; using BF = System.Reflection.BindingFlags; @@ -48,19 +50,28 @@ class XmlBraceCompletionCommandHandler : IChainedCommandHandler Name; public CommandState GetCommandState (TypeCharCommandArgs args, Func nextCommandHandler) => nextCommandHandler (); public void ExecuteCommand (TypeCharCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext) - => ExecuteCommandInternal (args, nextCommandHandler, executionContext); + { + try { + ExecuteCommandInternal (args, nextCommandHandler, executionContext); + } catch (Exception ex) { + loggerFactory.GetLogger (args.TextView).LogInternalException (ex); + } + } void ExecuteCommandInternal (TypeCharCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext) { diff --git a/Editor/Commands/AutoClosingTagCommandHandler.cs b/Editor/Commands/AutoClosingTagCommandHandler.cs index 34a0922..9f433e4 100644 --- a/Editor/Commands/AutoClosingTagCommandHandler.cs +++ b/Editor/Commands/AutoClosingTagCommandHandler.cs @@ -6,6 +6,7 @@ using System; using System.ComponentModel.Composition; +using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data; @@ -15,8 +16,10 @@ using Microsoft.VisualStudio.Utilities; using MonoDevelop.Xml.Dom; +using MonoDevelop.Xml.Editor.Logging; using MonoDevelop.Xml.Editor.Options; using MonoDevelop.Xml.Editor.Parsing; +using MonoDevelop.Xml.Logging; namespace MonoDevelop.Xml.Editor.Commands { @@ -30,13 +33,15 @@ class AutoClosingTagCommandHandler : IChainedCommandHandler const string Name = "Closing Tag Completion"; [ImportingConstructor] - public AutoClosingTagCommandHandler (XmlParserProvider parserProvider, IAsyncCompletionBroker completionBroker) + public AutoClosingTagCommandHandler (XmlParserProvider parserProvider, IAsyncCompletionBroker completionBroker, IEditorLoggerFactory loggerFactory) { this.parserProvider = parserProvider; this.completionBroker = completionBroker; + this.loggerFactory = loggerFactory; } readonly IAsyncCompletionBroker completionBroker; + readonly IEditorLoggerFactory loggerFactory; readonly XmlParserProvider parserProvider; public string DisplayName => Name; @@ -54,7 +59,11 @@ public void ExecuteCommand (TypeCharCommandArgs args, Action nextCommandHandler, nextCommandHandler (); if (args.TypedChar == '>' && args.TextView.Options.GetAutoInsertClosingTag ()) { - InsertCloseTag (args, executionContext); + try { + InsertCloseTag (args, executionContext); + } catch (Exception ex) { + loggerFactory.GetLogger (args.TextView).LogInternalException (ex); + } } } diff --git a/Editor/Commands/CommentUncommentCommandHandler.cs b/Editor/Commands/CommentUncommentCommandHandler.cs index 2d358eb..792ac99 100644 --- a/Editor/Commands/CommentUncommentCommandHandler.cs +++ b/Editor/Commands/CommentUncommentCommandHandler.cs @@ -18,7 +18,9 @@ using MonoDevelop.Xml.Dom; using MonoDevelop.Xml.Editor.Completion; +using MonoDevelop.Xml.Editor.Logging; using MonoDevelop.Xml.Editor.Parsing; +using MonoDevelop.Xml.Logging; using MonoDevelop.Xml.Parser; using JoinableTaskContext = Microsoft.VisualStudio.Threading.JoinableTaskContext; @@ -42,17 +44,20 @@ class CommentUncommentCommandHandler : [ImportingConstructor] public CommentUncommentCommandHandler ( XmlParserProvider parserProvider, + IEditorLoggerFactory loggerFactory, ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService, JoinableTaskContext joinableTaskContext) { this.parserProvider = parserProvider; + this.loggerFactory = loggerFactory; this.undoHistoryRegistry = undoHistoryRegistry; this.editorOperationsFactoryService = editorOperationsFactoryService; this.joinableTaskContext = joinableTaskContext; } readonly XmlParserProvider parserProvider; + readonly IEditorLoggerFactory loggerFactory; readonly ITextUndoHistoryRegistry undoHistoryRegistry; readonly IEditorOperationsFactoryService editorOperationsFactoryService; readonly JoinableTaskContext joinableTaskContext; @@ -87,6 +92,16 @@ public bool ExecuteCommand (ToggleLineCommentCommandArgs args, CommandExecutionC => ExecuteCommandCore (args, executionContext, Operation.Toggle); bool ExecuteCommandCore (EditorCommandArgs args, CommandExecutionContext context, Operation operation) + { + try { + return ExecuteCommandCoreInternal (args, context, operation); + } catch (Exception ex) { + loggerFactory.GetLogger (args.TextView).LogInternalException (ex); + throw; + } + } + + bool ExecuteCommandCoreInternal (EditorCommandArgs args, CommandExecutionContext context, Operation operation) { ITextView textView = args.TextView; ITextBuffer textBuffer = args.SubjectBuffer; diff --git a/Editor/Commands/NavigateToHighlightReferenceCommandHandler.cs b/Editor/Commands/NavigateToHighlightReferenceCommandHandler.cs index 6a5d2c4..de1bdc2 100644 --- a/Editor/Commands/NavigateToHighlightReferenceCommandHandler.cs +++ b/Editor/Commands/NavigateToHighlightReferenceCommandHandler.cs @@ -16,61 +16,70 @@ using Microsoft.VisualStudio.Text.Outlining; using Microsoft.VisualStudio.Text.Tagging; using Microsoft.VisualStudio.Utilities; + +using MonoDevelop.Xml.Logging; using MonoDevelop.Xml.Editor.Tagging; -using VSCommanding = Microsoft.VisualStudio.Commanding; +using MonoDevelop.Xml.Editor.Logging; namespace MonoDevelop.Xml.Editor.Commands { - [Export (typeof (VSCommanding.ICommandHandler))] + [Export (typeof (ICommandHandler))] [ContentType (XmlContentTypeNames.XmlCore)] [Name ("Xml Navigate to Highlighted Reference Command Handler")] internal partial class NavigateToHighlightReferenceCommandHandler : - VSCommanding.ICommandHandler, - VSCommanding.ICommandHandler + ICommandHandler, + ICommandHandler { - private readonly IOutliningManagerService _outliningManagerService; - private readonly IViewTagAggregatorFactoryService _tagAggregatorFactory; + readonly IEditorLoggerFactory loggerFactory; + readonly IOutliningManagerService _outliningManagerService; + readonly IViewTagAggregatorFactoryService _tagAggregatorFactory; public string DisplayName => "Navigate To Highlighted Reference"; + // log + [ImportingConstructor] public NavigateToHighlightReferenceCommandHandler ( + IEditorLoggerFactory loggerFactory, IOutliningManagerService outliningManagerService, IViewTagAggregatorFactoryService tagAggregatorFactory) { _outliningManagerService = outliningManagerService ?? throw new ArgumentNullException (nameof (outliningManagerService)); _tagAggregatorFactory = tagAggregatorFactory ?? throw new ArgumentNullException (nameof (tagAggregatorFactory)); + this.loggerFactory = loggerFactory; } - public CommandState GetCommandState (NavigateToNextHighlightedReferenceCommandArgs args) - { - return GetCommandStateImpl (args); - } + public CommandState GetCommandState (NavigateToNextHighlightedReferenceCommandArgs args) => GetCommandStateImpl (args); - public CommandState GetCommandState (NavigateToPreviousHighlightedReferenceCommandArgs args) - { - return GetCommandStateImpl (args); - } + public CommandState GetCommandState (NavigateToPreviousHighlightedReferenceCommandArgs args) => GetCommandStateImpl (args); private CommandState GetCommandStateImpl (EditorCommandArgs args) { - using (var tagAggregator = _tagAggregatorFactory.CreateTagAggregator (args.TextView)) { - var tagUnderCursor = FindTagUnderCaret (tagAggregator, args.TextView); - return tagUnderCursor == null ? CommandState.Unavailable : CommandState.Available; + try { + using (var tagAggregator = _tagAggregatorFactory.CreateTagAggregator (args.TextView)) { + var tagUnderCursor = FindTagUnderCaret (tagAggregator, args.TextView); + return tagUnderCursor == null ? CommandState.Unavailable : CommandState.Available; + } + } catch (Exception ex) { + loggerFactory.GetLogger (args.TextView).LogInternalException (ex); + throw; } } - public bool ExecuteCommand (NavigateToNextHighlightedReferenceCommandArgs args, CommandExecutionContext context) - { - return ExecuteCommandImpl (args, navigateToNext: true, context); - } + public bool ExecuteCommand (NavigateToNextHighlightedReferenceCommandArgs args, CommandExecutionContext context) => ExecuteCommandImpl (args, navigateToNext: true, context); - public bool ExecuteCommand (NavigateToPreviousHighlightedReferenceCommandArgs args, CommandExecutionContext context) - { - return ExecuteCommandImpl (args, navigateToNext: false, context); - } + public bool ExecuteCommand (NavigateToPreviousHighlightedReferenceCommandArgs args, CommandExecutionContext context) => ExecuteCommandImpl (args, navigateToNext: false, context); private bool ExecuteCommandImpl (EditorCommandArgs args, bool navigateToNext, CommandExecutionContext context) + { + try { + return ExecuteCommandImplInternal (args, navigateToNext, context); + } catch (Exception ex) { + loggerFactory.GetLogger (args.TextView).LogInternalException (ex); + throw; + } + } + bool ExecuteCommandImplInternal (EditorCommandArgs args, bool navigateToNext, CommandExecutionContext context) { using (var tagAggregator = _tagAggregatorFactory.CreateTagAggregator (args.TextView)) { var tagUnderCursor = FindTagUnderCaret (tagAggregator, args.TextView); diff --git a/Editor/Commands/SplitTagsOnEnterCommandHandler.cs b/Editor/Commands/SplitTagsOnEnterCommandHandler.cs index 69f707d..12452e7 100644 --- a/Editor/Commands/SplitTagsOnEnterCommandHandler.cs +++ b/Editor/Commands/SplitTagsOnEnterCommandHandler.cs @@ -13,6 +13,9 @@ using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Utilities; +using MonoDevelop.Xml.Editor.Logging; +using MonoDevelop.Xml.Logging; + namespace MonoDevelop.Xml.Editor.Commands { [Name (Name)] @@ -22,15 +25,21 @@ namespace MonoDevelop.Xml.Editor.Commands [TextViewRole (PredefinedTextViewRoles.Interactive)] class SplitTagsOnEnterCommandHandler : IChainedCommandHandler { - [Import] - ISmartIndentationService SmartIndentService { get; set; } - - [Import] - ITextBufferUndoManagerProvider UndoManagerProvider { get; set; } - - - [Import] - IAsyncCompletionBroker CompletionBroker{ get; set; } + readonly IEditorLoggerFactory loggerFactory; + readonly ISmartIndentationService smartIndentService; + readonly ITextBufferUndoManagerProvider undoManagerProvider; + readonly IAsyncCompletionBroker completionBroker; + + [ImportingConstructor] + public SplitTagsOnEnterCommandHandler ( + IEditorLoggerFactory loggerFactory, ISmartIndentationService smartIndentService, + ITextBufferUndoManagerProvider undoManagerProvider, IAsyncCompletionBroker completionBroker) + { + this.loggerFactory = loggerFactory; + this.smartIndentService = smartIndentService; + this.undoManagerProvider = undoManagerProvider; + this.completionBroker = completionBroker; + } const string Name = nameof (SplitTagsOnEnterCommandHandler); @@ -38,11 +47,21 @@ class SplitTagsOnEnterCommandHandler : IChainedCommandHandler (args.TextView).LogInternalException (ex); + throw; + } + } + + void ExecuteCommandInternal (ReturnKeyCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext) + { var caretPos = args.TextView.Caret.Position.BufferPosition; int p = caretPos.Position; var s = caretPos.Snapshot; @@ -56,7 +75,7 @@ public void ExecuteCommand (ReturnKeyCommandArgs args, Action nextCommandHandler return; } - var undoManager = UndoManagerProvider.GetTextBufferUndoManager (args.SubjectBuffer); + var undoManager = undoManagerProvider.GetTextBufferUndoManager (args.SubjectBuffer); using (var transaction = undoManager.TextBufferUndoHistory.CreateTransaction ("Split Tags")) { string lineBreakText = null; var currentLine = s.GetLineFromPosition (p); @@ -72,7 +91,7 @@ public void ExecuteCommand (ReturnKeyCommandArgs args, Action nextCommandHandler s = edit.Apply (); var nextLine = s.GetLineFromLineNumber (currentLine.LineNumber + 1); - var indent = SmartIndentService.GetDesiredIndentation (args.TextView, nextLine); + var indent = smartIndentService.GetDesiredIndentation (args.TextView, nextLine); if (indent != null) { edit = args.SubjectBuffer.CreateEdit (); edit.Insert (nextLine.Start.Position, GetIndentString (indent.Value, args.TextView.Options)); diff --git a/Editor/Logging/EditorLoggerFactoryExtensions.cs b/Editor/Logging/EditorLoggerFactoryExtensions.cs index cb23adb..d2e20e6 100644 --- a/Editor/Logging/EditorLoggerFactoryExtensions.cs +++ b/Editor/Logging/EditorLoggerFactoryExtensions.cs @@ -1,6 +1,10 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +#nullable enable + +using System; + using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; @@ -11,26 +15,35 @@ namespace MonoDevelop.Xml.Editor.Logging; public static class EditorLoggerFactoryExtensions { /// - /// Get a logger for the if it exists, reusing the existing logger if possible, and creating one if necessary. - /// - public static ILogger GetLogger (this IEditorLoggerFactory factory, ITextBuffer buffer) - => buffer.Properties.GetOrCreateSingletonProperty (typeof (ILogger), () => factory.CreateLogger (buffer)); + /// Get a logger for the if it exists, reusing a previously-created -specific logger if possible. + /// + /// A wrapper that defers creating/fetching the -specific logger until it's used. + /// + /// + /// If this will only be called once for this and , use instead and store the result. + /// + public static ILogger GetLogger (this IEditorLoggerFactory factory, ITextBuffer buffer) => new LazyTextBufferLogger (factory, buffer); /// - /// Get a logger for the , reusing the existing logger if possible, and creating one if necessary. + /// Get a logger for the , reusing a previously-created -specific if possible. /// - public static ILogger GetLogger (this IEditorLoggerFactory factory, ITextView textView) - => textView.Properties.GetOrCreateSingletonProperty (typeof (ILogger), () => factory.CreateLogger (textView)); + /// + /// A wrapper that defers creating/fetching the -specific logger until it's used. + /// + /// + /// If this will only be called once for this and , use instead and store the result. + /// + public static ILogger GetLogger (this IEditorLoggerFactory factory, ITextView textView) => new LazyTextViewLogger (factory, textView); /// /// Create a logger for the . /// - /// It is generally preferable to use , which reuses an existing logger if possible, and only creates one if necessary. + /// If this will be called multiple times for this and , use instead, which reuses a previously-created logger if possible. /// /// - public static ILogger CreateLogger (this IEditorLoggerFactory factory, ITextBuffer buffer) + public static ILogger CreateLogger (this IEditorLoggerFactory factory, ITextBuffer buffer) { - var logger = factory.CreateLogger (buffer.ContentType); + var logger = factory.CreateLogger (buffer.ContentType); logger.BeginScope (new TextBufferId (buffer)); return logger; } @@ -38,12 +51,12 @@ public static ILogger CreateLogger (this IEditorLoggerFactory factory, ITe /// /// Create a logger for the . /// - /// It is generally preferable to use , which reuses an existing logger if possible, and only creates one if necessary. + /// If this will be called multiple times for this and , use instead, which reuses a previously-created logger if possible. /// /// - public static ILogger CreateLogger (this IEditorLoggerFactory factory, ITextView textView) + public static ILogger CreateLogger (this IEditorLoggerFactory factory, ITextView textView) { - var logger = factory.CreateLogger (textView.TextBuffer.ContentType); + var logger = factory.CreateLogger (textView.TextBuffer.ContentType); logger.BeginScope (new TextViewId (textView)); logger.BeginScope (new TextBufferId (textView.TextBuffer)); return logger; @@ -74,4 +87,46 @@ public TextViewId (ITextView textView) : this () public override readonly string ToString () => $"TextView #{id}"; } + + class LazyTextBufferLogger : ILogger + { + readonly IEditorLoggerFactory factory; + readonly ITextBuffer buffer; + + ILogger? logger; + ILogger GetLogger () => logger ??= buffer.Properties.GetOrCreateSingletonProperty (() => factory.CreateLogger (buffer)); + + public LazyTextBufferLogger (IEditorLoggerFactory factory, ITextBuffer buffer) + { + this.factory = factory; + this.buffer = buffer; + } + + public IDisposable? BeginScope (TState state) where TState : notnull => GetLogger ().BeginScope (state); + + public bool IsEnabled (LogLevel logLevel) => GetLogger ().IsEnabled (logLevel); + + public void Log (LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) => GetLogger ().Log (logLevel, eventId, state, exception, formatter); + } + + class LazyTextViewLogger : ILogger + { + readonly IEditorLoggerFactory factory; + readonly ITextView textView; + + ILogger? logger; + ILogger GetLogger () => logger ??= textView.Properties.GetOrCreateSingletonProperty (() => factory.CreateLogger (textView)); + + public LazyTextViewLogger (IEditorLoggerFactory factory, ITextView textView) + { + this.factory = factory; + this.textView = textView; + } + + public IDisposable? BeginScope (TState state) where TState : notnull => GetLogger ().BeginScope (state); + + public bool IsEnabled (LogLevel logLevel) => GetLogger ().IsEnabled (logLevel); + + public void Log (LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) => GetLogger ().Log (logLevel, eventId, state, exception, formatter); + } } diff --git a/Editor/Logging/IEditorLoggerFactory.cs b/Editor/Logging/IEditorLoggerFactory.cs index f18d6b9..0c93577 100644 --- a/Editor/Logging/IEditorLoggerFactory.cs +++ b/Editor/Logging/IEditorLoggerFactory.cs @@ -24,6 +24,6 @@ namespace MonoDevelop.Xml.Editor.Logging; /// public interface IEditorLoggerFactory { - ILogger CreateLogger (string contentTypeName); - ILogger CreateLogger (IContentType contentType); + ILogger CreateLogger (string contentTypeName); + ILogger CreateLogger (IContentType contentType); } \ No newline at end of file diff --git a/Editor/Parsing/BackgroundParser.cs b/Editor/Parsing/BackgroundParser.cs index 7ce2686..eb36d91 100644 --- a/Editor/Parsing/BackgroundParser.cs +++ b/Editor/Parsing/BackgroundParser.cs @@ -40,9 +40,9 @@ Operation CreateOperation (TInput input) //capture successful parses task.ContinueWith ((t, state) => { - Operation op = (Operation)state; + Operation op = (Operation)state!; try { - // op.Output accesses the task.Result, thowing any exceptions + // op.Output accesses the task.Result, throwing any exceptions op.Processor.OnOperationCompleted (op.Input, op.Output); op.Processor.lastSuccessfulOperation = op; } catch (Exception eventException) { diff --git a/Editor/SmartIndent/XmlSmartIndent.cs b/Editor/SmartIndent/XmlSmartIndent.cs index de8db13..3da80cb 100644 --- a/Editor/SmartIndent/XmlSmartIndent.cs +++ b/Editor/SmartIndent/XmlSmartIndent.cs @@ -24,18 +24,18 @@ class XmlSmartIndent : ISmartIndent readonly ITextView textView; readonly IEditorOptions options; readonly XmlParserProvider parserProvider; - readonly ILogger logger; + readonly ILogger logger; - public XmlSmartIndent (ITextView textView, XmlParserProvider parserProvider, ILogger logger) : this (textView, parserProvider, textView.Options) + public XmlSmartIndent (ITextView textView, XmlParserProvider parserProvider, ILogger logger) : this (textView, parserProvider, textView.Options, logger) { - this.logger = logger; } - public XmlSmartIndent (ITextView textView, XmlParserProvider parserProvider, IEditorOptions options) + public XmlSmartIndent (ITextView textView, XmlParserProvider parserProvider, IEditorOptions options, ILogger logger) { this.textView = textView; this.options = options; this.parserProvider = parserProvider; + this.logger = logger; } public void Dispose () diff --git a/Editor/TextStructure/XmlTextStructureNavigator.cs b/Editor/TextStructure/XmlTextStructureNavigator.cs index 00e9982..281851b 100644 --- a/Editor/TextStructure/XmlTextStructureNavigator.cs +++ b/Editor/TextStructure/XmlTextStructureNavigator.cs @@ -76,7 +76,7 @@ SnapshotSpan GetSpanOfEnclosingInternal (SnapshotSpan activeSpan) // use last parse if it's up to date, which is most likely will be // else use a spine from the end of the selection and update as needed var lastParse = parser.LastOutput; - List nodePath; + List? nodePath = null; XmlSpineParser? spine = null; if (lastParse != null && lastParse.TextSnapshot.Version.VersionNumber == activeSpan.Snapshot.Version.VersionNumber) { var n = lastParse.XDocument.FindAtOrBeforeOffset (activeSpan.Start.Position);