Skip to content

Commit

Permalink
Merge pull request #70 from mhutch/log-command-errors
Browse files Browse the repository at this point in the history
Log exceptions in editor commands
  • Loading branch information
mhutch committed Jul 12, 2023
2 parents 0f703cd + fe739af commit f55462e
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 101 deletions.
43 changes: 5 additions & 38 deletions Editor.Tests/Commands/SmartIndentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

using MonoDevelop.Xml.Editor.Parsing;
using MonoDevelop.Xml.Editor.SmartIndent;
using MonoDevelop.Xml.Tests;

using NUnit.Framework;

Expand Down Expand Up @@ -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<XmlParserProvider> (), options);
var smartIndent = new XmlSmartIndent (textView, Catalog.GetService<XmlParserProvider> (), TestLoggerFactory.CreateTestMethodLogger ());
var indent = smartIndent.GetDesiredIndentation (line);
Assert.AreEqual (expectedIndent, indent);
}
}

class TestEditorOptions : IEditorOptions
{
Dictionary<string, object> storage = new Dictionary<string, object> ();

public IEnumerable<EditorOptionDefinition> 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<EditorOptionChangedEventArgs> OptionChanged;
#pragma warning restore 67

public bool ClearOptionValue (string optionId) => throw new NotImplementedException ();

public bool ClearOptionValue<T> (EditorOptionKey<T> key) => throw new NotImplementedException ();

public T GetOptionValue<T> (string optionId) => (T)storage[optionId];

public T GetOptionValue<T> (EditorOptionKey<T> 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<T> (EditorOptionKey<T> key, bool localScopeOnly) => throw new NotImplementedException ();

public void SetOptionValue (string optionId, object value) => storage[optionId] = value;

public void SetOptionValue<T> (EditorOptionKey<T> key, T value) => storage[key.Name] = value;
}
}
15 changes: 13 additions & 2 deletions Editor/BraceCompletion/XmlBraceCompletionCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -48,19 +50,28 @@ class XmlBraceCompletionCommandHandler : IChainedCommandHandler<TypeCharCommandA
const string Name = nameof (XmlBraceCompletionCommandHandler);

[ImportingConstructor]
public XmlBraceCompletionCommandHandler (XmlParserProvider parserProvider)
public XmlBraceCompletionCommandHandler (XmlParserProvider parserProvider, IEditorLoggerFactory loggerFactory)
{
this.parserProvider = parserProvider;
this.loggerFactory = loggerFactory;
}

readonly XmlParserProvider parserProvider;
readonly IEditorLoggerFactory loggerFactory;

// log
public string DisplayName => Name;

public CommandState GetCommandState (TypeCharCommandArgs args, Func<CommandState> 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<XmlBraceCompletionCommandHandler> (args.TextView).LogInternalException (ex);
}
}

void ExecuteCommandInternal (TypeCharCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext)
{
Expand Down
13 changes: 11 additions & 2 deletions Editor/Commands/AutoClosingTagCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
{
Expand All @@ -30,13 +33,15 @@ class AutoClosingTagCommandHandler : IChainedCommandHandler<TypeCharCommandArgs>
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;
Expand All @@ -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<AutoClosingTagCommandHandler> (args.TextView).LogInternalException (ex);
}
}
}

Expand Down
15 changes: 15 additions & 0 deletions Editor/Commands/CommentUncommentCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<CommentUncommentCommandHandler> (args.TextView).LogInternalException (ex);
throw;
}
}

bool ExecuteCommandCoreInternal (EditorCommandArgs args, CommandExecutionContext context, Operation operation)
{
ITextView textView = args.TextView;
ITextBuffer textBuffer = args.SubjectBuffer;
Expand Down
59 changes: 34 additions & 25 deletions Editor/Commands/NavigateToHighlightReferenceCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<NavigateToNextHighlightedReferenceCommandArgs>,
VSCommanding.ICommandHandler<NavigateToPreviousHighlightedReferenceCommandArgs>
ICommandHandler<NavigateToNextHighlightedReferenceCommandArgs>,
ICommandHandler<NavigateToPreviousHighlightedReferenceCommandArgs>
{
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<NavigableHighlightTag> (args.TextView)) {
var tagUnderCursor = FindTagUnderCaret (tagAggregator, args.TextView);
return tagUnderCursor == null ? CommandState.Unavailable : CommandState.Available;
try {
using (var tagAggregator = _tagAggregatorFactory.CreateTagAggregator<NavigableHighlightTag> (args.TextView)) {
var tagUnderCursor = FindTagUnderCaret (tagAggregator, args.TextView);
return tagUnderCursor == null ? CommandState.Unavailable : CommandState.Available;
}
} catch (Exception ex) {
loggerFactory.GetLogger<NavigateToHighlightReferenceCommandHandler> (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<NavigateToHighlightReferenceCommandHandler> (args.TextView).LogInternalException (ex);
throw;
}
}
bool ExecuteCommandImplInternal (EditorCommandArgs args, bool navigateToNext, CommandExecutionContext context)
{
using (var tagAggregator = _tagAggregatorFactory.CreateTagAggregator<NavigableHighlightTag> (args.TextView)) {
var tagUnderCursor = FindTagUnderCaret (tagAggregator, args.TextView);
Expand Down
43 changes: 31 additions & 12 deletions Editor/Commands/SplitTagsOnEnterCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -22,27 +25,43 @@ namespace MonoDevelop.Xml.Editor.Commands
[TextViewRole (PredefinedTextViewRoles.Interactive)]
class SplitTagsOnEnterCommandHandler : IChainedCommandHandler<ReturnKeyCommandArgs>
{
[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);

public string DisplayName => Name;

public void ExecuteCommand (ReturnKeyCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext)
{
if (SmartIndentService == null || CompletionBroker.IsCompletionActive (args.TextView)) {
if (smartIndentService == null || completionBroker.IsCompletionActive (args.TextView)) {
nextCommandHandler ();
return;
}

try {
ExecuteCommandInternal (args, nextCommandHandler, executionContext);
} catch (Exception ex) {
loggerFactory.GetLogger<SplitTagsOnEnterCommandHandler> (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;
Expand All @@ -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);
Expand All @@ -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));
Expand Down
Loading

0 comments on commit f55462e

Please sign in to comment.