1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-12-01 10:02:36 +03:00
This commit is contained in:
Tae Won Ha 2019-02-24 14:42:45 +01:00
parent d321d4fca0
commit bbf83c7856
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44

View File

@ -18,7 +18,11 @@ class FileOutlineView: NSOutlineView,
private(set) var theme = Theme.default private(set) var theme = Theme.default
required init(source: Observable<StateType>, emitter: ActionEmitter, state: StateType) { required init(
source: Observable<StateType>,
emitter: ActionEmitter,
state: StateType) {
self.emit = emitter.typedEmit() self.emit = emitter.typedEmit()
self.uuid = state.uuid self.uuid = state.uuid
@ -35,14 +39,18 @@ class FileOutlineView: NSOutlineView,
self.delegate = self self.delegate = self
self.allowsEmptySelection = true self.allowsEmptySelection = true
guard Bundle.main.loadNibNamed(NSNib.Name("FileBrowserMenu"), owner: self, topLevelObjects: nil) else { guard Bundle.main.loadNibNamed(
NSNib.Name("FileBrowserMenu"),
owner: self,
topLevelObjects: nil
) else {
NSLog("WARN: FileBrowserMenu.xib could not be loaded") NSLog("WARN: FileBrowserMenu.xib could not be loaded")
return return
} }
// If the target of the menu items is set to the first responder, the actions are not invoked // If the target of the menu items is set to the first responder,
// at all when the file monitor fires in the background... // the actions are not invoked at all when the file monitor fires
// Dunno why it worked before the redesign... -_- // in the background... Dunno why it worked before the redesign... -_-
self.menu?.items.forEach { $0.target = self } self.menu?.items.forEach { $0.target = self }
self.doubleAction = #selector(FileOutlineView.doubleClickAction) self.doubleAction = #selector(FileOutlineView.doubleClickAction)
@ -56,7 +64,9 @@ class FileOutlineView: NSOutlineView,
.observeOn(MainScheduler.instance) .observeOn(MainScheduler.instance)
.subscribe(onNext: { state in .subscribe(onNext: { state in
self.lastFileSystemUpdateMark = state.lastFileSystemUpdate.mark self.lastFileSystemUpdateMark = state.lastFileSystemUpdate.mark
guard let fileBrowserItem = self.fileBrowserItem(with: state.lastFileSystemUpdate.payload) else { guard let fileBrowserItem = self.fileBrowserItem(
with: state.lastFileSystemUpdate.payload
) else {
return return
} }
@ -67,7 +77,8 @@ class FileOutlineView: NSOutlineView,
source source
.observeOn(MainScheduler.instance) .observeOn(MainScheduler.instance)
.subscribe(onNext: { state in .subscribe(onNext: { state in
if state.viewToBeFocused != nil, case .fileBrowser = state.viewToBeFocused! { if state.viewToBeFocused != nil,
case .fileBrowser = state.viewToBeFocused! {
self.beFirstResponder() self.beFirstResponder()
} }
@ -80,7 +91,9 @@ class FileOutlineView: NSOutlineView,
self.usesTheme = state.appearance.usesTheme self.usesTheme = state.appearance.usesTheme
guard self.shouldReloadData(for: state, themeChanged: themeChanged) else { guard self.shouldReloadData(
for: state, themeChanged: themeChanged
) else {
return return
} }
@ -108,14 +121,18 @@ class FileOutlineView: NSOutlineView,
if item.url.isDirectParent(of: url) { if item.url.isDirectParent(of: url) {
if let targetItem = item.children.first(where: { $0.url == url }) { if let targetItem = item.children.first(where: { $0.url == url }) {
let targetRow = self.row(forItem: targetItem) let targetRow = self.row(forItem: targetItem)
self.selectRowIndexes(IndexSet(integer: targetRow), byExtendingSelection: false) self.selectRowIndexes(
IndexSet(integer: targetRow), byExtendingSelection: false
)
self.scrollRowToVisible(targetRow) self.scrollRowToVisible(targetRow)
} }
break break
} }
stack.append(contentsOf: item.children.filter { $0.url.isParent(of: url) }) stack.append(contentsOf: item.children.filter {
$0.url.isParent(of: url)
})
} }
} }
@ -149,7 +166,9 @@ class FileOutlineView: NSOutlineView,
self.lastThemeMark = theme.mark self.lastThemeMark = theme.mark
} }
private func shouldReloadData(for state: StateType, themeChanged: Bool = false) -> Bool { private func shouldReloadData(
for state: StateType, themeChanged: Bool = false
) -> Bool {
if self.isShowHidden != state.fileBrowserShowHidden { if self.isShowHidden != state.fileBrowserShowHidden {
return true return true
} }
@ -170,7 +189,7 @@ class FileOutlineView: NSOutlineView,
} }
private func handleRemovals(for fileBrowserItem: FileBrowserItem, private func handleRemovals(for fileBrowserItem: FileBrowserItem,
new newChildren: [FileBrowserItem]) { new newChildren: [FileBrowserItem]) {
let curChildren = fileBrowserItem.children let curChildren = fileBrowserItem.children
let curPreparedChildren = self.prepare(curChildren) let curPreparedChildren = self.prepare(curChildren)
@ -178,7 +197,9 @@ class FileOutlineView: NSOutlineView,
let indicesToRemove = curPreparedChildren let indicesToRemove = curPreparedChildren
.enumerated() .enumerated()
.filter { (_, fileBrowserItem) in newPreparedChildren.contains(fileBrowserItem) == false } .filter { (_, fileBrowserItem) in
newPreparedChildren.contains(fileBrowserItem) == false
}
.map { (idx, _) in idx } .map { (idx, _) in idx }
indicesToRemove.forEach { index in indicesToRemove.forEach { index in
@ -195,7 +216,7 @@ class FileOutlineView: NSOutlineView,
} }
private func handleAdditions(for fileBrowserItem: FileBrowserItem, private func handleAdditions(for fileBrowserItem: FileBrowserItem,
new newChildren: [FileBrowserItem]) { new newChildren: [FileBrowserItem]) {
let curChildren = fileBrowserItem.children let curChildren = fileBrowserItem.children
let curPreparedChildren = self.prepare(curChildren) let curPreparedChildren = self.prepare(curChildren)
@ -203,11 +224,13 @@ class FileOutlineView: NSOutlineView,
let indicesToInsert = newPreparedChildren let indicesToInsert = newPreparedChildren
.enumerated() .enumerated()
.filter { (_, fileBrowserItem) in curPreparedChildren.contains(fileBrowserItem) == false } .filter { (_, fileBrowserItem) in
curPreparedChildren.contains(fileBrowserItem) == false
}
.map { (idx, _) in idx } .map { (idx, _) in idx }
// We don't just take newChildren because NSOutlineView look at the pointer equality for // We don't just take newChildren because NSOutlineView look
// preserving the expanded states... // at the pointer equality for preserving the expanded states...
fileBrowserItem.children = newChildren.substituting(elements: curChildren) fileBrowserItem.children = newChildren.substituting(elements: curChildren)
let parent = fileBrowserItem == self.root ? nil : fileBrowserItem let parent = fileBrowserItem == self.root ? nil : fileBrowserItem
@ -215,13 +238,14 @@ class FileOutlineView: NSOutlineView,
} }
private func sortedChildren(of url: URL) -> [FileBrowserItem] { private func sortedChildren(of url: URL) -> [FileBrowserItem] {
return FileUtils.directDescendants(of: url).map(FileBrowserItem.init).sorted{ return FileUtils.directDescendants(of: url)
if ($0.isDir == $1.isDir) { .map(FileBrowserItem.init).sorted {
return $0.url.absoluteString < $1.url.absoluteString if ($0.isDir == $1.isDir) {
} return $0.url.absoluteString < $1.url.absoluteString
}
return $0.isDir return $0.isDir
} }
} }
private func update(_ fileBrowserItem: FileBrowserItem) { private func update(_ fileBrowserItem: FileBrowserItem) {
@ -240,7 +264,9 @@ class FileOutlineView: NSOutlineView,
fileBrowserItem.isChildrenScanned = true fileBrowserItem.isChildrenScanned = true
fileBrowserItem.children.filter { self.isItemExpanded($0) }.forEach(self.update) fileBrowserItem.children
.filter { self.isItemExpanded($0) }
.forEach(self.update)
} }
private func fileBrowserItem(with url: URL) -> FileBrowserItem? { private func fileBrowserItem(with url: URL) -> FileBrowserItem? {
@ -256,7 +282,8 @@ class FileOutlineView: NSOutlineView,
let pathComps = url.pathComponents let pathComps = url.pathComponents
let childPart = pathComps[rootPathComps.count..<pathComps.count] let childPart = pathComps[rootPathComps.count..<pathComps.count]
return childPart.reduce(self.root) { (resultItem, childName) -> FileBrowserItem? in return childPart
.reduce(self.root) { (resultItem, childName) -> FileBrowserItem? in
guard let parent = resultItem else { guard let parent = resultItem else {
return nil return nil
} }
@ -301,7 +328,9 @@ extension FileOutlineView {
return 0 return 0
} }
func outlineView(_: NSOutlineView, child index: Int, ofItem item: Any?) -> Any { func outlineView(
_: NSOutlineView, child index: Int, ofItem item: Any?
) -> Any {
let level = self.level(forItem: item) + 2 let level = self.level(forItem: item) + 2
defer { self.adjustColumnWidths() } defer { self.adjustColumnWidths() }
@ -340,7 +369,9 @@ extension FileOutlineView {
if self.showsFileIcon { if self.showsFileIcon {
let icon = FileUtils.icon(forUrl: item.url) let icon = FileUtils.icon(forUrl: item.url)
cell.image = cell.isHidden ? icon?.tinting(with: NSColor.white.withAlphaComponent(0.4)) : icon cell.image = cell.isHidden
? icon?.tinting(with: NSColor.white.withAlphaComponent(0.4))
: icon
} }
return cell return cell
@ -353,8 +384,11 @@ extension FileOutlineView {
return fileBrowserItem.url.isDir return fileBrowserItem.url.isDir
} }
@objc(outlineView: objectValueForTableColumn:byItem:) @objc(outlineView:objectValueForTableColumn:byItem:)
func outlineView(_: NSOutlineView, objectValueFor: NSTableColumn?, byItem item: Any?) -> Any? { func outlineView(_: NSOutlineView,
objectValueFor: NSTableColumn?,
byItem item: Any?) -> Any? {
guard let fileBrowserItem = item as? FileBrowserItem else { guard let fileBrowserItem = item as? FileBrowserItem else {
return nil return nil
} }
@ -381,12 +415,19 @@ extension FileOutlineView {
// MARK: - NSOutlineViewDelegate // MARK: - NSOutlineViewDelegate
extension FileOutlineView { extension FileOutlineView {
func outlineView(_ outlineView: NSOutlineView, rowViewForItem item: Any) -> NSTableRowView? { func outlineView(
return self.makeView(withIdentifier: NSUserInterfaceItemIdentifier("file-row-view"), owner: self) as? ThemedTableRow _ outlineView: NSOutlineView, rowViewForItem item: Any
?? ThemedTableRow(withIdentifier: "file-row-view", themedView: self) ) -> NSTableRowView? {
return self.makeView(
withIdentifier: NSUserInterfaceItemIdentifier("file-row-view"),
owner: self
) as? ThemedTableRow ?? ThemedTableRow(withIdentifier: "file-row-view",
themedView: self)
} }
func outlineView(_: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { func outlineView(
_: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any
) -> NSView? {
guard let fileBrowserItem = item as? FileBrowserItem else { guard let fileBrowserItem = item as? FileBrowserItem else {
return nil return nil
} }
@ -411,7 +452,8 @@ extension FileOutlineView {
self.toggle(item: item) self.toggle(item: item)
} else { } else {
self.emit( self.emit(
UuidAction(uuid: self.uuid, action: .open(url: item.url, mode: .default)) UuidAction(uuid: self.uuid,
action: .open(url: item.url, mode: .default))
) )
} }
} }
@ -432,7 +474,8 @@ extension FileOutlineView {
} }
self.emit( self.emit(
UuidAction(uuid: self.uuid, action: .open(url: item.url, mode: .currentTab)) UuidAction(uuid: self.uuid,
action: .open(url: item.url, mode: .currentTab))
) )
} }
@ -442,7 +485,8 @@ extension FileOutlineView {
} }
self.emit( self.emit(
UuidAction(uuid: self.uuid, action: .open(url: item.url, mode: .horizontalSplit)) UuidAction(uuid: self.uuid,
action: .open(url: item.url, mode: .horizontalSplit))
) )
} }
@ -452,7 +496,8 @@ extension FileOutlineView {
} }
self.emit( self.emit(
UuidAction(uuid: self.uuid, action: .open(url: item.url, mode: .verticalSplit)) UuidAction(uuid: self.uuid,
action: .open(url: item.url, mode: .verticalSplit))
) )
} }
@ -474,7 +519,9 @@ extension FileOutlineView {
// MARK: - NSUserInterfaceValidations // MARK: - NSUserInterfaceValidations
extension FileOutlineView { extension FileOutlineView {
override func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool { override func validateUserInterfaceItem(
_ item: NSValidatedUserInterfaceItem
) -> Bool {
guard let clickedItem = self.clickedItem as? FileBrowserItem else { guard let clickedItem = self.clickedItem as? FileBrowserItem else {
return true return true
} }
@ -507,7 +554,8 @@ extension FileOutlineView {
self.toggle(item: item) self.toggle(item: item)
} else { } else {
self.emit( self.emit(
UuidAction(uuid: self.uuid, action: .open(url: item.url, mode: .newTab)) UuidAction(uuid: self.uuid,
action: .open(url: item.url, mode: .newTab))
) )
} }
@ -544,8 +592,9 @@ private class FileBrowserItem: Hashable, Comparable, CustomStringConvertible {
init(_ url: URL) { init(_ url: URL) {
self.url = url self.url = url
// We cache the value here since we often get the value when the file is not there, eg when // We cache the value here since we often get the value when the file is
// updating because the file gets deleted (in self.prepare() function) // not there, eg when updating because the file gets deleted
// (in self.prepare() function)
self.isHidden = url.isHidden self.isHidden = url.isHidden
self.isDir = url.isDir self.isDir = url.isDir
} }