Fix crash with empty fullname path
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user