mirror of
https://github.com/qvacua/vimr.git
synced 2024-12-26 23:36:08 +03:00
Use one file monitor for each file browser
This commit is contained in:
parent
7493a6fefb
commit
1c2b1b16b2
@ -35,13 +35,11 @@
|
||||
1929B5257DB27F03C6663482 /* MainWindow+Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B067B3247675BCD09218 /* MainWindow+Actions.swift */; };
|
||||
1929B542A071BD03C846F6EF /* PrefUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B8241CDE58F7AAF89AE4 /* PrefUtils.swift */; };
|
||||
1929B543D5C82485F053CF17 /* FuzzySearch.xcdatamodel in Sources */ = {isa = PBXBuildFile; fileRef = 1929B656C04BA6F950BFA2F5 /* FuzzySearch.xcdatamodel */; };
|
||||
1929B5543B1E31A26096E656 /* FileMonitorReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B04EC69F616EEFAF5F96 /* FileMonitorReducer.swift */; };
|
||||
1929B560C6CE264FD1E1F5A3 /* com.qvacua.VimR.vim in Resources */ = {isa = PBXBuildFile; fileRef = 1929BC6D45B7E14D4D75D4E6 /* com.qvacua.VimR.vim */; };
|
||||
1929B59FA5C286E010F70BEE /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BFC0A5A9C6DB09BE1368 /* Types.swift */; };
|
||||
1929B5A0EDD1119CFF7BB84C /* Defs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B7F7A4B3FD52263D211D /* Defs.swift */; };
|
||||
1929B5A2EE366F79ED32744C /* KeysPrefReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B88B5FA08E897A3C2168 /* KeysPrefReducer.swift */; };
|
||||
1929B5C1BABBC0D09D97C3EF /* PreviewMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B617C229B19DB3E987B8 /* PreviewMiddleware.swift */; };
|
||||
1929B5F016431A76292D1E84 /* FileMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B365A6434354B568B04F /* FileMonitor.swift */; };
|
||||
1929B6460862447A31B5B082 /* ImageAndTextTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDC3F82CB4CB4FE56D1B /* ImageAndTextTableCell.swift */; };
|
||||
1929B66F795867B8C07FAAD4 /* DictionaryCommonsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9355C892BEBA7496C71 /* DictionaryCommonsTest.swift */; };
|
||||
1929B67DA3EB21A631EF1DBB /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA8AC40B901B20F20B71 /* FileUtils.swift */; };
|
||||
@ -124,8 +122,6 @@
|
||||
4B2636C9223A487B00021586 /* PreviewToolReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BFB0F294F3714D5E095F /* PreviewToolReducer.swift */; };
|
||||
4B2636CA223A487B00021586 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BFC0A5A9C6DB09BE1368 /* Types.swift */; };
|
||||
4B2636CB223A487B00021586 /* OpenQuicklyReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B12CE56A9B36980288A4 /* OpenQuicklyReducer.swift */; };
|
||||
4B2636CC223A487B00021586 /* FileMonitorReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B04EC69F616EEFAF5F96 /* FileMonitorReducer.swift */; };
|
||||
4B2636CD223A487B00021586 /* FileMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B365A6434354B568B04F /* FileMonitor.swift */; };
|
||||
4B2636CE223A487B00021586 /* FileBrowserReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDC8F5D48578A90236E9 /* FileBrowserReducer.swift */; };
|
||||
4B2636CF223A487B00021586 /* BufferList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA43449BA41666CD55ED /* BufferList.swift */; };
|
||||
4B2636D0223A487B00021586 /* BufferListReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B67A10E6BB2986B2416E /* BufferListReducer.swift */; };
|
||||
@ -508,7 +504,6 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1929B02440BC99C42F9EBD45 /* NetUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NetUtils.m; sourceTree = "<group>"; };
|
||||
1929B04EC69F616EEFAF5F96 /* FileMonitorReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileMonitorReducer.swift; sourceTree = "<group>"; };
|
||||
1929B067B3247675BCD09218 /* MainWindow+Actions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MainWindow+Actions.swift"; sourceTree = "<group>"; };
|
||||
1929B07A4A9209C88380E015 /* PrefPane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefPane.swift; sourceTree = "<group>"; };
|
||||
1929B07F0085B7AE10413346 /* ShortcutsTableSubviews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsTableSubviews.swift; sourceTree = "<group>"; };
|
||||
@ -532,7 +527,6 @@
|
||||
1929B230EE8F1428980988F0 /* RpcAppearanceEpic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RpcAppearanceEpic.swift; sourceTree = "<group>"; };
|
||||
1929B34FC23D805A8B29E8F7 /* Context.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Context.swift; sourceTree = "<group>"; };
|
||||
1929B364460D86F17E80943C /* PrefMiddleware.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefMiddleware.swift; sourceTree = "<group>"; };
|
||||
1929B365A6434354B568B04F /* FileMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileMonitor.swift; sourceTree = "<group>"; };
|
||||
1929B41F704A4D67621197ED /* MainWindow+Types.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MainWindow+Types.swift"; sourceTree = "<group>"; };
|
||||
1929B457B9D0FA4D21F3751E /* UiRootReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UiRootReducer.swift; sourceTree = "<group>"; };
|
||||
1929B49E6924847AD085C8C9 /* PrefWindowReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrefWindowReducer.swift; sourceTree = "<group>"; };
|
||||
@ -835,7 +829,6 @@
|
||||
children = (
|
||||
1929BD4149D5A25C82064DD8 /* UiRoot.swift */,
|
||||
1929B6C6C7792B05164B0216 /* PreviewTool.swift */,
|
||||
1929B365A6434354B568B04F /* FileMonitor.swift */,
|
||||
1929BA43449BA41666CD55ED /* BufferList.swift */,
|
||||
1929BC56ADBA3275E7A0A598 /* Preferences */,
|
||||
1929B1645977E0AEFE53193D /* File Browser */,
|
||||
@ -865,7 +858,6 @@
|
||||
1929BE37AA2843779CAFA76F /* PreviewReducer.swift */,
|
||||
1929BFB0F294F3714D5E095F /* PreviewToolReducer.swift */,
|
||||
1929B12CE56A9B36980288A4 /* OpenQuicklyReducer.swift */,
|
||||
1929B04EC69F616EEFAF5F96 /* FileMonitorReducer.swift */,
|
||||
1929BDC8F5D48578A90236E9 /* FileBrowserReducer.swift */,
|
||||
1929B67A10E6BB2986B2416E /* BufferListReducer.swift */,
|
||||
1929BB4CF1C1FFEE6CCDD6FD /* Preferences */,
|
||||
@ -1579,8 +1571,6 @@
|
||||
4B2636CB223A487B00021586 /* OpenQuicklyReducer.swift in Sources */,
|
||||
4BF70EE223D1B5B3009E51E9 /* FileScanBaton.m in Sources */,
|
||||
4B917E582334D52D00752149 /* EonilFSEventStreamCreateFlags.swift in Sources */,
|
||||
4B2636CC223A487B00021586 /* FileMonitorReducer.swift in Sources */,
|
||||
4B2636CD223A487B00021586 /* FileMonitor.swift in Sources */,
|
||||
4B2636CE223A487B00021586 /* FileBrowserReducer.swift in Sources */,
|
||||
4B2636CF223A487B00021586 /* BufferList.swift in Sources */,
|
||||
4B2636D0223A487B00021586 /* BufferListReducer.swift in Sources */,
|
||||
@ -1681,8 +1671,6 @@
|
||||
1929B6D8F5FC723B7109031F /* OpenQuicklyReducer.swift in Sources */,
|
||||
4BF70EE123D1B5B3009E51E9 /* FileScanBaton.m in Sources */,
|
||||
4B917E562334D52D00752149 /* EonilFSEventStreamCreateFlags.swift in Sources */,
|
||||
1929B5543B1E31A26096E656 /* FileMonitorReducer.swift in Sources */,
|
||||
1929B5F016431A76292D1E84 /* FileMonitor.swift in Sources */,
|
||||
1929B71381946860626E5224 /* FileBrowserReducer.swift in Sources */,
|
||||
1929BA715337FE26155B2071 /* BufferList.swift in Sources */,
|
||||
1929B4E54E2F13A7F5F2B682 /* BufferListReducer.swift in Sources */,
|
||||
|
@ -38,7 +38,6 @@ class Context: ReduxContext {
|
||||
AppDelegateReducer(baseServerUrl: baseServerUrl).reduce,
|
||||
uiRootReducer.mainWindow.reduce,
|
||||
openQuicklyReducer.mainWindow.reduce,
|
||||
FileMonitorReducer().reduce,
|
||||
openQuicklyReducer.reduce,
|
||||
uiRootReducer.reduce,
|
||||
|
||||
|
@ -1,85 +0,0 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Cocoa
|
||||
import RxSwift
|
||||
import os
|
||||
|
||||
private let monitorDispatchQueue = DispatchQueue.global(qos: .userInitiated)
|
||||
|
||||
class FileMonitor: UiComponent {
|
||||
|
||||
typealias StateType = AppState
|
||||
|
||||
enum Action {
|
||||
|
||||
case change(in : URL)
|
||||
}
|
||||
|
||||
static let fileSystemEventsLatency = 1.0
|
||||
|
||||
required init(source: Observable<StateType>, emitter: ActionEmitter, state: StateType) {
|
||||
self.emit = emitter.typedEmit()
|
||||
|
||||
source
|
||||
.subscribe(onNext: { [unowned self] appState in
|
||||
let urlsToMonitor = Set(appState.mainWindows.map { $1.cwd })
|
||||
|
||||
let newUrls = urlsToMonitor.subtracting(self.monitoredUrls)
|
||||
let obsoleteUrls = self.monitoredUrls.subtracting(urlsToMonitor)
|
||||
|
||||
newUrls.forEach { url in
|
||||
self.log.info("Adding \(url) to monitoring")
|
||||
self.monitoredUrls.insert(url)
|
||||
|
||||
let path = url.path
|
||||
|
||||
// FIXME: Handle EonilFileSystemEventFlag.RootChanged, ie watchRoot: true
|
||||
do {
|
||||
let monitor = try EonilFSEventStream(
|
||||
pathsToWatch: [path],
|
||||
sinceWhen: EonilFSEventsEventID.getCurrentEventId(),
|
||||
latency: FileMonitor.fileSystemEventsLatency,
|
||||
flags: [],
|
||||
handler: { [weak self] event in
|
||||
self?.emit(.change(in: URL(fileURLWithPath: event.path)))
|
||||
})
|
||||
monitor.setDispatchQueue(monitorDispatchQueue)
|
||||
try monitor.start()
|
||||
self.monitors[url] = monitor
|
||||
} catch {
|
||||
self.log.error("Could not start file monitor for \(path): "
|
||||
+ "\(error)")
|
||||
}
|
||||
}
|
||||
|
||||
obsoleteUrls.forEach { url in
|
||||
self.log.info("Removing \(url) from monitoring")
|
||||
self.monitoredUrls.remove(url)
|
||||
|
||||
self.monitors[url]?.stop()
|
||||
self.monitors[url]?.invalidate()
|
||||
self.monitors.removeValue(forKey: url)
|
||||
}
|
||||
})
|
||||
.disposed(by: self.disposeBag)
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.monitors.values.forEach { monitor in
|
||||
monitor.stop()
|
||||
monitor.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
private let emit: (Action) -> Void
|
||||
private let disposeBag = DisposeBag()
|
||||
|
||||
private var monitoredUrls = Set<URL>()
|
||||
private var monitors = [URL: EonilFSEventStream]()
|
||||
|
||||
private let log = OSLog(subsystem: Defs.loggerSubsystem,
|
||||
category: Defs.LoggerCategory.uiComponents)
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
class FileMonitorReducer: ReducerType {
|
||||
|
||||
typealias StateType = AppState
|
||||
typealias ActionType = FileMonitor.Action
|
||||
|
||||
func typedReduce(_ tuple: ReduceTuple) -> ReduceTuple {
|
||||
var state = tuple.state
|
||||
|
||||
switch tuple.action {
|
||||
|
||||
case let .change(in: url):
|
||||
state.mainWindows
|
||||
.filter { (uuid, mainWindow) in url == mainWindow.cwd || url.isContained(in: mainWindow.cwd) }
|
||||
.map { $0.0 }
|
||||
.forEach { uuid in
|
||||
state.mainWindows[uuid]?.lastFileSystemUpdate = Marked(url)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (state, tuple.action, true)
|
||||
}
|
||||
}
|
@ -44,6 +44,10 @@ class FileOutlineView: NSOutlineView,
|
||||
|
||||
super.init(frame: .zero)
|
||||
|
||||
try? self.fileMonitor.monitor(url: state.cwd) { [weak self] url in
|
||||
self?.handleFileSystemChanges(url)
|
||||
}
|
||||
|
||||
NSOutlineView.configure(toStandard: self)
|
||||
self.delegate = self
|
||||
|
||||
@ -69,30 +73,18 @@ class FileOutlineView: NSOutlineView,
|
||||
self.showsFileIcon = state.appearance.showsFileIcon
|
||||
self.isShowHidden = state.fileBrowserShowHidden
|
||||
self.lastFileSystemUpdateMark = state.lastFileSystemUpdate.mark
|
||||
|
||||
if self.root.url != state.cwd {
|
||||
self.root = Node(url: state.cwd)
|
||||
try? self.fileMonitor.monitor(url: state.cwd) { [weak self] url in
|
||||
self?.handleFileSystemChanges(url)
|
||||
}
|
||||
}
|
||||
|
||||
self.reloadRoot()
|
||||
})
|
||||
.disposed(by: self.disposeBag)
|
||||
|
||||
source
|
||||
.filter { !self.shouldReloadData(for: $0) }
|
||||
.filter { $0.lastFileSystemUpdate.mark != self.lastFileSystemUpdateMark }
|
||||
.map { $0.lastFileSystemUpdate.payload }
|
||||
.throttle(
|
||||
2 * FileMonitor.fileSystemEventsLatency + 1,
|
||||
latest: true,
|
||||
scheduler: SerialDispatchQueueScheduler(qos: .background)
|
||||
)
|
||||
.map { ($0, Set(self.childUrls(for: $0))) }
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onNext: { url, newChildUrls in
|
||||
guard let changeTreeNode = self.changeRootTreeNode(for: url) else { return }
|
||||
|
||||
self.handleRemoval(changeTreeNode: changeTreeNode, newChildUrls: newChildUrls)
|
||||
self.handleAddition(changeTreeNode: changeTreeNode, newChildUrls: newChildUrls)
|
||||
})
|
||||
.disposed(by: self.disposeBag)
|
||||
|
||||
self.initContextMenu()
|
||||
self.initBindings()
|
||||
self.reloadRoot()
|
||||
@ -161,6 +153,16 @@ class FileOutlineView: NSOutlineView,
|
||||
|
||||
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
|
||||
|
||||
private func handleFileSystemChanges(_ changedUrl: URL) {
|
||||
let newChildUrls = Set(self.childUrls(for: changedUrl))
|
||||
DispatchQueue.main.async {
|
||||
guard let changeTreeNode = self.changeRootTreeNode(for: changedUrl) else { return }
|
||||
|
||||
self.handleRemoval(changeTreeNode: changeTreeNode, newChildUrls: newChildUrls)
|
||||
self.handleAddition(changeTreeNode: changeTreeNode, newChildUrls: newChildUrls)
|
||||
}
|
||||
}
|
||||
|
||||
private let emit: (UuidAction<FileBrowser.Action>) -> Void
|
||||
private let disposeBag = DisposeBag()
|
||||
|
||||
@ -169,6 +171,7 @@ class FileOutlineView: NSOutlineView,
|
||||
private var root: Node
|
||||
private var cwd: URL { self.root.url }
|
||||
private let treeController = NSTreeController()
|
||||
private let fileMonitor = FuzzySearchFileMonitor()
|
||||
|
||||
private var cachedColumnWidth = 20.cgf
|
||||
private var usesTheme: Bool
|
||||
|
@ -10,7 +10,11 @@ class FuzzySearchFileMonitor {
|
||||
|
||||
static let fileSystemEventsLatency = 1.0
|
||||
|
||||
func start(eventHandler: (@escaping (URL) -> Void)) throws {
|
||||
private(set) var urlToMonitor = FileUtils.userHomeUrl
|
||||
|
||||
func monitor(url: URL, eventHandler: (@escaping (URL) -> Void)) throws {
|
||||
self.stopMonitor()
|
||||
self.urlToMonitor = url
|
||||
self.monitor = try EonilFSEventStream(
|
||||
pathsToWatch: [urlToMonitor.path],
|
||||
sinceWhen: EonilFSEventsEventID.getCurrentEventId(),
|
||||
@ -31,16 +35,13 @@ class FuzzySearchFileMonitor {
|
||||
self.log.info("Started monitoring \(self.urlToMonitor)")
|
||||
}
|
||||
|
||||
init(urlToMonitor: URL) {
|
||||
self.urlToMonitor = urlToMonitor
|
||||
}
|
||||
deinit { stopMonitor() }
|
||||
|
||||
deinit {
|
||||
private func stopMonitor() {
|
||||
self.monitor?.stop()
|
||||
self.monitor?.invalidate()
|
||||
}
|
||||
|
||||
private var urlToMonitor: URL
|
||||
private var monitor: EonilFSEventStream?
|
||||
|
||||
private let log = OSLog(subsystem: Defs.loggerSubsystem, category: Defs.LoggerCategory.service)
|
||||
|
@ -295,10 +295,9 @@ class FuzzySearchService {
|
||||
)
|
||||
self.root = root
|
||||
self.writeContext = self.coreDataStack.newBackgroundContext()
|
||||
self.fileMonitor = FuzzySearchFileMonitor(urlToMonitor: root)
|
||||
|
||||
self.queue.sync { self.ensureRootFileInStore() }
|
||||
try self.fileMonitor.start { [weak self] url in self?.handleChange(in: url) }
|
||||
try self.fileMonitor.monitor(url: root) { [weak self] url in self?.handleChange(in: url) }
|
||||
}
|
||||
|
||||
private func ensureRootFileInStore() {
|
||||
@ -442,7 +441,7 @@ class FuzzySearchService {
|
||||
|
||||
private let queue = DispatchQueue(label: "scan-score-queue", qos: .userInitiated)
|
||||
|
||||
private let fileMonitor: FuzzySearchFileMonitor
|
||||
private let fileMonitor = FuzzySearchFileMonitor()
|
||||
private let writeContext: NSManagedObjectContext
|
||||
|
||||
private let log = OSLog(subsystem: Defs.loggerSubsystem, category: Defs.LoggerCategory.service)
|
||||
|
@ -24,7 +24,6 @@ class UiRoot: UiComponent {
|
||||
self.emitter = emitter
|
||||
self.emit = emitter.typedEmit()
|
||||
|
||||
self.fileMonitor = FileMonitor(source: source, emitter: emitter, state: state)
|
||||
self.openQuicklyWindow = OpenQuicklyWindow(source: source, emitter: emitter, state: state)
|
||||
self.prefWindow = PrefWindow(source: source, emitter: emitter, state: state)
|
||||
|
||||
@ -95,7 +94,6 @@ class UiRoot: UiComponent {
|
||||
private let emit: (Action) -> Void
|
||||
private let disposeBag = DisposeBag()
|
||||
|
||||
private let fileMonitor: FileMonitor
|
||||
private let openQuicklyWindow: OpenQuicklyWindow
|
||||
private let prefWindow: PrefWindow
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user