Skip to content

Commit 5b30bb6

Browse files
committed
feat: remove 300-entry cap and add architecture docs
Clipboard history is now unlimited — removed the hard 300-entry prune-on-insert limit. Users can manage history size via the existing auto-prune setting. Added docs/architecture.html: interactive visual explainer covering the full system architecture, search pipeline, paste flow, image processing, data layer, window system, and key design decisions.
1 parent 6b8e404 commit 5b30bb6

6 files changed

Lines changed: 1189 additions & 127 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ All notable changes to this project are documented in this file.
44

55
## [Unreleased]
66

7+
### Changed
8+
9+
- Clipboard history is now unlimited (removed the hard 300-entry cap). Entries accumulate indefinitely; use the auto-prune setting to manage size by age.
10+
11+
### Added
12+
13+
- Architecture documentation: `docs/architecture.html` — interactive visual explainer covering the full system.
14+
715
## [0.2.0] - 2026-02-20
816

917
### Added

Sources/CBManager/ClipboardDatabase.swift

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,17 @@ final class ClipboardDatabase {
2222
sqlite3_close(db)
2323
}
2424

25-
func loadEntries(limit: Int) -> [ClipboardEntry] {
25+
func loadEntries() -> [ClipboardEntry] {
2626
let sql = """
2727
SELECT id, created_at, source_app, kind, content, image_path, ocr_text, ocr_pending,
2828
ai_title, ai_title_pending
2929
FROM clipboard_entries
30-
ORDER BY created_at DESC
31-
LIMIT ?;
30+
ORDER BY created_at DESC;
3231
"""
3332

3433
guard let statement = prepare(sql) else { return [] }
3534
defer { sqlite3_finalize(statement) }
3635

37-
sqlite3_bind_int(statement, 1, Int32(limit))
38-
3936
var result: [ClipboardEntry] = []
4037
while sqlite3_step(statement) == SQLITE_ROW {
4138
let id = string(at: 0, from: statement) ?? UUID().uuidString
@@ -180,22 +177,6 @@ final class ClipboardDatabase {
180177
return removed
181178
}
182179

183-
func prune(limit: Int) {
184-
let sql = """
185-
DELETE FROM clipboard_entries
186-
WHERE id NOT IN (
187-
SELECT id FROM clipboard_entries
188-
ORDER BY created_at DESC
189-
LIMIT ?
190-
);
191-
"""
192-
193-
guard let statement = prepare(sql) else { return }
194-
defer { sqlite3_finalize(statement) }
195-
196-
sqlite3_bind_int(statement, 1, Int32(limit))
197-
sqlite3_step(statement)
198-
}
199180

200181
private func openDatabase() {
201182
guard sqlite3_open(dbPath, &db) == SQLITE_OK else {

Sources/CBManager/ClipboardStore.swift

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ final class ClipboardStore: ObservableObject {
134134
private var pendingImageDeletions: [String: Date] = [:]
135135
private let undoWindow: TimeInterval = 20
136136

137-
private let limit = 300
138137
private let database = ClipboardDatabase()
139138
private let imageDirectory: URL
140139
private let qmdSearch: QMDSearchEngine
@@ -149,7 +148,7 @@ final class ClipboardStore: ObservableObject {
149148
self.imageDirectory = imageDirectory
150149
self.qmdSearch = QMDSearchEngine(baseDirectory: base)
151150

152-
entries = database.loadEntries(limit: limit)
151+
entries = database.loadEntries()
153152

154153
let qmdSearch = self.qmdSearch
155154
Task { [weak self, qmdSearch] in
@@ -282,7 +281,6 @@ final class ClipboardStore: ObservableObject {
282281
generateTitleForImageEntry(newEntry)
283282
}
284283

285-
pruneIfNeeded()
286284
scheduleQMDSearch()
287285
}
288286

@@ -409,24 +407,6 @@ final class ClipboardStore: ObservableObject {
409407
return false
410408
}
411409

412-
private func pruneIfNeeded() {
413-
guard entries.count > limit else { return }
414-
415-
let removed = entries.suffix(from: limit)
416-
entries.removeLast(entries.count - limit)
417-
database.prune(limit: limit)
418-
419-
for entry in removed {
420-
if let path = entry.imagePath {
421-
try? FileManager.default.removeItem(atPath: path)
422-
pendingImageDeletions.removeValue(forKey: path)
423-
}
424-
if isQMDAvailable {
425-
Task { await qmdSearch.remove(id: entry.id) }
426-
}
427-
}
428-
}
429-
430410
private func captureClipboardEntry(from pasteboard: NSPasteboard) -> ClipboardEntry? {
431411
let sourceApp = NSWorkspace.shared.frontmostApplication?.localizedName
432412

0 commit comments

Comments
 (0)