1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-12-25 23:02:35 +03:00

List all menu items

This commit is contained in:
Tae Won Ha 2019-02-26 16:12:32 +01:00
parent 23ef772e2b
commit 27d4972c15
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
9 changed files with 451 additions and 59 deletions

View File

@ -10,6 +10,6 @@ github "sindresorhus/github-markdown-css" == 3.0.1
github "httpswift/swifter" == 1.4.5
github "a2/MessagePack.swift" == 3.0.0
github "elegantchaos/DictionaryCoding" == 1.0.6
github "Kentzo/ShortcutRecorder" == 2.17.2
github "qvacua/ShortcutRecorder" "master"
github "Quick/Nimble" == 7.3.4

View File

@ -1,5 +1,4 @@
github "IBM-Swift/BlueSocket" "1.0.44"
github "Kentzo/ShortcutRecorder" "2.17.2"
github "PureLayout/PureLayout" "v3.1.4"
github "Quick/Nimble" "v7.3.4"
github "ReactiveX/RxSwift" "4.4.1"
@ -12,5 +11,6 @@ github "qvacua/CocoaMarkdown" "7756ad96d5fb390c66531004868e828bb54d3609"
github "qvacua/RxMessagePort" "v0.0.5"
github "qvacua/RxMsgpackRpc" "v0.0.7"
github "qvacua/RxNeovimApi" "0.3.4"
github "qvacua/ShortcutRecorder" "c978ce9bb482c31acfabe23baa2b075808a1fdd8"
github "sindresorhus/github-markdown-css" "v3.0.1"
github "sparkle-project/Sparkle" "1.21.3"

View File

