mirror of
https://github.com/qvacua/vimr.git
synced 2024-12-18 03:01:38 +03:00
Add general pref pane
This commit is contained in:
parent
e04e14bd64
commit
7cd3477331
@ -14,6 +14,7 @@
|
||||
1929B18A0D7C7407C51DB642 /* DataWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB6CFF4CC0B5E8B00C62 /* DataWrapper.m */; };
|
||||
1929B1E05C116514C1D3A384 /* CocoaCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = 1929B5C3F2F1CA4113DABFFD /* CocoaCategories.m */; };
|
||||
1929B29B95AD176D57942E08 /* UiRootTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B457B9D0FA4D21F3751E /* UiRootTransformer.swift */; };
|
||||
1929B3217A7A3D79E28C80DB /* PrefWindowTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B49E6924847AD085C8C9 /* PrefWindowTransformer.swift */; };
|
||||
1929B3AC66EFE35D68C020E3 /* PreviewToolTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BFB0F294F3714D5E095F /* PreviewToolTransformer.swift */; };
|
||||
1929B3CEE0C1A1850E9CCE2F /* BasicTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B2FBE11048569391E092 /* BasicTypes.swift */; };
|
||||
1929B3F5743967125F357C9F /* Matcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BEEB33113B0E33C3830F /* Matcher.swift */; };
|
||||
@ -29,6 +30,7 @@
|
||||
1929B5F016431A76292D1E84 /* FileMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B365A6434354B568B04F /* FileMonitor.swift */; };
|
||||
1929B6388EAF16C190B82955 /* FileItemIgnorePattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B69499B2569793350CEC /* FileItemIgnorePattern.swift */; };
|
||||
1929B67DA3EB21A631EF1DBB /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA8AC40B901B20F20B71 /* FileUtils.swift */; };
|
||||
1929B6BE1610892E6C4C0CE6 /* GeneralPrefTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B0EB3F49C42A57D083AF /* GeneralPrefTransformer.swift */; };
|
||||
1929B6D8F5FC723B7109031F /* OpenQuicklyTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B12CE56A9B36980288A4 /* OpenQuicklyTransformer.swift */; };
|
||||
1929B71381946860626E5224 /* FileBrowserTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDC8F5D48578A90236E9 /* FileBrowserTransformer.swift */; };
|
||||
1929B728262BAA14FC93F6AC /* NeoVimView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BF00B466B40629C2AABE /* NeoVimView.swift */; };
|
||||
@ -37,6 +39,7 @@
|
||||
1929B902534935D0EADED52E /* PreviewUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BC589C366CF02CDB4997 /* PreviewUtils.swift */; };
|
||||
1929BA120290D6A2A61A4468 /* ArrayCommonsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B477E1E62433BC48E10B /* ArrayCommonsTest.swift */; };
|
||||
1929BA715337FE26155B2071 /* OpenedFileList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA43449BA41666CD55ED /* OpenedFileList.swift */; };
|
||||
1929BAE4900D72A7877741B1 /* PrefWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE168F31344B69E61B62 /* PrefWindow.swift */; };
|
||||
1929BAFF1E011321D3186EE6 /* UiRoot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD4149D5A25C82064DD8 /* UiRoot.swift */; };
|
||||
1929BB4A9B2FA42A64CCCC76 /* MainWindowTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD83A13BF133741766CC /* MainWindowTransformer.swift */; };
|
||||
1929BCF444CE7F1D14D421DE /* FileItemTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B4778E20696E3AAFB69B /* FileItemTest.swift */; };
|
||||
@ -47,11 +50,12 @@
|
||||
1929BD8BFE753FE724958320 /* OpenQuicklyWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B1215220464EF4A7AD2B /* OpenQuicklyWindow.swift */; };
|
||||
1929BE0DAEE9664C5BCFA211 /* States.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB6608B4F0E037CA0F4C /* States.swift */; };
|
||||
1929BE3936E6CF0F80D4183C /* FileBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BFCBD821FC8383B7C3E3 /* FileBrowser.swift */; };
|
||||
1929BEAE0592096BC1191B67 /* PrefPane.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B07A4A9209C88380E015 /* PrefPane.swift */; };
|
||||
1929BEB90DCDAF7A2B68C886 /* ColorUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA6128BFDD54CA92F46E /* ColorUtils.swift */; };
|
||||
1929BEDE1BE950EDA9497363 /* GeneralPref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB55946DAEBF55D24048 /* GeneralPref.swift */; };
|
||||
1929BEFEABA0448306CDB6D4 /* FileItemIgnorePatternTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BBC84557C8351EC6183E /* FileItemIgnorePatternTest.swift */; };
|
||||
1929BF3F3841B4BF0B4397ED /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9A55E12B703DDD673FD /* Debouncer.swift */; };
|
||||
1929BF81A40B4154D3EA33CE /* server_ui.m in Sources */ = {isa = PBXBuildFile; fileRef = 1929B93013228985F509C8F6 /* server_ui.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
1929BFD3CA6AD3CAAFFCC581 /* PrefWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B587502F00C3664AFEB2 /* PrefWindow.swift */; };
|
||||
4B029F1A1D45E349004EE0D3 /* PrefWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B029F1C1D45E349004EE0D3 /* PrefWindow.xib */; };
|
||||
4B0BCC941D70320C00D3CE65 /* Logger.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B0BCC931D70320C00D3CE65 /* Logger.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
4B183E0E1E06E2940079E8A8 /* CocoaMarkdown.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B183E0D1E06E2940079E8A8 /* CocoaMarkdown.framework */; };
|
||||
@ -287,6 +291,8 @@
|
||||
/* Begin PBXFileReference section */
|
||||
1929B02440BC99C42F9EBD45 /* NetUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NetUtils.m; sourceTree = "<group>"; };
|
||||
1929B04EC69F616EEFAF5F96 /* FileMonitorTransformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileMonitorTransformer.swift; sourceTree = "<group>"; };
|
||||
1929B07A4A9209C88380E015 /* PrefPane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefPane.swift; sourceTree = "<group>"; };
|
||||
1929B0EB3F49C42A57D083AF /* GeneralPrefTransformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralPrefTransformer.swift; sourceTree = "<group>"; };
|
||||
1929B0EEBE4A765934AF8335 /* DataWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataWrapper.h; sourceTree = "<group>"; };
|
||||
1929B1215220464EF4A7AD2B /* OpenQuicklyWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenQuicklyWindow.swift; sourceTree = "<group>"; };
|
||||
1929B12CE56A9B36980288A4 /* OpenQuicklyTransformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenQuicklyTransformer.swift; sourceTree = "<group>"; };
|
||||
@ -302,7 +308,7 @@
|
||||
1929B457B9D0FA4D21F3751E /* UiRootTransformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UiRootTransformer.swift; sourceTree = "<group>"; };
|
||||
1929B4778E20696E3AAFB69B /* FileItemTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItemTest.swift; sourceTree = "<group>"; };
|
||||
1929B477E1E62433BC48E10B /* ArrayCommonsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayCommonsTest.swift; sourceTree = "<group>"; };
|
||||
1929B587502F00C3664AFEB2 /* PrefWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefWindow.swift; sourceTree = "<group>"; };
|
||||
1929B49E6924847AD085C8C9 /* PrefWindowTransformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefWindowTransformer.swift; sourceTree = "<group>"; };
|
||||
1929B5C3F2F1CA4113DABFFD /* CocoaCategories.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CocoaCategories.m; sourceTree = "<group>"; };
|
||||
1929B5D977261F1EBFA9E8F1 /* FileUtilsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtilsTest.swift; sourceTree = "<group>"; };
|
||||
1929B617C229B19DB3E987B8 /* PreviewService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewService.swift; sourceTree = "<group>"; };
|
||||
@ -322,6 +328,7 @@
|
||||
1929BA8AC40B901B20F20B71 /* FileUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = "<group>"; };
|
||||
1929BADEB143008EFA6F3318 /* NetUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetUtils.h; sourceTree = "<group>"; };
|
||||
1929BB251F74BEFC82CEEF84 /* PrefPaneOld.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefPaneOld.swift; sourceTree = "<group>"; };
|
||||
1929BB55946DAEBF55D24048 /* GeneralPref.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneralPref.swift; sourceTree = "<group>"; };
|
||||
1929BB6608B4F0E037CA0F4C /* States.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = States.swift; sourceTree = "<group>"; };
|
||||
1929BB6CFF4CC0B5E8B00C62 /* DataWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DataWrapper.m; sourceTree = "<group>"; };
|
||||
1929BB8BCA48637156F92945 /* PreviewServiceOld.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewServiceOld.swift; sourceTree = "<group>"; };
|
||||
@ -333,6 +340,7 @@
|
||||
1929BD8CBADC191CF8C85309 /* MainWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainWindow.swift; sourceTree = "<group>"; };
|
||||
1929BDC8F5D48578A90236E9 /* FileBrowserTransformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileBrowserTransformer.swift; sourceTree = "<group>"; };
|
||||
1929BDF9EBAF1D9D44399045 /* ScoredFileItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScoredFileItem.swift; sourceTree = "<group>"; };
|
||||
1929BE168F31344B69E61B62 /* PrefWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefWindow.swift; sourceTree = "<group>"; };
|
||||
1929BE37AA2843779CAFA76F /* PreviewTransformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewTransformer.swift; sourceTree = "<group>"; };
|
||||
1929BE69CF9AB1A10D0DD4F2 /* CocoaCategories.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CocoaCategories.h; sourceTree = "<group>"; };
|
||||
1929BEEB33113B0E33C3830F /* Matcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Matcher.swift; sourceTree = "<group>"; };
|
||||
@ -541,7 +549,7 @@
|
||||
1929B365A6434354B568B04F /* FileMonitor.swift */,
|
||||
1929BFCBD821FC8383B7C3E3 /* FileBrowser.swift */,
|
||||
1929BA43449BA41666CD55ED /* OpenedFileList.swift */,
|
||||
1929B587502F00C3664AFEB2 /* PrefWindow.swift */,
|
||||
1929BC56ADBA3275E7A0A598 /* Preferences */,
|
||||
);
|
||||
name = Components;
|
||||
sourceTree = "<group>";
|
||||
@ -575,6 +583,7 @@
|
||||
1929B04EC69F616EEFAF5F96 /* FileMonitorTransformer.swift */,
|
||||
1929BDC8F5D48578A90236E9 /* FileBrowserTransformer.swift */,
|
||||
1929B67A10E6BB2986B2416E /* OpenedFileListTransformer.swift */,
|
||||
1929BB4CF1C1FFEE6CCDD6FD /* Preferences */,
|
||||
);
|
||||
name = Transformers;
|
||||
sourceTree = "<group>";
|
||||
@ -604,6 +613,25 @@
|
||||
name = Redesign;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1929BB4CF1C1FFEE6CCDD6FD /* Preferences */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1929B49E6924847AD085C8C9 /* PrefWindowTransformer.swift */,
|
||||
1929B0EB3F49C42A57D083AF /* GeneralPrefTransformer.swift */,
|
||||
);
|
||||
name = Preferences;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1929BC56ADBA3275E7A0A598 /* Preferences */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1929BE168F31344B69E61B62 /* PrefWindow.swift */,
|
||||
1929B07A4A9209C88380E015 /* PrefPane.swift */,
|
||||
1929BB55946DAEBF55D24048 /* GeneralPref.swift */,
|
||||
);
|
||||
name = Preferences;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1929BFA93DC859DD76C46192 /* Services */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1405,7 +1433,11 @@
|
||||
1929B71381946860626E5224 /* FileBrowserTransformer.swift in Sources */,
|
||||
1929BA715337FE26155B2071 /* OpenedFileList.swift in Sources */,
|
||||
1929B4E54E2F13A7F5F2B682 /* OpenedFileListTransformer.swift in Sources */,
|
||||
1929BFD3CA6AD3CAAFFCC581 /* PrefWindow.swift in Sources */,
|
||||
1929BAE4900D72A7877741B1 /* PrefWindow.swift in Sources */,
|
||||
1929BEAE0592096BC1191B67 /* PrefPane.swift in Sources */,
|
||||
1929BEDE1BE950EDA9497363 /* GeneralPref.swift in Sources */,
|
||||
1929B3217A7A3D79E28C80DB /* PrefWindowTransformer.swift in Sources */,
|
||||
1929B6BE1610892E6C4C0CE6 /* GeneralPrefTransformer.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -27,6 +27,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
case newMainWindow(urls: [URL], cwd: URL)
|
||||
case openInKeyWindow(urls: [URL], cwd: URL)
|
||||
|
||||
case preferences
|
||||
|
||||
case quitWithoutSaving
|
||||
case quit
|
||||
}
|
||||
@ -52,6 +54,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
.subscribe(onNext: { appState in
|
||||
self.hasMainWindows = !appState.mainWindows.isEmpty
|
||||
self.hasDirtyWindows = appState.mainWindows.values.reduce(false) { $1.isDirty ? true : $0 }
|
||||
|
||||
self.openNewMainWindowOnLaunch = appState.openNewMainWindowOnLaunch
|
||||
self.openNewMainWindowOnReactivation = appState.openNewMainWindowOnReactivation
|
||||
})
|
||||
.addDisposableTo(self.disposeBag)
|
||||
|
||||
@ -224,8 +229,7 @@ extension AppDelegate {
|
||||
}
|
||||
|
||||
@IBAction func showPrefWindow(_ sender: Any?) {
|
||||
// FIXME
|
||||
// self.prefWindowComponent.show()
|
||||
self.stateContext.actionEmitter.emit(Action.preferences)
|
||||
}
|
||||
|
||||
// Invoked when no main window is open.
|
||||
|
@ -34,6 +34,9 @@ class AppDelegateTransformer: Transformer {
|
||||
state.mainWindows[uuid]?.urlsToOpen.append(Marked(urls.toDict { url in MainWindow.OpenMode.default }))
|
||||
state.mainWindows[uuid]?.cwd = cwd
|
||||
|
||||
case .preferences:
|
||||
state.preferencesOpen = Marked(true)
|
||||
|
||||
case .quitWithoutSaving, .quit:
|
||||
state.mainWindows.removeAll()
|
||||
state.quitWhenNoMainWindow = true
|
||||
|
@ -130,6 +130,27 @@ class StateContext {
|
||||
})
|
||||
.addDisposableTo(self.disposeBag)
|
||||
|
||||
Observable
|
||||
.of(
|
||||
actionSource
|
||||
.mapOmittingNil { $0 as? PrefWindow.Action }
|
||||
.map { StateActionPair(state: self.appState, action: $0, modified: false) }
|
||||
.transform(by: self.prefWindowTransformer)
|
||||
.filter { $0.modified }
|
||||
.map { $0.state },
|
||||
actionSource
|
||||
.mapOmittingNil { $0 as? GeneralPref.Action }
|
||||
.map { StateActionPair(state: self.appState, action: $0, modified: false) }
|
||||
.transform(by: self.generalPrefTransformer)
|
||||
.filter { $0.modified }
|
||||
.map { $0.state }
|
||||
)
|
||||
.merge()
|
||||
.subscribe(onNext: { state in
|
||||
self.appState = state
|
||||
self.stateSubject.onNext(self.appState)
|
||||
})
|
||||
.addDisposableTo(self.disposeBag)
|
||||
|
||||
#if DEBUG
|
||||
// actionSource.debug().subscribe().addDisposableTo(self.disposeBag)
|
||||
@ -151,6 +172,9 @@ class StateContext {
|
||||
fileprivate let uiRootTransformer = UiRootTransformer()
|
||||
fileprivate let fileMonitorTransformer = FileMonitorTransformer()
|
||||
|
||||
fileprivate let prefWindowTransformer = PrefWindowTransformer()
|
||||
fileprivate let generalPrefTransformer = GeneralPrefTransformer()
|
||||
|
||||
fileprivate let mainWindowTransformer = MainWindowTransformer()
|
||||
fileprivate let mainWindowOpenQuicklyTransformer = MainWindowToOpenQuicklyTransformer()
|
||||
|
||||
|
@ -9,7 +9,7 @@ import RxSwift
|
||||
class FileItemUtils {
|
||||
|
||||
static func flatFileItems(ofUrl url: URL,
|
||||
ignorePatterns: [FileItemIgnorePattern],
|
||||
ignorePatterns: Set<FileItemIgnorePattern>,
|
||||
ignoreToken: Token,
|
||||
root: FileItem) -> Observable<[FileItem]> {
|
||||
guard url.isFileURL else {
|
||||
|
@ -5,11 +5,39 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
func ==(lhs: FileItemIgnorePattern, rhs: FileItemIgnorePattern) -> Bool {
|
||||
fileprivate let whitespaceCharSet = CharacterSet.whitespaces
|
||||
|
||||
class FileItemIgnorePattern: Hashable, CustomStringConvertible {
|
||||
|
||||
static func ==(lhs: FileItemIgnorePattern, rhs: FileItemIgnorePattern) -> Bool {
|
||||
return lhs.pattern == rhs.pattern
|
||||
}
|
||||
|
||||
class FileItemIgnorePattern: Hashable, CustomStringConvertible {
|
||||
static func from(string str: String) -> Set<FileItemIgnorePattern> {
|
||||
if str.trimmingCharacters(in: whitespaceCharSet).characters.count == 0 {
|
||||
return Set()
|
||||
}
|
||||
|
||||
let patterns: [FileItemIgnorePattern] = str
|
||||
.components(separatedBy: ",")
|
||||
.flatMap {
|
||||
let trimmed = $0.trimmingCharacters(in: whitespaceCharSet)
|
||||
if trimmed.characters.count == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return FileItemIgnorePattern(pattern: trimmed)
|
||||
}
|
||||
|
||||
return Set(patterns)
|
||||
}
|
||||
|
||||
static func toString(_ set: Set<FileItemIgnorePattern>) -> String {
|
||||
return Array(set)
|
||||
.map { $0.pattern }
|
||||
.sorted()
|
||||
.joined(separator: ", ")
|
||||
}
|
||||
|
||||
var hashValue: Int {
|
||||
return self.pattern.hashValue
|
||||
|
228
VimR/GeneralPref.swift
Normal file
228
VimR/GeneralPref.swift
Normal file
@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Cocoa
|
||||
import PureLayout
|
||||
import RxSwift
|
||||
|
||||
class GeneralPref: PrefPane, UiComponent, NSTextFieldDelegate {
|
||||
|
||||
typealias StateType = AppState
|
||||
|
||||
enum Action {
|
||||
|
||||
case setOpenOnLaunch(Bool)
|
||||
case setOpenOnReactivation(Bool)
|
||||
case setIgnorePatterns(Set<FileItemIgnorePattern>)
|
||||
}
|
||||
|
||||
override var displayName: String {
|
||||
return "General"
|
||||
}
|
||||
|
||||
override var pinToContainer: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
override func windowWillClose() {
|
||||
self.ignorePatternsAction()
|
||||
}
|
||||
|
||||
required init(source: Observable<StateType>, emitter: ActionEmitter, state: StateType) {
|
||||
self.emitter = emitter
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
||||
self.addViews()
|
||||
|
||||
self.openWhenLaunchingCheckbox.boolState = state.openNewMainWindowOnLaunch
|
||||
self.openOnReactivationCheckbox.boolState = state.openNewMainWindowOnReactivation
|
||||
self.ignorePatterns = state.openQuickly.ignorePatterns
|
||||
self.ignoreField.stringValue = FileItemIgnorePattern.toString(state.openQuickly.ignorePatterns)
|
||||
|
||||
source
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onNext: { state in
|
||||
if self.openWhenLaunchingCheckbox.boolState != state.openNewMainWindowOnLaunch {
|
||||
self.openWhenLaunchingCheckbox.boolState = state.openNewMainWindowOnLaunch
|
||||
}
|
||||
|
||||
if self.openOnReactivationCheckbox.boolState != state.openNewMainWindowOnReactivation {
|
||||
self.openOnReactivationCheckbox.boolState = state.openNewMainWindowOnReactivation
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
.addDisposableTo(self.disposeBag)
|
||||
}
|
||||
|
||||
fileprivate let emitter: ActionEmitter
|
||||
fileprivate let disposeBag = DisposeBag()
|
||||
|
||||
fileprivate let openWhenLaunchingCheckbox = NSButton(forAutoLayout: ())
|
||||
fileprivate let openOnReactivationCheckbox = NSButton(forAutoLayout: ())
|
||||
fileprivate let ignoreField = NSTextField(forAutoLayout: ())
|
||||
|
||||
fileprivate var ignorePatterns = Set<FileItemIgnorePattern>()
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
fileprivate func addViews() {
|
||||
let paneTitle = self.paneTitleTextField(title: "General")
|
||||
|
||||
let openUntitledWindowTitle = self.titleTextField(title: "Open Untitled Window:")
|
||||
self.configureCheckbox(button: self.openWhenLaunchingCheckbox,
|
||||
title: "On launch",
|
||||
action: #selector(GeneralPref.openUntitledWindowWhenLaunchingAction(_:)))
|
||||
self.configureCheckbox(button: self.openOnReactivationCheckbox,
|
||||
title: "On re-activation",
|
||||
action: #selector(GeneralPref.openUntitledWindowOnReactivationAction(_:)))
|
||||
|
||||
let whenLaunching = self.openWhenLaunchingCheckbox
|
||||
let onReactivation = self.openOnReactivationCheckbox
|
||||
|
||||
let ignoreListTitle = self.titleTextField(title: "Files To Ignore:")
|
||||
let ignoreField = self.ignoreField
|
||||
NotificationCenter.default.addObserver(forName: NSNotification.Name.NSControlTextDidEndEditing,
|
||||
object: ignoreField,
|
||||
queue: nil) { [unowned self] _ in
|
||||
self.ignorePatternsAction()
|
||||
}
|
||||
let ignoreInfo =
|
||||
self.infoTextField(markdown:
|
||||
"Comma-separated list of ignore patterns \n"
|
||||
+ "Matching files will be ignored in \"Open Quickly\" and the file browser. \n"
|
||||
+ "Example: `*/.git, */node_modules` \n"
|
||||
+ "For detailed information see [VimR Wiki](https://github.com/qvacua/vimr/wiki)."
|
||||
)
|
||||
|
||||
let cliToolTitle = self.titleTextField(title: "CLI Tool:")
|
||||
let cliToolButton = NSButton(forAutoLayout: ())
|
||||
cliToolButton.title = "Copy 'vimr' CLI Tool..."
|
||||
cliToolButton.bezelStyle = .rounded
|
||||
cliToolButton.isBordered = true
|
||||
cliToolButton.setButtonType(.momentaryPushIn)
|
||||
cliToolButton.target = self
|
||||
cliToolButton.action = #selector(GeneralPref.copyCliTool(_:))
|
||||
let cliToolInfo = self.infoTextField(
|
||||
markdown: "Put the executable `vimr` in your `$PATH` and execute `vimr -h` for help."
|
||||
)
|
||||
|
||||
self.addSubview(paneTitle)
|
||||
self.addSubview(openUntitledWindowTitle)
|
||||
self.addSubview(whenLaunching)
|
||||
self.addSubview(onReactivation)
|
||||
|
||||
self.addSubview(ignoreListTitle)
|
||||
self.addSubview(ignoreField)
|
||||
self.addSubview(ignoreInfo)
|
||||
|
||||
self.addSubview(cliToolTitle)
|
||||
self.addSubview(cliToolButton)
|
||||
self.addSubview(cliToolInfo)
|
||||
|
||||
paneTitle.autoPinEdge(toSuperviewEdge: .top, withInset: 18)
|
||||
paneTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
|
||||
paneTitle.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
|
||||
|
||||
openUntitledWindowTitle.autoAlignAxis(.baseline, toSameAxisOf: whenLaunching, withOffset: 0)
|
||||
openUntitledWindowTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
|
||||
|
||||
whenLaunching.autoPinEdge(.top, to: .bottom, of: paneTitle, withOffset: 18)
|
||||
whenLaunching.autoPinEdge(.left, to: .right, of: openUntitledWindowTitle, withOffset: 5)
|
||||
whenLaunching.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
|
||||
|
||||
onReactivation.autoPinEdge(.top, to: .bottom, of: whenLaunching, withOffset: 5)
|
||||
onReactivation.autoPinEdge(.left, to: .left, of: whenLaunching)
|
||||
onReactivation.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
|
||||
|
||||
ignoreListTitle.autoAlignAxis(.baseline, toSameAxisOf: ignoreField)
|
||||
ignoreListTitle.autoPinEdge(.right, to: .right, of: openUntitledWindowTitle)
|
||||
ignoreListTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18, relation: .greaterThanOrEqual)
|
||||
|
||||
ignoreField.autoPinEdge(.top, to: .bottom, of: onReactivation, withOffset: 18)
|
||||
ignoreField.autoPinEdge(toSuperviewEdge: .right, withInset: 18)
|
||||
ignoreField.autoPinEdge(.left, to: .right, of: ignoreListTitle, withOffset: 5)
|
||||
|
||||
ignoreInfo.autoPinEdge(.top, to: .bottom, of: ignoreField, withOffset: 5)
|
||||
ignoreInfo.autoPinEdge(toSuperviewEdge: .right, withInset: 18)
|
||||
ignoreInfo.autoPinEdge(.left, to: .right, of: ignoreListTitle, withOffset: 5)
|
||||
|
||||
cliToolTitle.autoAlignAxis(.baseline, toSameAxisOf: cliToolButton)
|
||||
cliToolTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18, relation: .greaterThanOrEqual)
|
||||
cliToolTitle.autoPinEdge(.right, to: .right, of: openUntitledWindowTitle)
|
||||
|
||||
cliToolButton.autoPinEdge(.top, to: .bottom, of: ignoreInfo, withOffset: 18)
|
||||
cliToolButton.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
|
||||
cliToolButton.autoPinEdge(.left, to: .right, of: cliToolTitle, withOffset: 5)
|
||||
|
||||
cliToolInfo.autoPinEdge(.top, to: .bottom, of: cliToolButton, withOffset: 5)
|
||||
cliToolInfo.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
|
||||
cliToolInfo.autoPinEdge(.left, to: .right, of: cliToolTitle, withOffset: 5)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Actions
|
||||
extension GeneralPref {
|
||||
|
||||
func copyCliTool(_ sender: NSButton) {
|
||||
let panel = NSOpenPanel()
|
||||
panel.canChooseFiles = false
|
||||
panel.canChooseDirectories = true
|
||||
|
||||
panel.beginSheetModal(for: self.window!) { result in
|
||||
guard result == NSFileHandlingPanelOKButton else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let vimrUrl = Bundle.main.url(forResource: "vimr", withExtension: nil) else {
|
||||
self.alert(title: "Something Went Wrong.",
|
||||
info: "The CLI tool 'vimr' could not be found. Please re-download VimR and try again.")
|
||||
return
|
||||
}
|
||||
|
||||
guard let targetUrl = panel.url?.appendingPathComponent("vimr") else {
|
||||
self.alert(title: "Something Went Wrong.",
|
||||
info: "The target directory could not be determined. Please try again with a different directory.")
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
try FileManager.default.copyItem(at: vimrUrl, to: targetUrl)
|
||||
} catch let err as NSError {
|
||||
self.alert(title: "Error copying 'vimr'", info: err.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func openUntitledWindowWhenLaunchingAction(_ sender: NSButton) {
|
||||
self.emitter.emit(Action.setOpenOnLaunch(self.openWhenLaunchingCheckbox.boolState))
|
||||
}
|
||||
|
||||
func openUntitledWindowOnReactivationAction(_ sender: NSButton) {
|
||||
NSLog("\(self.openOnReactivationCheckbox.boolState)")
|
||||
self.emitter.emit(Action.setOpenOnReactivation(self.openOnReactivationCheckbox.boolState))
|
||||
}
|
||||
|
||||
fileprivate func ignorePatternsAction() {
|
||||
let patterns = FileItemIgnorePattern.from(string: self.ignoreField.stringValue)
|
||||
if patterns == self.ignorePatterns {
|
||||
return
|
||||
}
|
||||
|
||||
self.ignorePatterns = patterns
|
||||
self.emitter.emit(Action.setIgnorePatterns(ignorePatterns))
|
||||
}
|
||||
|
||||
fileprivate func alert(title: String, info: String) {
|
||||
let alert = NSAlert()
|
||||
alert.alertStyle = .warning
|
||||
alert.messageText = title
|
||||
alert.informativeText = info
|
||||
alert.runModal()
|
||||
}
|
||||
}
|
34
VimR/GeneralPrefTransformer.swift
Normal file
34
VimR/GeneralPrefTransformer.swift
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import RxSwift
|
||||
|
||||
class GeneralPrefTransformer: Transformer {
|
||||
|
||||
typealias Pair = StateActionPair<AppState, GeneralPref.Action>
|
||||
|
||||
func transform(_ source: Observable<Pair>) -> Observable<Pair> {
|
||||
return source.map { pair in
|
||||
var state = pair.state
|
||||
|
||||
switch pair.action {
|
||||
|
||||
case let .setOpenOnLaunch(value):
|
||||
state.openNewMainWindowOnLaunch = value
|
||||
|
||||
case let .setOpenOnReactivation(value):
|
||||
state.openNewMainWindowOnReactivation = value
|
||||
|
||||
case let .setIgnorePatterns(patterns):
|
||||
state.openQuickly.ignorePatterns = patterns
|
||||
state.openQuickly.ignoreToken = Token()
|
||||
|
||||
}
|
||||
|
||||
return StateActionPair(state: state, action: pair.action)
|
||||
}
|
||||
}
|
||||
}
|
76
VimR/PrefPane.swift
Normal file
76
VimR/PrefPane.swift
Normal file
@ -0,0 +1,76 @@
|
||||
//
|
||||
// Created by Tae Won Ha on 2/27/17.
|
||||
// Copyright (c) 2017 Tae Won Ha. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class PrefPane: NSView {
|
||||
|
||||
// Return true to place this to the upper left corner when the scroll view is bigger than this view.
|
||||
override var isFlipped: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var displayName: String {
|
||||
preconditionFailure("Please override")
|
||||
}
|
||||
|
||||
var pinToContainer: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func windowWillClose() {
|
||||
// noop, override
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Control Utils
|
||||
extension PrefPane {
|
||||
|
||||
func paneTitleTextField(title: String) -> NSTextField {
|
||||
let field = defaultTitleTextField()
|
||||
field.font = NSFont.boldSystemFont(ofSize: 16)
|
||||
field.alignment = .left;
|
||||
field.stringValue = title
|
||||
return field
|
||||
}
|
||||
|
||||
func titleTextField(title: String) -> NSTextField {
|
||||
let field = defaultTitleTextField()
|
||||
field.alignment = .right;
|
||||
field.stringValue = title
|
||||
return field
|
||||
}
|
||||
|
||||
func infoTextField(markdown: String) -> NSTextField {
|
||||
let field = NSTextField(forAutoLayout: ())
|
||||
field.backgroundColor = NSColor.clear
|
||||
field.isEditable = false
|
||||
field.isBordered = false
|
||||
field.usesSingleLineMode = false
|
||||
|
||||
// both are needed, otherwise hyperlink won't accept mousedown
|
||||
field.isSelectable = true
|
||||
field.allowsEditingTextAttributes = true
|
||||
|
||||
field.attributedStringValue = NSAttributedString.infoLabel(markdown: markdown)
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
func configureCheckbox(button: NSButton, title: String, action: Selector) {
|
||||
button.title = title
|
||||
button.setButtonType(.switch)
|
||||
button.target = self
|
||||
button.action = action
|
||||
}
|
||||
|
||||
fileprivate func defaultTitleTextField() -> NSTextField {
|
||||
let field = NSTextField(forAutoLayout: ())
|
||||
field.backgroundColor = NSColor.clear;
|
||||
field.isEditable = false;
|
||||
field.isBordered = false;
|
||||
return field
|
||||
}
|
||||
}
|
@ -14,19 +14,42 @@ class PrefWindow: NSObject,
|
||||
|
||||
typealias StateType = AppState
|
||||
|
||||
enum Action {
|
||||
|
||||
case close
|
||||
}
|
||||
|
||||
required init(source: Observable<StateType>, emitter: ActionEmitter, state: StateType) {
|
||||
self.emitter = emitter
|
||||
self.openStatusMark = state.preferencesOpen.mark
|
||||
|
||||
self.windowController = NSWindowController(windowNibName: "PrefWindow")
|
||||
|
||||
self.panes = [
|
||||
GeneralPref(source: source, emitter: emitter, state: state)
|
||||
]
|
||||
|
||||
super.init()
|
||||
|
||||
self.window.delegate = self
|
||||
|
||||
self.addViews()
|
||||
|
||||
source
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onNext: { state in
|
||||
if state.preferencesOpen.payload == false {
|
||||
self.openStatusMark = state.preferencesOpen.mark
|
||||
self.windowController.close()
|
||||
return
|
||||
}
|
||||
|
||||
if state.preferencesOpen.mark == self.openStatusMark {
|
||||
return
|
||||
}
|
||||
|
||||
self.openStatusMark = state.preferencesOpen.mark
|
||||
self.windowController.showWindow(self)
|
||||
})
|
||||
.addDisposableTo(self.disposeBag)
|
||||
}
|
||||
@ -34,6 +57,8 @@ class PrefWindow: NSObject,
|
||||
fileprivate let emitter: ActionEmitter
|
||||
fileprivate let disposeBag = DisposeBag()
|
||||
|
||||
fileprivate var openStatusMark: Token
|
||||
|
||||
fileprivate let windowController: NSWindowController
|
||||
fileprivate var window: NSWindow { return self.windowController.window! }
|
||||
|
||||
@ -58,10 +83,53 @@ class PrefWindow: NSObject,
|
||||
}
|
||||
|
||||
fileprivate func addViews() {
|
||||
let categoryView = self.categoryView
|
||||
categoryView.dataSource = self
|
||||
categoryView.delegate = self
|
||||
|
||||
let categoryScrollView = self.categoryScrollView
|
||||
categoryScrollView.documentView = categoryView
|
||||
|
||||
let paneContainer = self.paneContainer
|
||||
paneContainer.hasVerticalScroller = true
|
||||
paneContainer.hasHorizontalScroller = true
|
||||
paneContainer.autohidesScrollers = true
|
||||
paneContainer.borderType = .noBorder
|
||||
paneContainer.autoresizesSubviews = false
|
||||
paneContainer.backgroundColor = NSColor.windowBackgroundColor
|
||||
|
||||
self.window.contentView?.addSubview(categoryScrollView)
|
||||
self.window.contentView?.addSubview(paneContainer)
|
||||
|
||||
categoryScrollView.autoSetDimension(.width, toSize: 150)
|
||||
categoryScrollView.autoPinEdge(toSuperviewEdge: .top, withInset: -1)
|
||||
categoryScrollView.autoPinEdge(toSuperviewEdge: .bottom, withInset: -1)
|
||||
categoryScrollView.autoPinEdge(toSuperviewEdge: .left, withInset: -1)
|
||||
|
||||
paneContainer.autoSetDimension(.width, toSize: 200, relation: .greaterThanOrEqual)
|
||||
paneContainer.autoPinEdge(toSuperviewEdge: .top)
|
||||
paneContainer.autoPinEdge(toSuperviewEdge: .right)
|
||||
paneContainer.autoPinEdge(toSuperviewEdge: .bottom)
|
||||
paneContainer.autoPinEdge(.left, to: .right, of: categoryScrollView)
|
||||
|
||||
self.currentPane = self.panes[0]
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - NSWindowDelegate
|
||||
extension PrefWindow {
|
||||
|
||||
func windowShouldClose(_: Any) -> Bool {
|
||||
self.emitter.emit(Action.close)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// func windowWillClose(_: Notification) {
|
||||
//
|
||||
// }
|
||||
}
|
||||
|
||||
// MARK: - NSTableViewDataSource
|
||||
extension PrefWindow {
|
||||
|
||||
|
27
VimR/PrefWindowTransformer.swift
Normal file
27
VimR/PrefWindowTransformer.swift
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import RxSwift
|
||||
|
||||
class PrefWindowTransformer: Transformer {
|
||||
|
||||
typealias Pair = StateActionPair<AppState, PrefWindow.Action>
|
||||
|
||||
func transform(_ source: Observable<Pair>) -> Observable<Pair> {
|
||||
return source.map { pair in
|
||||
var state = pair.state
|
||||
|
||||
switch pair.action {
|
||||
|
||||
case .close:
|
||||
state.preferencesOpen = Marked(false)
|
||||
|
||||
}
|
||||
|
||||
return StateActionPair(state: state, action: pair.action)
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,8 @@ struct AppState {
|
||||
var openNewMainWindowOnLaunch = true
|
||||
var openNewMainWindowOnReactivation = true
|
||||
|
||||
var preferencesOpen = Marked(false)
|
||||
|
||||
var mainWindowTemplate: MainWindow.State
|
||||
var currentMainWindowUuid: String?
|
||||
|
||||
@ -37,7 +39,7 @@ extension OpenQuicklyWindow {
|
||||
|
||||
var flatFileItems = Observable<[FileItem]>.empty()
|
||||
var cwd = FileUtils.userHomeUrl
|
||||
var ignorePatterns = [FileItemIgnorePattern]()
|
||||
var ignorePatterns = Set(["*/.git", "*.o", "*.d", "*.dia"].map(FileItemIgnorePattern.init))
|
||||
var ignoreToken = Token()
|
||||
|
||||
var open = false
|
||||
@ -73,8 +75,7 @@ struct PreviewState {
|
||||
buffer: URL? = nil,
|
||||
html: URL? = nil,
|
||||
server: URL? = nil,
|
||||
updateDate: Date = Date())
|
||||
{
|
||||
updateDate: Date = Date()) {
|
||||
self.status = status
|
||||
self.buffer = buffer
|
||||
self.html = html
|
||||
|
@ -15,6 +15,7 @@ class UiRoot: UiComponent {
|
||||
self.emitter = emitter
|
||||
|
||||
self.fileMonitor = FileMonitor(source: source, emitter: emitter, state: state)
|
||||
self.prefWindow = PrefWindow(source: source, emitter: emitter, state: state)
|
||||
self.openQuicklyWindow = OpenQuicklyWindow(source: source, emitter: emitter, state: state)
|
||||
|
||||
source
|
||||
@ -47,6 +48,18 @@ class UiRoot: UiComponent {
|
||||
.addDisposableTo(self.disposeBag)
|
||||
}
|
||||
|
||||
fileprivate let source: Observable<AppState>
|
||||
fileprivate let emitter: ActionEmitter
|
||||
fileprivate let disposeBag = DisposeBag()
|
||||
|
||||
fileprivate let fileMonitor: FileMonitor
|
||||
fileprivate let prefWindow: PrefWindow
|
||||
fileprivate let openQuicklyWindow: OpenQuicklyWindow
|
||||
|
||||
fileprivate var mainWindows = [String: MainWindow]()
|
||||
fileprivate var subjectForMainWindows = [String: PublishSubject<MainWindow.State>]()
|
||||
fileprivate var disposables = [String: Disposable]()
|
||||
|
||||
fileprivate func createNewMainWindow(with state: MainWindow.State) {
|
||||
let subject = PublishSubject<MainWindow.State>()
|
||||
let source = self.source.mapOmittingNil { $0.mainWindows[state.uuid] }
|
||||
@ -67,16 +80,4 @@ class UiRoot: UiComponent {
|
||||
self.disposables.removeValue(forKey: uuid)
|
||||
self.mainWindows.removeValue(forKey: uuid)
|
||||
}
|
||||
|
||||
fileprivate let source: Observable<AppState>
|
||||
fileprivate let emitter: ActionEmitter
|
||||
fileprivate let disposeBag = DisposeBag()
|
||||
|
||||
fileprivate var mainWindows = [String: MainWindow]()
|
||||
fileprivate var subjectForMainWindows = [String: PublishSubject<MainWindow.State>]()
|
||||
fileprivate var disposables = [String: Disposable]()
|
||||
|
||||
fileprivate let fileMonitor: FileMonitor
|
||||
|
||||
fileprivate let openQuicklyWindow: OpenQuicklyWindow
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user