Editor command
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
namespace FileTime.App.Core.Configuration;
|
||||||
|
|
||||||
|
public class ProgramsConfigurationRoot
|
||||||
|
{
|
||||||
|
public ProgramsConfiguration Linux { get; set; } = new();
|
||||||
|
public ProgramsConfiguration Windows { get; set; } = new();
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using FileTime.App.Core.Configuration;
|
||||||
|
|
||||||
|
namespace FileTime.App.Core.Services;
|
||||||
|
|
||||||
|
public interface IProgramsService
|
||||||
|
{
|
||||||
|
ProgramConfiguration? GetEditorProgram(bool getNext = false);
|
||||||
|
void ResetLastGoodEditor();
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace FileTime.App.Core.UserCommand;
|
||||||
|
|
||||||
|
public class EditCommand : IIdentifiableUserCommand
|
||||||
|
{
|
||||||
|
public const string CommandName = "edit";
|
||||||
|
public static readonly EditCommand Instance = new();
|
||||||
|
|
||||||
|
private EditCommand()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public string UserCommandID => CommandName;
|
||||||
|
public string Title => "Edit";
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ namespace FileTime.App.Core.Configuration;
|
|||||||
|
|
||||||
public class MainConfiguration
|
public class MainConfiguration
|
||||||
{
|
{
|
||||||
private static readonly Lazy<List<CommandBindingConfiguration>> _defaultKeybindings = new(InitDefaultKeyBindings);
|
private static readonly Lazy<List<CommandBindingConfiguration>> DefaultKeybindings = new(InitDefaultKeyBindings);
|
||||||
|
|
||||||
public static Dictionary<string, string?> Configuration { get; }
|
public static Dictionary<string, string?> Configuration { get; }
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ public class MainConfiguration
|
|||||||
};
|
};
|
||||||
|
|
||||||
PopulateDefaultEditorPrograms(Configuration);
|
PopulateDefaultEditorPrograms(Configuration);
|
||||||
PopulateDefaultKeyBindings(Configuration, _defaultKeybindings.Value,
|
PopulateDefaultKeyBindings(Configuration, DefaultKeybindings.Value,
|
||||||
SectionNames.KeybindingSectionName + ":" + nameof(KeyBindingConfiguration.DefaultKeyBindings));
|
SectionNames.KeybindingSectionName + ":" + nameof(KeyBindingConfiguration.DefaultKeyBindings));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ public class MainConfiguration
|
|||||||
new(CreateContainer.CommandName, new[] {Keys.C, Keys.C}),
|
new(CreateContainer.CommandName, new[] {Keys.C, Keys.C}),
|
||||||
new(CreateElementCommand.CommandName, new[] {Keys.C, Keys.E}),
|
new(CreateElementCommand.CommandName, new[] {Keys.C, Keys.E}),
|
||||||
//new CommandBindingConfiguration(ConfigCommand.Cut, new[] { Keys.D, Keys.D }),
|
//new CommandBindingConfiguration(ConfigCommand.Cut, new[] { Keys.D, Keys.D }),
|
||||||
//new CommandBindingConfiguration(ConfigCommand.Edit, new KeyConfig(Keys.F4)),
|
new(EditCommand.CommandName, new[] {Keys.F4}),
|
||||||
new(EnterRapidTravelCommand.CommandName, new KeyConfig(Keys.Comma, shift: true)),
|
new(EnterRapidTravelCommand.CommandName, new KeyConfig(Keys.Comma, shift: true)),
|
||||||
new(EnterRapidTravelCommand.CommandName, new KeyConfig(Keys.Question, shift: true)),
|
new(EnterRapidTravelCommand.CommandName, new KeyConfig(Keys.Question, shift: true)),
|
||||||
new(GoBackCommand.CommandName, new KeyConfig(Keys.Left, alt: true)),
|
new(GoBackCommand.CommandName, new KeyConfig(Keys.Left, alt: true)),
|
||||||
@@ -120,23 +120,35 @@ public class MainConfiguration
|
|||||||
|
|
||||||
private static void PopulateDefaultEditorPrograms(Dictionary<string, string?> configuration)
|
private static void PopulateDefaultEditorPrograms(Dictionary<string, string?> configuration)
|
||||||
{
|
{
|
||||||
var editorPrograms = new List<ProgramConfiguration>()
|
var linuxEditorPrograms = new List<ProgramConfiguration>
|
||||||
|
{
|
||||||
|
new(@"gedit"),
|
||||||
|
};
|
||||||
|
var windowsEditorPrograms = new List<ProgramConfiguration>
|
||||||
{
|
{
|
||||||
new(@"c:\Program Files\Notepad++\notepad++.exe"),
|
|
||||||
new("notepad.exe"),
|
new("notepad.exe"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PopulateDefaultEditorPrograms(configuration, linuxEditorPrograms, nameof(ProgramsConfigurationRoot.Linux));
|
||||||
|
PopulateDefaultEditorPrograms(configuration, windowsEditorPrograms, nameof(ProgramsConfigurationRoot.Windows));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PopulateDefaultEditorPrograms(
|
||||||
|
Dictionary<string, string?> configuration,
|
||||||
|
List<ProgramConfiguration> editorPrograms,
|
||||||
|
string os)
|
||||||
|
{
|
||||||
for (var i = 0; i < editorPrograms.Count; i++)
|
for (var i = 0; i < editorPrograms.Count; i++)
|
||||||
{
|
{
|
||||||
if (editorPrograms[i].Path is not { } path) continue;
|
if (editorPrograms[i].Path is not { } path) continue;
|
||||||
configuration.Add(
|
configuration.Add(
|
||||||
$"{SectionNames.ProgramsSectionName}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Path)}",
|
$"{SectionNames.ProgramsSectionName}:{os}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Path)}",
|
||||||
path);
|
path);
|
||||||
|
|
||||||
if (editorPrograms[i].Arguments is { } arguments)
|
if (editorPrograms[i].Arguments is { } arguments)
|
||||||
{
|
{
|
||||||
configuration.Add(
|
configuration.Add(
|
||||||
$"{SectionNames.ProgramsSectionName}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Arguments)}",
|
$"{SectionNames.ProgramsSectionName}:{os}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Arguments)}",
|
||||||
arguments);
|
arguments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
91
src/AppCommon/FileTime.App.Core/Services/ProgramsService.cs
Normal file
91
src/AppCommon/FileTime.App.Core/Services/ProgramsService.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using FileTime.App.Core.Configuration;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace FileTime.App.Core.Services;
|
||||||
|
|
||||||
|
public class ProgramsService : IProgramsService
|
||||||
|
{
|
||||||
|
private enum Os
|
||||||
|
{
|
||||||
|
Linux,
|
||||||
|
Windows,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Os _os;
|
||||||
|
private readonly IOptionsMonitor<ProgramsConfigurationRoot> _configuration;
|
||||||
|
private int _lastGoodEditorProgramIndex;
|
||||||
|
private readonly List<ProgramConfiguration> _lastEditorPrograms = new();
|
||||||
|
|
||||||
|
public ProgramsService(IOptionsMonitor<ProgramsConfigurationRoot> configuration)
|
||||||
|
{
|
||||||
|
_configuration = configuration;
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
_os = Os.Windows;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_os = Os.Linux;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgramConfiguration? GetEditorProgram(bool getNext = false)
|
||||||
|
{
|
||||||
|
GeneratePrograms();
|
||||||
|
|
||||||
|
if (getNext)
|
||||||
|
{
|
||||||
|
_lastGoodEditorProgramIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_lastGoodEditorProgramIndex < 0)
|
||||||
|
{
|
||||||
|
_lastGoodEditorProgramIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_lastEditorPrograms.Count <= _lastGoodEditorProgramIndex)
|
||||||
|
{
|
||||||
|
ResetLastGoodEditor();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _lastEditorPrograms[_lastGoodEditorProgramIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GeneratePrograms()
|
||||||
|
{
|
||||||
|
var programsConfig = _os switch
|
||||||
|
{
|
||||||
|
Os.Windows => _configuration.CurrentValue.Windows,
|
||||||
|
_ => _configuration.CurrentValue.Linux
|
||||||
|
};
|
||||||
|
var programConfigs = programsConfig.EditorPrograms.Count == 0
|
||||||
|
? programsConfig.DefaultEditorPrograms
|
||||||
|
: programsConfig.EditorPrograms.Concat(programsConfig.DefaultEditorPrograms).ToList();
|
||||||
|
|
||||||
|
var generateNew = programConfigs.Count != _lastEditorPrograms.Count;
|
||||||
|
|
||||||
|
if (!generateNew)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < programConfigs.Count; i++)
|
||||||
|
{
|
||||||
|
if (programConfigs[i].Path != _lastEditorPrograms[i].Path
|
||||||
|
|| programConfigs[i].Arguments != _lastEditorPrograms[i].Arguments)
|
||||||
|
{
|
||||||
|
generateNew = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generateNew)
|
||||||
|
{
|
||||||
|
_lastEditorPrograms.Clear();
|
||||||
|
_lastEditorPrograms.AddRange(programConfigs);
|
||||||
|
_lastGoodEditorProgramIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetLastGoodEditor() => _lastGoodEditorProgramIndex = -1;
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ using FileTime.Core.Enums;
|
|||||||
using FileTime.Core.Interactions;
|
using FileTime.Core.Interactions;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Timeline;
|
using FileTime.Core.Timeline;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace FileTime.App.Core.Services.UserCommandHandler;
|
namespace FileTime.App.Core.Services.UserCommandHandler;
|
||||||
|
|
||||||
@@ -22,6 +23,8 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
private readonly IUserCommandHandlerService _userCommandHandlerService;
|
private readonly IUserCommandHandlerService _userCommandHandlerService;
|
||||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||||
private readonly IContainerSizeScanProvider _containerSizeScanProvider;
|
private readonly IContainerSizeScanProvider _containerSizeScanProvider;
|
||||||
|
private readonly IProgramsService _programsService;
|
||||||
|
private readonly ILogger<ToolUserCommandHandlerService> _logger;
|
||||||
private IDeclarativeProperty<IContainer?>? _currentLocation;
|
private IDeclarativeProperty<IContainer?>? _currentLocation;
|
||||||
private IDeclarativeProperty<IItemViewModel?>? _currentSelectedItem;
|
private IDeclarativeProperty<IItemViewModel?>? _currentSelectedItem;
|
||||||
private ITabViewModel? _currentSelectedTab;
|
private ITabViewModel? _currentSelectedTab;
|
||||||
@@ -35,7 +38,9 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
ITimelessContentProvider timelessContentProvider,
|
ITimelessContentProvider timelessContentProvider,
|
||||||
IUserCommandHandlerService userCommandHandlerService,
|
IUserCommandHandlerService userCommandHandlerService,
|
||||||
IContentAccessorFactory contentAccessorFactory,
|
IContentAccessorFactory contentAccessorFactory,
|
||||||
IContainerSizeScanProvider containerSizeScanProvider) : base(appState)
|
IContainerSizeScanProvider containerSizeScanProvider,
|
||||||
|
IProgramsService programsService,
|
||||||
|
ILogger<ToolUserCommandHandlerService> logger) : base(appState)
|
||||||
{
|
{
|
||||||
_systemClipboardService = systemClipboardService;
|
_systemClipboardService = systemClipboardService;
|
||||||
_userCommunicationService = userCommunicationService;
|
_userCommunicationService = userCommunicationService;
|
||||||
@@ -45,6 +50,8 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
_userCommandHandlerService = userCommandHandlerService;
|
_userCommandHandlerService = userCommandHandlerService;
|
||||||
_contentAccessorFactory = contentAccessorFactory;
|
_contentAccessorFactory = contentAccessorFactory;
|
||||||
_containerSizeScanProvider = containerSizeScanProvider;
|
_containerSizeScanProvider = containerSizeScanProvider;
|
||||||
|
_programsService = programsService;
|
||||||
|
_logger = logger;
|
||||||
SaveCurrentLocation(l => _currentLocation = l);
|
SaveCurrentLocation(l => _currentLocation = l);
|
||||||
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
||||||
SaveSelectedTab(t => _currentSelectedTab = t);
|
SaveSelectedTab(t => _currentSelectedTab = t);
|
||||||
@@ -54,16 +61,68 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
new TypeUserCommandHandler<OpenInDefaultFileExplorerCommand>(OpenInDefaultFileExplorer),
|
new TypeUserCommandHandler<OpenInDefaultFileExplorerCommand>(OpenInDefaultFileExplorer),
|
||||||
new TypeUserCommandHandler<CopyNativePathCommand>(CopyNativePath),
|
new TypeUserCommandHandler<CopyNativePathCommand>(CopyNativePath),
|
||||||
new TypeUserCommandHandler<CopyBase64Command>(CopyBase64),
|
new TypeUserCommandHandler<CopyBase64Command>(CopyBase64),
|
||||||
|
new TypeUserCommandHandler<EditCommand>(Edit),
|
||||||
new TypeUserCommandHandler<SearchCommand>(Search),
|
new TypeUserCommandHandler<SearchCommand>(Search),
|
||||||
new TypeUserCommandHandler<ScanSizeCommand>(ScanSize),
|
new TypeUserCommandHandler<ScanSizeCommand>(ScanSize),
|
||||||
new TypeUserCommandHandler<SortItemsCommand>(SortItems),
|
new TypeUserCommandHandler<SortItemsCommand>(SortItems),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task Edit()
|
||||||
|
{
|
||||||
|
if ( _currentSelectedTab?.CurrentSelectedItem.Value?.BaseItem is not IElement {NativePath: { } filePath})
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var getNext = false;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
string? execPath = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var editorProgram = _programsService.GetEditorProgram(getNext);
|
||||||
|
if (editorProgram is null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editorProgram.Path is { } executablePath)
|
||||||
|
{
|
||||||
|
execPath = executablePath;
|
||||||
|
if (string.IsNullOrWhiteSpace(editorProgram.Arguments))
|
||||||
|
{
|
||||||
|
Process.Start(executablePath, "\"" + filePath + "\"");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var parts = editorProgram.Arguments.Split("%%1");
|
||||||
|
var arguments = string.Join("%%1", parts.Select(p => p.Replace("%1", "\"" + filePath + "\""))).Replace("%%1", "%1");
|
||||||
|
Process.Start(executablePath, arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (System.ComponentModel.Win32Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Error while running editor program, possible the executable path does not exists. {ExecutablePath}", execPath);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Unknown error while running editor program");
|
||||||
|
}
|
||||||
|
|
||||||
|
getNext = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: else
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ScanSize()
|
private async Task ScanSize()
|
||||||
{
|
{
|
||||||
if (_currentLocation?.Value is null) return;
|
if (_currentLocation?.Value is null) return;
|
||||||
|
|
||||||
var searchTask = _containerSizeScanProvider.StartSizeScan(_currentLocation.Value);
|
var searchTask = _containerSizeScanProvider.StartSizeScan(_currentLocation.Value);
|
||||||
var openContainerCommand = new OpenContainerCommand(new AbsolutePath(_timelessContentProvider, searchTask.SizeSizeScanContainer));
|
var openContainerCommand = new OpenContainerCommand(new AbsolutePath(_timelessContentProvider, searchTask.SizeSizeScanContainer));
|
||||||
await _userCommandHandlerService.HandleCommandAsync(openContainerCommand);
|
await _userCommandHandlerService.HandleCommandAsync(openContainerCommand);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public static class Startup
|
|||||||
serviceCollection.TryAddSingleton<ICommandKeysHelperService, CommandKeysHelperService>();
|
serviceCollection.TryAddSingleton<ICommandKeysHelperService, CommandKeysHelperService>();
|
||||||
serviceCollection.TryAddSingleton<IPossibleCommandsService, PossibleCommandsService>();
|
serviceCollection.TryAddSingleton<IPossibleCommandsService, PossibleCommandsService>();
|
||||||
serviceCollection.TryAddSingleton<IPossibleCommandsViewModel, PossibleCommandsViewModel>();
|
serviceCollection.TryAddSingleton<IPossibleCommandsViewModel, PossibleCommandsViewModel>();
|
||||||
|
serviceCollection.TryAddSingleton<IProgramsService, ProgramsService>();
|
||||||
|
|
||||||
return serviceCollection
|
return serviceCollection
|
||||||
.AddCommandHandlers()
|
.AddCommandHandlers()
|
||||||
@@ -53,7 +54,7 @@ public static class Startup
|
|||||||
|
|
||||||
internal static IServiceCollection AddConfiguration(this IServiceCollection serviceCollection, IConfigurationRoot configuration) =>
|
internal static IServiceCollection AddConfiguration(this IServiceCollection serviceCollection, IConfigurationRoot configuration) =>
|
||||||
serviceCollection
|
serviceCollection
|
||||||
.Configure<ProgramsConfiguration>(configuration.GetSection(SectionNames.ProgramsSectionName))
|
.Configure<ProgramsConfigurationRoot>(configuration.GetSection(SectionNames.ProgramsSectionName))
|
||||||
.Configure<KeyBindingConfiguration>(configuration.GetSection(SectionNames.KeybindingSectionName))
|
.Configure<KeyBindingConfiguration>(configuration.GetSection(SectionNames.KeybindingSectionName))
|
||||||
.AddSingleton<IConfiguration>(configuration);
|
.AddSingleton<IConfiguration>(configuration);
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,7 @@ public class DefaultIdentifiableCommandHandlerRegister : IStartupHandler
|
|||||||
AddUserCommand(CreateElementCommand.Instance);
|
AddUserCommand(CreateElementCommand.Instance);
|
||||||
AddUserCommand(DeleteCommand.HardDelete);
|
AddUserCommand(DeleteCommand.HardDelete);
|
||||||
AddUserCommand(DeleteCommand.SoftDelete);
|
AddUserCommand(DeleteCommand.SoftDelete);
|
||||||
|
AddUserCommand(EditCommand.Instance);
|
||||||
AddUserCommand(EnterRapidTravelCommand.Instance);
|
AddUserCommand(EnterRapidTravelCommand.Instance);
|
||||||
AddUserCommand(ExitRapidTravelCommand.Instance);
|
AddUserCommand(ExitRapidTravelCommand.Instance);
|
||||||
AddUserCommand(GoBackCommand.Instance);
|
AddUserCommand(GoBackCommand.Instance);
|
||||||
|
|||||||
Reference in New Issue
Block a user