Skip to content

LastOpenFilesList is never cleared when startup files are passed or "Open last files" is disabled #686

Description

@Hirogen

Summary

LastOpenFilesList is only cleared inside one branch of LoadStartupFiles. Two common startup paths skip that clear, after which every application close appends the current tabs to the stale list instead of replacing it. The list grows without bound, and once it is read again the user gets tabs they closed sessions ago, opened before the current ones.

Steps to reproduce

  1. Enable Open last files in the preferences.
  2. Start LogExpert normally, open a.log and b.log, close the app.
  3. Start LogExpert by double-clicking c.log in Explorer (i.e. with a command-line file argument). Close the app.
  4. Start LogExpert normally again.

Expected: only c.log is restored.
Actual: a.log, b.log and c.log are restored, with the stale files first. settings.json now holds five entries for three files.

Repeating steps 3–4 keeps growing the list.

The same happens with Open last files disabled: the list is never read and never cleared, so it accumulates silently. Enabling the preference later opens a flood of stale tabs.

Root cause

src/LogExpert.UI/Services/FileOperationService/FileOperationService.cs

ClearLastOpenFilesList() is called from exactly one place — line 353, inside the if (_configManager.Settings.Preferences.OpenLastFiles) branch of LoadStartupFiles, after the reopen loop:

public void LoadStartupFiles (IList<string> lastOpenFiles, string[]? startupFileNames)
{
    if (startupFileNames != null && startupFileNames.Length > 0)
    {
        _ = LoadFilesWithOption(startupFileNames, false);
        return;                                   // <-- no clear
    }

    if (_configManager.Settings.Preferences.OpenLastFiles)   // <-- no clear when false
    {
        foreach (var name in lastOpenFiles.Where(filename => !string.IsNullOrEmpty(filename)))
        {
            _ = AddFileTab(new FileTabRequest { FileName = name });
        }

        _configManager.ClearLastOpenFilesList();
    }
}

SaveLastOpenFilesList (line 330) only ever calls Add, so it depends on that clear having happened:

public void SaveLastOpenFilesList ()
{
    foreach (var logWin in _tabController.GetAllWindowsFromDockPanel().Where(logwin => !logwin.IsTempFile))
    {
        _configManager.Settings.LastOpenFilesList.Add(logWin.GivenFileName);
    }
}

It is invoked unconditionally from OnLogTabWindowFormClosing (src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs:1759), so save and clear are not symmetric.

Duplicate entries do not create duplicate tabs — AddFileTab resolves an existing window by normalized full path (line 66) and activates it instead — so the visible symptoms are unwanted tabs and an ever-growing settings list, not duplicated tabs.

Suggested fix

Make the save total rather than additive, so it no longer depends on a clear elsewhere:

public void SaveLastOpenFilesList ()
{
    _configManager.ClearLastOpenFilesList();

    foreach (var logWin in _tabController.GetAllWindowsFromDockPanel().Where(logwin => !logwin.IsTempFile))
    {
        _configManager.Settings.LastOpenFilesList.Add(logWin.GivenFileName);
    }
}

Alternative: move ClearLastOpenFilesList() in LoadStartupFiles so it runs on every path including the command-line early return. The first option is preferable — it makes the method self-contained and idempotent regardless of how startup went.

Notes

  • src/LogExpert.Tests/Services/FileOperationServiceTests.cs asserts ClearLastOpenFilesList call counts (Times.Never / Times.Once) around lines 803–866 and in the SaveLastOpenFilesList_* tests; those expectations need updating with either fix.
  • Independent of Fix: Open tabs order on next start #685, which addresses the order of the entries this method writes, not their staleness.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions