From c2cc6a0600cf51aeb536736315829b3f53b201b6 Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Thu, 28 Feb 2019 12:44:23 +0100 Subject: [PATCH 01/17] Add actions and enums --- VimR/VimR/Base.lproj/MainMenu.xib | 15 +++++++++++++++ VimR/VimR/MainWindow+Actions.swift | 12 ++++++++++++ VimR/VimR/MainWindow.swift | 4 +++- VimR/VimR/PreviewTool.swift | 2 +- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/VimR/VimR/Base.lproj/MainMenu.xib b/VimR/VimR/Base.lproj/MainMenu.xib index a38c959b..a0eed151 100644 --- a/VimR/VimR/Base.lproj/MainMenu.xib +++ b/VimR/VimR/Base.lproj/MainMenu.xib @@ -220,6 +220,21 @@ + + + + + + + + + + + + + + + diff --git a/VimR/VimR/MainWindow+Actions.swift b/VimR/VimR/MainWindow+Actions.swift index 6e2909a7..06a119f1 100644 --- a/VimR/VimR/MainWindow+Actions.swift +++ b/VimR/VimR/MainWindow+Actions.swift @@ -140,6 +140,18 @@ extension MainWindow { self.emit(self.uuidAction(for: .focus(.fileBrowser))) } + @IBAction func toggleBufferList(_ sender: Any?) { + + } + + @IBAction func toggleMarkdownPreview(_ sender: Any?) { + + } + + @IBAction func toggleHtmlPreview(_ sender: Any?) { + + } + @IBAction func focusNvimView(_: Any?) { // self.window.makeFirstResponder(self.neoVimView) self.emit(self.uuidAction(for: .focus(.neoVimView))) diff --git a/VimR/VimR/MainWindow.swift b/VimR/VimR/MainWindow.swift index 365c4e39..0589bd3b 100644 --- a/VimR/VimR/MainWindow.swift +++ b/VimR/VimR/MainWindow.swift @@ -49,7 +49,9 @@ class MainWindow: NSObject, case neoVimView case fileBrowser - case preview + case bufferList + case markdownPreview + case htmlPreview } enum Tools: String, Codable { diff --git a/VimR/VimR/PreviewTool.swift b/VimR/VimR/PreviewTool.swift index 0f7c8cbe..f02be862 100644 --- a/VimR/VimR/PreviewTool.swift +++ b/VimR/VimR/PreviewTool.swift @@ -80,7 +80,7 @@ class PreviewTool: NSView, UiComponent, WKNavigationDelegate { source .observeOn(MainScheduler.instance) .subscribe(onNext: { state in - if state.viewToBeFocused != nil, case .preview = state.viewToBeFocused! { + if state.viewToBeFocused != nil, case .markdownPreview = state.viewToBeFocused! { self.beFirstResponder() } From 5bc983a1543793ce4e7e9b8f418465efe86de182 Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Thu, 28 Feb 2019 12:47:58 +0100 Subject: [PATCH 02/17] Reformat --- VimR/VimR/MainWindow.swift | 113 +++++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 35 deletions(-) diff --git a/VimR/VimR/MainWindow.swift b/VimR/VimR/MainWindow.swift index 0589bd3b..cd1c658a 100644 --- a/VimR/VimR/MainWindow.swift +++ b/VimR/VimR/MainWindow.swift @@ -56,7 +56,14 @@ class MainWindow: NSObject, enum Tools: String, Codable { - static let all = Set([Tools.fileBrowser, Tools.buffersList, Tools.preview, Tools.htmlPreview]) + static let all = Set( + [ + Tools.fileBrowser, + Tools.buffersList, + Tools.preview, + Tools.htmlPreview + ] + ) case fileBrowser = "com.qvacua.vimr.tools.file-browser" case buffersList = "com.qvacua.vimr.tools.opened-files-list" @@ -104,18 +111,26 @@ class MainWindow: NSObject, var isClosing = false let cliPipePath: String? - required init(source: Observable, emitter: ActionEmitter, state: StateType) { + required init( + source: Observable, + emitter: ActionEmitter, + state: StateType + ) { self.emit = emitter.typedEmit() self.uuid = state.uuid self.cliPipePath = state.cliPipePath - self.windowController = NSWindowController(windowNibName: NSNib.Name("MainWindow")) + self.windowController = NSWindowController( + windowNibName: NSNib.Name("MainWindow") + ) - let neoVimViewConfig = NvimView.Config(useInteractiveZsh: state.useInteractiveZsh, - cwd: state.cwd, - nvimArgs: state.nvimArgs, - envDict: state.envDict) + let neoVimViewConfig = NvimView.Config( + useInteractiveZsh: state.useInteractiveZsh, + cwd: state.cwd, + nvimArgs: state.nvimArgs, + envDict: state.envDict + ) self.neoVimView = NvimView(frame: .zero, config: neoVimViewConfig) self.neoVimView.configureForAutoLayout() @@ -124,9 +139,11 @@ class MainWindow: NSObject, var tools: [Tools: WorkspaceTool] = [:] if state.activeTools[.preview] == true { self.preview = PreviewTool(source: source, emitter: emitter, state: state) - let previewConfig = WorkspaceTool.Config(title: "Markdown", - view: self.preview!, - customMenuItems: self.preview!.menuItems) + let previewConfig = WorkspaceTool.Config( + title: "Markdown", + view: self.preview!, + customMenuItems: self.preview!.menuItems + ) self.previewContainer = WorkspaceTool(previewConfig) self.previewContainer!.dimension = state.tools[.preview]?.dimension ?? 250 tools[.preview] = self.previewContainer @@ -134,30 +151,43 @@ class MainWindow: NSObject, if state.activeTools[.htmlPreview] == true { self.htmlPreview = HtmlPreviewTool(source: source, emitter: emitter, state: state) - let htmlPreviewConfig = WorkspaceTool.Config(title: "HTML", - view: self.htmlPreview!, - customToolbar: self.htmlPreview!.innerCustomToolbar) + let htmlPreviewConfig = WorkspaceTool.Config( + title: "HTML", + view: self.htmlPreview!, + customToolbar: self.htmlPreview!.innerCustomToolbar + ) self.htmlPreviewContainer = WorkspaceTool(htmlPreviewConfig) self.htmlPreviewContainer!.dimension = state.tools[.htmlPreview]?.dimension ?? 250 tools[.htmlPreview] = self.htmlPreviewContainer } if state.activeTools[.fileBrowser] == true { - self.fileBrowser = FileBrowser(source: source, emitter: emitter, state: state) - let fileBrowserConfig = WorkspaceTool.Config(title: "Files", - view: self.fileBrowser!, - customToolbar: self.fileBrowser!.innerCustomToolbar, - customMenuItems: self.fileBrowser!.menuItems) + self.fileBrowser = FileBrowser( + source: source, emitter: emitter, state: state + ) + let fileBrowserConfig = WorkspaceTool.Config( + title: "Files", + view: self.fileBrowser!, + customToolbar: self.fileBrowser!.innerCustomToolbar, + customMenuItems: self.fileBrowser!.menuItems + ) self.fileBrowserContainer = WorkspaceTool(fileBrowserConfig) - self.fileBrowserContainer!.dimension = state.tools[.fileBrowser]?.dimension ?? 200 + self.fileBrowserContainer!.dimension = state + .tools[.fileBrowser]? + .dimension ?? 200 tools[.fileBrowser] = self.fileBrowserContainer } if state.activeTools[.buffersList] == true { - self.buffersList = BuffersList(source: source, emitter: emitter, state: state) - let buffersListConfig = WorkspaceTool.Config(title: "Buffers", view: self.buffersList!) + self.buffersList = BuffersList( + source: source, emitter: emitter, state: state + ) + let buffersListConfig = WorkspaceTool.Config(title: "Buffers", + view: self.buffersList!) self.buffersListContainer = WorkspaceTool(buffersListConfig) - self.buffersListContainer!.dimension = state.tools[.buffersList]?.dimension ?? 200 + self.buffersListContainer!.dimension = state + .tools[.buffersList]? + .dimension ?? 200 tools[.buffersList] = self.buffersListContainer } @@ -183,7 +213,8 @@ class MainWindow: NSObject, return } - self.workspace.append(tool: tool, location: state.tools[toolId]?.location ?? .left) + self.workspace.append(tool: tool, + location: state.tools[toolId]?.location ?? .left) } self.tools.forEach { (toolId, toolContainer) in @@ -205,7 +236,9 @@ class MainWindow: NSObject, self.addViews() - self.neoVimView.trackpadScrollResistance = CGFloat(state.trackpadScrollResistance) + self.neoVimView.trackpadScrollResistance = CGFloat( + state.trackpadScrollResistance + ) self.neoVimView.usesLiveResize = state.useLiveResize self.updateNeoVimAppearance() @@ -231,7 +264,8 @@ class MainWindow: NSObject, case .newCurrentBuffer(let curBuf): self.newCurrentBuffer(curBuf) case .bufferWritten(let buf): self.bufferWritten(buf) case .colorschemeChanged(let theme): self.colorschemeChanged(to: theme) - case .ipcBecameInvalid(let reason): self.ipcBecameInvalid(reason: reason) + case .ipcBecameInvalid(let reason): + self.ipcBecameInvalid(reason: reason) case .scroll: self.scroll() case .cursor(let position): self.cursor(to: position) case .initVimError: self.showInitError() @@ -253,7 +287,8 @@ class MainWindow: NSObject, return } - if state.viewToBeFocused != nil, case .neoVimView = state.viewToBeFocused! { + if state.viewToBeFocused != nil, + case .neoVimView = state.viewToBeFocused! { self.window.makeFirstResponder(self.neoVimView) } @@ -271,7 +306,9 @@ class MainWindow: NSObject, && state.preview.previewPosition.hasDifferentMark(as: self.previewPosition) { self.previewPosition = state.preview.previewPosition - return self.neoVimView.cursorGo(to: state.preview.previewPosition.payload) + return self.neoVimView.cursorGo( + to: state.preview.previewPosition.payload + ) } return .empty() @@ -305,10 +342,13 @@ class MainWindow: NSObject, } _ = changeTheme( - themePrefChanged: themePrefChanged, themeChanged: themeChanged, usesTheme: usesTheme, + themePrefChanged: themePrefChanged, + themeChanged: themeChanged, + usesTheme: usesTheme, forTheme: { self.themeTitlebar(grow: !self.titlebarThemed) - self.window.backgroundColor = state.appearance.theme.payload.background.brightening(by: 0.9) + self.window.backgroundColor = state.appearance + .theme.payload.background.brightening(by: 0.9) self.set(workspaceThemeWith: state.appearance.theme.payload) self.lastThemeMark = state.appearance.theme.mark @@ -447,8 +487,10 @@ class MainWindow: NSObject, case .default: return self.neoVimView.open(urls: [url]) case .currentTab: return self.neoVimView.openInCurrentTab(url: url) case .newTab: return self.neoVimView.openInNewTab(urls: [url]) - case .horizontalSplit: return self.neoVimView.openInHorizontalSplit(urls: [url]) - case .verticalSplit: return self.neoVimView.openInVerticalSplit(urls: [url]) + case .horizontalSplit: + return self.neoVimView.openInHorizontalSplit(urls: [url]) + case .verticalSplit: + return self.neoVimView.openInVerticalSplit(urls: [url]) } } ) @@ -462,10 +504,11 @@ class MainWindow: NSObject, private func showInitError() { let notification = NSUserNotification() notification.title = "Error during initialization" - notification.informativeText = """ - There was an error during the initialization of NeoVim. - Use :messages to view the error messages. - """ + notification + .informativeText = """ + There was an error during the initialization of NeoVim. + Use :messages to view the error messages. + """ NSUserNotificationCenter.default.deliver(notification) } From ef180ede03845b109c71fc41bf92bba46c5b5b50 Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Thu, 28 Feb 2019 13:00:13 +0100 Subject: [PATCH 03/17] Add key shortcuts --- VimR/VimR/Base.lproj/MainMenu.xib | 9 ++--- VimR/VimR/BufferList.swift | 5 +++ VimR/VimR/DefaultShortcuts.swift | 18 ++++++++++ VimR/VimR/HtmlPreviewTool.swift | 5 +++ VimR/VimR/MainWindow+Actions.swift | 53 ++++++++++++++++-------------- VimR/VimR/PreviewTool.swift | 3 +- 6 files changed, 64 insertions(+), 29 deletions(-) diff --git a/VimR/VimR/Base.lproj/MainMenu.xib b/VimR/VimR/Base.lproj/MainMenu.xib index a0eed151..1c69ad33 100644 --- a/VimR/VimR/Base.lproj/MainMenu.xib +++ b/VimR/VimR/Base.lproj/MainMenu.xib @@ -220,17 +220,17 @@ - + - + - + @@ -279,7 +279,8 @@ - + + diff --git a/VimR/VimR/BufferList.swift b/VimR/VimR/BufferList.swift index 174ad412..206a1c4b 100644 --- a/VimR/VimR/BufferList.swift +++ b/VimR/VimR/BufferList.swift @@ -48,6 +48,11 @@ class BuffersList: NSView, source .observeOn(MainScheduler.instance) .subscribe(onNext: { state in + if state.viewToBeFocused != nil, + case .bufferList = state.viewToBeFocused! { + self.beFirstResponder() + } + let themeChanged = changeTheme( themePrefChanged: state.appearance.usesTheme != self.usesTheme, themeChanged: state.appearance.theme.mark != self.lastThemeMark, diff --git a/VimR/VimR/DefaultShortcuts.swift b/VimR/VimR/DefaultShortcuts.swift index d151a640..0c2645d3 100644 --- a/VimR/VimR/DefaultShortcuts.swift +++ b/VimR/VimR/DefaultShortcuts.swift @@ -111,6 +111,24 @@ let defaultShortcuts: [String: [String: Any]] = [ SRShortcutKeyCode: 18, SRShortcutModifierFlagsKey: 1048840, ], + "com.qvacua.vimr.menuitems.tools.toggle-buffer-list": [ + SRShortcutCharacters: "1", + SRShortcutCharactersIgnoringModifiers: "2", + SRShortcutKeyCode: 19, + SRShortcutModifierFlagsKey: 1048840, + ], + "com.qvacua.vimr.menuitems.tools.toggle-markdown-preview": [ + SRShortcutCharacters: "1", + SRShortcutCharactersIgnoringModifiers: "3", + SRShortcutKeyCode: 20, + SRShortcutModifierFlagsKey: 1048840, + ], + "com.qvacua.vimr.menuitems.tools.toggle-html-preview": [ + SRShortcutCharacters: "1", + SRShortcutCharactersIgnoringModifiers: "4", + SRShortcutKeyCode: 21, + SRShortcutModifierFlagsKey: 1048840, + ], "com.qvacua.vimr.menuitems.tools.toggle-tool-buttons": [ SRShortcutCharacters: "\\", SRShortcutCharactersIgnoringModifiers: "|", diff --git a/VimR/VimR/HtmlPreviewTool.swift b/VimR/VimR/HtmlPreviewTool.swift index dab02215..ef1319ed 100644 --- a/VimR/VimR/HtmlPreviewTool.swift +++ b/VimR/VimR/HtmlPreviewTool.swift @@ -45,6 +45,11 @@ class HtmlPreviewTool: NSView, UiComponent, WKNavigationDelegate { source .observeOn(MainScheduler.instance) .subscribe(onNext: { [unowned self] state in + if state.viewToBeFocused != nil, + case .htmlPreview = state.viewToBeFocused! { + self.beFirstResponder() + } + guard let serverUrl = state.htmlPreview.server, let htmlFileUrl = state.htmlPreview.htmlFile else { self.monitor = nil return diff --git a/VimR/VimR/MainWindow+Actions.swift b/VimR/VimR/MainWindow+Actions.swift index 06a119f1..81c68d19 100644 --- a/VimR/VimR/MainWindow+Actions.swift +++ b/VimR/VimR/MainWindow+Actions.swift @@ -123,38 +123,43 @@ extension MainWindow { } @IBAction func toggleFileBrowser(_ sender: Any?) { - let fileBrowser = self.fileBrowserContainer + guard let fileBrowser = self.fileBrowserContainer else { return } + self.toggle(tool: fileBrowser, toolType: .fileBrowser) + } - if fileBrowser?.isSelected == true { - if fileBrowser?.view.isFirstResponder == true { - fileBrowser?.toggle() + @IBAction func toggleBufferList(_ sender: Any?) { + guard let bufferList = self.buffersListContainer else { return } + self.toggle(tool: bufferList, toolType: .bufferList) + } + + @IBAction func toggleMarkdownPreview(_ sender: Any?) { + guard let markdownPreview = self.previewContainer else { return } + self.toggle(tool: markdownPreview, toolType: .markdownPreview) + } + + @IBAction func toggleHtmlPreview(_ sender: Any?) { + guard let htmlPreview = self.htmlPreviewContainer else { return } + self.toggle(tool: htmlPreview, toolType: .htmlPreview) + } + + @IBAction func focusNvimView(_: Any?) { + self.emit(self.uuidAction(for: .focus(.neoVimView))) + } + + private func toggle(tool: WorkspaceTool, toolType: FocusableView) { + if tool.isSelected == true { + if tool.view.isFirstResponder == true { + tool.toggle() self.focusNvimView(self) } else { - self.emit(self.uuidAction(for: .focus(.fileBrowser))) + self.emit(self.uuidAction(for: .focus(toolType))) } return } - fileBrowser?.toggle() - self.emit(self.uuidAction(for: .focus(.fileBrowser))) - } - - @IBAction func toggleBufferList(_ sender: Any?) { - - } - - @IBAction func toggleMarkdownPreview(_ sender: Any?) { - - } - - @IBAction func toggleHtmlPreview(_ sender: Any?) { - - } - - @IBAction func focusNvimView(_: Any?) { -// self.window.makeFirstResponder(self.neoVimView) - self.emit(self.uuidAction(for: .focus(.neoVimView))) + tool.toggle() + self.emit(self.uuidAction(for: .focus(toolType))) } } diff --git a/VimR/VimR/PreviewTool.swift b/VimR/VimR/PreviewTool.swift index f02be862..490fcd17 100644 --- a/VimR/VimR/PreviewTool.swift +++ b/VimR/VimR/PreviewTool.swift @@ -80,7 +80,8 @@ class PreviewTool: NSView, UiComponent, WKNavigationDelegate { source .observeOn(MainScheduler.instance) .subscribe(onNext: { state in - if state.viewToBeFocused != nil, case .markdownPreview = state.viewToBeFocused! { + if state.viewToBeFocused != nil, + case .markdownPreview = state.viewToBeFocused! { self.beFirstResponder() } From 7feca99e6b59e14cbf8657cef3207ae07fbcc7a4 Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Thu, 28 Feb 2019 13:01:48 +0100 Subject: [PATCH 04/17] Update release notes --- resources/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/release-notes.md b/resources/release-notes.md index 077bf736..9986a4e3 100644 --- a/resources/release-notes.md +++ b/resources/release-notes.md @@ -1,6 +1,7 @@ # 0.26.0-??? * GH-314: You can customize the key shortcut for all menu items in the *Shortcut* preferences pane. +* GH-501: Add key shortcuts to toggle the Buffer List, Markdown Preview, and HTML Preview tools. * Draw the disclosure triangle in appropriate color of the current color scheme (and improve handling of changes of `cwd` in the file browser). * ... From a78309fc3a026da5f6967ff64a23541c678ecfe9 Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Thu, 28 Feb 2019 16:12:42 +0100 Subject: [PATCH 05/17] Use logger --- NvimView/NvimView/NvimView+Resize.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/NvimView/NvimView/NvimView+Resize.swift b/NvimView/NvimView/NvimView+Resize.swift index f9ae9e01..77d6c494 100644 --- a/NvimView/NvimView/NvimView+Resize.swift +++ b/NvimView/NvimView/NvimView+Resize.swift @@ -68,11 +68,11 @@ extension NvimView { .subscribe(onNext: { msg in switch msg { case let .notification(method, params): - print("NOTIFICATION: \(method) with \(params.count) elements") + logger.debug("NOTIFICATION: \(method) with \(params.count) elements") case let .error(_, msg): - print("MSG ERROR: \(msg)") + logger.debug("MSG ERROR: \(msg)") default: - print("???") + logger.debug("???: This should not happen") break } }, onError: { print("ERROR: \($0)" )}) From 4e50c6c09065d7dfac459690ec6cd2a22a5ccda0 Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Thu, 28 Feb 2019 16:17:35 +0100 Subject: [PATCH 06/17] Reformat --- NvimView/NvimView/NvimView+Resize.swift | 41 +++++++++++++++---------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/NvimView/NvimView/NvimView+Resize.swift b/NvimView/NvimView/NvimView+Resize.swift index 77d6c494..74beacb1 100644 --- a/NvimView/NvimView/NvimView+Resize.swift +++ b/NvimView/NvimView/NvimView+Resize.swift @@ -52,8 +52,12 @@ extension NvimView { return } - self.offset.x = floor((size.width - self.cellSize.width * CGFloat(discreteSize.width)) / 2) - self.offset.y = floor((size.height - self.cellSize.height * CGFloat(discreteSize.height)) / 2) + self.offset.x = floor( + (size.width - self.cellSize.width * CGFloat(discreteSize.width)) / 2 + ) + self.offset.y = floor( + (size.height - self.cellSize.height * CGFloat(discreteSize.height)) / 2 + ) self.bridge .resize(width: discreteSize.width, height: discreteSize.height) @@ -62,24 +66,27 @@ extension NvimView { private func launchNeoVim(_ size: Size) { logger.info("=== Starting neovim...") - let sockPath = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("vimr_\(self.uuid).sock").path + let sockPath = URL( + fileURLWithPath: NSTemporaryDirectory() + ).appendingPathComponent("vimr_\(self.uuid).sock").path self.api.msgpackRawStream - .subscribe(onNext: { msg in - switch msg { - case let .notification(method, params): - logger.debug("NOTIFICATION: \(method) with \(params.count) elements") - case let .error(_, msg): - logger.debug("MSG ERROR: \(msg)") - default: - logger.debug("???: This should not happen") - break - } - }, onError: { print("ERROR: \($0)" )}) - .disposed(by: self.disposeBag) + .subscribe(onNext: { msg in + switch msg { + case let .notification(method, params): + logger.debug("NOTIFICATION: \(method) with \(params.count) elements") + case let .error(_, msg): + logger.debug("MSG ERROR: \(msg)") + default: + logger.debug("???: This should not happen") + break + } + }, onError: { print("ERROR: \($0)") }) + .disposed(by: self.disposeBag) - // We wait here, since the user of NvimView cannot subscribe on the Completable. We could demand that the user - // call launchNeoVim() by themselves, but... + // We wait here, since the user of NvimView cannot subscribe + // on the Completable. We could demand that the user call launchNeoVim() + // by themselves, but... try? self.bridge .runLocalServerAndNvim(width: size.width, height: size.height) .andThen(self.api.run(at: sockPath)) From add17a7933e80674be57fb1daaadc32a304745ea Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Thu, 28 Feb 2019 22:55:45 +0100 Subject: [PATCH 07/17] Add some rpc events. - Fire GUIEnter autocmd when the rpc events subscription is done. --- NvimView/NvimServer/NvimServer.m | 3 + NvimView/NvimServer/server_ui.h | 1 + NvimView/NvimServer/server_ui.m | 6 ++ NvimView/NvimView.xcodeproj/project.pbxproj | 8 +-- NvimView/NvimView/NvimView+Resize.swift | 10 +++- NvimView/NvimView/NvimView+UiBridge.swift | 1 + NvimView/NvimView/NvimView.swift | 57 ++++++++++++++----- NvimView/NvimView/UiBridge.swift | 4 ++ .../{vimr.vim => com.qvacua.NvimView.vim} | 0 NvimView/SharedTypes.h | 1 + NvimView/neovim | 2 +- VimR/VimR.xcodeproj/project.pbxproj | 10 ++++ VimR/VimR/MainWindow+Actions.swift | 48 ++++++++++++++++ VimR/VimR/MainWindow.swift | 11 +++- VimR/VimR/RpcEvents.swift | 15 +++++ VimR/VimR/com.qvacua.VimR.vim | 30 ++++++++++ 16 files changed, 186 insertions(+), 21 deletions(-) rename NvimView/NvimView/{vimr.vim => com.qvacua.NvimView.vim} (100%) create mode 100644 VimR/VimR/RpcEvents.swift create mode 100644 VimR/VimR/com.qvacua.VimR.vim diff --git a/NvimView/NvimServer/NvimServer.m b/NvimView/NvimServer/NvimServer.m index 87d28449..314a254d 100644 --- a/NvimView/NvimServer/NvimServer.m +++ b/NvimView/NvimServer/NvimServer.m @@ -68,6 +68,9 @@ static CFDataRef local_server_callback(CFMessagePortRef local, SInt32 msgid, CFD case NvimBridgeMsgIdFocusGained: return data_async(data, neovim_focus_gained); + case NvimBridgeMsgIdReadyForRpcEvents: + return data_async(data, neovim_ready_for_rpcevents); + default: CFRelease(data); return NULL; diff --git a/NvimView/NvimServer/server_ui.h b/NvimView/NvimServer/server_ui.h index 04739e89..fb3f7bcc 100644 --- a/NvimView/NvimServer/server_ui.h +++ b/NvimView/NvimServer/server_ui.h @@ -19,5 +19,6 @@ extern void neovim_vim_input(void **argv); extern void neovim_delete_and_input(void **argv); extern void neovim_focus_gained(void **argv); +extern void neovim_ready_for_rpcevents(void **argv); extern void neovim_debug1(void **argv); diff --git a/NvimView/NvimServer/server_ui.m b/NvimView/NvimServer/server_ui.m index e2c811ae..23ebeb69 100644 --- a/NvimView/NvimServer/server_ui.m +++ b/NvimView/NvimServer/server_ui.m @@ -747,6 +747,12 @@ void neovim_focus_gained(void **argv) { }); } +void neovim_ready_for_rpcevents(void **argv) { + work_async(argv, ^(NSData *data) { + apply_autocmds(EVENT_GUIENTER, NULL, NULL, false, NULL); + }); +} + void neovim_debug1(void **argv) { work_async(argv, ^(NSData *data) { NSLog(@"normal fg: %#08X", normal_fg); diff --git a/NvimView/NvimView.xcodeproj/project.pbxproj b/NvimView/NvimView.xcodeproj/project.pbxproj index 7a854902..bc111032 100644 --- a/NvimView/NvimView.xcodeproj/project.pbxproj +++ b/NvimView/NvimView.xcodeproj/project.pbxproj @@ -45,7 +45,7 @@ 4B177886201220F300E32FF0 /* SharedTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 1929B4F32708E99C40A57020 /* SharedTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B17E549209E3E4100265C1D /* RxNeovimApi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B17E548209E3E4100265C1D /* RxNeovimApi.framework */; }; 4B21ED53213D4AEC009FD017 /* CocoaCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B0C89838D8402BB80BFC /* CocoaCommons.swift */; }; - 4B8662E81FDC3F9F007F490D /* vimr.vim in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B8662E41FDC3D4F007F490D /* vimr.vim */; }; + 4B8662E81FDC3F9F007F490D /* com.qvacua.NvimView.vim in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B8662E41FDC3D4F007F490D /* com.qvacua.NvimView.vim */; }; 4B90F02E1FD2AFAE008A39E0 /* NvimView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0101FD2AFAC008A39E0 /* NvimView.swift */; }; 4B90F02F1FD2AFAE008A39E0 /* NvimView+Resize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0111FD2AFAC008A39E0 /* NvimView+Resize.swift */; }; 4B90F0301FD2AFAE008A39E0 /* KeyUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0121FD2AFAC008A39E0 /* KeyUtils.swift */; }; @@ -140,7 +140,7 @@ dstPath = runtime/plugin; dstSubfolderSpec = 7; files = ( - 4B8662E81FDC3F9F007F490D /* vimr.vim in CopyFiles */, + 4B8662E81FDC3F9F007F490D /* com.qvacua.NvimView.vim in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -199,7 +199,7 @@ 4B0A1B152129F49500F1E02F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4B0A1B38212B332800F1E02F /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = ../Carthage/Build/Mac/Nimble.framework; sourceTree = ""; }; 4B17E548209E3E4100265C1D /* RxNeovimApi.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxNeovimApi.framework; path = ../Carthage/Build/Mac/RxNeovimApi.framework; sourceTree = ""; }; - 4B8662E41FDC3D4F007F490D /* vimr.vim */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = vimr.vim; sourceTree = ""; }; + 4B8662E41FDC3D4F007F490D /* com.qvacua.NvimView.vim */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.vim; path = com.qvacua.NvimView.vim; sourceTree = ""; }; 4B90F0041FD2AF59008A39E0 /* NvimView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NvimView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4B90F0081FD2AF59008A39E0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4B90F0101FD2AFAC008A39E0 /* NvimView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NvimView.swift; sourceTree = ""; }; @@ -359,7 +359,7 @@ isa = PBXGroup; children = ( 4B90F0081FD2AF59008A39E0 /* Info.plist */, - 4B8662E41FDC3D4F007F490D /* vimr.vim */, + 4B8662E41FDC3D4F007F490D /* com.qvacua.NvimView.vim */, 4BF18C5C1FD2EEE400DF95D1 /* NvimView.h */, 4B90F0121FD2AFAC008A39E0 /* KeyUtils.swift */, 4B90F0271FD2AFAD008A39E0 /* Logger.swift */, diff --git a/NvimView/NvimView/NvimView+Resize.swift b/NvimView/NvimView/NvimView+Resize.swift index 74beacb1..61e912b7 100644 --- a/NvimView/NvimView/NvimView+Resize.swift +++ b/NvimView/NvimView/NvimView+Resize.swift @@ -74,7 +74,9 @@ extension NvimView { .subscribe(onNext: { msg in switch msg { case let .notification(method, params): - logger.debug("NOTIFICATION: \(method) with \(params.count) elements") + logger.debug("NOTIFICATION: \(method): \(params)") + guard self.subscribedEvents.contains(method) else { return } + self.eventsSubject.onNext(.rpcEvent(method, params)) case let .error(_, msg): logger.debug("MSG ERROR: \(msg)") default: @@ -90,6 +92,12 @@ extension NvimView { try? self.bridge .runLocalServerAndNvim(width: size.width, height: size.height) .andThen(self.api.run(at: sockPath)) + .andThen( + self.subscribedEvents.reduce(Completable.empty()) { prev, event in + prev.andThen(self.api.subscribe(event: event)) + } + ) + .andThen(self.bridge.notifyReadinessForRpcEvents()) .wait() } diff --git a/NvimView/NvimView/NvimView+UiBridge.swift b/NvimView/NvimView/NvimView+UiBridge.swift index f2f522a0..6731a6ce 100644 --- a/NvimView/NvimView/NvimView+UiBridge.swift +++ b/NvimView/NvimView/NvimView+UiBridge.swift @@ -132,6 +132,7 @@ extension NvimView { } final func autoCommandEvent(_ value: MessagePackValue) { + logger.debug(value) guard let array = MessagePackUtils.array( from: value, ofSize: 2, conversion: { $0.intValue } ), diff --git a/NvimView/NvimView/NvimView.swift b/NvimView/NvimView/NvimView.swift index d8f3e9fc..b97ccfa8 100644 --- a/NvimView/NvimView/NvimView.swift +++ b/NvimView/NvimView/NvimView.swift @@ -6,10 +6,11 @@ import Cocoa import RxNeovimApi import RxSwift +import MessagePack public class NvimView: NSView, - NSUserInterfaceValidations, - NSTextInputClient { + NSUserInterfaceValidations, + NSTextInputClient { // MARK: - Public public struct Config { @@ -18,16 +19,20 @@ public class NvimView: NSView, var cwd: URL var nvimArgs: [String]? var envDict: [String: String]? + var rpcEvents: [String] - public init(useInteractiveZsh: Bool, - cwd: URL, - nvimArgs: [String]?, - envDict: [String: String]?) { - + public init( + useInteractiveZsh: Bool, + cwd: URL, + nvimArgs: [String]?, + envDict: [String: String]?, + rpcEvents: [String] + ) { self.useInteractiveZsh = useInteractiveZsh self.cwd = cwd self.nvimArgs = nvimArgs self.envDict = envDict + self.rpcEvents = rpcEvents } } @@ -50,6 +55,8 @@ public class NvimView: NSView, case scroll case cursor(Position) + case rpcEvent(String, [MessagePack.MessagePackValue]) + case initVimError // FIXME: maybe do onError()? @@ -95,9 +102,9 @@ public class NvimView: NSView, public var description: String { return "NVV.Theme<" + - "fg: \(self.foreground.hex), bg: \(self.background.hex), " + - "visual-fg: \(self.visualForeground.hex), visual-bg: \(self.visualBackground.hex)" + - ">" + "fg: \(self.foreground.hex), bg: \(self.background.hex), " + + "visual-fg: \(self.visualForeground.hex), visual-bg: \(self.visualBackground.hex)" + + ">" } } @@ -202,6 +209,8 @@ public class NvimView: NSView, self.scheduler = SerialDispatchQueueScheduler(queue: self.queue, internalSerialQueueName: "com.qvacua.NvimView.NvimView") + self.subscribedEvents.formUnion(config.rpcEvents) + super.init(frame: .zero) self.registerForDraggedTypes([NSPasteboard.PasteboardType(String(kUTTypeFileURL))]) @@ -295,11 +304,29 @@ public class NvimView: NSView, .disposed(by: self.disposeBag) } + public func subscribe(to events: [String]) -> Completable { + let result = Set(events) + .subtracting(self.subscribedEvents) + .reduce(Completable.empty()) { prev, event in + prev.andThen(self.api.subscribe(event: event)) + } + + self.subscribedEvents.formUnion(events) + + return result + } + convenience override public init(frame rect: NSRect) { - self.init(frame: rect, config: Config(useInteractiveZsh: false, - cwd: URL(fileURLWithPath: NSHomeDirectory()), - nvimArgs: nil, - envDict: nil)) + self.init( + frame: rect, + config: Config( + useInteractiveZsh: false, + cwd: URL(fileURLWithPath: NSHomeDirectory()), + nvimArgs: nil, + envDict: nil, + rpcEvents: [] + ) + ) } required public init?(coder: NSCoder) { @@ -364,6 +391,8 @@ public class NvimView: NSView, shouldLogDebug: nil ) + var subscribedEvents = Set() + // MARK: - Private private var _linespacing = NvimView.defaultLinespacing } diff --git a/NvimView/NvimView/UiBridge.swift b/NvimView/NvimView/UiBridge.swift index 40737276..31696e54 100644 --- a/NvimView/NvimView/UiBridge.swift +++ b/NvimView/NvimView/UiBridge.swift @@ -125,6 +125,10 @@ class UiBridge { return self.sendMessage(msgId: .resize, data: [width, height].data()) } + func notifyReadinessForRpcEvents() -> Completable { + return self.sendMessage(msgId: .readyForRpcEvents, data: nil) + } + func focusGained(_ gained: Bool) -> Completable { return self.sendMessage(msgId: .focusGained, data: [gained].data()) } diff --git a/NvimView/NvimView/vimr.vim b/NvimView/NvimView/com.qvacua.NvimView.vim similarity index 100% rename from NvimView/NvimView/vimr.vim rename to NvimView/NvimView/com.qvacua.NvimView.vim diff --git a/NvimView/SharedTypes.h b/NvimView/SharedTypes.h index be314a2c..3453448a 100644 --- a/NvimView/SharedTypes.h +++ b/NvimView/SharedTypes.h @@ -47,6 +47,7 @@ typedef NS_ENUM(NSInteger, NvimServerMsgId) { typedef NS_ENUM(NSInteger, NvimBridgeMsgId) { NvimBridgeMsgIdAgentReady = 0, + NvimBridgeMsgIdReadyForRpcEvents, NvimBridgeMsgIdInput, NvimBridgeMsgIdDeleteInput, NvimBridgeMsgIdResize, diff --git a/NvimView/neovim b/NvimView/neovim index ab81a4c3..722d04f7 160000 --- a/NvimView/neovim +++ b/NvimView/neovim @@ -1 +1 @@ -Subproject commit ab81a4c3c6c7dce4fdc02c48c7fcbf20352fa328 +Subproject commit 722d04f7e67679f136ee9e5808aa4b96014ca286 diff --git a/VimR/VimR.xcodeproj/project.pbxproj b/VimR/VimR.xcodeproj/project.pbxproj index c2df9b57..03c06b67 100644 --- a/VimR/VimR.xcodeproj/project.pbxproj +++ b/VimR/VimR.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 1929B0F599D1F62C7BE53D2C /* HttpServerMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B1DC584C89C477E83FA2 /* HttpServerMiddleware.swift */; }; 1929B1837C750CADB3A5BCB9 /* OpenQuicklyFileViewRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B1558455B3A74D93EF2A /* OpenQuicklyFileViewRow.swift */; }; 1929B20CE35B43BB1CE023BA /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BC2F05E9A5C0DB039739 /* Theme.swift */; }; + 1929B250DB3FB395A700FE8C /* RpcEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BBF0944940845485A512 /* RpcEvents.swift */; }; 1929B29B95AD176D57942E08 /* UiRootReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B457B9D0FA4D21F3751E /* UiRootReducer.swift */; }; 1929B2D56C4652E251C23AD4 /* DefaultShortcuts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B93256AF7F9137223E36 /* DefaultShortcuts.swift */; }; 1929B3217A7A3D79E28C80DB /* PrefWindowReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B49E6924847AD085C8C9 /* PrefWindowReducer.swift */; }; @@ -26,6 +27,7 @@ 1929B3AC66EFE35D68C020E3 /* PreviewToolReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BFB0F294F3714D5E095F /* PreviewToolReducer.swift */; }; 1929B3F5743967125F357C9F /* Matcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BEEB33113B0E33C3830F /* Matcher.swift */; }; 1929B462CD4935AFF6D69457 /* FileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B7CB4863F80230C32D3C /* FileItem.swift */; }; + 1929B489A51FD5B13888A00C /* RpcEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BBF0944940845485A512 /* RpcEvents.swift */; }; 1929B4B00D7BB191A9A6532D /* HtmlPreviewToolReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE5AEA3D0980860EED50 /* HtmlPreviewToolReducer.swift */; }; 1929B4B70926DE113E6BF990 /* PreviewReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BE37AA2843779CAFA76F /* PreviewReducer.swift */; }; 1929B4E54E2F13A7F5F2B682 /* BufferListReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B67A10E6BB2986B2416E /* BufferListReducer.swift */; }; @@ -36,6 +38,7 @@ 1929B53876E6952D378C2B30 /* ScoredFileItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDF9EBAF1D9D44399045 /* ScoredFileItem.swift */; }; 1929B542A071BD03C846F6EF /* PrefUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B8241CDE58F7AAF89AE4 /* PrefUtils.swift */; }; 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 */; }; 1929B5A2EE366F79ED32744C /* KeysPrefReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B88B5FA08E897A3C2168 /* KeysPrefReducer.swift */; }; 1929B5C1BABBC0D09D97C3EF /* PreviewMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B617C229B19DB3E987B8 /* PreviewMiddleware.swift */; }; @@ -352,7 +355,9 @@ 1929BB6608B4F0E037CA0F4C /* States.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = States.swift; sourceTree = ""; }; 1929BBC84557C8351EC6183E /* FileItemIgnorePatternTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileItemIgnorePatternTest.swift; sourceTree = ""; }; 1929BBE0A534F2F6009D31BE /* AdvencedPref.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvencedPref.swift; sourceTree = ""; }; + 1929BBF0944940845485A512 /* RpcEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RpcEvents.swift; sourceTree = ""; }; 1929BC2F05E9A5C0DB039739 /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; + 1929BC6D45B7E14D4D75D4E6 /* com.qvacua.VimR.vim */ = {isa = PBXFileReference; lastKnownFileType = file.vim; path = com.qvacua.VimR.vim; sourceTree = ""; }; 1929BCE3E156C06EDF1F2806 /* FileOutlineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileOutlineView.swift; sourceTree = ""; }; 1929BD2CA8DD198A6BCDBCB7 /* ThemedTableSubviews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemedTableSubviews.swift; sourceTree = ""; }; 1929BD4149D5A25C82064DD8 /* UiRoot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UiRoot.swift; sourceTree = ""; }; @@ -817,6 +822,7 @@ 4BEBA50F1CFF374B00673FDF /* Info.plist */, 4B37ADB81D6E471B00970D55 /* vimr */, 4B3AC8931DB031C600AC5823 /* sparkle_pub.pem */, + 1929BC6D45B7E14D4D75D4E6 /* com.qvacua.VimR.vim */, ); name = resources; sourceTree = ""; @@ -878,6 +884,7 @@ 4B97E2CF1D33F92200FC0660 /* resources */, 1929BA652D3B88FC071531EC /* UI */, 1929B66A5E2D00EA143AFD86 /* RxRedux.swift */, + 1929BBF0944940845485A512 /* RpcEvents.swift */, ); path = VimR; sourceTree = ""; @@ -1067,6 +1074,7 @@ 4B9433E620B95EC6005807BA /* MacVim-log.icns in Resources */, 4B94340D20B95EC7005807BA /* MacVim-dtd.icns in Resources */, 4B9433DF20B95EC6005807BA /* MacVim-lisp.icns in Resources */, + 1929B560C6CE264FD1E1F5A3 /* com.qvacua.VimR.vim in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1182,6 +1190,7 @@ 1929BA269EBD68251410A08E /* ShortcutsTableSubviews.swift in Sources */, 1929B2D56C4652E251C23AD4 /* DefaultShortcuts.swift in Sources */, 1929B0C7150100A84FBDB8BF /* ShortcutItem.swift in Sources */, + 1929B250DB3FB395A700FE8C /* RpcEvents.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1216,6 +1225,7 @@ 1929BC682EA78BF50D1E0890 /* ShortcutsTableSubviews.swift in Sources */, 1929B0244BD7111E168726CF /* DefaultShortcuts.swift in Sources */, 1929BDC69A5F9D1661423488 /* ShortcutItem.swift in Sources */, + 1929B489A51FD5B13888A00C /* RpcEvents.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/VimR/VimR/MainWindow+Actions.swift b/VimR/VimR/MainWindow+Actions.swift index 81c68d19..f6ddc47a 100644 --- a/VimR/VimR/MainWindow+Actions.swift +++ b/VimR/VimR/MainWindow+Actions.swift @@ -5,6 +5,54 @@ import Cocoa import RxSwift +import MessagePack + +// MARK: - RpcEvent Actions +extension MainWindow { + + func rpcEventAction(for event: RpcEvent, params: [MessagePackValue]) { + switch event { + case .makeSessionTemporary: + stdoutLog.debug("\(event): \(params)") + + case .maximizeWindow: + guard let screen = self.window.screen else { return } + self.window.setFrame(screen.frame, display: true) + + case .toggleTools: + stdoutLog.debug("\(event): \(params)") + if params.isEmpty { + self.toggleAllTools(self) + return + } + + guard let param = params[0].integerValue else { return } + if param == -1 { + + } else if param == 1 { + + } + + case .toggleToolButtons: + stdoutLog.debug("\(event): \(params)") + if params.isEmpty { + self.workspace.toggleToolButtons() + return + } + + guard let param = params[0].integerValue else { return } + if param == -1 { + + } else if param == 1 { + + } + + case .toggleFullScreen: + self.window.toggleFullScreen(self) + + } + } +} // MARK: - File Menu Item Actions extension MainWindow { diff --git a/VimR/VimR/MainWindow.swift b/VimR/VimR/MainWindow.swift index cd1c658a..35c50a5f 100644 --- a/VimR/VimR/MainWindow.swift +++ b/VimR/VimR/MainWindow.swift @@ -129,7 +129,8 @@ class MainWindow: NSObject, useInteractiveZsh: state.useInteractiveZsh, cwd: state.cwd, nvimArgs: state.nvimArgs, - envDict: state.envDict + envDict: state.envDict, + rpcEvents: RpcEvent.allCases.map { $0.rawValue } ) self.neoVimView = NvimView(frame: .zero, config: neoVimViewConfig) self.neoVimView.configureForAutoLayout() @@ -264,15 +265,23 @@ class MainWindow: NSObject, case .newCurrentBuffer(let curBuf): self.newCurrentBuffer(curBuf) case .bufferWritten(let buf): self.bufferWritten(buf) case .colorschemeChanged(let theme): self.colorschemeChanged(to: theme) + case .ipcBecameInvalid(let reason): self.ipcBecameInvalid(reason: reason) + case .scroll: self.scroll() case .cursor(let position): self.cursor(to: position) case .initVimError: self.showInitError() + case .apiError(let error, let msg): fileLog.error("Got api error with msg '\(msg)' and error: \(error)") break + case .rpcEvent(let method, let params): + guard let event = RpcEvent(rawValue: method) else { break } + stdoutLog.debug(event) + self.rpcEventAction(for: event, params: params) + } }, onError: { error in // FIXME call onError diff --git a/VimR/VimR/RpcEvents.swift b/VimR/VimR/RpcEvents.swift new file mode 100644 index 00000000..19e25f2d --- /dev/null +++ b/VimR/VimR/RpcEvents.swift @@ -0,0 +1,15 @@ +/** + * Tae Won Ha - http://taewon.de - @hataewon + * See LICENSE + */ + +import Foundation + +enum RpcEvent: String, CaseIterable { + + case makeSessionTemporary = "com.qvacua.vimr.rpc-events.make-session-temporary" + case maximizeWindow = "com.qvacua.vimr.rpc-events.maximize-window" + case toggleTools = "com.qvacua.vimr.rpc-events.toggle-tools" + case toggleToolButtons = "com.qvacua.vimr.rpc-events.toggle-tool-buttons" + case toggleFullScreen = "com.qvacua.vimr.rpc-events.toggle-fullscreen" +} diff --git a/VimR/VimR/com.qvacua.VimR.vim b/VimR/VimR/com.qvacua.VimR.vim new file mode 100644 index 00000000..85129001 --- /dev/null +++ b/VimR/VimR/com.qvacua.VimR.vim @@ -0,0 +1,30 @@ +function! s:VimRMakeSessionTemporary() abort + call rpcnotify(0, 'com.qvacua.vimr.rpc-events.make-session-temporary') +endfunction +command! -nargs=0 VimRMakeSessionTemporary call s:VimRMakeSessionTemporary() + +function! s:VimRMaximizeWindow() abort + call rpcnotify(0, 'com.qvacua.vimr.rpc-events.maximize-window') +endfunction +command! -nargs=0 VimRMaximizeWindow call s:VimRMaximizeWindow() + +" -1: hide, 0: toggle, 1: show +function! s:VimRToggleTools(value) abort + call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-tools', a:value) +endfunction +command! -nargs=0 VimRHideTools call s:VimRToggleTools(-1) +command! -nargs=0 VimRToggleTools call s:VimRToggleTools(0) +command! -nargs=0 VimRShowTools call s:VimRToggleTools(1) + +" -1: hide, 0: toggle, 1: show +function! s:VimRToggleToolButtons(value) abort + call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-tool-buttons', a:value) +endfunction +command! -nargs=0 VimRHideToolButtons call s:VimRToggleToolButtons(-1) +command! -nargs=0 VimRToggleToolButtons call s:VimRToggleToolButtons(0) +command! -nargs=0 VimRShowToolButtons call s:VimRToggleToolButtons(1) + +function! s:VimRToggleFullscreen() abort + call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-fullscreen') +endfunction +command! -nargs=0 VimRToggleFullscreen call s:VimRToggleFullscreen() From 16206a2182f6c2641eaa0c43555f3787d74cda1d Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Fri, 1 Mar 2019 14:34:18 +0100 Subject: [PATCH 08/17] Quit the bridge after emitting neoVimStopped event --- NvimView/NvimView/NvimView+UiBridge.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NvimView/NvimView/NvimView+UiBridge.swift b/NvimView/NvimView/NvimView+UiBridge.swift index 6731a6ce..6b1751c1 100644 --- a/NvimView/NvimView/NvimView+UiBridge.swift +++ b/NvimView/NvimView/NvimView+UiBridge.swift @@ -119,7 +119,6 @@ extension NvimView { self.bridgeLogger.hr() try? self.api .stop() - .andThen(self.bridge.quit()) .andThen(Completable.create { completable in self.eventsSubject.onNext(.neoVimStopped) self.eventsSubject.onCompleted() @@ -127,6 +126,7 @@ extension NvimView { completable(.completed) return Disposables.create() }) + .andThen(self.bridge.quit()) .observeOn(MainScheduler.instance) .wait() } From becd58ff97d4fd0d459bda12926736a55e853c48 Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Fri, 1 Mar 2019 14:03:03 +0100 Subject: [PATCH 09/17] Add actions --- VimR/VimR/MainWindow+Actions.swift | 64 ++++++++++++++++++++--------- VimR/VimR/MainWindow.swift | 3 +- VimR/VimR/MainWindowReducer.swift | 3 ++ VimR/VimR/States.swift | 2 + VimR/VimR/UiRootReducer.swift | 25 +++++++++++ VimR/VimR/Workspace/Workspace.swift | 24 +++++++++++ 6 files changed, 101 insertions(+), 20 deletions(-) diff --git a/VimR/VimR/MainWindow+Actions.swift b/VimR/VimR/MainWindow+Actions.swift index f6ddc47a..52b2610b 100644 --- a/VimR/VimR/MainWindow+Actions.swift +++ b/VimR/VimR/MainWindow+Actions.swift @@ -13,38 +13,32 @@ extension MainWindow { func rpcEventAction(for event: RpcEvent, params: [MessagePackValue]) { switch event { case .makeSessionTemporary: - stdoutLog.debug("\(event): \(params)") + self.emit(self.uuidAction(for: .makeSessionTemporary)) case .maximizeWindow: guard let screen = self.window.screen else { return } self.window.setFrame(screen.frame, display: true) case .toggleTools: - stdoutLog.debug("\(event): \(params)") - if params.isEmpty { + let param = params[0].integerValue + + if params.isEmpty || param == 0 { self.toggleAllTools(self) - return - } - - guard let param = params[0].integerValue else { return } - if param == -1 { - + } else if param == -1 { + self.hideAllTools() } else if param == 1 { - + self.showAllTools() } case .toggleToolButtons: - stdoutLog.debug("\(event): \(params)") - if params.isEmpty { - self.workspace.toggleToolButtons() - return - } - - guard let param = params[0].integerValue else { return } - if param == -1 { + let param = params[0].integerValue + if params.isEmpty || param == 0 { + self.toggleToolButtons(self) + } else if param == -1 { + self.hideToolButtons() } else if param == 1 { - + self.showToolButtons() } case .toggleFullScreen: @@ -52,6 +46,38 @@ extension MainWindow { } } + + private func hideToolButtons() { + self.workspace.hideToolButtons() + self.focusNvimView(self) + self.emit(self.uuidAction( + for: .toggleToolButtons(self.workspace.isToolButtonsVisible) + )) + } + + private func showToolButtons() { + self.workspace.showToolButtons() + self.focusNvimView(self) + self.emit(self.uuidAction( + for: .toggleToolButtons(self.workspace.isToolButtonsVisible) + )) + } + + private func hideAllTools() { + self.workspace.hideAllTools() + self.focusNvimView(self) + self.emit(self.uuidAction( + for: .toggleAllTools(self.workspace.isAllToolsVisible) + )) + } + + private func showAllTools() { + self.workspace.showAllTools() + self.focusNvimView(self) + self.emit(self.uuidAction( + for: .toggleAllTools(self.workspace.isAllToolsVisible) + )) + } } // MARK: - File Menu Item Actions diff --git a/VimR/VimR/MainWindow.swift b/VimR/VimR/MainWindow.swift index 35c50a5f..ec292d1a 100644 --- a/VimR/VimR/MainWindow.swift +++ b/VimR/VimR/MainWindow.swift @@ -40,6 +40,8 @@ class MainWindow: NSObject, case setState(for: Tools, with: WorkspaceTool) case setToolsState([(Tools, WorkspaceTool)]) + case makeSessionTemporary + case setTheme(Theme) case close @@ -279,7 +281,6 @@ class MainWindow: NSObject, case .rpcEvent(let method, let params): guard let event = RpcEvent(rawValue: method) else { break } - stdoutLog.debug(event) self.rpcEventAction(for: event, params: params) } diff --git a/VimR/VimR/MainWindowReducer.swift b/VimR/VimR/MainWindowReducer.swift index f3c58635..9216638e 100644 --- a/VimR/VimR/MainWindowReducer.swift +++ b/VimR/VimR/MainWindowReducer.swift @@ -78,6 +78,9 @@ class MainWindowReducer: ReducerType { case let .setTheme(theme): state.appearance.theme = Marked(theme) + case .makeSessionTemporary: + state.isTemporarySession = true + default: return tuple diff --git a/VimR/VimR/States.swift b/VimR/VimR/States.swift index 3c5103e7..34e23f2b 100644 --- a/VimR/VimR/States.swift +++ b/VimR/VimR/States.swift @@ -264,6 +264,8 @@ extension MainWindow { var trackpadScrollResistance = 5.0 var useLiveResize = false + var isTemporarySession = false + // neovim var uuid = UUID().uuidString var currentBuffer: NvimView.Buffer? diff --git a/VimR/VimR/UiRootReducer.swift b/VimR/VimR/UiRootReducer.swift index ef353815..e22b6e9d 100644 --- a/VimR/VimR/UiRootReducer.swift +++ b/VimR/VimR/UiRootReducer.swift @@ -38,6 +38,11 @@ class UiRootReducer: ReducerType { case let .becomeKey(isFullScreen): appState.currentMainWindowUuid = uuid + + if appState.mainWindows[uuid]?.isTemporarySession == true { + break + } + appState.mainWindowTemplate = self.mainWindowTemplate( from: appState.mainWindowTemplate, new: appState.mainWindows[uuid] ?? appState.mainWindowTemplate, @@ -45,20 +50,40 @@ class UiRootReducer: ReducerType { ) case let .frameChanged(to:frame): + if appState.mainWindows[uuid]?.isTemporarySession == true { + break + } + if uuid == appState.currentMainWindowUuid { appState.mainWindowTemplate.frame = frame } case let .setToolsState(tools): + if appState.mainWindows[uuid]?.isTemporarySession == true { + break + } + appState.mainWindowTemplate.orderedTools = tools.map { $0.0 } case let .toggleAllTools(value): + if appState.mainWindows[uuid]?.isTemporarySession == true { + break + } + appState.mainWindowTemplate.isAllToolsVisible = value case let .toggleToolButtons(value): + if appState.mainWindows[uuid]?.isTemporarySession == true { + break + } + appState.mainWindowTemplate.isToolButtonsVisible = value case .close: + if appState.mainWindows[uuid]?.isTemporarySession == true { + break + } + if appState.currentMainWindowUuid == uuid, let mainWindowToClose = appState.mainWindows[uuid] { appState.mainWindowTemplate = self.mainWindowTemplate(from: appState.mainWindowTemplate, new: mainWindowToClose, diff --git a/VimR/VimR/Workspace/Workspace.swift b/VimR/VimR/Workspace/Workspace.swift index 6342e6f5..5125be6f 100644 --- a/VimR/VimR/Workspace/Workspace.swift +++ b/VimR/VimR/Workspace/Workspace.swift @@ -127,10 +127,34 @@ class Workspace: NSView, WorkspaceBarDelegate { self.delegate?.moved(tool: tool) } + func hideAllTools() { + if self.isAllToolsVisible { + self.isAllToolsVisible = false + } + } + + func showAllTools() { + if !self.isAllToolsVisible { + self.isAllToolsVisible = true + } + } + func toggleAllTools() { self.isAllToolsVisible = !self.isAllToolsVisible } + func hideToolButtons() { + if self.isToolButtonsVisible { + self.isToolButtonsVisible = false + } + } + + func showToolButtons() { + if !self.isToolButtonsVisible { + self.isToolButtonsVisible = true + } + } + func toggleToolButtons() { self.isToolButtonsVisible = !self.isToolButtonsVisible } From 1df0d134af33652ab7c3ec8d44abd7d9b66fd46e Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Fri, 1 Mar 2019 20:15:10 +0100 Subject: [PATCH 10/17] Source a custom viml file --- NvimView/NvimView/NvimView+Resize.swift | 5 +++++ NvimView/NvimView/NvimView.swift | 10 ++++++++-- VimR/VimR/MainWindow.swift | 11 ++++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/NvimView/NvimView/NvimView+Resize.swift b/NvimView/NvimView/NvimView+Resize.swift index 61e912b7..9ce34711 100644 --- a/NvimView/NvimView/NvimView+Resize.swift +++ b/NvimView/NvimView/NvimView+Resize.swift @@ -97,6 +97,11 @@ extension NvimView { prev.andThen(self.api.subscribe(event: event)) } ) + .andThen( + self.sourceFileUrls.reduce(Completable.empty()) { prev, url in + prev.andThen(self.api.command(command: "source \(url.path)")) + } + ) .andThen(self.bridge.notifyReadinessForRpcEvents()) .wait() } diff --git a/NvimView/NvimView/NvimView.swift b/NvimView/NvimView/NvimView.swift index b97ccfa8..232bbab2 100644 --- a/NvimView/NvimView/NvimView.swift +++ b/NvimView/NvimView/NvimView.swift @@ -20,19 +20,22 @@ public class NvimView: NSView, var nvimArgs: [String]? var envDict: [String: String]? var rpcEvents: [String] + var sourceFiles: [URL] public init( useInteractiveZsh: Bool, cwd: URL, nvimArgs: [String]?, envDict: [String: String]?, - rpcEvents: [String] + rpcEvents: [String], + sourceFiles: [URL] ) { self.useInteractiveZsh = useInteractiveZsh self.cwd = cwd self.nvimArgs = nvimArgs self.envDict = envDict self.rpcEvents = rpcEvents + self.sourceFiles = sourceFiles } } @@ -210,6 +213,7 @@ public class NvimView: NSView, internalSerialQueueName: "com.qvacua.NvimView.NvimView") self.subscribedEvents.formUnion(config.rpcEvents) + self.sourceFileUrls = config.sourceFiles super.init(frame: .zero) self.registerForDraggedTypes([NSPasteboard.PasteboardType(String(kUTTypeFileURL))]) @@ -324,7 +328,8 @@ public class NvimView: NSView, cwd: URL(fileURLWithPath: NSHomeDirectory()), nvimArgs: nil, envDict: nil, - rpcEvents: [] + rpcEvents: [], + sourceFiles: [] ) ) } @@ -392,6 +397,7 @@ public class NvimView: NSView, ) var subscribedEvents = Set() + let sourceFileUrls: [URL] // MARK: - Private private var _linespacing = NvimView.defaultLinespacing diff --git a/VimR/VimR/MainWindow.swift b/VimR/VimR/MainWindow.swift index ec292d1a..611c8550 100644 --- a/VimR/VimR/MainWindow.swift +++ b/VimR/VimR/MainWindow.swift @@ -127,12 +127,21 @@ class MainWindow: NSObject, windowNibName: NSNib.Name("MainWindow") ) + let sourceFileUrls: [URL] + if let sourceFileUrl = Bundle(for: MainWindow.self) + .url(forResource: "com.qvacua.VimR", withExtension: "vim") { + sourceFileUrls = [sourceFileUrl] + } else { + sourceFileUrls = [] + } + let neoVimViewConfig = NvimView.Config( useInteractiveZsh: state.useInteractiveZsh, cwd: state.cwd, nvimArgs: state.nvimArgs, envDict: state.envDict, - rpcEvents: RpcEvent.allCases.map { $0.rawValue } + rpcEvents: RpcEvent.allCases.map { $0.rawValue }, + sourceFiles: sourceFileUrls ) self.neoVimView = NvimView(frame: .zero, config: neoVimViewConfig) self.neoVimView.configureForAutoLayout() From 9caa84f8c5cf4c3cd84450e4620cb3be681617d7 Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Fri, 1 Mar 2019 20:16:54 +0100 Subject: [PATCH 11/17] Refactor slightly --- NvimView/NvimView/NvimView+Resize.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NvimView/NvimView/NvimView+Resize.swift b/NvimView/NvimView/NvimView+Resize.swift index 9ce34711..489dfd6a 100644 --- a/NvimView/NvimView/NvimView+Resize.swift +++ b/NvimView/NvimView/NvimView+Resize.swift @@ -107,7 +107,7 @@ extension NvimView { } private func randomEmoji() -> String { - let idx = Int(arc4random_uniform(UInt32(emojis.count))) + let idx = Int.random(in: 0.. Date: Fri, 1 Mar 2019 22:47:23 +0100 Subject: [PATCH 12/17] Use UUID instead of String --- NvimView/NvimView/NvimView.swift | 2 +- NvimView/NvimView/UiBridge.swift | 4 ++-- VimR/VimR/AppDelegateReducer.swift | 2 +- VimR/VimR/BufferList.swift | 2 +- VimR/VimR/FileBrowser.swift | 2 +- VimR/VimR/FileOutlineView.swift | 2 +- VimR/VimR/HtmlPreviewTool.swift | 2 +- VimR/VimR/MainWindow.swift | 2 +- VimR/VimR/PreviewMiddleware.swift | 4 ++-- VimR/VimR/PreviewTool.swift | 2 +- VimR/VimR/PreviewUtils.swift | 6 +++--- VimR/VimR/States.swift | 6 +++--- VimR/VimR/Types.swift | 12 ++++++------ VimR/VimR/UiRoot.swift | 6 +++--- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/NvimView/NvimView/NvimView.swift b/NvimView/NvimView/NvimView.swift index d8f3e9fc..d8475ed2 100644 --- a/NvimView/NvimView/NvimView.swift +++ b/NvimView/NvimView/NvimView.swift @@ -112,7 +112,7 @@ public class NvimView: NSView, public var isLeftOptionMeta = false public var isRightOptionMeta = false - public let uuid = UUID().uuidString + public let uuid = UUID() public internal(set) var mode = CursorModeShape.normal diff --git a/NvimView/NvimView/UiBridge.swift b/NvimView/NvimView/UiBridge.swift index 40737276..59fcc961 100644 --- a/NvimView/NvimView/UiBridge.swift +++ b/NvimView/NvimView/UiBridge.swift @@ -51,7 +51,7 @@ class UiBridge { return self.streamSubject.asObservable() } - init(uuid: String, queue: DispatchQueue, config: NvimView.Config) { + init(uuid: UUID, queue: DispatchQueue, config: NvimView.Config) { self.uuid = uuid self.useInteractiveZsh = config.useInteractiveZsh @@ -319,7 +319,7 @@ class UiBridge { private let logger = LogContext.fileLogger(as: UiBridge.self, with: URL(fileURLWithPath: "/tmp/nvv-bridge.log")) - private let uuid: String + private let uuid: UUID private let useInteractiveZsh: Bool private let cwd: URL diff --git a/VimR/VimR/AppDelegateReducer.swift b/VimR/VimR/AppDelegateReducer.swift index b1d734b1..339bb638 100644 --- a/VimR/VimR/AppDelegateReducer.swift +++ b/VimR/VimR/AppDelegateReducer.swift @@ -50,7 +50,7 @@ class AppDelegateReducer: ReducerType { var mainWindow = state.mainWindowTemplate - mainWindow.uuid = UUID().uuidString + mainWindow.uuid = UUID() mainWindow.cwd = config.cwd mainWindow.isDirty = false diff --git a/VimR/VimR/BufferList.swift b/VimR/VimR/BufferList.swift index 206a1c4b..499e4e60 100644 --- a/VimR/VimR/BufferList.swift +++ b/VimR/VimR/BufferList.swift @@ -78,7 +78,7 @@ class BuffersList: NSView, private let emit: (UuidAction) -> Void private let disposeBag = DisposeBag() - private let uuid: String + private let uuid: UUID private var usesTheme: Bool private var showsFileIcon: Bool diff --git a/VimR/VimR/FileBrowser.swift b/VimR/VimR/FileBrowser.swift index 06a474f3..671df4b5 100644 --- a/VimR/VimR/FileBrowser.swift +++ b/VimR/VimR/FileBrowser.swift @@ -67,7 +67,7 @@ class FileBrowser: NSView, private let emit: (UuidAction) -> Void private let disposeBag = DisposeBag() - private let uuid: String + private let uuid: UUID private var currentBufferUrl: URL? diff --git a/VimR/VimR/FileOutlineView.swift b/VimR/VimR/FileOutlineView.swift index 7ce4a34b..c4be8e1a 100644 --- a/VimR/VimR/FileOutlineView.swift +++ b/VimR/VimR/FileOutlineView.swift @@ -130,7 +130,7 @@ class FileOutlineView: NSOutlineView, private let emit: (UuidAction) -> Void private let disposeBag = DisposeBag() - private let uuid: String + private let uuid: UUID private var root: Node private var cwd: URL { diff --git a/VimR/VimR/HtmlPreviewTool.swift b/VimR/VimR/HtmlPreviewTool.swift index ef1319ed..847e8d1c 100644 --- a/VimR/VimR/HtmlPreviewTool.swift +++ b/VimR/VimR/HtmlPreviewTool.swift @@ -92,7 +92,7 @@ class HtmlPreviewTool: NSView, UiComponent, WKNavigationDelegate { } private let emit: (UuidAction) -> Void - private let uuid: String + private let uuid: UUID private var mark = Token() private var scrollTop = 0 diff --git a/VimR/VimR/MainWindow.swift b/VimR/VimR/MainWindow.swift index cd1c658a..e731dbf0 100644 --- a/VimR/VimR/MainWindow.swift +++ b/VimR/VimR/MainWindow.swift @@ -80,7 +80,7 @@ class MainWindow: NSObject, case verticalSplit } - let uuid: String + let uuid: UUID let emit: (UuidAction) -> Void let windowController: NSWindowController diff --git a/VimR/VimR/PreviewMiddleware.swift b/VimR/VimR/PreviewMiddleware.swift index 8eeec5e9..abf4cdad 100644 --- a/VimR/VimR/PreviewMiddleware.swift +++ b/VimR/VimR/PreviewMiddleware.swift @@ -34,7 +34,7 @@ class PreviewMiddleware { self.template = template } - func apply(_ state: MainWindow.State, uuid: String) { + func apply(_ state: MainWindow.State, uuid: UUID) { let preview = state.preview guard let buffer = preview.buffer, let html = preview.html else { guard let previewUrl = self.previewFiles[uuid] else { @@ -80,7 +80,7 @@ class PreviewMiddleware { } private let template: String - private var previewFiles = [String: URL]() + private var previewFiles = [UUID: URL]() } class PreviewToolMiddleware: MiddlewareType { diff --git a/VimR/VimR/PreviewTool.swift b/VimR/VimR/PreviewTool.swift index 490fcd17..291a25b5 100644 --- a/VimR/VimR/PreviewTool.swift +++ b/VimR/VimR/PreviewTool.swift @@ -144,7 +144,7 @@ class PreviewTool: NSView, UiComponent, WKNavigationDelegate { } private let emit: (UuidAction) -> Void - private let uuid: String + private let uuid: UUID private let webview: WKWebView private let disposeBag = DisposeBag() diff --git a/VimR/VimR/PreviewUtils.swift b/VimR/VimR/PreviewUtils.swift index 7fdb54e5..d742d8bb 100644 --- a/VimR/VimR/PreviewUtils.swift +++ b/VimR/VimR/PreviewUtils.swift @@ -40,7 +40,7 @@ class PreviewUtils { } } - static func state(for uuid: String, + static func state(for uuid: UUID, baseUrl: URL, buffer: NvimView.Buffer?, editorPosition: Marked, @@ -72,11 +72,11 @@ class PreviewUtils { previewPosition: previewPosition) } - private static func serverUrl(for uuid: String, baseUrl: URL, lastComponent: String) -> URL { + private static func serverUrl(for uuid: UUID, baseUrl: URL, lastComponent: String) -> URL { return baseUrl.appendingPathComponent("\(uuid)/\(markdownPath)/\(lastComponent)") } - private static func htmlUrl(with uuid: String) -> URL { + private static func htmlUrl(with uuid: UUID) -> URL { return self.tempDir.appendingPathComponent("\(uuid)-markdown-index.html") } diff --git a/VimR/VimR/States.swift b/VimR/VimR/States.swift index 3c5103e7..45e49908 100644 --- a/VimR/VimR/States.swift +++ b/VimR/VimR/States.swift @@ -38,9 +38,9 @@ struct AppState: Codable { var preferencesOpen = Marked(false) var mainWindowTemplate = MainWindow.State.default - var currentMainWindowUuid: String? + var currentMainWindowUuid: UUID? - var mainWindows: [String: MainWindow.State] = [:] + var mainWindows: [UUID: MainWindow.State] = [:] var openQuickly = OpenQuicklyWindow.State.default @@ -265,7 +265,7 @@ extension MainWindow { var useLiveResize = false // neovim - var uuid = UUID().uuidString + var uuid = UUID() var currentBuffer: NvimView.Buffer? var buffers = [NvimView.Buffer]() var cwd = FileUtils.userHomeUrl diff --git a/VimR/VimR/Types.swift b/VimR/VimR/Types.swift index 290e072b..1203a390 100644 --- a/VimR/VimR/Types.swift +++ b/VimR/VimR/Types.swift @@ -15,19 +15,19 @@ struct StateActionPair { protocol UuidTagged { - var uuid: String { get } + var uuid: UUID { get } } class UuidAction: UuidTagged, CustomStringConvertible { - let uuid: String + let uuid: UUID let payload: A var description: String { return "UuidAction(uuid: \(uuid), payload: \(String(reflecting: payload)))" } - init(uuid: String, action: A) { + init(uuid: UUID, action: A) { self.uuid = uuid self.payload = action } @@ -35,14 +35,14 @@ class UuidAction: UuidTagged, CustomStringConvertible { class UuidState: UuidTagged, CustomStringConvertible { - let uuid: String + let uuid: UUID let payload: S var description: String { return "UuidState(uuid: \(uuid), payload: \(String(reflecting: payload)))" } - init(uuid: String, state: S) { + init(uuid: UUID, state: S) { self.uuid = uuid self.payload = state } @@ -127,4 +127,4 @@ class UiComponentTemplate: UiComponent { private let disposeBag = DisposeBag() private let someField: String -} \ No newline at end of file +} diff --git a/VimR/VimR/UiRoot.swift b/VimR/VimR/UiRoot.swift index c80942ab..2f663ff1 100644 --- a/VimR/VimR/UiRoot.swift +++ b/VimR/VimR/UiRoot.swift @@ -79,8 +79,8 @@ class UiRoot: UiComponent { private let openQuicklyWindow: OpenQuicklyWindow private let prefWindow: PrefWindow - private var mainWindows = [String: MainWindow]() - private var subjectForMainWindows = [String: CompletableSubject]() + private var mainWindows = [UUID: MainWindow]() + private var subjectForMainWindows = [UUID: CompletableSubject]() private func newMainWindow(with state: MainWindow.State) -> MainWindow { let subject = self.source.mapOmittingNil { $0.mainWindows[state.uuid] }.completableSubject() @@ -89,7 +89,7 @@ class UiRoot: UiComponent { return MainWindow(source: subject.asObservable(), emitter: self.emitter, state: state) } - private func removeMainWindow(with uuid: String) { + private func removeMainWindow(with uuid: UUID) { self.subjectForMainWindows[uuid]?.onCompleted() self.subjectForMainWindows.removeValue(forKey: uuid) From 0ba13f0a2b5c6fba7d55671685b48e35e10a9205 Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Sat, 2 Mar 2019 18:58:01 +0100 Subject: [PATCH 13/17] Fire GUIEnter when all rpc events subscription is done --- NvimView/NvimServer/server_ui.m | 43 ++++- NvimView/NvimView/Logger.swift | 2 +- .../NvimAutoCommandEvent.generated.swift | 169 +++++++++--------- NvimView/NvimView/NvimView+Draw.swift | 7 + NvimView/NvimView/NvimView+Resize.swift | 13 +- NvimView/NvimView/NvimView+UiBridge.swift | 39 +++- NvimView/NvimView/NvimView.swift | 11 +- NvimView/NvimView/UiBridge.swift | 4 + NvimView/NvimView/com.qvacua.NvimView.vim | 42 +++++ NvimView/SharedTypes.h | 3 +- NvimView/neovim | 2 +- VimR/VimR/Logger.swift | 2 +- VimR/VimR/MainWindow+Actions.swift | 1 + VimR/VimR/MainWindow.swift | 16 +- 14 files changed, 254 insertions(+), 100 deletions(-) diff --git a/NvimView/NvimServer/server_ui.m b/NvimView/NvimServer/server_ui.m index 23ebeb69..1257bc13 100644 --- a/NvimView/NvimServer/server_ui.m +++ b/NvimView/NvimServer/server_ui.m @@ -16,6 +16,7 @@ #define FileInfo CarbonFileInfo #define Boolean CarbonBoolean +#import #import #import #import @@ -73,6 +74,8 @@ static NSInteger _initialHeight = 15; static msgpack_sbuffer flush_sbuffer; static msgpack_packer *flush_packer; +static dispatch_queue_t rpc_queue; + #pragma mark Helper functions static inline String vim_string_from(NSString *str) { @@ -245,6 +248,8 @@ static void server_ui_main(UIBridgeData *bridge, UI *ui) { msgpack_sbuffer_init(&flush_sbuffer); flush_packer = msgpack_packer_new(&flush_sbuffer, msgpack_sbuffer_write); + rpc_queue = dispatch_queue_create("rpc_queu", NULL); + Loop loop; loop_init(&loop, NULL); @@ -553,6 +558,21 @@ void custom_ui_start(void) { ui_bridge_attach(ui, server_ui_main, server_ui_scheduler); } +static int rpc_event_counter = 0; + +void custom_ui_rpcevent_subscribed() { + dispatch_async(rpc_queue, ^{ + rpc_event_counter++; + + ELOG("counter: %d", rpc_event_counter); + send_msg_packing( + NvimServerMsgIdRpcEventSubscribed, + ^(msgpack_packer *packer) { + msgpack_pack_int(packer, rpc_event_counter); + }); + }); +} + void custom_ui_autocmds_groups( event_T event, char_u *fname __unused, @@ -573,6 +593,8 @@ void custom_ui_autocmds_groups( case EVENT_TABENTER: case EVENT_TEXTCHANGED: case EVENT_TEXTCHANGEDI: + case EVENT_VIMENTER: + case EVENT_GUIENTER: break; default: @@ -739,6 +761,25 @@ void neovim_delete_and_input(void **argv) { }); } +static void do_autocmd_guienter() { + static bool recursive = false; + + if (recursive) { + return; // disallow recursion + } + recursive = true; + apply_autocmds(EVENT_GUIENTER, NULL, NULL, false, curbuf); + recursive = false; +} + +static void guienter_event(void **argv __unused) { + do_autocmd_guienter(); +} + +static void aucmd_schedule_guienter() { + loop_schedule_deferred(&main_loop, event_create(guienter_event, 0)); +} + void neovim_focus_gained(void **argv) { work_async(argv, ^(NSData *data) { const bool *values = data.bytes; @@ -749,7 +790,7 @@ void neovim_focus_gained(void **argv) { void neovim_ready_for_rpcevents(void **argv) { work_async(argv, ^(NSData *data) { - apply_autocmds(EVENT_GUIENTER, NULL, NULL, false, NULL); + aucmd_schedule_guienter(); }); } diff --git a/NvimView/NvimView/Logger.swift b/NvimView/NvimView/Logger.swift index 78008a74..6451f83b 100644 --- a/NvimView/NvimView/Logger.swift +++ b/NvimView/NvimView/Logger.swift @@ -86,7 +86,7 @@ class Logger { default: self.name = String(describing: name) } - self.logDateFormatter.dateFormat = "dd HH:mm:SSS" + self.logDateFormatter.dateFormat = "dd HH:mm:ss.SSS" self.appender = appender } diff --git a/NvimView/NvimView/NvimAutoCommandEvent.generated.swift b/NvimView/NvimView/NvimAutoCommandEvent.generated.swift index 69cf1101..2d7d5438 100644 --- a/NvimView/NvimView/NvimAutoCommandEvent.generated.swift +++ b/NvimView/NvimView/NvimAutoCommandEvent.generated.swift @@ -1,4 +1,4 @@ -// Auto generated for nvim v0.3.2-dev. +// Auto generated for nvim v0.3.4. // See bin/generate_autocmds.py enum NvimAutoCommandEvent: Int { @@ -21,86 +21,89 @@ enum NvimAutoCommandEvent: Int { case bufwritecmd = 16 case bufwritepost = 17 case bufwritepre = 18 - case chanopen = 19 - case chaninfo = 20 - case cmdlineenter = 21 - case cmdlineleave = 22 - case cmdundefined = 23 - case cmdwinenter = 24 - case cmdwinleave = 25 - case colorscheme = 26 - case completedone = 27 - case cursorhold = 28 - case cursorholdi = 29 - case cursormoved = 30 - case cursormovedi = 31 - case dirchanged = 32 - case encodingchanged = 33 - case exitpre = 34 - case fileappendcmd = 35 - case fileappendpost = 36 - case fileappendpre = 37 - case filechangedro = 38 - case filechangedshell = 39 - case filechangedshellpost = 40 - case filereadcmd = 41 - case filereadpost = 42 - case filereadpre = 43 - case filetype = 44 - case filewritecmd = 45 - case filewritepost = 46 - case filewritepre = 47 - case filterreadpost = 48 - case filterreadpre = 49 - case filterwritepost = 50 - case filterwritepre = 51 - case focusgained = 52 - case focuslost = 53 - case funcundefined = 54 - case guienter = 55 - case guifailed = 56 - case insertchange = 57 - case insertcharpre = 58 - case insertenter = 59 - case insertleave = 60 - case jobactivity = 61 - case menupopup = 62 - case optionset = 63 - case quickfixcmdpost = 64 - case quickfixcmdpre = 65 - case quitpre = 66 - case remotereply = 67 - case sessionloadpost = 68 - case shellcmdpost = 69 - case shellfilterpost = 70 - case sourcecmd = 71 - case sourcepre = 72 - case spellfilemissing = 73 - case stdinreadpost = 74 - case stdinreadpre = 75 - case swapexists = 76 - case syntax = 77 - case tabclosed = 78 - case tabenter = 79 - case tableave = 80 - case tabnew = 81 - case tabnewentered = 82 - case termchanged = 83 - case termclose = 84 - case termopen = 85 - case termresponse = 86 - case textchanged = 87 - case textchangedi = 88 - case textchangedp = 89 - case textyankpost = 90 - case user = 91 - case vimenter = 92 - case vimleave = 93 - case vimleavepre = 94 - case vimresized = 95 - case vimresume = 96 - case vimsuspend = 97 - case winnew = 98 - case winenter = 99 - case winleave = 100 + case chaninfo = 19 + case chanopen = 20 + case cmdlinechanged = 21 + case cmdlineenter = 22 + case cmdlineleave = 23 + case cmdundefined = 24 + case cmdwinenter = 25 + case cmdwinleave = 26 + case colorscheme = 27 + case colorschemepre = 28 + case completedone = 29 + case cursorhold = 30 + case cursorholdi = 31 + case cursormoved = 32 + case cursormovedi = 33 + case diffupdated = 34 + case dirchanged = 35 + case encodingchanged = 36 + case exitpre = 37 + case fileappendcmd = 38 + case fileappendpost = 39 + case fileappendpre = 40 + case filechangedro = 41 + case filechangedshell = 42 + case filechangedshellpost = 43 + case filereadcmd = 44 + case filereadpost = 45 + case filereadpre = 46 + case filetype = 47 + case filewritecmd = 48 + case filewritepost = 49 + case filewritepre = 50 + case filterreadpost = 51 + case filterreadpre = 52 + case filterwritepost = 53 + case filterwritepre = 54 + case focusgained = 55 + case focuslost = 56 + case funcundefined = 57 + case guienter = 58 + case guifailed = 59 + case insertchange = 60 + case insertcharpre = 61 + case insertenter = 62 + case insertleave = 63 + case jobactivity = 64 + case menupopup = 65 + case optionset = 66 + case quickfixcmdpost = 67 + case quickfixcmdpre = 68 + case quitpre = 69 + case remotereply = 70 + case sessionloadpost = 71 + case shellcmdpost = 72 + case shellfilterpost = 73 + case sourcecmd = 74 + case sourcepre = 75 + case spellfilemissing = 76 + case stdinreadpost = 77 + case stdinreadpre = 78 + case swapexists = 79 + case syntax = 80 + case tabclosed = 81 + case tabenter = 82 + case tableave = 83 + case tabnew = 84 + case tabnewentered = 85 + case termchanged = 86 + case termclose = 87 + case termopen = 88 + case termresponse = 89 + case textchanged = 90 + case textchangedi = 91 + case textchangedp = 92 + case textyankpost = 93 + case user = 94 + case vimenter = 95 + case vimleave = 96 + case vimleavepre = 97 + case vimresized = 98 + case vimresume = 99 + case vimsuspend = 100 + case winenter = 101 + case winleave = 102 + case winnew = 103 } diff --git a/NvimView/NvimView/NvimView+Draw.swift b/NvimView/NvimView/NvimView+Draw.swift index 31ad1037..eecffa81 100644 --- a/NvimView/NvimView/NvimView+Draw.swift +++ b/NvimView/NvimView/NvimView+Draw.swift @@ -88,6 +88,13 @@ extension NvimView { } let cursorRegion = self.cursorRegion(for: self.ugrid.cursorPosition) + if cursorRegion.top < 0 + || cursorRegion.bottom > self.ugrid.size.height - 1 + || cursorRegion.left < 0 + || cursorRegion.right > self.ugrid.size.width - 1 { + logger.error("\(cursorRegion) vs. \(self.ugrid.size)") + return + } guard let cursorAttrs = self.cellAttributesCollection.attributes( of: self.ugrid.cells[cursorPosition.row][cursorPosition.column].attrId )?.reversed else { diff --git a/NvimView/NvimView/NvimView+Resize.swift b/NvimView/NvimView/NvimView+Resize.swift index 489dfd6a..990a8d4d 100644 --- a/NvimView/NvimView/NvimView+Resize.swift +++ b/NvimView/NvimView/NvimView+Resize.swift @@ -92,17 +92,18 @@ extension NvimView { try? self.bridge .runLocalServerAndNvim(width: size.width, height: size.height) .andThen(self.api.run(at: sockPath)) + .andThen( + self.sourceFileUrls.reduce(Completable.empty()) { prev, url in + prev.andThen(self.api + .commandOutput(str: "source \(url.path)") + .asCompletable()) + } + ) .andThen( self.subscribedEvents.reduce(Completable.empty()) { prev, event in prev.andThen(self.api.subscribe(event: event)) } ) - .andThen( - self.sourceFileUrls.reduce(Completable.empty()) { prev, url in - prev.andThen(self.api.command(command: "source \(url.path)")) - } - ) - .andThen(self.bridge.notifyReadinessForRpcEvents()) .wait() } diff --git a/NvimView/NvimView/NvimView+UiBridge.swift b/NvimView/NvimView/NvimView+UiBridge.swift index 6b1751c1..6e447256 100644 --- a/NvimView/NvimView/NvimView+UiBridge.swift +++ b/NvimView/NvimView/NvimView+UiBridge.swift @@ -132,7 +132,6 @@ extension NvimView { } final func autoCommandEvent(_ value: MessagePackValue) { - logger.debug(value) guard let array = MessagePackUtils.array( from: value, ofSize: 2, conversion: { $0.intValue } ), @@ -142,6 +141,32 @@ extension NvimView { } let bufferHandle = array[1] + + logger.debug("aucmd: \(event)") + if event == .vimenter { + Completable + .empty() + .observeOn(SerialDispatchQueueScheduler(qos: .userInitiated)) + .andThen( + Completable.create { completable in + self.rpcSubscribedCondition.lock() + defer { self.rpcSubscribedCondition.unlock() } + + while !self.rpcEventsSubscribed + && self.rpcSubscribedCondition + .wait(until: Date(timeIntervalSinceNow: 5)) {} + + completable(.completed) + return Disposables.create() + } + ) + .andThen(self.bridge.notifyReadinessForRpcEvents()) + .subscribe(onCompleted: {}) + .disposed(by: self.disposeBag) + + return + } + #if TRACE self.bridgeLogger.trace("\(event) -> \(bufferHandle)") #endif @@ -365,6 +390,18 @@ extension NvimView { self.eventsSubject.onNext(.setDirtyStatus(dirty)) } + final func rpcEventSubscribed() { + self.subscribedEventCount += 1 + if self.subscribedEvents.count == self.subscribedEventCount { + self.rpcSubscribedCondition.lock() + defer { self.rpcSubscribedCondition.unlock() } + self.rpcEventsSubscribed = true + self.rpcSubscribedCondition.broadcast() + + self.eventsSubject.onNext(.rpcEventSubscribed) + } + } + final func setAttr(with value: MessagePackValue) { guard let array = value.arrayValue else { return } guard array.count == 6 else { return } diff --git a/NvimView/NvimView/NvimView.swift b/NvimView/NvimView/NvimView.swift index 232bbab2..3756289d 100644 --- a/NvimView/NvimView/NvimView.swift +++ b/NvimView/NvimView/NvimView.swift @@ -59,6 +59,7 @@ public class NvimView: NSView, case cursor(Position) case rpcEvent(String, [MessagePack.MessagePackValue]) + case rpcEventSubscribed case initVimError @@ -298,6 +299,10 @@ public class NvimView: NSView, case let .highlightAttrs(value): self.setAttr(with: value) + case .rpcEventSubscribed: + self.rpcEventSubscribed() + + case .debug1: self.debug1(self) @@ -396,9 +401,13 @@ public class NvimView: NSView, shouldLogDebug: nil ) - var subscribedEvents = Set() let sourceFileUrls: [URL] + var subscribedEvents = Set() + var subscribedEventCount = 0 + let rpcSubscribedCondition = NSCondition() + var rpcEventsSubscribed = false + // MARK: - Private private var _linespacing = NvimView.defaultLinespacing } diff --git a/NvimView/NvimView/UiBridge.swift b/NvimView/NvimView/UiBridge.swift index 31696e54..39fe3d5e 100644 --- a/NvimView/NvimView/UiBridge.swift +++ b/NvimView/NvimView/UiBridge.swift @@ -35,6 +35,7 @@ class UiBridge { case defaultColorsChanged(MessagePackValue) case autoCommandEvent(MessagePackValue) case highlightAttrs(MessagePackValue) + case rpcEventSubscribed case debug1 case unknown } @@ -253,6 +254,9 @@ class UiBridge { guard let v = MessagePackUtils.value(from: data) else { return } self.streamSubject.onNext(.highlightAttrs(v)) + case .rpcEventSubscribed: + self.streamSubject.onNext(.rpcEventSubscribed) + } } diff --git a/NvimView/NvimView/com.qvacua.NvimView.vim b/NvimView/NvimView/com.qvacua.NvimView.vim index 69002294..1f1b847e 100644 --- a/NvimView/NvimView/com.qvacua.NvimView.vim +++ b/NvimView/NvimView/com.qvacua.NvimView.vim @@ -1,3 +1,45 @@ set termguicolors set mouse=a set title + +"function! s:VimRMakeSessionTemporary() abort +" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.make-session-temporary') +"endfunction +"command! -nargs=0 VimRMakeSessionTemporary call s:VimRMakeSessionTemporary() +" +"function! s:VimRMaximizeWindow() abort +" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.maximize-window') +"endfunction +"command! -nargs=0 VimRMaximizeWindow call s:VimRMaximizeWindow() +" +"" -1: hide, 0: toggle, 1: show +"function! s:VimRToggleTools(value) abort +" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-tools', a:value) +"endfunction +"command! -nargs=0 VimRHideTools call s:VimRToggleTools(-1) +"command! -nargs=0 VimRToggleTools call s:VimRToggleTools(0) +"command! -nargs=0 VimRShowTools call s:VimRToggleTools(1) +" +"" -1: hide, 0: toggle, 1: show +"function! s:VimRToggleToolButtons(value) abort +" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-tool-buttons', a:value) +"endfunction +"command! -nargs=0 VimRHideToolButtons call s:VimRToggleToolButtons(-1) +"command! -nargs=0 VimRToggleToolButtons call s:VimRToggleToolButtons(0) +"command! -nargs=0 VimRShowToolButtons call s:VimRToggleToolButtons(1) +" +"function! s:VimRToggleFullscreen() abort +" call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-fullscreen') +"endfunction +"command! -nargs=0 VimRToggleFullscreen call s:VimRToggleFullscreen() +" +"function! s:VimRTest() abort +" VimRMakeSessionTemporary +" VimRHideTools +" VimRMaximizeWindow +" normal o +"endfunction +"command! -nargs=0 VimRTest call s:VimRTest() +" +""au VimEnter * echo "hello" +""au GuiEnter * echo "world" diff --git a/NvimView/SharedTypes.h b/NvimView/SharedTypes.h index 3453448a..3beae944 100644 --- a/NvimView/SharedTypes.h +++ b/NvimView/SharedTypes.h @@ -41,7 +41,8 @@ typedef NS_ENUM(NSInteger, NvimServerMsgId) { NvimServerMsgIdColorSchemeChanged, NvimServerMsgIdDefaultColorsChanged, NvimServerMsgIdAutoCommandEvent, - + NvimServerMsgIdRpcEventSubscribed, + NvimServerMsgIdDebug1, }; diff --git a/NvimView/neovim b/NvimView/neovim index 722d04f7..57d2679d 160000 --- a/NvimView/neovim +++ b/NvimView/neovim @@ -1 +1 @@ -Subproject commit 722d04f7e67679f136ee9e5808aa4b96014ca286 +Subproject commit 57d2679d048678210fd19db6b197afc4385c4ded diff --git a/VimR/VimR/Logger.swift b/VimR/VimR/Logger.swift index 09ce61c0..1bc65ffe 100644 --- a/VimR/VimR/Logger.swift +++ b/VimR/VimR/Logger.swift @@ -80,7 +80,7 @@ class Logger { default: self.name = String(describing: name) } - self.logDateFormatter.dateFormat = "dd HH:mm:SSS" + self.logDateFormatter.dateFormat = "dd HH:mm:ss.SSS" self.appender = appender } diff --git a/VimR/VimR/MainWindow+Actions.swift b/VimR/VimR/MainWindow+Actions.swift index 52b2610b..8a4265e6 100644 --- a/VimR/VimR/MainWindow+Actions.swift +++ b/VimR/VimR/MainWindow+Actions.swift @@ -11,6 +11,7 @@ import MessagePack extension MainWindow { func rpcEventAction(for event: RpcEvent, params: [MessagePackValue]) { + stdoutLog.debug("\(event)") switch event { case .makeSessionTemporary: self.emit(self.uuidAction(for: .makeSessionTemporary)) diff --git a/VimR/VimR/MainWindow.swift b/VimR/VimR/MainWindow.swift index 611c8550..964cb6a7 100644 --- a/VimR/VimR/MainWindow.swift +++ b/VimR/VimR/MainWindow.swift @@ -127,12 +127,17 @@ class MainWindow: NSObject, windowNibName: NSNib.Name("MainWindow") ) - let sourceFileUrls: [URL] + var sourceFileUrls = [URL]() if let sourceFileUrl = Bundle(for: MainWindow.self) .url(forResource: "com.qvacua.VimR", withExtension: "vim") { - sourceFileUrls = [sourceFileUrl] - } else { - sourceFileUrls = [] + sourceFileUrls.append(sourceFileUrl) + } + + let ginitUrl = URL(fileURLWithPath: NSHomeDirectory()) + .appendingPathComponent(".config/nvim/ginit.vim") + let loadGinit = FileManager.default.fileExists(atPath: ginitUrl.path) + if loadGinit { + sourceFileUrls.append(ginitUrl) } let neoVimViewConfig = NvimView.Config( @@ -292,6 +297,9 @@ class MainWindow: NSObject, guard let event = RpcEvent(rawValue: method) else { break } self.rpcEventAction(for: event, params: params) + case .rpcEventSubscribed: + break + } }, onError: { error in // FIXME call onError From fc5110f3088a12509473b0e013361dd592fa7617 Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Sun, 3 Mar 2019 18:05:48 +0100 Subject: [PATCH 14/17] Load ginit.vim after subscription --- NvimView/NvimView/NvimView+UiBridge.swift | 24 +++++++++++++++++------ VimR/VimR/MainWindow.swift | 7 ------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/NvimView/NvimView/NvimView+UiBridge.swift b/NvimView/NvimView/NvimView+UiBridge.swift index 6e447256..c022cac1 100644 --- a/NvimView/NvimView/NvimView+UiBridge.swift +++ b/NvimView/NvimView/NvimView+UiBridge.swift @@ -160,6 +160,18 @@ extension NvimView { return Disposables.create() } ) + .andThen( + { + let ginitPath = URL(fileURLWithPath: NSHomeDirectory()) + .appendingPathComponent(".config/nvim/ginit.vim").path + let loadGinit = FileManager.default.fileExists(atPath: ginitPath) + if loadGinit { + return self.api.command(command: "source \(ginitPath)") + } else { + return .empty() + } + }() + ) .andThen(self.bridge.notifyReadinessForRpcEvents()) .subscribe(onCompleted: {}) .disposed(by: self.disposeBag) @@ -226,8 +238,8 @@ extension NvimView { #if TRACE self.bridgeLogger.trace( "row: \(row), startCol: \(startCol), endCol: \(endCol), " + - "clearCol: \(clearCol), clearAttr: \(clearAttr), " + - "chunk: \(chunk), attrIds: \(attrIds)" + "clearCol: \(clearCol), clearAttr: \(clearAttr), " + + "chunk: \(chunk), attrIds: \(attrIds)" ) #endif @@ -268,13 +280,13 @@ extension NvimView { } if row == self.markedPosition.row - && startCol <= self.markedPosition.column - && self.markedPosition.column <= endCol { + && startCol <= self.markedPosition.column + && self.markedPosition.column <= endCol { self.ugrid.markCell(at: self.markedPosition) } let oldRowContainsWideChar = self.ugrid.cells[row][startCol.. Date: Sun, 3 Mar 2019 18:39:48 +0100 Subject: [PATCH 15/17] Use only one rpc event --- NvimView/NvimServer/server_ui.m | 12 ++-------- NvimView/NvimView/NvimView+Resize.swift | 13 ++++++----- NvimView/NvimView/NvimView+UiBridge.swift | 27 ++++++++++------------- NvimView/NvimView/NvimView.swift | 25 ++++----------------- NvimView/neovim | 2 +- VimR/VimR/MainWindow+Actions.swift | 18 +++++++++++++-- VimR/VimR/MainWindow.swift | 4 +--- VimR/VimR/RpcEvents.swift | 2 ++ VimR/VimR/com.qvacua.VimR.vim | 10 ++++----- 9 files changed, 50 insertions(+), 63 deletions(-) diff --git a/NvimView/NvimServer/server_ui.m b/NvimView/NvimServer/server_ui.m index 1257bc13..f9d40fe6 100644 --- a/NvimView/NvimServer/server_ui.m +++ b/NvimView/NvimServer/server_ui.m @@ -558,18 +558,10 @@ void custom_ui_start(void) { ui_bridge_attach(ui, server_ui_main, server_ui_scheduler); } -static int rpc_event_counter = 0; - void custom_ui_rpcevent_subscribed() { dispatch_async(rpc_queue, ^{ - rpc_event_counter++; - - ELOG("counter: %d", rpc_event_counter); - send_msg_packing( - NvimServerMsgIdRpcEventSubscribed, - ^(msgpack_packer *packer) { - msgpack_pack_int(packer, rpc_event_counter); - }); + [_neovim_server sendMessageWithId:NvimServerMsgIdRpcEventSubscribed + data:NULL]; }); } diff --git a/NvimView/NvimView/NvimView+Resize.swift b/NvimView/NvimView/NvimView+Resize.swift index 990a8d4d..4a365dde 100644 --- a/NvimView/NvimView/NvimView+Resize.swift +++ b/NvimView/NvimView/NvimView+Resize.swift @@ -73,15 +73,20 @@ extension NvimView { self.api.msgpackRawStream .subscribe(onNext: { msg in switch msg { + case let .notification(method, params): logger.debug("NOTIFICATION: \(method): \(params)") - guard self.subscribedEvents.contains(method) else { return } + + guard method == NvimView.rpcEventName else { return } self.eventsSubject.onNext(.rpcEvent(method, params)) + case let .error(_, msg): logger.debug("MSG ERROR: \(msg)") + default: logger.debug("???: This should not happen") break + } }, onError: { print("ERROR: \($0)") }) .disposed(by: self.disposeBag) @@ -99,11 +104,7 @@ extension NvimView { .asCompletable()) } ) - .andThen( - self.subscribedEvents.reduce(Completable.empty()) { prev, event in - prev.andThen(self.api.subscribe(event: event)) - } - ) + .andThen(self.api.subscribe(event: NvimView.rpcEventName)) .wait() } diff --git a/NvimView/NvimView/NvimView+UiBridge.swift b/NvimView/NvimView/NvimView+UiBridge.swift index c022cac1..caef27a4 100644 --- a/NvimView/NvimView/NvimView+UiBridge.swift +++ b/NvimView/NvimView/NvimView+UiBridge.swift @@ -141,19 +141,17 @@ extension NvimView { } let bufferHandle = array[1] - - logger.debug("aucmd: \(event)") if event == .vimenter { Completable .empty() .observeOn(SerialDispatchQueueScheduler(qos: .userInitiated)) .andThen( Completable.create { completable in - self.rpcSubscribedCondition.lock() - defer { self.rpcSubscribedCondition.unlock() } + self.rpcEventSubscribedCondition.lock() + defer { self.rpcEventSubscribedCondition.unlock() } - while !self.rpcEventsSubscribed - && self.rpcSubscribedCondition + while !self.rpcEventSubscribedFlag + && self.rpcEventSubscribedCondition .wait(until: Date(timeIntervalSinceNow: 5)) {} completable(.completed) @@ -173,7 +171,9 @@ extension NvimView { }() ) .andThen(self.bridge.notifyReadinessForRpcEvents()) - .subscribe(onCompleted: {}) + .subscribe(onCompleted: { + logger.debug("GUIEnter aucmd fired") + }) .disposed(by: self.disposeBag) return @@ -403,15 +403,12 @@ extension NvimView { } final func rpcEventSubscribed() { - self.subscribedEventCount += 1 - if self.subscribedEvents.count == self.subscribedEventCount { - self.rpcSubscribedCondition.lock() - defer { self.rpcSubscribedCondition.unlock() } - self.rpcEventsSubscribed = true - self.rpcSubscribedCondition.broadcast() + self.rpcEventSubscribedCondition.lock() + defer { self.rpcEventSubscribedCondition.unlock() } + self.rpcEventSubscribedFlag = true + self.rpcEventSubscribedCondition.broadcast() - self.eventsSubject.onNext(.rpcEventSubscribed) - } + self.eventsSubject.onNext(.rpcEventSubscribed) } final func setAttr(with value: MessagePackValue) { diff --git a/NvimView/NvimView/NvimView.swift b/NvimView/NvimView/NvimView.swift index 3756289d..cee3fe52 100644 --- a/NvimView/NvimView/NvimView.swift +++ b/NvimView/NvimView/NvimView.swift @@ -19,7 +19,6 @@ public class NvimView: NSView, var cwd: URL var nvimArgs: [String]? var envDict: [String: String]? - var rpcEvents: [String] var sourceFiles: [URL] public init( @@ -27,14 +26,12 @@ public class NvimView: NSView, cwd: URL, nvimArgs: [String]?, envDict: [String: String]?, - rpcEvents: [String], sourceFiles: [URL] ) { self.useInteractiveZsh = useInteractiveZsh self.cwd = cwd self.nvimArgs = nvimArgs self.envDict = envDict - self.rpcEvents = rpcEvents self.sourceFiles = sourceFiles } } @@ -112,6 +109,8 @@ public class NvimView: NSView, } } + public static let rpcEventName = "com.qvacua.NvimView" + public static let minFontSize = CGFloat(4) public static let maxFontSize = CGFloat(128) public static let defaultFont = NSFont.userFixedPitchFont(ofSize: 12)! @@ -213,7 +212,6 @@ public class NvimView: NSView, self.scheduler = SerialDispatchQueueScheduler(queue: self.queue, internalSerialQueueName: "com.qvacua.NvimView.NvimView") - self.subscribedEvents.formUnion(config.rpcEvents) self.sourceFileUrls = config.sourceFiles super.init(frame: .zero) @@ -313,18 +311,6 @@ public class NvimView: NSView, .disposed(by: self.disposeBag) } - public func subscribe(to events: [String]) -> Completable { - let result = Set(events) - .subtracting(self.subscribedEvents) - .reduce(Completable.empty()) { prev, event in - prev.andThen(self.api.subscribe(event: event)) - } - - self.subscribedEvents.formUnion(events) - - return result - } - convenience override public init(frame rect: NSRect) { self.init( frame: rect, @@ -333,7 +319,6 @@ public class NvimView: NSView, cwd: URL(fileURLWithPath: NSHomeDirectory()), nvimArgs: nil, envDict: nil, - rpcEvents: [], sourceFiles: [] ) ) @@ -403,10 +388,8 @@ public class NvimView: NSView, let sourceFileUrls: [URL] - var subscribedEvents = Set() - var subscribedEventCount = 0 - let rpcSubscribedCondition = NSCondition() - var rpcEventsSubscribed = false + let rpcEventSubscribedCondition = NSCondition() + var rpcEventSubscribedFlag = false // MARK: - Private private var _linespacing = NvimView.defaultLinespacing diff --git a/NvimView/neovim b/NvimView/neovim index 57d2679d..28461d7c 160000 --- a/NvimView/neovim +++ b/NvimView/neovim @@ -1 +1 @@ -Subproject commit 57d2679d048678210fd19db6b197afc4385c4ded +Subproject commit 28461d7c5750c88dc43dbf1bb6cce9320a5ebae0 diff --git a/VimR/VimR/MainWindow+Actions.swift b/VimR/VimR/MainWindow+Actions.swift index 8a4265e6..8a7c68b8 100644 --- a/VimR/VimR/MainWindow+Actions.swift +++ b/VimR/VimR/MainWindow+Actions.swift @@ -10,8 +10,18 @@ import MessagePack // MARK: - RpcEvent Actions extension MainWindow { - func rpcEventAction(for event: RpcEvent, params: [MessagePackValue]) { - stdoutLog.debug("\(event)") + func rpcEventAction(params rawParams: [MessagePackValue]) { + guard rawParams.count > 0 else { return } + + guard let strEvent = rawParams[0].stringValue, + let event = RpcEvent(rawValue: "\(RpcEvent.prefix).\(strEvent)") + else { + return + } + let params = Array(rawParams.suffix(from: 1)) + + stdoutLog.debug("\(event): \(params)") + switch event { case .makeSessionTemporary: self.emit(self.uuidAction(for: .makeSessionTemporary)) @@ -21,6 +31,8 @@ extension MainWindow { self.window.setFrame(screen.frame, display: true) case .toggleTools: + if params.count == 0 { return } + let param = params[0].integerValue if params.isEmpty || param == 0 { @@ -32,6 +44,8 @@ extension MainWindow { } case .toggleToolButtons: + if params.count == 0 { return } + let param = params[0].integerValue if params.isEmpty || param == 0 { diff --git a/VimR/VimR/MainWindow.swift b/VimR/VimR/MainWindow.swift index 9d99cc3d..dd154940 100644 --- a/VimR/VimR/MainWindow.swift +++ b/VimR/VimR/MainWindow.swift @@ -138,7 +138,6 @@ class MainWindow: NSObject, cwd: state.cwd, nvimArgs: state.nvimArgs, envDict: state.envDict, - rpcEvents: RpcEvent.allCases.map { $0.rawValue }, sourceFiles: sourceFileUrls ) self.neoVimView = NvimView(frame: .zero, config: neoVimViewConfig) @@ -287,8 +286,7 @@ class MainWindow: NSObject, break case .rpcEvent(let method, let params): - guard let event = RpcEvent(rawValue: method) else { break } - self.rpcEventAction(for: event, params: params) + self.rpcEventAction(params: params) case .rpcEventSubscribed: break diff --git a/VimR/VimR/RpcEvents.swift b/VimR/VimR/RpcEvents.swift index 19e25f2d..020415fd 100644 --- a/VimR/VimR/RpcEvents.swift +++ b/VimR/VimR/RpcEvents.swift @@ -7,6 +7,8 @@ import Foundation enum RpcEvent: String, CaseIterable { + static let prefix = "com.qvacua.vimr.rpc-events" + case makeSessionTemporary = "com.qvacua.vimr.rpc-events.make-session-temporary" case maximizeWindow = "com.qvacua.vimr.rpc-events.maximize-window" case toggleTools = "com.qvacua.vimr.rpc-events.toggle-tools" diff --git a/VimR/VimR/com.qvacua.VimR.vim b/VimR/VimR/com.qvacua.VimR.vim index 85129001..eed681df 100644 --- a/VimR/VimR/com.qvacua.VimR.vim +++ b/VimR/VimR/com.qvacua.VimR.vim @@ -1,16 +1,16 @@ function! s:VimRMakeSessionTemporary() abort - call rpcnotify(0, 'com.qvacua.vimr.rpc-events.make-session-temporary') + call rpcnotify(0, 'com.qvacua.NvimView', 'make-session-temporary') endfunction command! -nargs=0 VimRMakeSessionTemporary call s:VimRMakeSessionTemporary() function! s:VimRMaximizeWindow() abort - call rpcnotify(0, 'com.qvacua.vimr.rpc-events.maximize-window') + call rpcnotify(0, 'com.qvacua.NvimView', 'maximize-window') endfunction command! -nargs=0 VimRMaximizeWindow call s:VimRMaximizeWindow() " -1: hide, 0: toggle, 1: show function! s:VimRToggleTools(value) abort - call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-tools', a:value) + call rpcnotify(0, 'com.qvacua.NvimView', 'toggle-tools', a:value) endfunction command! -nargs=0 VimRHideTools call s:VimRToggleTools(-1) command! -nargs=0 VimRToggleTools call s:VimRToggleTools(0) @@ -18,13 +18,13 @@ command! -nargs=0 VimRShowTools call s:VimRToggleTools(1) " -1: hide, 0: toggle, 1: show function! s:VimRToggleToolButtons(value) abort - call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-tool-buttons', a:value) + call rpcnotify(0, 'com.qvacua.NvimView', 'toggle-tool-buttons', a:value) endfunction command! -nargs=0 VimRHideToolButtons call s:VimRToggleToolButtons(-1) command! -nargs=0 VimRToggleToolButtons call s:VimRToggleToolButtons(0) command! -nargs=0 VimRShowToolButtons call s:VimRToggleToolButtons(1) function! s:VimRToggleFullscreen() abort - call rpcnotify(0, 'com.qvacua.vimr.rpc-events.toggle-fullscreen') + call rpcnotify(0, 'com.qvacua.NvimView', 'toggle-fullscreen') endfunction command! -nargs=0 VimRToggleFullscreen call s:VimRToggleFullscreen() From 18f98be59323e8500e17c8432ff05a5fac8513f8 Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Sun, 3 Mar 2019 18:47:17 +0100 Subject: [PATCH 16/17] Update release notes --- resources/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/release-notes.md b/resources/release-notes.md index 9986a4e3..448068b0 100644 --- a/resources/release-notes.md +++ b/resources/release-notes.md @@ -2,6 +2,7 @@ * GH-314: You can customize the key shortcut for all menu items in the *Shortcut* preferences pane. * GH-501: Add key shortcuts to toggle the Buffer List, Markdown Preview, and HTML Preview tools. +* GH-649: Add commands that can control some of GUI elements. * Draw the disclosure triangle in appropriate color of the current color scheme (and improve handling of changes of `cwd` in the file browser). * ... From 4bbe370ba72d204ce75e129369d489ba3b9d4474 Mon Sep 17 00:00:00 2001 From: Tae Won Ha Date: Sun, 3 Mar 2019 21:13:43 +0100 Subject: [PATCH 17/17] Bump version: snapshot/301 --- NvimView/DrawerDev/Info.plist | 4 ++-- NvimView/NvimView.xcodeproj/project.pbxproj | 8 ++++---- NvimView/NvimView/Info.plist | 4 ++-- NvimView/NvimViewTests/Info.plist | 4 ++-- VimR/VimR.xcodeproj/project.pbxproj | 4 ++-- VimR/VimR/Info.plist | 4 ++-- VimR/VimRTests/Info.plist | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/NvimView/DrawerDev/Info.plist b/NvimView/DrawerDev/Info.plist index cbb9b409..bb0e22c7 100644 --- a/NvimView/DrawerDev/Info.plist +++ b/NvimView/DrawerDev/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - SNAPSHOT-300 + SNAPSHOT-301 CFBundleVersion - 300 + 301 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright diff --git a/NvimView/NvimView.xcodeproj/project.pbxproj b/NvimView/NvimView.xcodeproj/project.pbxproj index bc111032..28ed4e39 100644 --- a/NvimView/NvimView.xcodeproj/project.pbxproj +++ b/NvimView/NvimView.xcodeproj/project.pbxproj @@ -783,7 +783,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 300; + CURRENT_PROJECT_VERSION = 301; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -845,7 +845,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 300; + CURRENT_PROJECT_VERSION = 301; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -874,7 +874,7 @@ COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 300; + DYLIB_CURRENT_VERSION = 301; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac"; FRAMEWORK_VERSION = A; @@ -896,7 +896,7 @@ COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 300; + DYLIB_CURRENT_VERSION = 301; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac"; FRAMEWORK_VERSION = A; diff --git a/NvimView/NvimView/Info.plist b/NvimView/NvimView/Info.plist index d1a2ab21..4cb41d50 100644 --- a/NvimView/NvimView/Info.plist +++ b/NvimView/NvimView/Info.plist @@ -15,9 +15,9 @@ CFBundlePackageType FMWK CFBundleShortVersionString - SNAPSHOT-300 + SNAPSHOT-301 CFBundleVersion - 300 + 301 NSHumanReadableCopyright Copyright © 2017 Tae Won Ha. All rights reserved. NSPrincipalClass diff --git a/NvimView/NvimViewTests/Info.plist b/NvimView/NvimViewTests/Info.plist index 32fdfdea..9252666e 100644 --- a/NvimView/NvimViewTests/Info.plist +++ b/NvimView/NvimViewTests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType BNDL CFBundleShortVersionString - SNAPSHOT-300 + SNAPSHOT-301 CFBundleVersion - 300 + 301 diff --git a/VimR/VimR.xcodeproj/project.pbxproj b/VimR/VimR.xcodeproj/project.pbxproj index 03c06b67..97f8d051 100644 --- a/VimR/VimR.xcodeproj/project.pbxproj +++ b/VimR/VimR.xcodeproj/project.pbxproj @@ -1320,7 +1320,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 300; + CURRENT_PROJECT_VERSION = 301; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -1378,7 +1378,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 300; + CURRENT_PROJECT_VERSION = 301; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; diff --git a/VimR/VimR/Info.plist b/VimR/VimR/Info.plist index 14affb17..86db3cf6 100644 --- a/VimR/VimR/Info.plist +++ b/VimR/VimR/Info.plist @@ -1224,7 +1224,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - SNAPSHOT-300 + SNAPSHOT-301 CFBundleSignature ???? CFBundleURLTypes @@ -1241,7 +1241,7 @@ CFBundleVersion - 300 + 301 LSApplicationCategoryType public.app-category.productivity LSMinimumSystemVersion diff --git a/VimR/VimRTests/Info.plist b/VimR/VimRTests/Info.plist index cc27bf47..1764ac9b 100644 --- a/VimR/VimRTests/Info.plist +++ b/VimR/VimRTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - SNAPSHOT-300 + SNAPSHOT-301 CFBundleSignature ???? CFBundleVersion - 300 + 301