Clang-format // Use Google Swift Format Style.

This commit is contained in:
ShikiSuen 2023-02-07 17:40:28 +08:00
parent e1edd189ad
commit 856c5d02d7
169 changed files with 2987 additions and 2935 deletions

View File

@ -1,56 +0,0 @@
{
"fileScopedDeclarationPrivacy" : {
"accessLevel" : "private"
},
"indentation" : {
"spaces" : 2
},
"indentConditionalCompilationBlocks" : true,
"indentSwitchCaseLabels" : true,
"lineBreakAroundMultilineExpressionChainComponents" : false,
"lineBreakBeforeControlFlowKeywords" : false,
"lineBreakBeforeEachArgument" : false,
"lineBreakBeforeEachGenericRequirement" : false,
"lineLength" : 120,
"maximumBlankLines" : 1,
"prioritizeKeepingFunctionOutputTogether" : false,
"respectsExistingLineBreaks" : true,
"rules" : {
"AllPublicDeclarationsHaveDocumentation" : false,
"AlwaysUseLowerCamelCase" : true,
"AmbiguousTrailingClosureOverload" : true,
"BeginDocumentationCommentWithOneLineSummary" : false,
"DoNotUseSemicolons" : true,
"DontRepeatTypeInStaticProperties" : false,
"FileScopedDeclarationPrivacy" : true,
"FullyIndirectEnum" : true,
"GroupNumericLiterals" : true,
"IdentifiersMustBeASCII" : true,
"NeverForceUnwrap" : false,
"NeverUseForceTry" : false,
"NeverUseImplicitlyUnwrappedOptionals" : false,
"NoAccessLevelOnExtensionDeclaration" : true,
"NoBlockComments" : false,
"NoCasesWithOnlyFallthrough" : true,
"NoEmptyTrailingClosureParentheses" : true,
"NoLabelsInCasePatterns" : true,
"NoLeadingUnderscores" : false,
"NoParensAroundConditions" : true,
"NoVoidReturnOnFunctionSignature" : true,
"OneCasePerLine" : true,
"OneVariableDeclarationPerLine" : true,
"OnlyOneTrailingClosureArgument" : false,
"OrderedImports" : true,
"ReturnVoidInsteadOfEmptyTuple" : true,
"UseEarlyExits" : false,
"UseLetInEveryBoundCaseVariable" : false,
"UseShorthandTypeNames" : true,
"UseSingleLinePropertyGetter" : true,
"UseSynthesizedInitializer" : true,
"UseTripleSlashForDocumentationComments" : false,
"UseWhereClausesInForLoops" : false,
"ValidateDocumentationComments" : false
},
"tabWidth" : 8,
"version" : 1
}

104
.swiftformat.json Normal file
View File

@ -0,0 +1,104 @@
# SwiftFormat config compliant with Google Swift Guideline
# https://google.github.io/swift/#control-flow-statements
# Specify version used in a project
--swiftversion 5.5
# Rules explicitly required by the guideline
--rules \
blankLinesAroundMark, \
blankLinesAtEndOfScope, \
blankLinesAtStartOfScope, \
blankLinesBetweenScopes, \
braces, \
consecutiveBlankLines, \
consecutiveSpaces, \
duplicateImports, \
elseOnSameLine, \
emptyBraces, \
enumNamespaces, \
extensionAccessControl, \
hoistPatternLet, \
indent, \
leadingDelimiters, \
linebreakAtEndOfFile, \
markTypes, \
organizeDeclarations, \
redundantInit, \
redundantParens, \
redundantPattern, \
redundantRawValues, \
redundantType, \
redundantVoidReturnType, \
semicolons, \
sortedImports, \
sortedSwitchCases, \
spaceAroundBraces, \
spaceAroundBrackets, \
spaceAroundComments, \
spaceAroundGenerics, \
spaceAroundOperators, \
spaceAroundParens, \
spaceInsideBraces, \
spaceInsideBrackets, \
spaceInsideComments, \
spaceInsideGenerics, \
spaceInsideParens, \
todos, \
trailingClosures, \
trailingCommas, \
trailingSpace, \
typeSugar, \
void, \
wrap, \
wrapArguments, \
wrapAttributes, \
#
#
# Additional rules not mentioned in the guideline, but helping to keep the codebase clean
# Quoting the guideline:
# Common themes among the rules in this section are:
# avoid redundancy, avoid ambiguity, and prefer implicitness over explicitness
# unless being explicit improves readability and/or reduces ambiguity.
#
#
andOperator, \
isEmpty, \
redundantBackticks, \
redundantBreak, \
redundantExtensionACL, \
redundantGet, \
redundantLetError, \
redundantNilInit, \
redundantObjc, \
redundantReturn, \
redundantSelf, \
strongifiedSelf
# Options for basic rules
--extensionacl on-declarations
--funcattributes prev-line
--indent 2
--maxwidth 100
--typeattributes prev-line
--varattributes prev-line
--voidtype tuple
--wraparguments before-first
--wrapparameters before-first
--wrapcollections before-first
--wrapreturntype if-multiline
--wrapconditions after-first
# Option for additional rules
--self init-only
# Excluded folders
--exclude Pods,**/UNTESTED_TODO,vendor,fastlane
# https://github.com/NoemiRozpara/Google-SwiftFormat-Config

View File

