Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pipeline/state #96

Merged
merged 44 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
0655f7c
tweaks
retailcoder Feb 28, 2024
06efd62
code folding tweaks
retailcoder Mar 2, 2024
5486118
tweaks
retailcoder Mar 2, 2024
7682ede
moved discovering code foldings to their own pipeline block
retailcoder Mar 2, 2024
ecc0fba
added expand/collapse icons
retailcoder Mar 2, 2024
ad03b0a
refactor syntax errors
retailcoder Mar 2, 2024
b9faf1a
fix document state issues :)
retailcoder Mar 2, 2024
a2ea3e1
(WIP) text markers for diagnostics
retailcoder Mar 5, 2024
3de35ff
fix URI issues
retailcoder Mar 6, 2024
6a43a63
fix async delegate
retailcoder Mar 6, 2024
56b289b
tweaks
retailcoder Mar 6, 2024
79ce0c8
simplified exceptions
retailcoder Mar 7, 2024
850f3da
tweaks
retailcoder Mar 8, 2024
e18f238
WIP (FIXME URI mismatch bug)
retailcoder Mar 11, 2024
965fdef
fix URI mismatches
retailcoder Mar 11, 2024
01828c7
fix some uri issues
retailcoder Mar 13, 2024
2664910
tweaks
retailcoder Mar 13, 2024
8cdbc50
fixed pipeline state update race condition, markers render (once) in …
retailcoder Mar 14, 2024
f9c3ec4
added LSP DidCloseDocument notification
retailcoder Mar 15, 2024
c7ea5f0
fixed save disabled message keys, added OokiiMessageService, implemen…
retailcoder Mar 16, 2024
88a34c5
added SettingsUI and some captions
retailcoder Mar 16, 2024
e6360e7
more captions
retailcoder Mar 16, 2024
a88087c
update value from Selection
retailcoder Mar 16, 2024
a3dbb05
disable message keys from message service
retailcoder Mar 16, 2024
b786675
show welcome tab on startup; settings UI tweaks.
retailcoder Mar 16, 2024
b88e8d5
settings UI tweaks
retailcoder Mar 17, 2024
f7f7c4f
fix enumgroup settings de/serialization (telemetry settings subgroups)
retailcoder Mar 18, 2024
1b6913a
tweaks
retailcoder Mar 18, 2024
a857881
UI tweaks; implemented search and navigation, broke FlatButton hover/…
retailcoder Mar 20, 2024
dc45ced
tweaks
retailcoder Mar 20, 2024
c62451f
in theory all that should be needed for OkCancel buttons
retailcoder Mar 21, 2024
f932ac3
tweaks
retailcoder Mar 21, 2024
298c67d
fix app shutdown
retailcoder Mar 23, 2024
396f19d
tweaks
retailcoder Mar 24, 2024
4ac0f5a
tweak
retailcoder Mar 24, 2024
36a9f5f
added missing serialization specs
retailcoder Mar 25, 2024
14143a8
added setting group name for search results; added IdleTimerDurationS…
retailcoder Mar 25, 2024
5e48ada
use idle delay setting
retailcoder Mar 25, 2024
2ddf7b7
tweak
retailcoder Mar 25, 2024
a4f37f4
render marker icon per diagnostic severity
retailcoder Mar 25, 2024
f302d08
some renames; separated document vs source code documents
retailcoder Mar 27, 2024
52bf87f
update document state on change
retailcoder Mar 27, 2024
e5bebc7
added title
retailcoder Mar 27, 2024
6627c6a
Merge branch 'main' of https://github.com/rubberduck-vba/Rubberduck3 …
retailcoder Mar 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 35 additions & 15 deletions Client/Rubberduck.Editor/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Dragablz;
using AsyncAwaitBestPractices;
using Dragablz;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NLog;
Expand Down Expand Up @@ -98,8 +99,6 @@ protected override async void OnStartup(StartupEventArgs e)
_ = UiContextProvider.Instance(); // we MUST do this while we KNOW we're on the main thread.
try
{
ShutdownMode = ShutdownMode.OnLastWindowClose;

var args = e.Args;
_options = await ServerArgs.ParseAsync(args);
_tokenSource = new CancellationTokenSource();
Expand All @@ -119,7 +118,10 @@ protected override async void OnStartup(StartupEventArgs e)
_settings = _serviceProvider.GetRequiredService<RubberduckSettingsProvider>();

var splash = _serviceProvider.GetRequiredService<SplashService>();
splash.Show(WindowSize.Splash);
if (_settings.Settings.GeneralSettings.ShowSplash)
{
splash.Show(WindowSize.Splash);
}

splash.UpdateStatus("Loading configuration...");
_settings.ClearCache();
Expand Down Expand Up @@ -161,6 +163,10 @@ private async Task ShowEditorAsync()
var model = _serviceProvider.GetRequiredService<IShellWindowViewModel>();

var view = _shell ??= new ShellWindow() { DataContext = model };

ShutdownMode = ShutdownMode.OnMainWindowClose;
MainWindow = view;

view.Show();

ShowStartupToolwindows(settings);
Expand Down Expand Up @@ -199,14 +205,19 @@ private void ShowStartupToolwindows(EditorSettings settings)
private async Task LoadWelcomeTabAsync(IShellWindowViewModel model)
{
var fileSystem = _serviceProvider.GetRequiredService<IFileSystem>();
var path = fileSystem.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Rubberduck", "Templates", "Welcome.md");
var folder = fileSystem.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Rubberduck", "Templates");
var filename = "Welcome.md";
var path = fileSystem.Path.Combine(folder, filename);
var content = await fileSystem.File.ReadAllTextAsync(path);

var rootUri = new Uri(folder);
var fileUri = new WorkspaceFileUri(filename, rootUri);

var showSettingsCommand = _serviceProvider.GetRequiredService<ShowRubberduckSettingsCommand>();
var closeToolWindowCommand = _serviceProvider.GetRequiredService<CloseToolWindowCommand>();
var activeDocumentStatus = _serviceProvider.GetRequiredService<IDocumentStatusViewModel>();
var welcome = new MarkdownDocumentTabViewModel(new Uri(path), "Welcome", content, isReadOnly: true, showSettingsCommand, closeToolWindowCommand, activeDocumentStatus);

var documentState = new DocumentState(fileUri, content, isOpened: true);
var welcome = new MarkdownDocumentTabViewModel(documentState, isReadOnly: true, showSettingsCommand, closeToolWindowCommand, activeDocumentStatus);
var welcomeTabContent = new MarkdownEditorControl() { DataContext = welcome };
welcome.ContentControl = welcomeTabContent;
welcome.IsSelected = true;
Expand All @@ -219,11 +230,11 @@ protected override void OnExit(ExitEventArgs e)
{
var level = _settings.Settings.LoggerSettings.TraceLevel.ToTraceLevel();
var delay = _settings.Settings.LanguageClientSettings.ExitNotificationDelay;
e.ApplicationExitCode = 0;

if (TimedAction.TryRun(() =>
{
_languageClient?.ExitAsync().ConfigureAwait(false).GetAwaiter().GetResult();
base.OnExit(e);
_languageClient?.ExitAsync().SafeFireAndForget();
}, out var elapsed, out var exception))
{
_logger.LogPerformance(level, $"Notified language server to shutdown and exit (delay: {delay.TotalMilliseconds}ms).", elapsed);
Expand All @@ -232,6 +243,16 @@ protected override void OnExit(ExitEventArgs e)
{
_logger.LogError(level, exception, "Error sending shutdown/exit notifications.");
}

if (_editorServer != null)
{
if (!_editorServer.ServerState.IsCleanExit)
{
e.ApplicationExitCode = 1;
}
}

base.OnExit(e);
}

private void ConfigureLogging(ILoggingBuilder builder)
Expand All @@ -257,8 +278,7 @@ private void ConfigureLogging(ILoggingBuilder builder)

private void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<Func<ILanguageServer>>(provider => () => _editorServer.Server);
services.AddSingleton<Func<ILanguageClient?>>(provider => () => _languageClient.LanguageClient);
services.AddSingleton<Func<ILanguageClient>>(provider => () => _languageClient.LanguageClient!);
services.AddSingleton<LanguageClientApp>(provider => _languageClient);
services.AddSingleton<ILanguageClientService, LanguageClientService>();
services.AddSingleton<ILanguageServerConnectionStatusProvider, LanguageClientService>(provider => (LanguageClientService)provider.GetRequiredService<ILanguageClientService>());
Expand Down Expand Up @@ -301,7 +321,7 @@ private void ConfigureServices(IServiceCollection services)
services.AddSingleton<ShellProvider>();
services.AddSingleton<IShellWindowViewModel, ShellWindowViewModel>();
services.AddSingleton<IShellStatusBarViewModel, ShellStatusBarViewModel>();
services.AddSingleton<IWindowChromeViewModel, WindowChromeViewModel>();
services.AddTransient<IWindowChromeViewModel, WindowChromeViewModel>();

services.AddSingleton<InterTabClient>();
services.AddSingleton<InterToolTabClient>();
Expand All @@ -311,7 +331,7 @@ private void ConfigureServices(IServiceCollection services)

services.AddSingleton<MessageActionsProvider>();
services.AddSingleton<IMessageWindowFactory, MessageWindowFactory>();
services.AddSingleton<IMessageService, MessageService>();
services.AddSingleton<IMessageService, OokiiMessageService>();
services.AddSingleton<ShowMessageHandler>();
services.AddSingleton<ShowMessageRequestHandler>();

Expand All @@ -323,10 +343,10 @@ private void ConfigureServices(IServiceCollection services)
services.AddSingleton<IWindowFactory<SettingsWindow, SettingsWindowViewModel>, SettingsWindowFactory>();
services.AddSingleton<ISettingViewModelFactory, SettingViewModelFactory>();

services.AddSingleton<IWorkspaceService, WorkspaceClientService>();
services.AddSingleton<IAppWorkspacesService, WorkspaceClientService>();
services.AddSingleton<ILanguageServerTraceViewModel, LanguageServerTraceViewModel>();
services.AddSingleton<IWorkspaceExplorerViewModel, WorkspaceExplorerViewModel>();
services.AddSingleton<IWorkspaceStateManager, WorkspaceStateManager>();
services.AddSingleton<IAppWorkspacesStateManager, WorkspaceStateManager>();
services.AddSingleton<DocumentContentStore>();
services.AddSingleton<OpenDocumentCommand>();

Expand Down
4 changes: 2 additions & 2 deletions Client/Rubberduck.Editor/Commands/CloseAllDocumentsCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ namespace Rubberduck.Editor.Commands
{
public class CloseAllDocumentsCommand : CommandBase
{
private readonly IWorkspaceService _workspace;
private readonly IAppWorkspacesService _workspace;

public CloseAllDocumentsCommand(UIServiceHelper service,
IWorkspaceService workspace)
IAppWorkspacesService workspace)
: base(service)
{
_workspace = workspace;
Expand Down
22 changes: 15 additions & 7 deletions Client/Rubberduck.Editor/Commands/CloseDocumentCommand.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Rubberduck.InternalApi.Extensions;
using OmniSharp.Extensions.LanguageServer.Protocol.Client;
using OmniSharp.Extensions.LanguageServer.Protocol.Document;
using Rubberduck.InternalApi.Extensions;
using Rubberduck.InternalApi.Services;
using Rubberduck.UI.Command.Abstract;
using Rubberduck.UI.Services;
Expand All @@ -9,24 +11,30 @@ namespace Rubberduck.Editor.Commands
{
public class CloseDocumentCommand : CommandBase
{
private readonly IWorkspaceService _workspace;
private readonly IAppWorkspacesService _workspace;
private readonly Func<ILanguageClient> _lsp;


public CloseDocumentCommand(UIServiceHelper service,
IWorkspaceService workspace)
IAppWorkspacesService workspace,
Func<ILanguageClient> lsp)
: base(service)
{
_workspace = workspace;
_lsp = lsp;
}

protected async override Task OnExecuteAsync(object? parameter)
{
if (parameter is WorkspaceFileUri uri)
{
_workspace.CloseFile(uri);
return;
if (_workspace.Workspaces.ActiveWorkspace?.TryGetWorkspaceFile(uri, out var document) ?? false)
{
var server = _lsp();
_workspace.CloseFile(uri);
server?.TextDocument.DidCloseTextDocument(new() { TextDocument = new() { Uri = uri.AbsoluteLocation.AbsoluteUri } });
}
}

// TODO once there's a document state manager, grab the ActiveDocument here
}
}
}
4 changes: 2 additions & 2 deletions Client/Rubberduck.Editor/Commands/CloseWorkspaceCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ namespace Rubberduck.Editor.Commands
{
public class CloseWorkspaceCommand : CommandBase
{
private readonly IWorkspaceService _workspace;
private readonly IAppWorkspacesService _workspace;

public CloseWorkspaceCommand(UIServiceHelper service,
IWorkspaceService workspace)
IAppWorkspacesService workspace)
: base(service)
{
_workspace = workspace;
Expand Down
4 changes: 2 additions & 2 deletions Client/Rubberduck.Editor/Commands/ExitCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ namespace Rubberduck.Editor.Commands
{
public class ExitCommand : CommandBase
{
private readonly IWorkspaceService _workspace;
private readonly IAppWorkspacesService _workspace;

public ExitCommand(UIServiceHelper service, IWorkspaceService workspace)
public ExitCommand(UIServiceHelper service, IAppWorkspacesService workspace)
: base(service)
{
_workspace = workspace;
Expand Down
99 changes: 63 additions & 36 deletions Client/Rubberduck.Editor/Commands/OpenDocumentCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using Rubberduck.Editor.Shell.Document;
using Rubberduck.InternalApi.Extensions;
using Rubberduck.InternalApi.Model.Workspace;
using Rubberduck.InternalApi.ServerPlatform.LanguageServer;
using Rubberduck.InternalApi.Services;
using Rubberduck.UI.Command;
Expand All @@ -13,28 +12,31 @@
using Rubberduck.UI.Shell.Document;
using Rubberduck.UI.Shell.StatusBar;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace Rubberduck.Editor.Commands
{
public class OpenDocumentCommand : CommandBase
{
private readonly IWorkspaceStateManager _workspaces;
private readonly IAppWorkspacesStateManager _workspaces;
private readonly ShellProvider _shell;

private readonly ShowRubberduckSettingsCommand _showSettingsCommand;
private readonly CloseToolWindowCommand _closeToolWindowCommand;
private readonly IDocumentStatusViewModel _activeDocumentStatus;

private readonly Func<ILanguageClient?> _lsp;
private readonly Func<ILanguageClient> _lsp;
private readonly Lazy<ILanguageClient> _languageClient;
private ILanguageClient LanguageClient => _languageClient.Value;

public OpenDocumentCommand(UIServiceHelper service,
IWorkspaceStateManager workspaces,
IAppWorkspacesStateManager workspaces,
ShellProvider shell,
ShowRubberduckSettingsCommand showSettingsCommand,
CloseToolWindowCommand closeToolWindow,
IDocumentStatusViewModel activeDocumentStatus, Func<ILanguageClient?> lsp)
IDocumentStatusViewModel activeDocumentStatus, Func<ILanguageClient> lsp)
: base(service)
{
_workspaces = workspaces;
Expand All @@ -45,54 +47,83 @@ public OpenDocumentCommand(UIServiceHelper service,
AddToCanExecuteEvaluation(e => true);

_lsp = lsp;
_languageClient = new Lazy<ILanguageClient>(() => lsp.Invoke(), isThreadSafe: true);
}

protected async override Task OnExecuteAsync(object? parameter)
{
var workspace = _workspaces.ActiveWorkspace;
if (workspace != null && parameter is WorkspaceFileUri uri)
if (LanguageClient != null && workspace != null && parameter is WorkspaceFileUri uri)
{
var rootUri = workspace.WorkspaceRoot;
//var root = _workspaces.ActiveWorkspace?.WorkspaceRoot?.LocalPath ?? throw new InvalidOperationException();
//var srcRoot = System.IO.Path.Combine(root, ProjectFile.SourceRoot);
//var relativeUri = uri.OriginalString[1..][srcRoot.Length..];

if (rootUri != null && workspace.TryGetWorkspaceFile(uri, out var file) && file != null && !file.IsMissing && !file.IsLoadError)
if (workspace.WorkspaceRoot != null && workspace.TryGetWorkspaceFile(uri, out var file) && file != null)
{
//&& !file.IsMissing && !file.IsLoadError

UserControl view;
IDocumentTabViewModel document;

if (file is SourceFileDocumentState)
if (file is DocumentState state)
{
document = new VBACodeDocumentTabViewModel(uri, file.Name, file.Text, isReadOnly: false, _showSettingsCommand, _closeToolWindowCommand, _activeDocumentStatus);
view = new SourceCodeEditorControl() { DataContext = document };
if (state is CodeDocumentState codeDocumentState)
{
if (codeDocumentState.Language.Id == SupportedLanguage.VBA.Id)
{
document = new VBACodeDocumentTabViewModel(codeDocumentState, isReadOnly: false, _showSettingsCommand, _closeToolWindowCommand, _activeDocumentStatus, _lsp, Service);
view = new SourceCodeEditorControl() { DataContext = document };
}
else if (codeDocumentState.Language.Id == SupportedLanguage.VB6.Id)
{
document = new VB6CodeDocumentTabViewModel(codeDocumentState, isReadOnly: false, _showSettingsCommand, _closeToolWindowCommand, _activeDocumentStatus, _lsp, Service);
view = new SourceCodeEditorControl() { DataContext = document };
}
else
{
throw new NotSupportedException();
}
}
else
{
switch (file.FileExtension)
{
case "md":
document = new MarkdownDocumentTabViewModel(state, isReadOnly: false, _showSettingsCommand, _closeToolWindowCommand, _activeDocumentStatus);
view = new MarkdownEditorControl() { DataContext = document };
break;
case "rdproj":
document = new RubberduckProjectDocumentTabViewModel(state, isReadOnly: false, _showSettingsCommand, _closeToolWindowCommand, _activeDocumentStatus);
view = new SourceCodeEditorControl() { DataContext = document }; // TODO understand json as a different "language" / make a json language server
break;
default:
document = new TextDocumentTabViewModel(state, isReadOnly: false, _showSettingsCommand, _closeToolWindowCommand, _activeDocumentStatus);
view = new TextEditorControl() { DataContext = document };
break;
}
}

workspace.WorkspaceFileStateChanged += (sender, args) =>
{
if (args.Uri == state.Uri && workspace.TryGetWorkspaceFile(args.Uri, out var updated) && updated != null)
{
document.DocumentState = updated;
}
};
}
else
{
switch (file.FileExtension)
{
case "md":
document = new MarkdownDocumentTabViewModel(uri, file.Name, file.Text, isReadOnly: false, _showSettingsCommand, _closeToolWindowCommand, _activeDocumentStatus);
view = new MarkdownEditorControl() { DataContext = document };
break;
case "rdproj":
document = new RubberduckProjectDocumentTabViewModel(uri, workspace.ProjectName, file.Text, isReadOnly: false, _showSettingsCommand, _closeToolWindowCommand, _activeDocumentStatus);
view = new SourceCodeEditorControl() { DataContext = document }; // TODO understand json as a different "language"
break;
default:
document = new TextDocumentTabViewModel(uri, file.Name, file.Text, isReadOnly: false, _showSettingsCommand, _closeToolWindowCommand, _activeDocumentStatus);
view = new TextEditorControl() { DataContext = document };
break;
}
throw new InvalidOperationException("document state was unexpectedly null.");
}

file = file.WithOpened(true);
file = file with { IsOpened = true };
NotifyLanguageServer(file);

document.ContentControl = view;
_shell.ViewModel.DocumentWindows.Add(document);
_shell.ViewModel.ActiveDocumentTab = document;
}
else
{
throw new FileNotFoundException($"File '{uri}' is present in the workspace folder, but not included in this workspace. Include it in the project?");
}
}

await Task.CompletedTask;
Expand All @@ -109,15 +140,11 @@ private void NotifyLanguageServer(DocumentState file)

var absoluteUri = file.Uri.AbsoluteLocation;

var languageId = file is SourceFileDocumentState
? SupportedLanguage.VBA.Id
: "none";

var textDocumentItem = new TextDocumentItem
{
Uri = absoluteUri,
Version = 1,
LanguageId = languageId,
LanguageId = SupportedLanguage.VBA.Id,
Text = file.Text,
};
lsp.TextDocument.DidOpenTextDocument(new() { TextDocument = textDocumentItem });
Expand Down
Loading
Loading