1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-12-26 07:13:24 +03:00

Use one file monitor for each file browser

This commit is contained in:
Tae Won Ha 2020-01-25 10:01:06 +01:00
parent 7493a6fefb
commit 1c2b1b16b2
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
8 changed files with 32 additions and 159 deletions

View File

@ -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 */,

View File

@ -38,7 +38,6 @@ class Context: ReduxContext {
AppDelegateReducer(baseServerUrl: baseServerUrl).reduce,
uiRootReducer.mainWindow.reduce,
openQuicklyReducer.mainWindow.reduce,
FileMonitorReducer().reduce,
openQuicklyReducer.reduce,
uiRootReducer.reduce,

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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
self.root = Node(url: state.cwd)
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

View File

@ -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)

View File

@ -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)

View File

@ -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