diff --git a/Installer/AppDelegate.swift b/Installer/AppDelegate.swift index 873eb4f8..b55ceff4 100644 --- a/Installer/AppDelegate.swift +++ b/Installer/AppDelegate.swift @@ -11,6 +11,7 @@ import Cocoa import IMKUtils import InputMethodKit +import SwiftExtension public let kTargetBin = "vChewing" public let kTargetBinPhraseEditor = "vChewingPhraseEditor" @@ -166,9 +167,15 @@ class AppDelegate: NSWindowController, NSApplicationDelegate { task.launch() } - let data = pipe.fileHandleForReading.readDataToEndOfFile() - let output = String(data: data, encoding: .utf8)! - + var output = "" + do { + let data = try pipe.fileHandleForReading.readToEnd() + if let data = data, let str = String(data: data, encoding: .utf8) { + output.append(str) + } + } catch { + return "" + } return output } } diff --git a/Packages/RMJay_LineReader/Package.swift b/Packages/RMJay_LineReader/Package.swift index a64bc503..f55211b8 100644 --- a/Packages/RMJay_LineReader/Package.swift +++ b/Packages/RMJay_LineReader/Package.swift @@ -12,11 +12,15 @@ let package = Package( targets: ["LineReader"] ) ], - dependencies: [], + dependencies: [ + .package(path: "../vChewing_SwiftExtension") + ], targets: [ .target( name: "LineReader", - dependencies: [] + dependencies: [ + .product(name: "SwiftExtension", package: "vChewing_SwiftExtension") + ] ) ] ) diff --git a/Packages/RMJay_LineReader/Sources/LineReader/LineReader.swift b/Packages/RMJay_LineReader/Sources/LineReader/LineReader.swift index b6d68429..dfbfe9c7 100644 --- a/Packages/RMJay_LineReader/Sources/LineReader/LineReader.swift +++ b/Packages/RMJay_LineReader/Sources/LineReader/LineReader.swift @@ -1,6 +1,7 @@ // (c) 2019 and onwards Robert Muckle-Jones (Apache 2.0 License). import Foundation +import SwiftExtension public class LineReader { let encoding: String.Encoding @@ -36,17 +37,22 @@ public class LineReader { return line.trimmingCharacters(in: .newlines) } - let nextData = fileHandle.readData(ofLength: chunkSize) - if !nextData.isEmpty { - buffer.append(nextData) - } else { - // End of file or read error - atEof = true - if !buffer.isEmpty { - // Buffer contains last line in file (not terminated by delimiter). - let line = String(data: buffer as Data, encoding: encoding)! - return line.trimmingCharacters(in: .newlines) + fileRead: do { + let nextData = try fileHandle.read(upToCount: chunkSize) + if let nextData = nextData, !nextData.isEmpty { + buffer.append(nextData) + continue } + } catch { + break fileRead + } + + // End of file or read error + atEof = true + if !buffer.isEmpty { + // Buffer contains last line in file (not terminated by delimiter). + let line = String(data: buffer as Data, encoding: encoding)! + return line.trimmingCharacters(in: .newlines) } } return nil diff --git a/Packages/vChewing_CocoaExtension/Package.swift b/Packages/vChewing_CocoaExtension/Package.swift index 052a7113..6b8213e9 100644 --- a/Packages/vChewing_CocoaExtension/Package.swift +++ b/Packages/vChewing_CocoaExtension/Package.swift @@ -13,13 +13,15 @@ let package = Package( ) ], dependencies: [ - .package(path: "../vChewing_IMKUtils") + .package(path: "../vChewing_IMKUtils"), + .package(path: "../vChewing_SwiftExtension"), ], targets: [ .target( name: "CocoaExtension", dependencies: [ - .product(name: "IMKUtils", package: "vChewing_IMKUtils") + .product(name: "IMKUtils", package: "vChewing_IMKUtils"), + .product(name: "SwiftExtension", package: "vChewing_SwiftExtension"), ] ) ] diff --git a/Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_Misc.swift b/Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_Misc.swift index de38470e..7919f24f 100644 --- a/Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_Misc.swift +++ b/Packages/vChewing_CocoaExtension/Sources/CocoaExtension/CocoaExtension_Misc.swift @@ -7,6 +7,7 @@ // requirements defined in MIT License. import Cocoa +import SwiftExtension // MARK: - NSMutableString extension @@ -45,9 +46,15 @@ extension NSApplication { task.launch() } - let data = pipe.fileHandleForReading.readDataToEndOfFile() - let output = String(data: data, encoding: .utf8)! - + var output = "" + do { + let data = try pipe.fileHandleForReading.readToEnd() + if let data = data, let str = String(data: data, encoding: .utf8) { + output.append(str) + } + } catch { + return "" + } return output } } diff --git a/Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftExtension.swift b/Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftExtension.swift index 59522e51..53059fdb 100644 --- a/Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftExtension.swift +++ b/Packages/vChewing_SwiftExtension/Sources/SwiftExtension/SwiftExtension.swift @@ -205,3 +205,16 @@ extension BinaryInteger { return formatter.string(from: NSDecimalNumber(string: "\(self)")) ?? "" } } + +// MARK: - File Handle API Compatibility for macOS 10.15.3 and Earlier. + +@available(macOS, deprecated: 10.15.4) +extension FileHandle { + public func read(upToCount count: Int) throws -> Data? { + readData(ofLength: count) + } + + public func readToEnd() throws -> Data? { + readDataToEndOfFile() + } +} diff --git a/Source/Modules/LMMgr.swift b/Source/Modules/LMMgr.swift index 65acef33..aaafff0e 100644 --- a/Source/Modules/LMMgr.swift +++ b/Source/Modules/LMMgr.swift @@ -11,6 +11,7 @@ import LangModelAssembly import NotifierUI import PhraseEditorUI import Shared +import SwiftExtension /// 使用者辭典資料預設範例檔案名稱。 private let kTemplateNameUserPhrases = "template-userphrases" @@ -675,9 +676,13 @@ public class LMMgr { } catch { NSWorkspace.shared.openFile(url.path, withApplication: "TextEdit") } - if let outStr = String(data: fileHandle.readDataToEndOfFile(), encoding: .utf8) { - vCLog(outStr) - } + do { + if let theData = try fileHandle.readToEnd(), + let outStr = String(data: theData, encoding: .utf8) + { + vCLog(outStr) + } + } catch {} case "Finder": NSWorkspace.shared.activateFileViewerSelecting([url]) default: diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index c7eec6b0..eff4eb7a 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -49,6 +49,8 @@ 5B963CA328D5C23600DCEE88 /* SwiftExtension in Frameworks */ = {isa = PBXBuildFile; productRef = 5B963CA228D5C23600DCEE88 /* SwiftExtension */; }; 5B963CA828D5DB1400DCEE88 /* PrefMgr_Core.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B963CA728D5DB1400DCEE88 /* PrefMgr_Core.swift */; }; 5B98114828D6198700CBC605 /* PinyinPhonaConverter in Frameworks */ = {isa = PBXBuildFile; productRef = 5B98114728D6198700CBC605 /* PinyinPhonaConverter */; }; + 5B9A62D9295BEA3400F79F3C /* SwiftExtension in Frameworks */ = {isa = PBXBuildFile; productRef = 5B9A62D8295BEA3400F79F3C /* SwiftExtension */; }; + 5B9A62DB295BEA4500F79F3C /* CocoaExtension in Frameworks */ = {isa = PBXBuildFile; productRef = 5B9A62DA295BEA4500F79F3C /* CocoaExtension */; }; 5BA8C30328DF0360004C5CC4 /* CandidateWindow in Frameworks */ = {isa = PBXBuildFile; productRef = 5BA8C30228DF0360004C5CC4 /* CandidateWindow */; }; 5BA9FD0F27FEDB6B002DE248 /* VwrPrefPaneGeneral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0A27FEDB6B002DE248 /* VwrPrefPaneGeneral.swift */; }; 5BA9FD1027FEDB6B002DE248 /* VwrPrefPaneKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0B27FEDB6B002DE248 /* VwrPrefPaneKeyboard.swift */; }; @@ -376,6 +378,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 5B9A62D9295BEA3400F79F3C /* SwiftExtension in Frameworks */, + 5B9A62DB295BEA4500F79F3C /* CocoaExtension in Frameworks */, 5BFC63D128D4B9F7004A77B7 /* IMKUtils in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -824,6 +828,8 @@ name = vChewingInstaller; packageProductDependencies = ( 5BFC63D028D4B9F7004A77B7 /* IMKUtils */, + 5B9A62D8295BEA3400F79F3C /* SwiftExtension */, + 5B9A62DA295BEA4500F79F3C /* CocoaExtension */, ); productName = vChewingInstaller; productReference = 6ACA41CB15FC1D7500935EF6 /* vChewingInstaller.app */; @@ -1821,6 +1827,14 @@ isa = XCSwiftPackageProductDependency; productName = PinyinPhonaConverter; }; + 5B9A62D8295BEA3400F79F3C /* SwiftExtension */ = { + isa = XCSwiftPackageProductDependency; + productName = SwiftExtension; + }; + 5B9A62DA295BEA4500F79F3C /* CocoaExtension */ = { + isa = XCSwiftPackageProductDependency; + productName = CocoaExtension; + }; 5BA8C30228DF0360004C5CC4 /* CandidateWindow */ = { isa = XCSwiftPackageProductDependency; productName = CandidateWindow;