Skip to content

Commit

Permalink
[CI] Add SwiftLint and Periphery for code style and dead code check
Browse files Browse the repository at this point in the history
  • Loading branch information
LEOYoon-Tsaw committed May 27, 2024
1 parent 73a5bd6 commit 5c83f63
Show file tree
Hide file tree
Showing 15 changed files with 151 additions and 22 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/commit-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ on:
push:
branches:
- '*'
paths:
- 'sources/**'
jobs:
build:
runs-on: macos-14
Expand All @@ -12,13 +14,25 @@ jobs:
with:
submodules: true

- name: Install SwiftLint
run: brew install swiftlint

- name: Lint
run: swiftlint

- name: Configure build environment
run: |
echo git_ref_name="$(git describe --always)" >> $GITHUB_ENV
- name: Build Squirrel
run: ./action-build.sh package

- name: Install periphery
run: brew install peripheryapp/periphery/periphery

- name: Check Unused Code
run: periphery scan

- name: Upload Squirrel artifact
uses: actions/upload-artifact@v4
with:
Expand Down
12 changes: 12 additions & 0 deletions .github/workflows/pull-request-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,25 @@ jobs:
with:
submodules: true

- name: Install SwiftLint
run: brew install swiftlint

- name: Lint
run: swiftlint

- name: Configure build environment
run: |
echo git_ref_name="$(git describe --always)" >> $GITHUB_ENV
- name: Build Squirrel
run: ./action-build.sh package

- name: Install periphery
run: brew install peripheryapp/periphery/periphery

- name: Check Unused Code
run: periphery scan

- name: Upload Squirrel artifact
uses: actions/upload-artifact@v4
with:
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/release-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ on:
- '*'
branches:
- master
paths:
- 'sources/**'
workflow_dispatch:

jobs:
Expand All @@ -19,9 +21,21 @@ jobs:
fetch-depth: 0
submodules: true

- name: Install SwiftLint
run: brew install swiftlint

- name: Lint
run: swiftlint

- name: Build Squirrel
run: ./action-build.sh archive

- name: Install periphery
run: brew install peripheryapp/periphery/periphery

- name: Check Unused Code
run: periphery scan

- name: Build changelog
id: release_log
run: |
Expand Down
5 changes: 5 additions & 0 deletions .periphery.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
project: Squirrel.xcodeproj
schemes:
- Squirrel
targets:
- Squirrel
56 changes: 56 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# By default, SwiftLint uses a set of sensible default rules you can adjust:
disabled_rules: # rule identifiers turned on by default to exclude from running
- force_cast
- force_try
- todo
opt_in_rules: # some rules are turned off by default, so you need to opt-in

# Alternatively, specify all rules explicitly by uncommenting this option:
# only_rules: # delete `disabled_rules` & `opt_in_rules` if using this
# - empty_parameters
# - vertical_whitespace

analyzer_rules: # rules run by `swiftlint analyze`
- explicit_self

included: # case-sensitive paths to include during linting. `--path` is ignored if present
- sources
excluded: # case-sensitive paths to ignore during linting. Takes precedence over `included`

# If true, SwiftLint will not fail if no lintable files are found.
allow_zero_lintable_files: false

# If true, SwiftLint will treat all warnings as errors.
strict: false

# rules that have both warning and error levels, can set just the warning level
# implicitly
line_length: 200
function_body_length: 200
# they can set both implicitly with an array
type_body_length:
- 300 # warning
- 400 # error
# or they can set both explicitly
file_length:
warning: 800
error: 1200
# naming rules can set warnings/errors for min_length and max_length
# additionally they can set excluded names
type_name:
min_length: 4 # only warning
max_length: # warning and error
warning: 40
error: 50
excluded: # excluded via string
allowed_symbols: ["_"] # these are allowed in type names
identifier_name:
min_length: # only min_length
warning: 3
error: 2
excluded: [i, URL, of, by] # excluded via string array
large_tuple:
warning: 3
warning: 5
reporter: "github-actions-logging" # reporter type (xcode, json, csv, checkstyle, codeclimate, junit, html, emoji, sonarqube, markdown, github-actions-logging, summary)

7 changes: 5 additions & 2 deletions sources/BridgingFunctions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
import Foundation

protocol DataSizeable {
var data_size: Int32 { get set }
// swiftlint:disable:next identifier_name
var data_size: Int32 { get set }
}

