Fix crash with empty fullname path

This commit is contained in:
2023-02-22 22:13:38 +01:00
parent 28bc479ee4
commit 3dccaa5243
8 changed files with 46 additions and 37 deletions

View File

@@ -128,7 +128,7 @@ public class TabPersistenceService : ITabPersistenceService
if (tab.Path == null) continue;
IContainer? container = null;
var path = new FullName(tab.Path);
var path = FullName.CreateSafe(tab.Path);
while (true)
{
try

View File

@@ -67,7 +67,7 @@ public abstract partial class ItemViewModel : IItemViewModel
IsSelected = itemViewModelType is ItemViewModelType.Main
? parentTab.CurrentSelectedItem.Select(EqualsTo)
: Observable.Return(IsInDeespestPath());
: Observable.Return(IsInDeepestPath());
IsAlternative = sourceCollection.Select(c => c?.Index().FirstOrDefault(i => EqualsTo(i.Value)).Key % 2 == 0);
@@ -92,7 +92,7 @@ public abstract partial class ItemViewModel : IItemViewModel
return BaseItem?.FullName?.Path is string path && path == itemViewModel?.BaseItem?.FullName?.Path;
}
private bool IsInDeespestPath()
private bool IsInDeepestPath()
{
if (_parentTab?.Tab?.LastDeepestSelectedPath is null
|| BaseItem?.FullName is null)
@@ -102,7 +102,7 @@ public abstract partial class ItemViewModel : IItemViewModel
var ownFullName = BaseItem.FullName;
var deepestPath = _parentTab.Tab.LastDeepestSelectedPath;
var commonPath = new FullName(PathHelper.GetCommonPath(ownFullName.Path, deepestPath.Path));
var commonPath = FullName.CreateSafe(PathHelper.GetCommonPath(ownFullName.Path, deepestPath.Path));
return commonPath.Path == ownFullName.Path;
}

View File

@@ -7,11 +7,18 @@ public record FullName(string Path)
var pathParts = Path.TrimEnd(Constants.SeparatorChar).Split(Constants.SeparatorChar);
return pathParts.Length switch
{
> 1 => new(string.Join(Constants.SeparatorChar, pathParts.SkipLast(1))),
> 1 => CreateSafe(string.Join(Constants.SeparatorChar, pathParts.SkipLast(1))),
_ => null
};
}
public static FullName? CreateSafe(string? path)
{
if (string.IsNullOrWhiteSpace(path))
return null;
return new(path);
}
public string GetName()
=> Path.Split(Constants.SeparatorChar).Last();

View File

@@ -55,7 +55,7 @@ public abstract class ContentProviderBase : IContentProvider
protected ContentProviderBase(string name)
{
DisplayName = Name = name;
FullName = new FullName(name);
FullName = FullName.CreateSafe(name);
Extensions = new ExtensionCollection();
_extensions = Extensions.AsReadOnly();
}

View File

@@ -1,10 +1,8 @@
using System.Collections.ObjectModel;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using DynamicData;
using FileTime.Core.ContentAccess;
using FileTime.Core.Enums;
using FileTime.Core.Services;
using FileTime.Core.Timeline;
namespace FileTime.Core.Models;
@@ -28,7 +26,7 @@ public record Container(
ReadOnlyExtensionCollection Extensions,
IObservable<IObservable<IChangeSet<AbsolutePath, string>>?> Items) : IContainer
{
BehaviorSubject<bool> IsLoading { get; } = new BehaviorSubject<bool>(false);
BehaviorSubject<bool> IsLoading { get; } = new(false);
IObservable<bool> IContainer.IsLoading => IsLoading.AsObservable();
public AbsolutePathType Type => AbsolutePathType.Container;
}

View File

@@ -1,7 +1,5 @@
using System.Collections.ObjectModel;
using FileTime.Core.ContentAccess;
using FileTime.Core.Enums;
using FileTime.Core.Services;
using FileTime.Core.Timeline;
namespace FileTime.Core.Models;

View File

