# How Clipboard History Manages Pinned Favorites and Search in vorssaint-utils

> Discover how vorssaint-utils clipboard history manages pinned favorites and search with a dual-section array and a tokenized ranking algorithm that prioritizes pinned items.

- Repository: [vorssaint/vorssaint-utils](https://github.com/vorssaint/vorssaint-utils)
- Tags: internals
- Published: 2026-09-11

---

**The clipboard history system in vorssaint-utils separates pinned favorites from recent items using a dual-section array managed by `ClipboardHistoryService`, while search employs a normalized, tokenized ranking algorithm that prioritizes pinned entries with a +30 bonus and scores matches by exact, prefix, and token relevance.**

The vorssaint-utils repository provides a robust clipboard management system implemented in Swift that handles persistent storage, automatic eviction, and intelligent search. Understanding how the codebase separates pinned favorites from transient history items—and how it ranks search results—requires examining the interplay between [`ClipboardHistoryService.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/ClipboardHistoryService.swift) and [`ClipboardHistorySupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/ClipboardHistorySupport.swift).

## Architecture Overview

The clipboard history implementation divides responsibilities between two primary files in `Sources/Vorssaint/Services/Clipboard/`. The service layer manages the mutable entry list and UI state, while the support layer defines the data models and search algorithms.

- **[`ClipboardHistoryService.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/ClipboardHistoryService.swift)** maintains the master array of entries, handles persistence, and exposes filtered views for the UI.
- **[`ClipboardHistorySupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/ClipboardHistorySupport.swift)** defines `ClipboardHistoryEntry`, search candidates, and the ranking logic used by the filtering system.

This separation allows the search algorithm to remain pure and testable while the service handles side effects like persistence and memory management.

## Pinning Logic and Entry Management

### Entry Model and Pinned State

Each clipboard item is represented by `ClipboardHistoryEntry` in [`ClipboardHistorySupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/ClipboardHistorySupport.swift) (lines 12‑30). The model tracks pinned status through an optional `pinnedAt` timestamp:

```swift
// Conceptual representation from ClipboardHistorySupport.swift
struct ClipboardHistoryEntry {
    let id: UUID
    let content: String
    let timestamp: Date
    var pinnedAt: Date?  // nil = not pinned, Date = pinned with ordering
}

```

When `pinnedAt` is non-nil, the entry belongs to the favorites section. The timestamp itself determines relative order among pinned items.

### Toggle Pin Mechanism

The `togglePin(_:)` method in [`ClipboardHistoryService.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/ClipboardHistoryService.swift) (lines 39‑52) handles state transitions. When pinning an entry, the method moves it to the front of the internal array immediately after the last pinned item. When unpinning, it relocates the entry to the first position of the recent section.

After any modification, the service triggers `normalizeEntryOrder()` to ensure the array maintains the invariant: **all pinned entries precede recent entries**, sorted by `pinnedAt` descending within the pinned group.

### Persistence and Limits

Following normalization, `trimToLimit()` enforces the maximum history size. Critically, pinned entries are exempt from eviction during this trimming phase. The service persists the final array to disk, ensuring favorites survive app relaunches.

Accessing the separated lists is handled through computed properties exposed on the service:

```swift
// In ClipboardHistoryService.swift (lines 11‑18)
let favorites = ClipboardHistoryService.shared.pinnedEntries   // Array of pinned items
let recent = ClipboardHistoryService.shared.recentEntries    // Array of unpinned items

```

## Search and Ranking Algorithm

### Query Processing and Normalization

The entry point for search is `filteredEntries(matching:)` in [`ClipboardHistoryService.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/ClipboardHistoryService.swift) (lines 90‑100). This method maintains an internal cache of the current query string to avoid recomputation across rapid UI updates.

Before scoring, both the query and entry content undergo normalization via `normalized(_:)` in [`ClipboardHistorySupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/ClipboardHistorySupport.swift). This folding process removes diacritics and converts text to a canonical case-insensitive form, ensuring "résumé" matches "resume".

The normalized query is then tokenized on whitespace into `queryTokens`, allowing multi-word searches to match individual components anywhere in the entry text.

### Scoring System

The heavy lifting occurs in `ClipboardHistorySearch.rankedIndexes(...)` (lines 25‑48 of [`ClipboardHistorySupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/ClipboardHistorySupport.swift)). The algorithm evaluates each entry through `score(for:text:normalizedQuery:tokens:isPinned:)` (lines 58‑78), which applies the following hierarchy:

**Base Score Modifiers:**
- **Pinned bonus:** +30 points if `isPinned` is true
- **Exact match:** Highest additional score when query equals entry text exactly
- **Prefix match:** High score when entry text starts with the query
- **Token match:** Moderate score for each token found anywhere in the text
- **Substring match:** Lowest score for simple containment

This weighted approach ensures that a pinned entry containing a token match outranks an unpinned entry with an exact match, keeping favorites visible even with imperfect search terms.

### Result Ordering

After scoring, candidates are sorted by descending score and original index to maintain stability. The method returns entry indexes that the service transforms back into `ClipboardHistoryEntry` objects for UI rendering.

## Implementation Example

Integrating these features into a macOS or iOS application requires minimal boilerplate:

```swift
// Pin or un-pin an entry from user interaction
ClipboardHistoryService.shared.togglePin(selectedEntry)

// Retrieve favorites for a dedicated "Pinned" sidebar section
let pinnedItems = ClipboardHistoryService.shared.pinnedEntries

// Perform live search with relevance ranking
// Results automatically include both pinned and recent items, sorted by score
let searchResults = ClipboardHistoryService.shared.filteredEntries(matching: "swift image")

```

The service automatically manages the cache invalidation, ensuring that subsequent calls with the same query return immediately without recomputing the ranking.

## Summary

- **`ClipboardHistoryEntry`** tracks pinned state via an optional `pinnedAt` timestamp in [`ClipboardHistorySupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/ClipboardHistorySupport.swift).
- **`togglePin(_:)`** moves entries between the pinned and recent sections, followed by `normalizeEntryOrder()` to maintain array invariants.
- **Pinned entries** receive priority placement at the front of the list and are protected from eviction during `trimToLimit()`.
- **Search normalization** removes case and diacritic sensitivity before tokenizing the query on whitespace.
- **Ranking algorithm** adds a +30 bonus to pinned items and scores matches by exact, prefix, token, and substring relevance in `ClipboardHistorySearch.rankedIndexes(...)`.
- **Public API** exposes `pinnedEntries`, `recentEntries`, and `filteredEntries(matching:)` for UI consumption without exposing internal array management.

## Frequently Asked Questions

### How does vorssaint-utils ensure pinned clipboard items persist across app restarts?

The `ClipboardHistoryService` persists the entire entry array—including the `pinnedAt` timestamps—to disk after every mutation. Because pinned entries are stored with their metadata intact, they reload in the correct order when the service initializes, maintaining the separation between favorites and recent items.

### What happens when the clipboard history reaches its size limit?

The `trimToLimit()` method removes oldest entries from the recent section only. Pinned entries are exempt from this eviction logic, ensuring that favorited clipboard items never disappear automatically, regardless of how many new items are copied.

### Why do pinned entries appear higher in search results even with weak matches?

The scoring algorithm in `ClipboardHistorySearch` applies a +30 base bonus to all pinned entries before evaluating text matches. This weighting ensures that a pinned entry with a token match outranks an unpinned entry with an exact match, preserving quick access to favorites during search.

### How does the search handle special characters and accented text?

Both queries and entry content are processed through the `normalized(_:)` function, which performs case folding and diacritic removal. Consequently, searching for "resume" matches "résumé", and the tokenization splits on whitespace to handle multi-word queries gracefully.