@ -7,11 +7,14 @@
objects = {
/* Begin PBXBuildFile section */
1929B02DAC94F0E47CFC8EA2 /* ShortcutsTableSubviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BCF66D08CC02A9233A88 /* ShortcutsTableSubviews.swift */; };
1929B04CE8ECBD75CBBB0991 /* StringCommonsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B5D45C9792BBE76B8AFF /* StringCommonsTest.swift */; };
1929B05B9D664052EC2D23EF /* FileOutlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BCE3E156C06EDF1F2806 /* FileOutlineView.swift */; };
1929B083D2176A9C615B8807 /* ShortcutsPref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD256AA54518D37D6CBB /* ShortcutsPref.swift */; };
1929B08C6230B9C5AB72DAF1 /* Pref128ToCurrentConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B5046239709E33516F5C /* Pref128ToCurrentConverter.swift */; };
1929B0E0C3BC59F52713D5A2 /* FoundationCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B9AF20D7BD6E5C975128 /* FoundationCommons.swift */; };
1929B0F599D1F62C7BE53D2C /* HttpServerMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B1DC584C89C477E83FA2 /* HttpServerMiddleware.swift */; };
1929B148AA06340F22533377 /* ShortcutItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B1E4B11A92D8DD171D93 /* ShortcutItem.swift */; };
1929B1837C750CADB3A5BCB9 /* OpenQuicklyFileViewRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B1558455B3A74D93EF2A /* OpenQuicklyFileViewRow.swift */; };
1929B20CE35B43BB1CE023BA /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BC2F05E9A5C0DB039739 /* Theme.swift */; };
1929B29B95AD176D57942E08 /* UiRootReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B457B9D0FA4D21F3751E /* UiRootReducer.swift */; };
@ -25,6 +28,7 @@
1929B462CD4935AFF6D69457 /* FileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B7CB4863F80230C32D3C /* FileItem.swift */; };
1929B4B00D7BB191A9A6532D /* HtmlPreviewToolReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE5AEA3D0980860EED50 /* HtmlPreviewToolReducer.swift */; };
1929B4B70926DE113E6BF990 /* PreviewReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE37AA2843779CAFA76F /* PreviewReducer.swift */; };
1929B4DD667E1E57EFA2AA57 /* ShortcutItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B1E4B11A92D8DD171D93 /* ShortcutItem.swift */; };
1929B4E54E2F13A7F5F2B682 /* BufferListReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B67A10E6BB2986B2416E /* BufferListReducer.swift */; };
1929B4F0612224E594E89B92 /* AppearancePref.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B0FBFB766042CF06E463 /* AppearancePref.swift */; };
1929B4FEE6EB56EF3F56B805 /* Context.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B34FC23D805A8B29E8F7 /* Context.swift */; };
@ -56,6 +60,7 @@
1929B990A143763A56CFCED0 /* PrefMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B364460D86F17E80943C /* PrefMiddleware.swift */; };
1929BA715337FE26155B2071 /* BufferList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA43449BA41666CD55ED /* BufferList.swift */; };
1929BA76A1D97D8226F7CFB1 /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B6AD3396160AA2C46919 /* Debouncer.swift */; };
1929BA8E1A7C425E0E03EB40 /* ShortcutsTableSubviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BCF66D08CC02A9233A88 /* ShortcutsTableSubviews.swift */; };
1929BAAD7336FDFF1F78E749 /* ScorerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BF69B01107F358CF7EAD /* ScorerTest.swift */; };
1929BAE4900D72A7877741B1 /* PrefWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE168F31344B69E61B62 /* PrefWindow.swift */; };
1929BAFF1E011321D3186EE6 /* UiRoot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD4149D5A25C82064DD8 /* UiRoot.swift */; };
@ -296,6 +301,7 @@
1929B14A5949FB64C4B2646F /* KeysPref.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeysPref.swift; sourceTree = "<group>"; };
1929B1558455B3A74D93EF2A /* OpenQuicklyFileViewRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenQuicklyFileViewRow.swift; sourceTree = "<group>"; };
1929B1DC584C89C477E83FA2 /* HttpServerMiddleware.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HttpServerMiddleware.swift; sourceTree = "<group>"; };
1929B1E4B11A92D8DD171D93 /* ShortcutItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutItem.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>"; };
@ -340,6 +346,8 @@
1929BBE0A534F2F6009D31BE /* AdvencedPref.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvencedPref.swift; sourceTree = "<group>"; };
1929BC2F05E9A5C0DB039739 /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
1929BCE3E156C06EDF1F2806 /* FileOutlineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileOutlineView.swift; sourceTree = "<group>"; };
1929BCF66D08CC02A9233A88 /* ShortcutsTableSubviews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsTableSubviews.swift; sourceTree = "<group>"; };
1929BD256AA54518D37D6CBB /* ShortcutsPref.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsPref.swift; sourceTree = "<group>"; };
1929BD2CA8DD198A6BCDBCB7 /* ThemedTableSubviews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemedTableSubviews.swift; sourceTree = "<group>"; };
1929BD4149D5A25C82064DD8 /* UiRoot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UiRoot.swift; sourceTree = "<group>"; };
1929BD83A13BF133741766CC /* MainWindowReducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainWindowReducer.swift; sourceTree = "<group>"; };
@ -593,6 +601,7 @@
1929B5E773BDB3B4EE9D00C1 /* Reducers */,
1929BFA93DC859DD76C46192 /* Middlewares */,
1929BFC0A5A9C6DB09BE1368 /* Types.swift */,
1929B1E4B11A92D8DD171D93 /* ShortcutItem.swift */,
);
name = UI;
sourceTree = "<group>";
@ -631,6 +640,8 @@
1929BBE0A534F2F6009D31BE /* AdvencedPref.swift */,
1929BB2AD21A10A0ECA66A5E /* ToolsPref.swift */,
1929B14A5949FB64C4B2646F /* KeysPref.swift */,
1929BD256AA54518D37D6CBB /* ShortcutsPref.swift */,
1929BCF66D08CC02A9233A88 /* ShortcutsTableSubviews.swift */,
);
name = Preferences;
sourceTree = "<group>";
@ -1147,6 +1158,9 @@
1929B8F498D1E7C53F572CE2 /* KeysPref.swift in Sources */,
1929B5A2EE366F79ED32744C /* KeysPrefReducer.swift in Sources */,
1929BB67CAAD4F6CBD38DF0A /* RxRedux.swift in Sources */,
1929B083D2176A9C615B8807 /* ShortcutsPref.swift in Sources */,
1929B4DD667E1E57EFA2AA57 /* ShortcutItem.swift in Sources */,
1929B02DAC94F0E47CFC8EA2 /* ShortcutsTableSubviews.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1178,6 +1192,8 @@
1929B8E90A1378E494D481E7 /* PrefUtilsTest.swift in Sources */,
1929B20CE35B43BB1CE023BA /* Theme.swift in Sources */,
1929B9318D32146D58BB38EC /* AppKitCommons.swift in Sources */,
1929B148AA06340F22533377 /* ShortcutItem.swift in Sources */,
1929BA8E1A7C425E0E03EB40 /* ShortcutsTableSubviews.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -9,6 +9,8 @@ import PureLayout
import Sparkle
import CocoaFontAwesome
let debugMenuItemIdentifier = NSUserInterfaceItemIdentifier("debug-menu-item")
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDelegate {
@ -60,12 +62,41 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
self.openNewMainWindowOnReactivation = initialAppState.openNewMainWindowOnReactivation
self.useSnapshot = initialAppState.useSnapshotUpdate
let source = self.context.stateSource
self.uiRoot = UiRoot(source: source, emitter: self.context.actionEmitter, state: initialAppState)
super.init()
NSUserNotificationCenter.default.delegate = self
// FIXME: GH-611: https://github.com/qvacua/vimr/issues/611
// Check whether FontAwesome can be loaded. If not, show a warning.
// We don't know yet why this happens to some users.
DispatchQueue.main.async {
guard NSFont.fontAwesome(ofSize: 13) == nil else {
return
}
let notification = NSUserNotification()
notification.title = "FontAwesome could not be loaded."
notification.subtitle = "Unfortunately we don't know yet what is causing this."
notification.informativeText = """
We use the FontAwesome font for icons in the tools, e.g. the file browser. Those icons are now shown as ?.
You can track the progress on this issue at GitHub issue 611.
"""
NSUserNotificationCenter.default.deliver(notification)
}
}
override func awakeFromNib() {
super.awakeFromNib()
let source = self.context.stateSource
// We want to build the menu items tree at some point, eg in the init() of
// ShortcutsPref. We have to do that *after* the MainMenu.xib is loaded.
// Therefore, we use optional var for the self.uiRoot. Ugly, but, well...
self.uiRoot = UiRoot(
source: source,
emitter: self.context.actionEmitter,
state: self.context.state
)
source
.observeOn(MainScheduler.instance)
@ -86,30 +117,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
}
})
.disposed(by: self.disposeBag)
// FIXME: GH-611: https://github.com/qvacua/vimr/issues/611
// Check whether FontAwesome can be loaded. If not, show a warning.
// We don't know yet why this happens to some users.
DispatchQueue.main.async {
guard NSFont.fontAwesome(ofSize: 13) == nil else {
return
}
let notification = NSUserNotification()
notification.title = "FontAwesome could not be loaded."
notification.subtitle = "Unfortunately we don't know yet what is causing this."
notification.informativeText = """
We use the FontAwesome font for icons in the tools, e.g. the file browser. Those icons are now shown as ?.
You can track the progress on this issue at GitHub issue 611.
"""
NSUserNotificationCenter.default.deliver(notification)
}
}
private let context: Context
private let emit: (Action) -> Void
private let uiRoot: UiRoot
private var uiRoot: UiRoot?
private var hasDirtyWindows = false
private var hasMainWindows = false
@ -151,9 +164,12 @@ extension AppDelegate {
func applicationDidFinishLaunching(_: Notification) {
self.launching = false
#if DEBUG
#if DEBUG
NSApp.mainMenu?.items.first { $0.identifier == debugMenuItemIdentifier }?.isHidden = false
#endif
// GH-314 FIXME: Remove when finished.
self.showPrefWindow(self)
#endif
}
func applicationOpenUntitledFile(_ sender: NSApplication) -> Bool {
@ -186,7 +202,7 @@ extension AppDelegate {
if alert.runModal() == .alertSecondButtonReturn {
self.updateMainWindowTemplateBeforeQuitting()
self.uiRoot.prepareQuit()
self.uiRoot?.prepareQuit()
return .terminateNow
}
@ -195,7 +211,7 @@ extension AppDelegate {
if self.hasMainWindows {
self.updateMainWindowTemplateBeforeQuitting()
self.uiRoot.prepareQuit()
self.uiRoot?.prepareQuit()
return .terminateNow
}
@ -414,8 +430,6 @@ private enum VimRUrlAction: String {
private let updater = SUUpdater()
private let debugMenuItemIdentifier = NSUserInterfaceItemIdentifier("debug-menu-item")
// Keep in sync with QueryParamKey in the `vimr` Python script.
private let filePrefix = "file="
private let cwdPrefix = "cwd="

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="Application" customModule="VimR" customModuleProvider="target">
@ -73,45 +73,45 @@
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="File" id="bib-Uj-vzu">
<items>
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
<menuItem title="New" keyEquivalent="n" identifier="com.qvacua.vimr.menuitems.file.new" id="Was-JA-tGl">
<connections>
<action selector="newDocument:" target="-1" id="4Si-XN-c54"/>
</connections>
</menuItem>
<menuItem title="New Tab" keyEquivalent="t" id="TX9-92-Oe2">
<menuItem title="New Tab" keyEquivalent="t" identifier="com.qvacua.vimr.menuitems.file.new-tab" id="TX9-92-Oe2">
<connections>
<action selector="newTab:" target="-1" id="RfK-C0-Bu9"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="t9v-Ee-SaA"/>
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
<menuItem title="Open…" keyEquivalent="o" identifier="com.qvacua.vimr.menuitems.file.open" id="IAo-SY-fd9">
<connections>
<action selector="openDocument:" target="-1" id="zbe-h0-oBM"/>
</connections>
</menuItem>
<menuItem title="Open In New Window…" keyEquivalent="o" id="c6W-bD-wRy">
<menuItem title="Open In New Window…" keyEquivalent="o" identifier="com.qvacua.vimr.menuitems.file.open-in-new-window" id="c6W-bD-wRy">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="openInNewWindow:" target="-1" id="2ZC-Rl-rjR"/>
</connections>
</menuItem>
<menuItem title="Open Quickly…" keyEquivalent="O" id="0V2-yi-P2z">
<menuItem title="Open Quickly…" keyEquivalent="O" identifier="com.qvacua.vimr.menuitems.file.open-quickly" id="0V2-yi-P2z">
<connections>
<action selector="openQuickly:" target="-1" id="FSA-7W-F0m"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="Lje-kE-tCa"/>
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
<menuItem title="Close" keyEquivalent="w" identifier="com.qvacua.vimr.menuitems.file.close" id="DVo-aG-piG">
<connections>
<action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/>
</connections>
</menuItem>
<menuItem title="Save..." keyEquivalent="s" id="Pgi-pt-dWC">
<menuItem title="Save..." keyEquivalent="s" identifier="com.qvacua.vimr.menuitems.file.save" id="Pgi-pt-dWC">
<connections>
<action selector="saveDocument:" target="-1" id="Qhz-Mg-Anr"/>
</connections>
</menuItem>
<menuItem title="Save As…" keyEquivalent="S" id="01H-3e-ZCV">
<menuItem title="Save As…" keyEquivalent="S" identifier="com.qvacua.vimr.menuitems.file.save-as" id="01H-3e-ZCV">
<connections>
<action selector="saveDocumentAs:" target="-1" id="2iM-rb-3fJ"/>
</connections>
@ -123,39 +123,39 @@
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<menuItem title="Undo" keyEquivalent="z" identifier="com.qvacua.vimr.menuitems.edit.undo" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<menuItem title="Redo" keyEquivalent="Z" identifier="com.qvacua.vimr.menuitems.edit.redo" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<menuItem title="Cut" keyEquivalent="x" identifier="com.qvacua.vimr.menuitems.edit.cut" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<menuItem title="Copy" keyEquivalent="c" identifier="com.qvacua.vimr.menuitems.edit.copy" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<menuItem title="Paste" keyEquivalent="v" identifier="com.qvacua.vimr.menuitems.edit.paste" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<menuItem title="Delete" identifier="com.qvacua.vimr.menuitems.edit.delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<menuItem title="Select All" keyEquivalent="a" identifier="com.qvacua.vimr.menuitems.edit.select-all" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections>
@ -171,17 +171,17 @@
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Font" systemMenu="font" id="Wj0-kR-IJp">
<items>
<menuItem title="Reset To Default Size" keyEquivalent="0" id="dmv-1c-kFU">
<menuItem title="Reset To Default Size" keyEquivalent="0" identifier="com.qvacua.vimr.menuitems.view.font.reset-to-default-size" id="dmv-1c-kFU">
<connections>
<action selector="resetFontSize:" target="-1" id="8Rb-Wd-iZH"/>
</connections>
</menuItem>
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="FIs-h6-uga">
<menuItem title="Bigger" tag="3" keyEquivalent="+" identifier="com.qvacua.vimr.menuitems.view.font.bigger" id="FIs-h6-uga">
<connections>
<action selector="makeFontBigger:" target="-1" id="FVE-Cp-LhT"/>
</connections>
</menuItem>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="BHh-O4-8m0">
<menuItem title="Smaller" tag="4" keyEquivalent="-" identifier="com.qvacua.vimr.menuitems.view.font.smaller" id="BHh-O4-8m0">
<connections>
<action selector="makeFontSmaller:" target="-1" id="nqo-sN-9tq"/>
</connections>
@ -190,7 +190,7 @@
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="NXP-NG-aHV"/>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="Co5-Y0-sqo">
<menuItem title="Enter Full Screen" keyEquivalent="f" identifier="com.qvacua.vimr.menuitems.view.enter-full-screen" id="Co5-Y0-sqo">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleFullScreen:" target="-1" id="b4d-vv-b5h"/>
@ -203,25 +203,25 @@
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Tools" id="7MO-P5-uU3">
<items>
<menuItem title="Toggle All Tools" keyEquivalent="\" id="Lb6-TZ-LgL">
<menuItem title="Toggle All Tools" keyEquivalent="\" identifier="com.qvacua.vimr.menuitems.tools.toggle-all-tools" id="Lb6-TZ-LgL">
<connections>
<action selector="toggleAllTools:" target="-1" id="V97-0e-bES"/>
</connections>
</menuItem>
<menuItem title="Toggle Tool Buttons" keyEquivalent="\" id="oK0-ZG-w1f">
<menuItem title="Toggle Tool Buttons" keyEquivalent="\" identifier="com.qvacua.vimr.menuitems.tools.toggle-tool-buttons" id="oK0-ZG-w1f">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="toggleToolButtons:" target="-1" id="bxj-O1-Vo9"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="UAq-9D-Jex"/>
<menuItem title="Toggle File Browser" keyEquivalent="1" id="PWx-V8-0cQ">
<menuItem title="Toggle File Browser" keyEquivalent="1" identifier="com.qvacua.vimr.menuitems.tools.toggle-file-browser" id="PWx-V8-0cQ">
<connections>
<action selector="toggleFileBrowser:" target="-1" id="Ggq-4w-iN7"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="XHW-5e-Vad"/>
<menuItem title="Focus Neovim View" keyEquivalent="." id="TtL-Gg-pCj">
<menuItem title="Focus Neovim View" keyEquivalent="." identifier="com.qvacua.vimr.menuitems.tools.focus-neovim-view" id="TtL-Gg-pCj">
<connections>
<action selector="focusNvimView:" target="-1" id="obY-Kb-RxK"/>
</connections>
@ -233,19 +233,19 @@
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<menuItem title="Minimize" keyEquivalent="m" identifier="com.qvacua.vimr.menuitems.window.minimize" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<menuItem title="Zoom" identifier="com.qvacua.vimr.menuitems.window.zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<menuItem title="Bring All to Front" identifier="com.qvacua.vimr.menuitems.window.bring-all-to-front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
@ -276,7 +276,7 @@
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items>
<menuItem title="VimR Help" keyEquivalent="?" id="FKE-Sm-Kum">
<menuItem title="VimR Help" keyEquivalent="?" identifier="com.qvacua.vimr.menuitems.help.vimr-help" id="FKE-Sm-Kum">
<connections>
<action selector="showHelp:" target="-1" id="y7X-2Q-9no"/>
</connections>

View File

@ -30,6 +30,7 @@ class PrefWindow: NSObject,
ToolsPref(source: source, emitter: emitter, state: state),
AppearancePref(source: source, emitter: emitter, state: state),
KeysPref(source: source, emitter: emitter, state: state),
ShortcutsPref(source: source, emitter: emitter, state: state),
AdvancedPref(source: source, emitter: emitter, state: state),
]
@ -119,6 +120,11 @@ class PrefWindow: NSObject,
paneContainer.autoPinEdge(.left, to: .right, of: categoryScrollView)
self.currentPane = self.panes[0]
// GH-314 FIXME: Remove when finished.
#if DEBUG
self.categoryView.selectRowIndexes(IndexSet(integer: 4), byExtendingSelection: false)
#endif
}
}

View File

@ -0,0 +1,46 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
class ShortcutItem: NSObject, Comparable {
static func <(lhs: ShortcutItem, rhs: ShortcutItem) -> Bool {
return lhs.title < rhs.title
}
@objc dynamic var title: String
@objc dynamic var isLeaf: Bool
@objc dynamic var childrenCount: Int {
return self.children?.count ?? -1
}
var isContainer: Bool {
return !self.isLeaf
}
override var description: String {
return "<ShortcutItem: \(title), " +
"id: '\(self.item?.identifier?.rawValue ?? "")', " +
"isLeaf: \(self.isLeaf), " +
"childrenCount: \(self.children?.count ?? -1)" +
">"
}
let item: NSMenuItem?
@objc dynamic var children: [ShortcutItem]?
init(
title: String,
isLeaf: Bool,
item: NSMenuItem?
) {
self.title = title
self.isLeaf = isLeaf
self.item = item
self.children = isLeaf ? nil : []
}
}

View File

@ -0,0 +1,223 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
import PureLayout
import RxSwift
class DummyItem {
let isGroup: Bool
let text: String
init(_ text: String, _ isGroup: Bool) {
self.isGroup = isGroup
self.text = text
}
}
class ShortcutsPref: PrefPane,
UiComponent,
NSOutlineViewDelegate {
typealias StateType = AppState
enum Action {
case dummy
}
@objc dynamic var content = [ShortcutItem]()
override var displayName: String {
return "Shortcuts"
}
override var pinToContainer: Bool {
return true
}
required init(
source: Observable<StateType>,
emitter: ActionEmitter,
state: StateType
) {
self.emit = emitter.typedEmit()
super.init(frame: .zero)
self.addViews()
self.updateViews()
self.initShortcutItems()
if let children = self.shortcutItemsRoot.children {
self.content.append(contentsOf: children)
}
source
.observeOn(MainScheduler.instance)
.subscribe(onNext: { state in
})
.disposed(by: self.disposeBag)
initBindings()
self.shortcutList.expandItem(nil, expandChildren: true)
}
private let emit: (Action) -> Void
private let disposeBag = DisposeBag()
private let shortcutList = NSOutlineView.standardOutlineView()
private let shortcutScrollView = NSScrollView.standardScrollView()
private let treeController = NSTreeController()
private let shortcutItemsRoot = ShortcutItem(
title: "root", isLeaf: false, item: nil
)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func initBindings() {
self.treeController.childrenKeyPath = "children"
self.treeController.leafKeyPath = "isLeaf"
self.treeController.countKeyPath = "childrenCount"
self.treeController.objectClass = ShortcutItem.self
self.treeController.avoidsEmptySelection = false
self.treeController.preservesSelection = true
self.treeController.sortDescriptors = [
NSSortDescriptor(key: "title", ascending: true)
]
self.treeController.bind(.contentArray, to: self, withKeyPath: "content")
self.shortcutList.bind(.content,
to: self.treeController,
withKeyPath: "arrangedObjects")
self.shortcutList.bind(.selectionIndexPaths,
to: self.treeController,
withKeyPath: "selectionIndexPaths")
}
private func initShortcutItems() {
guard let mainMenu = NSApplication.shared.mainMenu else { return }
let firstLevel = mainMenu.items
.suffix(from: 1)
.filter { $0.identifier != debugMenuItemIdentifier }
var queue = firstLevel.map {
(
parent: self.shortcutItemsRoot,
shortcutItem: ShortcutItem(title: $0.title, isLeaf: false, item: $0)
)
}
while (!queue.isEmpty) {
guard let entry = queue.popLast() else { break }
if !entry.shortcutItem.isLeaf
|| entry.shortcutItem.item?
.identifier?
.rawValue
.hasPrefix("com.qvacua.vimr.menuitems.") == true {
entry.parent.children?.append(entry.shortcutItem)
}
if entry.shortcutItem.isContainer,
let childMenuItems = entry.shortcutItem.item?.submenu?.items {
let shortcutChildItems = childMenuItems
.filter { !$0.title.isEmpty }
.map { menuItem in
(
parent: entry.shortcutItem,
shortcutItem: ShortcutItem(title: menuItem.title,
isLeaf: !menuItem.hasSubmenu,
item: menuItem)
)
}
queue.append(contentsOf: shortcutChildItems)
}
}
}
private func updateViews() {
}
private func addViews() {
let paneTitle = self.paneTitleTextField(title: "Shortcuts")
let shortcutList = self.shortcutList
shortcutList.delegate = self
let shortcutScrollView = self.shortcutScrollView
shortcutScrollView.documentView = shortcutList
self.addSubview(paneTitle)
self.addSubview(shortcutScrollView)
paneTitle.autoPinEdge(toSuperviewEdge: .top, withInset: 18)
paneTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
paneTitle.autoPinEdge(
toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual
)
shortcutScrollView.autoPinEdge(
.top, to: .bottom, of: paneTitle, withOffset: 18
)
shortcutScrollView.autoPinEdge(.left, to: .left, of: paneTitle)
shortcutScrollView.autoPinEdge(toSuperviewEdge: .right, withInset: 18)
shortcutScrollView.autoPinEdge(toSuperviewEdge: .bottom, withInset: 18)
}
}
// MARK: - Actions
extension ShortcutsPref {
@objc func isLeftOptionMetaAction(_ sender: NSButton) {
self.emit(.dummy)
}
}
// MARK: - NSOutlineViewDelegate
extension ShortcutsPref {
func outlineView(
_ outlineView: NSOutlineView,
rowViewForItem item: Any
) -> NSTableRowView? {
let view = self.shortcutList.makeView(
withIdentifier: NSUserInterfaceItemIdentifier("shortcut-row-view"),
owner: self
) as? ShortcutTableRow
?? ShortcutTableRow(withIdentifier: "shortcut-row-view")
return view
}
func outlineView(
_: NSOutlineView,
viewFor tableColumn: NSTableColumn?,
item: Any
) -> NSView? {
let cellView = self.shortcutList.makeView(
withIdentifier: NSUserInterfaceItemIdentifier("shortcut-cell-view"),
owner: self
) as? ShortcutTableCell
?? ShortcutTableCell(withIdentifier: "shortcut-cell-view")
let repObj = (item as? NSTreeNode)?.representedObject
guard let item = repObj as? ShortcutItem else {
return nil
}
cellView.text = item.title
return cellView
}
func outlineView(_: NSOutlineView, heightOfRowByItem item: Any) -> CGFloat {
return 24
}
}

View File

@ -0,0 +1,87 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
class ShortcutTableRow: NSTableRowView {
init(withIdentifier identifier: String) {
super.init(frame: .zero)
self.identifier = NSUserInterfaceItemIdentifier(identifier)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class ShortcutTableCell: NSTableCellView {
static let font = NSFont.systemFont(ofSize: 13)
var isDir = false
var attributedText: NSAttributedString {
get {
return self.textField!.attributedStringValue
}
set {
self.textField?.attributedStringValue = newValue
self.addTextField()
}
}
var text: String {
get {
return self.textField!.stringValue
}
set {
self.textField?.stringValue = newValue
self.addTextField()
}
}
init(withIdentifier identifier: String) {
super.init(frame: .zero)
self.identifier = NSUserInterfaceItemIdentifier(identifier)
self.textField = self._textField
let textField = self._textField
textField.font = ShortcutTableCell.font
textField.isBordered = false
textField.isBezeled = false
textField.allowsEditingTextAttributes = false
textField.isEditable = false
textField.usesSingleLineMode = true
textField.drawsBackground = false
}
func reset() -> ShortcutTableCell {
self.text = ""
self.removeAllSubviews()
return self
}
private func addTextField() {
let textField = self._textField
textField.removeFromSuperview()
self.addSubview(textField)
textField.autoPinEdgesToSuperviewEdges(
with: NSEdgeInsets(top: 2, left: 4, bottom: 2, right: 2)
)
}
private let _textField = NSTextField(forAutoLayout: ())
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}