/** * Tae Won Ha - http://taewon.de - @hataewon * See LICENSE */ import Cocoa import RxSwift private class PrefKeys { static let openNewWindowWhenLaunching = "open-new-window-when-launching" static let openNewWindowOnReactivation = "open-new-window-on-reactivation" static let openQuicklyIgnorePatterns = "open-quickly-ignore-patterns" static let editorFontName = "editor-font-name" static let editorFontSize = "editor-font-size" static let editorUsesLigatures = "editor-uses-ligatures" static let useInteractiveZsh = "use-interactive-zsh" } class PrefStore: Store { private static let compatibleVersion = "38" private static let defaultEditorFont = NeoVimView.defaultFont static let minimumEditorFontSize = NeoVimView.minFontSize static let maximumEditorFontSize = NeoVimView.maxFontSize private let source: Observable private let disposeBag = DisposeBag() private let subject = PublishSubject() var sink: Observable { return self.subject.asObservable() } private let userDefaults = NSUserDefaults.standardUserDefaults() private let fontManager = NSFontManager.sharedFontManager() var data = PrefData( general: GeneralPrefData(openNewWindowWhenLaunching: true, openNewWindowOnReactivation: true, ignorePatterns: Set([ "*/.git", "*.o", "*.d", "*.dia" ].map(FileItemIgnorePattern.init))), appearance: AppearancePrefData(editorFont: PrefStore.defaultEditorFont, editorUsesLigatures: false), advanced: AdvancedPrefData(useInteractiveZsh: false) ) init(source: Observable) { self.source = source if let prefs = self.userDefaults.dictionaryForKey(PrefStore.compatibleVersion) { self.data = self.prefDataFromDict(prefs) } else { self.userDefaults.setValue(self.prefsDict(self.data), forKey: PrefStore.compatibleVersion) } self.addReactions() } deinit { self.subject.onCompleted() } private func prefDataFromDict(prefs: [String: AnyObject]) -> PrefData { let editorFontName = prefs[PrefKeys.editorFontName] as? String ?? PrefStore.defaultEditorFont.fontName let editorFontSize = CGFloat( (prefs[PrefKeys.editorFontSize] as? NSNumber)?.floatValue ?? Float(PrefStore.defaultEditorFont.pointSize) ) let editorFont = self.saneFont(editorFontName, fontSize: editorFontSize) let usesLigatures = (prefs[PrefKeys.editorUsesLigatures] as? NSNumber)?.boolValue ?? false let openNewWindowWhenLaunching = (prefs[PrefKeys.openNewWindowWhenLaunching] as? NSNumber)?.boolValue ?? true let openNewWindowOnReactivation = (prefs[PrefKeys.openNewWindowOnReactivation] as? NSNumber)?.boolValue ?? true let ignorePatternsList = (prefs[PrefKeys.openQuicklyIgnorePatterns] as? String) ?? "*/.git, *.o, *.d, *.dia" let ignorePatterns = PrefUtils.ignorePatterns(fromString: ignorePatternsList) let useInteractiveZsh = (prefs[PrefKeys.useInteractiveZsh] as? NSNumber)?.boolValue ?? false return PrefData( general: GeneralPrefData( openNewWindowWhenLaunching: openNewWindowWhenLaunching, openNewWindowOnReactivation: openNewWindowOnReactivation, ignorePatterns: ignorePatterns ), appearance: AppearancePrefData(editorFont: editorFont, editorUsesLigatures: usesLigatures), advanced: AdvancedPrefData(useInteractiveZsh: useInteractiveZsh) ) } private func saneFont(fontName: String, fontSize: CGFloat) -> NSFont { var editorFont = NSFont(name: fontName, size: fontSize) ?? PrefStore.defaultEditorFont if !editorFont.fixedPitch { editorFont = fontManager.convertFont(PrefStore.defaultEditorFont, toSize: editorFont.pointSize) } if editorFont.pointSize < PrefStore.minimumEditorFontSize || editorFont.pointSize > PrefStore.maximumEditorFontSize { editorFont = fontManager.convertFont(editorFont, toSize: PrefStore.defaultEditorFont.pointSize) } return editorFont } private func prefsDict(prefData: PrefData) -> [String: AnyObject] { let generalData = prefData.general let appearanceData = prefData.appearance let advancedData = prefData.advanced let prefs: [String: AnyObject] = [ // General PrefKeys.openNewWindowWhenLaunching: generalData.openNewWindowWhenLaunching, PrefKeys.openNewWindowOnReactivation: generalData.openNewWindowOnReactivation, PrefKeys.openQuicklyIgnorePatterns: PrefUtils.ignorePatternString(fromSet: generalData.ignorePatterns), // Appearance PrefKeys.editorFontName: appearanceData.editorFont.fontName, PrefKeys.editorFontSize: appearanceData.editorFont.pointSize, PrefKeys.editorUsesLigatures: appearanceData.editorUsesLigatures, // Advanced PrefKeys.useInteractiveZsh: advancedData.useInteractiveZsh, ] return prefs } private func addReactions() { self.source .filter { $0 is PrefData } .map { $0 as! PrefData } .subscribeNext { [unowned self] prefData in self.data = prefData self.userDefaults.setValue(self.prefsDict(prefData), forKey: PrefStore.compatibleVersion) self.subject.onNext(prefData) } .addDisposableTo(self.disposeBag) } }