@ -10,8 +10,8 @@
import Cocoa
extension String {
fileprivate mutating func regReplace(pattern: String, replaceWith: String = "") {
fileprivate extension String {
mutating func regReplace(pattern: String, replaceWith: String = "") {
// Ref: https://stackoverflow.com/a/40993403/4162914 && https://stackoverflow.com/a/71291137/4162914
do {
let regex = try NSRegularExpression(

View File

@ -12,8 +12,8 @@ import Foundation
// MARK: -
extension String {
fileprivate mutating func regReplace(pattern: String, replaceWith: String = "") {
fileprivate extension String {
mutating func regReplace(pattern: String, replaceWith: String = "") {
// Ref: https://stackoverflow.com/a/40993403/4162914 && https://stackoverflow.com/a/71291137/4162914
do {
let regex = try NSRegularExpression(
@ -29,21 +29,21 @@ extension String {
// MARK: - String charComponents Extension
extension String {
public var charComponents: [String] { map { String($0) } }
public extension String {
var charComponents: [String] { map { String($0) } }
}
extension Array where Element == String.Element {
public var charComponents: [String] { map { String($0) } }
public extension Array where Element == String.Element {
var charComponents: [String] { map { String($0) } }
}
// MARK: - StringView Ranges Extension (by Isaac Xen)
extension String {
fileprivate func ranges(splitBy separator: Element) -> [Range<String.Index>] {
fileprivate extension String {
func ranges(splitBy separator: Element) -> [Range<String.Index>] {
var startIndex = startIndex
return split(separator: separator).reduce(into: []) { ranges, substring in
_ = range(of: substring, range: startIndex..<endIndex).map { range in
_ = range(of: substring, range: startIndex ..< endIndex).map { range in
ranges.append(range)
startIndex = range.upperBound
}
@ -54,8 +54,8 @@ extension String {
// MARK: -
// Ref: https://stackoverflow.com/a/32581409/4162914
extension Double {
fileprivate func rounded(toPlaces places: Int) -> Double {
fileprivate extension Double {
func rounded(toPlaces places: Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
@ -173,15 +173,15 @@ func rawDictForPhrases(isCHS: Bool) -> [Unigram] {
return []
}
//
strRAW = strRAW.replacingOccurrences(of: " #MACOS", with: "") // macOS
strRAW = strRAW.replacingOccurrences(of: " #MACOS", with: "") // macOS
// CJKWhiteSpace (\x{3000}) to ASCII Space
// NonBreakWhiteSpace (\x{A0}) to ASCII Space
// Tab to ASCII Space
// ASCII
strRAW.regReplace(pattern: #"( +| +| +|\t+)+"#, replaceWith: " ")
strRAW.regReplace(pattern: #"(^ | $)"#, replaceWith: "") //
strRAW.regReplace(pattern: #"(\f+|\r+|\n+)+"#, replaceWith: "\n") // CR & Form Feed to LF,
strRAW.regReplace(pattern: #"^(#.*|.*#WIN32.*)$"#, replaceWith: "") // #+ WIN32
strRAW.regReplace(pattern: #"(^ | $)"#, replaceWith: "") //
strRAW.regReplace(pattern: #"(\f+|\r+|\n+)+"#, replaceWith: "\n") // CR & Form Feed to LF,
strRAW.regReplace(pattern: #"^(#.*|.*#WIN32.*)$"#, replaceWith: "") // #+ WIN32
//
let arrData = Array(
NSOrderedSet(array: strRAW.components(separatedBy: "\n")).array as! [String])
@ -202,25 +202,25 @@ func rawDictForPhrases(isCHS: Bool) -> [Unigram] {
}
// Unigram
let arrCells: [String] = varLineDataProcessed.components(separatedBy: "\t")
count = 0 //
count = 0 //
var phone = ""
var phrase = ""
var occurrence = 0
for cell in arrCells {
count += 1
switch count {
case 1: phrase = cell
case 3: phone = cell
case 2: occurrence = Int(cell) ?? 0
default: break
case 1: phrase = cell
case 3: phone = cell
case 2: occurrence = Int(cell) ?? 0
default: break
}
}
if phrase != "" { //
if phrase != "" { //
arrUnigramRAW += [
Unigram(
key: phone, value: phrase, score: 0.0,
count: occurrence
)
),
]
}
}
@ -242,15 +242,15 @@ func rawDictForKanjis(isCHS: Bool) -> [Unigram] {
return []
}
//
strRAW = strRAW.replacingOccurrences(of: " #MACOS", with: "") // macOS
strRAW = strRAW.replacingOccurrences(of: " #MACOS", with: "") // macOS
// CJKWhiteSpace (\x{3000}) to ASCII Space
// NonBreakWhiteSpace (\x{A0}) to ASCII Space
// Tab to ASCII Space
// ASCII
strRAW.regReplace(pattern: #"( +| +| +|\t+)+"#, replaceWith: " ")
strRAW.regReplace(pattern: #"(^ | $)"#, replaceWith: "") //
strRAW.regReplace(pattern: #"(\f+|\r+|\n+)+"#, replaceWith: "\n") // CR & Form Feed to LF,
strRAW.regReplace(pattern: #"^(#.*|.*#WIN32.*)$"#, replaceWith: "") // #+ WIN32
strRAW.regReplace(pattern: #"(^ | $)"#, replaceWith: "") //
strRAW.regReplace(pattern: #"(\f+|\r+|\n+)+"#, replaceWith: "\n") // CR & Form Feed to LF,
strRAW.regReplace(pattern: #"^(#.*|.*#WIN32.*)$"#, replaceWith: "") // #+ WIN32
//
let arrData = Array(
NSOrderedSet(array: strRAW.components(separatedBy: "\n")).array as! [String])
@ -281,20 +281,20 @@ func rawDictForKanjis(isCHS: Bool) -> [Unigram] {
}
// Unigram
let arrCells: [String] = varLineDataProcessed.components(separatedBy: "\t")
count = 0 //
count = 0 //
var phone = ""
var phrase = ""
var occurrence = 0
for cell in arrCells {
count += 1
switch count {
case 1: phrase = cell
case 3: phone = cell
case 2: occurrence = Int(cell) ?? 0
default: break
case 1: phrase = cell
case 3: phone = cell
case 2: occurrence = Int(cell) ?? 0
default: break
}
}
if phrase != "" { //
if phrase != "" { //
if !isReverseLookupDictionaryProcessed {
mapReverseLookup[phrase, default: []].append(cnvPhonabetToASCII(phone).data(using: .utf8)!)
mapReverseLookupUnencrypted[phrase, default: []].append(phone)
@ -303,7 +303,7 @@ func rawDictForKanjis(isCHS: Bool) -> [Unigram] {
Unigram(
key: phone, value: phrase, score: 0.0,
count: occurrence
)
),
]
}
}
@ -337,15 +337,15 @@ func rawDictForNonKanjis(isCHS: Bool) -> [Unigram] {
return []
}
//
strRAW = strRAW.replacingOccurrences(of: " #MACOS", with: "") // macOS
strRAW = strRAW.replacingOccurrences(of: " #MACOS", with: "") // macOS
// CJKWhiteSpace (\x{3000}) to ASCII Space
// NonBreakWhiteSpace (\x{A0}) to ASCII Space
// Tab to ASCII Space
// ASCII
strRAW.regReplace(pattern: #"( +| +| +|\t+)+"#, replaceWith: " ")
strRAW.regReplace(pattern: #"(^ | $)"#, replaceWith: "") //
strRAW.regReplace(pattern: #"(\f+|\r+|\n+)+"#, replaceWith: "\n") // CR & Form Feed to LF,
strRAW.regReplace(pattern: #"^(#.*|.*#WIN32.*)$"#, replaceWith: "") // #+ WIN32
strRAW.regReplace(pattern: #"(^ | $)"#, replaceWith: "") //
strRAW.regReplace(pattern: #"(\f+|\r+|\n+)+"#, replaceWith: "\n") // CR & Form Feed to LF,
strRAW.regReplace(pattern: #"^(#.*|.*#WIN32.*)$"#, replaceWith: "") // #+ WIN32
//
let arrData = Array(
NSOrderedSet(array: strRAW.components(separatedBy: "\n")).array as! [String])
@ -354,7 +354,7 @@ func rawDictForNonKanjis(isCHS: Bool) -> [Unigram] {
varLineData = lineData
//
varLineData = varLineData.components(separatedBy: " ").prefix(3).joined(
separator: "\t") //
separator: "\t") //
let arrLineData = varLineData.components(separatedBy: " ")
var varLineDataProcessed = ""
var count = 0
@ -370,26 +370,26 @@ func rawDictForNonKanjis(isCHS: Bool) -> [Unigram] {
}
// Unigram
let arrCells: [String] = varLineDataProcessed.components(separatedBy: "\t")
count = 0 //
count = 0 //
var phone = ""
var phrase = ""
var occurrence = 0
for cell in arrCells {
count += 1
switch count {
case 1: phrase = cell
case 3: phone = cell
case 2: occurrence = Int(cell) ?? 0
default: break
case 1: phrase = cell
case 3: phone = cell
case 2: occurrence = Int(cell) ?? 0
default: break
}
}
if phrase != "" { //
if phrase != "" { //
exceptedChars.insert(phrase)
arrUnigramRAW += [
Unigram(
key: phone, value: phrase, score: 0.0,
count: occurrence
)
),
]
}
}
@ -415,24 +415,24 @@ func weightAndSort(_ arrStructUncalculated: [Unigram], isCHS: Bool) -> [Unigram]
for unigram in arrStructUncalculated {
var weight: Double = 0
switch unigram.count {
case -2: //
weight = -13
case -1: //
weight = -13
case 0: //
weight = log10(
fscale ** (Double(unigram.value.count) / 3.0 - 1.0) * 0.25 / norm)
default:
weight = log10(
fscale ** (Double(unigram.value.count) / 3.0 - 1.0)
* Double(unigram.count) / norm) // Credit: MJHsieh.
case -2: //
weight = -13
case -1: //
weight = -13
case 0: //
weight = log10(
fscale ** (Double(unigram.value.count) / 3.0 - 1.0) * 0.25 / norm)
default:
weight = log10(
fscale ** (Double(unigram.value.count) / 3.0 - 1.0)
* Double(unigram.count) / norm) // Credit: MJHsieh.
}
let weightRounded: Double = weight.rounded(toPlaces: 3) //
let weightRounded: Double = weight.rounded(toPlaces: 3) //
arrStructCalculated += [
Unigram(
key: unigram.key, value: unigram.value, score: weightRounded,
count: unigram.count
)
),
]
}
NSLog(" - \(i18n): 成功計算權重。")
@ -763,7 +763,7 @@ func healthCheck(_ data: [Unigram]) -> String {
let separator: String = {
var result = ""
for _ in 0..<72 { result += "-" }
for _ in 0 ..< 72 { result += "-" }
return result
}()
@ -784,7 +784,7 @@ func healthCheck(_ data: [Unigram]) -> String {
printl("\n其中有:")
var insufficientsMap = [Int: [(String, String, Double, [Unigram], Double)]]()
for x in 2...10 {
for x in 2 ... 10 {
insufficientsMap[x] = insufficients.filter { $0.0.split(separator: "-").count == x }
}

View File

@ -53,7 +53,7 @@ class AppDelegate: NSWindowController, NSApplicationDelegate {
var allRegisteredInstancesOfThisInputMethod: [TISInputSource] {
guard let components = Bundle(url: imeURLInstalled)?.infoDictionary?["ComponentInputModeDict"] as? [String: Any],
let tsInputModeListKey = components["tsInputModeListKey"] as? [String: Any]
let tsInputModeListKey = components["tsInputModeListKey"] as? [String: Any]
else {
return []
}
@ -102,7 +102,7 @@ class AppDelegate: NSWindowController, NSApplicationDelegate {
let currentVersion = currentBundle?.infoDictionary?[kCFBundleVersionKey as String] as? String
currentVersionNumber = (currentVersion as NSString?)?.integerValue ?? 0
if shortVersion != nil, let currentVersion = currentVersion,
currentVersion.compare(installingVersion, options: .numeric) == .orderedAscending
currentVersion.compare(installingVersion, options: .numeric) == .orderedAscending
{
// Upgrading confirmed.
installButton.title = NSLocalizedString("Upgrade", comment: "")

View File

@ -24,7 +24,7 @@ extension AppDelegate {
let shouldWaitForTranslocationRemoval =
Reloc.isAppBundleTranslocated(atPath: kTargetPartialPath)
&& window.responds(to: #selector(NSWindow.beginSheet(_:completionHandler:)))
&& window.responds(to: #selector(NSWindow.beginSheet(_:completionHandler:)))
//
do {
@ -116,7 +116,7 @@ extension AppDelegate {
_ = try? shell("/usr/bin/xattr -drs com.apple.quarantine \(kTargetPartialPath)")
guard let theBundle = Bundle(url: imeURLInstalled),
let imeIdentifier = theBundle.bundleIdentifier
let imeIdentifier = theBundle.bundleIdentifier
else {
endAppWithDelay()
return

View File

@ -20,23 +20,14 @@ debug:
DSTROOT = /Library/Input Methods
VC_APP_ROOT = $(DSTROOT)/vChewing.app
.PHONY: clang-format lint batchfix format clang-format-swift clang-format-cpp
.PHONY: lint format
format: batchfix clang-format lint
clang-format:
@git ls-files --exclude-standard | grep -E '\.swift$$' | xargs swift-format format --in-place --configuration ./.clang-format-swift.json --parallel
@git ls-files --exclude-standard | grep -E '\.swift$$' | xargs swift-format lint --configuration ./.clang-format-swift.json --parallel
format:
@swiftformat --swiftversion 5.5 --indent 2 ./
lint:
@git ls-files --exclude-standard | grep -E '\.swift$$' | xargs swift-format lint --configuration ./.clang-format-swift.json --parallel
batchfix:
@git ls-files --exclude-standard | grep -E '\.swift$$' | swiftlint --fix --autocorrect
advanced-lint:
@swiftformat --swiftversion 5.5 --indent 2 ./
.PHONY: permission-check install-debug install-release
permission-check:

View File

@ -4,19 +4,19 @@ import PackageDescription
let package = Package(
name: "FolderMonitor",
platforms: [
.macOS(.v10_11)
.macOS(.v10_11),
],
products: [
.library(
name: "FolderMonitor",
targets: ["FolderMonitor"]
)
),
],
dependencies: [],
targets: [
.target(
name: "FolderMonitor",
dependencies: []
)
),
]
)

View File

@ -4,19 +4,19 @@ import PackageDescription
let package = Package(
name: "NSAttributedTextView",
platforms: [
.macOS(.v10_11)
.macOS(.v10_11),
],
products: [
.library(
name: "NSAttributedTextView",
targets: ["NSAttributedTextView"]
)
),
],
dependencies: [],
targets: [
.target(
name: "NSAttributedTextView",
dependencies: []
)
),
]
)

View File

@ -103,8 +103,8 @@ public class NSAttributedTextView: NSView {
@discardableResult public func shrinkFrame() -> NSRect {
let attrString: NSAttributedString = {
switch direction {
case .horizontal: return attributedStringValue()
default: return attributedStringValue(areaCalculation: true)
case .horizontal: return attributedStringValue()
default: return attributedStringValue(areaCalculation: true)
}
}()
var rect = attrString.boundingRect(
@ -130,14 +130,14 @@ public class NSAttributedTextView: NSView {
let path = CGPath(rect: rect, transform: nil)
let theCTFrameProgression: CTFrameProgression = {
switch direction {
case .horizontal: return CTFrameProgression.topToBottom
case .vertical: return CTFrameProgression.rightToLeft
case .verticalReversed: return CTFrameProgression.leftToRight
case .horizontal: return CTFrameProgression.topToBottom
case .vertical: return CTFrameProgression.rightToLeft
case .verticalReversed: return CTFrameProgression.leftToRight
}
}()
let frameAttrs: CFDictionary =
[
kCTFrameProgressionAttributeName: theCTFrameProgression.rawValue
kCTFrameProgressionAttributeName: theCTFrameProgression.rawValue,
] as CFDictionary
let newFrame = CTFramesetterCreateFrame(setter, CFRangeMake(0, 0), path, frameAttrs)
ctFrame = newFrame

View File

@ -4,19 +4,19 @@ import PackageDescription
let package = Package(
name: "BookmarkManager",
platforms: [
.macOS(.v10_11)
.macOS(.v10_11),
],
products: [
.library(
name: "BookmarkManager",
targets: ["BookmarkManager"]
)
),
],
dependencies: [],
targets: [
.target(
name: "BookmarkManager",
dependencies: []
)
),
]
)

View File

@ -8,7 +8,7 @@ public class BookmarkManager {
// Save bookmark for URL. Use this inside the NSOpenPanel `begin` closure
public func saveBookmark(for url: URL) {
guard let bookmarkDic = getBookmarkData(url: url),
let bookmarkURL = getBookmarkURL()
let bookmarkURL = getBookmarkURL()
else {
NSLog("Error getting data or bookmarkURL")
return

View File

@ -4,19 +4,19 @@ import PackageDescription
let package = Package(
name: "ShiftKeyUpChecker",
platforms: [
.macOS(.v10_11)
.macOS(.v10_11),
],
products: [
.library(
name: "ShiftKeyUpChecker",
targets: ["ShiftKeyUpChecker"]
)
),
],
dependencies: [],
targets: [
.target(
name: "ShiftKeyUpChecker",
dependencies: []
)
),
]
)

View File

@ -5,8 +5,8 @@
import Carbon
import Cocoa
extension Date {
fileprivate static func - (lhs: Date, rhs: Date) -> TimeInterval {
private extension Date {
static func - (lhs: Date, rhs: Date) -> TimeInterval {
lhs.timeIntervalSinceReferenceDate - rhs.timeIntervalSinceReferenceDate
}
}
@ -40,8 +40,8 @@ public struct ShiftKeyUpChecker {
private mutating func checkModifierKeyUp(event: NSEvent) -> Bool {
if event.type == .flagsChanged,
event.modifierFlags.intersection(.deviceIndependentFlagsMask) == .init(rawValue: 0),
Date() - lastTime <= delayInterval, shiftIsBeingPressed
event.modifierFlags.intersection(.deviceIndependentFlagsMask) == .init(rawValue: 0),
Date() - lastTime <= delayInterval, shiftIsBeingPressed
{
// modifier keyup event
lastTime = Date(timeInterval: -3600 * 4, since: Date())
@ -56,8 +56,8 @@ public struct ShiftKeyUpChecker {
print("isLeftShift: \(isLeftShift), isRightShift: \(isRightShift)")
let isKeyDown =
event.type == .flagsChanged
&& checkModifier.contains(event.modifierFlags.intersection(.deviceIndependentFlagsMask))
&& checkKeyCode.contains(event.keyCode)
&& checkModifier.contains(event.modifierFlags.intersection(.deviceIndependentFlagsMask))
&& checkKeyCode.contains(event.keyCode)
if isKeyDown {
// modifier keydown event
lastTime = Date()

View File

@ -4,23 +4,23 @@ import PackageDescription
let package = Package(
name: "LineReader",
platforms: [
.macOS(.v10_11)
.macOS(.v10_11),
],
products: [
.library(
name: "LineReader",
targets: ["LineReader"]
)
),
],
dependencies: [
.package(path: "../vChewing_SwiftExtension")
.package(path: "../vChewing_SwiftExtension"),
],
targets: [
.target(
name: "LineReader",
dependencies: [
.product(name: "SwiftExtension", package: "vChewing_SwiftExtension")
.product(name: "SwiftExtension", package: "vChewing_SwiftExtension"),
]
)
),
]
)

View File

@ -31,9 +31,9 @@ public class LineReader {
// get a data from the buffer up to the next delimiter
if let range = buffer.range(of: delimData) {
// convert data to a string
let line = String(data: buffer.subdata(in: 0..<range.lowerBound), encoding: encoding)!
let line = String(data: buffer.subdata(in: 0 ..< range.lowerBound), encoding: encoding)!
// remove that data from the buffer
buffer.removeSubrange(0..<range.upperBound)
buffer.removeSubrange(0 ..< range.upperBound)
return line.trimmingCharacters(in: .newlines)
}

View File

@ -13,10 +13,10 @@ let package = Package(
.library(
name: "SwiftUIBackports",
targets: ["SwiftUIBackports"]
)
),
],
targets: [
.target(name: "SwiftUIBackports")
.target(name: "SwiftUIBackports"),
],
swiftLanguageVersions: [.v5]
)

View File

@ -42,21 +42,21 @@ public struct Backport<Wrapped> {
}
@available(macOS 10.15, *)
extension View {
public extension View {
/// Wraps a SwiftUI `View` that can be extended to provide backport functionality.
public var backport: Backport<Self> { .init(self) }
var backport: Backport<Self> { .init(self) }
}
@available(macOS 10.15, *)
extension NSObjectProtocol {
public extension NSObjectProtocol {
/// Wraps an `NSObject` that can be extended to provide backport functionality.
public var backport: Backport<Self> { .init(self) }
var backport: Backport<Self> { .init(self) }
}
@available(macOS 10.15, *)
extension AnyTransition {
public extension AnyTransition {
/// Wraps an `AnyTransition` that can be extended to provide backport functionality.
public static var backport: Backport<AnyTransition> {
static var backport: Backport<AnyTransition> {
Backport(.identity)
}
}

View File

@ -7,7 +7,7 @@ import SwiftUI
@available(macOS 10.15, *)
/// A geometry reader that automatically sizes its height to 'fit' its content.
public struct FittingGeometryReader<Content>: View where Content: View {
@State private var height: CGFloat = 10 // must be non-zero
@State private var height: CGFloat = 10 // must be non-zero
private var content: (GeometryProxy) -> Content
@available(macOS 10.15, *)

View File

@ -5,12 +5,12 @@
import SwiftUI
@available(macOS 10.15, *)
extension EnvironmentValues {
fileprivate func containsValue(forKey key: String) -> Bool {
private extension EnvironmentValues {
func containsValue(forKey key: String) -> Bool {
value(forKey: key) != nil
}
fileprivate func value<T>(forKey key: String, from mirror: Mirror, as _: T.Type) -> T? {
func value<T>(forKey key: String, from mirror: Mirror, as _: T.Type) -> T? {
// Found a match
if let value = mirror.descendant("value", "some") {
if let typedValue = value as? T {
@ -32,7 +32,7 @@ extension EnvironmentValues {
/// Extracts a value from the environment by the name of its associated EnvironmentKey.
/// Can be used to grab private environment values such as foregroundColor ("ForegroundColorKey").
fileprivate func value<T>(forKey key: String, as _: T.Type) -> T? {
func value<T>(forKey key: String, as _: T.Type) -> T? {
if let mirror = value(forKey: key) as? Mirror {
return value(forKey: key, from: mirror, as: T.self)
} else if let value = value(forKey: key) as? T {
@ -42,7 +42,7 @@ extension EnvironmentValues {
}
}
fileprivate func value(forKey key: String) -> Any? {
func value(forKey key: String) -> Any? {
func keyFromTypeName(typeName: String) -> String? {
let expectedPrefix = "TypedElement<EnvironmentPropertyKey<"
guard typeName.hasPrefix(expectedPrefix) else {
@ -74,7 +74,7 @@ extension EnvironmentValues {
// Environment values are stored in a doubly linked list. The "before" and "after" keys point
// to the next environment member.
if let linkedListMirror = mirror.superclassMirror,
let nextNode = linkedListMirror.descendant("after", "some")
let nextNode = linkedListMirror.descendant("after", "some")
{
return extract(startingAt: nextNode)
}

View File

@ -123,7 +123,7 @@ import SwiftUI
#if os(iOS)
extension InspectionView {
fileprivate struct Representable: UIViewRepresentable {
struct Representable: UIViewRepresentable {
let parent: InspectionView
func makeUIView(context _: Context) -> UIView { .init() }
@ -149,7 +149,7 @@ import SwiftUI
#elseif os(macOS)
@available(macOS 10.15, *)
extension InspectionView {
fileprivate struct Representable: NSViewRepresentable {
struct Representable: NSViewRepresentable {
let parent: InspectionView
func makeNSView(context _: Context) -> NSView {

View File

@ -5,8 +5,8 @@
#if os(iOS)
import UIKit
extension UIView {
public var parentController: UIViewController? {
public extension UIView {
var parentController: UIViewController? {
var responder: UIResponder? = self
while !(responder is UIViewController), superview != nil {
@ -24,8 +24,8 @@
import AppKit
@available(macOS 10.15, *)
extension NSView {
public var parentController: NSViewController? {
public extension NSView {
var parentController: NSViewController? {
var responder: NSResponder? = self
while !(responder is NSViewController), superview != nil {

View File

@ -29,12 +29,12 @@ import SwiftUI
guard let viewClassNameUtf8 = (viewSubclassName as NSString).utf8String else { return }
guard let viewSubclass = objc_allocateClassPair(viewClass, viewClassNameUtf8, 0) else { return }
if let method = class_getInstanceMethod(UIView.self, #selector(getter:UIView.safeAreaInsets)) {
if let method = class_getInstanceMethod(UIView.self, #selector(getter: UIView.safeAreaInsets)) {
let safeAreaInsets: @convention(block) (AnyObject) -> UIEdgeInsets = { _ in
.zero
}
class_addMethod(
viewSubclass, #selector(getter:UIView.safeAreaInsets), imp_implementationWithBlock(safeAreaInsets),
viewSubclass, #selector(getter: UIView.safeAreaInsets), imp_implementationWithBlock(safeAreaInsets),
method_getTypeEncoding(method)
)
}

View File

@ -43,7 +43,7 @@ extension Backport where Wrapped == Any {
}
@available(macOS 10.15, *)
extension Backport.AppStorage {
public extension Backport.AppStorage {
/// Creates a property that can read and write to a boolean user default.
///
/// - Parameters:
@ -53,7 +53,7 @@ extension Backport.AppStorage {
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value == Bool {
init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value == Bool {
let value = store.value(forKey: key) as? Value ?? wrappedValue
self.init(
value: value, store: store, key: key,
@ -71,7 +71,7 @@ extension Backport.AppStorage {
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value == Int {
init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value == Int {
let value = store.value(forKey: key) as? Value ?? wrappedValue
self.init(
value: value, store: store, key: key,
@ -89,7 +89,7 @@ extension Backport.AppStorage {
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value == Double {
init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value == Double {
let value = store.value(forKey: key) as? Value ?? wrappedValue
self.init(
value: value, store: store, key: key,
@ -107,7 +107,7 @@ extension Backport.AppStorage {
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value == String {
init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value == String {
let value = store.value(forKey: key) as? Value ?? wrappedValue
self.init(
value: value, store: store, key: key,
@ -125,7 +125,7 @@ extension Backport.AppStorage {
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value == URL {
init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value == URL {
let value = store.url(forKey: key) ?? wrappedValue
self.init(
value: value, store: store, key: key,
@ -146,7 +146,7 @@ extension Backport.AppStorage {
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value == Data {
init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value == Data {
let value = store.value(forKey: key) as? Data ?? wrappedValue
self.init(
value: value, store: store, key: key,
@ -157,7 +157,7 @@ extension Backport.AppStorage {
}
@available(macOS 10.15, *)
extension Backport.AppStorage where Wrapped == Any, Value: ExpressibleByNilLiteral {
public extension Backport.AppStorage where Wrapped == Any, Value: ExpressibleByNilLiteral {
/// Creates a property that can read and write an Optional boolean user
/// default.
///
@ -168,7 +168,7 @@ extension Backport.AppStorage where Wrapped == Any, Value: ExpressibleByNilLiter
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(_ key: String, store: UserDefaults = .standard) where Value == Bool? {
init(_ key: String, store: UserDefaults = .standard) where Value == Bool? {
let value = store.value(forKey: key) as? Value ?? .none
self.init(
value: value, store: store, key: key,
@ -187,7 +187,7 @@ extension Backport.AppStorage where Wrapped == Any, Value: ExpressibleByNilLiter
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(_ key: String, store: UserDefaults = .standard) where Value == Int? {
init(_ key: String, store: UserDefaults = .standard) where Value == Int? {
let value = store.value(forKey: key) as? Value ?? .none
self.init(
value: value, store: store, key: key,
@ -206,7 +206,7 @@ extension Backport.AppStorage where Wrapped == Any, Value: ExpressibleByNilLiter
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(_ key: String, store: UserDefaults = .standard) where Value == Double? {
init(_ key: String, store: UserDefaults = .standard) where Value == Double? {
let value = store.value(forKey: key) as? Value ?? .none
self.init(
value: value, store: store, key: key,
@ -225,7 +225,7 @@ extension Backport.AppStorage where Wrapped == Any, Value: ExpressibleByNilLiter
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(_ key: String, store: UserDefaults = .standard) where Value == String? {
init(_ key: String, store: UserDefaults = .standard) where Value == String? {
let value = store.value(forKey: key) as? Value ?? .none
self.init(
value: value, store: store, key: key,
@ -244,7 +244,7 @@ extension Backport.AppStorage where Wrapped == Any, Value: ExpressibleByNilLiter
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(_ key: String, store: UserDefaults = .standard) where Value == URL? {
init(_ key: String, store: UserDefaults = .standard) where Value == URL? {
let value = store.url(forKey: key) ?? .none
self.init(
value: value, store: store, key: key,
@ -263,7 +263,7 @@ extension Backport.AppStorage where Wrapped == Any, Value: ExpressibleByNilLiter
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(_ key: String, store: UserDefaults = .standard) where Value == Data? {
init(_ key: String, store: UserDefaults = .standard) where Value == Data? {
let value = store.value(forKey: key) as? Value ?? .none
self.init(
value: value, store: store, key: key,
@ -274,7 +274,7 @@ extension Backport.AppStorage where Wrapped == Any, Value: ExpressibleByNilLiter
}
@available(macOS 10.15, *)
extension Backport.AppStorage where Wrapped == Any, Value: RawRepresentable {
public extension Backport.AppStorage where Wrapped == Any, Value: RawRepresentable {
/// Creates a property that can read and write to a string user default,
/// transforming that to `RawRepresentable` data type.
///
@ -295,7 +295,7 @@ extension Backport.AppStorage where Wrapped == Any, Value: RawRepresentable {
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value.RawValue == String {
init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value.RawValue == String {
let rawValue = store.value(forKey: key) as? Value.RawValue
let value = rawValue.flatMap(Value.init) ?? wrappedValue
self.init(
@ -325,7 +325,7 @@ extension Backport.AppStorage where Wrapped == Any, Value: RawRepresentable {
/// store.
/// - store: The store to read and write to. A value
/// of `nil` will use the user default store from the environment.
public init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value.RawValue == Int {
init(wrappedValue: Value, _ key: String, store: UserDefaults = .standard) where Value.RawValue == Int {
let rawValue = store.value(forKey: key) as? Value.RawValue
let value = rawValue.flatMap(Value.init) ?? wrappedValue
self.init(

View File

@ -5,7 +5,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension Backport where Wrapped: View {
public extension Backport where Wrapped: View {
/// Layers the views that you specify behind this view.
///
/// Use this modifier to place one or more views behind another view.
@ -128,7 +128,7 @@ extension Backport where Wrapped: View {
/// The last view that you list appears at the front of the stack.
///
/// - Returns: A view that uses the specified content as a background.
public func background<Content: View>(alignment: Alignment = .center, @ViewBuilder _ content: () -> Content)
func background<Content: View>(alignment: Alignment = .center, @ViewBuilder _ content: () -> Content)
-> some View
{
self.content.background(content(), alignment: alignment)

View File

@ -5,7 +5,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension EnvironmentValues {
public extension EnvironmentValues {
/// An action that dismisses the current presentation.
///
/// Use this environment value to get the ``Backport.DismissAction`` instance
@ -73,7 +73,7 @@ extension EnvironmentValues {
/// The dismiss action has no effect on a view that isn't currently
/// presented. If you need to query whether SwiftUI is currently presenting
/// a view, read the ``EnvironmentValues/backportIsPresented`` environment value.
public var backportDismiss: Backport<Any>.DismissAction {
var backportDismiss: Backport<Any>.DismissAction {
.init(presentation: presentationMode)
}
@ -104,7 +104,7 @@ extension EnvironmentValues {
///
/// To dismiss the currently presented view, use
/// ``EnvironmentValues/backportDismiss``.
public var backportIsPresented: Bool {
var backportIsPresented: Bool {
presentationMode.wrappedValue.isPresented
}
}

View File

@ -5,7 +5,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension Backport where Wrapped: View {
public extension Backport where Wrapped: View {
/// Sets the Dynamic Type size within the view to the given value.
///
/// As an example, you can set a Dynamic Type size in `ContentView` to be
@ -31,7 +31,7 @@ extension Backport where Wrapped: View {
/// - Returns: A view that sets the Dynamic Type size to the specified
/// `size`.
@ViewBuilder
public func dynamicTypeSize(_ size: Backport<Any>.DynamicTypeSize) -> some View {
func dynamicTypeSize(_ size: Backport<Any>.DynamicTypeSize) -> some View {
content.environment(\.backportDynamicTypeSize, size)
}
@ -66,8 +66,9 @@ extension Backport where Wrapped: View {
/// - Returns: A view that constrains the Dynamic Type size of this view
/// within the specified `range`.
@ViewBuilder
public func dynamicTypeSize<T>(_ range: T) -> some View
where T: RangeExpression, T.Bound == Backport<Any>.DynamicTypeSize {
func dynamicTypeSize<T>(_ range: T) -> some View
where T: RangeExpression, T.Bound == Backport<Any>.DynamicTypeSize
{
if let range = range as? Range<T.Bound> {
content
.modifier(DynamicTypeRangeModifier())

View File

@ -63,38 +63,6 @@ extension Backport where Wrapped == Any {
/// Create a Dynamic Type size from its `UIContentSizeCategory` equivalent.
public init?(_ uiSizeCategory: UIContentSizeCategory) {
switch uiSizeCategory {
case .extraSmall:
self = .xSmall
case .small:
self = .small
case .medium:
self = .medium
case .large:
self = .medium
case .extraLarge:
self = .xLarge
case .extraExtraLarge:
self = .xxLarge
case .extraExtraExtraLarge:
self = .xxxLarge
case .accessibilityMedium:
self = .accessibility1
case .accessibilityLarge:
self = .accessibility2
case .accessibilityExtraLarge:
self = .accessibility3
case .accessibilityExtraExtraLarge:
self = .accessibility4
case .accessibilityExtraExtraExtraLarge:
self = .accessibility5
default:
return nil
}
}
#endif
internal init(_ sizeCategory: ContentSizeCategory) {
switch sizeCategory {
case .extraSmall:
self = .xSmall
case .small:
@ -102,7 +70,7 @@ extension Backport where Wrapped == Any {
case .medium:
self = .medium
case .large:
self = .large
self = .medium
case .extraLarge:
self = .xLarge
case .extraExtraLarge:
@ -120,36 +88,68 @@ extension Backport where Wrapped == Any {
case .accessibilityExtraExtraExtraLarge:
self = .accessibility5
default:
self = .large
return nil
}
}
#endif
internal init(_ sizeCategory: ContentSizeCategory) {
switch sizeCategory {
case .extraSmall:
self = .xSmall
case .small:
self = .small
case .medium:
self = .medium
case .large:
self = .large
case .extraLarge:
self = .xLarge
case .extraExtraLarge:
self = .xxLarge
case .extraExtraExtraLarge:
self = .xxxLarge
case .accessibilityMedium:
self = .accessibility1
case .accessibilityLarge:
self = .accessibility2
case .accessibilityExtraLarge:
self = .accessibility3
case .accessibilityExtraExtraLarge:
self = .accessibility4
case .accessibilityExtraExtraExtraLarge:
self = .accessibility5
default:
self = .large
}
}
var sizeCategory: ContentSizeCategory {
switch self {
case .xSmall:
return .extraSmall
case .small:
return .small
case .medium:
return .medium
case .large:
return .large
case .xLarge:
return .extraLarge
case .xxLarge:
return .extraExtraLarge
case .xxxLarge:
return .extraExtraExtraLarge
case .accessibility1:
return .accessibilityMedium
case .accessibility2:
return .accessibilityLarge
case .accessibility3:
return .accessibilityExtraLarge
case .accessibility4:
return .accessibilityExtraExtraLarge
case .accessibility5:
return .accessibilityExtraExtraExtraLarge
case .xSmall:
return .extraSmall
case .small:
return .small
case .medium:
return .medium
case .large:
return .large
case .xLarge:
return .extraLarge
case .xxLarge:
return .extraExtraLarge
case .xxxLarge:
return .extraExtraExtraLarge
case .accessibility1:
return .accessibilityMedium
case .accessibility2:
return .accessibilityLarge
case .accessibility3:
return .accessibilityExtraLarge
case .accessibility4:
return .accessibilityExtraExtraLarge
case .accessibility5:
return .accessibilityExtraExtraExtraLarge
}
}
}
@ -159,30 +159,30 @@ extension Backport where Wrapped == Any {
extension Backport.DynamicTypeSize {
var dynamicTypeSize: DynamicTypeSize {
switch self {
case .xSmall:
return .xSmall
case .small:
return .small
case .medium:
return .medium
case .large:
return .large
case .xLarge:
return .xLarge
case .xxLarge:
return .xxLarge
case .xxxLarge:
return .xxxLarge
case .accessibility1:
return .accessibility1
case .accessibility2:
return .accessibility2
case .accessibility3:
return .accessibility3
case .accessibility4:
return .accessibility4
case .accessibility5:
return .accessibility5
case .xSmall:
return .xSmall
case .small:
return .small
case .medium:
return .medium
case .large:
return .large
case .xLarge:
return .xLarge
case .xxLarge:
return .xxLarge
case .xxxLarge:
return .xxxLarge
case .accessibility1:
return .accessibility1
case .accessibility2:
return .accessibility2
case .accessibility3:
return .accessibility3
case .accessibility4:
return .accessibility4
case .accessibility5:
return .accessibility5
}
}
}
@ -193,32 +193,32 @@ extension Backport.DynamicTypeSize {
extension UIContentSizeCategory {
public init(_ dynamicTypeSize: Backport<Any>.DynamicTypeSize?) {
switch dynamicTypeSize {
case .xSmall:
self = .extraSmall
case .small:
self = .small
case .medium:
self = .medium
case .large:
self = .large
case .xLarge:
self = .extraLarge
case .xxLarge:
self = .extraExtraLarge
case .xxxLarge:
self = .extraExtraExtraLarge
case .accessibility1:
self = .accessibilityMedium
case .accessibility2:
self = .accessibilityLarge
case .accessibility3:
self = .accessibilityExtraLarge
case .accessibility4:
self = .accessibilityExtraExtraLarge
case .accessibility5:
self = .accessibilityExtraExtraExtraLarge
case .none:
self = .large
case .xSmall:
self = .extraSmall
case .small:
self = .small
case .medium:
self = .medium
case .large:
self = .large
case .xLarge:
self = .extraLarge
case .xxLarge:
self = .extraExtraLarge
case .xxxLarge:
self = .extraExtraExtraLarge
case .accessibility1:
self = .accessibilityMedium
case .accessibility2:
self = .accessibilityLarge
case .accessibility3:
self = .accessibilityExtraLarge
case .accessibility4:
self = .accessibilityExtraExtraLarge
case .accessibility5:
self = .accessibilityExtraExtraExtraLarge
case .none:
self = .large
}
}
}

View File

@ -111,14 +111,14 @@ extension Backport where Wrapped == Any {
}
@available(macOS 10.15, *)
extension Backport.Label where Wrapped == Any, Title == Text, Icon == Image {
public extension Backport.Label where Wrapped == Any, Title == Text, Icon == Image {
/// Creates a label with an icon image and a title generated from a
/// localized string.
///
/// - Parameters:
/// - titleKey: A title generated from a localized string.
/// - image: The name of the image resource to lookup.
public init(_ titleKey: LocalizedStringKey, image name: String) {
init(_ titleKey: LocalizedStringKey, image name: String) {
self.init(title: { Text(titleKey) }, icon: { Image(name) })
}
@ -127,7 +127,7 @@ extension Backport.Label where Wrapped == Any, Title == Text, Icon == Image {
/// - Parameters:
/// - title: A string used as the label's title.
/// - image: The name of the image resource to lookup.
public init<S>(_ title: S, image name: String) where S: StringProtocol {
init<S>(_ title: S, image name: String) where S: StringProtocol {
self.init(title: { Text(title) }, icon: { Image(name) })
}
}
@ -156,8 +156,9 @@ extension Backport.Label where Wrapped == Any, Title == Text, Icon == Image {
}
@available(macOS 10.15, *)
extension Backport.Label
where Wrapped == Any, Title == Backport.LabelStyleConfiguration.Title, Icon == Backport.LabelStyleConfiguration.Icon {
public extension Backport.Label
where Wrapped == Any, Title == Backport.LabelStyleConfiguration.Title, Icon == Backport.LabelStyleConfiguration.Icon
{
/// Creates a label representing the configuration of a style.
///
/// You can use this initializer within the ``LabelStyle/makeBody(configuration:)``
@ -177,7 +178,7 @@ where Wrapped == Any, Title == Backport.LabelStyleConfiguration.Title, Icon == B
/// }
///
/// - Parameter configuration: The label style to use.
public init(_ configuration: Backport.LabelStyleConfiguration) {
init(_ configuration: Backport.LabelStyleConfiguration) {
config = configuration
}
}

View File

@ -137,8 +137,8 @@ extension Backport where Wrapped == Any {
}
@available(macOS 10.15, *)
extension Backport.LabeledContent
where
public extension Backport.LabeledContent
where
Wrapped == Any, Label == Backport<Any>.LabeledContentStyleConfiguration.Label,
Content == Backport<Any>.LabeledContentStyleConfiguration.Content
{
@ -161,13 +161,13 @@ where
/// }
///
/// - Parameter configuration: The properties of the labeled content
public init(_ config: Backport.LabeledContentStyleConfiguration) {
init(_ config: Backport.LabeledContentStyleConfiguration) {
self.config = config
}
}
@available(macOS 10.15, *)
extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content: View {
public extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content: View {
/// Creates a labeled view that generates its label from a localized string
/// key.
///
@ -179,7 +179,7 @@ extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content:
/// - titleKey: The key for the view's localized title, that describes
/// the purpose of the view.
/// - content: The value content being labeled.
public init(_ titleKey: LocalizedStringKey, @ViewBuilder content: () -> Content) {
init(_ titleKey: LocalizedStringKey, @ViewBuilder content: () -> Content) {
config = .init(
label: Text(titleKey),
content: content()
@ -196,7 +196,7 @@ extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content:
/// - Parameters:
/// - title: A string that describes the purpose of the view.
/// - content: The value content being labeled.
public init<S>(_ title: S, @ViewBuilder content: () -> Content) where S: StringProtocol {
init<S>(_ title: S, @ViewBuilder content: () -> Content) where S: StringProtocol {
config = .init(
label: Text(title),
content: content()
@ -226,7 +226,7 @@ extension Backport.LabeledContent: View where Wrapped == Any, Label: View, Conte
}
@available(macOS 10.15, *)
extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content == Text {
public extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content == Text {
/// Creates a labeled informational view.
///
/// This initializer creates a ``Text`` label on your behalf, and treats the
@ -243,7 +243,7 @@ extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content =
/// - titleKey: The key for the view's localized title, that describes
/// the purpose of the view.
/// - value: The value being labeled.
public init<S: StringProtocol>(_ titleKey: LocalizedStringKey, value: S) {
init<S: StringProtocol>(_ titleKey: LocalizedStringKey, value: S) {
config = .init(
label: Text(titleKey),
content: Text(value)
@ -266,7 +266,7 @@ extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content =
/// - Parameters:
/// - title: A string that describes the purpose of the view.
/// - value: The value being labeled.
public init<S1: StringProtocol, S2: StringProtocol>(_ title: S1, value: S2) {
init<S1: StringProtocol, S2: StringProtocol>(_ title: S1, value: S2) {
config = .init(
label: Text(title),
content: Text(value)

View File

@ -5,8 +5,8 @@
import SwiftUI
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
public struct AutomaticLabeledContentStyle: BackportLabeledContentStyle {
public extension Backport where Wrapped == Any {
struct AutomaticLabeledContentStyle: BackportLabeledContentStyle {
public func makeBody(configuration: Configuration) -> some View {
HStack(alignment: .firstTextBaseline) {
configuration.label

View File

@ -47,7 +47,7 @@ extension Backport where Wrapped: View {
.environment(
\.navigationDestinations,
[
.init(type: D.self): .init { destination($0 as! D) }
.init(type: D.self): .init { destination($0 as! D) },
]
)
}
@ -96,8 +96,8 @@ private struct NavigationDestinationsEnvironmentKey: EnvironmentKey {
}
@available(macOS 10.15, *)
extension EnvironmentValues {
fileprivate var navigationDestinations: [AnyMetaType: DestinationView] {
private extension EnvironmentValues {
var navigationDestinations: [AnyMetaType: DestinationView] {
get { self[NavigationDestinationsEnvironmentKey.self] }
set {
var current = self[NavigationDestinationsEnvironmentKey.self]
@ -127,8 +127,8 @@ extension AnyMetaType: Hashable {
}
@available(macOS 10.15, *)
extension Dictionary {
fileprivate subscript(_ key: Any.Type) -> Value? where Key == AnyMetaType {
private extension Dictionary {
subscript(_ key: Any.Type) -> Value? where Key == AnyMetaType {
get { self[.init(type: key)] }
_modify { yield &self[.init(type: key)] }
}

View File

@ -132,16 +132,16 @@ extension Backport where Wrapped == Any {
let result = handler(url).value
switch result {
case .handled, .discarded: break
case let .systemAction(updatedUrl):
let resolved = updatedUrl ?? url
#if os(macOS)
NSWorkspace.shared.open(resolved)
#elseif os(iOS) || os(tvOS)
UIApplication.shared.open(resolved)
#else
WKExtension.shared().openSystemURL(resolved)
#endif
case .handled, .discarded: break
case let .systemAction(updatedUrl):
let resolved = updatedUrl ?? url
#if os(macOS)
NSWorkspace.shared.open(resolved)
#elseif os(iOS) || os(tvOS)
UIApplication.shared.open(resolved)
#else
WKExtension.shared().openSystemURL(resolved)
#endif
}
return result
@ -169,8 +169,8 @@ private struct BackportOpenURLKey: EnvironmentKey {
}
@available(macOS 10.15, *)
extension EnvironmentValues {
public var backportOpenURL: Backport<Any>.OpenURLAction {
public extension EnvironmentValues {
var backportOpenURL: Backport<Any>.OpenURLAction {
get { self[BackportOpenURLKey.self] }
set { self[BackportOpenURLKey.self] = newValue }
}

View File

@ -5,7 +5,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension Backport where Wrapped: View {
public extension Backport where Wrapped: View {
/// Layers the views that you specify in front of this view.
///
/// Use this modifier to place one or more views in front of another view.
@ -121,8 +121,7 @@ extension Backport where Wrapped: View {
/// The last view that you list appears at the front of the stack.
///
/// - Returns: A view that uses the specified content as a foreground.
public func overlay<Content: View>(alignment: Alignment = .center, @ViewBuilder _ content: () -> Content) -> some View
{
func overlay<Content: View>(alignment: Alignment = .center, @ViewBuilder _ content: () -> Content) -> some View {
self.content.overlay(content(), alignment: alignment)
}
}

View File

@ -104,7 +104,8 @@ extension Backport.ProgressView where Wrapped == Any {
/// task, meaning the task is complete if `value` equals `total`. The
/// default value is `1.0`.
public init<V>(value: V?, total: V = 1.0)
where Label == EmptyView, CurrentValueLabel == EmptyView, V: BinaryFloatingPoint {
where Label == EmptyView, CurrentValueLabel == EmptyView, V: BinaryFloatingPoint
{
if let value = value {
config = .init(fractionCompleted: Double(value) / Double(total), preferredKind: .linear, max: Double(total))
} else {
@ -130,7 +131,8 @@ extension Backport.ProgressView where Wrapped == Any {
/// - label: A view builder that creates a view that describes the task
/// in progress.
public init<V>(value: V?, total: V = 1.0, @ViewBuilder label: () -> Label)
where CurrentValueLabel == EmptyView, V: BinaryFloatingPoint {
where CurrentValueLabel == EmptyView, V: BinaryFloatingPoint
{
if let value = value {
config = .init(
fractionCompleted: Double(value) / Double(total), label: .init(content: label()), preferredKind: .linear
@ -200,7 +202,8 @@ extension Backport.ProgressView where Wrapped == Any {
/// task, meaning the task is complete if `value` equals `total`. The
/// default value is `1.0`.
public init<V>(_ titleKey: LocalizedStringKey, value: V?, total: V = 1.0)
where Label == Text, CurrentValueLabel == EmptyView, V: BinaryFloatingPoint {
where Label == Text, CurrentValueLabel == EmptyView, V: BinaryFloatingPoint
{
if let value = value {
config = .init(
fractionCompleted: Double(value) / Double(total), label: .init(content: Text(titleKey)), preferredKind: .linear,
@ -237,7 +240,8 @@ extension Backport.ProgressView where Wrapped == Any {
/// task, meaning the task is complete if `value` equals `total`. The
/// default value is `1.0`.
public init<S, V>(_ title: S, value: V?, total: V = 1.0)
where Label == Text, CurrentValueLabel == EmptyView, S: StringProtocol, V: BinaryFloatingPoint {
where Label == Text, CurrentValueLabel == EmptyView, S: StringProtocol, V: BinaryFloatingPoint
{
if let value = value {
config = .init(
fractionCompleted: Double(value) / Double(total), label: .init(content: Text(title)), preferredKind: .linear,

View File

@ -42,8 +42,8 @@ extension Backport where Wrapped == Any {
}
@available(macOS 10.15, *)
extension BackportProgressViewStyle where Self == Backport<Any>.CircularProgressViewStyle {
public static var circular: Self { .init() }
public extension BackportProgressViewStyle where Self == Backport<Any>.CircularProgressViewStyle {
static var circular: Self { .init() }
}
#if os(macOS)

View File

@ -31,24 +31,24 @@ extension Backport where Wrapped == Any {
/// its preferred progress type.
public func makeBody(configuration: Configuration) -> some View {
switch configuration.preferredKind {
case .circular:
Backport.CircularProgressViewStyle().makeBody(configuration: configuration)
case .linear:
#if os(iOS)
if configuration.fractionCompleted == nil {
Backport.CircularProgressViewStyle().makeBody(configuration: configuration)
} else {
Backport.LinearProgressViewStyle().makeBody(configuration: configuration)
}
#else
case .circular:
Backport.CircularProgressViewStyle().makeBody(configuration: configuration)
case .linear:
#if os(iOS)
if configuration.fractionCompleted == nil {
Backport.CircularProgressViewStyle().makeBody(configuration: configuration)
} else {
Backport.LinearProgressViewStyle().makeBody(configuration: configuration)
#endif
}
#else
Backport.LinearProgressViewStyle().makeBody(configuration: configuration)
#endif
}
}
}
}
@available(macOS 10.15, *)
extension BackportProgressViewStyle where Self == Backport<Any>.DefaultProgressViewStyle {
public static var automatic: Self { .init() }
public extension BackportProgressViewStyle where Self == Backport<Any>.DefaultProgressViewStyle {
static var automatic: Self { .init() }
}

View File

@ -63,8 +63,8 @@ extension Backport where Wrapped == Any {
}
@available(macOS 10.15, *)
extension BackportProgressViewStyle where Self == Backport<Any>.LinearProgressViewStyle {
public static var linear: Self { .init() }
public extension BackportProgressViewStyle where Self == Backport<Any>.LinearProgressViewStyle {
static var linear: Self { .init() }
}
#if os(macOS)

View File

@ -9,7 +9,8 @@ import SwiftUI
final class PreviewController<Items>: UIViewController, UIAdaptivePresentationControllerDelegate,
QLPreviewControllerDelegate, QLPreviewControllerDataSource
where Items: RandomAccessCollection, Items.Element == URL {
where Items: RandomAccessCollection, Items.Element == URL
{
var items: Items
var selection: Binding<Items.Element?> {
@ -34,14 +35,14 @@ import SwiftUI
private func updateControllerLifecycle(from oldValue: Items.Element?, to newValue: Items.Element?) {
switch (oldValue, newValue) {
case (.none, .some):
presentController()
case (.some, .some):
updateController()
case (.some, .none):
dismissController()
case (.none, .none):
break
case (.none, .some):
presentController()
case (.some, .some):
updateController()
case (.some, .none):
dismissController()
case (.none, .none):
break
}
}

View File

@ -10,7 +10,8 @@ import SwiftUI
@available(macOS 10.15, *)
final class PreviewController<Items>: NSViewController, QLPreviewPanelDataSource, QLPreviewPanelDelegate
where Items: RandomAccessCollection, Items.Element == URL {
where Items: RandomAccessCollection, Items.Element == URL
{
private let panel = QLPreviewPanel.shared()!
private weak var windowResponder: NSResponder?
@ -27,14 +28,14 @@ import SwiftUI
private func updateControllerLifecycle(from oldValue: Items.Element?, to newValue: Items.Element?) {
switch (oldValue, newValue) {
case (.none, .some):
present()
case (.some, .some):
update()
case (.some, .none):
dismiss()
case (.none, .none):
break
case (.none, .some):
present()
case (.some, .some):
update()
case (.some, .none):
dismiss()
case (.none, .none):
break
}
}

View File

@ -29,7 +29,8 @@ extension Backport where Wrapped: View {
///
/// - Returns: A view that presents the preview of the contents of the URL.
public func quickLookPreview<Items>(_ selection: Binding<Items.Element?>, in items: Items) -> some View
where Items: RandomAccessCollection, Items.Element == URL {
where Items: RandomAccessCollection, Items.Element == URL
{
#if os(iOS) || os(macOS)
content.background(QuicklookSheet(selection: selection, items: items))
#else
@ -64,7 +65,8 @@ extension Backport where Wrapped: View {
@available(macOS 10.15, *)
private struct QuicklookSheet<Items>: NSViewControllerRepresentable
where Items: RandomAccessCollection, Items.Element == URL {
where Items: RandomAccessCollection, Items.Element == URL
{
let selection: Binding<Items.Element?>
let items: Items
@ -81,7 +83,8 @@ extension Backport where Wrapped: View {
#elseif os(iOS)
private struct QuicklookSheet<Items>: UIViewControllerRepresentable
where Items: RandomAccessCollection, Items.Element == URL {
where Items: RandomAccessCollection, Items.Element == URL
{
let selection: Binding<Items.Element?>
let items: Items

View File

@ -3,14 +3,14 @@ import SwiftUI
#if os(iOS) || os(macOS)
@available(macOS 10.15, *)
extension EnvironmentValues {
public extension EnvironmentValues {
/// An instance that tells StoreKit to request an App Store rating or review from the user, if appropriate.
/// Read the requestReview environment value to get an instance of this structure for a given Environment. Call the instance to tell StoreKit to ask the user to rate or review your app, if appropriate. You call the instance directly because it defines a callAsFunction() method that Swift calls when you call the instance.
///
/// Although you normally call this instance to request a review when it makes sense in the user experience flow of your app, the App Store policy governs the actual display of the rating and review request view. Because calling this instance may not present an alert, dont call it in response to a user action, such as a button tap.
///
/// > When you call this instance while your app is in development mode, the system always displays a rating and review request view so you can test the user interface and experience. This instance has no effect when you call it in an app that you distribute using TestFlight.
@MainActor public var backportRequestReview: Backport<Any>.RequestReviewAction { .init() }
@MainActor var backportRequestReview: Backport<Any>.RequestReviewAction { .init() }
}
/// An instance that tells StoreKit to request an App Store rating or review from the user, if appropriate.

View File

@ -33,13 +33,13 @@ extension Backport where Wrapped == Any {
}
@available(macOS 10.15, *)
extension Backport.Section where Wrapped == Any, Parent == Text, Footer == EmptyView {
public extension Backport.Section where Wrapped == Any, Parent == Text, Footer == EmptyView {
/// Creates a section with the provided section content.
/// - Parameters:
/// - titleKey: The key for the section's localized title, which describes
/// the contents of the section.
/// - content: The section's content.
public init(_ titleKey: LocalizedStringKey, @ViewBuilder content: @escaping () -> Content) {
init(_ titleKey: LocalizedStringKey, @ViewBuilder content: @escaping () -> Content) {
header = { Text(titleKey) }
self.content = content
footer = { EmptyView() }
@ -50,7 +50,7 @@ extension Backport.Section where Wrapped == Any, Parent == Text, Footer == Empty
/// - Parameters:
/// - title: A string that describes the contents of the section.
/// - content: The section's content.
public init<S>(_ title: S, @ViewBuilder content: @escaping () -> Content) where S: StringProtocol {
init<S>(_ title: S, @ViewBuilder content: @escaping () -> Content) where S: StringProtocol {
header = { Text(title) }
self.content = content
footer = { EmptyView() }

View File

@ -5,7 +5,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension Backport where Wrapped == AnyTransition {
public extension Backport where Wrapped == AnyTransition {
/// Creates a transition that when added to a view will animate the views insertion by moving it in from the specified edge while fading it in, and animate its removal by moving it out towards the opposite edge and fading it out.
/// - Parameter edge: the edge from which the view will be animated in.
/// - Returns: A transition that animates a view by moving and fading it.
@ -13,17 +13,17 @@ extension Backport where Wrapped == AnyTransition {
@available(watchOS, deprecated: 9.0)
@available(macOS, deprecated: 13.0)
@available(tvOS, deprecated: 16.0)
public func push(from edge: Edge) -> AnyTransition {
func push(from edge: Edge) -> AnyTransition {
var oppositeEdge: Edge
switch edge {
case .top:
oppositeEdge = .bottom
case .leading:
oppositeEdge = .trailing
case .bottom:
oppositeEdge = .top
case .trailing:
oppositeEdge = .leading
case .top:
oppositeEdge = .bottom
case .leading:
oppositeEdge = .trailing
case .bottom:
oppositeEdge = .top
case .trailing:
oppositeEdge = .leading
}
return .asymmetric(

View File

@ -178,10 +178,10 @@ extension Backport where Wrapped == Any {
@available(macOS 10.15, *)
public static func < (lhs: PresentationDetent, rhs: PresentationDetent) -> Bool {
switch (lhs, rhs) {
case (.large, .medium):
return false
default:
return true
case (.large, .medium):
return false
default:
return true
}
}
}
@ -189,8 +189,8 @@ extension Backport where Wrapped == Any {
#if os(iOS)
@available(iOS 15, *)
extension Backport where Wrapped == Any {
fileprivate struct Representable: UIViewControllerRepresentable {
fileprivate extension Backport where Wrapped == Any {
struct Representable: UIViewControllerRepresentable {
let detents: Set<Backport<Any>.PresentationDetent>
let selection: Binding<Backport<Any>.PresentationDetent>?
let largestUndimmed: Backport<Any>.PresentationDetent?
@ -207,8 +207,8 @@ extension Backport where Wrapped == Any {
@available(macOS 10.15, *)
@available(iOS 15, *)
extension Backport.Representable {
fileprivate final class Controller: UIViewController, UISheetPresentationControllerDelegate {
fileprivate extension Backport.Representable {
final class Controller: UIViewController, UISheetPresentationControllerDelegate {
var detents: Set<Backport<Any>.PresentationDetent>
var selection: Binding<Backport<Any>.PresentationDetent>?
var largestUndimmed: Backport<Any>.PresentationDetent?
@ -256,10 +256,10 @@ extension Backport where Wrapped == Any {
controller.animateChanges {
controller.detents = detents.sorted().map {
switch $0 {
case .medium:
return .medium()
default:
return .large()
case .medium:
return .medium()
default:
return .large()
}
}

View File

@ -48,8 +48,8 @@ extension Backport where Wrapped: View {
#if os(iOS)
@available(iOS 15, *)
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
fileprivate struct Representable: UIViewControllerRepresentable {
fileprivate extension Backport where Wrapped == Any {
struct Representable: UIViewControllerRepresentable {
let visibility: Backport<Any>.Visibility
func makeUIViewController(context _: Context) -> Backport.Representable.Controller {
@ -64,8 +64,8 @@ extension Backport where Wrapped: View {
@available(macOS 10.15, *)
@available(iOS 15, *)
extension Backport.Representable {
fileprivate final class Controller: UIViewController {
fileprivate extension Backport.Representable {
final class Controller: UIViewController {
var visibility: Backport<Any>.Visibility
@available(macOS 10.15, *)

View File

@ -53,8 +53,8 @@ extension Backport where Wrapped: View {
#if os(iOS)
@available(iOS 15, *)
extension Backport where Wrapped == Any {
fileprivate struct Representable: UIViewControllerRepresentable {
fileprivate extension Backport where Wrapped == Any {
struct Representable: UIViewControllerRepresentable {
let identifier: Backport<Any>.PresentationDetent.Identifier?
func makeUIViewController(context _: Context) -> Backport.Representable.Controller {
@ -68,8 +68,8 @@ extension Backport where Wrapped: View {
}
@available(iOS 15, *)
extension Backport.Representable {
fileprivate final class Controller: UIViewController {
fileprivate extension Backport.Representable {
final class Controller: UIViewController {
var identifier: Backport<Any>.PresentationDetent.Identifier?
init(identifier: Backport<Any>.PresentationDetent.Identifier?) {

View File

@ -5,7 +5,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension Backport where Wrapped: View {
public extension Backport where Wrapped: View {
/// Conditionally prevents interactive dismissal of a popover or a sheet.
///
/// Users can dismiss certain kinds of presentations using built-in
@ -76,7 +76,7 @@ extension Backport where Wrapped: View {
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)
@available(watchOS, deprecated: 9)
public func interactiveDismissDisabled(_ isDisabled: Bool = true) -> some View {
func interactiveDismissDisabled(_ isDisabled: Bool = true) -> some View {
#if os(iOS)
if #available(iOS 15, *) {
content.background(Backport<Any>.Representable(isModal: isDisabled, onAttempt: nil))
@ -157,7 +157,7 @@ extension Backport where Wrapped: View {
/// - Parameter onAttempt: A closure that will be called when an interactive dismiss attempt occurs.
/// You can use this as an opportunity to present an confirmation or prompt to the user.
@ViewBuilder
public func interactiveDismissDisabled(_ isDisabled: Bool = true, onAttempt: @escaping () -> Void) -> some View {
func interactiveDismissDisabled(_ isDisabled: Bool = true, onAttempt: @escaping () -> Void) -> some View {
#if os(iOS)
if #available(iOS 15, *) {
content.background(Backport<Any>.Representable(isModal: isDisabled, onAttempt: onAttempt))
@ -172,8 +172,8 @@ extension Backport where Wrapped: View {
#if os(iOS)
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
fileprivate struct Representable: UIViewControllerRepresentable {
fileprivate extension Backport where Wrapped == Any {
struct Representable: UIViewControllerRepresentable {
let isModal: Bool
let onAttempt: (() -> Void)?
@ -190,8 +190,8 @@ extension Backport where Wrapped: View {
}
@available(macOS 10.15, *)
extension Backport.Representable {
fileprivate final class Controller: UIViewController, UIAdaptivePresentationControllerDelegate {
fileprivate extension Backport.Representable {
final class Controller: UIViewController, UIAdaptivePresentationControllerDelegate {
var isModal: Bool
var onAttempt: (() -> Void)?
weak var _delegate: UIAdaptivePresentationControllerDelegate?

View File

@ -24,7 +24,7 @@ extension Backport where Wrapped == Any {
public var wrappedValue: Value {
#if os(iOS) || os(tvOS)
let traits = UITraitCollection(traitsFrom: [
UITraitCollection(preferredContentSizeCategory: UIContentSizeCategory(sizeCategory: sizeCategory))
UITraitCollection(preferredContentSizeCategory: UIContentSizeCategory(sizeCategory: sizeCategory)),
])
return Value(metrics.scaledValue(for: CGFloat(baseValue), compatibleWith: traits))
@ -59,22 +59,22 @@ extension Backport where Wrapped == Any {
}
#if os(iOS) || os(tvOS)
extension UIContentSizeCategory {
fileprivate init(sizeCategory: ContentSizeCategory?) {
fileprivate extension UIContentSizeCategory {
init(sizeCategory: ContentSizeCategory?) {
switch sizeCategory {
case .accessibilityExtraExtraExtraLarge: self = .accessibilityExtraExtraExtraLarge
case .accessibilityExtraExtraLarge: self = .accessibilityExtraExtraLarge
case .accessibilityExtraLarge: self = .accessibilityExtraLarge
case .accessibilityLarge: self = .accessibilityLarge
case .accessibilityMedium: self = .accessibilityMedium
case .extraExtraExtraLarge: self = .extraExtraExtraLarge
case .extraExtraLarge: self = .extraExtraLarge
case .extraLarge: self = .extraLarge
case .extraSmall: self = .extraSmall
case .large: self = .large
case .medium: self = .medium
case .small: self = .small
default: self = .unspecified
case .accessibilityExtraExtraExtraLarge: self = .accessibilityExtraExtraExtraLarge
case .accessibilityExtraExtraLarge: self = .accessibilityExtraExtraLarge
case .accessibilityExtraLarge: self = .accessibilityExtraLarge
case .accessibilityLarge: self = .accessibilityLarge
case .accessibilityMedium: self = .accessibilityMedium
case .extraExtraExtraLarge: self = .extraExtraExtraLarge
case .extraExtraLarge: self = .extraExtraLarge
case .extraLarge: self = .extraLarge
case .extraSmall: self = .extraSmall
case .large: self = .large
case .medium: self = .medium
case .small: self = .small
default: self = .unspecified
}
}
}

View File

@ -27,10 +27,10 @@ extension Backport where Wrapped == Any {
#if os(iOS)
var scrollViewDismissMode: UIScrollView.KeyboardDismissMode {
switch dismissMode {
case .automatic: return .none
case .immediately: return .onDrag
case .interactively: return .interactive
case .never: return .none
case .automatic: return .none
case .immediately: return .onDrag
case .interactively: return .interactive
case .never: return .none
}
}
#endif

View File

@ -22,7 +22,7 @@ import SwiftUI
/// Setting a content configuration replaces the existing contentView of the
/// cell with a new content view instance from the configuration.
public var contentConfiguration: BackportUIContentConfiguration? {
get { nil } // we can't really support anything here, so for now we'll return nil
get { nil } // we can't really support anything here, so for now we'll return nil
nonmutating set {
content.configuredView?.removeFromSuperview()
@ -39,8 +39,8 @@ import SwiftUI
let insets =
Mirror(reflecting: configuration)
.children.first(where: { $0.label == "insets" })?.value as? ProposedInsets
?? .unspecified
.children.first(where: { $0.label == "insets" })?.value as? ProposedInsets
?? .unspecified
insets.top.flatMap { contentView.directionalLayoutMargins.top = $0 }
insets.bottom.flatMap { contentView.directionalLayoutMargins.bottom = $0 }

View File

@ -22,7 +22,7 @@ import SwiftUI
/// Setting a content configuration replaces the existing contentView of the
/// cell with a new content view instance from the configuration.
public var contentConfiguration: BackportUIContentConfiguration? {
get { nil } // we can't really support anything here, so for now we'll return nil
get { nil } // we can't really support anything here, so for now we'll return nil
nonmutating set {
content.configuredView?.removeFromSuperview()
@ -39,8 +39,8 @@ import SwiftUI
let insets =
Mirror(reflecting: configuration)
.children.first(where: { $0.label == "insets" })?.value as? ProposedInsets
?? .unspecified
.children.first(where: { $0.label == "insets" })?.value as? ProposedInsets
?? .unspecified
insets.top.flatMap { contentView.directionalLayoutMargins.top = $0 }
insets.bottom.flatMap { contentView.directionalLayoutMargins.bottom = $0 }

View File

@ -36,7 +36,8 @@ import SwiftUI
}
*/
public struct UIHostingConfiguration<Label, Background>: BackportUIContentConfiguration
where Label: View, Background: View {
where Label: View, Background: View
{
var content: Label
var background: AnyView?
var insets: ProposedInsets
@ -57,7 +58,8 @@ import SwiftUI
/// - Parameter background: The contents of the SwiftUI hierarchy to be
/// shown inside the background of the cell.
public func background<B>(@ViewBuilder background: () -> B) -> Backport.UIHostingConfiguration<Label, B>
where B: View {
where B: View
{
.init(content: content, background: AnyView(background()), insets: insets, minSize: minSize)
}
@ -95,7 +97,7 @@ import SwiftUI
}
}
extension Backport.UIHostingConfiguration {
public extension Backport.UIHostingConfiguration {
/// Sets the margins around the content of the configuration.
///
/// Use this modifier to replace the default margins applied to the root of
@ -112,7 +114,7 @@ import SwiftUI
/// use the system default values. The default value is
/// ``Edge/Set/all``.
/// - length: The amount to apply.
public func margins(_ edges: Edge.Set = .all, _ length: CGFloat) -> Self {
func margins(_ edges: Edge.Set = .all, _ length: CGFloat) -> Self {
var view = self
if edges.contains(.leading) { view.insets.leading = length }
if edges.contains(.trailing) { view.insets.trailing = length }
@ -138,7 +140,7 @@ import SwiftUI
/// use the system default values. The default value is
/// ``Edge/Set/all``.
/// - insets: The insets to apply.
public func margins(_ edges: Edge.Set = .all, _ insets: EdgeInsets) -> Self {
func margins(_ edges: Edge.Set = .all, _ insets: EdgeInsets) -> Self {
var view = self
if edges.contains(.leading) { view.insets.leading = insets.leading }
if edges.contains(.trailing) { view.insets.trailing = insets.trailing }

View File

@ -4,19 +4,19 @@ import PackageDescription
let package = Package(
name: "SSPreferences",
platforms: [
.macOS(.v10_11)
.macOS(.v10_11),
],
products: [
.library(
name: "SSPreferences",
targets: [
"SSPreferences"
"SSPreferences",
]
)
),
],
targets: [
.target(
name: "SSPreferences"
)
),
]
)

View File

@ -5,12 +5,12 @@
import SwiftUI
@available(macOS 10.15, *)
extension SSPreferences {
public extension SSPreferences {
/**
Function builder for `Preferences` components used in order to restrict types of child views to be of type `Section`.
*/
@resultBuilder
public enum SectionBuilder {
enum SectionBuilder {
public static func buildBlock(_ sections: Section...) -> [Section] {
sections
}
@ -19,7 +19,7 @@ extension SSPreferences {
/**
A view which holds `Preferences.Section` views and does all the alignment magic similar to `NSGridView` from AppKit.
*/
public struct Container: View {
struct Container: View {
private let sectionBuilder: () -> [Section]
private let contentWidth: Double
private let minimumLabelWidth: Double
@ -49,7 +49,7 @@ extension SSPreferences {
let sections = sectionBuilder()
return VStack(alignment: .preferenceSectionLabel) {
ForEach(0..<sections.count, id: \.self) { index in
ForEach(0 ..< sections.count, id: \.self) { index in
viewForSection(sections, index: index)
}
}

View File

@ -110,10 +110,10 @@ struct Localization {
// Iterate through all user-preferred languages until we find one that has a valid language code.
let preferredLocale =
Locale.preferredLanguages
.lazy
.map { Locale(identifier: $0) }
.first { $0.languageCode != nil }
?? .current
.lazy
.map { Locale(identifier: $0) }
.first { $0.languageCode != nil }
?? .current
guard let languageCode = preferredLocale.languageCode else {
return defaultLocalizedString

View File

@ -15,13 +15,13 @@ public protocol PreferencePaneConvertible {
}
@available(macOS 10.15, *)
extension SSPreferences {
public extension SSPreferences {
/**
Create a SwiftUI-based preference pane.
SwiftUI equivalent of the `PreferencePane` protocol.
*/
public struct Pane<Content: View>: View, PreferencePaneConvertible {
struct Pane<Content: View>: View, PreferencePaneConvertible {
let identifier: PaneIdentifier
let title: String
let toolbarIcon: NSImage
@ -49,7 +49,7 @@ extension SSPreferences {
/**
Hosting controller enabling `Preferences.Pane` to be used alongside AppKit `NSViewController`'s.
*/
public final class PaneHostingController<Content: View>: NSHostingController<Content>, PreferencePane {
final class PaneHostingController<Content: View>: NSHostingController<Content>, PreferencePane {
public let preferencePaneIdentifier: PaneIdentifier
public let preferencePaneTitle: String
public let toolbarItemIcon: NSImage
@ -84,11 +84,11 @@ extension SSPreferences {
}
@available(macOS 10.15, *)
extension View {
public extension View {
/**
Applies font and color for a label used for describing a preference.
*/
public func preferenceDescription() -> some View {
func preferenceDescription() -> some View {
font(.system(size: 11.0))
// TODO: Use `.foregroundStyle` when targeting macOS 12.
.foregroundColor(.secondary)

View File

@ -4,8 +4,8 @@
import Cocoa
extension SSPreferences {
public struct PaneIdentifier: Hashable, RawRepresentable, Codable {
public extension SSPreferences {
struct PaneIdentifier: Hashable, RawRepresentable, Codable {
public let rawValue: String
public init(rawValue: String) {
@ -20,24 +20,24 @@ public protocol PreferencePane: NSViewController {
var toolbarItemIcon: NSImage { get }
}
extension PreferencePane {
public var toolbarItemIdentifier: NSToolbarItem.Identifier {
public extension PreferencePane {
var toolbarItemIdentifier: NSToolbarItem.Identifier {
preferencePaneIdentifier.toolbarItemIdentifier
}
public var toolbarItemIcon: NSImage { .empty }
var toolbarItemIcon: NSImage { .empty }
}
extension SSPreferences.PaneIdentifier {
public init(_ rawValue: String) {
public extension SSPreferences.PaneIdentifier {
init(_ rawValue: String) {
self.init(rawValue: rawValue)
}
public init(fromToolbarItemIdentifier itemIdentifier: NSToolbarItem.Identifier) {
init(fromToolbarItemIdentifier itemIdentifier: NSToolbarItem.Identifier) {
self.init(rawValue: itemIdentifier.rawValue)
}
public var toolbarItemIdentifier: NSToolbarItem.Identifier {
var toolbarItemIdentifier: NSToolbarItem.Identifier {
NSToolbarItem.Identifier(rawValue)
}
}

View File

@ -4,8 +4,8 @@
import Cocoa
extension SSPreferences {
public enum Style {
public extension SSPreferences {
enum Style {
case toolbarItems
case segmentedControl
}

View File

@ -45,14 +45,14 @@ final class PreferencesTabViewController: NSViewController, PreferencesStyleCont
toolbar.delegate = self
switch style {
case .segmentedControl:
preferencesStyleController = SegmentedControlStyleViewController(preferencePanes: preferencePanes)
case .toolbarItems:
preferencesStyleController = ToolbarItemStyleViewController(
preferencePanes: preferencePanes,
toolbar: toolbar,
centerToolbarItems: false
)
case .segmentedControl:
preferencesStyleController = SegmentedControlStyleViewController(preferencePanes: preferencePanes)
case .toolbarItems:
preferencesStyleController = ToolbarItemStyleViewController(
preferencePanes: preferencePanes,
toolbar: toolbar,
centerToolbarItems: false
)
}
preferencesStyleController.delegate = self
@ -159,33 +159,31 @@ final class PreferencesTabViewController: NSViewController, PreferencesStyleCont
) {
let isAnimated =
options
.intersection([
.crossfade,
.slideUp,
.slideDown,
.slideForward,
.slideBackward,
.slideLeft,
.slideRight,
])
.isEmpty == false
.intersection([
.crossfade,
.slideUp,
.slideDown,
.slideForward,
.slideBackward,
.slideLeft,
.slideRight,
])
.isEmpty == false
if isAnimated {
NSAnimationContext.runAnimationGroup(
{ context in
context.allowsImplicitAnimation = true
context.duration = 0.25
context.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
setWindowFrame(for: toViewController, animated: true)
NSAnimationContext.runAnimationGroup({ context in
context.allowsImplicitAnimation = true
context.duration = 0.25
context.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
setWindowFrame(for: toViewController, animated: true)
super.transition(
from: fromViewController,
to: toViewController,
options: options,
completionHandler: completion
)
}, completionHandler: nil
)
super.transition(
from: fromViewController,
to: toViewController,
options: options,
completionHandler: completion
)
}, completionHandler: nil)
} else {
super.transition(
from: fromViewController,

View File

@ -27,7 +27,7 @@ public final class PreferencesWindowController: NSWindowController {
private func updateToolbarVisibility() {
window?.toolbar?.isVisible =
(hidesToolbarForSingleItem == false)
|| (tabViewController.preferencePanesCount > 1)
|| (tabViewController.preferencePanesCount > 1)
}
public init(
@ -54,10 +54,10 @@ public final class PreferencesWindowController: NSWindowController {
window.titleVisibility = {
switch style {
case .toolbarItems:
return .visible
case .segmentedControl:
return preferencePanes.count <= 1 ? .visible : .hidden
case .toolbarItems:
return .visible
case .segmentedControl:
return preferencePanes.count <= 1 ? .visible : .hidden
}
}()
@ -122,9 +122,9 @@ public final class PreferencesWindowController: NSWindowController {
}
}
extension PreferencesWindowController {
public extension PreferencesWindowController {
/// Returns the active pane if it responds to the given action.
public override func supplementalTarget(forAction action: Selector, sender: Any?) -> Any? {
override func supplementalTarget(forAction action: Selector, sender: Any?) -> Any? {
if let target = super.supplementalTarget(forAction: action, sender: sender) {
return target
}
@ -134,13 +134,13 @@ extension PreferencesWindowController {
}
if let target = NSApp.target(forAction: action, to: activeViewController, from: sender) as? NSResponder,
target.responds(to: action)
target.responds(to: action)
{
return target
}
if let target = activeViewController.supplementalTarget(forAction: action, sender: sender) as? NSResponder,
target.responds(to: action)
target.responds(to: action)
{
return target
}
@ -150,11 +150,11 @@ extension PreferencesWindowController {
}
@available(macOS 10.15, *)
extension PreferencesWindowController {
public extension PreferencesWindowController {
/**
Create a preferences window from only SwiftUI-based preference panes.
*/
public convenience init(
convenience init(
panes: [PreferencePaneConvertible],
style: SSPreferences.Style = .toolbarItems,
animated: Bool = true,

View File

@ -5,12 +5,12 @@
import SwiftUI
@available(macOS 10.15, *)
extension SSPreferences {
public extension SSPreferences {
/**
Represents a section with right-aligned title and optional bottom divider.
*/
@available(macOS 10.15, *)
public struct Section: View {
struct Section: View {
/**
Preference key holding max width of section labels.
*/
@ -74,7 +74,7 @@ extension SSPreferences {
) {
self.label = label()
.overlay(LabelOverlay())
.eraseToAnyView() // TODO: Remove use of `AnyView`.
.eraseToAnyView() // TODO: Remove use of `AnyView`.
self.bottomDivider = bottomDivider
self.verticalAlignment = verticalAlignment
let stack = VStack(alignment: .leading) { content() }

View File

@ -61,7 +61,7 @@ final class SegmentedControlStyleViewController: NSViewController, PreferencesSt
let title = preferencePane.preferencePaneTitle
let titleSize = title.size(
withAttributes: [
.font: NSFont.systemFont(ofSize: NSFont.systemFontSize(for: .regular))
.font: NSFont.systemFont(ofSize: NSFont.systemFontSize(for: .regular)),
]
)

View File

@ -4,13 +4,13 @@ import PackageDescription
let package = Package(
name: "CandidateWindow",
platforms: [
.macOS(.v10_11)
.macOS(.v10_11),
],
products: [
.library(
name: "CandidateWindow",
targets: ["CandidateWindow"]
)
),
],
dependencies: [
.package(path: "../vChewing_Shared"),

View File

@ -28,8 +28,8 @@ public class CandidateCellData: Hashable {
public var displayedText: String
public var size: Double { Self.unifiedSize }
public var isSelected: Bool = false
public var whichRow: Int = 0 //
public var whichColumn: Int = 0 //
public var whichRow: Int = 0 //
public var whichColumn: Int = 0 //
public var index: Int = 0
public var subIndex: Int = 0
@ -149,8 +149,8 @@ public class CandidateCellData: Hashable {
// MARK: - Contents specifically made for macOS 12 and newer.
@available(macOS 12, *)
extension CandidateCellData {
public var attributedStringForSwiftUI: some View {
public extension CandidateCellData {
var attributedStringForSwiftUI: some View {
var result: some View {
ZStack(alignment: .leading) {
if isSelected {
@ -179,21 +179,21 @@ extension CandidateCellData {
// MARK: - Contents specifically made for macOS 10.15 and macOS 11.
@available(macOS 10.15, *)
extension CandidateCellData {
public var themeColorBackports: some View {
public extension CandidateCellData {
var themeColorBackports: some View {
//
let result: Color = {
switch locale {
case "zh-Hans": return Color.red
case "zh-Hant": return Color.blue
case "ja": return Color.pink
default: return Color.accentColor
case "zh-Hans": return Color.red
case "zh-Hant": return Color.blue
case "ja": return Color.pink
default: return Color.accentColor
}
}()
return result.opacity(0.85)
}
public var attributedStringForSwiftUIBackports: some View {
var attributedStringForSwiftUIBackports: some View {
var result: some View {
ZStack(alignment: .leading) {
if isSelected {

View File

@ -38,73 +38,73 @@ public struct CandidatePool {
public var currentLineNumber: Int {
switch currentLayout {
case .horizontal:
return currentRowNumber
case .vertical:
return currentColumnNumber
@unknown default:
return 0
case .horizontal:
return currentRowNumber
case .vertical:
return currentColumnNumber
@unknown default:
return 0
}
}
public var candidateLines: [[CandidateCellData]] {
switch currentLayout {
case .horizontal:
return candidateRows
case .vertical:
return candidateColumns
@unknown default:
return []
case .horizontal:
return candidateRows
case .vertical:
return candidateColumns
@unknown default:
return []
}
}
public var maxLineCapacity: Int {
switch currentLayout {
case .horizontal:
return maxRowCapacity
case .vertical:
return maxColumnCapacity
@unknown default:
return 0
case .horizontal:
return maxRowCapacity
case .vertical:
return maxColumnCapacity
@unknown default:
return 0
}
}
public var maxLinesPerPage: Int {
get {
switch currentLayout {
case .horizontal:
return maxRowsPerPage
case .vertical:
return maxColumnsPerPage
@unknown default:
return 0
case .horizontal:
return maxRowsPerPage
case .vertical:
return maxColumnsPerPage
@unknown default:
return 0
}
}
set {
switch currentLayout {
case .horizontal:
maxRowsPerPage = newValue
case .vertical:
maxColumnsPerPage = newValue
@unknown default:
return
case .horizontal:
maxRowsPerPage = newValue
case .vertical:
maxColumnsPerPage = newValue
@unknown default:
return
}
}
}
public var rangeForLastPageBlanked: Range<Int> {
switch currentLayout {
case .horizontal: return rangeForLastHorizontalPageBlanked
case .vertical: return rangeForLastVerticalPageBlanked
@unknown default: return 0..<0
case .horizontal: return rangeForLastHorizontalPageBlanked
case .vertical: return rangeForLastVerticalPageBlanked
@unknown default: return 0 ..< 0
}
}
public var rangeForCurrentPage: Range<Int> {
switch currentLayout {
case .horizontal: return rangeForCurrentHorizontalPage
case .vertical: return rangeForCurrentVerticalPage
@unknown default: return 0..<0
case .horizontal: return rangeForCurrentHorizontalPage
case .vertical: return rangeForCurrentVerticalPage
@unknown default: return 0 ..< 0
}
}
@ -176,17 +176,17 @@ public struct CandidatePool {
public mutating func selectNewNeighborLine(isForward: Bool) {
switch currentLayout {
case .horizontal: selectNewNeighborRow(direction: isForward ? .down : .up)
case .vertical: selectNewNeighborColumn(direction: isForward ? .right : .left)
@unknown default: break
case .horizontal: selectNewNeighborRow(direction: isForward ? .down : .up)
case .vertical: selectNewNeighborColumn(direction: isForward ? .right : .left)
@unknown default: break
}
}
public mutating func highlight(at indexSpecified: Int) {
switch currentLayout {
case .horizontal: highlightHorizontal(at: indexSpecified)
case .vertical: highlightVertical(at: indexSpecified)
@unknown default: break
case .horizontal: highlightHorizontal(at: indexSpecified)
case .vertical: highlightVertical(at: indexSpecified)
@unknown default: break
}
vCLog("\n" + candidateDataAll[highlightedIndex].charDescriptions)
}
@ -206,102 +206,102 @@ extension CandidatePool {
}
private var rangeForLastHorizontalPageBlanked: Range<Int> {
0..<(maxRowsPerPage - rangeForCurrentHorizontalPage.count)
0 ..< (maxRowsPerPage - rangeForCurrentHorizontalPage.count)
}
private var rangeForLastVerticalPageBlanked: Range<Int> {
0..<(maxColumnsPerPage - rangeForCurrentVerticalPage.count)
0 ..< (maxColumnsPerPage - rangeForCurrentVerticalPage.count)
}
private var rangeForCurrentHorizontalPage: Range<Int> {
currentRowNumber..<min(candidateRows.count, currentRowNumber + maxRowsPerPage)
currentRowNumber ..< min(candidateRows.count, currentRowNumber + maxRowsPerPage)
}
private var rangeForCurrentVerticalPage: Range<Int> {
currentColumnNumber..<min(candidateColumns.count, currentColumnNumber + maxColumnsPerPage)
currentColumnNumber ..< min(candidateColumns.count, currentColumnNumber + maxColumnsPerPage)
}
private mutating func selectNewNeighborRow(direction: VerticalDirection) {
let currentSubIndex = candidateDataAll[highlightedIndex].subIndex
var result = currentSubIndex
switch direction {
case .up:
if currentRowNumber <= 0 {
if candidateRows.isEmpty { break }
let firstRow = candidateRows[0]
let newSubIndex = min(currentSubIndex, firstRow.count - 1)
highlightHorizontal(at: firstRow[newSubIndex].index)
break
}
if currentRowNumber >= candidateRows.count - 1 { currentRowNumber = candidateRows.count - 1 }
if candidateRows[currentRowNumber].count != candidateRows[currentRowNumber - 1].count {
let ratio: Double = min(1, Double(currentSubIndex) / Double(candidateRows[currentRowNumber].count))
result = Int(floor(Double(candidateRows[currentRowNumber - 1].count) * ratio))
}
let targetRow = candidateRows[currentRowNumber - 1]
let newSubIndex = min(result, targetRow.count - 1)
highlightHorizontal(at: targetRow[newSubIndex].index)
case .down:
if currentRowNumber >= candidateRows.count - 1 {
if candidateRows.isEmpty { break }
let finalRow = candidateRows[candidateRows.count - 1]
let newSubIndex = min(currentSubIndex, finalRow.count - 1)
highlightHorizontal(at: finalRow[newSubIndex].index)
break
}
if candidateRows[currentRowNumber].count != candidateRows[currentRowNumber + 1].count {
let ratio: Double = min(1, Double(currentSubIndex) / Double(candidateRows[currentRowNumber].count))
result = Int(floor(Double(candidateRows[currentRowNumber + 1].count) * ratio))
}
let targetRow = candidateRows[currentRowNumber + 1]
let newSubIndex = min(result, targetRow.count - 1)
highlightHorizontal(at: targetRow[newSubIndex].index)
case .up:
if currentRowNumber <= 0 {
if candidateRows.isEmpty { break }
let firstRow = candidateRows[0]
let newSubIndex = min(currentSubIndex, firstRow.count - 1)
highlightHorizontal(at: firstRow[newSubIndex].index)
break
}
if currentRowNumber >= candidateRows.count - 1 { currentRowNumber = candidateRows.count - 1 }
if candidateRows[currentRowNumber].count != candidateRows[currentRowNumber - 1].count {
let ratio: Double = min(1, Double(currentSubIndex) / Double(candidateRows[currentRowNumber].count))
result = Int(floor(Double(candidateRows[currentRowNumber - 1].count) * ratio))
}
let targetRow = candidateRows[currentRowNumber - 1]
let newSubIndex = min(result, targetRow.count - 1)
highlightHorizontal(at: targetRow[newSubIndex].index)
case .down:
if currentRowNumber >= candidateRows.count - 1 {
if candidateRows.isEmpty { break }
let finalRow = candidateRows[candidateRows.count - 1]
let newSubIndex = min(currentSubIndex, finalRow.count - 1)
highlightHorizontal(at: finalRow[newSubIndex].index)
break
}
if candidateRows[currentRowNumber].count != candidateRows[currentRowNumber + 1].count {
let ratio: Double = min(1, Double(currentSubIndex) / Double(candidateRows[currentRowNumber].count))
result = Int(floor(Double(candidateRows[currentRowNumber + 1].count) * ratio))
}
let targetRow = candidateRows[currentRowNumber + 1]
let newSubIndex = min(result, targetRow.count - 1)
highlightHorizontal(at: targetRow[newSubIndex].index)
}
}
private mutating func selectNewNeighborColumn(direction: HorizontalDirection) {
let currentSubIndex = candidateDataAll[highlightedIndex].subIndex
switch direction {
case .left:
if currentColumnNumber <= 0 {
if candidateColumns.isEmpty { break }
let firstColumn = candidateColumns[0]
let newSubIndex = min(currentSubIndex, firstColumn.count - 1)
highlightVertical(at: firstColumn[newSubIndex].index)
break
}
if currentColumnNumber >= candidateColumns.count - 1 { currentColumnNumber = candidateColumns.count - 1 }
let targetColumn = candidateColumns[currentColumnNumber - 1]
let newSubIndex = min(currentSubIndex, targetColumn.count - 1)
highlightVertical(at: targetColumn[newSubIndex].index)
case .right:
if currentColumnNumber >= candidateColumns.count - 1 {
if candidateColumns.isEmpty { break }
let finalColumn = candidateColumns[candidateColumns.count - 1]
let newSubIndex = min(currentSubIndex, finalColumn.count - 1)
highlightVertical(at: finalColumn[newSubIndex].index)
break
}
let targetColumn = candidateColumns[currentColumnNumber + 1]
let newSubIndex = min(currentSubIndex, targetColumn.count - 1)
highlightVertical(at: targetColumn[newSubIndex].index)
case .left:
if currentColumnNumber <= 0 {
if candidateColumns.isEmpty { break }
let firstColumn = candidateColumns[0]
let newSubIndex = min(currentSubIndex, firstColumn.count - 1)
highlightVertical(at: firstColumn[newSubIndex].index)
break
}
if currentColumnNumber >= candidateColumns.count - 1 { currentColumnNumber = candidateColumns.count - 1 }
let targetColumn = candidateColumns[currentColumnNumber - 1]
let newSubIndex = min(currentSubIndex, targetColumn.count - 1)
highlightVertical(at: targetColumn[newSubIndex].index)
case .right:
if currentColumnNumber >= candidateColumns.count - 1 {
if candidateColumns.isEmpty { break }
let finalColumn = candidateColumns[candidateColumns.count - 1]
let newSubIndex = min(currentSubIndex, finalColumn.count - 1)
highlightVertical(at: finalColumn[newSubIndex].index)
break
}
let targetColumn = candidateColumns[currentColumnNumber + 1]
let newSubIndex = min(currentSubIndex, targetColumn.count - 1)
highlightVertical(at: targetColumn[newSubIndex].index)
}
}
private mutating func highlightHorizontal(at indexSpecified: Int) {
var indexSpecified = indexSpecified
highlightedIndex = indexSpecified
if !(0..<candidateDataAll.count).contains(highlightedIndex) {
if !(0 ..< candidateDataAll.count).contains(highlightedIndex) {
switch highlightedIndex {
case candidateDataAll.count...:
currentRowNumber = candidateRows.count - 1
highlightedIndex = max(0, candidateDataAll.count - 1)
indexSpecified = highlightedIndex
case ..<0:
highlightedIndex = 0
currentRowNumber = 0
indexSpecified = highlightedIndex
default: break
case candidateDataAll.count...:
currentRowNumber = candidateRows.count - 1
highlightedIndex = max(0, candidateDataAll.count - 1)
indexSpecified = highlightedIndex
case ..<0:
highlightedIndex = 0
currentRowNumber = 0
indexSpecified = highlightedIndex
default: break
}
}
for (i, candidate) in candidateDataAll.enumerated() {
@ -324,17 +324,17 @@ extension CandidatePool {
private mutating func highlightVertical(at indexSpecified: Int) {
var indexSpecified = indexSpecified
highlightedIndex = indexSpecified
if !(0..<candidateDataAll.count).contains(highlightedIndex) {
if !(0 ..< candidateDataAll.count).contains(highlightedIndex) {
switch highlightedIndex {
case candidateDataAll.count...:
currentColumnNumber = candidateColumns.count - 1
highlightedIndex = max(0, candidateDataAll.count - 1)
indexSpecified = highlightedIndex
case ..<0:
highlightedIndex = 0
currentColumnNumber = 0
indexSpecified = highlightedIndex
default: break
case candidateDataAll.count...:
currentColumnNumber = candidateColumns.count - 1
highlightedIndex = max(0, candidateDataAll.count - 1)
indexSpecified = highlightedIndex
case ..<0:
highlightedIndex = 0
currentColumnNumber = 0
indexSpecified = highlightedIndex
default: break
}
}
for (i, candidate) in candidateDataAll.enumerated() {

View File

@ -24,13 +24,13 @@ open class CtlCandidate: NSWindowController, CtlCandidateProtocol {
}
//
switch locale {
case "zh-Hans":
result = NSColor.systemRed
case "zh-Hant":
result = NSColor.systemBlue
case "ja":
result = NSColor.systemBrown
default: break
case "zh-Hans":
result = NSColor.systemRed
case "zh-Hant":
result = NSColor.systemBlue
case "ja":
result = NSColor.systemBrown
default: break
}
var blendingAgainstTarget: NSColor = NSApplication.isDarkMode ? NSColor.black : NSColor.white
if #unavailable(macOS 10.14) {

View File

@ -52,16 +52,16 @@ public class CtlCandidateTDK: CtlCandidate {
private var thePool: CandidatePool {
get {
switch currentLayout {
case .horizontal: return Self.thePoolHorizontal
case .vertical: return Self.thePoolVertical
@unknown default: return .init(candidates: [], rowCapacity: 0)
case .horizontal: return Self.thePoolHorizontal
case .vertical: return Self.thePoolVertical
@unknown default: return .init(candidates: [], rowCapacity: 0)
}
}
set {
switch currentLayout {
case .horizontal: Self.thePoolHorizontal = newValue
case .vertical: Self.thePoolVertical = newValue
@unknown default: break
case .horizontal: Self.thePoolHorizontal = newValue
case .vertical: Self.thePoolVertical = newValue
@unknown default: break
}
}
}
@ -98,20 +98,20 @@ public class CtlCandidateTDK: CtlCandidate {
guard let delegate = delegate else { return }
switch currentLayout {
case .horizontal:
Self.thePoolHorizontal = .init(
candidates: delegate.candidatePairs(conv: true).map(\.1), rowCapacity: 6,
rows: maxLinesPerPage, selectionKeys: delegate.selectionKeys, locale: locale
)
Self.thePoolHorizontal.highlight(at: 0)
case .vertical:
Self.thePoolVertical = .init(
candidates: delegate.candidatePairs(conv: true).map(\.1), columnCapacity: 6,
columns: maxLinesPerPage, selectionKeys: delegate.selectionKeys, locale: locale
)
Self.thePoolVertical.highlight(at: 0)
@unknown default:
return
case .horizontal:
Self.thePoolHorizontal = .init(
candidates: delegate.candidatePairs(conv: true).map(\.1), rowCapacity: 6,
rows: maxLinesPerPage, selectionKeys: delegate.selectionKeys, locale: locale
)
Self.thePoolHorizontal.highlight(at: 0)
case .vertical:
Self.thePoolVertical = .init(
candidates: delegate.candidatePairs(conv: true).map(\.1), columnCapacity: 6,
columns: maxLinesPerPage, selectionKeys: delegate.selectionKeys, locale: locale
)
Self.thePoolVertical.highlight(at: 0)
@unknown default:
return
}
updateDisplay()
}
@ -120,30 +120,30 @@ public class CtlCandidateTDK: CtlCandidate {
guard let window = window else { return }
reverseLookupResult = delegate?.reverseLookup(for: currentSelectedCandidateText) ?? []
switch currentLayout {
case .horizontal:
DispatchQueue.main.async { [self] in
if #available(macOS 12, *) {
Self.currentView = NSHostingView(rootView: theViewHorizontal)
} else {
Self.currentView = NSHostingView(rootView: theViewHorizontalBackports)
}
let newSize = Self.currentView.fittingSize
window.contentView = Self.currentView
window.setContentSize(newSize)
case .horizontal:
DispatchQueue.main.async { [self] in
if #available(macOS 12, *) {
Self.currentView = NSHostingView(rootView: theViewHorizontal)
} else {
Self.currentView = NSHostingView(rootView: theViewHorizontalBackports)
}
case .vertical:
DispatchQueue.main.async { [self] in
if #available(macOS 12, *) {
Self.currentView = NSHostingView(rootView: theViewVertical)
} else {
Self.currentView = NSHostingView(rootView: theViewVerticalBackports)
}
let newSize = Self.currentView.fittingSize
window.contentView = Self.currentView
window.setContentSize(newSize)
let newSize = Self.currentView.fittingSize
window.contentView = Self.currentView
window.setContentSize(newSize)
}
case .vertical:
DispatchQueue.main.async { [self] in
if #available(macOS 12, *) {
Self.currentView = NSHostingView(rootView: theViewVertical)
} else {
Self.currentView = NSHostingView(rootView: theViewVerticalBackports)
}
@unknown default:
return
let newSize = Self.currentView.fittingSize
window.contentView = Self.currentView
window.setContentSize(newSize)
}
@unknown default:
return
}
}
@ -160,7 +160,7 @@ public class CtlCandidateTDK: CtlCandidate {
return highlightNextCandidate()
}
if count <= 0 { return false }
for _ in 0..<min(thePool.maxLinesPerPage, count) {
for _ in 0 ..< min(thePool.maxLinesPerPage, count) {
thePool.selectNewNeighborLine(isForward: true)
}
updateDisplay()
@ -180,7 +180,7 @@ public class CtlCandidateTDK: CtlCandidate {
return highlightPreviousCandidate()
}
if count <= 0 { return false }
for _ in 0..<min(thePool.maxLinesPerPage, count) {
for _ in 0 ..< min(thePool.maxLinesPerPage, count) {
thePool.selectNewNeighborLine(isForward: false)
}
updateDisplay()
@ -211,7 +211,7 @@ public class CtlCandidateTDK: CtlCandidate {
override public func candidateIndexAtKeyLabelIndex(_ id: Int) -> Int {
let arrCurrentLine = thePool.candidateLines[thePool.currentLineNumber]
if !(0..<arrCurrentLine.count).contains(id) { return -114_514 }
if !(0 ..< arrCurrentLine.count).contains(id) { return -114_514 }
let actualID = max(0, min(id, arrCurrentLine.count - 1))
return arrCurrentLine[actualID].index
}
@ -241,15 +241,15 @@ extension CtlCandidateTDK {
}
@available(macOS 10.15, *)
extension CtlCandidateTDK {
public var highlightedColorUIBackports: some View {
public extension CtlCandidateTDK {
var highlightedColorUIBackports: some View {
//
let result: Color = {
switch locale {
case "zh-Hans": return Color.red
case "zh-Hant": return Color.blue
case "ja": return Color.pink
default: return Color.accentColor
case "zh-Hans": return Color.red
case "zh-Hant": return Color.blue
case "ja": return Color.pink
default: return Color.accentColor
}
}()
return result.opacity(0.85)

View File

@ -106,7 +106,7 @@ public struct VwrCandidateVertical: View {
if thePool.maxLinesPerPage - thePool.rangeForCurrentPage.count > 0 {
ForEach(Array(thePool.rangeForLastPageBlanked.enumerated()), id: \.offset) { loopIndex, _ in
VStack(alignment: .leading, spacing: 0) {
ForEach(0..<thePool.maxLineCapacity, id: \.self) { _ in
ForEach(0 ..< thePool.maxLineCapacity, id: \.self) { _ in
thePool.blankCell.attributedStringForSwiftUI.fixedSize()
.frame(width: Double(CandidateCellData.unifiedSize * 5), alignment: .topLeading)
.contentShape(Rectangle())

View File

@ -107,7 +107,7 @@ public struct VwrCandidateVerticalBackports: View {
if thePool.maxLinesPerPage - thePool.rangeForCurrentPage.count > 0 {
ForEach(Array(thePool.rangeForLastPageBlanked.enumerated()), id: \.offset) { loopIndex, _ in
VStack(alignment: .leading, spacing: 0) {
ForEach(0..<thePool.maxLineCapacity, id: \.self) { _ in
ForEach(0 ..< thePool.maxLineCapacity, id: \.self) { _ in
thePool.blankCell.attributedStringForSwiftUIBackports.fixedSize()
.frame(width: Double(CandidateCellData.unifiedSize * 5), alignment: .topLeading)
.contentShape(Rectangle())

View File

@ -4,13 +4,13 @@ import PackageDescription
let package = Package(
name: "CocoaExtension",
platforms: [
.macOS(.v10_11)
.macOS(.v10_11),
],
products: [
.library(
name: "CocoaExtension",
targets: ["CocoaExtension"]
)
),
],
dependencies: [
.package(path: "../vChewing_IMKUtils"),
@ -23,6 +23,6 @@ let package = Package(
.product(name: "IMKUtils", package: "vChewing_IMKUtils"),
.product(name: "SwiftExtension", package: "vChewing_SwiftExtension"),
]
)
),
]
)

View File

@ -11,22 +11,22 @@ import SwiftExtension
// MARK: - NSMutableString extension
extension NSMutableString {
public var localized: String { NSLocalizedString(description, comment: "") }
public extension NSMutableString {
var localized: String { NSLocalizedString(description, comment: "") }
}
// MARK: - NSRect Extension
extension NSRect {
public static var seniorTheBeast: NSRect {
public extension NSRect {
static var seniorTheBeast: NSRect {
NSRect(x: 0.0, y: 0.0, width: 0.114, height: 0.514)
}
}
// MARK: - Shell Extension
extension NSApplication {
public static func shell(_ command: String) throws -> String {
public extension NSApplication {
static func shell(_ command: String) throws -> String {
let task = Process()
let pipe = Pipe()
@ -59,10 +59,10 @@ extension NSApplication {
}
}
extension NSApplication {
public extension NSApplication {
// MARK: - System Dark Mode Status Detector.
public static var isDarkMode: Bool {
static var isDarkMode: Bool {
if #unavailable(macOS 10.14) { return false }
if #available(macOS 10.15, *) {
let appearanceDescription = NSApp.effectiveAppearance.debugDescription
@ -76,23 +76,23 @@ extension NSApplication {
// MARK: - Tell whether this IME is running with Root privileges.
public static var isSudoMode: Bool {
static var isSudoMode: Bool {
NSUserName() == "root"
}
}
// MARK: - Real Home Dir for Sandboxed Apps
extension FileManager {
public static let realHomeDir = URL(
public extension FileManager {
static let realHomeDir = URL(
fileURLWithFileSystemRepresentation: getpwuid(getuid()).pointee.pw_dir, isDirectory: true, relativeTo: nil
)
}
// MARK: - Trash a file if it exists.
extension FileManager {
@discardableResult public static func trashTargetIfExists(_ path: String) -> Bool {
public extension FileManager {
@discardableResult static func trashTargetIfExists(_ path: String) -> Bool {
do {
if FileManager.default.fileExists(atPath: path) {
//
@ -113,9 +113,9 @@ extension FileManager {
// MARK: - Memory Footprint Calculator
// Ref: https://developer.apple.com/forums/thread/105088?answerId=357415022#357415022
extension NSApplication {
public extension NSApplication {
/// The memory footprint of the current application in bytes.
public static var memoryFootprint: UInt64? {
static var memoryFootprint: UInt64? {
// The `TASK_VM_INFO_COUNT` and `TASK_VM_INFO_REV1_COUNT` macros are too
// complex for the Swift C importer, so we have to define them ourselves.
let tskVMInfoCount = mach_msg_type_number_t(
@ -136,20 +136,20 @@ extension NSApplication {
// MARK: - Check whether current date is the given date.
extension Date {
public extension Date {
/// Check whether current date is the given date.
/// - Parameter dateDigits: `yyyyMMdd`, 8-digit integer. If only `MMdd`, then the year will be the current year.
/// - Returns: The result. Will return false if the given dateDigits is invalid.
public static func isTodayTheDate(from dateDigits: Int) -> Bool {
static func isTodayTheDate(from dateDigits: Int) -> Bool {
let currentYear = Self.currentYear
var dateDigits = dateDigits
let strDateDigits = dateDigits.description
switch strDateDigits.count {
case 3, 4: dateDigits = currentYear * 10000 + dateDigits
case 8:
if let theHighest = strDateDigits.first, "12".contains(theHighest) { break }
return false
default: return false
case 3, 4: dateDigits = currentYear * 10000 + dateDigits
case 8:
if let theHighest = strDateDigits.first, "12".contains(theHighest) { break }
return false
default: return false
}
let formatter = DateFormatter()
formatter.dateFormat = "yyyyMMdd"
@ -162,7 +162,7 @@ extension Date {
return false
}
public static var currentYear: Int {
static var currentYear: Int {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy"
return (Int(formatter.string(from: Date())) ?? 1970)

View File

@ -11,8 +11,8 @@ import IMKUtils
// MARK: - NSEvent Extension - Reconstructors
extension NSEvent {
public func reinitiate(
public extension NSEvent {
func reinitiate(
with type: NSEvent.EventType? = nil,
location: NSPoint? = nil,
modifierFlags: NSEvent.ModifierFlags? = nil,
@ -44,28 +44,28 @@ extension NSEvent {
/// Emacs NSEvent NSEvent NSEvent
/// - Parameter isVerticalTyping:
/// - Returns:
public func convertFromEmacsKeyEvent(isVerticalContext: Bool) -> NSEvent {
func convertFromEmacsKeyEvent(isVerticalContext: Bool) -> NSEvent {
guard isEmacsKey else { return self }
let newKeyCode: UInt16 = {
switch isVerticalContext {
case false: return EmacsKey.charKeyMapHorizontal[charCode] ?? 0
case true: return EmacsKey.charKeyMapVertical[charCode] ?? 0
case false: return EmacsKey.charKeyMapHorizontal[charCode] ?? 0
case true: return EmacsKey.charKeyMapVertical[charCode] ?? 0
}
}()
guard newKeyCode != 0 else { return self }
let newCharScalar: Unicode.Scalar = {
switch charCode {
case 6:
return isVerticalContext
? NSEvent.SpecialKey.downArrow.unicodeScalar : NSEvent.SpecialKey.rightArrow.unicodeScalar
case 2:
return isVerticalContext
? NSEvent.SpecialKey.upArrow.unicodeScalar : NSEvent.SpecialKey.leftArrow.unicodeScalar
case 1: return NSEvent.SpecialKey.home.unicodeScalar
case 5: return NSEvent.SpecialKey.end.unicodeScalar
case 4: return NSEvent.SpecialKey.deleteForward.unicodeScalar // Use "deleteForward" for PC delete.
case 22: return NSEvent.SpecialKey.pageDown.unicodeScalar
default: return .init(0)
case 6:
return isVerticalContext
? NSEvent.SpecialKey.downArrow.unicodeScalar : NSEvent.SpecialKey.rightArrow.unicodeScalar
case 2:
return isVerticalContext
? NSEvent.SpecialKey.upArrow.unicodeScalar : NSEvent.SpecialKey.leftArrow.unicodeScalar
case 1: return NSEvent.SpecialKey.home.unicodeScalar
case 5: return NSEvent.SpecialKey.end.unicodeScalar
case 4: return NSEvent.SpecialKey.deleteForward.unicodeScalar // Use "deleteForward" for PC delete.
case 22: return NSEvent.SpecialKey.pageDown.unicodeScalar
default: return .init(0)
}
}()
let newChar = String(newCharScalar)
@ -76,15 +76,15 @@ extension NSEvent {
// MARK: - NSEvent Extension - InputSignalProtocol
extension NSEvent {
public var isTypingVertical: Bool { charactersIgnoringModifiers == "Vertical" }
public var text: String { characters ?? "" }
public var inputTextIgnoringModifiers: String? {
public extension NSEvent {
var isTypingVertical: Bool { charactersIgnoringModifiers == "Vertical" }
var text: String { characters ?? "" }
var inputTextIgnoringModifiers: String? {
guard charactersIgnoringModifiers != nil else { return nil }
return charactersIgnoringModifiers ?? characters ?? ""
}
public var charCode: UInt16 {
var charCode: UInt16 {
guard type != .flagsChanged else { return 0 }
guard characters != nil else { return 0 }
// count > 0!isEmpty滿
@ -94,9 +94,9 @@ extension NSEvent {
return result <= UInt16.max ? UInt16(result) : UInt16.max
}
public var isFlagChanged: Bool { type == .flagsChanged }
var isFlagChanged: Bool { type == .flagsChanged }
public var isEmacsKey: Bool {
var isEmacsKey: Bool {
// isControlHold
[6, 2, 1, 5, 4, 22].contains(charCode) && modifierFlags == .control
}
@ -104,86 +104,86 @@ extension NSEvent {
// Alt+Shift+ macOS
// KeyCode
//
public var mainAreaNumKeyChar: String? { mapMainAreaNumKey[keyCode] }
var mainAreaNumKeyChar: String? { mapMainAreaNumKey[keyCode] }
// ANSI charCode InputHandler
public var isInvalid: Bool {
(0x20...0xFF).contains(charCode) ? false : !(isReservedKey && !isKeyCodeBlacklisted)
var isInvalid: Bool {
(0x20 ... 0xFF).contains(charCode) ? false : !(isReservedKey && !isKeyCodeBlacklisted)
}
public var isKeyCodeBlacklisted: Bool {
var isKeyCodeBlacklisted: Bool {
guard let code = KeyCodeBlackListed(rawValue: keyCode) else { return false }
return code.rawValue != KeyCode.kNone.rawValue
}
public var isReservedKey: Bool {
var isReservedKey: Bool {
guard let code = KeyCode(rawValue: keyCode) else { return false }
return code.rawValue != KeyCode.kNone.rawValue
}
/// flags KeyCode
public var isJISAlphanumericalKey: Bool { KeyCode(rawValue: keyCode) == KeyCode.kJISAlphanumericalKey }
public var isJISKanaSwappingKey: Bool { KeyCode(rawValue: keyCode) == KeyCode.kJISKanaSwappingKey }
public var isNumericPadKey: Bool { arrNumpadKeyCodes.contains(keyCode) }
public var isMainAreaNumKey: Bool { arrMainAreaNumKey.contains(keyCode) }
public var isShiftHold: Bool { modifierFlags.contains([.shift]) }
public var isCommandHold: Bool { modifierFlags.contains([.command]) }
public var isControlHold: Bool { modifierFlags.contains([.control]) }
public var isControlHotKey: Bool { modifierFlags.contains([.control]) && text.first?.isLetter ?? false }
public var isOptionHold: Bool { modifierFlags.contains([.option]) }
public var isOptionHotKey: Bool { modifierFlags.contains([.option]) && text.first?.isLetter ?? false }
public var isCapsLockOn: Bool { modifierFlags.contains([.capsLock]) }
public var isFunctionKeyHold: Bool { modifierFlags.contains([.function]) }
public var isNonLaptopFunctionKey: Bool { modifierFlags.contains([.numericPad]) && !isNumericPadKey }
public var isEnter: Bool { [KeyCode.kCarriageReturn, KeyCode.kLineFeed].contains(KeyCode(rawValue: keyCode)) }
public var isTab: Bool { KeyCode(rawValue: keyCode) == KeyCode.kTab }
public var isUp: Bool { KeyCode(rawValue: keyCode) == KeyCode.kUpArrow }
public var isDown: Bool { KeyCode(rawValue: keyCode) == KeyCode.kDownArrow }
public var isLeft: Bool { KeyCode(rawValue: keyCode) == KeyCode.kLeftArrow }
public var isRight: Bool { KeyCode(rawValue: keyCode) == KeyCode.kRightArrow }
public var isPageUp: Bool { KeyCode(rawValue: keyCode) == KeyCode.kPageUp }
public var isPageDown: Bool { KeyCode(rawValue: keyCode) == KeyCode.kPageDown }
public var isSpace: Bool { KeyCode(rawValue: keyCode) == KeyCode.kSpace }
public var isBackSpace: Bool { KeyCode(rawValue: keyCode) == KeyCode.kBackSpace }
public var isEsc: Bool { KeyCode(rawValue: keyCode) == KeyCode.kEscape }
public var isHome: Bool { KeyCode(rawValue: keyCode) == KeyCode.kHome }
public var isEnd: Bool { KeyCode(rawValue: keyCode) == KeyCode.kEnd }
public var isDelete: Bool { KeyCode(rawValue: keyCode) == KeyCode.kWindowsDelete }
var isJISAlphanumericalKey: Bool { KeyCode(rawValue: keyCode) == KeyCode.kJISAlphanumericalKey }
var isJISKanaSwappingKey: Bool { KeyCode(rawValue: keyCode) == KeyCode.kJISKanaSwappingKey }
var isNumericPadKey: Bool { arrNumpadKeyCodes.contains(keyCode) }
var isMainAreaNumKey: Bool { arrMainAreaNumKey.contains(keyCode) }
var isShiftHold: Bool { modifierFlags.contains([.shift]) }
var isCommandHold: Bool { modifierFlags.contains([.command]) }
var isControlHold: Bool { modifierFlags.contains([.control]) }
var isControlHotKey: Bool { modifierFlags.contains([.control]) && text.first?.isLetter ?? false }
var isOptionHold: Bool { modifierFlags.contains([.option]) }
var isOptionHotKey: Bool { modifierFlags.contains([.option]) && text.first?.isLetter ?? false }
var isCapsLockOn: Bool { modifierFlags.contains([.capsLock]) }
var isFunctionKeyHold: Bool { modifierFlags.contains([.function]) }
var isNonLaptopFunctionKey: Bool { modifierFlags.contains([.numericPad]) && !isNumericPadKey }
var isEnter: Bool { [KeyCode.kCarriageReturn, KeyCode.kLineFeed].contains(KeyCode(rawValue: keyCode)) }
var isTab: Bool { KeyCode(rawValue: keyCode) == KeyCode.kTab }
var isUp: Bool { KeyCode(rawValue: keyCode) == KeyCode.kUpArrow }
var isDown: Bool { KeyCode(rawValue: keyCode) == KeyCode.kDownArrow }
var isLeft: Bool { KeyCode(rawValue: keyCode) == KeyCode.kLeftArrow }
var isRight: Bool { KeyCode(rawValue: keyCode) == KeyCode.kRightArrow }
var isPageUp: Bool { KeyCode(rawValue: keyCode) == KeyCode.kPageUp }
var isPageDown: Bool { KeyCode(rawValue: keyCode) == KeyCode.kPageDown }
var isSpace: Bool { KeyCode(rawValue: keyCode) == KeyCode.kSpace }
var isBackSpace: Bool { KeyCode(rawValue: keyCode) == KeyCode.kBackSpace }
var isEsc: Bool { KeyCode(rawValue: keyCode) == KeyCode.kEscape }
var isHome: Bool { KeyCode(rawValue: keyCode) == KeyCode.kHome }
var isEnd: Bool { KeyCode(rawValue: keyCode) == KeyCode.kEnd }
var isDelete: Bool { KeyCode(rawValue: keyCode) == KeyCode.kWindowsDelete }
public var isCursorBackward: Bool {
var isCursorBackward: Bool {
isTypingVertical
? KeyCode(rawValue: keyCode) == .kUpArrow
: KeyCode(rawValue: keyCode) == .kLeftArrow
}
public var isCursorForward: Bool {
var isCursorForward: Bool {
isTypingVertical
? KeyCode(rawValue: keyCode) == .kDownArrow
: KeyCode(rawValue: keyCode) == .kRightArrow
}
public var isCursorClockRight: Bool {
var isCursorClockRight: Bool {
isTypingVertical
? KeyCode(rawValue: keyCode) == .kRightArrow
: KeyCode(rawValue: keyCode) == .kUpArrow
}
public var isCursorClockLeft: Bool {
var isCursorClockLeft: Bool {
isTypingVertical
? KeyCode(rawValue: keyCode) == .kLeftArrow
: KeyCode(rawValue: keyCode) == .kDownArrow
}
public var isASCII: Bool { charCode < 0x80 }
var isASCII: Bool { charCode < 0x80 }
// flags == .shift Shift
public var isUpperCaseASCIILetterKey: Bool {
(65...90).contains(charCode) && modifierFlags == .shift
var isUpperCaseASCIILetterKey: Bool {
(65 ... 90).contains(charCode) && modifierFlags == .shift
}
// KeyCode macOS Apple
// ![input isShiftHold] 使 Shift
public var isSymbolMenuPhysicalKey: Bool {
var isSymbolMenuPhysicalKey: Bool {
[KeyCode.kSymbolMenuPhysicalKeyIntl, KeyCode.kSymbolMenuPhysicalKeyJIS].contains(KeyCode(rawValue: keyCode))
}
}
@ -195,11 +195,11 @@ extension NSEvent {
// Also: HIToolbox.framework/Versions/A/Headers/Events.h
public enum KeyCode: UInt16 {
case kNone = 0
case kCarriageReturn = 36 // Renamed from "kReturn" to avoid nomenclatural confusions.
case kCarriageReturn = 36 // Renamed from "kReturn" to avoid nomenclatural confusions.
case kTab = 48
case kSpace = 49
case kSymbolMenuPhysicalKeyIntl = 50 // vChewing Specific (Non-JIS)
case kBackSpace = 51 // Renamed from "kDelete" to avoid nomenclatural confusions.
case kSymbolMenuPhysicalKeyIntl = 50 // vChewing Specific (Non-JIS)
case kBackSpace = 51 // Renamed from "kDelete" to avoid nomenclatural confusions.
case kEscape = 53
case kCommand = 55
case kShift = 56
@ -214,12 +214,12 @@ public enum KeyCode: UInt16 {
case kVolumeUp = 72
case kVolumeDown = 73
case kMute = 74
case kLineFeed = 76 // Another keyCode to identify the Enter Key, typable by Fn+Enter.
case kLineFeed = 76 // Another keyCode to identify the Enter Key, typable by Fn+Enter.
case kF18 = 79
case kF19 = 80
case kF20 = 90
case kYen = 93
case kSymbolMenuPhysicalKeyJIS = 94 // vChewing Specific (JIS)
case kSymbolMenuPhysicalKeyJIS = 94 // vChewing Specific (JIS)
case kJISNumPadComma = 95
case kF5 = 96
case kF6 = 97
@ -230,17 +230,17 @@ public enum KeyCode: UInt16 {
case kJISAlphanumericalKey = 102
case kF11 = 103
case kJISKanaSwappingKey = 104
case kF13 = 105 // PrtSc
case kF13 = 105 // PrtSc
case kF16 = 106
case kF14 = 107
case kF10 = 109
case kContextMenu = 110
case kF12 = 111
case kF15 = 113
case kHelp = 114 // Insert
case kHelp = 114 // Insert
case kHome = 115
case kPageUp = 116
case kWindowsDelete = 117 // Renamed from "kForwardDelete" to avoid nomenclatural confusions.
case kWindowsDelete = 117 // Renamed from "kForwardDelete" to avoid nomenclatural confusions.
case kF4 = 118
case kEnd = 119
case kF2 = 120
@ -267,13 +267,13 @@ enum KeyCodeBlackListed: UInt16 {
case kF8 = 100
case kF9 = 101
case kF11 = 103
case kF13 = 105 // PrtSc
case kF13 = 105 // PrtSc
case kF16 = 106
case kF14 = 107
case kF10 = 109
case kF12 = 111
case kF15 = 113
case kHelp = 114 // Insert
case kHelp = 114 // Insert
case kF4 = 118
case kF2 = 120
case kF1 = 122
@ -323,8 +323,8 @@ let arrAppleABCKeyboardMap: [UInt16: (String, String)] = [
45: ("n", "N"), 46: ("m", "M"), 43: (",", "<"), 47: (".", ">"), 44: ("/", "?"),
]
extension NSEvent {
public var inAppleABCStaticForm: NSEvent {
public extension NSEvent {
var inAppleABCStaticForm: NSEvent {
if type == .flagsChanged { return self }
guard modifierFlags == .shift || modifierFlags == [] else { return self }
if !arrAppleABCKeyboardMap.keys.contains(keyCode) { return self }

View File

@ -9,8 +9,8 @@
import AVFoundation
import Cocoa
extension NSSound {
public static func buzz(fart: Bool = false) {
public extension NSSound {
static func buzz(fart: Bool = false) {
let filePath = Bundle.main.path(forResource: fart ? "Fart" : "Beep", ofType: "m4a")!
let fileURL = URL(fileURLWithPath: filePath)
var soundID: SystemSoundID = 0
@ -18,12 +18,12 @@ extension NSSound {
AudioServicesPlaySystemSound(soundID)
}
public static func buzz(fart: Bool = false, count: Int) {
static func buzz(fart: Bool = false, count: Int) {
if count <= 1 {
NSSound.buzz(fart: fart)
return
}
for _ in 0...count {
for _ in 0 ... count {
NSSound.buzz(fart: fart)
usleep(500_000)
}

View File

@ -9,8 +9,8 @@
import Cocoa
import InputMethodKit
extension NSWindowController {
public func orderFront() {
public extension NSWindowController {
func orderFront() {
window?.orderFront(self)
}
@ -21,7 +21,7 @@ extension NSWindowController {
/// - Parameters:
/// - windowTopLeftPoint:
/// - heightDelta:
public func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight heightDelta: Double, useGCD: Bool) {
func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight heightDelta: Double, useGCD: Bool) {
func doSet() {
guard let window = window, var screenFrame = NSScreen.main?.visibleFrame else { return }
let windowSize = window.frame.size
@ -48,8 +48,8 @@ extension NSWindowController {
}
}
extension NSWindow {
@discardableResult public func callAlert(title: String, text: String? = nil) -> NSApplication.ModalResponse {
public extension NSWindow {
@discardableResult func callAlert(title: String, text: String? = nil) -> NSApplication.ModalResponse {
let alert = NSAlert()
alert.messageText = title
if let text = text { alert.informativeText = text }
@ -62,7 +62,7 @@ extension NSWindow {
}
}
extension IMKCandidates {
public extension IMKCandidates {
///
///
/// 使
@ -70,7 +70,7 @@ extension IMKCandidates {
/// - Parameters:
/// - windowTopLeftPoint:
/// - heightDelta:
public func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight heightDelta: Double, useGCD: Bool) {
func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight heightDelta: Double, useGCD: Bool) {
func doSet() {
DispatchQueue.main.async { [self] in
guard var screenFrame = NSScreen.main?.visibleFrame else { return }

View File

@ -7,8 +7,8 @@ import SwiftUI
// MARK: Model
extension NSWindow {
public struct Position {
public extension NSWindow {
struct Position {
public static let defaultPadding: CGFloat = 16
public var vertical: Vertical
@ -17,28 +17,28 @@ extension NSWindow {
}
}
extension NSWindow.Position {
public enum Horizontal {
public extension NSWindow.Position {
enum Horizontal {
case left, center, right
}
public enum Vertical {
enum Vertical {
case top, center, bottom
}
}
// MARK: Logic
extension NSWindow.Position {
public func value(forWindow windowRect: CGRect, inScreen screenRect: CGRect) -> CGPoint {
public extension NSWindow.Position {
func value(forWindow windowRect: CGRect, inScreen screenRect: CGRect) -> CGPoint {
let xPosition = horizontal.valueFor(
screenRange: screenRect.minX..<screenRect.maxX,
screenRange: screenRect.minX ..< screenRect.maxX,
width: windowRect.width,
padding: padding
)
let yPosition = vertical.valueFor(
screenRange: screenRect.minY..<screenRect.maxY,
screenRange: screenRect.minY ..< screenRect.maxY,
height: windowRect.height,
padding: padding
)
@ -47,8 +47,8 @@ extension NSWindow.Position {
}
}
extension NSWindow.Position.Horizontal {
public func valueFor(
public extension NSWindow.Position.Horizontal {
func valueFor(
screenRange: Range<CGFloat>,
width: CGFloat,
padding: CGFloat
@ -56,15 +56,15 @@ extension NSWindow.Position.Horizontal {
-> CGFloat
{
switch self {
case .left: return screenRange.lowerBound + padding
case .center: return (screenRange.upperBound + screenRange.lowerBound - width) / 2
case .right: return screenRange.upperBound - width - padding
case .left: return screenRange.lowerBound + padding
case .center: return (screenRange.upperBound + screenRange.lowerBound - width) / 2
case .right: return screenRange.upperBound - width - padding
}
}
}
extension NSWindow.Position.Vertical {
public func valueFor(
public extension NSWindow.Position.Vertical {
func valueFor(
screenRange: Range<CGFloat>,
height: CGFloat,
padding: CGFloat
@ -72,23 +72,23 @@ extension NSWindow.Position.Vertical {
-> CGFloat
{
switch self {
case .top: return screenRange.upperBound - height - padding
case .center: return (screenRange.upperBound + screenRange.lowerBound - height) / 2
case .bottom: return screenRange.lowerBound + padding
case .top: return screenRange.upperBound - height - padding
case .center: return (screenRange.upperBound + screenRange.lowerBound - height) / 2
case .bottom: return screenRange.lowerBound + padding
}
}
}
// MARK: - AppKit extension
extension NSWindow {
public func setPosition(_ position: Position, in screen: NSScreen?) {
public extension NSWindow {
func setPosition(_ position: Position, in screen: NSScreen?) {
guard let visibleFrame = (screen ?? self.screen)?.visibleFrame else { return }
let origin = position.value(forWindow: frame, inScreen: visibleFrame)
setFrameOrigin(origin)
}
public func setPosition(
func setPosition(
vertical: Position.Vertical,
horizontal: Position.Horizontal,
padding: CGFloat = Position.defaultPadding,
@ -136,8 +136,8 @@ extension NSWindow {
}
@available(macOS 10.15, *)
extension View {
public func hostingWindowPosition(
public extension View {
func hostingWindowPosition(
vertical: NSWindow.Position.Vertical,
horizontal: NSWindow.Position.Horizontal,
padding: CGFloat = NSWindow.Position.defaultPadding,

View File

@ -4,13 +4,13 @@ import PackageDescription
let package = Package(
name: "Hotenka",
platforms: [
.macOS(.v10_11)
.macOS(.v10_11),
],
products: [
.library(
name: "Hotenka",
targets: ["Hotenka"]
)
),
],
dependencies: [],
targets: [

View File

@ -127,18 +127,18 @@ public class HotenkaChineseConverter {
var dictTypeKey: String
switch dictType {
case .zhHantTW:
dictTypeKey = "zh2TW"
case .zhHantHK:
dictTypeKey = "zh2HK"
case .zhHansSG:
dictTypeKey = "zh2SG"
case .zhHansJP:
dictTypeKey = "zh2JP"
case .zhHantKX:
dictTypeKey = "zh2KX"
case .zhHansCN:
dictTypeKey = "zh2CN"
case .zhHantTW:
dictTypeKey = "zh2TW"
case .zhHantHK:
dictTypeKey = "zh2HK"
case .zhHansSG:
dictTypeKey = "zh2SG"
case .zhHansJP:
dictTypeKey = "zh2JP"
case .zhHantKX:
dictTypeKey = "zh2KX"
case .zhHansCN:
dictTypeKey = "zh2CN"
}
var result = ""
@ -153,7 +153,7 @@ public class HotenkaChineseConverter {
innerloop: while j > 0 {
let start = target.index(target.startIndex, offsetBy: i)
let end = target.index(target.startIndex, offsetBy: i + j)
guard let useDictSubStr = useDict[String(target[start..<end])] else {
guard let useDictSubStr = useDict[String(target[start ..< end])] else {
j -= 1
continue
}
@ -164,7 +164,7 @@ public class HotenkaChineseConverter {
if j == 0 {
let start = target.index(target.startIndex, offsetBy: i)
let end = target.index(target.startIndex, offsetBy: i + 1)
result = result + String(target[start..<end])
result = result + String(target[start ..< end])
i += 1
} else {
i += j
@ -177,18 +177,18 @@ public class HotenkaChineseConverter {
// MARK: - String extensions
extension String {
fileprivate func range(of str: String) -> Range<Int> {
private extension String {
func range(of str: String) -> Range<Int> {
var start = -1
withCString { bytes in
str.withCString { sbytes in
start = strstr(bytes, sbytes) - UnsafeMutablePointer<Int8>(mutating: bytes)
}
}
return start < 0 ? 0..<0 : start..<start + str.utf8.count
return start < 0 ? 0 ..< 0 : start ..< start + str.utf8.count
}
fileprivate func substring(to index: Int) -> String {
func substring(to index: Int) -> String {
var out = self
withCString { bytes in
let bytes = UnsafeMutablePointer<Int8>(mutating: bytes)
@ -198,7 +198,7 @@ extension String {
return out
}
fileprivate func substring(from index: Int) -> String {
func substring(from index: Int) -> String {
var out = self
withCString { bytes in
out = String(cString: bytes + index)

View File

@ -1,6 +1,7 @@
.PHONY: format
.PHONY: lint format
format:
swiftformat ./ --swiftversion 5.5
@git ls-files --exclude-standard | grep -E '\.swift$$' | xargs swift-format format --in-place --configuration ./.clang-format-swift.json --parallel
@git ls-files --exclude-standard | grep -E '\.swift$$' | xargs swift-format lint --configuration ./.clang-format-swift.json --parallel
@swiftformat --swiftversion 5.5 --indent 2 ./
lint:
@git ls-files --exclude-standard | grep -E '\.swift$$' | swiftlint --fix --autocorrect

View File

@ -4,19 +4,19 @@ import PackageDescription
let package = Package(
name: "IMKUtils",
platforms: [
.macOS(.v10_11)
.macOS(.v10_11),
],
products: [
.library(
name: "IMKUtils",
targets: ["IMKUtils"]
)
),
],
dependencies: [],
targets: [
.target(
name: "IMKUtils",
dependencies: []
)
),
]
)

View File

@ -92,8 +92,8 @@ public enum IMKHelper {
// MARK: -
extension IMKHelper {
@discardableResult public static func registerInputMethod() -> Int32 {
public extension IMKHelper {
@discardableResult static func registerInputMethod() -> Int32 {
TISInputSource.registerInputMethod() ? 0 : -1
}
}

View File

@ -11,21 +11,21 @@ import InputMethodKit
// MARK: - TISInputSource Extension by The vChewing Project (MIT-NTL License).
extension TISInputSource {
public static var allRegisteredInstancesOfThisInputMethod: [TISInputSource] {
public extension TISInputSource {
static var allRegisteredInstancesOfThisInputMethod: [TISInputSource] {
TISInputSource.modes.compactMap { TISInputSource.generate(from: $0) }
}
public static var modes: [String] {
static var modes: [String] {
guard let components = Bundle.main.infoDictionary?["ComponentInputModeDict"] as? [String: Any],
let tsInputModeListKey = components["tsInputModeListKey"] as? [String: Any]
let tsInputModeListKey = components["tsInputModeListKey"] as? [String: Any]
else {
return []
}
return tsInputModeListKey.keys.map { $0 }
}
@discardableResult public static func registerInputMethod() -> Bool {
@discardableResult static func registerInputMethod() -> Bool {
let instances = TISInputSource.allRegisteredInstancesOfThisInputMethod
if instances.isEmpty {
//
@ -46,15 +46,15 @@ extension TISInputSource {
return succeeded
}
@discardableResult public static func registerInputSource() -> Bool {
@discardableResult static func registerInputSource() -> Bool {
TISRegisterInputSource(Bundle.main.bundleURL as CFURL) == noErr
}
@discardableResult public func activate() -> Bool {
@discardableResult func activate() -> Bool {
TISEnableInputSource(self) == noErr
}
@discardableResult public func select() -> Bool {
@discardableResult func select() -> Bool {
if !isSelectable {
NSLog("Non-selectable: \(identifier)")
return false
@ -66,35 +66,35 @@ extension TISInputSource {
return true
}
@discardableResult public func deactivate() -> Bool {
@discardableResult func deactivate() -> Bool {
TISDisableInputSource(self) == noErr
}
public var isActivated: Bool {
var isActivated: Bool {
unsafeBitCast(TISGetInputSourceProperty(self, kTISPropertyInputSourceIsEnabled), to: CFBoolean.self)
== kCFBooleanTrue
}
public var isSelectable: Bool {
var isSelectable: Bool {
unsafeBitCast(TISGetInputSourceProperty(self, kTISPropertyInputSourceIsSelectCapable), to: CFBoolean.self)
== kCFBooleanTrue
}
public static func generate(from identifier: String) -> TISInputSource? {
static func generate(from identifier: String) -> TISInputSource? {
TISInputSource.rawTISInputSources(onlyASCII: false)[identifier]
}
public var inputModeID: String {
var inputModeID: String {
unsafeBitCast(TISGetInputSourceProperty(self, kTISPropertyInputModeID), to: NSString.self) as String? ?? ""
}
public var vChewingLocalizedName: String {
var vChewingLocalizedName: String {
switch identifier {
case "com.apple.keylayout.ZhuyinBopomofo":
return NSLocalizedString("Apple Zhuyin Bopomofo (Dachen)", comment: "")
case "com.apple.keylayout.ZhuyinEten":
return NSLocalizedString("Apple Zhuyin Eten (Traditional)", comment: "")
default: return localizedName
case "com.apple.keylayout.ZhuyinBopomofo":
return NSLocalizedString("Apple Zhuyin Bopomofo (Dachen)", comment: "")
case "com.apple.keylayout.ZhuyinEten":
return NSLocalizedString("Apple Zhuyin Eten (Traditional)", comment: "")
default: return localizedName
}
}
}
@ -104,23 +104,23 @@ extension TISInputSource {
// Ref: Original source codes are written in Swift 4 from Mzp's InputMethodKit textbook.
// Note: Slightly modified by vChewing Project: Using Dictionaries when necessary.
extension TISInputSource {
public var localizedName: String {
public extension TISInputSource {
var localizedName: String {
unsafeBitCast(TISGetInputSourceProperty(self, kTISPropertyLocalizedName), to: NSString.self) as String? ?? ""
}
public var identifier: String {
var identifier: String {
unsafeBitCast(TISGetInputSourceProperty(self, kTISPropertyInputSourceID), to: NSString.self) as String? ?? ""
}
public var scriptCode: Int {
var scriptCode: Int {
// Shiki's note: There is no "kTISPropertyScriptCode" in TextInputSources.h file.
// Using Mzp's latest solution in his blog: https://mzp.hatenablog.com/entry/2018/07/16/212026
let r = TISGetInputSourceProperty(self, "TSMInputSourcePropertyScriptCode" as CFString)
return unsafeBitCast(r, to: NSString.self).integerValue as Int? ?? 0
}
public static func rawTISInputSources(onlyASCII: Bool = false) -> [String: TISInputSource] {
static func rawTISInputSources(onlyASCII: Bool = false) -> [String: TISInputSource] {
// CFDictionary
//
let conditions = CFDictionaryCreateMutable(nil, 2, nil, nil)

View File

@ -4,13 +4,13 @@ import PackageDescription
let package = Package(
name: "LangModelAssembly",
platforms: [
.macOS(.v10_11)
.macOS(.v10_11),
],
products: [
.library(
name: "LangModelAssembly",
targets: ["LangModelAssembly"]
)
),
],
dependencies: [
.package(path: "../RMJay_LineReader"),

View File

@ -10,8 +10,8 @@ import Foundation
import LineReader
import Shared
extension vChewingLM {
public enum LMConsolidator {
public extension vChewingLM {
enum LMConsolidator {
public static let kPragmaHeader = "# 𝙵𝙾𝚁𝙼𝙰𝚃 𝚘𝚛𝚐.𝚊𝚝𝚎𝚕𝚒𝚎𝚛𝙸𝚗𝚖𝚞.𝚟𝚌𝚑𝚎𝚠𝚒𝚗𝚐.𝚞𝚜𝚎𝚛𝙻𝚊𝚗𝚐𝚞𝚊𝚐𝚎𝙼𝚘𝚍𝚎𝚕𝙳𝚊𝚝𝚊.𝚏𝚘𝚛𝚖𝚊𝚝𝚝𝚎𝚍"
///
@ -24,7 +24,7 @@ extension vChewingLM {
throw FileErrors.fileHandleError("")
}
let lineReader = try LineReader(file: fileHandle)
for strLine in lineReader { // i=0
for strLine in lineReader { // i=0
if strLine != kPragmaHeader {
vCLog("Header Mismatch, Starting In-Place Consolidation.")
return false
@ -56,7 +56,7 @@ extension vChewingLM {
if !strIncoming.hasSuffix("\n") {
vCLog("EOF Fix Necessity Confirmed, Start Fixing.")
if let writeFile = FileHandle(forUpdatingAtPath: path),
let endl = "\n".data(using: .utf8)
let endl = "\n".data(using: .utf8)
{
writeFile.seekToEndOfFile()
writeFile.write(endl)
@ -85,7 +85,7 @@ extension vChewingLM {
var pragmaResult: Bool {
let realPragmaHeader = kPragmaHeader + "\n"
if strProcessed.count <= kPragmaHeader.count { return false }
let range = 0..<(realPragmaHeader.count)
let range = 0 ..< (realPragmaHeader.count)
let fetchedPragma = ContiguousArray(strProcessed.utf8CString[range])
return fetchedPragma == realPragmaHeader.utf8CString
}
@ -104,14 +104,14 @@ extension vChewingLM {
strProcessed.regReplace(pattern: #"(\n | \n)"#, replaceWith: "\n")
// CR & FF to LF,
strProcessed.regReplace(pattern: #"(\f+|\r+|\n+)+"#, replaceWith: "\n")
if strProcessed.prefix(1) == " " { //
if strProcessed.prefix(1) == " " { //
strProcessed.removeFirst()
}
if strProcessed.suffix(1) == " " { //
if strProcessed.suffix(1) == " " { //
strProcessed.removeLast()
}
strProcessed = kPragmaHeader + "\n" + strProcessed // Add Pragma Header
strProcessed = kPragmaHeader + "\n" + strProcessed // Add Pragma Header
// Step 3: Deduplication.
let arrData = strProcessed.split(separator: "\n")

View File

@ -10,7 +10,7 @@ import Foundation
import Megrez
import Shared
extension vChewingLM {
public extension vChewingLM {
/// LMInstantiatorLMI
/// LangModelProtocol 使
///
@ -28,7 +28,7 @@ extension vChewingLM {
///
/// LMI LMI
///
public class LMInstantiator: LangModelProtocol {
class LMInstantiator: LangModelProtocol {
//
public var isCassetteEnabled = false
public var isPhraseReplacementEnabled = false
@ -242,8 +242,8 @@ extension vChewingLM {
let keyChain = keyArray.joined(separator: "-")
_ =
isFiltering
? lmFiltered.temporaryMap[keyChain, default: []].append(unigram)
: lmUserPhrases.temporaryMap[keyChain, default: []].append(unigram)
? lmFiltered.temporaryMap[keyChain, default: []].append(unigram)
: lmUserPhrases.temporaryMap[keyChain, default: []].append(unigram)
}
/// 使
@ -251,11 +251,11 @@ extension vChewingLM {
/// - targetType:
public func retrieveData(from targetType: ReplacableUserDataType) -> String {
switch targetType {
case .thePhrases: return lmUserPhrases.strData
case .theFilter: return lmFiltered.strData
case .theReplacements: return lmReplacements.strData
case .theAssociates: return lmAssociates.strData
case .theSymbols: return lmUserSymbols.strData
case .thePhrases: return lmUserPhrases.strData
case .theFilter: return lmFiltered.strData
case .theReplacements: return lmReplacements.strData
case .theAssociates: return lmAssociates.strData
case .theSymbols: return lmUserSymbols.strData
}
}
@ -267,21 +267,21 @@ extension vChewingLM {
var rawText = rawStrData
LMConsolidator.consolidate(text: &rawText, pragma: true)
switch targetType {
case .theAssociates:
lmAssociates.replaceData(textData: rawText)
if save { lmAssociates.saveData() }
case .theFilter:
lmFiltered.replaceData(textData: rawText)
if save { lmAssociates.saveData() }
case .theReplacements:
lmReplacements.replaceData(textData: rawText)
if save { lmAssociates.saveData() }
case .thePhrases:
lmUserPhrases.replaceData(textData: rawText)
if save { lmAssociates.saveData() }
case .theSymbols:
lmUserSymbols.replaceData(textData: rawText)
if save { lmAssociates.saveData() }
case .theAssociates:
lmAssociates.replaceData(textData: rawText)
if save { lmAssociates.saveData() }
case .theFilter:
lmFiltered.replaceData(textData: rawText)
if save { lmAssociates.saveData() }
case .theReplacements:
lmReplacements.replaceData(textData: rawText)
if save { lmAssociates.saveData() }
case .thePhrases:
lmUserPhrases.replaceData(textData: rawText)
if save { lmAssociates.saveData() }
case .theSymbols:
lmUserSymbols.replaceData(textData: rawText)
if save { lmAssociates.saveData() }
}
}
@ -348,7 +348,7 @@ extension vChewingLM {
//
if isPhraseReplacementEnabled {
for i in 0..<rawAllUnigrams.count {
for i in 0 ..< rawAllUnigrams.count {
let newValue = lmReplacements.valuesFor(key: rawAllUnigrams[i].value)
guard !newValue.isEmpty else { continue }
rawAllUnigrams[i].value = newValue

View File

@ -10,37 +10,37 @@ import Foundation
import Megrez
import Shared
extension vChewingLM.LMInstantiator {
public extension vChewingLM.LMInstantiator {
///
public var cassetteWildcardKey: String { Self.lmCassette.wildcardKey }
var cassetteWildcardKey: String { Self.lmCassette.wildcardKey }
///
public var maxCassetteKeyLength: Int { Self.lmCassette.maxKeyLength }
var maxCassetteKeyLength: Int { Self.lmCassette.maxKeyLength }
///
/// - Parameter char:
/// - Returns:
public func convertCassetteKeyToDisplay(char: String) -> String {
func convertCassetteKeyToDisplay(char: String) -> String {
Self.lmCassette.convertKeyToDisplay(char: char)
}
///
/// - Parameter key:
/// - Returns:
public func isThisCassetteKeyAllowed(key: String) -> Bool {
func isThisCassetteKeyAllowed(key: String) -> Bool {
Self.lmCassette.allowedKeys.contains(key)
}
///
/// - Parameter key:
/// - Returns:
public func hasCassetteWildcardResultsFor(key: String) -> Bool {
func hasCassetteWildcardResultsFor(key: String) -> Bool {
Self.lmCassette.hasUnigramsFor(key: key + Self.lmCassette.wildcard)
}
///
/// - Parameter value:
/// - Returns:
public func cassetteReverseLookup(for value: String) -> [String] {
func cassetteReverseLookup(for value: String) -> [String] {
var lookupResult = Self.lmCassette.reverseLookupMap[value] ?? []
guard !lookupResult.isEmpty else { return [] }
lookupResult = lookupResult.map { $0.trimmingCharacters(in: .newlines) }

View File

@ -22,56 +22,56 @@ extension vChewingLM.LMInstantiator {
delta.year = max(min(deltaOfCalendarYears, 0), thisYear * -1)
let currentDateShortened = Calendar.current.date(byAdding: delta, to: currentDate)
switch key {
case "ㄖˋ-ㄑㄧ", "ㄖˋ-ㄑㄧˊ":
let formatterDate1 = DateFormatter()
let formatterDate2 = DateFormatter()
formatterDate1.dateFormat = "yyyy-MM-dd"
formatterDate2.dateFormat = "yyyy年MM月dd日"
let date1 = formatterDate1.string(from: currentDate)
let date2 = formatterDate2.string(from: currentDate)
var date3 = date2.convertArabicNumeralsToChinese
date3 = date3.replacingOccurrences(of: "年〇", with: "")
date3 = date3.replacingOccurrences(of: "月〇", with: "")
results.append(.init(value: date1, score: -94))
results.append(.init(value: date2, score: -95))
results.append(.init(value: date3, score: -96))
if let currentDateShortened = currentDateShortened, delta.year != 0 {
var dateAlt1: String = formatterDate1.string(from: currentDateShortened)
dateAlt1.regReplace(pattern: #"^0+"#)
var dateAlt2: String = formatterDate2.string(from: currentDateShortened)
dateAlt2.regReplace(pattern: #"^0+"#)
var dateAlt3 = dateAlt2.convertArabicNumeralsToChinese
dateAlt3 = dateAlt3.replacingOccurrences(of: "年〇", with: "")
dateAlt3 = dateAlt3.replacingOccurrences(of: "月〇", with: "")
results.append(.init(value: dateAlt1, score: -97))
results.append(.init(value: dateAlt2, score: -98))
results.append(.init(value: dateAlt3, score: -99))
}
case "ㄕˊ-ㄐㄧㄢ":
let formatterTime1 = DateFormatter()
let formatterTime2 = DateFormatter()
let formatterTime3 = DateFormatter()
formatterTime1.dateFormat = "HH:mm"
formatterTime2.dateFormat = isCHS ? "HH点mm分" : "HH點mm分"
formatterTime3.dateFormat = isCHS ? "HH时mm分" : "HH時mm分"
let time1 = formatterTime1.string(from: currentDate)
let time2 = formatterTime2.string(from: currentDate)
let time3 = formatterTime3.string(from: currentDate)
results.append(.init(value: time1, score: -97))
results.append(.init(value: time2, score: -98))
results.append(.init(value: time3, score: -99))
case "ㄒㄧㄥ-ㄑㄧ", "ㄒㄧㄥ-ㄑㄧˊ":
let formatterWeek1 = DateFormatter()
let formatterWeek2 = DateFormatter()
formatterWeek1.dateFormat = "EEEE"
formatterWeek2.dateFormat = "EE"
formatterWeek1.locale = theLocale
formatterWeek2.locale = theLocale
let week1 = formatterWeek1.string(from: currentDate)
let week2 = formatterWeek2.string(from: currentDate)
results.append(.init(value: week1, score: -98))
results.append(.init(value: week2, score: -99))
default: return .init()
case "ㄖˋ-ㄑㄧ", "ㄖˋ-ㄑㄧˊ":
let formatterDate1 = DateFormatter()
let formatterDate2 = DateFormatter()
formatterDate1.dateFormat = "yyyy-MM-dd"
formatterDate2.dateFormat = "yyyy年MM月dd日"
let date1 = formatterDate1.string(from: currentDate)
let date2 = formatterDate2.string(from: currentDate)
var date3 = date2.convertArabicNumeralsToChinese
date3 = date3.replacingOccurrences(of: "年〇", with: "")
date3 = date3.replacingOccurrences(of: "月〇", with: "")
results.append(.init(value: date1, score: -94))
results.append(.init(value: date2, score: -95))
results.append(.init(value: date3, score: -96))
if let currentDateShortened = currentDateShortened, delta.year != 0 {
var dateAlt1: String = formatterDate1.string(from: currentDateShortened)
dateAlt1.regReplace(pattern: #"^0+"#)
var dateAlt2: String = formatterDate2.string(from: currentDateShortened)
dateAlt2.regReplace(pattern: #"^0+"#)
var dateAlt3 = dateAlt2.convertArabicNumeralsToChinese
dateAlt3 = dateAlt3.replacingOccurrences(of: "年〇", with: "")
dateAlt3 = dateAlt3.replacingOccurrences(of: "月〇", with: "")
results.append(.init(value: dateAlt1, score: -97))
results.append(.init(value: dateAlt2, score: -98))
results.append(.init(value: dateAlt3, score: -99))
}
case "ㄕˊ-ㄐㄧㄢ":
let formatterTime1 = DateFormatter()
let formatterTime2 = DateFormatter()
let formatterTime3 = DateFormatter()
formatterTime1.dateFormat = "HH:mm"
formatterTime2.dateFormat = isCHS ? "HH点mm分" : "HH點mm分"
formatterTime3.dateFormat = isCHS ? "HH时mm分" : "HH時mm分"
let time1 = formatterTime1.string(from: currentDate)
let time2 = formatterTime2.string(from: currentDate)
let time3 = formatterTime3.string(from: currentDate)
results.append(.init(value: time1, score: -97))
results.append(.init(value: time2, score: -98))
results.append(.init(value: time3, score: -99))
case "ㄒㄧㄥ-ㄑㄧ", "ㄒㄧㄥ-ㄑㄧˊ":
let formatterWeek1 = DateFormatter()
let formatterWeek2 = DateFormatter()
formatterWeek1.dateFormat = "EEEE"
formatterWeek2.dateFormat = "EE"
formatterWeek1.locale = theLocale
formatterWeek2.locale = theLocale
let week1 = formatterWeek1.string(from: currentDate)
let week2 = formatterWeek2.string(from: currentDate)
results.append(.init(value: week1, score: -98))
results.append(.init(value: week2, score: -99))
default: return .init()
}
return results
}
@ -83,10 +83,10 @@ private let tableMappingArabicNumeralsToChinese: [String: String] = [
"0": "", "1": "", "2": "", "3": "", "4": "", "5": "", "6": "", "7": "", "8": "", "9": "",
]
extension String {
private extension String {
///
/// - Parameter target:
fileprivate var convertArabicNumeralsToChinese: String {
var convertArabicNumeralsToChinese: String {
var target = self
for key in tableMappingArabicNumeralsToChinese.keys {
guard let result = tableMappingArabicNumeralsToChinese[key] else { continue }

View File

@ -24,7 +24,7 @@ extension String {
) {
var startIndex = startIndex
split(separator: separator).forEach { substring in
let theRange = range(of: substring, range: startIndex..<endIndex)
let theRange = range(of: substring, range: startIndex ..< endIndex)
guard let theRange = theRange else { return }
task(theRange)
startIndex = theRange.upperBound
@ -36,11 +36,11 @@ extension String {
// This is only for reference and is not used in this assembly.
extension String {
fileprivate func ranges(splitBy separator: Element) -> [Range<String.Index>] {
private extension String {
func ranges(splitBy separator: Element) -> [Range<String.Index>] {
var startIndex = startIndex
return split(separator: separator).reduce(into: []) { ranges, substring in
_ = range(of: substring, range: startIndex..<endIndex).map { range in
_ = range(of: substring, range: startIndex ..< endIndex).map { range in
ranges.append(range)
startIndex = range.upperBound
}

View File

@ -10,8 +10,8 @@ import Megrez
import PinyinPhonaConverter
import Shared
extension vChewingLM {
@frozen public struct LMAssociates {
public extension vChewingLM {
@frozen struct LMAssociates {
public private(set) var filePath: String?
var rangeMap: [String: [(Range<String.Index>, Int)]] = [:]
var strData: String = ""

View File

@ -12,9 +12,9 @@ import LineReader
import Megrez
import Shared
extension vChewingLM {
public extension vChewingLM {
/// 便使
@frozen public struct LMCassette {
@frozen struct LMCassette {
public private(set) var filePath: String?
public private(set) var nameShort: String = ""
public private(set) var nameENG: String = ""
@ -115,9 +115,9 @@ extension vChewingLM {
} else if loadingOctagramData, !strLine.contains("%octagram") {
guard let countValue = Int(cells[1]) else { continue }
switch cells.count {
case 2: octagramMap[strFirstCell] = countValue
case 3: octagramDividedMap[strFirstCell] = (countValue, cells[2].trimmingCharacters(in: .newlines))
default: break
case 2: octagramMap[strFirstCell] = countValue
case 3: octagramDividedMap[strFirstCell] = (countValue, cells[2].trimmingCharacters(in: .newlines))
default: break
}
norm += Self.fscale ** (Double(cells[0].count) / 3.0 - 1.0) * Double(countValue)
}
@ -187,7 +187,7 @@ extension vChewingLM {
let arrRaw = charDefMap[key]?.deduplicated ?? []
var arrRawWildcard: [String] = []
if let arrRawWildcardValues = charDefWildcardMap[key]?.deduplicated,
key.contains(wildcard), key.first?.description != wildcard
key.contains(wildcard), key.first?.description != wildcard
{
arrRawWildcard.append(contentsOf: arrRawWildcardValues)
}
@ -236,18 +236,18 @@ extension vChewingLM {
private func calculateWeight(count theCount: Int, phraseLength: Int) -> Double {
var weight: Double = 0
switch theCount {
case -2: //
weight = -13
case -1: //
weight = -13
case 0: //
weight = log10(
Self.fscale ** (Double(phraseLength) / 3.0 - 1.0) * 0.25 / norm)
default:
weight = log10(
Self.fscale ** (Double(phraseLength) / 3.0 - 1.0)
* Double(theCount) / norm
)
case -2: //
weight = -13
case -1: //
weight = -13
case 0: //
weight = log10(
Self.fscale ** (Double(phraseLength) / 3.0 - 1.0) * 0.25 / norm)
default:
weight = log10(
Self.fscale ** (Double(phraseLength) / 3.0 - 1.0)
* Double(theCount) / norm
)
}
return weight
}

View File

@ -10,12 +10,12 @@ import Megrez
import PinyinPhonaConverter
import Shared
extension vChewingLM {
public extension vChewingLM {
/// LMCore LMCoreEX range
/// range strData
/// C++ ParselessLM Swift
/// For
@frozen public struct LMCoreEX {
@frozen struct LMCoreEX {
public private(set) var filePath: String?
/// 便 strData
var rangeMap: [String: [Range<String.Index>]] = [:]
@ -97,7 +97,7 @@ extension vChewingLM {
if strData == rawStrData { return }
strData = rawStrData
var newMap: [String: [Range<String.Index>]] = [:]
let shouldReverse = shouldReverse // closure
let shouldReverse = shouldReverse // closure
strData.parse(splitee: "\n") { theRange in
let theCells = rawStrData[theRange].split(separator: " ")
if theCells.count >= 2, theCells[0].description.first != "#" {
@ -167,7 +167,7 @@ extension vChewingLM {
theScore = .init(String(neta[2])) ?? defaultScore
}
if theScore > 0 {
theScore *= -1 //
theScore *= -1 //
}
grams.append(Megrez.Unigram(value: theValue, score: theScore))
}

View File

@ -10,11 +10,11 @@ import Foundation
import Megrez
import Shared
extension vChewingLM {
public extension vChewingLM {
/// LMCore LMCoreNS plist
/// mac
/// 使 plist
@frozen public struct LMCoreNS {
@frozen struct LMCoreNS {
public private(set) var filePath: String?
/// UTF8
var dataMap: [String: [Data]] = [:]
@ -144,7 +144,7 @@ extension vChewingLM {
theScore = .init(String(neta[1])) ?? defaultScore
}
if theScore > 0 {
theScore *= -1 //
theScore *= -1 //
}
grams.append(Megrez.Unigram(value: theValue, score: theScore))
if !key.contains("_punctuation") { continue }

View File

@ -9,8 +9,8 @@
import Foundation
import Shared
extension vChewingLM {
@frozen public struct LMPlainBopomofo {
public extension vChewingLM {
@frozen struct LMPlainBopomofo {
public private(set) var filePath: String?
var dataMap: [String: String] = [:]

View File

@ -8,8 +8,8 @@
import Shared
extension vChewingLM {
@frozen public struct LMReplacements {
public extension vChewingLM {
@frozen struct LMReplacements {
public private(set) var filePath: String?
var rangeMap: [String: Range<String.Index>] = [:]
var strData: String = ""

View File

@ -9,8 +9,8 @@
import Foundation
import Shared
extension vChewingLM {
@frozen public struct LMRevLookup {
public extension vChewingLM {
@frozen struct LMRevLookup {
public private(set) var dataMap: [String: [Data]] = [:]
public private(set) var filePath: String = ""

View File

@ -11,21 +11,21 @@ import Foundation
import Megrez
import Shared
extension vChewingLM {
public class LMUserOverride {
public extension vChewingLM {
class LMUserOverride {
// MARK: - Main
var mutCapacity: Int
var mutDecayExponent: Double
var mutLRUList: [KeyObservationPair] = []
var mutLRUMap: [String: KeyObservationPair] = [:]
let kDecayThreshold: Double = 1.0 / 1_048_576.0 //
let kDecayThreshold: Double = 1.0 / 1_048_576.0 //
var fileSaveLocationURL: URL
public static let kObservedOverrideHalfLife: Double = 3600.0 * 6 // 6
public static let kObservedOverrideHalfLife: Double = 3600.0 * 6 // 6
public init(capacity: Int = 500, decayConstant: Double = LMUserOverride.kObservedOverrideHalfLife, dataURL: URL) {
mutCapacity = max(capacity, 1) // Ensures that this integer value is always > 0.
mutCapacity = max(capacity, 1) // Ensures that this integer value is always > 0.
mutDecayExponent = log(0.5) / decayConstant
fileSaveLocationURL = dataURL
}
@ -43,7 +43,7 @@ extension vChewingLM {
// 使
guard currentNode.spanLength <= 3 else { return }
//
guard actualCursor > 0 else { return } //
guard actualCursor > 0 else { return } //
let currentNodeIndex = actualCursor
actualCursor -= 1
var prevNodeIndex = 0
@ -153,8 +153,8 @@ extension vChewingLM.LMUserOverride {
// MARK: - Hash and Dehash the entire UOM data, etc.
extension vChewingLM.LMUserOverride {
public func bleachSpecifiedSuggestions(targets: [String], saveCallback: @escaping () -> Void) {
public extension vChewingLM.LMUserOverride {
func bleachSpecifiedSuggestions(targets: [String], saveCallback: @escaping () -> Void) {
if targets.isEmpty { return }
for neta in mutLRUMap {
for target in targets {
@ -168,7 +168,7 @@ extension vChewingLM.LMUserOverride {
}
/// LRU
public func bleachUnigrams(saveCallback: @escaping () -> Void) {
func bleachUnigrams(saveCallback: @escaping () -> Void) {
for key in mutLRUMap.keys {
if !key.contains("(),()") { continue }
mutLRUMap.removeValue(forKey: key)
@ -184,7 +184,7 @@ extension vChewingLM.LMUserOverride {
}
}
public func clearData(withURL fileURL: URL) {
func clearData(withURL fileURL: URL) {
mutLRUMap = .init()
mutLRUList = .init()
do {
@ -196,7 +196,7 @@ extension vChewingLM.LMUserOverride {
}
}
public func saveData(toURL fileURL: URL? = nil) {
func saveData(toURL fileURL: URL? = nil) {
let encoder = JSONEncoder()
do {
guard let jsonData = try? encoder.encode(mutLRUMap) else { return }
@ -208,7 +208,7 @@ extension vChewingLM.LMUserOverride {
}
}
public func loadData(fromURL fileURL: URL) {
func loadData(fromURL fileURL: URL) {
let decoder = JSONDecoder()
do {
let data = try Data(contentsOf: fileURL, options: .mappedIfSafe)
@ -225,7 +225,7 @@ extension vChewingLM.LMUserOverride {
}
}
public struct Suggestion {
struct Suggestion {
public var candidates = [(String, Megrez.Unigram)]()
public var forceHighScoreOverride = false
public var isEmpty: Bool { candidates.isEmpty }
@ -282,7 +282,7 @@ extension vChewingLM.LMUserOverride {
eventCount: theObservation.count, totalCount: observation.count,
eventTimestamp: theObservation.timestamp, timestamp: timestamp, lambda: decayExp
)
if (0...currentHighScore).contains(overrideScore) { continue }
if (0 ... currentHighScore).contains(overrideScore) { continue }
candidates.append((headReading, .init(value: i, score: overrideScore)))
forceHighScoreOverride = theObservation.forceHighScoreOverride
@ -356,16 +356,16 @@ extension vChewingLM.LMUserOverride {
}
if arrNodes.count >= 2,
!kvPrevious.joinedKey().contains("_"),
kvPrevious.joinedKey().split(separator: "-").count == kvPrevious.value.count
!kvPrevious.joinedKey().contains("_"),
kvPrevious.joinedKey().split(separator: "-").count == kvPrevious.value.count
{
kvPrevious = arrNodes[1].currentPair
readingStack = kvPrevious.joinedKey() + readingStack
}
if arrNodes.count >= 3,
!kvAnterior.joinedKey().contains("_"),
kvAnterior.joinedKey().split(separator: "-").count == kvAnterior.value.count
!kvAnterior.joinedKey().contains("_"),
kvAnterior.joinedKey().split(separator: "-").count == kvAnterior.value.count
{
kvAnterior = arrNodes[2].currentPair
readingStack = kvAnterior.joinedKey() + readingStack

View File

@ -4,13 +4,13 @@ import PackageDescription
let package = Package(
name: "Megrez",
platforms: [
.macOS(.v10_11)
.macOS(.v10_11),
],
products: [
.library(
name: "Megrez",
targets: ["Megrez"]
)
),
],
dependencies: [],
targets: [

View File

@ -5,7 +5,7 @@
import Foundation
extension Megrez {
public extension Megrez {
///
///
///
@ -15,7 +15,7 @@ extension Megrez {
///
///
///
public struct Compositor {
struct Compositor {
///
public enum TypingDirection { case front, rear }
///
@ -92,7 +92,7 @@ extension Megrez {
spans = gridBackup
return false
}
cursor += 1 // update()
cursor += 1 // update()
return true
}
@ -106,7 +106,7 @@ extension Megrez {
let isBackSpace: Bool = direction == .rear ? true : false
guard cursor != (isBackSpace ? 0 : keys.count) else { return false }
keys.remove(at: cursor - (isBackSpace ? 1 : 0))
cursor -= isBackSpace ? 1 : 0 //
cursor -= isBackSpace ? 1 : 0 //
resizeGrid(at: cursor, do: .shrink)
update()
return true
@ -129,36 +129,36 @@ extension Megrez {
{
var target = isMarker ? marker : cursor
switch direction {
case .front:
if target == length { return false }
case .rear:
if target == 0 { return false }
case .front:
if target == length { return false }
case .rear:
if target == 0 { return false }
}
guard let currentRegion = walkedNodes.cursorRegionMap[target] else { return false }
let aRegionForward = max(currentRegion - 1, 0)
let currentRegionBorderRear: Int = walkedNodes[0..<currentRegion].map(\.spanLength).reduce(0, +)
let currentRegionBorderRear: Int = walkedNodes[0 ..< currentRegion].map(\.spanLength).reduce(0, +)
switch target {
case currentRegionBorderRear:
switch direction {
case .front:
target =
(currentRegion > walkedNodes.count)
? keys.count : walkedNodes[0...currentRegion].map(\.spanLength).reduce(0, +)
case .rear:
target = walkedNodes[0..<aRegionForward].map(\.spanLength).reduce(0, +)
}
default:
switch direction {
case .front:
target = currentRegionBorderRear + walkedNodes[currentRegion].spanLength
case .rear:
target = currentRegionBorderRear
}
case currentRegionBorderRear:
switch direction {
case .front:
target =
(currentRegion > walkedNodes.count)
? keys.count : walkedNodes[0 ... currentRegion].map(\.spanLength).reduce(0, +)
case .rear:
target = walkedNodes[0 ..< aRegionForward].map(\.spanLength).reduce(0, +)
}
default:
switch direction {
case .front:
target = currentRegionBorderRear + walkedNodes[currentRegion].spanLength
case .rear:
target = currentRegionBorderRear
}
}
switch isMarker {
case false: cursor = target
case true: marker = target
case false: cursor = target
case true: marker = target
}
return true
}
@ -168,7 +168,7 @@ extension Megrez {
// C# StringBuilder Swift NSMutableString
let strOutput: NSMutableString = .init(string: "digraph {\ngraph [ rankdir=LR ];\nBOS;\n")
for (p, span) in spans.enumerated() {
for ni in 0...(span.maxLength) {
for ni in 0 ... (span.maxLength) {
guard let np = span.nodeOf(length: ni) else { continue }
if p == 0 {
strOutput.append("BOS -> \(np.value);\n")
@ -176,7 +176,7 @@ extension Megrez {
strOutput.append("\(np.value);\n")
if (p + ni) < spans.count {
let destinationSpan = spans[p + ni]
for q in 0...(destinationSpan.maxLength) {
for q in 0 ... (destinationSpan.maxLength) {
guard let dn = destinationSpan.nodeOf(length: q) else { continue }
strOutput.append(np.value + " -> " + dn.value + ";\n")
}
@ -199,14 +199,14 @@ extension Megrez.Compositor {
/// - location:
/// - action:
mutating func resizeGrid(at location: Int, do action: ResizeBehavior) {
let location = max(min(location, spans.count), 0) //
let location = max(min(location, spans.count), 0) //
switch action {
case .expand:
spans.insert(SpanUnit(), at: location)
if [0, spans.count].contains(location) { return }
case .shrink:
if spans.count == location { return }
spans.remove(at: location)
case .expand:
spans.insert(SpanUnit(), at: location)
if [0, spans.count].contains(location) { return }
case .shrink:
if spans.count == location { return }
spans.remove(at: location)
}
dropWreckedNodes(at: location)
}
@ -243,12 +243,12 @@ extension Megrez.Compositor {
/// ```
/// - Parameter location:
mutating func dropWreckedNodes(at location: Int) {
let location = max(min(location, spans.count), 0) //
let location = max(min(location, spans.count), 0) //
guard !spans.isEmpty else { return }
let affectedLength = Megrez.Compositor.maxSpanLength - 1
let begin = max(0, location - affectedLength)
guard location >= begin else { return }
for i in begin..<location {
for i in begin ..< location {
spans[i].dropNodesOfOrBeyond(length: location - i + 1)
}
}
@ -269,7 +269,7 @@ extension Megrez.Compositor {
/// - keyArray:
/// - Returns: nil
func getNode(at location: Int, length: Int, keyArray: [String]) -> Node? {
let location = max(min(location, spans.count - 1), 0) //
let location = max(min(location, spans.count - 1), 0) //
guard let node = spans[location].nodeOf(length: length) else { return nil }
return keyArray == node.keyArray ? node : nil
}
@ -280,11 +280,11 @@ extension Megrez.Compositor {
/// - Returns: 0
@discardableResult public mutating func update(updateExisting: Bool = false) -> Int {
let maxSpanLength = Megrez.Compositor.maxSpanLength
let range = max(0, cursor - maxSpanLength)..<min(cursor + maxSpanLength, keys.count)
let range = max(0, cursor - maxSpanLength) ..< min(cursor + maxSpanLength, keys.count)
var nodesChanged = 0
for position in range {
for theLength in 1...min(maxSpanLength, range.upperBound - position) {
let joinedKeyArray = getJoinedKeyArray(range: position..<(position + theLength))
for theLength in 1 ... min(maxSpanLength, range.upperBound - position) {
let joinedKeyArray = getJoinedKeyArray(range: position ..< (position + theLength))
if let theNode = getNode(at: position, length: theLength, keyArray: joinedKeyArray) {
if !updateExisting { continue }
let unigrams = langModel.unigramsFor(keyArray: joinedKeyArray)

View File

@ -3,7 +3,7 @@
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
extension Megrez.Compositor {
public extension Megrez.Compositor {
/// walkedNodes
///
///
@ -13,7 +13,7 @@ extension Megrez.Compositor {
/// `G = (V, E)` `O(|V|+|E|)` `G`
/// 使
/// - Returns:
@discardableResult public mutating func walk() -> (walkedNode: [Node], succeeded: Bool) {
@discardableResult mutating func walk() -> (walkedNode: [Node], succeeded: Bool) {
var result = [Node]()
defer { walkedNodes = result }
guard !spans.isEmpty else { return (result, true) }
@ -24,7 +24,7 @@ extension Megrez.Compositor {
}
for (i, span) in spans.enumerated() {
for j in 1...span.maxLength {
for j in 1 ... span.maxLength {
if let theNode = span.nodeOf(length: j) {
vertexSpans[i].append(.init(node: theNode))
}

View File

@ -5,9 +5,9 @@
import Foundation
extension Megrez.Compositor {
public extension Megrez.Compositor {
///
public struct KeyValuePaired: Equatable, Hashable, Comparable, CustomStringConvertible {
struct KeyValuePaired: Equatable, Hashable, Comparable, CustomStringConvertible {
///
public var keyArray: [String]
///
@ -77,17 +77,17 @@ extension Megrez.Compositor {
/// - all: 穿
/// - beginAt:
/// - endAt
public enum CandidateFetchFilter { case all, beginAt, endAt }
enum CandidateFetchFilter { case all, beginAt, endAt }
///
///
/// location - 1
/// - Parameter location:
/// - Returns:
public func fetchCandidates(at location: Int, filter: CandidateFetchFilter = .all) -> [KeyValuePaired] {
func fetchCandidates(at location: Int, filter: CandidateFetchFilter = .all) -> [KeyValuePaired] {
var result = [KeyValuePaired]()
guard !keys.isEmpty else { return result }
let location = max(min(location, keys.count - 1), 0) //
let location = max(min(location, keys.count - 1), 0) //
let anchors: [NodeAnchor] = fetchOverlappingNodes(at: location).stableSorted {
//
$0.spanLength > $1.spanLength
@ -97,13 +97,13 @@ extension Megrez.Compositor {
if theNode.keyArray.isEmpty { continue }
for gram in theNode.unigrams {
switch filter {
case .all:
//
if !theNode.keyArray.contains(keyAtCursor) { continue }
case .beginAt:
if theNode.keyArray[0] != keyAtCursor { continue }
case .endAt:
if theNode.keyArray.reversed()[0] != keyAtCursor { continue }
case .all:
//
if !theNode.keyArray.contains(keyAtCursor) { continue }
case .beginAt:
if theNode.keyArray[0] != keyAtCursor { continue }
case .endAt:
if theNode.keyArray.reversed()[0] != keyAtCursor { continue }
}
result.append(.init(keyArray: theNode.keyArray, value: gram.value))
}
@ -119,7 +119,7 @@ extension Megrez.Compositor {
/// - location:
/// - overrideType:
/// - Returns:
@discardableResult public func overrideCandidate(
@discardableResult func overrideCandidate(
_ candidate: KeyValuePaired, at location: Int, overrideType: Node.OverrideType = .withHighScore
)
-> Bool
@ -135,7 +135,7 @@ extension Megrez.Compositor {
/// - location:
/// - overrideType:
/// - Returns:
@discardableResult public func overrideCandidateLiteral(
@discardableResult func overrideCandidateLiteral(
_ candidate: String,
at location: Int, overrideType: Node.OverrideType = .withHighScore
) -> Bool {
@ -154,7 +154,7 @@ extension Megrez.Compositor {
internal func overrideCandidateAgainst(keyArray: [String]?, at location: Int, value: String, type: Node.OverrideType)
-> Bool
{
let location = max(min(location, keys.count), 0) //
let location = max(min(location, keys.count), 0) //
var arrOverlappedNodes: [NodeAnchor] = fetchOverlappingNodes(at: min(keys.count - 1, location))
var overridden: NodeAnchor?
for anchor in arrOverlappedNodes {
@ -164,9 +164,9 @@ extension Megrez.Compositor {
break
}
guard let overridden = overridden else { return false } //
guard let overridden = overridden else { return false } //
for i in overridden.spanIndex..<min(spans.count, overridden.spanIndex + overridden.node.spanLength) {
for i in overridden.spanIndex ..< min(spans.count, overridden.spanIndex + overridden.node.spanLength) {
/// A BC
/// A BC 使 A
/// DEF BC A
@ -190,12 +190,12 @@ extension Megrez.Compositor {
// Reference: https://stackoverflow.com/a/50545761/4162914
extension Sequence {
private extension Sequence {
/// Return a stable-sorted collection.
///
/// - Parameter areInIncreasingOrder: Return nil when two element are equal.
/// - Returns: The sorted collection.
fileprivate func stableSorted(
func stableSorted(
by areInIncreasingOrder: (Element, Element) throws -> Bool
)
rethrows -> [Element]

Some files were not shown because too many files have changed in this diff Show More