diff --git a/.gitignore b/.gitignore
index 0085abe..a7e41b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -354,3 +354,4 @@ MigrationBackup/
#VSCode
.vscode/
.idea/
+*.lscache
diff --git a/Changelog.md b/Changelog.md
index aa11fd7..6ca59c8 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,11 +1,24 @@
# Changelog
+## 3.1.0
+
+- :star: **Recent pages** is dead, long live **sort by last modified**. ([#32](https://github.com/Odotocodot/Flow.Launcher.Plugin.OneNote/issues/32))
+ - Using the **sort by last modified** keyword, as the name implies, allows you to sort results by last modified. But unlike **recent pages** you can now use it in multiple places, i.e. with **title search**, **scoped search** and **notebook explorer**. Note it must be placed after the aforementioned keywords.
+ - Examples:\
+ (`#` = **sort by last modified** keyword, `*` = **title search** keyword, `nb:\` = **notebook explorer** keyword, `>` = **scoped search** keyword)
+ - ```on #{your search query}```
+ - ```on *#{your search query}```
+ - ```on nb:\PathToItem\#{your search query}```
+ - ```on nb:\PathToItem\>#{your search query}```
+ - ```on nb:\PathToItem\*#{your search query}```
+- Added a setting to allow users to always open items in a new OneNote window. ([#40](https://github.com/Odotocodot/Flow.Launcher.Plugin.OneNote/issues/40))
+
## 3.0.1 - 2026-03-13
- Fix crash on quick note with empty title (Updated to `LinqToOneNote-2.1.1`)
- Fix incorrect **scope search** check
- Cache OneNote hierarchy when applicable
- - This brings the performance improvement for Notebook Explorer from last version to **recent pages** and **title search**
+ - This brings the performance improvement from **notebook explorer** from last version to **recent pages** and **title search**
## 3.0.0 - 2026-03-04
diff --git a/Flow.Launcher.Plugin.OneNote/Icons/IconGeneratorInfo.cs b/Flow.Launcher.Plugin.OneNote/Icons/IconGeneratorInfo.cs
index fdb9d41..30013e5 100644
--- a/Flow.Launcher.Plugin.OneNote/Icons/IconGeneratorInfo.cs
+++ b/Flow.Launcher.Plugin.OneNote/Icons/IconGeneratorInfo.cs
@@ -3,30 +3,27 @@
namespace Flow.Launcher.Plugin.OneNote.Icons
{
- public struct IconGeneratorInfo
+ public readonly struct IconGeneratorInfo
{
public readonly string prefix = string.Empty;
public readonly Color? color;
-
- public IconGeneratorInfo(IOneNoteItem item)
+
+ private IconGeneratorInfo(string prefix, Color? color = null)
+ {
+ this.prefix = prefix;
+ this.color = color;
+ }
+
+ public static IconGeneratorInfo Create(IOneNoteItem item)
{
- switch (item)
+ return item switch
{
- case Notebook n:
- prefix = IconConstants.Notebook;
- color = n.Color;
- break;
- case SectionGroup sg:
- prefix = sg.IsRecycleBin ? IconConstants.RecycleBin : IconConstants.SectionGroup;
- break;
- case Section s:
- prefix = IconConstants.Section;
- color = s.Color;
- break;
- case Page:
- prefix = IconConstants.Page;
- break;
- }
+ Notebook n => new (IconConstants.Notebook, n.Color),
+ SectionGroup sg => new (sg.IsRecycleBin ? IconConstants.RecycleBin : IconConstants.SectionGroup),
+ Section s => new (IconConstants.Section, s.Color),
+ Page => new (IconConstants.Page),
+ _ => new (),
+ };
}
}
}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/Images/logo.png b/Flow.Launcher.Plugin.OneNote/Images/logo.png
index ea9fb28..db3e387 100644
Binary files a/Flow.Launcher.Plugin.OneNote/Images/logo.png and b/Flow.Launcher.Plugin.OneNote/Images/logo.png differ
diff --git a/Flow.Launcher.Plugin.OneNote/Keywords.cs b/Flow.Launcher.Plugin.OneNote/Keywords.cs
index bbb74b5..f92b5b5 100644
--- a/Flow.Launcher.Plugin.OneNote/Keywords.cs
+++ b/Flow.Launcher.Plugin.OneNote/Keywords.cs
@@ -8,26 +8,27 @@ namespace Flow.Launcher.Plugin.OneNote
public class Keywords
{
public const string NotebookExplorerSeparator = "\\";
- public Keyword NotebookExplorer { get; set; } = new($"nb:{NotebookExplorerSeparator}");
- public Keyword RecentPages { get; set; } = new ("rp:");
- public Keyword TitleSearch { get; set; } = new ("*");
- public Keyword ScopedSearch { get; set; } = new (">");
-
+ public Keyword NotebookExplorer { get; init; } = new($"nb:{NotebookExplorerSeparator}");
+ [JsonPropertyName("RecentPages")]
+ public Keyword SortByLastModified { get; init; } = new ("rp:");
+ public Keyword TitleSearch { get; init; } = new ("*");
+ public Keyword ScopedSearch { get; init; } = new (">");
+
+ private Keyword[]? keywords;
+ [JsonIgnore]
+ public Keyword[] All => keywords ??= [NotebookExplorer, SortByLastModified, TitleSearch, ScopedSearch];
}
[JsonConverter(typeof(KeywordJsonConverter))]
- public class Keyword
+ public class Keyword(string value)
{
- public Keyword(string value) => Value = value;
- public string Value { get; private set; }
+ public string Value { get; private set; } = value;
public void ChangeKeyword(string newValue) => Value = newValue;
public int Length => Value.Length;
public static implicit operator string(Keyword keyword) => keyword.Value;
public override string ToString() => Value;
-
- public static Keyword Empty { get; } = new ("");
}
//Needed for legacy as keywords where just saved as a string
@@ -39,5 +40,4 @@ public override Keyword Read(ref Utf8JsonReader reader, Type typeToConvert, Json
public override void Write(Utf8JsonWriter writer, Keyword value, JsonSerializerOptions options)
=> JsonSerializer.Serialize(writer, value.Value, options);
}
-
}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/ResultCreator.cs b/Flow.Launcher.Plugin.OneNote/ResultCreator.cs
index bb954ea..856acc3 100644
--- a/Flow.Launcher.Plugin.OneNote/ResultCreator.cs
+++ b/Flow.Launcher.Plugin.OneNote/ResultCreator.cs
@@ -11,22 +11,12 @@
namespace Flow.Launcher.Plugin.OneNote
{
- public class ResultCreator
+ public class ResultCreator(PluginInitContext context, Settings settings, IconProvider iconProvider)
{
- private readonly PluginInitContext context;
- private readonly Settings settings;
- private readonly IconProvider iconProvider;
-
private const string PathSeparator = " > ";
private const string BulletPoint = "\u2022 ";
private const string TrianglePoint = "\u2023 ";
private string ActionKeyword => context.CurrentPluginMetadata.ActionKeyword;
- public ResultCreator(PluginInitContext context, Settings settings, IconProvider iconProvider)
- {
- this.settings = settings;
- this.iconProvider = iconProvider;
- this.context = context;
- }
private static string GetNicePath(IOneNoteItem item, string separator = PathSeparator) => item.GetRelativePath(false, separator);
@@ -84,14 +74,14 @@ public List EmptyQuery()
new Result
{
Title = "See recent pages",
- SubTitle = $"Type \"{settings.Keywords.RecentPages}\" or select this option to see recently modified pages",
- AutoCompleteText = $"{ActionKeyword} {settings.Keywords.RecentPages}",
+ SubTitle = $"Type \"{settings.Keywords.SortByLastModified}\" or select this option to see recently modified pages",
+ AutoCompleteText = $"{ActionKeyword} {settings.Keywords.SortByLastModified}",
IcoPath = iconProvider.Recent,
AddSelectedCount = false,
Score = -1000,
Action = _ =>
{
- context.API.ChangeQuery($"{ActionKeyword} {settings.Keywords.RecentPages}", true);
+ context.API.ChangeQuery($"{ActionKeyword} {settings.Keywords.SortByLastModified}", true);
return false;
},
},
@@ -104,7 +94,7 @@ public List EmptyQuery()
PreviewPanel = GetNewPagePreviewPanel(null, null),
Action = _ =>
{
- OneNoteApp.CreateQuickNote(OpenMode.ExistingOrNewWindow);
+ OneNoteApp.CreateQuickNote(settings.AlwaysOpenInNewWindow ? OpenMode.NewWindow : OpenMode.ExistingOrNewWindow);
WindowHelper.FocusOneNote();
return true;
},
@@ -142,7 +132,7 @@ public Result CreateOneNoteItemResult(IOneNoteItem item, bool actionIsAutoComple
var toolTip = string.Empty;
var subTitle = GetNicePath(item);
var autoCompleteText = GetAutoCompleteText(item);
- var iconInfo = new IconGeneratorInfo(item);
+ var iconInfo = IconGeneratorInfo.Create(item);
switch (item)
{
@@ -213,27 +203,27 @@ public Result CreateOneNoteItemResult(IOneNoteItem item, bool actionIsAutoComple
await Task.Run(() =>
{
item.Sync();
- item.Open();
+ OneNoteApp.Open(item, settings.AlwaysOpenInNewWindow);
});
WindowHelper.FocusOneNote();
return true;
},
};
}
-
- public Result CreatePageResult(Page page, string query)
- => CreateOneNoteItemResult(page, false, string.IsNullOrWhiteSpace(query) ? null : context.API.FuzzySearch(query, page.Name).MatchData);
- public Result CreateRecentPageResult(Page page)
+ public Result CreateRecentItemResult(IOneNoteItem item, bool actionIsAutoComplete, List? highlightData = null)
{
- var result = CreateOneNoteItemResult(page, false);
- result.SubTitle = $"{page.LastModified.Humanize()} | {result.SubTitle}";
- result.IcoPath = iconProvider.Recent;
+ var result = CreateOneNoteItemResult(item, actionIsAutoComplete, highlightData);
+ result.SubTitle = string.IsNullOrWhiteSpace(result.SubTitle)
+ ? $"{item.LastModified.Humanize()}"
+ : $"{item.LastModified.Humanize()} | {result.SubTitle}";
+ if(item is Page)
+ result.IcoPath = iconProvider.Recent;
result.AddSelectedCount = false;
return result;
}
- //When name can have invalid chars
+ //When new name can have invalid chars
private Result CreateNewItemResult(string newName, TParent? parent, string iconPath, Func createFunc)
where TNew : IOneNoteItem, INameInvalidCharacters
where TParent : IOneNoteItem
@@ -261,7 +251,10 @@ private Result CreateNewItemResult(string newName, TParent? paren
return false;
bool showOneNote = !c.SpecialKeyState.CtrlPressed;
- createFunc(parent, newName, showOneNote ? OpenMode.ExistingOrNewWindow : OpenMode.None);
+ bool newWindow = settings.AlwaysOpenInNewWindow;
+
+ OpenMode openMode = showOneNote ? newWindow ? OpenMode.NewWindow : OpenMode.ExistingOrNewWindow : OpenMode.None;
+ createFunc(parent, newName, openMode);
context.API.ReQuery();
@@ -291,18 +284,27 @@ public List ContextMenu(Result selectedResult)
var results = new List();
if (selectedResult.ContextData is IOneNoteItem item)
{
- var result = CreateOneNoteItemResult(item, false);
- result.Title = $"Open and sync \"{item.Name}\"";
- result.SubTitle = string.Empty;
- result.Score = 30;
- result.AddSelectedCount = false;
- result.ContextData = null;
- results.Add(result);
+ Result.IconDelegate icon = iconProvider.GetIcon(IconGeneratorInfo.Create(item));
+ results.Add(new Result
+ {
+ Title = $"Open and sync \"{item.Name}\"",
+ Icon = icon,
+ Score = 30,
+ AddSelectedCount = false,
+ Action = _ =>
+ {
+ OneNoteApp.Open(item);
+ OneNoteApp.SyncItem(item);
+ WindowHelper.FocusOneNote();
+ return true;
+ }
+ });
+
results.Add(new Result
{
Title = $"Open \"{item.Name}\" in new OneNote window",
- Icon = result.Icon,
+ Icon = icon,
Score = 20,
AddSelectedCount = false,
Action = _ =>
@@ -381,7 +383,7 @@ Result EmptyCollectionResult(string title, string iconPath, string? subTitle = n
}
private Lazy GetNewPagePreviewPanel(Section? section, string? pageTitle)
- => new(() => new NewOneNotePagePreviewPanel(context, section, pageTitle));
+ => new(() => new NewOneNotePagePreviewPanel(context, settings, section, pageTitle));
public static List NoMatchesFound()
{
diff --git a/Flow.Launcher.Plugin.OneNote/Search/DefaultSearch.cs b/Flow.Launcher.Plugin.OneNote/Search/DefaultSearch.cs
deleted file mode 100644
index 150042f..0000000
--- a/Flow.Launcher.Plugin.OneNote/Search/DefaultSearch.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using OneNoteApp = LinqToOneNote.OneNote;
-
-namespace Flow.Launcher.Plugin.OneNote.Search
-{
- public class DefaultSearch(PluginInitContext context, Settings settings, ResultCreator resultCreator)
- : SearchBase(context, settings, resultCreator, Keyword.Empty)
- {
- public override List GetResults(Query query)
- {
- string search = query.Search;
- if (!char.IsLetterOrDigit(search[0]))
- {
- return resultCreator.InvalidQuery();
- }
-
- return OneNoteApp.FindPages(search)
- .Select(pg => resultCreator.CreatePageResult(pg, search))
- .ToList();
- }
- }
-}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/Search/NotebookExplorer.cs b/Flow.Launcher.Plugin.OneNote/Search/NotebookExplorer.cs
index d7e5efc..2e8674a 100644
--- a/Flow.Launcher.Plugin.OneNote/Search/NotebookExplorer.cs
+++ b/Flow.Launcher.Plugin.OneNote/Search/NotebookExplorer.cs
@@ -1,46 +1,53 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using LinqToOneNote;
using LinqToOneNote.Abstractions;
-using OneNoteApp = LinqToOneNote.OneNote;
namespace Flow.Launcher.Plugin.OneNote.Search
{
- public class NotebookExplorer(PluginInitContext context, Settings settings, ResultCreator resultCreator, TitleSearch titleSearch, RootCache rootCache)
- : SearchBase(context, settings, resultCreator, settings.Keywords.NotebookExplorer)
+ public class NotebookExplorer(PluginInitContext context, Settings settings, ResultCreator resultCreator, TitleSearch titleSearch, StandardSearch standardSearch)
+ : SearchBase(context, settings, resultCreator)
{
- public override List GetResults(Query query)
+ private readonly Explorer explorer = new(context, settings, resultCreator);
+ private readonly Keywords keywords = settings.Keywords;
+
+ protected override List GetResultsInternal(ref SearchData searchData)
{
- if (!ValidateSearch(query, out string? search, out IOneNoteItem? parent, out IEnumerable collection))
+ if (!ValidateSearch(ref searchData))
return resultCreator.InvalidQuery(false);
- List results = search switch
+ Keyword? keyword = SearchExtensions.GetKeyword(ref searchData, keywords);
+
+ IOneNoteItem? parent = searchData.Parent;
+ SearchBase searchBase = (keyword, parent) switch
{
- { } when search.StartsWithOrd(Keywords.TitleSearch) && parent is not Page => titleSearch.Filter(search, parent, collection),
- { } when search.StartsWithOrd(Keywords.ScopedSearch) && parent is INotebookOrSectionGroup => ScopedSearch(search, parent),
- { } when !string.IsNullOrWhiteSpace(search) => Explorer(search, parent, collection),
- _ => ShowAll(parent, collection),
+ (not null, not Page) when keyword == keywords.TitleSearch => titleSearch,
+ (not null, INotebookOrSectionGroup) when keyword == keywords.ScopedSearch => standardSearch,
+ _ => explorer,
};
+ var results = searchBase.GetResults(ref searchData);
+
if (parent == null)
return results;
Result result = resultCreator.CreateOneNoteItemResult(parent, false, score: Result.MaxScore);
result.Title = $"Open \"{parent.Name}\" in OneNote";
- result.SubTitle = $"Use \'{Keywords.ScopedSearch}\' to search this item. Use \'{Keywords.TitleSearch}\' to search by title in this item";
+ result.SubTitle = $"Use \'{keywords.ScopedSearch}\' to search this item. Use \'{keywords.TitleSearch}\' to search by title in this item. Use \'{keywords.SortByLastModified}\' to sort by recently modified";
results.Add(result);
return results;
}
-
- private bool ValidateSearch(Query query, out string? lastSearch, out IOneNoteItem? parent, out IEnumerable collection)
+
+ private static bool ValidateSearch(ref SearchData searchData)
{
- lastSearch = null;
- parent = null;
-
- collection = rootCache.Root.Notebooks;
+ (var search, IOneNoteItem? parent, IEnumerable? collection, _) = searchData;
+
+ //From SearchManager.Query SearchData
+ //parent is null here
+ //collection is rootCache.Root.Notebooks as this functions validates the search with the whole query;
- string search = query.Search[(query.Search.IndexOf(Keywords.NotebookExplorer, StringComparison.Ordinal) + Keywords.NotebookExplorer.Length)..];
const string separator = Keywords.NotebookExplorerSeparator;
var currIndex = search.IndexOf(separator, StringComparison.Ordinal);
var prevIndex = 0;
@@ -48,7 +55,7 @@ private bool ValidateSearch(Query query, out string? lastSearch, out IOneNoteIte
while (currIndex != -1)
{
var itemName = search[prevIndex..currIndex];
- parent = collection.FirstOrDefault(item => item.Name == itemName);
+ parent = collection?.FirstOrDefault(item => item.Name == itemName);
if (parent == null)
return false;
@@ -58,69 +65,78 @@ private bool ValidateSearch(Query query, out string? lastSearch, out IOneNoteIte
currIndex = search.IndexOf(separator, currIndex + separator.Length, StringComparison.Ordinal);
}
- lastSearch = search[prevIndex..];
+ searchData.Search = search[prevIndex..];
+ searchData.Parent = parent;
+ searchData.Collection = collection;
return true;
}
+
+ protected override List EmptySearch(ref SearchData searchData) => explorer.GetResults(ref searchData);
- private List ShowAll(IOneNoteItem? parent, IEnumerable collection)
- {
- var results = collection.FilterBySettings(settings)
- .Select(item => resultCreator.CreateOneNoteItemResult(item, true))
- .ToList();
-
- return results.Count != 0 ? results : resultCreator.EmptyCollection(results, parent);
- }
-
- private List ScopedSearch(string query, IOneNoteItem parent)
+ private class Explorer(PluginInitContext context, Settings settings, ResultCreator resultCreator) : SearchBase(context, settings, resultCreator)
{
- if (query.Length == Keywords.ScopedSearch.Length)
- return resultCreator.SearchType("Now searching all pages", parent.Name);
+ protected override List GetResultsInternal(ref SearchData searchData)
+ {
+ var (search, parent, collection, sortOrder) = searchData;
- if (!char.IsLetterOrDigit(query[Keywords.ScopedSearch.Length]))
- return resultCreator.InvalidQuery();
+ Debug.Assert(collection != null, nameof(collection) + " != null");
+
+ var searchResults = collection.FilterBySettings(settings).FuzzySearch(search, context);
+ var results = sortOrder switch
+ {
+ SortOrder.RecentlyModified => searchResults.OrderByDescending(sr => sr.Item.LastModified)
+ .Select(sr => resultCreator.CreateRecentItemResult(sr.Item, true, sr.HighlightData))
+ .ToList(),
+ _ => searchResults.Select(sr => resultCreator.CreateOneNoteItemResult(sr.Item, true, sr.HighlightData, sr.Score))
+ .ToList(),
+ };
- string currentSearch = query[Keywords.ScopedSearch.Length..];
+ // If parent is a section, pages inside can have the same name
+ if (parent is not Section && results.Any(result => string.Equals(search.Trim(), result.Title, StringComparison.OrdinalIgnoreCase)))
+ return results;
- var results = OneNoteApp.FindPages(currentSearch, parent)
- .Select(pg => resultCreator.CreatePageResult(pg, currentSearch))
- .ToList();
+ if (parent?.IsInRecycleBin() == true)
+ return results;
- return results.Count != 0 ? results : ResultCreator.NoMatchesFound();
- }
-
- private List Explorer(string search, IOneNoteItem? parent, IEnumerable collection)
- {
- var results = collection.FilterBySettings(settings)
- .FuzzySearch(search, context)
- .Select(r => resultCreator.CreateOneNoteItemResult(r.Item, true, r.HighlightData, r.Score))
- .ToList();
+ //Add option to create new items
+ switch (parent)
+ {
+ case null:
+ results.Add(resultCreator.CreateNewNotebookResult(search));
+ break;
+ case INotebookOrSectionGroup x:
+ results.Add(resultCreator.CreateNewSectionResult(search, x));
+ results.Add(resultCreator.CreateNewSectionGroupResult(search, x));
+ break;
+ case Section section:
+ if (!section.Locked)
+ {
+ results.Add(resultCreator.CreateNewPageResult(search, section));
+ }
+ break;
+ }
- // If parent is a section, pages inside can have the same name
- if (parent is not Section && results.Any(result => string.Equals(search.Trim(), result.Title, StringComparison.OrdinalIgnoreCase)))
- return results;
-
- if (parent?.IsInRecycleBin() == true)
return results;
+ }
- //Add option to create new items
- switch (parent)
+ protected override List EmptySearch(ref SearchData searchData)
{
- case null:
- results.Add(resultCreator.CreateNewNotebookResult(search));
- break;
- case INotebookOrSectionGroup x:
- results.Add(resultCreator.CreateNewSectionResult(search, x));
- results.Add(resultCreator.CreateNewSectionGroupResult(search, x));
- break;
- case Section section:
- if (!section.Locked)
- {
- results.Add(resultCreator.CreateNewPageResult(search, section));
- }
- break;
+ var (_, parent, collection, sortOrder) = searchData;
+
+ Debug.Assert(collection != null);
+ var results = sortOrder switch
+ {
+ SortOrder.RecentlyModified => collection.FilterBySettings(settings)
+ .OrderByDescending(item => item.LastModified)
+ .Select(item => resultCreator.CreateRecentItemResult(item, true))
+ .ToList(),
+ _ => collection.FilterBySettings(settings)
+ .Select(item => resultCreator.CreateOneNoteItemResult(item, true))
+ .ToList(),
+ };
+
+ return results.Count != 0 ? results : resultCreator.EmptyCollection(results, parent);
}
-
- return results;
}
}
}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/Search/RecentPages.cs b/Flow.Launcher.Plugin.OneNote/Search/RecentPages.cs
deleted file mode 100644
index 41f7129..0000000
--- a/Flow.Launcher.Plugin.OneNote/Search/RecentPages.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using LinqToOneNote;
-
-namespace Flow.Launcher.Plugin.OneNote.Search
-{
- public class RecentPages(PluginInitContext context, Settings settings, ResultCreator resultCreator, RootCache rootCache)
- : SearchBase(context, settings, resultCreator, settings.Keywords.RecentPages)
- {
- public override List GetResults(Query query)
- {
- int count = settings.DefaultRecentsCount;
- string search = query.Search;
- if (search.Length > keyword.Length && int.TryParse(search[keyword.Length..], out int userChosenCount))
- count = userChosenCount;
-
- return rootCache.Root
- .Notebooks
- .GetAllPages()
- .FilterBySettings(settings)
- .OrderByDescending(pg => pg.LastModified)
- .Take(count)
- .Select(resultCreator.CreateRecentPageResult)
- .ToList();
- }
- }
-}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/Search/SearchBase.cs b/Flow.Launcher.Plugin.OneNote/Search/SearchBase.cs
index 12bc90f..67cbc0a 100644
--- a/Flow.Launcher.Plugin.OneNote/Search/SearchBase.cs
+++ b/Flow.Launcher.Plugin.OneNote/Search/SearchBase.cs
@@ -2,13 +2,17 @@
namespace Flow.Launcher.Plugin.OneNote.Search
{
- public abstract class SearchBase(PluginInitContext context, Settings settings, ResultCreator resultCreator, Keyword keyword)
+ public abstract class SearchBase(PluginInitContext context, Settings settings, ResultCreator resultCreator)
{
- protected readonly PluginInitContext context = context;
- protected readonly Settings settings = settings;
protected readonly ResultCreator resultCreator = resultCreator;
- public readonly Keyword keyword = keyword;
- protected Keywords Keywords => settings.Keywords;
- public abstract List GetResults(Query query);
+ protected readonly Settings settings = settings;
+ protected readonly PluginInitContext context = context;
+ protected abstract List GetResultsInternal(ref SearchData searchData);
+ protected abstract List EmptySearch(ref SearchData searchData);
+
+ public List GetResults(ref SearchData searchData) =>
+ string.IsNullOrWhiteSpace(searchData.Search)
+ ? EmptySearch(ref searchData)
+ : GetResultsInternal(ref searchData);
}
}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/Search/SearchExtensions.cs b/Flow.Launcher.Plugin.OneNote/Search/SearchExtensions.cs
index 20ac402..08ee964 100644
--- a/Flow.Launcher.Plugin.OneNote/Search/SearchExtensions.cs
+++ b/Flow.Launcher.Plugin.OneNote/Search/SearchExtensions.cs
@@ -1,14 +1,27 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using Flow.Launcher.Plugin.SharedModels;
using LinqToOneNote;
namespace Flow.Launcher.Plugin.OneNote.Search
{
- public record struct SearchResult(T Item, List? HighlightData, int Score) where T : IOneNoteItem;
+ public enum SortOrder
+ {
+ Default = 0,
+ RecentlyModified = 1,
+ }
+
+ //Parent => parent of the current item/search area
+ //Collection => children of the parent, if parent == null; Collection = rootCache.Root.Notebooks
+ public record struct SearchData(string Search, IOneNoteItem? Parent, IEnumerable? Collection, SortOrder SortOrder);
+
+ public record SearchResult(T Item, List? HighlightData, int Score) where T : IOneNoteItem;
+
public static class SearchExtensions
{
- public static IEnumerable> FuzzySearch(this IEnumerable source, string search, PluginInitContext context) where T: IOneNoteItem
+ public static IEnumerable> FuzzySearch(this IEnumerable source, string search, PluginInitContext context)
+ where T : IOneNoteItem
{
foreach (var item in source)
{
@@ -19,31 +32,63 @@ public static IEnumerable> FuzzySearch(this IEnumerable so
}
}
}
+
public static IEnumerable FilterBySettings(this IEnumerable source, Settings settings) where T : IOneNoteItem
{
- foreach (var item in source)
+ return source.Where(item =>
{
- var success = true;
if (!settings.ShowEncrypted && item is Section section)
{
- success = !section.Encrypted;
+ return !section.Encrypted;
}
- if (!settings.ShowRecycleBin && item.IsInRecycleBin())
- {
- success = false;
- }
+ return settings.ShowRecycleBin || !item.IsInRecycleBin();
+ });
+ }
+
+ public static IEnumerable Take(this IEnumerable source, Settings settings) =>
+ settings.UseMaxResults
+ ? source.Take(settings.MaxResults)
+ : source;
+
+ ///
+ /// Gets the keyword from the search, and removes it from the search string. Also gets the sort order
+ ///
+ ///
+ ///
+ ///
+ public static Keyword? GetKeyword(ref SearchData searchData, Keywords keywords)
+ {
+ Keyword? keyword = null;
+ var searchSpan = searchData.Search.AsSpan();
+
+ for (var i = 0; i < keywords.All.Length; i++)
+ {
+ Keyword key = keywords.All[i];
+ if (!StartsWithKeyword(ref searchSpan, key))
+ continue;
+
+ keyword = key;
+ break;
+ }
+
+ if (keyword == keywords.SortByLastModified || StartsWithKeyword(ref searchSpan, keywords.SortByLastModified))
+ searchData.SortOrder = SortOrder.RecentlyModified;
- if (success)
+ searchData.Search = searchSpan.ToString();
+ return keyword;
+
+ //Check if starts with keyword and if so trim the keyword
+ static bool StartsWithKeyword(ref ReadOnlySpan searchSpan, Keyword keyword)
+ {
+ if (searchSpan.StartsWith(keyword.Value.AsSpan(), StringComparison.Ordinal))
{
- yield return item;
+ searchSpan = searchSpan[keyword.Length..];
+ return true;
}
- }
- }
- public static bool StartsWithOrd(this string str, string value)
- {
- return str.StartsWith(value, StringComparison.Ordinal);
+ return false;
+ }
}
}
}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/Search/SearchManager.cs b/Flow.Launcher.Plugin.OneNote/Search/SearchManager.cs
index ed56c56..8d8683d 100644
--- a/Flow.Launcher.Plugin.OneNote/Search/SearchManager.cs
+++ b/Flow.Launcher.Plugin.OneNote/Search/SearchManager.cs
@@ -4,36 +4,42 @@ namespace Flow.Launcher.Plugin.OneNote.Search
{
public class SearchManager
{
- private readonly TitleSearch titleSearch;
+ private readonly Keywords keywords;
private readonly NotebookExplorer notebookExplorer;
- private readonly DefaultSearch defaultSearch;
- private readonly RecentPages recentPages;
- private readonly RootCache rootCache;
- public RootCache RootCache => rootCache;
+ private readonly StandardSearch standardSearch;
+ private readonly TitleSearch titleSearch;
+ public RootCache RootCache { get; }
public SearchManager(PluginInitContext context, Settings settings, ResultCreator resultCreator)
{
- rootCache = new RootCache();
- titleSearch = new TitleSearch(context, settings, resultCreator, rootCache);
- notebookExplorer = new NotebookExplorer(context, settings, resultCreator, titleSearch, rootCache);
- recentPages = new RecentPages(context, settings, resultCreator, rootCache);
- defaultSearch = new DefaultSearch(context, settings, resultCreator);
+ standardSearch = new StandardSearch(context, settings, resultCreator);
+ titleSearch = new TitleSearch(context, settings, resultCreator);
+ notebookExplorer = new NotebookExplorer(context, settings, resultCreator, titleSearch, standardSearch);
+
+ RootCache = new RootCache();
+ keywords = settings.Keywords;
}
public List Query(Query query)
{
if (query.IsReQuery)
{
- rootCache.SetDirty();
+ RootCache.SetDirty();
}
- string search = query.Search;
- return search switch
+
+ var searchData = new SearchData(query.Search, null, RootCache.Root.Notebooks, SortOrder.Default);
+ Keyword? keyword = SearchExtensions.GetKeyword(ref searchData, keywords);
+
+ SearchBase searchBase = keyword switch
{
- { } when search.StartsWithOrd(titleSearch.keyword) => titleSearch.GetResults(query),
- { } when search.StartsWithOrd(notebookExplorer.keyword) => notebookExplorer.GetResults(query),
- { } when search.StartsWithOrd(recentPages.keyword) => recentPages.GetResults(query),
- _ => defaultSearch.GetResults(query),
+ not null when keyword == keywords.NotebookExplorer => notebookExplorer,
+ not null when keyword == keywords.TitleSearch => titleSearch,
+ _ => standardSearch,
};
+
+ var results = searchBase.GetResults(ref searchData);
+
+ return results.Count != 0 ? results : ResultCreator.NoMatchesFound();
}
}
}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/Search/StandardSearch.cs b/Flow.Launcher.Plugin.OneNote/Search/StandardSearch.cs
new file mode 100644
index 0000000..f8e0ed7
--- /dev/null
+++ b/Flow.Launcher.Plugin.OneNote/Search/StandardSearch.cs
@@ -0,0 +1,50 @@
+using System.Collections.Generic;
+using System.Linq;
+using LinqToOneNote;
+
+namespace Flow.Launcher.Plugin.OneNote.Search
+{
+ public class StandardSearch(PluginInitContext context, Settings settings, ResultCreator resultCreator) : SearchBase(context, settings, resultCreator)
+ {
+ protected override List GetResultsInternal(ref SearchData searchData)
+ {
+ var (search, parent, _, sortOrder) = searchData;
+
+ if (!char.IsLetterOrDigit(search[0]))
+ return resultCreator.InvalidQuery();
+
+ IEnumerable pages = parent is null
+ ? LinqToOneNote.OneNote.FindPages(search)
+ : LinqToOneNote.OneNote.FindPages(search, parent);
+
+ return sortOrder switch
+ {
+ SortOrder.RecentlyModified => pages.OrderByDescending(pg => pg.LastModified)
+ .Take(settings)
+ .Select(pg => resultCreator.CreateRecentItemResult(pg, false))
+ .ToList(),
+ _ => pages.Take(settings)
+ .Select(pg => resultCreator.CreateOneNoteItemResult(pg, false,
+ string.IsNullOrWhiteSpace(search)
+ ? null
+ : context.API.FuzzySearch(search, pg.Name).MatchData))
+ .ToList()
+ };
+ }
+
+ protected override List EmptySearch(ref SearchData searchData)
+ {
+ return searchData.SortOrder switch
+ {
+ SortOrder.RecentlyModified => searchData.Collection
+ .GetAllPages()
+ .FilterBySettings(settings)
+ .OrderByDescending(pg => pg.LastModified)
+ .Take(settings)
+ .Select(pg => resultCreator.CreateRecentItemResult(pg, false))
+ .ToList(),
+ _ => resultCreator.SearchType("Now searching all pages", searchData.Parent?.Name),
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/Search/TitleSearch.cs b/Flow.Launcher.Plugin.OneNote/Search/TitleSearch.cs
index a6649fe..1f5ae54 100644
--- a/Flow.Launcher.Plugin.OneNote/Search/TitleSearch.cs
+++ b/Flow.Launcher.Plugin.OneNote/Search/TitleSearch.cs
@@ -4,25 +4,35 @@
namespace Flow.Launcher.Plugin.OneNote.Search
{
- public class TitleSearch(PluginInitContext context, Settings settings, ResultCreator resultCreator, RootCache rootCache)
- : SearchBase(context, settings, resultCreator, settings.Keywords.TitleSearch)
+ public class TitleSearch(PluginInitContext context, Settings settings, ResultCreator resultCreator) : SearchBase(context, settings, resultCreator)
{
- public override List GetResults(Query query) => Filter(query.Search, null, rootCache.Root.Notebooks);
-
- public List Filter(string query, IOneNoteItem? parent, IEnumerable collection)
+ protected override List GetResultsInternal(ref SearchData searchData)
{
- if (query.Length == keyword.Length)
- return resultCreator.SearchType("Now searching by title", parent?.Name);
-
- var currentSearch = query[keyword.Length..];
-
+ var (search, _, collection, sortOrder) = searchData;
var results = collection.Descendants()
.FilterBySettings(settings)
- .FuzzySearch(currentSearch, context)
- .Select(x => resultCreator.CreateOneNoteItemResult(x.Item, false, x.HighlightData, x.Score))
- .ToList();
+ .FuzzySearch(search, context);
- return results.Count != 0 ? results : ResultCreator.NoMatchesFound();
+ return sortOrder switch
+ {
+ SortOrder.RecentlyModified => results.OrderByDescending(sr => sr.Item.LastModified)
+ .Take(settings)
+ .Select(sr => resultCreator.CreateRecentItemResult(sr.Item, false, sr.HighlightData))
+ .ToList(),
+ _ => results.Take(settings)
+ .Select(sr => resultCreator.CreateOneNoteItemResult(sr.Item, false, sr.HighlightData, sr.Score))
+ .ToList(),
+ };
+ }
+
+ protected override List EmptySearch(ref SearchData searchData)
+ {
+ const string emptySearchPrefix = "Now searching by title";
+ return searchData.SortOrder switch
+ {
+ SortOrder.RecentlyModified => resultCreator.SearchType($"{emptySearchPrefix} ordered by last modified", searchData.Parent?.Name),
+ _ => resultCreator.SearchType(emptySearchPrefix, searchData.Parent?.Name),
+ };
}
}
}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/Settings.cs b/Flow.Launcher.Plugin.OneNote/Settings.cs
index 109321d..455cbe0 100644
--- a/Flow.Launcher.Plugin.OneNote/Settings.cs
+++ b/Flow.Launcher.Plugin.OneNote/Settings.cs
@@ -2,46 +2,64 @@
namespace Flow.Launcher.Plugin.OneNote
{
- public class Settings : UI.Model
- {
- private bool showUnread = true;
- private int defaultRecentsCount = 5;
- private bool showRecycleBin = true;
- private bool showEncrypted;
- private bool createColoredIcons = true;
- private IconTheme iconTheme = IconTheme.Color;
- public Keywords Keywords { get; init; } = new Keywords();
-
- public bool ShowRecycleBin
- {
- get => showRecycleBin;
- set => SetProperty(ref showRecycleBin, value);
- }
- public bool ShowUnread
- {
- get => showUnread;
- set => SetProperty(ref showUnread, value);
- }
- public int DefaultRecentsCount
- {
- get => defaultRecentsCount;
- set => SetProperty(ref defaultRecentsCount, value);
- }
- public bool ShowEncrypted
- {
- get => showEncrypted;
- set => SetProperty(ref showEncrypted, value);
- }
- public bool CreateColoredIcons
- {
- get => createColoredIcons;
- set => SetProperty(ref createColoredIcons, value);
- }
-
- public IconTheme IconTheme
- {
- get => iconTheme;
- set => SetProperty(ref iconTheme, value);
- }
- }
-}
+ public class Settings : UI.Model
+ {
+ private bool showUnread = true;
+ private bool showRecycleBin = true;
+ private bool showEncrypted;
+ private bool createColoredIcons = true;
+ private int maxResults = 30;
+ private bool useMaxResults = true;
+ private bool alwaysOpenInNewWindow = false;
+ private IconTheme iconTheme = IconTheme.Color;
+ public Keywords Keywords { get; init; } = new Keywords();
+
+ public bool ShowRecycleBin
+ {
+ get => showRecycleBin;
+ set => SetProperty(ref showRecycleBin, value);
+ }
+
+ public bool ShowUnread
+ {
+ get => showUnread;
+ set => SetProperty(ref showUnread, value);
+ }
+
+ public int MaxResults
+ {
+ get => maxResults;
+ set => SetProperty(ref maxResults, value);
+ }
+
+ public bool UseMaxResults
+ {
+ get => useMaxResults;
+ set => SetProperty(ref useMaxResults, value);
+ }
+
+ public bool ShowEncrypted
+ {
+ get => showEncrypted;
+ set => SetProperty(ref showEncrypted, value);
+ }
+
+ public bool CreateColoredIcons
+ {
+ get => createColoredIcons;
+ set => SetProperty(ref createColoredIcons, value);
+ }
+
+ public IconTheme IconTheme
+ {
+ get => iconTheme;
+ set => SetProperty(ref iconTheme, value);
+ }
+
+ public bool AlwaysOpenInNewWindow
+ {
+ get => alwaysOpenInNewWindow;
+ set => alwaysOpenInNewWindow = value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin.OneNote/UI/Model.cs b/Flow.Launcher.Plugin.OneNote/UI/Model.cs
index 71699e8..5379f54 100644
--- a/Flow.Launcher.Plugin.OneNote/UI/Model.cs
+++ b/Flow.Launcher.Plugin.OneNote/UI/Model.cs
@@ -1,4 +1,5 @@
-using System.Runtime.CompilerServices;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
namespace Flow.Launcher.Plugin.OneNote.UI
{
@@ -6,7 +7,7 @@ public class Model : BaseModel
{
protected bool SetProperty(ref T field, T newValue, [CallerMemberName] string? propertyName = null)
{
- if (Equals(field, newValue))
+ if (EqualityComparer.Default.Equals(field, newValue))
return false;
field = newValue;
diff --git a/Flow.Launcher.Plugin.OneNote/UI/ViewModels/NewOneNotePageViewModel.cs b/Flow.Launcher.Plugin.OneNote/UI/ViewModels/NewOneNotePageViewModel.cs
index b70c486..9c6adfb 100644
--- a/Flow.Launcher.Plugin.OneNote/UI/ViewModels/NewOneNotePageViewModel.cs
+++ b/Flow.Launcher.Plugin.OneNote/UI/ViewModels/NewOneNotePageViewModel.cs
@@ -12,10 +12,12 @@ public class NewOneNotePageViewModel : Model
private string pageContent = string.Empty;
private readonly Section? section;
private readonly PluginInitContext context;
+ private readonly Settings settings;
- public NewOneNotePageViewModel(PluginInitContext context, Section? section, string? pageTitle)
+ public NewOneNotePageViewModel(PluginInitContext context, Settings settings, Section? section, string? pageTitle)
{
this.context = context;
+ this.settings = settings;
this.section = section;
PageTitle = pageTitle;
CreateCommand = new RelayCommand(() => CreatePage(false));
@@ -33,6 +35,7 @@ private void CreatePage(bool openImmediately)
{
page = OneNoteApp.CreatePage(section, PageTitle);
}
+
var xmlWrap = $"""
@@ -52,7 +55,7 @@ private void CreatePage(bool openImmediately)
context.API.ReQuery();
if (openImmediately)
{
- page.Open();
+ OneNoteApp.Open(page, settings.AlwaysOpenInNewWindow);
context.API.HideMainWindow();
WindowHelper.FocusOneNote();
}
diff --git a/Flow.Launcher.Plugin.OneNote/UI/ViewModels/SettingsViewModel.cs b/Flow.Launcher.Plugin.OneNote/UI/ViewModels/SettingsViewModel.cs
index 91e153a..5b305c5 100644
--- a/Flow.Launcher.Plugin.OneNote/UI/ViewModels/SettingsViewModel.cs
+++ b/Flow.Launcher.Plugin.OneNote/UI/ViewModels/SettingsViewModel.cs
@@ -21,6 +21,7 @@ public SettingsViewModel(PluginInitContext context, Settings settings, IconProvi
Keywords = settings.Keywords //Order is the order they are written in Keywords.cs
.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
+ .Where(p => p.PropertyType == typeof(Keyword))
.Select(p => new KeywordViewModel(p.Name.Humanize(LetterCasing.Title), (Keyword)p.GetValue(settings.Keywords)!))
.ToArray();
IconThemes = Enum.GetValues()
@@ -61,7 +62,6 @@ public SettingsViewModel(PluginInitContext context, Settings settings, IconProvi
public Settings Settings { get; }
public KeywordViewModel[] Keywords { get; }
public KeywordViewModel NotebookExplorerKeyword => Keywords[0];
- public KeywordViewModel RecentPagesKeyword => Keywords[1];
public IconThemeViewModel[] IconThemes { get; }
public string CachedIconsFileSize => iconProvider.GeneratedImagesDirectoryInfo.EnumerateFiles()
.Select(file => file.Length)
diff --git a/Flow.Launcher.Plugin.OneNote/UI/Views/NewOneNotePagePreviewPanel.xaml.cs b/Flow.Launcher.Plugin.OneNote/UI/Views/NewOneNotePagePreviewPanel.xaml.cs
index 4d000ed..a36608a 100644
--- a/Flow.Launcher.Plugin.OneNote/UI/Views/NewOneNotePagePreviewPanel.xaml.cs
+++ b/Flow.Launcher.Plugin.OneNote/UI/Views/NewOneNotePagePreviewPanel.xaml.cs
@@ -8,9 +8,9 @@ namespace Flow.Launcher.Plugin.OneNote.UI.Views
{
public partial class NewOneNotePagePreviewPanel : UserControl
{
- public NewOneNotePagePreviewPanel(PluginInitContext context, Section? section, string? pageTitle)
+ public NewOneNotePagePreviewPanel(PluginInitContext context, Settings settings, Section? section, string? pageTitle)
{
- DataContext = new NewOneNotePageViewModel(context, section, pageTitle);
+ DataContext = new NewOneNotePageViewModel(context, settings, section, pageTitle);
InitializeComponent();
}
private void NewOneNotePagePreviewPanel_OnLoaded(object sender, RoutedEventArgs e)
diff --git a/Flow.Launcher.Plugin.OneNote/UI/Views/SettingsView.xaml b/Flow.Launcher.Plugin.OneNote/UI/Views/SettingsView.xaml
index 0b7745d..aa1e65f 100644
--- a/Flow.Launcher.Plugin.OneNote/UI/Views/SettingsView.xaml
+++ b/Flow.Launcher.Plugin.OneNote/UI/Views/SettingsView.xaml
@@ -19,15 +19,6 @@
-
-
- 1
- 20
-
-
@@ -85,6 +76,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -165,28 +197,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
OneNote for Flow Launcher
@@ -24,11 +24,11 @@ A [OneNote](https://www.microsoft.com/en-gb/microsoft-365/onenote/digital-note-t
- [Installation](#installation)
- [Features](#features)
- [At a Glance](#at-a-glance)
- - [New with Version 2.1.0](#new-with-version-210)
- [Default Search](#default-search)
- [Notebook Explorer](#notebook-explorer)
- [Create New Items](#create-new-items)
- - [Recent Pages](#recent-pages)
+ - [Create Pages](#create-pages)
+ - [Sort by Last Modified](#sort-by-last-modified)
- [Scoped Search](#scoped-search)
- [Title Search](#title-search)
- [Settings](#settings)
@@ -48,7 +48,7 @@ pm install OneNote
> [!IMPORTANT]
>
> - [Versions `2.0+`](Changelog.md#200---2023-10-05) requires Flow Launcher version `1.16+`. For earlier versions see [releases](https://github.com/Odotocodot/Flow.Launcher.Plugin.OneNote/releases).
-> - [Versions `3.0+`](Changelog.md#300---2026-03-04) requires Flow Launcher version `2.1+`.
+> - [Versions `3.0+`](Changelog.md#300---2026-03-04) requires Flow Launcher version `2.1+`.
> - This plugin is local only! It requires an installation of OneNote on you system!
> - Some features require Windows/Microsoft Search to be enabled on your system. See more info [here](#additional-information).
@@ -60,23 +60,21 @@ pm install OneNote
| -------------------------- | --------------------------------------- | ---------------------------- |
| ` on {your search query} ` | [Default Search](#default-search) | Search OneNote pages |
| ` on nb:\ ` | [Notebook Explorer](#notebook-explorer) | Navigate notebooks hierarchy |
-| ` on rp: ` | [Recent Pages](#recent-pages) | View recently modified pages |
#### Modifiers
-| Keyword | Name | Notes |
-| ------- | ------------------------------- | -------------------------------------------- |
-| ` > ` | [Scoped Search](#scoped-search) | Search only within a specific hierarchy item |
-| ` * ` | [Title Search](#title-search) | Search only the title of hierarchy items |
+| Keyword | Name | Notes |
+| ------- | ----------------------------------------------- | -------------------------------------------- |
+| ` > ` | [Scoped Search](#scoped-search) | Search only within a specific hierarchy item |
+| ` * ` | [Title Search](#title-search) | Search only the title of hierarchy items |
+| ` # ` | [Sort by Last Modified](#sort-by-last-modified) | Sort results by last modified |
> [!NOTE]
> Hierarchy items are notebooks, section groups, sections and pages.
-### New with Version 2.1.0
-
-- :star: [New page preview panel](#create-pages) :star: for quickly creating pages with text!
-- Added icons for different themes. The themes available are color, light, dark and one that matches Flow Launcher's current theme. Change it in the settings!
+> [!NOTE]
+> Keywords are customisable in the [settings](#settings).
### Default Search
@@ -140,17 +138,30 @@ This preview panel is available on all *create a page* results in the plugin and

-### Recent Pages
+### Sort by Last Modified
```
-on rp:
+on #{your search query}
```
-Displays your recently modified OneNote pages.
+Displays your results sorted by last modified.
-Add a number after `` rp: `` to display that number of recent pages. E.g. the full query ``on rp:10`` will show the 10 most recently modified pages.
+Can be used with [default search](#default-search), [notebook explorer](#notebook-explorer), [title search](#title-search) and [scoped search](#scoped-search).
-
+
+ Examples
+
+- ```on #{your search query}```
+- ```on *#{your search query}```
+- ```on nb:\PathToItem\#{your search query}```
+- ```on nb:\PathToItem\>#{your search query}```
+- ```on nb:\PathToItem\*#{your search query}```
+
+
+
+
+> [!IMPORTANT]
+> The sort by last modified keyword must be placed after other keywords but before your search.
### Scoped Search
@@ -224,7 +235,7 @@ All the keywords used can be changed according to user preference.
## Changelog
-See [here](Changelog.md) for the full list of changes.
+See [Changelog.md](Changelog.md) for the full list of changes.
## Additional Information
diff --git a/doc/keywords.png b/doc/keywords.png
index 1231593..1d59a9d 100644
Binary files a/doc/keywords.png and b/doc/keywords.png differ
diff --git a/doc/onenote.png b/doc/onenote.png
deleted file mode 100644
index 2fec1ba..0000000
Binary files a/doc/onenote.png and /dev/null differ
diff --git a/doc/settings.png b/doc/settings.png
index 5f3ac27..e63483e 100644
Binary files a/doc/settings.png and b/doc/settings.png differ