extension RimeContext_stdbool: DataSizeable {}
Expand Down Expand Up @@ -37,19 +38,21 @@ extension DataSizeable {
let mutableCStr = strdup(cStr)
// Free the existing string if there is one
if let existing = self[keyPath: keypath] {
free(UnsafeMutableRawPointer(mutating: existing))
free(UnsafeMutableRawPointer(mutating: existing))
}
self[keyPath: keypath] = UnsafePointer(mutableCStr)
}
}
}

infix operator ?= : AssignmentPrecedence
// swiftlint:disable:next operator_whitespace
func ?=<T>(left: inout T, right: T?) {
if let right = right {
left = right
}
}
// swiftlint:disable:next operator_whitespace
func ?=<T>(left: inout T?, right: T?) {
if let right = right {
left = right
Expand Down
4 changes: 2 additions & 2 deletions sources/InputSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ final class SquirrelInstaller {
}
for (mode, inputSource) in getInputSource(modes: [modeToSelect]) {
if let enabled = getBool(for: inputSource, key: kTISPropertyInputSourceIsEnabled),
let selectable = getBool(for: inputSource, key: kTISPropertyInputSourceIsSelectCapable),
let selected = getBool(for: inputSource, key: kTISPropertyInputSourceIsSelected),
let selectable = getBool(for: inputSource, key: kTISPropertyInputSourceIsSelectCapable),
let selected = getBool(for: inputSource, key: kTISPropertyInputSourceIsSelected),
enabled && selectable && !selected {
let error = TISSelectInputSource(inputSource)
print("Selection \(error == noErr ? "succeeds" : "fails") for input source: \(mode.rawValue)")
Expand Down
2 changes: 1 addition & 1 deletion sources/MacOSKeyCodes.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// MacOSKeyCOdes.swift
// MacOSKeyCodes.swift
// Squirrel
//
// Created by Leo Liu on 5/9/24.
Expand Down
5 changes: 3 additions & 2 deletions sources/Main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ import InputMethodKit

@main
struct SquirrelApp {
static let userDir = if let pw = getpwuid(getuid()) {
URL(fileURLWithFileSystemRepresentation: pw.pointee.pw_dir, isDirectory: true, relativeTo: nil).appending(components: "Library", "Rime")
static let userDir = if let pwuid = getpwuid(getuid()) {
URL(fileURLWithFileSystemRepresentation: pwuid.pointee.pw_dir, isDirectory: true, relativeTo: nil).appending(components: "Library", "Rime")
} else {
try! FileManager.default.url(for: .libraryDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("Rime", isDirectory: true)
}
static let appDir = "/Library/Input Library/Squirrel.app".withCString { dir in
URL(fileURLWithFileSystemRepresentation: dir, isDirectory: false, relativeTo: nil)
}

// swiftlint:disable:next cyclomatic_complexity
static func main() {
let rimeAPI: RimeApi_stdbool = rime_get_api_stdbool().pointee

Expand Down
3 changes: 3 additions & 0 deletions sources/SquirrelApplicationDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ final class SquirrelApplicationDelegate: NSObject, NSApplicationDelegate, SPUSta
}

func applicationWillTerminate(_ notification: Notification) {
// swiftlint:disable:next notification_center_detachment
NotificationCenter.default.removeObserver(self)
DistributedNotificationCenter.default().removeObserver(self)
panel?.hide()
Expand Down Expand Up @@ -132,8 +133,10 @@ final class SquirrelApplicationDelegate: NSObject, NSApplicationDelegate, SPUSta
print("Error creating user data directory: \(userDataDir.path())")
}
}
// swiftlint:disable identifier_name
let notification_handler: @convention(c) (UnsafeMutableRawPointer?, RimeSessionId, UnsafePointer<CChar>?, UnsafePointer<CChar>?) -> Void = notificationHandler
let context_object = Unmanaged.passUnretained(self).toOpaque()
// swiftlint:enable identifier_name
rimeAPI.set_notification_handler(notification_handler, context_object)

var squirrelTraits = RimeTraits.rimeStructInit()
Expand Down
2 changes: 1 addition & 1 deletion sources/SquirrelConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ final class SquirrelConfig {

// isVertical
func updateTextOrientation(prefix: String) -> Bool {
let textOrientation = getString("\(prefix)/text_orientation")
let textOrientation = getString("\(prefix)/text_orientation")
switch textOrientation {
case "horizontal":
return false
Expand Down
17 changes: 14 additions & 3 deletions sources/SquirrelInputController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ final class SquirrelInputController: IMKInputController {
private var chordDuration: TimeInterval = 0
private var currentApp: String = ""

// swiftlint:disable:next cyclomatic_complexity
override func handle(_ event: NSEvent!, client sender: Any!) -> Bool {
let modifiers = event.modifierFlags
let changes = lastModifiers.symmetricDifference(modifiers)
Expand Down Expand Up @@ -128,6 +129,7 @@ final class SquirrelInputController: IMKInputController {
return success
}

// swiftlint:disable:next identifier_name
func page(up: Bool) -> Bool {
var handled = false
handled = rimeAPI.change_page(session, up)
Expand Down Expand Up @@ -282,7 +284,8 @@ private extension SquirrelInputController {
if chordKeyCount > 0 && session != 0 {
// simulate key-ups
for i in 0..<chordKeyCount {
if rimeAPI.process_key(session, Int32(chordKeyCodes[i]), Int32(chordModifiers[i] | kReleaseMask.rawValue)) {
let handled = rimeAPI.process_key(session, Int32(chordKeyCodes[i]), Int32(chordModifiers[i] | kReleaseMask.rawValue))
if handled {
processedKeys = true
}
}
Expand Down Expand Up @@ -413,13 +416,15 @@ private extension SquirrelInputController {
}
}

// swiftlint:disable:next cyclomatic_complexity
func rimeUpdate() {
// print("[DEBUG] rimeUpdate")
rimeConsumeCommittedText()

var status = RimeStatus_stdbool.rimeStructInit()
if rimeAPI.get_status(session, &status) {
// enable schema specific ui style
// swiftlint:disable:next identifier_name
if let schema_id = status.schema_id, schemaId == "" || schemaId != String(cString: schema_id) {
schemaId = String(cString: schema_id)
NSApp.squirrelAppDelegate.loadSettings(for: schemaId)
Expand Down Expand Up @@ -484,15 +489,20 @@ private extension SquirrelInputController {
comments.append(candidate.comment.map { String(cString: $0) } ?? "")
}
var labels = [String]()
// swiftlint:disable identifier_name
if let select_keys = ctx.menu.select_keys {
labels = Array(arrayLiteral: String(cString: select_keys))
labels = String(cString: select_keys).map { String($0) }
} else if let select_labels = ctx.select_labels {
let pageSize = Int(ctx.menu.page_size)
for i in 0..<pageSize {
labels.append(select_labels[i].map { String(cString: $0) } ?? "")
}
}
showPanel(preedit: inlinePreedit ? "" : preedit, selRange: NSRange(location: start.utf16Offset(in: preedit), length: preedit.utf16.distance(from: start, to: end)), caretPos: caretPos.utf16Offset(in: preedit), candidates: candidates, comments: comments, labels: labels, highlighted: Int(ctx.menu.highlighted_candidate_index))
// swiftlint:enable identifier_name

let selRange = NSRange(location: start.utf16Offset(in: preedit), length: preedit.utf16.distance(from: start, to: end))
showPanel(preedit: inlinePreedit ? "" : preedit, selRange: selRange, caretPos: caretPos.utf16Offset(in: preedit),
candidates: candidates, comments: comments, labels: labels, highlighted: Int(ctx.menu.highlighted_candidate_index))
_ = rimeAPI.free_context(&ctx)
} else {
hidePalettes()
Expand Down Expand Up @@ -531,6 +541,7 @@ private extension SquirrelInputController {
client.setMarkedText(attrString, selectionRange: NSRange(location: caretPos, length: 0), replacementRange: NSRange(location: NSNotFound, length: 0))
}

// swiftlint:disable:next function_parameter_count
func showPanel(preedit: String, selRange: NSRange, caretPos: Int, candidates: [String], comments: [String], labels: [String], highlighted: Int) {
// print("[DEBUG] showPanelWithPreedit:...:")
guard let client = client else { return }
Expand Down
10 changes: 7 additions & 3 deletions sources/SquirrelPanel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ final class SquirrelPanel: NSPanel {
view.currentTheme.inlineCandidate
}

// swiftlint:disable:next cyclomatic_complexity
override func sendEvent(_ event: NSEvent) {
switch event.type {
case .leftMouseDown:
Expand Down Expand Up @@ -98,15 +99,15 @@ final class SquirrelPanel: NSPanel {
case .scrollWheel:
if event.phase == .began {
scrollDirection = .zero
// Scrollboard span
// Scrollboard span
} else if event.phase == .ended || (event.phase == .init(rawValue: 0) && event.momentumPhase != .init(rawValue: 0)) {
if abs(scrollDirection.dx) > abs(scrollDirection.dy) && abs(scrollDirection.dx) > 10 {
_ = inputController?.page(up: (scrollDirection.dx < 0) == vertical)
} else if abs(scrollDirection.dx) < abs(scrollDirection.dy) && abs(scrollDirection.dy) > 10 {
_ = inputController?.page(up: scrollDirection.dx > 0)
}
scrollDirection = .zero
// Mouse scroll wheel
// Mouse scroll wheel
} else if event.phase == .init(rawValue: 0) && event.momentumPhase == .init(rawValue: 0) {
if scrollTime.timeIntervalSinceNow < -1 {
scrollDirection = .zero
Expand Down Expand Up @@ -139,6 +140,7 @@ final class SquirrelPanel: NSPanel {
}

// Main function to add attributes to text output from librime
// swiftlint:disable:next cyclomatic_complexity function_parameter_count
func update(preedit: String, selRange: NSRange, caretPos: Int, candidates: [String], comments: [String], labels: [String], highlighted index: Int, update: Bool) {
if update {
self.preedit = preedit
Expand Down Expand Up @@ -335,6 +337,7 @@ private extension SquirrelPanel {

// Get the window size, the windows will be the dirtyRect in
// SquirrelView.drawRect
// swiftlint:disable:next cyclomatic_complexity
func show() {
currentScreen()
let theme = view.currentTheme
Expand Down Expand Up @@ -437,7 +440,8 @@ private extension SquirrelPanel {
text.addAttribute(.paragraphStyle, value: theme.paragraphStyle, range: NSRange(location: 0, length: text.length))
view.textContentStorage.attributedString = text
view.textView.setLayoutOrientation(vertical ? .vertical : .horizontal)
view.drawView(candidateRanges: [NSRange(location: 0, length: text.length)], hilightedIndex: -1, preeditRange: NSRange(location: NSNotFound, length: 0), highlightedPreeditRange: NSRange(location: NSNotFound, length: 0))
view.drawView(candidateRanges: [NSRange(location: 0, length: text.length)], hilightedIndex: -1,
preeditRange: NSRange(location: NSNotFound, length: 0), highlightedPreeditRange: NSRange(location: NSNotFound, length: 0))
show()

statusTimer?.invalidate()
Expand Down
12 changes: 6 additions & 6 deletions sources/SquirrelTheme.swift
Original file line number Diff line number Diff line change
Expand Up @@ -294,12 +294,12 @@ private extension SquirrelTheme {
func blendColor(foregroundColor: NSColor, backgroundColor: NSColor?) -> NSColor {
let foregroundColor = foregroundColor.usingColorSpace(NSColorSpace.deviceRGB)!
let backgroundColor = (backgroundColor ?? NSColor.gray).usingColorSpace(NSColorSpace.deviceRGB)!
func blend(_ a: CGFloat, _ b: CGFloat) -> CGFloat {
return (a * 2 + b) / 3
func blend(foreground: CGFloat, background: CGFloat) -> CGFloat {
return (foreground * 2 + background) / 3
}
return NSColor(deviceRed: blend(foregroundColor.redComponent, backgroundColor.redComponent),
green: blend(foregroundColor.greenComponent, backgroundColor.greenComponent),
blue: blend(foregroundColor.blueComponent, backgroundColor.blueComponent),
alpha: blend(foregroundColor.alphaComponent, backgroundColor.alphaComponent))
return NSColor(deviceRed: blend(foreground: foregroundColor.redComponent, background: backgroundColor.redComponent),
green: blend(foreground: foregroundColor.greenComponent, background: backgroundColor.greenComponent),
blue: blend(foreground: foregroundColor.blueComponent, background: backgroundColor.blueComponent),
alpha: blend(foreground: foregroundColor.alphaComponent, background: backgroundColor.alphaComponent))
}
}
Loading

0 comments on commit 5c83f63

Please sign in to comment.