@@ -37,7 +37,7 @@ public class Tab : ITab
{
if (_currentSelectedItemCached is not null)
{
LastDeepestSelectedPath = new FullName(PathHelper.GetLongerPath(LastDeepestSelectedPath?.Path, _currentSelectedItemCached.Path.Path));
LastDeepestSelectedPath = FullName.CreateSafe(PathHelper.GetLongerPath(LastDeepestSelectedPath?.Path, _currentSelectedItemCached.Path.Path));
}
})
.Publish(null)
@@ -57,7 +57,7 @@ public class Tab : ITab
.Where(c => c is null)
.Select(_ => (IObservable<IChangeSet<IItem, string>>?)null)
)
.Publish((IObservable<IChangeSet<IItem, string>>?)null)
.Publish(null)
.RefCount();
CurrentSelectedItem =
@@ -96,7 +96,7 @@ public class Tab : ITab
_currentLocation.OnNext(currentLocation);
}
private AbsolutePath? GetSelectedItemByItems(IEnumerable<IItem> items)
private AbsolutePath? GetSelectedItemByItems(IReadOnlyCollection<IItem> items)
{
if (!items.Any()) return null;
@@ -109,7 +109,7 @@ public class Tab : ITab
{
var itemNameToSelect = LastDeepestSelectedPath.Path
.Split(Constants.SeparatorChar)
.Skip((parentPath?.Split(Constants.SeparatorChar).Length) ?? 0)
.Skip(parentPath.Split(Constants.SeparatorChar).Length)
.FirstOrDefault();
var itemToSelect = items.FirstOrDefault(i => i.FullName?.GetName() == itemNameToSelect);
@@ -121,7 +121,7 @@ public class Tab : ITab
}
}
LastDeepestSelectedPath = new FullName(PathHelper.GetLongerPath(LastDeepestSelectedPath?.Path, newSelectedItem.Path.Path));
LastDeepestSelectedPath = FullName.CreateSafe(PathHelper.GetLongerPath(LastDeepestSelectedPath?.Path, newSelectedItem.Path.Path));
return newSelectedItem;
}

View File

@@ -76,11 +76,11 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
{
if ((path?.Length ?? 0) == 0)
{
return Task.FromResult((IItem) this);
return Task.FromResult((IItem)this);
}
else if (Directory.Exists(path))
{
return Task.FromResult((IItem) DirectoryToContainer(
return Task.FromResult((IItem)DirectoryToContainer(
new DirectoryInfo(path!.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar),
pointInTime,
!itemInitializationSettings.SkipChildInitialization)
@@ -88,7 +88,7 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
}
else if (File.Exists(path))
{
return Task.FromResult((IItem) FileToElement(new FileInfo(path), pointInTime));
return Task.FromResult((IItem)FileToElement(new FileInfo(path), pointInTime));
}
var type = forceResolvePathType switch
@@ -120,10 +120,10 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
return forceResolvePathType switch
{
AbsolutePathType.Container => Task.FromResult(
(IItem) CreateEmptyContainer(
(IItem)CreateEmptyContainer(
nativePath,
pointInTime,
Observable.Return(new List<Exception>() {innerException})
Observable.Return(new List<Exception>() { innerException })
)
),
AbsolutePathType.Element => Task.FromResult(CreateEmptyElement(nativePath)),
@@ -142,10 +142,13 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
var fullName = GetFullName(nativePath);
var parentFullName = fullName.GetParent();
var parent = new AbsolutePath(
var parent =
parentFullName is null
? null
: new AbsolutePath(
_timelessContentProvider,
pointInTime,
parentFullName ?? new FullName(""),
parentFullName,
AbsolutePathType.Container);
return new Container(
@@ -208,10 +211,13 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
{
var fullName = GetFullName(directoryInfo.FullName);
var parentFullName = fullName.GetParent();
var parent = new AbsolutePath(
var parent =
parentFullName is null
? null
: new AbsolutePath(
_timelessContentProvider,
pointInTime,
parentFullName ?? new FullName(""),
parentFullName,
AbsolutePathType.Container);
var exceptions = new BehaviorSubject<IEnumerable<Exception>>(Enumerable.Empty<Exception>());
@@ -247,14 +253,14 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
var items = GetItemsByContainer(directoryInfo, pointInTime);
var result = new SourceCache<AbsolutePath, string>(i => i.Path.Path);
if (items.Count == 0) return (IObservable<IChangeSet<AbsolutePath, string>>?) result.Connect().StartWithEmpty();
if (items.Count == 0) return (IObservable<IChangeSet<AbsolutePath, string>>?)result.Connect().StartWithEmpty();
result.AddOrUpdate(items);
return (IObservable<IChangeSet<AbsolutePath, string>>?) result.Connect();
return (IObservable<IChangeSet<AbsolutePath, string>>?)result.Connect();
}
catch (Exception e)
{
exceptions.OnNext(new List<Exception> {e});
exceptions.OnNext(new List<Exception> { e });
}
return null;
@@ -299,10 +305,10 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
private FullName GetFullName(NativePath nativePath) => GetFullName(nativePath.Path);
private FullName GetFullName(string nativePath) =>
new((Name + Constants.SeparatorChar +
FullName.CreateSafe((Name + Constants.SeparatorChar +
string.Join(Constants.SeparatorChar,
nativePath.TrimStart(Constants.SeparatorChar).Split(Path.DirectorySeparatorChar)))
.TrimEnd(Constants.SeparatorChar));
.TrimEnd(Constants.SeparatorChar))!;
public override NativePath GetNativePath(FullName fullName)
{
@@ -328,7 +334,7 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
var size = maxLength ?? realFileSize switch
{
> int.MaxValue => int.MaxValue,
_ => (int) realFileSize
_ => (int)realFileSize
};
var buffer = new byte[size];
await reader.ReadAsync(buffer.AsMemory(0, size), cancellationToken);