From 16c27a9d11e12e2aa54828a42a056f90cc0ee187 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 9 Oct 2023 12:46:08 -0700 Subject: [PATCH 01/33] build fixes --- VimR/VimR.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/VimR/VimR.xcodeproj/project.pbxproj b/VimR/VimR.xcodeproj/project.pbxproj index baf700352..bf3046c99 100644 --- a/VimR/VimR.xcodeproj/project.pbxproj +++ b/VimR/VimR.xcodeproj/project.pbxproj @@ -1224,6 +1224,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 13.0; OTHER_LDFLAGS = "-pthread"; PRODUCT_BUNDLE_IDENTIFIER = "$(VIMR_BUNDLE_IDENTIFIER)"; PRODUCT_MODULE_NAME = VimR; @@ -1246,6 +1247,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 13.0; OTHER_LDFLAGS = "-pthread"; PRODUCT_BUNDLE_IDENTIFIER = "$(VIMR_BUNDLE_IDENTIFIER)"; PRODUCT_MODULE_NAME = VimR; From d7411b7badf6cf11b903b48c4bdda9ea3c39a829 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 9 Oct 2023 13:03:09 -0700 Subject: [PATCH 02/33] point at forked nvimserver --- .gitmodules | 2 +- NvimServer | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 29b3edf58..d6053a5ce 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "NvimServer"] path = NvimServer - url = git@github.com:qvacua/neovim.git + url = git@github.com:georgeharker/vimr-neovim.git diff --git a/NvimServer b/NvimServer index 5f8dd8c4a..2143e16ef 160000 --- a/NvimServer +++ b/NvimServer @@ -1 +1 @@ -Subproject commit 5f8dd8c4a33203277cf6058f559383626411693d +Subproject commit 2143e16ef20eb45fe29b726294a6549623f94424 From 3306da6842775ce2da85b185f9c83efbe2c7d096 Mon Sep 17 00:00:00 2001 From: George Harker Date: Sun, 29 Oct 2023 12:36:56 -0700 Subject: [PATCH 03/33] custom binary option wiring --- VimR/VimR/AdvancedPrefReducer.swift | 3 +++ VimR/VimR/AdvencedPref.swift | 36 +++++++++++++++++++++++++++++ VimR/VimR/MainWindow.swift | 3 ++- VimR/VimR/PrefMiddleware.swift | 5 +++- VimR/VimR/States.swift | 13 +++++++++-- 5 files changed, 56 insertions(+), 4 deletions(-) diff --git a/VimR/VimR/AdvancedPrefReducer.swift b/VimR/VimR/AdvancedPrefReducer.swift index 322df51dc..68cd19e82 100644 --- a/VimR/VimR/AdvancedPrefReducer.swift +++ b/VimR/VimR/AdvancedPrefReducer.swift @@ -26,6 +26,9 @@ final class AdvancedPrefReducer: ReducerType { case let .setUseSnapshotUpdate(value): state.useSnapshotUpdate = value + + case let .setNvimBinary(value): + state.mainWindowTemplate.nvimBinary = value } return (state, pair.action, true) diff --git a/VimR/VimR/AdvencedPref.swift b/VimR/VimR/AdvencedPref.swift index 31247ff11..8b0309385 100644 --- a/VimR/VimR/AdvencedPref.swift +++ b/VimR/VimR/AdvencedPref.swift @@ -15,6 +15,7 @@ final class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate { case setUseSnapshotUpdate(Bool) case setUseLiveResize(Bool) case setDrawsParallel(Bool) + case setNvimBinary(String) } override var displayName: String { @@ -32,6 +33,7 @@ final class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate { self.useSnapshotUpdate = state.useSnapshotUpdate self.useLiveResize = state.mainWindowTemplate.useLiveResize self.drawsParallel = state.mainWindowTemplate.drawsParallel + self.nvimBinary = state.mainWindowTemplate.nvimBinary super.init(frame: .zero) @@ -42,11 +44,13 @@ final class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate { .observe(on: MainScheduler.instance) .subscribe(onNext: { state in if self.useInteractiveZsh != state.mainWindowTemplate.useInteractiveZsh + || self.nvimBinary != state.mainWindowTemplate.nvimBinary || self.useSnapshotUpdate != state.useSnapshotUpdate || self.useLiveResize != state.mainWindowTemplate.useLiveResize || self.drawsParallel != state.mainWindowTemplate.drawsParallel { self.useInteractiveZsh = state.mainWindowTemplate.useInteractiveZsh + self.nvimBinary = state.mainWindowTemplate.nvimBinary self.useSnapshotUpdate = state.useSnapshotUpdate self.useLiveResize = state.mainWindowTemplate.useLiveResize self.drawsParallel = state.mainWindowTemplate.drawsParallel @@ -64,22 +68,29 @@ final class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate { private var useSnapshotUpdate: Bool private var useLiveResize: Bool private var drawsParallel: Bool + private var nvimBinary: String private let useInteractiveZshCheckbox = NSButton(forAutoLayout: ()) private let useSnapshotUpdateCheckbox = NSButton(forAutoLayout: ()) private let useLiveResizeCheckbox = NSButton(forAutoLayout: ()) private let drawsParallelCheckbox = NSButton(forAutoLayout: ()) + private let nvimBinaryField = NSTextView(forAutoLayout: ()) @available(*, unavailable) required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } + override func windowWillClose() { + self.nvimBinaryFieldAction() + } + private func updateViews() { self.useSnapshotUpdateCheckbox.boolState = self.useSnapshotUpdate self.useInteractiveZshCheckbox.boolState = self.useInteractiveZsh self.useLiveResizeCheckbox.boolState = self.useLiveResize self.drawsParallelCheckbox.boolState = self.drawsParallel + self.nvimBinaryField.string = self.nvimBinary } private func addViews() { @@ -136,6 +147,9 @@ final class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate { when scrolling very fast. """#) + let nvimBinaryTitle = self.titleTextField(title: "NeoVim Binary:") + let nvimBinaryField = self.nvimBinaryField + self.addSubview(paneTitle) self.addSubview(useSnapshotUpdate) @@ -146,6 +160,8 @@ final class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate { self.addSubview(useLiveResizeInfo) self.addSubview(drawsParallelBox) self.addSubview(drawsParallelInfo) + self.addSubview(nvimBinaryTitle) + self.addSubview(nvimBinaryField) paneTitle.autoPinEdge(toSuperviewEdge: .top, withInset: 18) paneTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18) @@ -174,6 +190,21 @@ final class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate { useInteractiveZshInfo.autoPinEdge(.top, to: .bottom, of: useInteractiveZsh, withOffset: 5) useInteractiveZshInfo.autoPinEdge(.left, to: .left, of: useInteractiveZsh) + + nvimBinaryTitle.autoPinEdge(.top, to: .bottom, of: useInteractiveZshInfo, withOffset: 18) + nvimBinaryTitle.autoPinEdge(.left, to: .left, of: useLiveResize, withOffset: 5) + //nvimBinaryTitle.autoAlignAxis(.baseline, toSameAxisOf: nvimBinaryField) + + nvimBinaryField.autoPinEdge(.top, to: .bottom, of: useInteractiveZshInfo, withOffset: 18) + nvimBinaryField.autoPinEdge(.left, to: .right, of: nvimBinaryTitle, withOffset: 5) + nvimBinaryField.autoPinEdge(toSuperviewEdge: .right, withInset: 18) + nvimBinaryField.autoSetDimension(.height, toSize: 20, relation: .greaterThanOrEqual) + NotificationCenter.default.addObserver( + forName: NSControl.textDidEndEditingNotification, + object: nvimBinaryField, + queue: nil + ) { [weak self] _ in self?.nvimBinaryFieldAction() } + } } @@ -195,4 +226,9 @@ extension AdvancedPref { @objc func useSnapshotUpdateChannelAction(_ sender: NSButton) { self.emit(.setUseSnapshotUpdate(sender.boolState)) } + + func nvimBinaryFieldAction() { + let newNvimBinary = self.nvimBinaryField.string + self.emit(.setNvimBinary(newNvimBinary)) + } } diff --git a/VimR/VimR/MainWindow.swift b/VimR/VimR/MainWindow.swift index 84a8ca522..3be21f84d 100644 --- a/VimR/VimR/MainWindow.swift +++ b/VimR/VimR/MainWindow.swift @@ -86,6 +86,7 @@ final class MainWindow: NSObject, usesCustomTabBar: state.appearance.usesCustomTab, useInteractiveZsh: state.useInteractiveZsh, cwd: state.cwd, + nvimBinary: state.nvimBinary, nvimArgs: state.nvimArgs, envDict: state.envDict, sourceFiles: sourceFileUrls @@ -259,7 +260,7 @@ final class MainWindow: NSObject, private var usesTheme = true private var lastThemeMark = Token() - private let log = OSLog( + internal let log = OSLog( subsystem: Defs.loggerSubsystem, category: Defs.LoggerCategory.ui ) diff --git a/VimR/VimR/PrefMiddleware.swift b/VimR/VimR/PrefMiddleware.swift index 5a2c04446..dae81e54b 100644 --- a/VimR/VimR/PrefMiddleware.swift +++ b/VimR/VimR/PrefMiddleware.swift @@ -11,7 +11,7 @@ final class PrefMiddleware: MiddlewareType { typealias StateType = AppState typealias ActionType = AnyAction - static let compatibleVersion = "168" + static let compatibleVersion = "169" let mainWindow = MainWindowMiddleware() @@ -20,6 +20,7 @@ final class PrefMiddleware: MiddlewareType { do { let dictionary: [String: Any] = try dictEncoder.encode(appState) defaults.set(dictionary, forKey: PrefMiddleware.compatibleVersion) + defaults.synchronize() } catch { self.log.error("AppState could not converted to Dictionary: \(error)") } @@ -59,6 +60,7 @@ final class PrefMiddleware: MiddlewareType { do { let dictionary: [String: Any] = try dictEncoder.encode(result.state) defaults.set(dictionary, forKey: PrefMiddleware.compatibleVersion) + defaults.synchronize() } catch { self.log.error("AppState could not converted to Dictionary: \(error)") } @@ -86,6 +88,7 @@ final class PrefMiddleware: MiddlewareType { do { let dictionary: [String: Any] = try dictEncoder.encode(result.state) defaults.set(dictionary, forKey: PrefMiddleware.compatibleVersion) + defaults.synchronize() } catch { self.log.error("AppState could not converted to Dictionary: \(error)") } diff --git a/VimR/VimR/States.swift b/VimR/VimR/States.swift index 84dcaa2b1..f9fda0be4 100644 --- a/VimR/VimR/States.swift +++ b/VimR/VimR/States.swift @@ -263,7 +263,9 @@ struct AppearanceState: Codable { extension MainWindow { struct State: Codable { - static let `default` = State(isAllToolsVisible: true, isToolButtonsVisible: true) + static let `default` = State(isAllToolsVisible: true, + isToolButtonsVisible: true, + nvimBinary: "") static let defaultTools: [MainWindow.Tools: WorkspaceToolState] = [ .fileBrowser: WorkspaceToolState(location: .left, dimension: 200, open: true), @@ -315,6 +317,7 @@ extension MainWindow { var appearance = AppearanceState.default var useInteractiveZsh = false + var nvimBinary: String = "" var nvimArgs: [String]? var cliPipePath: String? var envDict: [String: String]? @@ -324,15 +327,17 @@ extension MainWindow { var isLeftOptionMeta = false var isRightOptionMeta = false + // to be cleaned var urlsToOpen = [URL: OpenMode]() var currentBufferToSet: NvimView.Buffer? var cwdToSet: URL? var viewToBeFocused: FocusableView? = FocusableView.neoVimView - init(isAllToolsVisible: Bool, isToolButtonsVisible: Bool) { + init(isAllToolsVisible: Bool, isToolButtonsVisible: Bool, nvimBinary: String) { self.isAllToolsVisible = isAllToolsVisible self.isToolButtonsVisible = isToolButtonsVisible + self.nvimBinary = nvimBinary } enum CodingKeys: String, CodingKey { @@ -346,6 +351,8 @@ extension MainWindow { case isRightOptionMeta = "is-right-option-meta" case useInteractiveZsh = "use-interactive-zsh" + case nvimBinary = "nvim-binary" + case useLiveResize = "use-live-resize" case drawsParallel = "draws-parallel" case isShowHidden = "is-show-hidden" @@ -370,6 +377,7 @@ extension MainWindow { forKey: .useInteractiveZsh, default: State.default.useInteractiveZsh ) + self.nvimBinary = try container.decodeIfPresent(String.self, forKey: .nvimBinary) ?? State.default.nvimBinary self.useLiveResize = try container.decode( forKey: .useLiveResize, default: State.default.useLiveResize @@ -450,6 +458,7 @@ extension MainWindow { try container.encode(self.isLeftOptionMeta, forKey: .isLeftOptionMeta) try container.encode(self.isRightOptionMeta, forKey: .isRightOptionMeta) try container.encode(self.useInteractiveZsh, forKey: .useInteractiveZsh) + try container.encode(self.nvimBinary, forKey: .nvimBinary) try container.encode(self.fileBrowserShowHidden, forKey: .isShowHidden) // See [1] From 68c29ca60f363ed98e6f715625e0d314730048d4 Mon Sep 17 00:00:00 2001 From: George Harker Date: Sun, 29 Oct 2023 12:41:46 -0700 Subject: [PATCH 04/33] fix colorscheme decode --- VimR/VimR/MainWindow+Delegates.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/VimR/VimR/MainWindow+Delegates.swift b/VimR/VimR/MainWindow+Delegates.swift index 98da52fb5..8172df0ee 100644 --- a/VimR/VimR/MainWindow+Delegates.swift +++ b/VimR/VimR/MainWindow+Delegates.swift @@ -4,6 +4,7 @@ */ import Cocoa +import MessagePack import NvimView import RxNeovim import RxPack @@ -101,6 +102,8 @@ extension MainWindow { for: .setTheme(Theme(from: nvimTheme, additionalColorDict: colors)) ) ) + }, onError: { + err in self.log.trace("oops couldn't set theme") }) .disposed(by: self.disposeBag) } @@ -153,7 +156,8 @@ extension MainWindow { ( colorName: colorName, observable: self.neoVimView.api - .getHlByName(name: colorName, rgb: true) + .getHl(ns_id: 0, + opts: ["name": MessagePackValue(colorName)]) .asObservable() ) }) From 615d32755c546e478a24574a91e3443f7fbccdb4 Mon Sep 17 00:00:00 2001 From: George Harker Date: Sun, 29 Oct 2023 13:46:05 -0700 Subject: [PATCH 05/33] Talk to external nvim without uibridge --- .../NvimAutoCommandEvent.generated.swift | 252 ++++----- .../NvimCursorModeShape.generated.swift | 43 +- NvimView/Sources/NvimView/NvimView+Api.swift | 74 ++- NvimView/Sources/NvimView/NvimView+Draw.swift | 3 +- NvimView/Sources/NvimView/NvimView+Key.swift | 9 +- .../Sources/NvimView/NvimView+Mouse.swift | 19 +- .../NvimView/NvimView+RemoteOptions.swift | 2 + .../Sources/NvimView/NvimView+Resize.swift | 92 +++- .../Sources/NvimView/NvimView+Types.swift | 3 + .../Sources/NvimView/NvimView+UiBridge.swift | 477 +++++++++++++----- NvimView/Sources/NvimView/NvimView.swift | 19 +- NvimView/Sources/NvimView/UGrid.swift | 46 ++ NvimView/Sources/NvimView/UiBridge.swift | 278 ++-------- .../RxNeovim/RxNeovimApi.generated.swift | 199 +++----- RxPack/Sources/RxPack/RxMessagePort.swift | 268 ---------- .../RxPackSupport.xcodeproj/project.pbxproj | 6 +- bin/generate_autocmds.py | 2 +- bin/generate_cursor_shape.py | 2 +- resources/autocmds.template.swift | 2 +- resources/cursor_shape.template.swift | 3 +- 20 files changed, 842 insertions(+), 957 deletions(-) delete mode 100644 RxPack/Sources/RxPack/RxMessagePort.swift diff --git a/NvimView/Sources/NvimView/NvimAutoCommandEvent.generated.swift b/NvimView/Sources/NvimView/NvimAutoCommandEvent.generated.swift index 9657e2076..5e941c33e 100644 --- a/NvimView/Sources/NvimView/NvimAutoCommandEvent.generated.swift +++ b/NvimView/Sources/NvimView/NvimAutoCommandEvent.generated.swift @@ -1,130 +1,132 @@ -// Auto generated for nvim v0.8.2 +// Auto generated for nvim v0.9.0-dev // See bin/generate_autocmds.py -enum NvimAutoCommandEvent: Int { +enum NvimAutoCommandEvent: String { - case bufadd = 0 - case bufdelete = 1 - case bufenter = 2 - case buffilepost = 3 - case buffilepre = 4 - case bufhidden = 5 - case bufleave = 6 - case bufmodifiedset = 7 - case bufnew = 8 - case bufnewfile = 9 - case bufreadcmd = 10 - case bufreadpost = 11 - case bufreadpre = 12 - case bufunload = 13 - case bufwinenter = 14 - case bufwinleave = 15 - case bufwipeout = 16 - case bufwritecmd = 17 - case bufwritepost = 18 - case bufwritepre = 19 - case chaninfo = 20 - case chanopen = 21 - case cmdundefined = 22 - case cmdwinenter = 23 - case cmdwinleave = 24 - case cmdlinechanged = 25 - case cmdlineenter = 26 - case cmdlineleave = 27 - case colorscheme = 28 - case colorschemepre = 29 - case completechanged = 30 - case completedone = 31 - case completedonepre = 32 - case cursorhold = 33 - case cursorholdi = 34 - case cursormoved = 35 - case cursormovedi = 36 - case diagnosticchanged = 37 - case diffupdated = 38 - case dirchanged = 39 - case dirchangedpre = 40 - case encodingchanged = 41 - case exitpre = 42 - case fileappendcmd = 43 - case fileappendpost = 44 - case fileappendpre = 45 - case filechangedro = 46 - case filechangedshell = 47 - case filechangedshellpost = 48 - case filereadcmd = 49 - case filereadpost = 50 - case filereadpre = 51 - case filetype = 52 - case filewritecmd = 53 - case filewritepost = 54 - case filewritepre = 55 - case filterreadpost = 56 - case filterreadpre = 57 - case filterwritepost = 58 - case filterwritepre = 59 - case focusgained = 60 - case focuslost = 61 - case funcundefined = 62 - case guienter = 63 - case guifailed = 64 - case insertchange = 65 - case insertcharpre = 66 - case insertenter = 67 - case insertleave = 68 - case insertleavepre = 69 - case lspattach = 70 - case lspdetach = 71 - case menupopup = 72 - case modechanged = 73 - case optionset = 74 - case quickfixcmdpost = 75 - case quickfixcmdpre = 76 - case quitpre = 77 - case recordingenter = 78 - case recordingleave = 79 - case remotereply = 80 - case searchwrapped = 81 - case sessionloadpost = 82 - case shellcmdpost = 83 - case shellfilterpost = 84 - case signal = 85 - case sourcecmd = 86 - case sourcepost = 87 - case sourcepre = 88 - case spellfilemissing = 89 - case stdinreadpost = 90 - case stdinreadpre = 91 - case swapexists = 92 - case syntax = 93 - case tabclosed = 94 - case tabenter = 95 - case tableave = 96 - case tabnew = 97 - case tabnewentered = 98 - case termchanged = 99 - case termclose = 100 - case termenter = 101 - case termleave = 102 - case termopen = 103 - case termresponse = 104 - case textchanged = 105 - case textchangedi = 106 - case textchangedp = 107 - case textyankpost = 108 - case uienter = 109 - case uileave = 110 - case user = 111 - case vimenter = 112 - case vimleave = 113 - case vimleavepre = 114 - case vimresized = 115 - case vimresume = 116 - case vimsuspend = 117 - case winclosed = 118 - case winenter = 119 - case winleave = 120 - case winnew = 121 - case winscrolled = 122 + case bufadd = "bufadd" + case bufdelete = "bufdelete" + case bufenter = "bufenter" + case buffilepost = "buffilepost" + case buffilepre = "buffilepre" + case bufhidden = "bufhidden" + case bufleave = "bufleave" + case bufmodifiedset = "bufmodifiedset" + case bufnew = "bufnew" + case bufnewfile = "bufnewfile" + case bufreadcmd = "bufreadcmd" + case bufreadpost = "bufreadpost" + case bufreadpre = "bufreadpre" + case bufunload = "bufunload" + case bufwinenter = "bufwinenter" + case bufwinleave = "bufwinleave" + case bufwipeout = "bufwipeout" + case bufwritecmd = "bufwritecmd" + case bufwritepost = "bufwritepost" + case bufwritepre = "bufwritepre" + case chaninfo = "chaninfo" + case chanopen = "chanopen" + case cmdundefined = "cmdundefined" + case cmdwinenter = "cmdwinenter" + case cmdwinleave = "cmdwinleave" + case cmdlinechanged = "cmdlinechanged" + case cmdlineenter = "cmdlineenter" + case cmdlineleave = "cmdlineleave" + case colorscheme = "colorscheme" + case colorschemepre = "colorschemepre" + case completechanged = "completechanged" + case completedone = "completedone" + case completedonepre = "completedonepre" + case cursorhold = "cursorhold" + case cursorholdi = "cursorholdi" + case cursormoved = "cursormoved" + case cursormovedi = "cursormovedi" + case diagnosticchanged = "diagnosticchanged" + case diffupdated = "diffupdated" + case dirchanged = "dirchanged" + case dirchangedpre = "dirchangedpre" + case encodingchanged = "encodingchanged" + case exitpre = "exitpre" + case fileappendcmd = "fileappendcmd" + case fileappendpost = "fileappendpost" + case fileappendpre = "fileappendpre" + case filechangedro = "filechangedro" + case filechangedshell = "filechangedshell" + case filechangedshellpost = "filechangedshellpost" + case filereadcmd = "filereadcmd" + case filereadpost = "filereadpost" + case filereadpre = "filereadpre" + case filetype = "filetype" + case filewritecmd = "filewritecmd" + case filewritepost = "filewritepost" + case filewritepre = "filewritepre" + case filterreadpost = "filterreadpost" + case filterreadpre = "filterreadpre" + case filterwritepost = "filterwritepost" + case filterwritepre = "filterwritepre" + case focusgained = "focusgained" + case focuslost = "focuslost" + case funcundefined = "funcundefined" + case guienter = "guienter" + case guifailed = "guifailed" + case insertchange = "insertchange" + case insertcharpre = "insertcharpre" + case insertenter = "insertenter" + case insertleave = "insertleave" + case insertleavepre = "insertleavepre" + case lspattach = "lspattach" + case lspdetach = "lspdetach" + case menupopup = "menupopup" + case modechanged = "modechanged" + case optionset = "optionset" + case quickfixcmdpost = "quickfixcmdpost" + case quickfixcmdpre = "quickfixcmdpre" + case quitpre = "quitpre" + case recordingenter = "recordingenter" + case recordingleave = "recordingleave" + case remotereply = "remotereply" + case searchwrapped = "searchwrapped" + case sessionloadpost = "sessionloadpost" + case shellcmdpost = "shellcmdpost" + case shellfilterpost = "shellfilterpost" + case signal = "signal" + case sourcecmd = "sourcecmd" + case sourcepost = "sourcepost" + case sourcepre = "sourcepre" + case spellfilemissing = "spellfilemissing" + case stdinreadpost = "stdinreadpost" + case stdinreadpre = "stdinreadpre" + case swapexists = "swapexists" + case syntax = "syntax" + case tabclosed = "tabclosed" + case tabenter = "tabenter" + case tableave = "tableave" + case tabnew = "tabnew" + case tabnewentered = "tabnewentered" + case termchanged = "termchanged" + case termclose = "termclose" + case termenter = "termenter" + case termleave = "termleave" + case termopen = "termopen" + case termresponse = "termresponse" + case textchanged = "textchanged" + case textchangedi = "textchangedi" + case textchangedp = "textchangedp" + case textchangedt = "textchangedt" + case textyankpost = "textyankpost" + case uienter = "uienter" + case uileave = "uileave" + case user = "user" + case vimenter = "vimenter" + case vimleave = "vimleave" + case vimleavepre = "vimleavepre" + case vimresized = "vimresized" + case vimresume = "vimresume" + case vimsuspend = "vimsuspend" + case winclosed = "winclosed" + case winenter = "winenter" + case winleave = "winleave" + case winnew = "winnew" + case winresized = "winresized" + case winscrolled = "winscrolled" } diff --git a/NvimView/Sources/NvimView/NvimCursorModeShape.generated.swift b/NvimView/Sources/NvimView/NvimCursorModeShape.generated.swift index 7642b2e6a..afefaee30 100644 --- a/NvimView/Sources/NvimView/NvimCursorModeShape.generated.swift +++ b/NvimView/Sources/NvimView/NvimCursorModeShape.generated.swift @@ -1,27 +1,26 @@ -// Auto generated for nvim v0.8.2 +// Auto generated for nvim v0.9.0-dev // See bin/generate_cursor_shape.py -public enum CursorModeShape: UInt { +public enum CursorModeShape: String { - case normal = 0 - case visual = 1 - case insert = 2 - case replace = 3 - case cmdlineNormal = 4 - case cmdlineInsert = 5 - case cmdlineReplace = 6 - case operatorPending = 7 - case visualExclusive = 8 - case onCmdline = 9 - case onStatusLine = 10 - case draggingStatusLine = 11 - case onVerticalSepLine = 12 - case draggingVerticalSepLine = 13 - case more = 14 - case moreLastLine = 15 - case showingMatchingParen = 16 - case termFocus = 17 - case count = 18 + case normal = "normal" + case visual = "visual" + case insert = "insert" + case replace = "replace" + case cmdlineNormal = "cmdlineNormal" + case cmdlineInsert = "cmdlineInsert" + case cmdlineReplace = "cmdlineReplace" + case operatorPending = "operatorPending" + case visualExclusive = "visualExclusive" + case onCmdline = "onCmdline" + case onStatusLine = "onStatusLine" + case draggingStatusLine = "draggingStatusLine" + case onVerticalSepLine = "onVerticalSepLine" + case draggingVerticalSepLine = "draggingVerticalSepLine" + case more = "more" + case moreLastLine = "moreLastLine" + case showingMatchingParen = "showingMatchingParen" + case termFocus = "termFocus" + case count = "count" } - diff --git a/NvimView/Sources/NvimView/NvimView+Api.swift b/NvimView/Sources/NvimView/NvimView+Api.swift index 8582ecf73..1546a540a 100644 --- a/NvimView/Sources/NvimView/NvimView+Api.swift +++ b/NvimView/Sources/NvimView/NvimView+Api.swift @@ -38,7 +38,18 @@ public extension NvimView { } func hasDirtyBuffers() -> Single { - self.api.getDirtyStatus() + self.api + .execLua(code: """ + return vim.fn.getbufinfo({"bufmodified": v:true}) + """, args: []) + .map { result -> Bool in + guard let info_array = result.arrayValue + else { + throw RxNeovimApi.Error + .exception(message: "Could not convert values into info array.") + } + return info_array.count > 0 + } } func waitTillNvimExits() { @@ -196,7 +207,17 @@ public extension NvimView { func vimOutput(of command: String) -> Single { self.api - .exec(src: command, output: true) + .exec2(src: command, opts:["output": true]) + .map({ + retval in + guard let output_value = retval["output"] ?? retval["output"], + let output = output_value.stringValue + else { + throw RxNeovimApi.Error + .exception(message: "Could not convert values to output.") + } + return output + }) .subscribe(on: self.scheduler) } @@ -209,22 +230,53 @@ public extension NvimView { .subscribe(on: self.scheduler) } - func didBecomeMain() -> Completable { self.bridge.focusGained(true) } + func didBecomeMain() -> Completable { + self.focusGained(true) + } - func didResignMain() -> Completable { self.bridge.focusGained(false) } + func didResignMain() -> Completable { + self.focusGained(false) + } internal func neoVimBuffer( for buf: RxNeovimApi.Buffer, currentBuffer: RxNeovimApi.Buffer? ) -> Single { self.api - .bufGetInfo(buffer: buf) - .map { info -> NvimView.Buffer in + .execLua(code: """ + local function map(tbl, f) + local t = {} + for k,v in pairs(tbl) do + t[k] = f(v) + end + return t + end + return map(vim.fn.getbufinfo(...), function(i) + i.buftype = vim.api.nvim_get_option_value("buftype", + {buf=i.bufnr}) + print(i.name, i.buftype) + return i + end) + """, args: [MessagePackValue(buf.handle)]) + .map { result -> NvimView.Buffer in + guard let info_array = result.arrayValue, + info_array.count == 1, + let raw_info = info_array[0].dictionaryValue + else { + throw RxNeovimApi.Error + .exception(message: "Could not convert values into info array.") + } + let info : [String: MessagePackValue] = Dictionary( + uniqueKeysWithValues: raw_info.map({ + (key: MessagePackValue, value: MessagePackValue) in + (key.stringValue!, value) + })) + let current = buf == currentBuffer - guard let path = info["filename"]?.stringValue, - let dirty = info["modified"]?.boolValue, + guard let path = info["name"]?.stringValue, + let dirty = info["changed"]?.intValue, let buftype = info["buftype"]?.stringValue, - let listed = info["buflisted"]?.boolValue + let listed = info["listed"]?.intValue else { throw RxNeovimApi.Error .exception(message: "Could not convert values from the dictionary.") @@ -236,9 +288,9 @@ public extension NvimView { apiBuffer: buf, url: url, type: buftype, - isDirty: dirty, + isDirty: dirty != 0, isCurrent: current, - isListed: listed + isListed: listed != 0 ) } .subscribe(on: self.scheduler) diff --git a/NvimView/Sources/NvimView/NvimView+Draw.swift b/NvimView/Sources/NvimView/NvimView+Draw.swift index 2d86be131..1290ec57f 100644 --- a/NvimView/Sources/NvimView/NvimView+Draw.swift +++ b/NvimView/Sources/NvimView/NvimView+Draw.swift @@ -97,11 +97,10 @@ extension NvimView { return } - guard self.modeInfoList.count > self.mode.rawValue else { + guard let modeInfo = modeInfos[self.mode.rawValue] else { self.log.error("Could not get modeInfo for mode index \(self.mode.rawValue)") return } - let modeInfo = modeInfoList[Int(mode.rawValue)] guard let cursorAttrId = modeInfo.attrId, let cursorShapeAttrs = self.cellAttributesCollection.attributes( diff --git a/NvimView/Sources/NvimView/NvimView+Key.swift b/NvimView/Sources/NvimView/NvimView+Key.swift index 6e79b8b99..defe4885f 100644 --- a/NvimView/Sources/NvimView/NvimView+Key.swift +++ b/NvimView/Sources/NvimView/NvimView+Key.swift @@ -58,8 +58,7 @@ public extension NvimView { default: return } - try? self.bridge - .deleteCharacters(0, andInputEscapedString: self.vimPlainString(text)) + try? self.api.feedkeys(keys: self.vimPlainString(text), mode:"i", escape_ks: false) .wait() if self.hasMarkedText() { self._unmarkText() } @@ -182,9 +181,9 @@ public extension NvimView { // after delete, cusor should be the location } if replacementRange.length > 0 { - try? self.bridge - .deleteCharacters(replacementRange.length, andInputEscapedString: "") - .wait() + let text = String(repeating:"", count: replacementRange.length) + try? self.api.feedkeys(keys: text, mode:"i", escape_ks: false) + .wait() } // delay to wait async gui update handled. diff --git a/NvimView/Sources/NvimView/NvimView+Mouse.swift b/NvimView/Sources/NvimView/NvimView+Mouse.swift index b41538e14..078422c96 100644 --- a/NvimView/Sources/NvimView/NvimView+Mouse.swift +++ b/NvimView/Sources/NvimView/NvimView+Mouse.swift @@ -5,6 +5,7 @@ import Cocoa import RxSwift +import RxNeovim public extension NvimView { override func mouseDown(with event: NSEvent) { @@ -87,8 +88,22 @@ public extension NvimView { min(Int(abs(deltaCellY)), maxScrollDeltaY) ) let (horizSign, vertSign) = (deltaCellX > 0 ? 1 : -1, deltaCellY > 0 ? 1 : -1) - self.bridge - .scroll(horizontal: horizSign * absDeltaX, vertical: vertSign * absDeltaY, at: cellPosition) + self.log.debug("# scroll: \(cellPosition.row + vertSign * absDeltaY) \(cellPosition.column + horizSign * absDeltaX)") + + self.api.winGetCursor(window: RxNeovimApi.Window(0)) + .map( { + guard $0.count == 2 + else { + self.log.error("Error decoding \($0)") + return + } + self.api.winSetCursor(window: RxNeovimApi.Window(0), + pos: [$0[0] + vertSign * absDeltaY, $0[1] + horizSign * absDeltaX]) + .subscribe(onError: { [weak self] error in + self?.log.error("Error in \(#function): \(error)") + }) + .disposed(by: self.disposeBag) + }) .subscribe(onError: { [weak self] error in self?.log.error("Error in \(#function): \(error)") }) diff --git a/NvimView/Sources/NvimView/NvimView+RemoteOptions.swift b/NvimView/Sources/NvimView/NvimView+RemoteOptions.swift index 450e46609..7de3ab7a0 100644 --- a/NvimView/Sources/NvimView/NvimView+RemoteOptions.swift +++ b/NvimView/Sources/NvimView/NvimView+RemoteOptions.swift @@ -102,6 +102,8 @@ extension NvimView { gui.async { self.font = newFont + // Cell size likely changed, do a resize. + self.resizeNeoVimUi(to: self.frame.size) self.markForRenderWholeView() self.eventsSubject.onNext(.guifontChanged(newFont)) } diff --git a/NvimView/Sources/NvimView/NvimView+Resize.swift b/NvimView/Sources/NvimView/NvimView+Resize.swift index 184cfe23f..18aac6943 100644 --- a/NvimView/Sources/NvimView/NvimView+Resize.swift +++ b/NvimView/Sources/NvimView/NvimView+Resize.swift @@ -5,6 +5,7 @@ import Cocoa import RxSwift +import RxNeovim extension NvimView { override public func setFrameSize(_ newSize: NSSize) { @@ -13,6 +14,9 @@ extension NvimView { if self.isInitialResize { self.isInitialResize = false self.launchNeoVim(self.discreteSize(size: newSize)) + // FIXME: not clear why this is needed but otherwise + // grid is too large + self.resizeNeoVimUi(to: newSize) return } @@ -53,8 +57,7 @@ extension NvimView { self.offset.x = floor((size.width - self.cellSize.width * discreteSize.width.cgf) / 2) self.offset.y = floor((size.height - self.cellSize.height * discreteSize.height.cgf) / 2) - self.bridge - .resize(width: discreteSize.width, height: discreteSize.height) + self.api.uiTryResize(width: discreteSize.width, height: discreteSize.height) .subscribe(onError: { [weak self] error in self?.log.error("Error in \(#function): \(error)") }) @@ -63,28 +66,83 @@ extension NvimView { private func launchNeoVim(_ size: Size) { self.log.info("=== Starting neovim...") - let sockPath = URL(fileURLWithPath: NSTemporaryDirectory()) - .appendingPathComponent("vimr_\(self.uuid).sock").path + let sockPath = self.bridge.listenAddress self.log.info("NVIM_LISTEN_ADDRESS=\(sockPath)") + self.bridge.runLocalServerAndNvim(width: size.width, height: size.height) + + // FIXME: need to wait for listen to occur + Thread.sleep(forTimeInterval: 0.1) + // 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)) + try? + self.api.run(at: sockPath) .andThen( - self.sourceFileUrls.reduce(Completable.empty()) { prev, url in - prev - .andThen( - self.api.exec(src: "source \(url.shellEscapedPath)", output: true) - .asCompletable() - ) - } - ) - .andThen(self.api.subscribe(event: NvimView.rpcEventName)) - .wait() + self.api.getApiInfo().map({ + value in + guard let info = value.arrayValue, + info.count == 2, + let channel = info[0].int32Value + else { + throw RxNeovimApi.Error + .exception(message: "Could not convert values to api info.") + } + return channel + }).flatMapCompletable({ + // FIXME: make lua + self.api.exec2(src: """ + ":augroup vimr + ":augroup! + :autocmd VimEnter * call rpcnotify(\($0), 'autocommand', 'vimenter') + :autocmd BufWinEnter * call rpcnotify(\($0), 'autocommand', 'bufwinenter', str2nr(expand(''))) + :autocmd BufWinEnter * call rpcnotify(\($0), 'autocommand', 'bufwinleave', str2nr(expand(''))) + :autocmd TabEnter * call rpcnotify(\($0), 'autocommand', 'tabenter', str2nr(expand(''))) + :autocmd BufWritePost * call rpcnotify(\($0), 'autocommand', 'bufwritepost', str2nr(expand(''))) + :autocmd BufEnter * call rpcnotify(\($0), 'autocommand', 'bufenter', str2nr(expand(''))) + :autocmd DirChanged * call rpcnotify(\($0), 'autocommand', 'dirchanged', expand('')) + :autocmd ColorScheme * call rpcnotify(\($0), 'autocommand', 'colorscheme', \ + nvim_get_hl(0, {'id': hlID('Normal')}).fg, \ + nvim_get_hl(0, {'id': hlID('Normal')}).bg, \ + nvim_get_hl(0, {'id': hlID('Visual')}).fg, \ + nvim_get_hl(0, {'id': hlID('Visual')}).bg, \ + nvim_get_hl(0, {'id': hlID('Directory')}).fg) + :autocmd ExitPre * call rpcnotify(\($0), 'autocommand', 'exitpre') + :autocmd BufModifiedSet * call rpcnotify(\($0), 'autocommand', 'bufmodifiedset', \ + str2nr(expand('')), getbufinfo(str2nr(expand('')))[0].changed) + :let g:gui_vimr = 1 + ":augroup END + """, opts: [:]).asCompletable() + + + .andThen(self.api.uiAttach(width: size.width, height: size.height, options: [ + "ext_linegrid": true, + "ext_multigrid": false, + "rgb": true + ])) + .andThen( + self.sourceFileUrls.reduce(Completable.empty()) { prev, url in + prev + .andThen( + self.api.exec2(src: "source \(url.shellEscapedPath)", opts:["output": true]) + .map({ + retval in + guard let output_value = retval["output"] ?? retval["output"], + let output = output_value.stringValue + else { + throw RxNeovimApi.Error + .exception(message: "Could not convert values to output.") + } + return output + }) + .asCompletable() + ) + } + ) + }) + ).wait() } private func randomEmoji() -> String { diff --git a/NvimView/Sources/NvimView/NvimView+Types.swift b/NvimView/Sources/NvimView/NvimView+Types.swift index bfc21cb2f..5b357fa02 100644 --- a/NvimView/Sources/NvimView/NvimView+Types.swift +++ b/NvimView/Sources/NvimView/NvimView+Types.swift @@ -24,6 +24,7 @@ public extension NvimView { var usesCustomTabBar: Bool var useInteractiveZsh: Bool var cwd: URL + var nvimBinary: String var nvimArgs: [String]? var envDict: [String: String]? var sourceFiles: [URL] @@ -32,6 +33,7 @@ public extension NvimView { usesCustomTabBar: Bool, useInteractiveZsh: Bool, cwd: URL, + nvimBinary: String, nvimArgs: [String]?, envDict: [String: String]?, sourceFiles: [URL] @@ -39,6 +41,7 @@ public extension NvimView { self.usesCustomTabBar = usesCustomTabBar self.useInteractiveZsh = useInteractiveZsh self.cwd = cwd + self.nvimBinary = nvimBinary self.nvimArgs = nvimArgs self.envDict = envDict self.sourceFiles = sourceFiles diff --git a/NvimView/Sources/NvimView/NvimView+UiBridge.swift b/NvimView/Sources/NvimView/NvimView+UiBridge.swift index 62c4966b0..4becff591 100644 --- a/NvimView/Sources/NvimView/NvimView+UiBridge.swift +++ b/NvimView/Sources/NvimView/NvimView+UiBridge.swift @@ -28,43 +28,74 @@ extension NvimView { } final func resize(_ value: MessagePackValue) { - guard let array = MessagePackUtils.array( - from: value, ofSize: 2, conversion: { $0.intValue } - ) else { + guard let array = value.arrayValue + else { self.bridgeLogger.error("Could not convert \(value)") return } + guard array.count == 3 else { + self.bridgeLogger.error("Could not convert; wrong count: \(array)") + return + } - self.bridgeLogger.debug(array) + guard let grid = array[0].intValue, + let width = array[1].intValue, + let height = array[2].intValue + else{ + self.bridgeLogger.error("Could not convert; wrong count: \(array)") + return + } + // FIXME: this must happen immediately, or subsequent updates fail + self.ugrid.resize(Size(width: width, height: height)) gui.async { - self.ugrid.resize(Size(width: array[0], height: array[1])) self.markForRenderWholeView() } } + final func optionSet(_ values: [MessagePackValue]) { + var options : [MessagePackValue: MessagePackValue] = [:] + for index in 1.. CursorModeShape? in - guard let rawValue = v.intValue else { return nil } - return CursorModeShape(rawValue: UInt(rawValue)) - } - ) else { + guard let mainTuple = value.arrayValue, + mainTuple.count == 2, + let modeName = mainTuple[0].stringValue, + let modeIndex = mainTuple[1].uintValue + else { + self.bridgeLogger.error("Could not convert \(value)") + return + } + + guard let modeShape = CursorModeShape(rawValue: modeName), + self.modeInfos[modeName] != nil + else { self.bridgeLogger.error("Could not convert \(value)") return } gui.async { self.lastMode = self.mode - self.mode = mode + self.mode = modeShape self.bridgeLogger.debug("\(self.lastMode) -> \(self.mode)") self.handleInputMethodSource() @@ -78,67 +109,141 @@ extension NvimView { self.bridgeLogger.trace("modeInfoSet: \(value)") if let mainTuple = value.arrayValue, mainTuple.count == 2, - let modeInfoList = mainTuple[1].arrayValue?.map(ModeInfo.init(withMsgPackDict:)) + let modeInfoArray = mainTuple[1].arrayValue?.map({ + let modeInfo = ModeInfo.init(withMsgPackDict:$0) + return (modeInfo.name, modeInfo) + }) { - self.modeInfoList = modeInfoList + self.modeInfos = Dictionary( + uniqueKeysWithValues: modeInfoArray) } } - - final func flush(_ renderData: [MessagePackValue]) { + + final func renderData(_ renderData: [MessagePackValue]) { self.bridgeLogger.trace("# of render data: \(renderData.count)") gui.async { [self] in var (recompute, rowStart) = (false, Int.max) renderData.forEach { value in guard let renderEntry = value.arrayValue else { return } - guard renderEntry.count == 2 else { return } + guard renderEntry.count >= 2 else { return } - guard let rawType = renderEntry[0].intValue, - let innerArray = renderEntry[1].arrayValue, - let type = RenderDataType(rawValue: rawType) + guard let rawType = renderEntry[0].stringValue, + let innerArray = renderEntry[1].arrayValue else { self.bridgeLogger.error("Could not convert \(value)") return } - switch type { - case .rawLine: - let possibleNewRowStart = self.doRawLine(data: innerArray) - rowStart = min(rowStart, possibleNewRowStart) + switch rawType { + case "mode_change": + self.modeChange(renderEntry[1]) + + case "grid_line": + for index in 1.. 0, + let aucmd = array[0].stringValue?.lowercased(), + let event = NvimAutoCommandEvent(rawValue: aucmd) + else { + self.bridgeLogger.error("Could not convert \(array)") + return + } + + self.bridgeLogger.debug("\(event): \(array)") + + if event == .vimenter { + Completable + .empty() + .observe(on: SerialDispatchQueueScheduler(qos: .userInitiated)) + .andThen( + Completable.create { completable in + self.rpcEventSubscriptionCondition.wait(for: 5) + self.bridgeLogger.debug("RPC events subscription done.") + + completable(.completed) + return Disposables.create() + } + ) + .andThen( + { + let ginitPath = URL(fileURLWithPath: NSHomeDirectory()) + .appendingPathComponent(".config/nvim/ginit.vim").path + let loadGinit = FileManager.default.fileExists(atPath: ginitPath) + if loadGinit { + self.bridgeLogger.debug("Source'ing ginit.vim") + return self.api.command(command: "source \(ginitPath.shellEscapedPath)") + } else { + return .empty() + } + }() + ) + //.andThen(self.bridge.notifyReadinessForRpcEvents()) + .subscribe(onCompleted: { [weak self] in + self?.log.debug("Notified the NvimServer to fire GUIEnter") + }) + .disposed(by: self.disposeBag) + + return + } + + if event == .exitpre { + self.stop() return } - self.bridgeLogger.debug("\(event): \(array)") - - let bufferHandle = array[1] - - if event == .vimenter { - Completable - .empty() - .observe(on: SerialDispatchQueueScheduler(qos: .userInitiated)) - .andThen( - Completable.create { completable in - self.rpcEventSubscriptionCondition.wait(for: 5) - self.bridgeLogger.debug("RPC events subscription done.") + if event == .dirchanged { + guard array.count > 1, + array[1].stringValue != nil + else { + self.bridgeLogger.error("Could not convert \(array)") + return + } + self.cwdChanged(array[1]) + return + } - completable(.completed) - return Disposables.create() - } - ) - .andThen( - { - let ginitPath = URL(fileURLWithPath: NSHomeDirectory()) - .appendingPathComponent(".config/nvim/ginit.vim").path - let loadGinit = FileManager.default.fileExists(atPath: ginitPath) - if loadGinit { - self.bridgeLogger.debug("Source'ing ginit.vim") - return self.api.command(command: "source \(ginitPath.shellEscapedPath)") - } else { - return .empty() - } - }() - ) - .andThen(self.bridge.notifyReadinessForRpcEvents()) - .subscribe(onCompleted: { [weak self] in - self?.log.debug("Notified the NvimServer to fire GUIEnter") - }) - .disposed(by: self.disposeBag) + if event == .colorscheme { + self.colorSchemeChanged(MessagePackValue(Array(array[1.. 1, + let bufferHandle = array[1].intValue + else { + self.bridgeLogger.error("Could not convert \(array)") return } + if event == .bufmodifiedset { + guard array.count > 2 + else { + self.bridgeLogger.error("Could not convert \(array)") + return + } + self.setDirty(with: array[2]) + } + if event == .bufwinenter || event == .bufwinleave { self.bufferListChanged() } @@ -260,19 +399,37 @@ extension NvimView { }) } - private func doRawLine(data: [MessagePackValue]) -> Int { - guard data.count == 7 else { + private func doRawLineNu(data: [MessagePackValue]) -> Int { + guard data.count == 5 else { self.bridgeLogger.error("Could not convert; wrong count: \(data)") return Int.max } - guard let row = data[0].intValue, - let startCol = data[1].intValue, - let endCol = data[2].intValue, // past last index, but can be 0 - let clearCol = data[3].intValue, // past last index (can be 0?) - let clearAttr = data[4].intValue, - let chunk = data[5].arrayValue?.compactMap(\.stringValue), - let attrIds = data[6].arrayValue?.compactMap(\.intValue) + guard let grid = data[0].intValue, + let row = data[1].intValue, + let startCol = data[2].intValue, + let chunk = data[3].arrayValue?.compactMap({ + arg -> UUpdate? in + guard arg != nil, + let argArray = arg.arrayValue + else { + return nil + } + var string = "" + var attrId: Int? = nil + var repeats: Int? = nil + if (argArray.count > 0 && arg[0] != nil && arg[0]?.stringValue != nil) { + string = arg[0]!.stringValue! + } + if (argArray.count > 1 && arg[1] != nil && arg[1]?.intValue != nil) { + attrId = arg[1]!.intValue! + } + if (argArray.count > 2 && arg[2] != nil && arg[2]?.intValue != nil) { + repeats = arg[2]!.intValue! + } + return UUpdate(string: string, attrId: attrId, repeats: repeats) + }), + let wrap = data[4].boolValue else { self.bridgeLogger.error("Could not convert \(data)") return Int.max @@ -281,24 +438,15 @@ extension NvimView { #if TRACE self.bridgeLogger.debug( "row: \(row), startCol: \(startCol), endCol: \(endCol), " + - "clearCol: \(clearCol), clearAttr: \(clearAttr), " + - "chunk: \(chunk), attrIds: \(attrIds)" + "chunk: \(chunk)" ) #endif - let count = endCol - startCol - guard chunk.count == count, attrIds.count == count else { - self.bridgeLogger.error("The count of chunks and attrIds do not match.") - return Int.max - } - self.ugrid.update( + let count = chunk.count + let endCol = self.ugrid.updateNu( row: row, startCol: startCol, - endCol: endCol, - clearCol: clearCol, - clearAttr: clearAttr, - chunk: chunk, - attrIds: attrIds + chunk: chunk ) if count > 0 { @@ -324,12 +472,6 @@ extension NvimView { } } - if clearCol > endCol { - self.markForRender(region: Region( - top: row, bottom: row, left: endCol, right: max(endCol, clearCol - 1) - )) - } - return row } @@ -368,11 +510,11 @@ extension NvimView { return rowStart } - private func doScroll(_ array: [Int]) -> Int { - self.bridgeLogger.trace("[top, bot, left, right, rows, cols] = \(array)") + private func doScrollNu(_ array: [Int]) -> Int { + self.bridgeLogger.trace("[grid, top, bot, left, right, rows, cols] = \(array)") - let (top, bottom, left, right, rows, cols) - = (array[0], array[1] - 1, array[2], array[3] - 1, array[4], array[5]) + let (grid, top, bottom, left, right, rows, cols) + = (array[0], array[1], array[2] - 1, array[3], array[4] - 1, array[5], array[6]) let scrollRegion = Region( top: top, bottom: bottom, @@ -472,13 +614,13 @@ extension NvimView { } final func setDirty(with value: MessagePackValue) { - guard let dirty = value.boolValue else { + guard let dirty = value.intValue else { self.bridgeLogger.error("Could not convert \(value)") return } self.bridgeLogger.debug(dirty) - self.eventsSubject.onNext(.setDirtyStatus(dirty)) + self.eventsSubject.onNext(.setDirtyStatus(dirty == 1)) } final func rpcEventSubscribed() { @@ -486,6 +628,7 @@ extension NvimView { self.eventsSubject.onNext(.rpcEventSubscribed) } + // FIXME: convert to subprocess final func bridgeHasFatalError(_ value: MessagePackValue?) { gui.async { let alert = NSAlert() @@ -543,39 +686,78 @@ extension NvimView { self.bridgeLogger.error("Could not convert \(value)") return } - guard array.count == 6 else { + guard array.count == 4 else { self.bridgeLogger.error("Could not convert; wrong count \(value)") return } guard let id = array[0].intValue, - let rawTrait = array[1].uint64Value, - let fg = array[2].intValue, - let bg = array[3].intValue, - let sp = array[4].intValue, - let reverse = array[5].boolValue + let rgb_dict = array[1].dictionaryValue, + let cterm_dict = array[2].dictionaryValue, + let info = array[3].arrayValue else { self.bridgeLogger.error( "Could not get highlight attributes from " + - "\(value)" + "\(value)" ) return } - let trait = FontTrait(rawValue: UInt(rawTrait)) + let mapped_rgb_dict = rgb_dict.map({ + (key: MessagePackValue, value: MessagePackValue) in + (key.stringValue!, value) + }) + let rgb_attr = Dictionary( + uniqueKeysWithValues: mapped_rgb_dict) let attrs = CellAttributes( - fontTrait: trait, - foreground: fg, - background: bg, - special: sp, - reverse: reverse + withDict: rgb_attr, + with: CellAttributes(fontTrait: FontTrait(), foreground: -1, background: -1, special:-1, reverse: false) + //self.cellAttributesCollection.defaultAttributes ) self.bridgeLogger.debug("AttrId: \(id): \(attrs)") - gui.async { + // FIXME: seems to not work well unless not async + //gui.async { self.cellAttributesCollection.set(attributes: attrs, for: id) + //} + } + + final func defaultColors(with value: MessagePackValue) { + guard let array = value.arrayValue else { + self.bridgeLogger.error("Could not convert \(value)") + return } + guard array.count == 5 else { + self.bridgeLogger.error("Could not convert; wrong count \(value)") + return + } + + guard let rgb_fg = array[0].intValue, + let rgb_bg = array[1].intValue, + let rgb_sp = array[2].intValue, + let cterm_fg = array[3].intValue, + let cterm_bg = array[4].intValue + else { + self.bridgeLogger.error( + "Could not get default colors from " + + "\(value)" + ) + return + } + + let attrs = CellAttributes( + fontTrait: FontTrait(), foreground: rgb_fg, background: rgb_bg, special: rgb_sp, reverse: false) + + //gui.async { + self.cellAttributesCollection.set( + attributes: attrs, + for: CellAttributesCollection.defaultAttributesId + ) + self.layer?.backgroundColor = ColorUtils.cgColorIgnoringAlpha( + attrs.background + ) + //} } final func updateMenu() { @@ -614,17 +796,17 @@ extension NvimView { } final func markForRender(region: Region) { - self.bridgeLogger.trace(region) + self.bridgeLogger.debug(region) self.setNeedsDisplay(self.rect(for: region)) } final func markForRender(row: Int, column: Int) { - self.bridgeLogger.trace("\(row):\(column)") + self.bridgeLogger.debug("\(row):\(column)") self.setNeedsDisplay(self.rect(forRow: row, column: column)) } final func markForRender(position: Position) { - self.bridgeLogger.trace(position) + self.bridgeLogger.debug(position) self.setNeedsDisplay( self.rect(forRow: position.row, column: position.column) ) @@ -649,7 +831,31 @@ extension NvimView { gui.async { self.tabBar?.update(tabRepresentatives: self.tabEntries) } } - func winViewportUpdate(_: [MessagePackValue]) {} + + func winViewportUpdate(_ value: [MessagePackValue]) { + // FIXME + /* + guard let array = value.arrayValue, + array.count == 8 + else { + self.bridgeLogger.error("Could not convert \(value)") + return + } + guard let grid = array[0].intValue, + let top = array[2].intValue, + let bot = array[3].intValue, + let curline = array[4].intValue, + let curcol = array[5].intValue, + let linecount = array[6].intValue, + let scroll_delta = array[6].intValue + else { + self.bridgeLogger.error("Could not convert \(value)") + return + } + // [top, bot, left, right, rows, cols] + // FIXMEL self.doScroll([]) + */ + } private func bufferWritten(_ handle: Int) { self @@ -691,6 +897,15 @@ extension NvimView { self.eventsSubject.onNext(.bufferListChanged) self.updateTouchBarCurrentBuffer() } + + func focusGained(_ gained: Bool) -> Completable { + return self.api.uiSetFocus(gained: gained) + } + + func quit() -> Completable { + return self.api.command(command: ":q") + .andThen(self.bridge.quit()) + } } extension TISInputSource { diff --git a/NvimView/Sources/NvimView/NvimView.swift b/NvimView/Sources/NvimView/NvimView.swift index 3027c1cc0..4eca267c0 100644 --- a/NvimView/Sources/NvimView/NvimView.swift +++ b/NvimView/Sources/NvimView/NvimView.swift @@ -28,8 +28,6 @@ public protocol NvimViewDelegate: AnyObject { public final class NvimView: NSView, NSUserInterfaceValidations, NSTextInputClient { // MARK: - Public - public static let rpcEventName = "com.qvacua.NvimView" - public static let minFontSize = 4.0 public static let maxFontSize = 128.0 public static let defaultFont = NSFont.userFixedPitchFont(ofSize: 12)! @@ -52,8 +50,8 @@ public final class NvimView: NSView, NSUserInterfaceValidations, NSTextInputClie public let uuid = UUID() public let api = RxNeovimApi() - public internal(set) var mode = CursorModeShape.normal - public internal(set) var modeInfoList = [ModeInfo]() + public internal(set) var mode: CursorModeShape = .normal + public internal(set) var modeInfos = [String : ModeInfo]() public internal(set) var theme = Theme.default @@ -171,9 +169,14 @@ public final class NvimView: NSView, NSUserInterfaceValidations, NSTextInputClie switch msg { case let .notification(method, params): self?.log.debug("NOTIFICATION: \(method): \(params)") - - guard method == NvimView.rpcEventName else { return } - self?.eventsSubject.onNext(.rpcEvent(params)) + + if (method == "redraw") { + self?.renderData(params) + } else if (method == "autocommand") { + self?.autoCommandEventNu(params) + } else { + self?.log.debug("MSG ERROR: \(msg)") + } case let .error(_, msg): self?.log.debug("MSG ERROR: \(msg)") @@ -219,7 +222,6 @@ public final class NvimView: NSView, NSUserInterfaceValidations, NSTextInputClie .disposed(by: db) } - self.bridge.consumer = self self.registerForDraggedTypes([NSPasteboard.PasteboardType(String(kUTTypeFileURL))]) self.wantsLayer = true @@ -235,6 +237,7 @@ public final class NvimView: NSView, NSUserInterfaceValidations, NSTextInputClie usesCustomTabBar: true, useInteractiveZsh: false, cwd: URL(fileURLWithPath: NSHomeDirectory()), + nvimBinary: "", nvimArgs: nil, envDict: nil, sourceFiles: [] diff --git a/NvimView/Sources/NvimView/UGrid.swift b/NvimView/Sources/NvimView/UGrid.swift index 4c48b5851..2d58ace18 100644 --- a/NvimView/Sources/NvimView/UGrid.swift +++ b/NvimView/Sources/NvimView/UGrid.swift @@ -6,6 +6,18 @@ import Foundation import os +struct UUpdate: Codable { + var string: String + var attrId: Int? + var repeats: Int? + + init(string: String, attrId: Int? = nil, repeats: Int? = nil) { + self.string = string + self.attrId = attrId + self.repeats = repeats + } +} + struct UCell: Codable { var string: String var attrId: Int @@ -259,6 +271,40 @@ final class UGrid: CustomStringConvertible, Codable { } } + /// This does not recompute the flat char indices. For performance it's done + /// in NvimView.flush() + func updateNu( + row: Int, + startCol: Int, + chunk: [UUpdate] + ) -> Int { + // remove marked patch and recover after modified from vim + var oldMarkedInfo: MarkedInfo? + if row == self.markedInfo?.position.row { + oldMarkedInfo = self.popMarkedInfo() + } + defer { + if let oldMarkedInfo = oldMarkedInfo { + updateMarkedInfo(newValue: oldMarkedInfo) + } + } + var lastAttrId : Int = 0 + var column = startCol + for cindex in 0.. Completable { + func runLocalServerAndNvim(width: Int, height: Int) { self.initialWidth = width self.initialHeight = height - return self.server - .run(as: self.localServerName) - .andThen(Completable.create { completable in - self.runLocalServerAndNvimCompletable = completable - self.launchNvimUsingLoginShellEnv() - - // This will be completed in .nvimReady branch of handleMessage() - return Disposables.create() - }) - .timeout(.seconds(timeout), scheduler: self.scheduler) - } - - func deleteCharacters(_ count: Int, andInputEscapedString string: String) -> Completable { - guard let strData = string.data(using: .utf8) else { return .empty() } - - var data = Data(capacity: MemoryLayout.size + strData.count) - - var c = count - withUnsafeBytes(of: &c) { data.append(contentsOf: $0) } - data.append(strData) - - return self.sendMessage(msgId: .deleteInput, data: data) - } - - func resize(width: Int, height: Int) -> Completable { - self.sendMessage(msgId: .resize, data: [width, height].data()) - } - - func notifyReadinessForRpcEvents() -> Completable { - self.sendMessage(msgId: .readyForRpcEvents, data: nil) - } - - func focusGained(_ gained: Bool) -> Completable { - self.sendMessage(msgId: .focusGained, data: [gained].data()) - } - - func scroll(horizontal: Int, vertical: Int, at position: Position) -> Completable { - self.sendMessage( - msgId: .scroll, - data: [horizontal, vertical, position.row, position.column].data() - ) + self.launchNvimUsingLoginShellEnv() } func quit() -> Completable { - self.quit { + Completable.create { completable in self.nvimServerProc?.waitUntilExit() self.log.info("NvimServer \(self.uuid) exited successfully.") + return Disposables.create() } } func forceQuit() -> Completable { self.log.fault("Force-exiting NvimServer \(self.uuid).") - - return self.quit { + + return Completable.create { completable in self.forceExitNvimServer() self.log.fault("NvimServer \(self.uuid) was forcefully exited.") + return Disposables.create() } } - func debug() -> Completable { self.sendMessage(msgId: .debug1, data: nil) } - - private func handleMessage(msgId: Int32, data: Data?) { - guard let msg = NvimServerMsgId(rawValue: Int(msgId)) else { return } - - switch msg { - case .serverReady: - self - .establishNvimConnection() - .subscribe(onError: { [weak self] error in self?.consumer?.ipcBecameInvalid(error) }) - .disposed(by: self.disposeBag) - - case .nvimReady: - self.runLocalServerAndNvimCompletable?(.completed) - self.runLocalServerAndNvimCompletable = nil - - let isInitErrorPresent = MessagePackUtils - .value(from: data, conversion: { $0.boolValue }) ?? false - if isInitErrorPresent { self.consumer?.initVimError() } - - case .resize: - guard let v = MessagePackUtils.value(from: data) else { return } - self.consumer?.resize(v) - - case .clear: - self.consumer?.clear() - - case .setMenu: - self.consumer?.updateMenu() - - case .busyStart: - self.consumer?.busyStart() - - case .busyStop: - self.consumer?.busyStop() - - case .modeChange: - guard let v = MessagePackUtils.value(from: data) else { return } - self.consumer?.modeChange(v) - - case .modeInfoSet: - guard let v = MessagePackUtils.value(from: data) else { return } - self.consumer?.modeInfoSet(v) - - case .bell: - self.consumer?.bell() - - case .visualBell: - self.consumer?.visualBell() - - case .flush: - guard let d = data, let v = (try? unpackAll(d)) else { return } - self.consumer?.flush(v) - - case .setTitle: - guard let v = MessagePackUtils.value(from: data) else { return } - self.consumer?.setTitle(with: v) - - case .stop: - self.consumer?.stop() - - case .dirtyStatusChanged: - guard let v = MessagePackUtils.value(from: data) else { return } - self.consumer?.setDirty(with: v) - - case .cwdChanged: - guard let v = MessagePackUtils.value(from: data) else { return } - self.consumer?.cwdChanged(v) - - case .defaultColorsChanged: - guard let v = MessagePackUtils.value(from: data) else { return } - self.consumer?.defaultColorsChanged(v) - - case .colorSchemeChanged: - guard let v = MessagePackUtils.value(from: data) else { return } - self.consumer?.colorSchemeChanged(v) - - case .optionSet: - guard let v = MessagePackUtils.value(from: data) else { return } - self.consumer?.optionSet(v) - - case .autoCommandEvent: - guard let v = MessagePackUtils.value(from: data) else { return } - self.consumer?.autoCommandEvent(v) - - case .event: - guard let v = MessagePackUtils.value(from: data) else { return } - self.consumer?.event(v) - - case .debug1: - break - - case .highlightAttrs: - guard let v = MessagePackUtils.value(from: data) else { return } - self.consumer?.setAttr(with: v) - - case .rpcEventSubscribed: - self.consumer?.rpcEventSubscribed() - - case .fatalError: - self.consumer?.bridgeHasFatalError(MessagePackUtils.value(from: data)) - - @unknown default: - self.log.error("Unkonwn msg type from NvimServer") - } - } - - private func closePorts() -> Completable { - self.client - .stop() - .andThen(self.server.stop()) - } - - private func quit(using body: @escaping () -> Void) -> Completable { - self - .closePorts() - .andThen(Completable.create { completable in - body() - - completable(.completed) - return Disposables.create() - }) - } - - private func establishNvimConnection() -> Completable { - self.client - .connect(to: self.remoteServerName) - .andThen( - self - .sendMessage(msgId: .agentReady, data: [self.initialWidth, self.initialHeight].data()) - ) - } - - private func sendMessage(msgId: NvimBridgeMsgId, data: Data?) -> Completable { - self.client - .send(msgid: Int32(msgId.rawValue), data: data, expectsReply: false) - .asCompletable() - } - private func forceExitNvimServer() { self.nvimServerProc?.interrupt() self.nvimServerProc?.terminate() } private func launchNvimUsingLoginShellEnv() { - let listenAddress = URL(fileURLWithPath: NSTemporaryDirectory()) - .appendingPathComponent("vimr_\(self.uuid).sock") var env = self.envDict - env["VIMRUNTIME"] = Bundle.module.url(forResource: "runtime", withExtension: nil)!.path - env["NVIM_LISTEN_ADDRESS"] = listenAddress.path + env["NVIM_LISTEN_ADDRESS"] = self.listenAddress - self.log.debug("Socket: \(listenAddress.path)") + self.log.debug("Socket: \(self.listenAddress)") + // FIXME let usesCustomTabBarArg = self.usesCustomTabBar ? "1" : "0" + let inPipe = Pipe() let outPipe = Pipe() let errorPipe = Pipe() let process = Process() - process.environment = env + process.standardInput = inPipe process.standardError = errorPipe process.standardOutput = outPipe process.currentDirectoryPath = self.cwd.path - // We know that NvimServer is there. - process.launchPath = Bundle.module.url(forResource: "NvimServer", withExtension: nil)!.path + + if (self.nvimBinary != "" && + FileManager.default.fileExists(atPath: self.nvimBinary)) { + process.launchPath = self.nvimBinary + } else { + // We know that NvimServer is there. + env["VIMRUNTIME"] = Bundle.module.url(forResource: "runtime", withExtension: nil)!.path + process.launchPath = Bundle.module.url(forResource: "NvimServer", withExtension: nil)!.path + } + process.environment = env + process - .arguments = [self.localServerName, self.remoteServerName, usesCustomTabBarArg] + - ["--headless"] + self.nvimArgs + .arguments = + ["--embed", + "--listen", + self.listenAddress] + self.nvimArgs self.log.debug( - "Launching NvimServer with args: \(String(describing: process.arguments))" + "Launching NvimServer \(String(describing: process.launchPath)) with args: \(String(describing: process.arguments))" ) - process.launch() + do { + try process.run() + } catch { + return + } self.nvimServerProc = process } - // FIXME: GH-832 - private func launchNvimUsingLoginShell() { - let nvimCmd = [ - // We know that NvimServer is there. - Bundle.module.url(forResource: "NvimServer", withExtension: nil)!.path, - self.localServerName, - self.remoteServerName, - self.usesCustomTabBar ? "1" : "0", - "--headless", - ] + self.nvimArgs - - let listenAddress = FileManager.default.temporaryDirectory - .appendingPathComponent("vimr_\(self.uuid).sock") - let nvimEnv = [ - // We know that runtime is there. - "VIMRUNTIME": Bundle.module.url(forResource: "runtime", withExtension: nil)!.path, - "NVIM_LISTEN_ADDRESS": listenAddress.path, - ] - - self.nvimServerProc = ProcessUtils.execProcessViaLoginShell( - cmd: nvimCmd.map { "'\($0)'" }.joined(separator: " "), - cwd: self.cwd, - envs: nvimEnv, - interactive: self.interactive(for: ProcessUtils.loginShell()), - qos: .userInteractive - ) - } - private func interactive(for shell: URL) -> Bool { if shell.lastPathComponent == "zsh" { return self.usesInteractiveZsh } return true @@ -331,9 +130,7 @@ final class UiBridge { private let cwd: URL private let nvimArgs: [String] private let envDict: [String: String] - - private let server = RxMessagePortServer(queueQos: .userInteractive) - private let client = RxMessagePortClient(queueQos: .userInteractive) + private let nvimBinary: String private var nvimServerProc: Process? @@ -353,6 +150,11 @@ final class UiBridge { private var localServerName: String { "com.qvacua.NvimView.\(self.uuid)" } private var remoteServerName: String { "com.qvacua.NvimView.NvimServer.\(self.uuid)" } + + var listenAddress: String { + return URL(fileURLWithPath: NSTemporaryDirectory()) + .appendingPathComponent("vimr_\(self.uuid).sock").path + } } private let timeout = 5 diff --git a/RxPack/Sources/RxNeovim/RxNeovimApi.generated.swift b/RxPack/Sources/RxNeovim/RxNeovimApi.generated.swift index ab23bcf25..da4878662 100644 --- a/RxPack/Sources/RxNeovim/RxNeovimApi.generated.swift +++ b/RxPack/Sources/RxNeovim/RxNeovimApi.generated.swift @@ -1,4 +1,4 @@ -// Auto generated for nvim version 0.8.2. +// Auto generated for nvim version 0.9.2. // See bin/generate_api_methods.py import Foundation @@ -983,36 +983,6 @@ extension RxNeovimApi { .map(transform) } - public func bufGetInfo( - buffer: RxNeovimApi.Buffer, - errWhenBlocked: Bool = true - ) -> Single> { - - let params: [RxNeovimApi.Value] = [ - .int(Int64(buffer.handle)), - ] - - func transform(_ value: Value) throws -> Dictionary { - guard let result = (msgPackDictToSwift(value.dictionaryValue)) else { - throw RxNeovimApi.Error.conversion(type: Dictionary.self) - } - - return result - } - - if errWhenBlocked { - return self - .checkBlocked( - self.rpc(method: "nvim_buf_get_info", params: params, expectsReturnValue: true) - ) - .map(transform) - } - - return self - .rpc(method: "nvim_buf_get_info", params: params, expectsReturnValue: true) - .map(transform) - } - public func parseCmd( str: String, opts: Dictionary, @@ -1239,6 +1209,36 @@ extension RxNeovimApi { .map(transform) } + public func getOptionInfo( + name: String, + errWhenBlocked: Bool = true + ) -> Single> { + + let params: [RxNeovimApi.Value] = [ + .string(name), + ] + + func transform(_ value: Value) throws -> Dictionary { + guard let result = (msgPackDictToSwift(value.dictionaryValue)) else { + throw RxNeovimApi.Error.conversion(type: Dictionary.self) + } + + return result + } + + if errWhenBlocked { + return self + .checkBlocked( + self.rpc(method: "nvim_get_option_info", params: params, expectsReturnValue: true) + ) + .map(transform) + } + + return self + .rpc(method: "nvim_get_option_info", params: params, expectsReturnValue: true) + .map(transform) + } + public func createNamespace( name: String, errWhenBlocked: Bool = true @@ -1623,13 +1623,15 @@ extension RxNeovimApi { .map(transform) } - public func getOptionInfo( + public func getOptionInfo2( name: String, + opts: Dictionary, errWhenBlocked: Bool = true ) -> Single> { let params: [RxNeovimApi.Value] = [ .string(name), + .map(opts.mapToDict({ (Value.string($0), $1) })), ] func transform(_ value: Value) throws -> Dictionary { @@ -1643,13 +1645,13 @@ extension RxNeovimApi { if errWhenBlocked { return self .checkBlocked( - self.rpc(method: "nvim_get_option_info", params: params, expectsReturnValue: true) + self.rpc(method: "nvim_get_option_info2", params: params, expectsReturnValue: true) ) .map(transform) } return self - .rpc(method: "nvim_get_option_info", params: params, expectsReturnValue: true) + .rpc(method: "nvim_get_option_info2", params: params, expectsReturnValue: true) .map(transform) } @@ -2051,6 +2053,28 @@ extension RxNeovimApi { .asCompletable() } + public func uiSetFocus( + gained: Bool, + expectsReturnValue: Bool = false + ) -> Completable { + + let params: [RxNeovimApi.Value] = [ + .bool(gained), + ] + + if expectsReturnValue { + return self + .checkBlocked( + self.rpc(method: "nvim_ui_set_focus", params: params, expectsReturnValue: expectsReturnValue) + ) + .asCompletable() + } + + return self + .rpc(method: "nvim_ui_set_focus", params: params, expectsReturnValue: expectsReturnValue) + .asCompletable() + } + public func uiDetach( expectsReturnValue: Bool = false ) -> Completable { @@ -2196,20 +2220,18 @@ extension RxNeovimApi { .asCompletable() } - public func getHlByName( + public func getHlIdByName( name: String, - rgb: Bool, errWhenBlocked: Bool = true - ) -> Single> { + ) -> Single { let params: [RxNeovimApi.Value] = [ .string(name), - .bool(rgb), ] - func transform(_ value: Value) throws -> Dictionary { - guard let result = (msgPackDictToSwift(value.dictionaryValue)) else { - throw RxNeovimApi.Error.conversion(type: Dictionary.self) + func transform(_ value: Value) throws -> Int { + guard let result = ((value.int64Value == nil ? nil : Int(value.int64Value!))) else { + throw RxNeovimApi.Error.conversion(type: Int.self) } return result @@ -2218,25 +2240,25 @@ extension RxNeovimApi { if errWhenBlocked { return self .checkBlocked( - self.rpc(method: "nvim_get_hl_by_name", params: params, expectsReturnValue: true) + self.rpc(method: "nvim_get_hl_id_by_name", params: params, expectsReturnValue: true) ) .map(transform) } return self - .rpc(method: "nvim_get_hl_by_name", params: params, expectsReturnValue: true) + .rpc(method: "nvim_get_hl_id_by_name", params: params, expectsReturnValue: true) .map(transform) } - public func getHlById( - hl_id: Int, - rgb: Bool, + public func getHl( + ns_id: Int, + opts: Dictionary, errWhenBlocked: Bool = true ) -> Single> { let params: [RxNeovimApi.Value] = [ - .int(Int64(hl_id)), - .bool(rgb), + .int(Int64(ns_id)), + .map(opts.mapToDict({ (Value.string($0), $1) })), ] func transform(_ value: Value) throws -> Dictionary { @@ -2250,43 +2272,13 @@ extension RxNeovimApi { if errWhenBlocked { return self .checkBlocked( - self.rpc(method: "nvim_get_hl_by_id", params: params, expectsReturnValue: true) - ) - .map(transform) - } - - return self - .rpc(method: "nvim_get_hl_by_id", params: params, expectsReturnValue: true) - .map(transform) - } - - public func getHlIdByName( - name: String, - errWhenBlocked: Bool = true - ) -> Single { - - let params: [RxNeovimApi.Value] = [ - .string(name), - ] - - func transform(_ value: Value) throws -> Int { - guard let result = ((value.int64Value == nil ? nil : Int(value.int64Value!))) else { - throw RxNeovimApi.Error.conversion(type: Int.self) - } - - return result - } - - if errWhenBlocked { - return self - .checkBlocked( - self.rpc(method: "nvim_get_hl_id_by_name", params: params, expectsReturnValue: true) + self.rpc(method: "nvim_get_hl", params: params, expectsReturnValue: true) ) .map(transform) } return self - .rpc(method: "nvim_get_hl_id_by_name", params: params, expectsReturnValue: true) + .rpc(method: "nvim_get_hl", params: params, expectsReturnValue: true) .map(transform) } @@ -3968,49 +3960,20 @@ extension RxNeovimApi { .map(transform) } - public func getDirtyStatus( - errWhenBlocked: Bool = true - ) -> Single { - - let params: [RxNeovimApi.Value] = [ - - ] - - func transform(_ value: Value) throws -> Bool { - guard let result = (value.boolValue) else { - throw RxNeovimApi.Error.conversion(type: Bool.self) - } - - return result - } - - if errWhenBlocked { - return self - .checkBlocked( - self.rpc(method: "nvim_get_dirty_status", params: params, expectsReturnValue: true) - ) - .map(transform) - } - - return self - .rpc(method: "nvim_get_dirty_status", params: params, expectsReturnValue: true) - .map(transform) - } - - public func exec( + public func exec2( src: String, - output: Bool, + opts: Dictionary, errWhenBlocked: Bool = true - ) -> Single { + ) -> Single> { let params: [RxNeovimApi.Value] = [ .string(src), - .bool(output), + .map(opts.mapToDict({ (Value.string($0), $1) })), ] - func transform(_ value: Value) throws -> String { - guard let result = (value.stringValue) else { - throw RxNeovimApi.Error.conversion(type: String.self) + func transform(_ value: Value) throws -> Dictionary { + guard let result = (msgPackDictToSwift(value.dictionaryValue)) else { + throw RxNeovimApi.Error.conversion(type: Dictionary.self) } return result @@ -4019,13 +3982,13 @@ extension RxNeovimApi { if errWhenBlocked { return self .checkBlocked( - self.rpc(method: "nvim_exec", params: params, expectsReturnValue: true) + self.rpc(method: "nvim_exec2", params: params, expectsReturnValue: true) ) .map(transform) } return self - .rpc(method: "nvim_exec", params: params, expectsReturnValue: true) + .rpc(method: "nvim_exec2", params: params, expectsReturnValue: true) .map(transform) } diff --git a/RxPack/Sources/RxPack/RxMessagePort.swift b/RxPack/Sources/RxPack/RxMessagePort.swift deleted file mode 100644 index 8442b591c..000000000 --- a/RxPack/Sources/RxPack/RxMessagePort.swift +++ /dev/null @@ -1,268 +0,0 @@ -/// Tae Won Ha - http://taewon.de - @hataewon -/// See LICENSE - -import Foundation -import RxSwift - -public final class RxMessagePortClient { - public enum ResponseCode { - // Unfortunately, case success = kCFMessagePortSuccess is not possible. - case success - case sendTimeout - case receiveTimeout - case isInvalid - case transportError - case becameInvalidError - case unknown - - fileprivate init(rawResponseCode code: Int32) { - switch code { - case kCFMessagePortSuccess: self = .success - case kCFMessagePortSendTimeout: self = .sendTimeout - case kCFMessagePortReceiveTimeout: self = .receiveTimeout - case kCFMessagePortIsInvalid: self = .isInvalid - case kCFMessagePortTransportError: self = .transportError - case kCFMessagePortBecameInvalidError: self = .becameInvalidError - default: self = .unknown - } - } - } - - public enum Error: Swift.Error { - case serverInit - case clientInit - case portInvalid - case send(msgid: Int32, response: ResponseCode) - } - - public static let defaultTimeout = CFTimeInterval(5) - - public let uuid = UUID() - public var timeout = RxMessagePortClient.defaultTimeout - - public init(queueQos: DispatchQoS) { - self.queue = DispatchQueue( - label: "\(String(reflecting: RxMessagePortClient.self))-\(self.uuid.uuidString)", - qos: queueQos, - target: .global(qos: queueQos.qosClass) - ) - } - - public func send(msgid: Int32, data: Data?, expectsReply: Bool) -> Single { - Single.create { single in - self.queue.async { - guard CFMessagePortIsValid(self.port) else { - single(.failure(Error.portInvalid)) - return - } - - let returnDataPtr = UnsafeMutablePointer?>.allocate(capacity: 1) - defer { returnDataPtr.deallocate() } - - let responseCode = CFMessagePortSendRequest( - self.port, - msgid, - data?.cfdata, - self.timeout, - self.timeout, - expectsReply ? CFRunLoopMode.defaultMode.rawValue : nil, - expectsReply ? returnDataPtr : nil - ) - - guard responseCode == kCFMessagePortSuccess else { - single(.failure( - Error.send(msgid: msgid, response: ResponseCode(rawResponseCode: responseCode)) - )) - return - } - - guard expectsReply else { - single(.success(nil)) - return - } - - // Upon return, [returnData] contains a CFData object - // containing the reply data. Ownership follows the The Create Rule. - // From: https://developer.apple.com/documentation/corefoundation/1543076-cfmessageportsendrequest - // This means that we have to release the returned CFData. - // Thus, we have to use Unmanaged.takeRetainedValue() - // See also https://www.mikeash.com/pyblog/friday-qa-2017-08-11-swiftunmanaged.html - let data: Data? = returnDataPtr.pointee?.takeRetainedValue().data - single(.success(data)) - } - - return Disposables.create() - } - } - - public func connect(to name: String) -> Completable { - Completable.create { completable in - self.queue.async { - self.port = CFMessagePortCreateRemote(kCFAllocatorDefault, name.cfstr) - - if self.port == nil { - completable(.error(Error.clientInit)) - return - } - - completable(.completed) - } - - return Disposables.create() - } - } - - public func stop() -> Completable { - Completable.create { completable in - self.queue.async { - if self.port != nil, CFMessagePortIsValid(self.port) { - CFMessagePortInvalidate(self.port) - } - completable(.completed) - } - - return Disposables.create() - } - } - - private var port: CFMessagePort? - - private let queue: DispatchQueue -} - -public final class RxMessagePortServer { - public typealias SyncReplyBody = (Int32, Data?) -> Data? - - public struct Message { - public var msgid: Int32 - public var data: Data? - } - - public let uuid = UUID() - - public var syncReplyBody: SyncReplyBody? { - get { self.messageHandler.syncReplyBody } - set { self.messageHandler.syncReplyBody = newValue } - } - - public var stream: Observable { self.streamSubject.asObservable() } - - public init(queueQos: DispatchQoS) { - self.queue = DispatchQueue( - label: "\(String(reflecting: RxMessagePortClient.self))-\(self.uuid.uuidString)", - qos: queueQos, - target: .global(qos: queueQos.qosClass) - ) - self.messageHandler = MessageHandler(subject: self.streamSubject) - - self.portQueue = DispatchQueue( - label: "\(String(reflecting: RxMessagePortClient.self))-portQueue-\(self.uuid.uuidString)", - qos: queueQos - ) - } - - public func run(as name: String) -> Completable { - Completable.create { [unowned self] completable in - self.queue.async { - var localCtx = CFMessagePortContext( - version: 0, - info: Unmanaged.passUnretained(self.messageHandler).toOpaque(), - retain: nil, - release: nil, - copyDescription: nil - ) - - self.port = CFMessagePortCreateLocal( - kCFAllocatorDefault, - name.cfstr, - { _, msgid, data, info in - guard let infoPtr = UnsafeRawPointer(info) else { return nil } - - let handler = Unmanaged.fromOpaque(infoPtr).takeUnretainedValue() - return handler.handleMessage(msgId: msgid, cfdata: data) - }, - &localCtx, - nil - ) - - if self.port == nil { - self.streamSubject.onError(RxMessagePortClient.Error.serverInit) - completable(.error(RxMessagePortClient.Error.serverInit)) - } - - self.portQueue.async { self.runServer() } - completable(.completed) - } - - return Disposables.create() - } - } - - public func stop() -> Completable { - Completable.create { completable in - self.queue.async { - self.messageHandler.syncReplyBody = nil - self.streamSubject.onCompleted() - - if let portRunLoop = self.portRunLoop { CFRunLoopStop(portRunLoop) } - - if self.port != nil, CFMessagePortIsValid(self.port) { - CFMessagePortInvalidate(self.port) - } - - completable(.completed) - } - - return Disposables.create() - } - } - - private var port: CFMessagePort? - private let portQueue: DispatchQueue - private var portRunLoop: CFRunLoop? - - private let queue: DispatchQueue - - private var messageHandler: MessageHandler - private let streamSubject = PublishSubject() - - private func runServer() { - self.portRunLoop = CFRunLoopGetCurrent() - let runLoopSrc = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, self.port, 0) - CFRunLoopAddSource(self.portRunLoop, runLoopSrc, .defaultMode) - CFRunLoopRun() - } -} - -private class MessageHandler { - fileprivate var syncReplyBody: RxMessagePortServer.SyncReplyBody? - - fileprivate init(subject: PublishSubject) { self.subject = subject } - - fileprivate func handleMessage(msgId: Int32, cfdata: CFData?) -> Unmanaged? { - let d = cfdata?.data - - self.subject.onNext(RxMessagePortServer.Message(msgid: msgId, data: d)) - - guard let reply = self.syncReplyBody?(msgId, d) else { return nil } - - // The system releases the returned CFData object. - // From https://developer.apple.com/documentation/corefoundation/cfmessageportcallback - // See also https://www.mikeash.com/pyblog/friday-qa-2017-08-11-swiftunmanaged.html - return Unmanaged.passRetained(reply.cfdata) - } - - private let subject: PublishSubject -} - -private extension Data { - var cfdata: CFData { self as NSData } -} - -private extension CFData { - var data: Data { self as NSData as Data } -} - -private extension String { - var cfstr: CFString { self as NSString } -} diff --git a/RxPack/Support/RxPackSupport.xcodeproj/project.pbxproj b/RxPack/Support/RxPackSupport.xcodeproj/project.pbxproj index f4961b6d3..6e7e1b95f 100644 --- a/RxPack/Support/RxPackSupport.xcodeproj/project.pbxproj +++ b/RxPack/Support/RxPackSupport.xcodeproj/project.pbxproj @@ -3,13 +3,12 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 4B022661224AB1490052362B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4B022660224AB1490052362B /* Assets.xcassets */; }; 4B022664224AB1490052362B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B022662224AB1490052362B /* MainMenu.xib */; }; - 4B2AD136293BC0C4009DA797 /* RxMessagePort.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2AD135293BC0C4009DA797 /* RxMessagePort.swift */; }; 4B2AD13B293BCC4E009DA797 /* RxPack in Frameworks */ = {isa = PBXBuildFile; productRef = 4B2AD13A293BCC4E009DA797 /* RxPack */; }; 4B7FBFD024EC8632002D12A1 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 4B7FBFCF24EC8632002D12A1 /* RxSwift */; }; 4B7FBFD124EC8851002D12A1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B02265E224AB1490052362B /* AppDelegate.swift */; }; @@ -34,7 +33,6 @@ 4B022660224AB1490052362B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 4B022663224AB1490052362B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 4B022665224AB1490052362B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 4B2AD135293BC0C4009DA797 /* RxMessagePort.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RxMessagePort.swift; path = ../Sources/RxPack/RxMessagePort.swift; sourceTree = ""; }; 4BE73FA8285DC4DA00B63585 /* RxPack */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = RxPack; path = ..; sourceTree = ""; }; /* End PBXFileReference section */ @@ -54,7 +52,6 @@ 4B02263A224AB11A0052362B = { isa = PBXGroup; children = ( - 4B2AD135293BC0C4009DA797 /* RxMessagePort.swift */, 4BE73FA7285DC4DA00B63585 /* Packages */, 4B02265D224AB1490052362B /* RxMessagePortDemo */, 4B022644224AB11A0052362B /* Products */, @@ -174,7 +171,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4B2AD136293BC0C4009DA797 /* RxMessagePort.swift in Sources */, 4B7FBFD124EC8851002D12A1 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/bin/generate_autocmds.py b/bin/generate_autocmds.py index d1449cfff..9044842dc 100755 --- a/bin/generate_autocmds.py +++ b/bin/generate_autocmds.py @@ -25,7 +25,7 @@ def swift_autocmds(version: str, template_string: str) -> str: return template.substitute( event_cases="\n".join( - [f" case {event[0].lower()} = {event[1]}" for event in autocmds] + [f" case {event[0].lower()} = \"{event[0].lower()}\"" for event in autocmds] ), version=version ) diff --git a/bin/generate_cursor_shape.py b/bin/generate_cursor_shape.py index 6ceee61d6..d4d1cb3b3 100755 --- a/bin/generate_cursor_shape.py +++ b/bin/generate_cursor_shape.py @@ -46,7 +46,7 @@ def are_shapes_same() -> bool: def swift_shapes() -> str: with io.open(SWIFT_TEMPLATE_FILE, "r") as template_file: template = Template(template_file.read()) - cases = "\n".join([f" case {v[1]} = {v[0]}" for (k, v) in SHAPE_NAMES.items()]) + cases = "\n".join([f" case {v[1]} = \"{v[1]}\"" for (k, v) in SHAPE_NAMES.items()]) return template.substitute( cursor_shapes=cases, version=version diff --git a/resources/autocmds.template.swift b/resources/autocmds.template.swift index 722fe6376..780084e9d 100644 --- a/resources/autocmds.template.swift +++ b/resources/autocmds.template.swift @@ -1,7 +1,7 @@ // Auto generated for nvim ${version} // See bin/generate_autocmds.py -enum NvimAutoCommandEvent: Int { +enum NvimAutoCommandEvent: String { ${event_cases} } diff --git a/resources/cursor_shape.template.swift b/resources/cursor_shape.template.swift index c96c829ff..5cac8759a 100644 --- a/resources/cursor_shape.template.swift +++ b/resources/cursor_shape.template.swift @@ -1,8 +1,7 @@ // Auto generated for nvim ${version} // See bin/generate_cursor_shape.py -public enum CursorModeShape: UInt { +public enum CursorModeShape: String { ${cursor_shapes} } - From 774f531608b9b2f4a8015d7ea6f51c241ca6fe17 Mon Sep 17 00:00:00 2001 From: George Harker Date: Sun, 29 Oct 2023 13:50:52 -0700 Subject: [PATCH 06/33] readme and ignores --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 2617c85bf..4489408d3 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,18 @@ ![Screenshot 1](https://raw.githubusercontent.com/qvacua/vimr/develop/resources/screenshot1.png) ![Screenshot 2](https://raw.githubusercontent.com/qvacua/vimr/develop/resources/screenshot2.png) +## Fork differences + +Originially and wonderfully by [qvacua](https://github.com/qvacua/) which appears to be unsupported any more. + +This version can talk to an arbitrary nvim (once the upstream bits get merged) +It therefore should be able to keep pace with nvim development better. Work was done to avoid +having to modify neovim, and the uibridge mechanism has been replaced with api calls. + ## About Project VimR is a Neovim GUI for macOS. + The goal is to build an editor that uses Neovim inside with many of the convenience GUI features similar to those present in modern editors. We mainly use Swift, but also use C/Objective-C when where appropriate. From dff45d951f1e4ee67e08b3a5e053aff034f71826 Mon Sep 17 00:00:00 2001 From: George Harker Date: Sun, 29 Oct 2023 14:30:28 -0700 Subject: [PATCH 07/33] gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index b55cc4751..da01c53f7 100644 --- a/.gitignore +++ b/.gitignore @@ -179,3 +179,5 @@ Temporary Items .deps tags.* +/RxPack/.build +/Workspace/.swiftpm From 5c1f97e1547f0724e10f1a22106e102f95d7daab Mon Sep 17 00:00:00 2001 From: George Harker Date: Sun, 29 Oct 2023 14:32:11 -0700 Subject: [PATCH 08/33] use upstream mods for neovim --- NvimServer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NvimServer b/NvimServer index 2143e16ef..7162a5572 160000 --- a/NvimServer +++ b/NvimServer @@ -1 +1 @@ -Subproject commit 2143e16ef20eb45fe29b726294a6549623f94424 +Subproject commit 7162a5572f51fa8dfee27ad5d6e899f2e397ce40 From 013110e6619f1ef8980bb7098797258be0313d6c Mon Sep 17 00:00:00 2001 From: George Harker Date: Sun, 29 Oct 2023 14:34:40 -0700 Subject: [PATCH 09/33] bump nvim server --- NvimServer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NvimServer b/NvimServer index 7162a5572..8dc07ee69 160000 --- a/NvimServer +++ b/NvimServer @@ -1 +1 @@ -Subproject commit 7162a5572f51fa8dfee27ad5d6e899f2e397ce40 +Subproject commit 8dc07ee690310ea5102ae6f64abd05a649eb97ed From ae221d3e3d7acdc98246f1db70c2293cbf2c8c2a Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 10:57:36 -0700 Subject: [PATCH 10/33] rename neovim submodule --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index d6053a5ce..010e023aa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "NvimServer"] +[submodule "Neovim"] path = NvimServer url = git@github.com:georgeharker/vimr-neovim.git From ba32d88eaf33f69f992e6c35d71e121f95954afc Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 10:57:58 -0700 Subject: [PATCH 11/33] rename neovim --- .gitmodules | 2 +- NvimServer => Neovim | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename NvimServer => Neovim (100%) diff --git a/.gitmodules b/.gitmodules index 010e023aa..192c86874 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "Neovim"] - path = NvimServer + path = Neovim url = git@github.com:georgeharker/vimr-neovim.git diff --git a/NvimServer b/Neovim similarity index 100% rename from NvimServer rename to Neovim From acc932808242ac06ce33aaafe0f470d47a4cdb59 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 13:25:04 -0700 Subject: [PATCH 12/33] update build requirements --- NvimServer/NvimServer/.gitignore | 3 + .../Resources/NvimServer.entitlements | 14 +++ .../NvimServer/Resources/buildInfo.json | 7 ++ .../NvimServer/Sources/NvimServerTypes.h | 1 + NvimServer/NvimServer/Sources/main.c | 1 + NvimServer/NvimServer/bin/.gitignore | 1 + NvimServer/NvimServer/bin/README.md | 86 +++++++++++++++++++ NvimServer/NvimServer/bin/build_libnvim.sh | 54 ++++++++++++ NvimServer/NvimServer/bin/build_nvimserver.sh | 26 ++++++ NvimServer/NvimServer/bin/build_runtime.sh | 38 ++++++++ NvimServer/NvimServer/bin/clean_all.sh | 18 ++++ NvimServer/NvimServer/bin/prepare_libintl.sh | 67 +++++++++++++++ NvimServer/NvimServer/neovim | 1 + .../NvimServerTypes/include/NvimServerTypes.h | 76 ++++++++++++++++ NvimServer/NvimServerTypes/stub.c | 6 ++ NvimServer/Package.swift | 58 +++++++++++++ NvimServer/README.md | 4 + NvimView/Sources/NvimView/UiBridge.swift | 1 - .../NvimViewSupport.xcodeproj/project.pbxproj | 10 ++- .../RxPackSupport.xcodeproj/project.pbxproj | 11 ++- .../xcshareddata/swiftpm/Package.resolved | 16 ++-- 21 files changed, 488 insertions(+), 11 deletions(-) create mode 100644 NvimServer/NvimServer/.gitignore create mode 100644 NvimServer/NvimServer/Resources/NvimServer.entitlements create mode 100644 NvimServer/NvimServer/Resources/buildInfo.json create mode 100644 NvimServer/NvimServer/Sources/NvimServerTypes.h create mode 120000 NvimServer/NvimServer/Sources/main.c create mode 100644 NvimServer/NvimServer/bin/.gitignore create mode 100644 NvimServer/NvimServer/bin/README.md create mode 100755 NvimServer/NvimServer/bin/build_libnvim.sh create mode 100755 NvimServer/NvimServer/bin/build_nvimserver.sh create mode 100755 NvimServer/NvimServer/bin/build_runtime.sh create mode 100755 NvimServer/NvimServer/bin/clean_all.sh create mode 100755 NvimServer/NvimServer/bin/prepare_libintl.sh create mode 120000 NvimServer/NvimServer/neovim create mode 100644 NvimServer/NvimServerTypes/include/NvimServerTypes.h create mode 100644 NvimServer/NvimServerTypes/stub.c create mode 100644 NvimServer/Package.swift create mode 100644 NvimServer/README.md diff --git a/NvimServer/NvimServer/.gitignore b/NvimServer/NvimServer/.gitignore new file mode 100644 index 000000000..61c274b8c --- /dev/null +++ b/NvimServer/NvimServer/.gitignore @@ -0,0 +1,3 @@ +.deps +third-party + diff --git a/NvimServer/NvimServer/Resources/NvimServer.entitlements b/NvimServer/NvimServer/Resources/NvimServer.entitlements new file mode 100644 index 000000000..068ae2801 --- /dev/null +++ b/NvimServer/NvimServer/Resources/NvimServer.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-executable-page-protection + + com.apple.security.cs.disable-library-validation + + + diff --git a/NvimServer/NvimServer/Resources/buildInfo.json b/NvimServer/NvimServer/Resources/buildInfo.json new file mode 100644 index 000000000..dc0416774 --- /dev/null +++ b/NvimServer/NvimServer/Resources/buildInfo.json @@ -0,0 +1,7 @@ +{ + "deploymentTarget": "10.15", + "gettext": { + "arm64BottleTag": "arm64_ventura", + "x86_64BottleTag": "ventura" + } +} diff --git a/NvimServer/NvimServer/Sources/NvimServerTypes.h b/NvimServer/NvimServer/Sources/NvimServerTypes.h new file mode 100644 index 000000000..077097623 --- /dev/null +++ b/NvimServer/NvimServer/Sources/NvimServerTypes.h @@ -0,0 +1 @@ +../../NvimServerTypes/Sources/include/NvimServerTypes.h diff --git a/NvimServer/NvimServer/Sources/main.c b/NvimServer/NvimServer/Sources/main.c new file mode 120000 index 000000000..12b15b886 --- /dev/null +++ b/NvimServer/NvimServer/Sources/main.c @@ -0,0 +1 @@ +../../../Neovim/src/nvim/main.c \ No newline at end of file diff --git a/NvimServer/NvimServer/bin/.gitignore b/NvimServer/NvimServer/bin/.gitignore new file mode 100644 index 000000000..485dee64b --- /dev/null +++ b/NvimServer/NvimServer/bin/.gitignore @@ -0,0 +1 @@ +.idea diff --git a/NvimServer/NvimServer/bin/README.md b/NvimServer/NvimServer/bin/README.md new file mode 100644 index 000000000..0f0e72bb3 --- /dev/null +++ b/NvimServer/NvimServer/bin/README.md @@ -0,0 +1,86 @@ +## How to develop + +First, clean everything + +``` +$ ./bin/clean_all.sh +``` + +Then, build `libnvim` once with dependencies + +``` +$ target=x86_64 build_deps=true ./bin/build_libnvim.sh +``` + +After editing the code of neovim or NvimServer, you build NvimServer in Xcode or by executing +the following: + +``` +$ target="${ARCH}" build_deps=false build_dir="${PROJECT_ROOT}/NvimServer/build" \ + ./bin/build_nvimserver.sh +``` + +where `${ARCH}` is either `arm64` or `x86_64`. +We use `${PROJECT_ROOT}/NvimServer/build` as the NvimServer target assumes that location. + +## How to release + +``` +$ ./bin/build_release.sh +``` + +The resulting package will be in `${PROJECT_ROOT}/NvimServer/build/NvimServer.tar.bz2`. + +## Individual steps + +In the following the `target` variable can be either `x86_64` or `arm64`. + +### How to build `libintl` + +``` +$ ./bin/build_deps.sh +``` + +which will result in + +``` +${PROJECT_ROOT} + NvimServer + third-party + lib + liba + libb + ... + include + a.h + b.h + ... + x86_64 + lib + liba + libb + include + a.h + b.h +``` + +Files, e.g. `lib` and `include`, in `${PROJECT_ROOT}/NvimServer/third-party` are used to build +`libnvim` and NvimServer. + +### How to build `libnvim` + +``` +$ build_deps=true ./bin/build_libnvim.sh +``` + +When `build_deps` is `true`, then the `build_deps.sh` is executed. The resuling library will be +located in `/build/lib/libnvim.a`. + +### how to build NvimServer + +``` +$ build_dir="${some_dir}" build_libnvim=true build_deps=true ./bin/build_nvimserver.sh +``` + +The `build_libnvim.sh` script is executed automatically with the given parameters. The resulting +binary will be located in `${some_dir}`. diff --git a/NvimServer/NvimServer/bin/build_libnvim.sh b/NvimServer/NvimServer/bin/build_libnvim.sh new file mode 100755 index 000000000..058ebdfba --- /dev/null +++ b/NvimServer/NvimServer/bin/build_libnvim.sh @@ -0,0 +1,54 @@ +#!/bin/bash +set -Eeuo pipefail + +readonly clean=${clean:?"true or false"} + +build_libnvim() { + local -r deployment_target=$1 + + # Brew's gettext does not get sym-linked to PATH + export PATH="/opt/homebrew/opt/gettext/bin:/usr/local/opt/gettext/bin:${PATH}" + + macos_flags="-DCMAKE_OSX_DEPLOYMENT_TARGET=${deployment_target} -DCMAKE_OSX_ARCHITECTURES=arm64\;x86_64" + + pushd ../Neovim + + # W/o setting MACOSX_DEPLOYMENT_TARGET, the dependencies have min. macOS set to the macOS you're on. + make \ + CMAKE_BUILD_TYPE=Release \ + SDKROOT="$(xcrun --show-sdk-path)" \ + MACOSX_DEPLOYMENT_TARGET="${deployment_target}" \ + CMAKE_EXTRA_FLAGS="" \ + DEPS_CMAKE_FLAGS="${macos_flags}" \ + libnvim nvim + + popd +} + +main() { + # This script is located in /NvimServer/bin and we have to go to / + echo "$(dirname "${BASH_SOURCE[0]}")/../../" + pushd "$(dirname "${BASH_SOURCE[0]}")/../../" >/dev/null + + echo "### Building libnvim" + local deployment_target + deployment_target=$(jq -r .deploymentTarget ./NvimServer/Resources/buildInfo.json) + readonly deployment_target + + if [[ "${clean}" == true ]]; then + pushd ../Neovim + make distclean + popd + + ./NvimServer/bin/prepare_libintl.sh + + fi + + build_libnvim "${deployment_target}" + + popd >/dev/null + echo "### Built libnvim" +} + +main + diff --git a/NvimServer/NvimServer/bin/build_nvimserver.sh b/NvimServer/NvimServer/bin/build_nvimserver.sh new file mode 100755 index 000000000..be2d4f6a8 --- /dev/null +++ b/NvimServer/NvimServer/bin/build_nvimserver.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -Eeuo pipefail + +declare -r -x clean=${clean:?"if true, will clean libnvim and nvimserver"} +readonly build_libnvim=${build_libnvim:?"true or false"} +readonly build_dir=${build_dir:-"./.build"} + +main() { + echo "### Building NvimServer" + # This script is located in /NvimServer/bin and we have to go to / + pushd "$(dirname "${BASH_SOURCE[0]}")/../.." >/dev/null + if [[ "${clean}" == true ]]; then + rm -rf "${build_dir}" + fi + + if [[ "${build_libnvim}" == true ]]; then + ./NvimServer/bin/build_libnvim.sh + fi + + swift build --arch arm64 --arch x86_64 -c release --product NvimServer + + popd >/dev/null + echo "### Built NvimServer" +} + +main diff --git a/NvimServer/NvimServer/bin/build_runtime.sh b/NvimServer/NvimServer/bin/build_runtime.sh new file mode 100755 index 000000000..e0c0a2fc3 --- /dev/null +++ b/NvimServer/NvimServer/bin/build_runtime.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -Eeuo pipefail + +readonly nvim_install_path=${nvim_install_path:?"where to install temp nvim"} + +build_runtime() { + local -r deployment_target=$1 + + echo "#### runtime in ${nvim_install_path}" + + echo "### Building nvim to get the complete runtime" + make \ + SDKROOT="$(xcrun --show-sdk-path)" \ + MACOSX_DEPLOYMENT_TARGET="${deployment_target}" \ + CMAKE_EXTRA_FLAGS="-DCMAKE_OSX_DEPLOYMENT_TARGET=${deployment_target} -DCUSTOM_UI=0 -DCMAKE_INSTALL_PREFIX=${nvim_install_path}" \ + DEPS_CMAKE_FLAGS="-DCMAKE_OSX_DEPLOYMENT_TARGET=${deployment_target}" \ + CMAKE_BUILD_TYPE="Release" \ + install + + echo "#### runtime is installed at ${nvim_install_path}/share/nvim/runtime" +} + +main() { + # This script is located in /NvimServer/bin and we have to go to / + pushd "$(dirname "${BASH_SOURCE[0]}")/../.." >/dev/null + + echo "### Building runtime" + local deployment_target + deployment_target=$(jq -r .deploymentTarget ./NvimServer/Resources/buildInfo.json) + readonly deployment_target + + build_runtime "${deployment_target}" + + popd >/dev/null + echo "### Built runtime" +} + +main diff --git a/NvimServer/NvimServer/bin/clean_all.sh b/NvimServer/NvimServer/bin/clean_all.sh new file mode 100755 index 000000000..1cf1d57e2 --- /dev/null +++ b/NvimServer/NvimServer/bin/clean_all.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -Eeuo pipefail + +readonly clean_deps=${clean_deps:-true} + +pushd "$(dirname "${BASH_SOURCE[0]}")/../.." >/dev/null + pushd ../Neovim + + rm -rf ./build + rm -rf ./.deps + make distclean + + popd + + if [[ "${clean_deps}" == true ]]; then + rm -rf ./NvimServer/build + fi +popd >/dev/null diff --git a/NvimServer/NvimServer/bin/prepare_libintl.sh b/NvimServer/NvimServer/bin/prepare_libintl.sh new file mode 100755 index 000000000..af937a1fc --- /dev/null +++ b/NvimServer/NvimServer/bin/prepare_libintl.sh @@ -0,0 +1,67 @@ +#!/bin/bash +set -Eeuo pipefail +shopt -s extglob + +main() { + # This script is located in /NvimServer/bin and we have to go to / + pushd "$(dirname "${BASH_SOURCE[0]}")/../.." >/dev/null + + rm -rf ./NvimServer/third-party + mkdir -p NvimServer/third-party + + local arm64_bottle + arm64_bottle=$(jq -r .gettext.arm64BottleTag ./NvimServer/Resources/buildInfo.json) + readonly arm64_bottle + + local x86_64_bottle + x86_64_bottle=$(jq -r .gettext.x86_64BottleTag ./NvimServer/Resources/buildInfo.json) + readonly x86_64_bottle + + pushd ./NvimServer/third-party >/dev/null + brew fetch --bottle-tag="${arm64_bottle}" gettext + brew fetch --bottle-tag="${x86_64_bottle}" gettext + brew fetch --bottle-tag="${x86_64_bottle}" lua + + local version; version=$(brew info gettext --json | jq -r ".[0].versions.stable"); readonly version + echo "### gettext version ${version}" + + local lua_version; lua_version=$(brew info lua --json | jq -r ".[0].versions.stable"); readonly version + echo "### gettext lua_version ${lua_version}" + + local temp_dir; temp_dir="$(mktemp -d)"; readonly temp_dir + echo "${temp_dir}" + + pushd "${temp_dir}" >/dev/null + mkdir "${arm64_bottle}" + pushd "${arm64_bottle}" >/dev/null + tar xf "$(brew --cache)"/**/*--gettext--+([0-9.])${arm64_bottle}*.tar.gz + tar xf "$(brew --cache)"/**/*--lua--+([0-9.])${arm64_bottle}*.tar.gz + popd >/dev/null + + mkdir "${x86_64_bottle}" + pushd "${x86_64_bottle}" >/dev/null + tar xf "$(brew --cache)"/**/*--gettext--+([0-9.])${x86_64_bottle}*.tar.gz + tar xf "$(brew --cache)"/**/*--lua--+([0-9.])${x86_64_bottle}*.tar.gz + popd >/dev/null + + mkdir universal + cp -r "${arm64_bottle}/gettext/${version}/include" ./universal/ + mkdir universal/lib + lipo "${arm64_bottle}/gettext/${version}/lib/libintl.a" "${x86_64_bottle}/gettext/${version}/lib/libintl.a" -create -output ./universal/lib/libintl.a + + mkdir universal_lua + cp -r "${arm64_bottle}/lua/${lua_version}/include" ./universal_lua/ + mkdir universal_lua/lib + lipo "${arm64_bottle}/lua/${lua_version}/lib/liblua.a" "${x86_64_bottle}/lua/${lua_version}/lib/liblua.a" -create -output ./universal_lua/lib/liblua.a + popd >/dev/null + + mv "${temp_dir}/universal" gettext + mv "${temp_dir}/universal_lua" lua + rm -rf "${temp_dir}" + + popd >/dev/null + + popd >/dev/null +} + +main diff --git a/NvimServer/NvimServer/neovim b/NvimServer/NvimServer/neovim new file mode 120000 index 000000000..9c4882f29 --- /dev/null +++ b/NvimServer/NvimServer/neovim @@ -0,0 +1 @@ +../../Neovim \ No newline at end of file diff --git a/NvimServer/NvimServerTypes/include/NvimServerTypes.h b/NvimServer/NvimServerTypes/include/NvimServerTypes.h new file mode 100644 index 000000000..5423e54df --- /dev/null +++ b/NvimServer/NvimServerTypes/include/NvimServerTypes.h @@ -0,0 +1,76 @@ +/** + * Tae Won Ha - http://taewon.de - @hataewon + * See LICENSE + */ + +#ifndef NVIMSERVER_SHARED_TYPES_H +#define NVIMSERVER_SHARED_TYPES_H + +#include + +#define NSInteger long +#define NSUInteger unsigned long + +typedef CF_OPTIONS(NSUInteger, FontTrait) { + FontTraitNone = 0, + FontTraitItalic = (1 << 0), + FontTraitBold = (1 << 1), + FontTraitUnderline = (1 << 2), + FontTraitUndercurl = (1 << 3) +}; + +typedef CF_ENUM(NSInteger, RenderDataType) { + RenderDataTypeRawLine, + RenderDataTypeGoto, + RenderDataTypeScroll, +}; + +typedef CF_ENUM(NSInteger, NvimServerMsgId) { + NvimServerMsgIdServerReady = 0, + NvimServerMsgIdNvimReady, + NvimServerMsgIdResize, + NvimServerMsgIdClear, + NvimServerMsgIdSetMenu, + NvimServerMsgIdBusyStart, + NvimServerMsgIdBusyStop, + NvimServerMsgIdModeChange, + NvimServerMsgIdModeInfoSet, + NvimServerMsgIdBell, + NvimServerMsgIdVisualBell, + NvimServerMsgIdFlush, + NvimServerMsgIdHighlightAttrs, + NvimServerMsgIdSetTitle, + NvimServerMsgIdStop, + NvimServerMsgIdOptionSet, + NvimServerMsgIdEvent, + + NvimServerMsgIdDirtyStatusChanged, + NvimServerMsgIdCwdChanged, + NvimServerMsgIdColorSchemeChanged, + NvimServerMsgIdDefaultColorsChanged, + NvimServerMsgIdAutoCommandEvent, + NvimServerMsgIdRpcEventSubscribed, + + NvimServerMsgIdFatalError, + + NvimServerMsgIdDebug1, +}; + +typedef CF_ENUM(NSInteger, NvimServerFatalErrorCode) { + NvimServerFatalErrorCodeLocalPort = 1, + NvimServerFatalErrorCodeRemotePort, +}; + +typedef CF_ENUM(NSInteger, NvimBridgeMsgId) { + NvimBridgeMsgIdAgentReady = 0, + NvimBridgeMsgIdReadyForRpcEvents, + NvimBridgeMsgIdDeleteInput, + NvimBridgeMsgIdResize, + NvimBridgeMsgIdScroll, + + NvimBridgeMsgIdFocusGained, + + NvimBridgeMsgIdDebug1, +}; + +#endif // NVIMSERVER_SHARED_TYPES_H diff --git a/NvimServer/NvimServerTypes/stub.c b/NvimServer/NvimServerTypes/stub.c new file mode 100644 index 000000000..a7ed817c9 --- /dev/null +++ b/NvimServer/NvimServerTypes/stub.c @@ -0,0 +1,6 @@ +/** + * Tae Won Ha - http://taewon.de - @hataewon + * See LICENSE + */ + +// SwiftPM requires at least one c source file, which can be empty. diff --git a/NvimServer/Package.swift b/NvimServer/Package.swift new file mode 100644 index 000000000..13651a762 --- /dev/null +++ b/NvimServer/Package.swift @@ -0,0 +1,58 @@ +// swift-tools-version:5.6 + +import PackageDescription + +let package = Package( + name: "NvimServer", + platforms: [.macOS(.v10_15)], + products: [ + .library(name: "NvimServerTypes", targets: ["NvimServerTypes"]), + ], + dependencies: [], + targets: [ + .target(name: "NvimServerTypes", dependencies: [], path: "NvimServerTypes"), + .executableTarget( + name: "NvimServer", + dependencies: [], + path: "NvimServer/Sources", + cSettings: [ + // Otherwise we get typedef redefinition error due to double definition of Boolean + .unsafeFlags(["-fno-modules"]), + .define("INCLUDE_GENERATED_DECLARATIONS", to: "1"), + // The target folder is the working directory. + .headerSearchPath("../../NvimServer/neovim/src"), + .headerSearchPath("../../NvimServer/neovim/build/include"), + .headerSearchPath("../../NvimServer/neovim/.deps/usr/include"), + .headerSearchPath("../../NvimServer/neovim/build/cmake.config"), + .headerSearchPath("../../NvimServer/neovim/build/src/nvim/auto/"), + .headerSearchPath("../../NvimServer/third-party/gettext/include"), + .headerSearchPath("../../NvimServer/third-party/lua/include/lua"), + ], + linkerSettings: [ + .linkedFramework("CoreServices"), + .linkedFramework("CoreFoundation"), + .linkedLibrary("util"), + .linkedLibrary("m"), + .linkedLibrary("dl"), + .linkedLibrary("pthread"), + .linkedLibrary("iconv"), + .unsafeFlags([ + // These paths seem to depend on where swift build is executed. Xcode does it in the + // folder where Package.swift is located. + "../neovim/build/lib/libnvim.a", + "../neovim/.deps/usr/lib/libmsgpack-c.a", + "../neovim/.deps/usr/lib/libluv.a", + "../neovim/.deps/usr/lib/liblpeg.a", + "../neovim/.deps/usr/lib/libtermkey.a", + "../neovim/.deps/usr/lib/libuv.a", + "../neovim/.deps/usr/lib/libunibilium.a", + "../neovim/.deps/usr/lib/libvterm.a", + "../neovim/.deps/usr/lib/libluajit-5.1.a", + "../neovim/.deps/usr/lib/libtree-sitter.a", + "NvimServer/third-party/gettext/lib/libintl.a", + ]), + ] + ), + ], + cLanguageStandard: .gnu99 +) diff --git a/NvimServer/README.md b/NvimServer/README.md new file mode 100644 index 000000000..93b671334 --- /dev/null +++ b/NvimServer/README.md @@ -0,0 +1,4 @@ +# NvimServerTypes + +This is a package to provider some types of NvimServer that are used in NvimView. +It consists of just one header file. Since SwiftPM requires at least a C file, we included an empty C file. diff --git a/NvimView/Sources/NvimView/UiBridge.swift b/NvimView/Sources/NvimView/UiBridge.swift index 57853054c..d6e6b748b 100644 --- a/NvimView/Sources/NvimView/UiBridge.swift +++ b/NvimView/Sources/NvimView/UiBridge.swift @@ -6,7 +6,6 @@ import Commons import Foundation import MessagePack -import NvimServerTypes import os import RxPack import RxSwift diff --git a/NvimView/Support/NvimViewSupport.xcodeproj/project.pbxproj b/NvimView/Support/NvimViewSupport.xcodeproj/project.pbxproj index 99767cda1..c887f1e18 100644 --- a/NvimView/Support/NvimViewSupport.xcodeproj/project.pbxproj +++ b/NvimView/Support/NvimViewSupport.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ @@ -339,6 +339,7 @@ packageReferences = ( 4BD67C9524ECF4AB00147C51 /* XCRemoteSwiftPackageReference "MessagePack" */, 4BD67CCF24ED08CB00147C51 /* XCRemoteSwiftPackageReference "PureLayout" */, + 1FF017012AF02F64003D62BB /* XCLocalSwiftPackageReference "../../NvimServer" */, ); productRefGroup = 4B90F0051FD2AF59008A39E0 /* Products */; projectDirPath = ""; @@ -754,6 +755,13 @@ }; /* End XCConfigurationList section */ +/* Begin XCLocalSwiftPackageReference section */ + 1FF017012AF02F64003D62BB /* XCLocalSwiftPackageReference "../../NvimServer" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = ../../NvimServer; + }; +/* End XCLocalSwiftPackageReference section */ + /* Begin XCRemoteSwiftPackageReference section */ 4BD67C9524ECF4AB00147C51 /* XCRemoteSwiftPackageReference "MessagePack" */ = { isa = XCRemoteSwiftPackageReference; diff --git a/RxPack/Support/RxPackSupport.xcodeproj/project.pbxproj b/RxPack/Support/RxPackSupport.xcodeproj/project.pbxproj index 6e7e1b95f..b49437aa6 100644 --- a/RxPack/Support/RxPackSupport.xcodeproj/project.pbxproj +++ b/RxPack/Support/RxPackSupport.xcodeproj/project.pbxproj @@ -124,8 +124,9 @@ 4B02263B224AB11A0052362B /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1020; - LastUpgradeCheck = 1340; + LastUpgradeCheck = 1500; ORGANIZATIONNAME = "Tae Won Ha"; TargetAttributes = { 4B02265B224AB1490052362B = { @@ -224,9 +225,11 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -287,9 +290,11 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = fast; @@ -314,11 +319,13 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; INFOPLIST_FILE = RxMessagePortDemo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.RxMessagePortDemo; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -330,11 +337,13 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; INFOPLIST_FILE = RxMessagePortDemo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.RxMessagePortDemo; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; diff --git a/VimR.xcworkspace/xcshareddata/swiftpm/Package.resolved b/VimR.xcworkspace/xcshareddata/swiftpm/Package.resolved index a7a705a8a..977a9f391 100644 --- a/VimR.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/VimR.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/mattgallagher/CwlCatchException.git", "state" : { - "revision" : "35f9e770f54ce62dd8526470f14c6e137cef3eea", - "version" : "2.1.1" + "revision" : "3b123999de19bf04905bc1dfdb76f817b0f2cc00", + "version" : "2.1.2" } }, { @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/mattgallagher/CwlPreconditionTesting.git", "state" : { - "revision" : "c21f7bab5ca8eee0a9998bbd17ca1d0eb45d4688", - "version" : "2.1.0" + "revision" : "a23ded2c91df9156628a6996ab4f347526f17b6b", + "version" : "2.1.2" } }, { @@ -86,8 +86,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/Quick/Nimble", "state" : { - "revision" : "b7f6c49acdb247e3158198c5448b38c3cc595533", - "version" : "11.2.1" + "revision" : "eb5e3d717224fa0d1f6aff3fc2c5e8e81fa1f728", + "version" : "11.2.2" } }, { @@ -131,8 +131,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2", - "version" : "1.0.4" + "revision" : "a902f1823a7ff3c9ab2fba0f992396b948eda307", + "version" : "1.0.5" } }, { From 2d7e3643d42bbb0b691f44ef8705ba63f85c4bcd Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 13:26:21 -0700 Subject: [PATCH 13/33] update ignores for swiftpm --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index da01c53f7..35f44eb2a 100644 --- a/.gitignore +++ b/.gitignore @@ -181,3 +181,5 @@ Temporary Items tags.* /RxPack/.build /Workspace/.swiftpm +.swiftpm +/NvimServer/.build From 7e7ad3428c88cfaeac0901deaa7c0e7412e3b352 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 13:26:41 -0700 Subject: [PATCH 14/33] update workspace --- VimR.xcworkspace/contents.xcworkspacedata | 3 --- 1 file changed, 3 deletions(-) diff --git a/VimR.xcworkspace/contents.xcworkspacedata b/VimR.xcworkspace/contents.xcworkspacedata index 88af7bc68..d21f5f792 100644 --- a/VimR.xcworkspace/contents.xcworkspacedata +++ b/VimR.xcworkspace/contents.xcworkspacedata @@ -16,9 +16,6 @@ - - From 690c5d12e0581305259643dfaee5985544afcfd1 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 13:31:51 -0700 Subject: [PATCH 15/33] remove print --- NvimView/Sources/NvimView/NvimView+Api.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/NvimView/Sources/NvimView/NvimView+Api.swift b/NvimView/Sources/NvimView/NvimView+Api.swift index 1546a540a..20b7a3a94 100644 --- a/NvimView/Sources/NvimView/NvimView+Api.swift +++ b/NvimView/Sources/NvimView/NvimView+Api.swift @@ -254,7 +254,6 @@ public extension NvimView { return map(vim.fn.getbufinfo(...), function(i) i.buftype = vim.api.nvim_get_option_value("buftype", {buf=i.bufnr}) - print(i.name, i.buftype) return i end) """, args: [MessagePackValue(buf.handle)]) From ff3597071beb29475033ba97e64eabd796f77e82 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 14:01:26 -0700 Subject: [PATCH 16/33] bump nvim to head --- Neovim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Neovim b/Neovim index 8dc07ee69..3dcf6880a 160000 --- a/Neovim +++ b/Neovim @@ -1 +1 @@ -Subproject commit 8dc07ee690310ea5102ae6f64abd05a649eb97ed +Subproject commit 3dcf6880ad65d15495dce18211e72a41e46f502c From 6fb2e5cd809ccfac3846fd5e8dcbbd3c1e44e289 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 14:01:41 -0700 Subject: [PATCH 17/33] arm64 only --- NvimServer/NvimServer/bin/build_libnvim.sh | 3 ++- NvimServer/NvimServer/bin/build_nvimserver.sh | 3 ++- NvimServer/Package.swift | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/NvimServer/NvimServer/bin/build_libnvim.sh b/NvimServer/NvimServer/bin/build_libnvim.sh index 058ebdfba..5ecad9b9e 100755 --- a/NvimServer/NvimServer/bin/build_libnvim.sh +++ b/NvimServer/NvimServer/bin/build_libnvim.sh @@ -9,7 +9,8 @@ build_libnvim() { # Brew's gettext does not get sym-linked to PATH export PATH="/opt/homebrew/opt/gettext/bin:/usr/local/opt/gettext/bin:${PATH}" - macos_flags="-DCMAKE_OSX_DEPLOYMENT_TARGET=${deployment_target} -DCMAKE_OSX_ARCHITECTURES=arm64\;x86_64" + #macos_flags="-DCMAKE_OSX_DEPLOYMENT_TARGET=${deployment_target} -DCMAKE_OSX_ARCHITECTURES=arm64\;x86_64" + macos_flags="-DCMAKE_OSX_DEPLOYMENT_TARGET=${deployment_target} -DCMAKE_OSX_ARCHITECTURES=arm64" pushd ../Neovim diff --git a/NvimServer/NvimServer/bin/build_nvimserver.sh b/NvimServer/NvimServer/bin/build_nvimserver.sh index be2d4f6a8..ecb96c8f6 100755 --- a/NvimServer/NvimServer/bin/build_nvimserver.sh +++ b/NvimServer/NvimServer/bin/build_nvimserver.sh @@ -17,7 +17,8 @@ main() { ./NvimServer/bin/build_libnvim.sh fi - swift build --arch arm64 --arch x86_64 -c release --product NvimServer + #swift build --arch arm64 --arch x86_64 -c release --product NvimServer + swift build --arch arm64 -c release --product NvimServer popd >/dev/null echo "### Built NvimServer" diff --git a/NvimServer/Package.swift b/NvimServer/Package.swift index 13651a762..6683cfff0 100644 --- a/NvimServer/Package.swift +++ b/NvimServer/Package.swift @@ -1,10 +1,10 @@ -// swift-tools-version:5.6 +// swift-tools-version:5.7 import PackageDescription let package = Package( name: "NvimServer", - platforms: [.macOS(.v10_15)], + platforms: [.macOS(.v13)], products: [ .library(name: "NvimServerTypes", targets: ["NvimServerTypes"]), ], From faa60d9c80fd3d2ce5dd4a28360629578967636a Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 14:21:27 -0700 Subject: [PATCH 18/33] update build scripts --- bin/build_vimr.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build_vimr.sh b/bin/build_vimr.sh index 778fb6b44..676b1cb54 100755 --- a/bin/build_vimr.sh +++ b/bin/build_vimr.sh @@ -13,7 +13,7 @@ prepare_nvimserver() { # Build NvimServer and copy build_libnvim=true ./NvimServer/NvimServer/bin/build_nvimserver.sh - cp ./NvimServer/.build/apple/Products/Release/NvimServer "${resources_folder}" + cp ./Neovim/.build/apple/Products/Release/NvimServer "${resources_folder}" # Create and copy runtime folder install_path="$(/usr/bin/mktemp -d -t 'nvim-runtime')" From c82ea28e3eb3be9cb3261ffd9b9fae518863c4d2 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 14:21:27 -0700 Subject: [PATCH 19/33] update build scripts --- NvimServer/NvimServer/bin/build_runtime.sh | 4 ++++ bin/build_vimr.sh | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/NvimServer/NvimServer/bin/build_runtime.sh b/NvimServer/NvimServer/bin/build_runtime.sh index e0c0a2fc3..115bb9abc 100755 --- a/NvimServer/NvimServer/bin/build_runtime.sh +++ b/NvimServer/NvimServer/bin/build_runtime.sh @@ -4,6 +4,8 @@ set -Eeuo pipefail readonly nvim_install_path=${nvim_install_path:?"where to install temp nvim"} build_runtime() { + pushd ../Neovim + local -r deployment_target=$1 echo "#### runtime in ${nvim_install_path}" @@ -18,6 +20,8 @@ build_runtime() { install echo "#### runtime is installed at ${nvim_install_path}/share/nvim/runtime" + + popd } main() { diff --git a/bin/build_vimr.sh b/bin/build_vimr.sh index 778fb6b44..676b1cb54 100755 --- a/bin/build_vimr.sh +++ b/bin/build_vimr.sh @@ -13,7 +13,7 @@ prepare_nvimserver() { # Build NvimServer and copy build_libnvim=true ./NvimServer/NvimServer/bin/build_nvimserver.sh - cp ./NvimServer/.build/apple/Products/Release/NvimServer "${resources_folder}" + cp ./Neovim/.build/apple/Products/Release/NvimServer "${resources_folder}" # Create and copy runtime folder install_path="$(/usr/bin/mktemp -d -t 'nvim-runtime')" From 6ff21ed002853e657de1bdadd559bb877adcfb26 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 14:25:22 -0700 Subject: [PATCH 20/33] bump min os to get things working --- VimR/VimR.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VimR/VimR.xcodeproj/project.pbxproj b/VimR/VimR.xcodeproj/project.pbxproj index bf3046c99..3a448dae7 100644 --- a/VimR/VimR.xcodeproj/project.pbxproj +++ b/VimR/VimR.xcodeproj/project.pbxproj @@ -1143,7 +1143,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_SWIFT_FLAGS = "-D DEBUG"; @@ -1200,7 +1200,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_DISABLE_SAFETY_CHECKS = YES; From 67012a447ea9ff1561ae5fdacd5b7b8f1fd4562d Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 14:25:22 -0700 Subject: [PATCH 21/33] bump min os to get things working --- Commons/Support/CommonsSupport.xcodeproj/project.pbxproj | 6 +++--- NvimView/Support/NvimViewSupport.xcodeproj/project.pbxproj | 4 ++-- RxPack/Support/RxPackSupport.xcodeproj/project.pbxproj | 4 ++-- VimR/VimR.xcodeproj/project.pbxproj | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Commons/Support/CommonsSupport.xcodeproj/project.pbxproj b/Commons/Support/CommonsSupport.xcodeproj/project.pbxproj index 85e16a900..88b180666 100644 --- a/Commons/Support/CommonsSupport.xcodeproj/project.pbxproj +++ b/Commons/Support/CommonsSupport.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -202,7 +202,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -257,7 +257,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/NvimView/Support/NvimViewSupport.xcodeproj/project.pbxproj b/NvimView/Support/NvimViewSupport.xcodeproj/project.pbxproj index c887f1e18..1dfb6f443 100644 --- a/NvimView/Support/NvimViewSupport.xcodeproj/project.pbxproj +++ b/NvimView/Support/NvimViewSupport.xcodeproj/project.pbxproj @@ -565,7 +565,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; @@ -624,7 +624,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_DISABLE_SAFETY_CHECKS = YES; diff --git a/RxPack/Support/RxPackSupport.xcodeproj/project.pbxproj b/RxPack/Support/RxPackSupport.xcodeproj/project.pbxproj index b49437aa6..d1663b3d6 100644 --- a/RxPack/Support/RxPackSupport.xcodeproj/project.pbxproj +++ b/RxPack/Support/RxPackSupport.xcodeproj/project.pbxproj @@ -244,7 +244,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -304,7 +304,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/VimR/VimR.xcodeproj/project.pbxproj b/VimR/VimR.xcodeproj/project.pbxproj index bf3046c99..3a448dae7 100644 --- a/VimR/VimR.xcodeproj/project.pbxproj +++ b/VimR/VimR.xcodeproj/project.pbxproj @@ -1143,7 +1143,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; OTHER_SWIFT_FLAGS = "-D DEBUG"; @@ -1200,7 +1200,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_DISABLE_SAFETY_CHECKS = YES; From b5adab050d4d425efd1d3e48c0cb61ac376f3553 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 14:48:04 -0700 Subject: [PATCH 22/33] bump package min os --- Commons/Package.swift | 4 ++-- Ignore/Package.swift | 4 ++-- NvimView/Package.swift | 4 ++-- NvimView/Sources/NvimView/UiBridge.swift | 3 ++- RxPack/Package.swift | 2 +- Tabs/Package.swift | 4 ++-- Workspace/Package.swift | 4 ++-- 7 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Commons/Package.swift b/Commons/Package.swift index 37d958465..bd302bd5e 100644 --- a/Commons/Package.swift +++ b/Commons/Package.swift @@ -1,10 +1,10 @@ -// swift-tools-version:5.6 +// swift-tools-version:5.7 import PackageDescription let package = Package( name: "Commons", - platforms: [.macOS(.v10_15)], + platforms: [.macOS(.v13)], products: [ .library(name: "Commons", targets: ["Commons", "CommonsObjC"]), ], diff --git a/Ignore/Package.swift b/Ignore/Package.swift index 30871a7ed..1a132433d 100644 --- a/Ignore/Package.swift +++ b/Ignore/Package.swift @@ -1,10 +1,10 @@ -// swift-tools-version:5.6 +// swift-tools-version:5.7 import PackageDescription let package = Package( name: "Ignore", - platforms: [.macOS(.v10_15)], + platforms: [.macOS(.v13)], products: [ .library(name: "Ignore", targets: ["Ignore"]), ], diff --git a/NvimView/Package.swift b/NvimView/Package.swift index e065feb38..79a78788a 100644 --- a/NvimView/Package.swift +++ b/NvimView/Package.swift @@ -1,10 +1,10 @@ -// swift-tools-version:5.6 +// swift-tools-version:5.7 import PackageDescription let package = Package( name: "NvimView", - platforms: [.macOS(.v10_15)], + platforms: [.macOS(.v13)], products: [ .library(name: "NvimView", targets: ["NvimView"]), ], diff --git a/NvimView/Sources/NvimView/UiBridge.swift b/NvimView/Sources/NvimView/UiBridge.swift index d6e6b748b..82b9c89b5 100644 --- a/NvimView/Sources/NvimView/UiBridge.swift +++ b/NvimView/Sources/NvimView/UiBridge.swift @@ -93,7 +93,8 @@ final class UiBridge { } else { // We know that NvimServer is there. env["VIMRUNTIME"] = Bundle.module.url(forResource: "runtime", withExtension: nil)!.path - process.launchPath = Bundle.module.url(forResource: "NvimServer", withExtension: nil)!.path + let launchPath = Bundle.module.url(forResource: "NvimServer", withExtension: nil)!.path + process.launchPath = launchPath } process.environment = env diff --git a/RxPack/Package.swift b/RxPack/Package.swift index a0b710c37..ac0088440 100644 --- a/RxPack/Package.swift +++ b/RxPack/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.6 +// swift-tools-version: 5.7 import PackageDescription diff --git a/Tabs/Package.swift b/Tabs/Package.swift index 8f86704ca..23fe8c39a 100644 --- a/Tabs/Package.swift +++ b/Tabs/Package.swift @@ -1,10 +1,10 @@ -// swift-tools-version:5.6 +// swift-tools-version:5.7 import PackageDescription let package = Package( name: "Tabs", - platforms: [.macOS(.v10_15)], + platforms: [.macOS(.v13)], products: [ .library(name: "Tabs", targets: ["Tabs"]), ], diff --git a/Workspace/Package.swift b/Workspace/Package.swift index 49f44f889..91000bb86 100644 --- a/Workspace/Package.swift +++ b/Workspace/Package.swift @@ -1,10 +1,10 @@ -// swift-tools-version:5.6 +// swift-tools-version:5.7 import PackageDescription let package = Package( name: "Workspace", - platforms: [.macOS(.v10_15)], + platforms: [.macOS(.v13)], products: [ .library(name: "Workspace", targets: ["Workspace"]), ], From 62817d6e9c40e0fe375971ea4161b35b4caef296 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 14:51:24 -0700 Subject: [PATCH 23/33] modify build scripts --- bin/build_vimr.sh | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/bin/build_vimr.sh b/bin/build_vimr.sh index 676b1cb54..73d8f5001 100755 --- a/bin/build_vimr.sh +++ b/bin/build_vimr.sh @@ -13,7 +13,7 @@ prepare_nvimserver() { # Build NvimServer and copy build_libnvim=true ./NvimServer/NvimServer/bin/build_nvimserver.sh - cp ./Neovim/.build/apple/Products/Release/NvimServer "${resources_folder}" + cp ./NvimServer/.build/arm64-apple-macosx/release/NvimServer "${resources_folder}" # Create and copy runtime folder install_path="$(/usr/bin/mktemp -d -t 'nvim-runtime')" @@ -38,10 +38,17 @@ build_vimr() { echo "### Xcodebuilding" rm -rf "${build_path}" - xcodebuild \ - -configuration Release -derivedDataPath "${build_path}" \ - -workspace VimR.xcworkspace -scheme VimR \ - clean build + if [[ "${clean}" == true ]]; then + xcodebuild \ + -configuration Release -derivedDataPath "${build_path}" \ + -workspace VimR.xcworkspace -scheme VimR \ + clean build + else + xcodebuild \ + -configuration Release -derivedDataPath "${build_path}" \ + -workspace VimR.xcworkspace -scheme VimR \ + build + fi } main () { From 3bd739473d35c13173bf19c79671259db7f05f76 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 16:18:26 -0700 Subject: [PATCH 24/33] make robust to colorschemes leaving out fg/bg --- NvimView/Sources/NvimView/NvimView+Resize.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/NvimView/Sources/NvimView/NvimView+Resize.swift b/NvimView/Sources/NvimView/NvimView+Resize.swift index 18aac6943..04e7df6c3 100644 --- a/NvimView/Sources/NvimView/NvimView+Resize.swift +++ b/NvimView/Sources/NvimView/NvimView+Resize.swift @@ -104,11 +104,11 @@ extension NvimView { :autocmd BufEnter * call rpcnotify(\($0), 'autocommand', 'bufenter', str2nr(expand(''))) :autocmd DirChanged * call rpcnotify(\($0), 'autocommand', 'dirchanged', expand('')) :autocmd ColorScheme * call rpcnotify(\($0), 'autocommand', 'colorscheme', \ - nvim_get_hl(0, {'id': hlID('Normal')}).fg, \ - nvim_get_hl(0, {'id': hlID('Normal')}).bg, \ - nvim_get_hl(0, {'id': hlID('Visual')}).fg, \ - nvim_get_hl(0, {'id': hlID('Visual')}).bg, \ - nvim_get_hl(0, {'id': hlID('Directory')}).fg) + get(nvim_get_hl(0, {'id': hlID('Normal')}), 'fg', 0xFFFFFF), \ + get(nvim_get_hl(0, {'id': hlID('Normal')}), 'bg', 0x000000), \ + get(nvim_get_hl(0, {'id': hlID('Visual')}), 'fg', 0xFFFFFF), \ + get(nvim_get_hl(0, {'id': hlID('Visual')}), 'bg', 0x000000), \ + get(nvim_get_hl(0, {'id': hlID('Directory')}), 'fg', 0x000000)) :autocmd ExitPre * call rpcnotify(\($0), 'autocommand', 'exitpre') :autocmd BufModifiedSet * call rpcnotify(\($0), 'autocommand', 'bufmodifiedset', \ str2nr(expand('')), getbufinfo(str2nr(expand('')))[0].changed) From d5b5b65ea0f83538e1ad599965113086835c2987 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 16:18:36 -0700 Subject: [PATCH 25/33] inverted scrolling --- NvimView/Sources/NvimView/NvimView+Mouse.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/NvimView/Sources/NvimView/NvimView+Mouse.swift b/NvimView/Sources/NvimView/NvimView+Mouse.swift index 078422c96..0c1fca55b 100644 --- a/NvimView/Sources/NvimView/NvimView+Mouse.swift +++ b/NvimView/Sources/NvimView/NvimView+Mouse.swift @@ -87,7 +87,10 @@ public extension NvimView { min(Int(abs(deltaCellX)), maxScrollDeltaX), min(Int(abs(deltaCellY)), maxScrollDeltaY) ) - let (horizSign, vertSign) = (deltaCellX > 0 ? 1 : -1, deltaCellY > 0 ? 1 : -1) + var (horizSign, vertSign) = (deltaCellX > 0 ? 1 : -1, deltaCellY > 0 ? 1 : -1) + if event.isDirectionInvertedFromDevice { + vertSign = -vertSign + } self.log.debug("# scroll: \(cellPosition.row + vertSign * absDeltaY) \(cellPosition.column + horizSign * absDeltaX)") self.api.winGetCursor(window: RxNeovimApi.Window(0)) From c1a7d38b47a08717b03a21a4127e6ddbeaa1b5d2 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 16:18:47 -0700 Subject: [PATCH 26/33] update signing cert --- bin/sign_vimr.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/sign_vimr.sh b/bin/sign_vimr.sh index 1360b4f70..34d2de7f7 100755 --- a/bin/sign_vimr.sh +++ b/bin/sign_vimr.sh @@ -2,7 +2,7 @@ set -Eeuo pipefail readonly vimr_app_path=${vimr_app_path:?"Path to VimR.app"} -readonly identity="Developer ID Application: Tae Won Ha (H96Q2NKTQH)" +readonly identity="Developer ID Application: George Harker (B8V3694RNX)" remove_sparkle_xpc () { # VimR is not sandboxed, so, remove the XPCs From 63e1c40468b71176c85146f30957895d27cf4467 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 16:47:49 -0700 Subject: [PATCH 27/33] fix input in blocked mode --- NvimView/Sources/NvimView/NvimView+Key.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/NvimView/Sources/NvimView/NvimView+Key.swift b/NvimView/Sources/NvimView/NvimView+Key.swift index defe4885f..921b85c51 100644 --- a/NvimView/Sources/NvimView/NvimView+Key.swift +++ b/NvimView/Sources/NvimView/NvimView+Key.swift @@ -58,8 +58,9 @@ public extension NvimView { default: return } - try? self.api.feedkeys(keys: self.vimPlainString(text), mode:"i", escape_ks: false) - .wait() + //try? self.api.feedkeys(keys: self.vimPlainString(text), mode:"m", escape_ks: false) + // .wait() + _ = self.api.input(keys: self.vimPlainString(text), errWhenBlocked: false).syncValue() if self.hasMarkedText() { self._unmarkText() } self.keyDownDone = true From 3e6de128bd3626ea118820e8f927ee77c4eff1d3 Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 20:02:17 -0700 Subject: [PATCH 28/33] handle color scheme missing fg, bg better --- NvimView/Sources/NvimView/NvimView+Resize.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/NvimView/Sources/NvimView/NvimView+Resize.swift b/NvimView/Sources/NvimView/NvimView+Resize.swift index 04e7df6c3..8f1587e5e 100644 --- a/NvimView/Sources/NvimView/NvimView+Resize.swift +++ b/NvimView/Sources/NvimView/NvimView+Resize.swift @@ -104,11 +104,11 @@ extension NvimView { :autocmd BufEnter * call rpcnotify(\($0), 'autocommand', 'bufenter', str2nr(expand(''))) :autocmd DirChanged * call rpcnotify(\($0), 'autocommand', 'dirchanged', expand('')) :autocmd ColorScheme * call rpcnotify(\($0), 'autocommand', 'colorscheme', \ - get(nvim_get_hl(0, {'id': hlID('Normal')}), 'fg', 0xFFFFFF), \ - get(nvim_get_hl(0, {'id': hlID('Normal')}), 'bg', 0x000000), \ - get(nvim_get_hl(0, {'id': hlID('Visual')}), 'fg', 0xFFFFFF), \ - get(nvim_get_hl(0, {'id': hlID('Visual')}), 'bg', 0x000000), \ - get(nvim_get_hl(0, {'id': hlID('Directory')}), 'fg', 0x000000)) + get(nvim_get_hl(0, {'id': hlID('Normal')}), 'fg', -1), \ + get(nvim_get_hl(0, {'id': hlID('Normal')}), 'bg', -1), \ + get(nvim_get_hl(0, {'id': hlID('Visual')}), 'fg', -1), \ + get(nvim_get_hl(0, {'id': hlID('Visual')}), 'bg', -1), \ + get(nvim_get_hl(0, {'id': hlID('Directory')}), 'fg', -1)) :autocmd ExitPre * call rpcnotify(\($0), 'autocommand', 'exitpre') :autocmd BufModifiedSet * call rpcnotify(\($0), 'autocommand', 'bufmodifiedset', \ str2nr(expand('')), getbufinfo(str2nr(expand('')))[0].changed) From dff22ec24d2190d03da389d7248a861d0b01da1c Mon Sep 17 00:00:00 2001 From: George Harker Date: Mon, 30 Oct 2023 21:49:54 -0700 Subject: [PATCH 29/33] implement custom tab bar --- .../Sources/NvimView/NvimView+Resize.swift | 2 ++ .../Sources/NvimView/NvimView+UiBridge.swift | 21 ++++--------------- NvimView/Sources/NvimView/NvimView.swift | 2 +- NvimView/Sources/NvimView/UiBridge.swift | 4 ---- 4 files changed, 7 insertions(+), 22 deletions(-) diff --git a/NvimView/Sources/NvimView/NvimView+Resize.swift b/NvimView/Sources/NvimView/NvimView+Resize.swift index 8f1587e5e..baefeb776 100644 --- a/NvimView/Sources/NvimView/NvimView+Resize.swift +++ b/NvimView/Sources/NvimView/NvimView+Resize.swift @@ -6,6 +6,7 @@ import Cocoa import RxSwift import RxNeovim +import MessagePack extension NvimView { override public func setFrameSize(_ newSize: NSSize) { @@ -120,6 +121,7 @@ extension NvimView { .andThen(self.api.uiAttach(width: size.width, height: size.height, options: [ "ext_linegrid": true, "ext_multigrid": false, + "ext_tabline": MessagePackValue(self.usesCustomTabBar), "rgb": true ])) .andThen( diff --git a/NvimView/Sources/NvimView/NvimView+UiBridge.swift b/NvimView/Sources/NvimView/NvimView+UiBridge.swift index 4becff591..d7047755e 100644 --- a/NvimView/Sources/NvimView/NvimView+UiBridge.swift +++ b/NvimView/Sources/NvimView/NvimView+UiBridge.swift @@ -235,6 +235,9 @@ extension NvimView { //self.markForRenderWholeView() break + case "tabline_update": + self.tablineUpdate(innerArray) + default: self.log.error("Unknown flush data type \(rawType)") } @@ -278,7 +281,7 @@ extension NvimView { .disposed(by: self.disposeBag) } - final func autoCommandEventNu(_ array: [MessagePackValue]) { + final func autoCommandEvent(_ array: [MessagePackValue]) { guard array.count > 0, let aucmd = array[0].stringValue?.lowercased(), let event = NvimAutoCommandEvent(rawValue: aucmd) @@ -665,22 +668,6 @@ extension NvimView { } } - final func event(_ value: MessagePackValue) { - guard let dict = value.dictionaryValue, - let event = dict.keys.first, - let args = dict[event]?.arrayValue - else { - self.bridgeLogger.error("Could not convert \(value)") - return - } - - switch event.stringValue { - case "tabline_update": self.tablineUpdate(args) - case "win_viewport": self.winViewportUpdate(args) - default: break - } - } - final func setAttr(with value: MessagePackValue) { guard let array = value.arrayValue else { self.bridgeLogger.error("Could not convert \(value)") diff --git a/NvimView/Sources/NvimView/NvimView.swift b/NvimView/Sources/NvimView/NvimView.swift index 4eca267c0..b5301ce06 100644 --- a/NvimView/Sources/NvimView/NvimView.swift +++ b/NvimView/Sources/NvimView/NvimView.swift @@ -173,7 +173,7 @@ public final class NvimView: NSView, NSUserInterfaceValidations, NSTextInputClie if (method == "redraw") { self?.renderData(params) } else if (method == "autocommand") { - self?.autoCommandEventNu(params) + self?.autoCommandEvent(params) } else { self?.log.debug("MSG ERROR: \(msg)") } diff --git a/NvimView/Sources/NvimView/UiBridge.swift b/NvimView/Sources/NvimView/UiBridge.swift index 82b9c89b5..cf34bc018 100644 --- a/NvimView/Sources/NvimView/UiBridge.swift +++ b/NvimView/Sources/NvimView/UiBridge.swift @@ -14,7 +14,6 @@ final class UiBridge { init(uuid: UUID, config: NvimView.Config) { self.uuid = uuid - self.usesCustomTabBar = config.usesCustomTabBar self.usesInteractiveZsh = config.useInteractiveZsh self.nvimBinary = config.nvimBinary self.nvimArgs = config.nvimArgs ?? [] @@ -75,8 +74,6 @@ final class UiBridge { self.log.debug("Socket: \(self.listenAddress)") - // FIXME - let usesCustomTabBarArg = self.usesCustomTabBar ? "1" : "0" let inPipe = Pipe() let outPipe = Pipe() @@ -125,7 +122,6 @@ final class UiBridge { private let uuid: UUID - private let usesCustomTabBar: Bool private let usesInteractiveZsh: Bool private let cwd: URL private let nvimArgs: [String] From f93ef45af5f7af043273a75ec708f083294ea125 Mon Sep 17 00:00:00 2001 From: George Harker Date: Sun, 5 Nov 2023 07:00:03 -0800 Subject: [PATCH 30/33] fix universal build --- NvimServer/NvimServer/bin/build_libnvim.sh | 5 +++-- NvimServer/NvimServer/bin/build_nvimserver.sh | 4 ++-- NvimServer/NvimServer/bin/prepare_libintl.sh | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/NvimServer/NvimServer/bin/build_libnvim.sh b/NvimServer/NvimServer/bin/build_libnvim.sh index 5ecad9b9e..bb8c6d596 100755 --- a/NvimServer/NvimServer/bin/build_libnvim.sh +++ b/NvimServer/NvimServer/bin/build_libnvim.sh @@ -9,8 +9,8 @@ build_libnvim() { # Brew's gettext does not get sym-linked to PATH export PATH="/opt/homebrew/opt/gettext/bin:/usr/local/opt/gettext/bin:${PATH}" - #macos_flags="-DCMAKE_OSX_DEPLOYMENT_TARGET=${deployment_target} -DCMAKE_OSX_ARCHITECTURES=arm64\;x86_64" - macos_flags="-DCMAKE_OSX_DEPLOYMENT_TARGET=${deployment_target} -DCMAKE_OSX_ARCHITECTURES=arm64" + macos_flags="-DCMAKE_OSX_DEPLOYMENT_TARGET=${deployment_target} -DCMAKE_OSX_ARCHITECTURES=arm64\;x86_64" + #macos_flags="-DCMAKE_OSX_DEPLOYMENT_TARGET=${deployment_target} -DCMAKE_OSX_ARCHITECTURES=arm64" pushd ../Neovim @@ -20,6 +20,7 @@ build_libnvim() { SDKROOT="$(xcrun --show-sdk-path)" \ MACOSX_DEPLOYMENT_TARGET="${deployment_target}" \ CMAKE_EXTRA_FLAGS="" \ + CMAKE_OSX_ARCHITECTURES="arm64;x86_64" \ DEPS_CMAKE_FLAGS="${macos_flags}" \ libnvim nvim diff --git a/NvimServer/NvimServer/bin/build_nvimserver.sh b/NvimServer/NvimServer/bin/build_nvimserver.sh index ecb96c8f6..6042f51b0 100755 --- a/NvimServer/NvimServer/bin/build_nvimserver.sh +++ b/NvimServer/NvimServer/bin/build_nvimserver.sh @@ -17,8 +17,8 @@ main() { ./NvimServer/bin/build_libnvim.sh fi - #swift build --arch arm64 --arch x86_64 -c release --product NvimServer - swift build --arch arm64 -c release --product NvimServer + swift build --arch arm64 --arch x86_64 -c release --product NvimServer + #swift build --arch arm64 -c release --product NvimServer popd >/dev/null echo "### Built NvimServer" diff --git a/NvimServer/NvimServer/bin/prepare_libintl.sh b/NvimServer/NvimServer/bin/prepare_libintl.sh index af937a1fc..e6d075083 100755 --- a/NvimServer/NvimServer/bin/prepare_libintl.sh +++ b/NvimServer/NvimServer/bin/prepare_libintl.sh @@ -20,6 +20,7 @@ main() { pushd ./NvimServer/third-party >/dev/null brew fetch --bottle-tag="${arm64_bottle}" gettext brew fetch --bottle-tag="${x86_64_bottle}" gettext + brew fetch --bottle-tag="${arm64_bottle}" lua brew fetch --bottle-tag="${x86_64_bottle}" lua local version; version=$(brew info gettext --json | jq -r ".[0].versions.stable"); readonly version From 39ca0b34e5ca9c4d1457eece0fabeb7efeaea9eb Mon Sep 17 00:00:00 2001 From: George Harker Date: Sun, 5 Nov 2023 07:32:54 -0800 Subject: [PATCH 31/33] make nvim binary optional string --- VimR/VimR/AdvencedPref.swift | 4 ++-- VimR/VimR/MainWindow.swift | 2 +- VimR/VimR/States.swift | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/VimR/VimR/AdvencedPref.swift b/VimR/VimR/AdvencedPref.swift index 8b0309385..b94168c60 100644 --- a/VimR/VimR/AdvencedPref.swift +++ b/VimR/VimR/AdvencedPref.swift @@ -68,7 +68,7 @@ final class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate { private var useSnapshotUpdate: Bool private var useLiveResize: Bool private var drawsParallel: Bool - private var nvimBinary: String + private var nvimBinary: String? private let useInteractiveZshCheckbox = NSButton(forAutoLayout: ()) private let useSnapshotUpdateCheckbox = NSButton(forAutoLayout: ()) @@ -90,7 +90,7 @@ final class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate { self.useInteractiveZshCheckbox.boolState = self.useInteractiveZsh self.useLiveResizeCheckbox.boolState = self.useLiveResize self.drawsParallelCheckbox.boolState = self.drawsParallel - self.nvimBinaryField.string = self.nvimBinary + self.nvimBinaryField.string = self.nvimBinary ?? "" } private func addViews() { diff --git a/VimR/VimR/MainWindow.swift b/VimR/VimR/MainWindow.swift index 3be21f84d..68ea0a28b 100644 --- a/VimR/VimR/MainWindow.swift +++ b/VimR/VimR/MainWindow.swift @@ -86,7 +86,7 @@ final class MainWindow: NSObject, usesCustomTabBar: state.appearance.usesCustomTab, useInteractiveZsh: state.useInteractiveZsh, cwd: state.cwd, - nvimBinary: state.nvimBinary, + nvimBinary: state.nvimBinary ?? "", nvimArgs: state.nvimArgs, envDict: state.envDict, sourceFiles: sourceFileUrls diff --git a/VimR/VimR/States.swift b/VimR/VimR/States.swift index f9fda0be4..b2fb2ddce 100644 --- a/VimR/VimR/States.swift +++ b/VimR/VimR/States.swift @@ -317,7 +317,7 @@ extension MainWindow { var appearance = AppearanceState.default var useInteractiveZsh = false - var nvimBinary: String = "" + var nvimBinary: String? var nvimArgs: [String]? var cliPipePath: String? var envDict: [String: String]? From e103f67d43de207e16bbbd426f75ac98b1bcec67 Mon Sep 17 00:00:00 2001 From: George Harker Date: Sun, 5 Nov 2023 07:35:04 -0800 Subject: [PATCH 32/33] revert prefs version bump --- VimR/VimR/PrefMiddleware.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VimR/VimR/PrefMiddleware.swift b/VimR/VimR/PrefMiddleware.swift index dae81e54b..5730f9841 100644 --- a/VimR/VimR/PrefMiddleware.swift +++ b/VimR/VimR/PrefMiddleware.swift @@ -11,7 +11,7 @@ final class PrefMiddleware: MiddlewareType { typealias StateType = AppState typealias ActionType = AnyAction - static let compatibleVersion = "169" + static let compatibleVersion = "168" let mainWindow = MainWindowMiddleware() From 63aafa0c3b30eba5d36242c2ebe7faed62a3cc8d Mon Sep 17 00:00:00 2001 From: George Harker Date: Sun, 5 Nov 2023 10:50:00 -0800 Subject: [PATCH 33/33] return nvimBinary to non optional string --- VimR/VimR/AdvencedPref.swift | 2 +- VimR/VimR/MainWindow.swift | 2 +- VimR/VimR/States.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VimR/VimR/AdvencedPref.swift b/VimR/VimR/AdvencedPref.swift index b94168c60..078f641a0 100644 --- a/VimR/VimR/AdvencedPref.swift +++ b/VimR/VimR/AdvencedPref.swift @@ -68,7 +68,7 @@ final class AdvancedPref: PrefPane, UiComponent, NSTextFieldDelegate { private var useSnapshotUpdate: Bool private var useLiveResize: Bool private var drawsParallel: Bool - private var nvimBinary: String? + private var nvimBinary: String = "" private let useInteractiveZshCheckbox = NSButton(forAutoLayout: ()) private let useSnapshotUpdateCheckbox = NSButton(forAutoLayout: ()) diff --git a/VimR/VimR/MainWindow.swift b/VimR/VimR/MainWindow.swift index 68ea0a28b..3be21f84d 100644 --- a/VimR/VimR/MainWindow.swift +++ b/VimR/VimR/MainWindow.swift @@ -86,7 +86,7 @@ final class MainWindow: NSObject, usesCustomTabBar: state.appearance.usesCustomTab, useInteractiveZsh: state.useInteractiveZsh, cwd: state.cwd, - nvimBinary: state.nvimBinary ?? "", + nvimBinary: state.nvimBinary, nvimArgs: state.nvimArgs, envDict: state.envDict, sourceFiles: sourceFileUrls diff --git a/VimR/VimR/States.swift b/VimR/VimR/States.swift index b2fb2ddce..f9fda0be4 100644 --- a/VimR/VimR/States.swift +++ b/VimR/VimR/States.swift @@ -317,7 +317,7 @@ extension MainWindow { var appearance = AppearanceState.default var useInteractiveZsh = false - var nvimBinary: String? + var nvimBinary: String = "" var nvimArgs: [String]? var cliPipePath: String? var envDict: [String: String]?