From c1c68ba194cf171898723651d1928d6d672a227d Mon Sep 17 00:00:00 2001 From: Alex Rodionov Date: Tue, 10 Sep 2024 07:26:14 -0700 Subject: [PATCH] Fix SwiftLint violations --- .swiftlint.yml | 6 + Maccy/FloatingPanel.swift | 2 +- Maccy/Intents/AppIntentError.swift | 2 +- Maccy/Intents/Get.swift | 5 +- Maccy/Intents/Select.swift | 5 +- Maccy/KeyChord.swift | 3 +- Maccy/KeyShortcut.swift | 7 +- Maccy/Models/HistoryItem.swift | 4 +- Maccy/Observables/AppState.swift | 5 +- Maccy/Observables/Footer.swift | 4 +- Maccy/Observables/FooterItem.swift | 2 +- Maccy/Observables/History.swift | 4 +- Maccy/PopupPosition.swift | 3 +- Maccy/Sorter.swift | 2 + Maccy/Storage.swift | 6 +- Maccy/Views/ConfirmationView.swift | 2 +- MaccyTests/HistoryDecoratorTests.swift | 16 ++- MaccyTests/SearchTests.swift | 176 ++++++++++++++++++++----- 18 files changed, 198 insertions(+), 56 deletions(-) create mode 100644 .swiftlint.yml diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 00000000..be7c8ea9 --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,6 @@ +disabled_rules: + - multiple_closures_with_trailing_closure + - non_optional_string_data_conversion + - todo +line_length: + ignores_comments: true diff --git a/Maccy/FloatingPanel.swift b/Maccy/FloatingPanel.swift index 1aa44c3c..b0362a22 100644 --- a/Maccy/FloatingPanel.swift +++ b/Maccy/FloatingPanel.swift @@ -83,7 +83,7 @@ class FloatingPanel: NSPanel, NSWindowDelegate { newSize.height = min(newHeight, newSize.height) var newOrigin = frame.origin - newOrigin.y = newOrigin.y + (frame.height - newSize.height) + newOrigin.y += (frame.height - newSize.height) NSAnimationContext.runAnimationGroup { (context) in context.duration = 0.2 diff --git a/Maccy/Intents/AppIntentError.swift b/Maccy/Intents/AppIntentError.swift index d8c5aec3..7e8a0c2f 100644 --- a/Maccy/Intents/AppIntentError.swift +++ b/Maccy/Intents/AppIntentError.swift @@ -5,7 +5,7 @@ enum AppIntentError: Swift.Error, CustomLocalizedStringResourceConvertible { var localizedStringResource: LocalizedStringResource { switch self { - case .notFound: return "Clipboard item not found" + case .notFound: return "Clipboard item not found" } } } diff --git a/Maccy/Intents/Get.swift b/Maccy/Intents/Get.swift index d39cac36..bf39e907 100644 --- a/Maccy/Intents/Get.swift +++ b/Maccy/Intents/Get.swift @@ -5,7 +5,10 @@ struct Get: AppIntent, CustomIntentMigratedAppIntent { static let intentClassName = "GetIntent" static var title: LocalizedStringResource = "Get Item from Clipboard History" - static var description = IntentDescription("Gets an item from Maccy clipboard history. The returned item can be used to access its plain/rich/HTML text, image contents or file location.") + static var description = IntentDescription(""" + Gets an item from Maccy clipboard history. + The returned item can be used to access its plain/rich/HTML text, image contents or file location. + """) @Parameter(title: "Selected", default: true) var selected: Bool diff --git a/Maccy/Intents/Select.swift b/Maccy/Intents/Select.swift index 37f2502f..bcfcaa1d 100644 --- a/Maccy/Intents/Select.swift +++ b/Maccy/Intents/Select.swift @@ -4,7 +4,10 @@ struct Select: AppIntent, CustomIntentMigratedAppIntent { static let intentClassName = "SelectIntent" static var title: LocalizedStringResource = "Select Item in Clipboard History" - static var description = IntentDescription("Selects an item in Maccy clipboard history. Depending on Maccy settings, it might trigger pasting of the selected item.") + static var description = IntentDescription(""" + Selects an item in Maccy clipboard history. + Depending on Maccy settings, it might trigger pasting of the selected item. + """) static var parameterSummary: some ParameterSummary { Summary("Select \(\.$number) Item in Clipboard History") diff --git a/Maccy/KeyChord.swift b/Maccy/KeyChord.swift index 03630e32..6bdb79c3 100644 --- a/Maccy/KeyChord.swift +++ b/Maccy/KeyChord.swift @@ -49,7 +49,7 @@ enum KeyChord: CaseIterable { ) } - init(_ key: Key, _ modifierFlags: NSEvent.ModifierFlags) { + init(_ key: Key, _ modifierFlags: NSEvent.ModifierFlags) { // swiftlint:disable:this cyclomatic_complexity switch (key, modifierFlags) { case (.delete, [.command, .option]): self = .clearHistory @@ -91,5 +91,4 @@ enum KeyChord: CaseIterable { self = .unknown } } - // swiftlint:enable cyclomatic_complexity } diff --git a/Maccy/KeyShortcut.swift b/Maccy/KeyShortcut.swift index c7ee3991..2e5146c8 100644 --- a/Maccy/KeyShortcut.swift +++ b/Maccy/KeyShortcut.swift @@ -4,10 +4,11 @@ import Sauce struct KeyShortcut: Identifiable { static func create(character: String) -> [KeyShortcut] { + let key = Key(character: character, virtualKeyCode: nil) return [ - KeyShortcut(key: Key(character: character, virtualKeyCode: nil)), - KeyShortcut(key: Key(character: character, virtualKeyCode: nil), modifierFlags: [.option]), - KeyShortcut(key: Key(character: character, virtualKeyCode: nil), modifierFlags: [Defaults[.pasteByDefault] ? .command : .option, .shift]) + KeyShortcut(key: key), + KeyShortcut(key: key, modifierFlags: [.option]), + KeyShortcut(key: key, modifierFlags: [Defaults[.pasteByDefault] ? .command : .option, .shift]) ] } diff --git a/Maccy/Models/HistoryItem.swift b/Maccy/Models/HistoryItem.swift index 301832cb..4fa40f3f 100644 --- a/Maccy/Models/HistoryItem.swift +++ b/Maccy/Models/HistoryItem.swift @@ -31,8 +31,8 @@ class HistoryItem { let descriptor = FetchDescriptor( predicate: #Predicate { $0.pin != nil } ) - let pins = try! Storage.shared.context.fetch(descriptor).compactMap({ $0.pin }) - let assignedPins = Set(pins) + let pins = try? Storage.shared.context.fetch(descriptor).compactMap({ $0.pin }) + let assignedPins = Set(pins ?? []) return Array(supportedPins.subtracting(assignedPins)) } diff --git a/Maccy/Observables/AppState.swift b/Maccy/Observables/AppState.swift index a0584492..d07654a0 100644 --- a/Maccy/Observables/AppState.swift +++ b/Maccy/Observables/AppState.swift @@ -37,7 +37,8 @@ class AppState: Sendable { } var menuIconText: String { - var title = history.unpinnedItems.first?.text.shortened(to: 100).trimmingCharacters(in: .whitespacesAndNewlines) ?? "" + var title = history.unpinnedItems.first?.text.shortened(to: 100) + .trimmingCharacters(in: .whitespacesAndNewlines) ?? "" title.unicodeScalars.removeAll(where: CharacterSet.newlines.contains) return title.shortened(to: 20) } @@ -131,7 +132,7 @@ class AppState: Sendable { } @MainActor - func openPreferences() { + func openPreferences() { // swiftlint:disable:this function_body_length if settingsWindowController == nil { settingsWindowController = SettingsWindowController( panes: [ diff --git a/Maccy/Observables/Footer.swift b/Maccy/Observables/Footer.swift index 941f59bf..6af1b0fa 100644 --- a/Maccy/Observables/Footer.swift +++ b/Maccy/Observables/Footer.swift @@ -39,7 +39,7 @@ class Footer { confirmation: .init( message: "clear_alert_message", comment: "clear_alert_comment", - ok: "clear_alert_confirm", + confirm: "clear_alert_confirm", cancel: "clear_alert_cancel" ), suppressConfirmation: suppressClearAlert @@ -53,7 +53,7 @@ class Footer { confirmation: .init( message: "clear_alert_message", comment: "clear_alert_comment", - ok: "clear_alert_confirm", + confirm: "clear_alert_confirm", cancel: "clear_alert_cancel" ), suppressConfirmation: suppressClearAlert diff --git a/Maccy/Observables/FooterItem.swift b/Maccy/Observables/FooterItem.swift index abad607c..408b7edd 100644 --- a/Maccy/Observables/FooterItem.swift +++ b/Maccy/Observables/FooterItem.swift @@ -5,7 +5,7 @@ class FooterItem: Equatable, Identifiable { struct Confirmation { var message: LocalizedStringKey var comment: LocalizedStringKey - var ok: LocalizedStringKey + var confirm: LocalizedStringKey var cancel: LocalizedStringKey } diff --git a/Maccy/Observables/History.swift b/Maccy/Observables/History.swift index 0c004341..4f3a6af6 100644 --- a/Maccy/Observables/History.swift +++ b/Maccy/Observables/History.swift @@ -7,7 +7,7 @@ import Settings import SwiftData @Observable -class History { +class History { // swiftlint:disable:this type_body_length static let shared = History() var items: [HistoryItemDecorator] = [] @@ -132,7 +132,7 @@ class History { item.contents = existingHistoryItem.contents } item.firstCopiedAt = existingHistoryItem.firstCopiedAt - item.numberOfCopies = item.numberOfCopies + existingHistoryItem.numberOfCopies + item.numberOfCopies += existingHistoryItem.numberOfCopies item.pin = existingHistoryItem.pin item.title = existingHistoryItem.title if !item.fromMaccy { diff --git a/Maccy/PopupPosition.swift b/Maccy/PopupPosition.swift index 8cd22f2d..a5df1c11 100644 --- a/Maccy/PopupPosition.swift +++ b/Maccy/PopupPosition.swift @@ -56,8 +56,7 @@ enum PopupPosition: String, CaseIterable, Identifiable, CustomStringConvertible, } var point = NSEvent.mouseLocation - point.y = point.y - size.height + point.y -= size.height return point } - } diff --git a/Maccy/Sorter.swift b/Maccy/Sorter.swift index 12d9092a..778fd1db 100644 --- a/Maccy/Sorter.swift +++ b/Maccy/Sorter.swift @@ -2,6 +2,7 @@ import AppKit import Defaults // swiftlint:disable identifier_name +// swiftlint:disable type_name class Sorter { enum By: String, CaseIterable, Identifiable, CustomStringConvertible, Defaults.Serializable { case lastCopiedAt @@ -48,3 +49,4 @@ class Sorter { } } // swiftlint:enable identifier_name +// swiftlint:enable type_name diff --git a/Maccy/Storage.swift b/Maccy/Storage.swift index 7474e3d3..837d63a5 100644 --- a/Maccy/Storage.swift +++ b/Maccy/Storage.swift @@ -10,6 +10,10 @@ class Storage { init() { let config = ModelConfiguration(url: URL.applicationSupportDirectory.appending(path: "Maccy/Storage.sqlite")) - container = try! ModelContainer(for: HistoryItem.self, configurations: config) + do { + container = try ModelContainer(for: HistoryItem.self, configurations: config) + } catch let error { + fatalError("Cannot load database: \(error.localizedDescription).") + } } } diff --git a/Maccy/Views/ConfirmationView.swift b/Maccy/Views/ConfirmationView.swift index dcf4ae14..7ca8f2a3 100644 --- a/Maccy/Views/ConfirmationView.swift +++ b/Maccy/Views/ConfirmationView.swift @@ -16,7 +16,7 @@ struct ConfirmationView: View { } .confirmationDialog(confirmation.message, isPresented: $item.showConfirmation) { Text(confirmation.comment) - Button(confirmation.ok, role: .destructive) { + Button(confirmation.confirm, role: .destructive) { item.action() } Button(confirmation.cancel, role: .cancel) {} diff --git a/MaccyTests/HistoryDecoratorTests.swift b/MaccyTests/HistoryDecoratorTests.swift index 24c514e5..6aef658e 100644 --- a/MaccyTests/HistoryDecoratorTests.swift +++ b/MaccyTests/HistoryDecoratorTests.swift @@ -122,7 +122,10 @@ class HistoryItemDecoratorTests: XCTestCase { func testHighlight() { let itemDecorator = historyItemDecorator("foo bar baz") - itemDecorator.highlight("random", [range(from: 1, to: 2, in: itemDecorator), range(from: 8, to: 10, in: itemDecorator)]) + itemDecorator.highlight("random", [ + range(from: 1, to: 2, in: itemDecorator), + range(from: 8, to: 10, in: itemDecorator) + ]) var expectedTitle = AttributedString("foo bar baz") expectedTitle[expectedTitle.range(of: "oo")!].font = .bold(.body)() expectedTitle[expectedTitle.range(of: "baz")!].font = .bold(.body)() @@ -131,7 +134,10 @@ class HistoryItemDecoratorTests: XCTestCase { XCTAssertEqual(itemDecorator.attributedTitle, nil) } - private func historyItemDecorator(_ value: String?, application: String? = "com.apple.finder") -> HistoryItemDecorator { + private func historyItemDecorator( + _ value: String?, + application: String? = "com.apple.finder" + ) -> HistoryItemDecorator { let contents = [ HistoryItemContent( type: NSPasteboard.PasteboardType.string.rawValue, @@ -149,7 +155,10 @@ class HistoryItemDecoratorTests: XCTestCase { return HistoryItemDecorator(item) } - private func historyItemDecorator(_ value: Data?, _ type: NSPasteboard.PasteboardType) -> HistoryItemDecorator { + private func historyItemDecorator( + _ value: Data?, + _ type: NSPasteboard.PasteboardType + ) -> HistoryItemDecorator { let contents = [ HistoryItemContent( type: type.rawValue, @@ -210,6 +219,7 @@ class HistoryItemDecoratorTests: XCTestCase { return HistoryItemDecorator(item) } + // swiftlint:disable:next identifier_name private func range(from: Int, to: Int, in item: HistoryItemDecorator) -> Range { let startIndex = item.title.startIndex let lowerBound = item.title.index(startIndex, offsetBy: from) diff --git a/MaccyTests/SearchTests.swift b/MaccyTests/SearchTests.swift index 0edf98c4..e1bc5327 100644 --- a/MaccyTests/SearchTests.swift +++ b/MaccyTests/SearchTests.swift @@ -12,7 +12,7 @@ class SearchTests: XCTestCase { } @MainActor - func testSimpleSearch() { + func testSimpleSearch() { // swiftlint:disable:this function_body_length Defaults[.searchMode] = Search.Mode.exact items = [ HistoryItemDecorator(historyItemWithTitle("foo bar baz")), @@ -26,26 +26,54 @@ class SearchTests: XCTestCase { Search.SearchResult(score: nil, object: items[2], ranges: []) ]) XCTAssertEqual(search("z"), [ - Search.SearchResult(score: nil, object: items[0], ranges: [range(from: 10, to: 10, in: items[0])]), - Search.SearchResult(score: nil, object: items[1], ranges: [range(from: 8, to: 8, in: items[1])]), - Search.SearchResult(score: nil, object: items[2], ranges: [range(from: 8, to: 8, in: items[2])]) + Search.SearchResult( + score: nil, + object: items[0], + ranges: [range(from: 10, to: 10, in: items[0])] + ), + Search.SearchResult( + score: nil, + object: items[1], + ranges: [range(from: 8, to: 8, in: items[1])] + ), + Search.SearchResult( + score: nil, + object: items[2], + ranges: [range(from: 8, to: 8, in: items[2])] + ) ]) XCTAssertEqual(search("foo"), [ - Search.SearchResult(score: nil, object: items[0], ranges: [range(from: 0, to: 2, in: items[0])]), - Search.SearchResult(score: nil, object: items[1], ranges: [range(from: 0, to: 2, in: items[1])]) + Search.SearchResult( + score: nil, + object: items[0], + ranges: [range(from: 0, to: 2, in: items[0])] + ), + Search.SearchResult( + score: nil, + object: items[1], + ranges: [range(from: 0, to: 2, in: items[1])] + ) ]) XCTAssertEqual(search("za"), [ - Search.SearchResult(score: nil, object: items[1], ranges: [range(from: 8, to: 9, in: items[1])]) + Search.SearchResult( + score: nil, + object: items[1], + ranges: [range(from: 8, to: 9, in: items[1])] + ) ]) XCTAssertEqual(search("yyy"), [ - Search.SearchResult(score: nil, object: items[2], ranges: [range(from: 4, to: 6, in: items[2])]) + Search.SearchResult( + score: nil, + object: items[2], + ranges: [range(from: 4, to: 6, in: items[2])] + ) ]) XCTAssertEqual(search("fbb"), []) XCTAssertEqual(search("m"), []) } @MainActor - func testFuzzySearch() { + func testFuzzySearch() { // swiftlint:disable:this function_body_length Defaults[.searchMode] = Search.Mode.fuzzy items = [ HistoryItemDecorator(historyItemWithTitle("foo bar baz")), @@ -59,31 +87,78 @@ class SearchTests: XCTestCase { Search.SearchResult(score: nil, object: items[2], ranges: []) ]) XCTAssertEqual(search("z"), [ - Search.SearchResult(score: 0.08, object: items[1], ranges: [range(from: 8, to: 8, in: items[1]), range(from: 10, to: 10, in: items[1])]), - Search.SearchResult(score: 0.08, object: items[2], ranges: [range(from: 8, to: 10, in: items[2])]), - Search.SearchResult(score: 0.1, object: items[0], ranges: [range(from: 10, to: 10, in: items[0])]) + Search.SearchResult( + score: 0.08, + object: items[1], + ranges: [range(from: 8, to: 8, in: items[1]), range(from: 10, to: 10, in: items[1])] + ), + Search.SearchResult( + score: 0.08, + object: items[2], + ranges: [range(from: 8, to: 10, in: items[2])] + ), + Search.SearchResult( + score: 0.1, + object: items[0], + ranges: [range(from: 10, to: 10, in: items[0])] + ) ]) XCTAssertEqual(search("foo"), [ - Search.SearchResult(score: 0.0, object: items[0], ranges: [range(from: 0, to: 2, in: items[0])]), - Search.SearchResult(score: 0.0, object: items[1], ranges: [range(from: 0, to: 2, in: items[1])]) + Search.SearchResult( + score: 0.0, + object: items[0], + ranges: [range(from: 0, to: 2, in: items[0])] + ), + Search.SearchResult( + score: 0.0, + object: items[1], + ranges: [range(from: 0, to: 2, in: items[1])] + ) ]) XCTAssertEqual(search("za"), [ - Search.SearchResult(score: 0.08, object: items[1], ranges: [range(from: 5, to: 5, in: items[1]), range(from: 8, to: 9, in: items[1])]), - Search.SearchResult(score: 0.54, object: items[0], ranges: [range(from: 5, to: 5, in: items[0]), range(from: 9, to: 10, in: items[0])]), - Search.SearchResult(score: 0.58, object: items[2], ranges: [range(from: 8, to: 10, in: items[2])]) + Search.SearchResult( + score: 0.08, + object: items[1], + ranges: [range(from: 5, to: 5, in: items[1]), range(from: 8, to: 9, in: items[1])] + ), + Search.SearchResult( + score: 0.54, + object: items[0], + ranges: [range(from: 5, to: 5, in: items[0]), range(from: 9, to: 10, in: items[0])] + ), + Search.SearchResult( + score: 0.58, + object: items[2], + ranges: [range(from: 8, to: 10, in: items[2])] + ) ]) XCTAssertEqual(search("yyy"), [ - Search.SearchResult(score: 0.04, object: items[2], ranges: [range(from: 4, to: 6, in: items[2])]) + Search.SearchResult( + score: 0.04, + object: items[2], + ranges: [range(from: 4, to: 6, in: items[2])] + ) ]) XCTAssertEqual(search("fbb"), [ - Search.SearchResult(score: 0.6666666666666666, object: items[0], ranges: [range(from: 0, to: 0, in: items[0]), range(from: 4, to: 4, in: items[0]), range(from: 8, to: 8, in: items[0])]), - Search.SearchResult(score: 0.6666666666666666, object: items[1], ranges: [range(from: 0, to: 0, in: items[1]), range(from: 4, to: 4, in: items[1])]) + Search.SearchResult( + score: 0.6666666666666666, + object: items[0], + ranges: [ + range(from: 0, to: 0, in: items[0]), + range(from: 4, to: 4, in: items[0]), + range(from: 8, to: 8, in: items[0]) + ] + ), + Search.SearchResult( + score: 0.6666666666666666, + object: items[1], + ranges: [range(from: 0, to: 0, in: items[1]), range(from: 4, to: 4, in: items[1])]) ]) XCTAssertEqual(search("m"), []) } @MainActor - func testRegexpSearch() { + func testRegexpSearch() { // swiftlint:disable:this function_body_length Defaults[.searchMode] = Search.Mode.regexp items = [ HistoryItemDecorator(historyItemWithTitle("foo bar baz")), @@ -97,24 +172,62 @@ class SearchTests: XCTestCase { Search.SearchResult(score: nil, object: items[2], ranges: []) ]) XCTAssertEqual(search("z+"), [ - Search.SearchResult(score: nil, object: items[0], ranges: [range(from: 10, to: 10, in: items[0])]), - Search.SearchResult(score: nil, object: items[1], ranges: [range(from: 8, to: 8, in: items[1])]), - Search.SearchResult(score: nil, object: items[2], ranges: [range(from: 8, to: 10, in: items[2])]) + Search.SearchResult( + score: nil, + object: items[0], + ranges: [range(from: 10, to: 10, in: items[0])] + ), + Search.SearchResult( + score: nil, + object: items[1], + ranges: [range(from: 8, to: 8, in: items[1])] + ), + Search.SearchResult( + score: nil, + object: items[2], + ranges: [range(from: 8, to: 10, in: items[2])] + ) ]) XCTAssertEqual(search("z*"), [ - Search.SearchResult(score: nil, object: items[0], ranges: [range(from: 0, to: -1, in: items[0])]), - Search.SearchResult(score: nil, object: items[1], ranges: [range(from: 0, to: -1, in: items[1])]), - Search.SearchResult(score: nil, object: items[2], ranges: [range(from: 0, to: -1, in: items[2])]) + Search.SearchResult( + score: nil, + object: items[0], + ranges: [range(from: 0, to: -1, in: items[0])] + ), + Search.SearchResult( + score: nil, + object: items[1], + ranges: [range(from: 0, to: -1, in: items[1])] + ), + Search.SearchResult( + score: nil, + object: items[2], + ranges: [range(from: 0, to: -1, in: items[2])] + ) ]) XCTAssertEqual(search("^foo"), [ - Search.SearchResult(score: nil, object: items[0], ranges: [range(from: 0, to: 2, in: items[0])]), - Search.SearchResult(score: nil, object: items[1], ranges: [range(from: 0, to: 2, in: items[1])]) + Search.SearchResult( + score: nil, + object: items[0], ranges: [range(from: 0, to: 2, in: items[0])] + ), + Search.SearchResult( + score: nil, + object: items[1], ranges: [range(from: 0, to: 2, in: items[1])] + ) ]) XCTAssertEqual(search(" za"), [ - Search.SearchResult(score: nil, object: items[1], ranges: [range(from: 7, to: 9, in: items[1])]) + Search.SearchResult( + score: nil, + object: items[1], + ranges: [range(from: 7, to: 9, in: items[1])] + ) ]) XCTAssertEqual(search("[y]+"), [ - Search.SearchResult(score: nil, object: items[2], ranges: [range(from: 4, to: 6, in: items[2])]) + Search.SearchResult( + score: nil, + object: items[2], + ranges: [range(from: 4, to: 6, in: items[2])] + ) ]) XCTAssertEqual(search("fbb"), []) XCTAssertEqual(search("m"), []) @@ -124,6 +237,7 @@ class SearchTests: XCTestCase { return Search().search(string: string, within: items) } + // swiftlint:disable:next identifier_name private func range(from: Int, to: Int, in item: HistoryItemDecorator) -> Range { let startIndex = item.title.startIndex let lowerBound = item.title.index(startIndex, offsetBy: from)