Skip to content

Commit

Permalink
update document state on change
Browse files Browse the repository at this point in the history
  • Loading branch information
retailcoder committed Mar 27, 2024
1 parent f302d08 commit 52bf87f
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 53 deletions.
74 changes: 53 additions & 21 deletions Client/Rubberduck.Editor/Shell/Document/CodeDocumentTabViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
using OmniSharp.Extensions.LanguageServer.Protocol.Client;
using AsyncAwaitBestPractices;
using OmniSharp.Extensions.LanguageServer.Protocol.Client;
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using Rubberduck.InternalApi.Extensions;
using Rubberduck.InternalApi.ServerPlatform.LanguageServer;
using Rubberduck.InternalApi.Settings.Model.Editor;
using Rubberduck.UI.Command.SharedHandlers;
using Rubberduck.UI.Services;
using Rubberduck.UI.Shell.Document;
using Rubberduck.UI.Shell.StatusBar;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
using Rubberduck.InternalApi.Extensions;
using System.Linq;
using System.Threading;
using Rubberduck.UI.Services;
using System.Threading.Tasks;

namespace Rubberduck.Editor.Shell.Document
{
Expand All @@ -21,6 +21,8 @@ namespace Rubberduck.Editor.Shell.Document
/// </summary>
public abstract class CodeDocumentTabViewModel : DocumentTabViewModel, ICodeDocumentTabViewModel
{
public event EventHandler CodeDocumentStateChanged = delegate { };

private readonly Lazy<ILanguageClient> _languageClient;
private readonly UIServiceHelper _service;

Expand All @@ -33,6 +35,7 @@ public CodeDocumentTabViewModel(CodeDocumentState state, bool isReadOnly,
{
_languageClient = new Lazy<ILanguageClient>(() => lsp.Invoke(), isThreadSafe: true);
_service = service;
_uri = state.Uri;

Title = state.Name;
SettingKey = nameof(EditorSettings);
Expand All @@ -46,12 +49,13 @@ public CodeDocumentTabViewModel(CodeDocumentState state, bool isReadOnly,
/// </summary>
private Timer IdleTimer { get; }
private TimeSpan IdleDelay => UIServiceHelper.Instance!.Settings.EditorSettings.IdleTimerDuration;
private void IdleTimerCallback(object? _) => NotifyDocumentChanged();
private void IdleTimerCallback(object? _) => NotifyDocumentChangedAsync().SafeFireAndForget();

/// <summary>
/// Resets the idle timer to fire a callback in <c>IdleDelay</c> milliseconds.
/// </summary>
private void ResetIdleTimer() => IdleTimer.Change(Convert.ToInt32(IdleDelay.TotalMilliseconds), Timeout.Infinite);
private void DisableIdleTimer() => IdleTimer.Change(Timeout.Infinite, Timeout.Infinite);

private ILanguageClient LanguageClient => _languageClient.Value;

Expand All @@ -62,14 +66,27 @@ public CodeDocumentState CodeDocumentState
set
{
_state = value;
DocumentState = value;
OnPropertyChanged();
CodeDocumentStateChanged?.Invoke(this, EventArgs.Empty);
}
}

public override DocumentState DocumentState
{
get => _state;
set => CodeDocumentState = value as CodeDocumentState ?? throw new InvalidOperationException();
}

public override Uri DocumentUri
{
get => _uri;
set => CodeDocumentUri = value as WorkspaceFileUri ?? throw new InvalidOperationException();
}

protected override void OnTextChanged()
{
// todo notify server, etc.
DisableIdleTimer();
NotifyDocumentChangedAsync().SafeFireAndForget(e => _service.LogException(e));
}

public string LanguageId => _state.Language.Id;
Expand All @@ -91,9 +108,9 @@ public WorkspaceFileUri CodeDocumentUri

public override SupportedDocumentType DocumentType => SupportedDocumentType.SourceFile;

private void NotifyDocumentChanged() => NotifyDocumentChanged(null!, null!);
private async Task NotifyDocumentChangedAsync() => await NotifyDocumentChangedAsync(null!, null!);

private void NotifyDocumentChanged(OmniSharp.Extensions.LanguageServer.Protocol.Models.Range? range, string? text)
private async Task NotifyDocumentChangedAsync(OmniSharp.Extensions.LanguageServer.Protocol.Models.Range? range, string? text)
{
// increment local version first...
DocumentState = _state with { Version = _state.Version + 1 };
Expand All @@ -114,43 +131,58 @@ private void NotifyDocumentChanged(OmniSharp.Extensions.LanguageServer.Protocol.
})
};

_service.LogDebug($"Notifying server of document changes.", $"DocumentId: {DocumentState.Id} Version: {DocumentState.Version}");
LanguageClient.DidChangeTextDocument(request);

await Task.WhenAll(RequestFoldingsAsync(), RequestDiagnosticsAsync()).ConfigureAwait(false);
}

private async Task<IEnumerable<Diagnostic>> RequestDiagnosticsAsync()
private async Task RequestDiagnosticsAsync()
{
var report = await LanguageClient.RequestDocumentDiagnostic(new DocumentDiagnosticParams
var request = new DocumentDiagnosticParams
{
Identifier = "RDE",
TextDocument = new TextDocumentIdentifier
{
Uri = _uri.AbsoluteLocation,
}
});
};

_service.LogDebug($"Requesting document diagnostics.");
var report = await LanguageClient.RequestDocumentDiagnostic(request);

if (report is IFullDocumentDiagnosticReport fullReport)
{
_service.LogDebug($"Received {fullReport.Items.Count()} diagnostics.");
CodeDocumentState = _state.WithDiagnostics(fullReport.Items);
return fullReport.Items;
}
else
{
return _state.Diagnostics;
_service.LogDebug($"Received a diagnostic report that was not a IFullDocumentDiagnosticReport.", $"Report type : {report?.GetType().Name ?? "(null)"}");
}
}

private async Task<IEnumerable<FoldingRange>> RequestFoldingsAsync()
private async Task RequestFoldingsAsync()
{
var foldings = await LanguageClient.RequestFoldingRange(new FoldingRangeRequestParam
var request = new FoldingRangeRequestParam
{
TextDocument = new TextDocumentIdentifier
{
Uri = _uri.AbsoluteLocation,
}
});
};

return foldings?.ToList() ?? [];
_service.LogDebug($"Requesting document folding ranges.");
var foldings = await LanguageClient.RequestFoldingRange(request);
if (foldings is not null)
{
_service.LogDebug($"Received {foldings.Count()} document folding ranges.");
CodeDocumentState = _state.WithFoldings(foldings);
}
else
{
_service.LogDebug($"Received a null response for folding ranges.");
}
}

}
}
11 changes: 3 additions & 8 deletions Client/Rubberduck.Editor/Shell/Document/DocumentTabViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ namespace Rubberduck.Editor.Shell.Document
/// </summary>
public abstract class DocumentTabViewModel : WindowViewModel, IDocumentTabViewModel
{
public event EventHandler<WorkspaceFileUriEventArgs> DocumentStateChanged = delegate { };

public DocumentTabViewModel(DocumentState state, bool isReadOnly,
ShowRubberduckSettingsCommand showSettingsCommand,
CloseToolWindowCommand closeToolWindowCommand,
Expand All @@ -31,7 +29,7 @@ public DocumentTabViewModel(DocumentState state, bool isReadOnly,
}

private DocumentState _state;
public DocumentState DocumentState
public virtual DocumentState DocumentState
{
get => _state;
set
Expand All @@ -47,7 +45,7 @@ public DocumentState DocumentState
public IDocumentStatusViewModel Status { get; }

private Uri _uri;
public Uri DocumentUri
public virtual Uri DocumentUri
{
get => _uri;
set
Expand Down Expand Up @@ -79,10 +77,7 @@ public string TextContent
}
}

protected virtual void OnTextChanged()
{

}
protected virtual void OnTextChanged() { }

private bool _isReadOnly;
public bool IsReadOnly
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ public interface IDocumentTabViewModel : ITabViewModel
{
Uri DocumentUri { get; set; }
DocumentState DocumentState { get; set; }
event EventHandler<WorkspaceFileUriEventArgs> DocumentStateChanged;

bool IsReadOnly { get; set; }

Expand All @@ -40,6 +39,7 @@ public interface IDocumentTabViewModel : ITabViewModel

public interface ICodeDocumentTabViewModel : IDocumentTabViewModel
{
event EventHandler CodeDocumentStateChanged;
string LanguageId { get; }

WorkspaceFileUri CodeDocumentUri { get; set; }
Expand Down
41 changes: 21 additions & 20 deletions Client/Rubberduck.UI/Shell/Document/SourceCodeEditorControl.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,44 +125,43 @@ private void HideMarkerToolTip()

private void ExpandAllFoldings()
{
foreach (var folding in _foldings.AllFoldings)
Dispatcher.Invoke(() =>
{
folding.IsFolded = false;
}
foreach (var folding in _foldings.AllFoldings)
{
folding.IsFolded = false;
}
});
}

private void CollapseAllFoldings()
{
foreach (var folding in _foldings.AllFoldings)
Dispatcher.Invoke(() =>
{
folding.IsFolded = true;
}
foreach (var folding in _foldings.AllFoldings)
{
folding.IsFolded = true;
}
});
}

private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
ViewModel = (ICodeDocumentTabViewModel)e.NewValue;
ViewModel.DocumentStateChanged += OnServerDocumentStateChanged;
HandleDataContextChangedAsync().SafeFireAndForget();
}
ViewModel.CodeDocumentStateChanged += ViewModelDocumentStateChanged;
DataContextChanged -= OnDataContextChanged;

private void OnServerDocumentStateChanged(object? sender, EventArgs e)
{
Editor.Text = ViewModel.TextContent;
UpdateFoldingsAsync().SafeFireAndForget();
UpdateDiagnostics();
UpdateStatusInfo();
}

private async Task HandleDataContextChangedAsync()
private void ViewModelDocumentStateChanged(object? sender, EventArgs e)
{
if (ViewModel.DocumentType == SupportedDocumentType.SourceFile)
{
Editor.Text = ViewModel.TextContent;
var foldingsTask = UpdateFoldingsAsync();

await Task.WhenAll([foldingsTask]).ConfigureAwait(false);
}

UpdateStatusInfo();
UpdateDiagnostics();
UpdateFoldingsAsync().SafeFireAndForget();
}

private async Task UpdateFoldingsAsync()
Expand All @@ -179,6 +178,7 @@ await Dispatcher.InvokeAsync(() =>
{
var newFoldings = foldings
.Select(e => e.ToNewFolding(Editor.Document))
.Where(e => e.EndOffset < Editor.Document.TextLength)
.OrderBy(e => e.StartOffset)
.ToArray();
if (firstErrorRange != null)
Expand All @@ -193,6 +193,7 @@ await Dispatcher.InvokeAsync(() =>
private void UpdateDiagnostics()
{
_markers.RemoveAll(e => true);
_margin.InvalidateVisual();
foreach (var diagnostic in ViewModel.CodeDocumentState.Diagnostics)
{
diagnostic.WithTextMarker(Editor, _markers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using Rubberduck.InternalApi.ServerPlatform.LanguageServer;
using Rubberduck.InternalApi.Services;
using Rubberduck.ServerPlatform;
using System;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -11,11 +12,13 @@ namespace Rubberduck.LanguageServer.Handlers.Language;

public class DocumentDiagnosticHandler : DocumentDiagnosticHandlerBase
{
private readonly ServerPlatformServiceHelper _service;
private readonly IAppWorkspacesService _workspaces;
private readonly TextDocumentSelector _selector;

public DocumentDiagnosticHandler(IAppWorkspacesService workspaces, SupportedLanguage language)
public DocumentDiagnosticHandler(ServerPlatformServiceHelper service, IAppWorkspacesService workspaces, SupportedLanguage language)
{
_service = service;
_workspaces = workspaces;
_selector = language.ToTextDocumentSelector();
}
Expand All @@ -29,6 +32,7 @@ public async override Task<RelatedDocumentDiagnosticReport> Handle(DocumentDiagn

if (workspace.TryGetWorkspaceFile(uri, out var state) && state is CodeDocumentState document)
{
_service.LogInformation($"Found {document.Diagnostics.Count} diagnostics for document at uri '{uri}'.");
return new RelatedFullDocumentDiagnosticReport
{
Items = new Container<Diagnostic>(document.Diagnostics)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ public FoldingRangeHandler(ServerPlatformServiceHelper service, IAppWorkspacesSt
}
}, out var exception, nameof(FoldingRangeHandler)) && exception != null)
{
// in case of failure, we throw here to return an error response:
// in case of failure, we throw here to return an error response (exception was already logged):
throw exception;
}

var result = new Container<FoldingRange>(items);
return await Task.FromResult(result);
return result;
}

protected override FoldingRangeRegistrationOptions CreateRegistrationOptions(FoldingRangeCapability capability, ClientCapabilities clientCapabilities)
Expand Down

0 comments on commit 52bf87f

Please # to comment.