Core Search & Actions
This chapter covers the core interfaces and data structures in Lertaro.PluginSdk for contributing search data sources, instant calculation answers, non-ASCII alias engines, query suffix token handlers, and static/dynamic context action menus.
1. Base Component Specifications: IPluginComponent & IPlugin
All plugin components inherit directly or indirectly from IPluginComponent:
namespace Lertaro.PluginSdk;
public interface IPluginComponent
{
string Name => GetType().Name; // Display name (defaults to class name)
string Description => string.Empty; // Description shown as a ToolTip in settings
}
public interface IPlugin : IPluginComponent
{
// Primary plugin assembly entry point
}2. Contributing Search Results
Static Cacheable Item Provider ISearchableItemProvider
Ideal for relatively static or slow-to-enumerate items that do not change with every keystroke (e.g. Start Menu shortcuts, browser bookmarks, control panel items):
public interface ISearchableItemProvider : IPluginComponent
{
bool EnableAlias => true; // Allow alias transliteration (e.g. pinyin)
event Action? ItemsChanged; // Trigger when items change to re-index
IEnumerable<SearchableItem> GetSearchableItems();
}Dynamic Instant Calculation Provider IInstantResultProvider
Executes synchronously on every keystroke, ideal for results derived purely from the query string (e.g. calculators, base converters, URL jumpers):
public interface IInstantResultProvider : IPluginComponent
{
IEnumerable<InstantResultItem> GetInstantResults(string query);
bool[]? GetHighlightMask(string text, string query) => null; // Custom highlight mask
}TIP
GetInstantResults is synchronous for typing fluidity. For async network queries (translation, web suggestions), return a placeholder item immediately, fetch data via Task.Run in the background, cache the result, and call SearchRefreshService.RefreshIfMatches to notify the host to refresh live results.
Non-ASCII Alias Transliteration Engine IAliasProvider
Generates indexable transliteration aliases for non-ASCII text, supporting mixed pinyin/character matching:
public interface IAliasProvider
{
string Name { get; }
bool CanHandle(string text);
IReadOnlyList<(char Start, char End)> InputRanges { get; } // Source range (e.g. CJK Ideographs)
IReadOnlyList<(char Start, char End)> OutputRanges { get; } // Target range (e.g. a-z)
IEnumerable<string> GetAliases(string text);
int Version => 1; // Increment to trigger re-indexing
int[]? MapAliasToSourceIndices(string text, string alias) => null; // Highlight mapping
void GetAliasesUtf8(string text, AliasByteSink dest); // Zero-allocation UTF-8 builder
IEnumerable<string> GetQueryForms(string term); // Query-side segmentation
}Query Suffix Token Handler IQueryTokenProvider
Claims and processes trailing tokens at the end of search queries (e.g. report :size, doc :@today, or image ::"hello world"), applying transformations (sorting, filtering) to matched results:
public interface IQueryTokenProvider : IPluginComponent
{
bool CanHandle(string token);
Task<IReadOnlyList<ISearchResult>> ApplyAsync(string token, IReadOnlyList<ISearchResult> results);
}3. Context Actions on Results
Action Provider Container IActionProvider
public interface IActionProvider
{
IEnumerable<ISearchResultAction> GetActions();
IEnumerable<IDynamicActionProvider> GetDynamicActionProviders();
}Static Action Contract ISearchResultAction
Represents a standalone static operation (e.g. Copy Path, Run as Administrator) displayed in Ctrl+O action menus or bound to hotkeys:
public interface ISearchResultAction : IPluginComponent
{
string GroupName { get; } // Group name
string DisplayName { get; } // Action title
string? Hotkey { get; } // Default shortcut (e.g. "Ctrl+Shift+C")
IReadOnlyList<string>? Keywords { get; }
IReadOnlyList<string>? Parameters { get; }
ImageSource Icon { get; } // Action icon
bool IsVisibleInSearch(IReadOnlyList<ISearchResult> selection, SearchWindowType windowType);
bool IsVisibleInMenu(IReadOnlyList<ISearchResult> selection, SearchWindowType windowType);
bool CanExecute(IReadOnlyList<ISearchResult> selection);
void Execute(IReadOnlyList<ISearchResult> selection, IPluginSearchWindow window);
}Dynamic Menu Builder IDynamicActionProvider
Constructs dynamic menus at runtime (such as embedding Windows Shell context menus):
public interface IDynamicActionProvider
{
string GroupName { get; }
int? Priority => 0; // Menu display priority
IReadOnlyList<string>? Keywords { get; }
IReadOnlyList<string>? Parameters { get; }
bool IsVisibleInSearch(IReadOnlyList<ISearchResult> selection, SearchWindowType windowType);
bool IsVisibleInMenu(IReadOnlyList<ISearchResult> selection, SearchWindowType windowType);
void Init() { } // One-time warmup initialization
bool CanProvide(IReadOnlyList<ISearchResult> selection);
IEnumerable<DynamicMenuItem> GetMenuItems(IReadOnlyList<ISearchResult> selection, IntPtr hMenu);
IEnumerable<(string Hotkey, Action Execute)> GetHotkeyActions(IReadOnlyList<ISearchResult> selection);
void ExecuteCommand(IReadOnlyList<ISearchResult> selection, uint commandId, IntPtr ownerHwnd);
void ClearSession() { }
}4. Supporting Models
SearchableItem/InstantResultItem: ContainsTitle,Description,IconData,IconColor,ActionType("Copy"/"Execute"/"None"),ActionArgument,TabCompletion,HBitmapIcon(auto-disposed by host), andOnExecutecallback.DynamicMenuItem: ContainsText,CommandId,IsSeparator,HasSubMenu,SubMenuHandle,IsDisabled,OnExecute,IsHeader(renders as a group header with optional action button).SearchWindowType: Enum withMain,Quick, andInline.