1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-11-24 03:25:03 +03:00

Add RxNeovimApi into workspace

This commit is contained in:
Tae Won Ha 2019-03-27 09:16:29 +01:00
parent b9922ad859
commit c7028d8719
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
23 changed files with 4154 additions and 159 deletions

View File

@ -1,14 +1,17 @@
# included as Framework
github "ReactiveX/RxSwift" == 4.4.2
github "PureLayout/PureLayout" == 3.1.4
github "eonil/FSEvents" "master"
github "sparkle-project/Sparkle" == 1.21.3
github "qvacua/CocoaFontAwesome" "master"
github "qvacua/CocoaMarkdown" "master"
github "qvacua/RxNeovimApi" == 0.3.4-3
github "sindresorhus/github-markdown-css" == 3.0.1
github "qvacua/swifter" "nonpublic"
github "a2/MessagePack.swift" == 3.0.0
github "elegantchaos/DictionaryCoding" == 1.0.6
github "qvacua/ShortcutRecorder" "temporary"
# included directly
github "eonil/FSEvents" "master"
github "elegantchaos/DictionaryCoding" == 1.0.6
github "sindresorhus/github-markdown-css" == 3.0.1
# for testing only
github "Quick/Nimble" == 8.0.1

View File

@ -1,4 +1,3 @@
github "IBM-Swift/BlueSocket" "1.0.45"
github "PureLayout/PureLayout" "v3.1.4"
github "Quick/Nimble" "v8.0.1"
github "ReactiveX/RxSwift" "4.4.2"
@ -7,8 +6,6 @@ github "elegantchaos/DictionaryCoding" "1.0.6"
github "eonil/FSEvents" "9723002bc2d9f596a56a63420deab30f9f670b86"
github "qvacua/CocoaFontAwesome" "fc2a08babd676525ced68061b19ad8ff3dd1d0b3"
github "qvacua/CocoaMarkdown" "c58166490a71ad4d8466f7e7b9faf7cb0917c42f"
github "qvacua/RxMsgpackRpc" "v0.0.10"
github "qvacua/RxNeovimApi" "v0.3.4-3"
github "qvacua/ShortcutRecorder" "71baf522a1e57b5f130055e33dcd800687f6ea80"
github "qvacua/swifter" "1905655ceedec5b5768f2089ceccf31621f6230a"
github "sindresorhus/github-markdown-css" "v3.0.1"

View File

@ -40,7 +40,6 @@
1929BAB9A0399206FB7EBC76 /* CellAttributesCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB19DD03ECD6ECC35F94 /* CellAttributesCollection.swift */; };
1929BB552C9D99E9ED938759 /* CellAttributesCollectionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B0B60CCAA00B08ACAB15 /* CellAttributesCollectionTest.swift */; };
1929BC8495028D66F0A7D618 /* AttributesRunDrawer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BB7E3430BD3FD88A7698 /* AttributesRunDrawer.swift */; };
1929BC8B14CA31C283455CF5 /* RxSwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B8E176C11DD61A8DCE95 /* RxSwiftCommons.swift */; };
1929BCA615324C58582BFC3C /* ProcessUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD167BE7C6BB788DAE2A /* ProcessUtils.swift */; };
1929BCF2B3C24F0E9A96FE25 /* CursorModeShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BA4C89E9FE90065C32F6 /* CursorModeShape.swift */; };
1929BDB2462E19B852EA1B47 /* CoreCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BAB9FFE8345228B559EC /* CoreCommons.swift */; };
@ -79,7 +78,6 @@
4B0A1B142129F49500F1E02F /* SwiftCommonsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A1B132129F49500F1E02F /* SwiftCommonsTest.swift */; };
4B0A1B39212B332800F1E02F /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B0A1B38212B332800F1E02F /* Nimble.framework */; };
4B0A1B3B212B333700F1E02F /* Nimble.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B0A1B38212B332800F1E02F /* Nimble.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
4B17E549209E3E4100265C1D /* RxNeovimApi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B17E548209E3E4100265C1D /* RxNeovimApi.framework */; };
4B21ED53213D4AEC009FD017 /* CocoaCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B0C89838D8402BB80BFC /* CocoaCommons.swift */; };
4B379CCD2248CFB7004B89B4 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B379CCC2248CFB6004B89B4 /* CoreFoundation.framework */; };
4B4A48DC222C7C6A00C8E3A1 /* SharedTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B4A48DB222C7C6A00C8E3A1 /* SharedTypes.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -97,7 +95,14 @@
4B90F0421FD2AFAE008A39E0 /* NvimView+UiBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0241FD2AFAD008A39E0 /* NvimView+UiBridge.swift */; };
4B90F0431FD2AFAE008A39E0 /* NvimView+MenuItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0251FD2AFAD008A39E0 /* NvimView+MenuItems.swift */; };
4B90F0521FD2AFD3008A39E0 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B90F0511FD2AFD3008A39E0 /* main.c */; };
4BB1F5C9209740E400EC394A /* RxMsgpackRpc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BB1F5C8209740E400EC394A /* RxMsgpackRpc.framework */; };
4BB1EFAE224B71ED00A5CD5A /* RxNeovimApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1EFAA224B71EC00A5CD5A /* RxNeovimApi.swift */; };
4BB1EFAF224B71ED00A5CD5A /* RxNeovimApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1EFAA224B71EC00A5CD5A /* RxNeovimApi.swift */; };
4BB1EFB0224B71ED00A5CD5A /* RxMsgpackRpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1EFAB224B71EC00A5CD5A /* RxMsgpackRpc.swift */; };
4BB1EFB1224B71ED00A5CD5A /* RxMsgpackRpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1EFAB224B71EC00A5CD5A /* RxMsgpackRpc.swift */; };
4BB1EFB2224B71ED00A5CD5A /* RxNeovimApi.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1EFAC224B71EC00A5CD5A /* RxNeovimApi.generated.swift */; };
4BB1EFB3224B71ED00A5CD5A /* RxNeovimApi.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1EFAC224B71EC00A5CD5A /* RxNeovimApi.generated.swift */; };
4BB1EFB4224B71ED00A5CD5A /* RxSwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1EFAD224B71ED00A5CD5A /* RxSwiftCommons.swift */; };
4BB1EFB5224B71ED00A5CD5A /* RxSwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1EFAD224B71ED00A5CD5A /* RxSwiftCommons.swift */; };
4BB1F5CB209740E900EC394A /* MessagePack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BB1F5CA209740E900EC394A /* MessagePack.framework */; };
4BC5B0431FE551DF0071D64F /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC5B0421FE551DF0071D64F /* RxSwift.framework */; };
4BD874302014C2600039888E /* NvimAutoCommandEvent.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD8742F2014C25F0039888E /* NvimAutoCommandEvent.generated.swift */; };
@ -256,7 +261,6 @@
1929B73455764E42DACF6BB8 /* Geometry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Geometry.swift; sourceTree = "<group>"; };
1929B7398AD1DE525FA53E38 /* server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = server.c; sourceTree = "<group>"; };
1929B8619FD13BC2570CBFB2 /* 1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = 1.json; sourceTree = "<group>"; };
1929B8E176C11DD61A8DCE95 /* RxSwiftCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxSwiftCommons.swift; sourceTree = "<group>"; };
1929B9290D503536FFDA9C49 /* MessagePackCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessagePackCommons.swift; sourceTree = "<group>"; };
1929B96A876229DA394F906E /* FontUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FontUtils.swift; sourceTree = "<group>"; };
1929B9C55A79D97272894F5D /* SwiftCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftCommons.swift; sourceTree = "<group>"; };
@ -317,6 +321,10 @@
4B90F04F1FD2AFD3008A39E0 /* NvimServer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = NvimServer; sourceTree = BUILT_PRODUCTS_DIR; };
4B90F0511FD2AFD3008A39E0 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
4B90F05B1FD2AFF7008A39E0 /* server_log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = server_log.h; sourceTree = "<group>"; };
4BB1EFAA224B71EC00A5CD5A /* RxNeovimApi.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RxNeovimApi.swift; path = ../../RxPack/RxNeovimApi.swift; sourceTree = "<group>"; };
4BB1EFAB224B71EC00A5CD5A /* RxMsgpackRpc.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RxMsgpackRpc.swift; path = ../../RxPack/RxMsgpackRpc.swift; sourceTree = "<group>"; };
4BB1EFAC224B71EC00A5CD5A /* RxNeovimApi.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RxNeovimApi.generated.swift; path = ../../RxPack/RxNeovimApi.generated.swift; sourceTree = "<group>"; };
4BB1EFAD224B71ED00A5CD5A /* RxSwiftCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RxSwiftCommons.swift; path = ../../RxPack/RxSwiftCommons.swift; sourceTree = "<group>"; };
4BB1F5C8209740E400EC394A /* RxMsgpackRpc.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxMsgpackRpc.framework; path = ../Carthage/Build/Mac/RxMsgpackRpc.framework; sourceTree = "<group>"; };
4BB1F5CA209740E900EC394A /* MessagePack.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessagePack.framework; path = ../Carthage/Build/Mac/MessagePack.framework; sourceTree = "<group>"; };
4BC5B0421FE551DF0071D64F /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = ../Carthage/Build/Mac/RxSwift.framework; sourceTree = "<group>"; };
@ -373,8 +381,6 @@
4BEBC23A215FD19C007113C4 /* Socket.framework in Frameworks */,
4BC5B0431FE551DF0071D64F /* RxSwift.framework in Frameworks */,
4BB1F5CB209740E900EC394A /* MessagePack.framework in Frameworks */,
4B17E549209E3E4100265C1D /* RxNeovimApi.framework in Frameworks */,
4BB1F5C9209740E400EC394A /* RxMsgpackRpc.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -408,7 +414,6 @@
children = (
1929BAB9FFE8345228B559EC /* CoreCommons.swift */,
1929B9C55A79D97272894F5D /* SwiftCommons.swift */,
1929B8E176C11DD61A8DCE95 /* RxSwiftCommons.swift */,
1929B0C89838D8402BB80BFC /* CocoaCommons.swift */,
1929B9290D503536FFDA9C49 /* MessagePackCommons.swift */,
1929B002A03693B14B14BE34 /* NvimApiCommons.swift */,
@ -451,6 +456,10 @@
4B022678224ACE320052362B /* RxPack */ = {
isa = PBXGroup;
children = (
4BB1EFAB224B71EC00A5CD5A /* RxMsgpackRpc.swift */,
4BB1EFAC224B71EC00A5CD5A /* RxNeovimApi.generated.swift */,
4BB1EFAA224B71EC00A5CD5A /* RxNeovimApi.swift */,
4BB1EFAD224B71ED00A5CD5A /* RxSwiftCommons.swift */,
4B022688224ACFE30052362B /* ReadersWriterLock.swift */,
4B022687224ACFE30052362B /* RxMessagePort.swift */,
);
@ -874,13 +883,17 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4BB1EFB5224B71ED00A5CD5A /* RxSwiftCommons.swift in Sources */,
4BB1EFAF224B71ED00A5CD5A /* RxNeovimApi.swift in Sources */,
4B0A1B142129F49500F1E02F /* SwiftCommonsTest.swift in Sources */,
4BB1EFB1224B71ED00A5CD5A /* RxMsgpackRpc.swift in Sources */,
1929B434DB094D61B3977390 /* TypesetterTest.swift in Sources */,
4B02268A224ACFE30052362B /* RxMessagePort.swift in Sources */,
1929BF6E40C70A4157A5C755 /* UGridTest.swift in Sources */,
1929BB552C9D99E9ED938759 /* CellAttributesCollectionTest.swift in Sources */,
4B02268C224ACFE30052362B /* ReadersWriterLock.swift in Sources */,
1929B90E2CFEAADE0CEE1562 /* CursorModeShape.swift in Sources */,
4BB1EFB3224B71ED00A5CD5A /* RxNeovimApi.generated.swift in Sources */,
1929BDC146B699BF49116CAB /* Defs.swift in Sources */,
1929B2E9F089A9E2800B67F2 /* NimbleCommons.swift in Sources */,
);
@ -909,6 +922,7 @@
1929B953E76914DA984697DC /* FontUtils.swift in Sources */,
1929B40C9C30B46C0E0B9DE2 /* CellAttributes.swift in Sources */,
1929B9A949EE85C27FF66367 /* UGrid.swift in Sources */,
4BB1EFB2224B71ED00A5CD5A /* RxNeovimApi.generated.swift in Sources */,
1929BC8495028D66F0A7D618 /* AttributesRunDrawer.swift in Sources */,
1929B6776A1D11409335FAAB /* SimpleCache.swift in Sources */,
1929B4632DE08273F990806F /* Runs.swift in Sources */,
@ -917,12 +931,14 @@
1929B70D3BA20F66CAFF08C8 /* CoreCommons.swift in Sources */,
1929BEA71F454E92A0CE5AB6 /* SwiftCommons.swift in Sources */,
4B02268B224ACFE30052362B /* ReadersWriterLock.swift in Sources */,
1929BC8B14CA31C283455CF5 /* RxSwiftCommons.swift in Sources */,
4BB1EFAE224B71ED00A5CD5A /* RxNeovimApi.swift in Sources */,
1929B83EAD32DC419FEC68DB /* CocoaCommons.swift in Sources */,
1929BAB9A0399206FB7EBC76 /* CellAttributesCollection.swift in Sources */,
1929B3B70C96A78FD63DE737 /* NvimView+Debug.swift in Sources */,
4B022689224ACFE30052362B /* RxMessagePort.swift in Sources */,
1929B738A3677586230704F7 /* MessagePackCommons.swift in Sources */,
4BB1EFB0224B71ED00A5CD5A /* RxMsgpackRpc.swift in Sources */,
4BB1EFB4224B71ED00A5CD5A /* RxSwiftCommons.swift in Sources */,
1929B00C084F8EA5EF0BE6E2 /* NvimView+Geometry.swift in Sources */,
1929B06F50B2585777FFBE48 /* NvimApiCommons.swift in Sources */,
1929BCF2B3C24F0E9A96FE25 /* CursorModeShape.swift in Sources */,

View File

@ -4,23 +4,22 @@
*/
import Foundation
import RxNeovimApi
import RxSwift
extension Api {
extension RxNeovimApi {
public func bufGetInfo(
buffer: Api.Buffer,
buffer: RxNeovimApi.Buffer,
checkBlocked: Bool = true
) -> Single<Dictionary<String, Api.Value>> {
) -> Single<Dictionary<String, RxNeovimApi.Value>> {
let params: [Api.Value] = [
let params: [RxNeovimApi.Value] = [
.int(Int64(buffer.handle)),
]
func transform(_ value: Value) throws -> Dictionary<String, Api.Value> {
func transform(_ value: Value) throws -> Dictionary<String, RxNeovimApi.Value> {
guard let result = (msgPackDictToSwift(value.dictionaryValue)) else {
throw Api.Error.conversion(type: Dictionary<String, Api.Value>.self)
throw RxNeovimApi.Error.conversion(type: Dictionary<String, RxNeovimApi.Value>.self)
}
return result
@ -40,7 +39,7 @@ extension Api {
}
}
func msgPackDictToSwift(_ dict: Dictionary<Api.Value, Api.Value>?) -> Dictionary<String, Api.Value>? {
private func msgPackDictToSwift(_ dict: Dictionary<RxNeovimApi.Value, RxNeovimApi.Value>?) -> Dictionary<String, RxNeovimApi.Value>? {
return dict?.flatMapToDict { k, v in
guard let strKey = k.stringValue else {
return nil
@ -50,7 +49,7 @@ func msgPackDictToSwift(_ dict: Dictionary<Api.Value, Api.Value>?) -> Dictionary
}
}
private func msgPackArrayDictToSwift(_ array: [Api.Value]?) -> [Dictionary<String, Api.Value>]? {
private func msgPackArrayDictToSwift(_ array: [RxNeovimApi.Value]?) -> [Dictionary<String, RxNeovimApi.Value>]? {
return array?
.compactMap { v in v.dictionaryValue }
.compactMap { d in msgPackDictToSwift(d) }

View File

@ -4,7 +4,6 @@
*/
import Cocoa
import RxNeovimApi
import RxSwift
import MessagePack
@ -74,7 +73,7 @@ extension NvimView {
let bufExists = buffers.contains { $0.url == url }
let wins = tabs.map({ $0.windows }).flatMap({ $0 })
if let win = bufExists ? wins.first(where: { win in win.buffer.url == url }) : nil {
return self.api.setCurrentWin(window: Api.Window(win.handle))
return self.api.setCurrentWin(window: RxNeovimApi.Window(win.handle))
}
return currentBufferIsTransient ? self.open(url, cmd: "e") : self.open(url, cmd: "tabe")
@ -112,7 +111,7 @@ extension NvimView {
.map { tabs in tabs.map { $0.windows }.flatMap { $0 } }
.flatMapCompletable { wins -> Completable in
if let win = wins.first(where: { $0.buffer == buffer }) {
return self.api.setCurrentWin(window: Api.Window(win.handle))
return self.api.setCurrentWin(window: RxNeovimApi.Window(win.handle))
}
return self.api.command(command: "tab sb \(buffer.handle)")
@ -157,7 +156,7 @@ extension NvimView {
public func vimOutput(of command: String) -> Single<String> {
return self.api
.commandOutput(str: command)
.commandOutput(command: command)
.subscribeOn(self.scheduler)
}
@ -176,7 +175,7 @@ extension NvimView {
return self.bridge.focusGained(false)
}
func neoVimBuffer(for buf: Api.Buffer, currentBuffer: Api.Buffer?) -> Single<NvimView.Buffer> {
func neoVimBuffer(for buf: RxNeovimApi.Buffer, currentBuffer: RxNeovimApi.Buffer?) -> Single<NvimView.Buffer> {
return self.api
.bufGetInfo(buffer: buf)
.map { info -> NvimView.Buffer in
@ -186,7 +185,7 @@ extension NvimView {
let buftype = info["buftype"]?.stringValue,
let listed = info["buflisted"]?.boolValue
else {
throw Api.Error.exception(message: "Could not convert values from the dictionary.")
throw RxNeovimApi.Error.exception(message: "Could not convert values from the dictionary.")
}
let url = path == "" || buftype != "" ? nil : URL(fileURLWithPath: path)
@ -207,9 +206,9 @@ extension NvimView {
.subscribeOn(self.scheduler)
}
private func neoVimWindow(for window: Api.Window,
currentWindow: Api.Window?,
currentBuffer: Api.Buffer?) -> Single<NvimView.Window> {
private func neoVimWindow(for window: RxNeovimApi.Window,
currentWindow: RxNeovimApi.Window?,
currentBuffer: RxNeovimApi.Buffer?) -> Single<NvimView.Window> {
return self.api
.winGetBuf(window: window)
@ -217,9 +216,9 @@ extension NvimView {
.map { buffer in NvimView.Window(apiWindow: window, buffer: buffer, isCurrentInTab: window == currentWindow) }
}
private func neoVimTab(for tabpage: Api.Tabpage,
currentTabpage: Api.Tabpage?,
currentBuffer: Api.Buffer?) -> Single<NvimView.Tabpage> {
private func neoVimTab(for tabpage: RxNeovimApi.Tabpage,
currentTabpage: RxNeovimApi.Tabpage?,
currentBuffer: RxNeovimApi.Buffer?) -> Single<NvimView.Tabpage> {
return Single.zip(
self.api.tabpageGetWin(tabpage: tabpage),

View File

@ -4,7 +4,6 @@
*/
import Foundation
import RxNeovimApi
extension NvimView {
@ -19,7 +18,7 @@ extension NvimView {
return lhs.url == rhs.url
}
public let apiBuffer: Api.Buffer
public let apiBuffer: RxNeovimApi.Buffer
public let url: URL?
public let type: String
@ -54,7 +53,7 @@ extension NvimView {
public struct Window {
public let apiWindow: Api.Window
public let apiWindow: RxNeovimApi.Window
public let buffer: Buffer
public let isCurrentInTab: Bool
@ -65,7 +64,7 @@ extension NvimView {
public struct Tabpage {
public let apiTabpage: Api.Tabpage
public let apiTabpage: RxNeovimApi.Tabpage
public let windows: [Window]
public let isCurrent: Bool

View File

@ -4,7 +4,6 @@
*/
import Cocoa
import RxNeovimApi
import RxSwift
extension NvimView {
@ -102,9 +101,10 @@ extension NvimView {
.andThen(self.api.run(at: sockPath))
.andThen(
self.sourceFileUrls.reduce(Completable.empty()) { prev, url in
prev.andThen(self.api
.commandOutput(str: "source \(url.path)")
.asCompletable())
prev.andThen(
self.api
.commandOutput(command: "source \(url.path)").asCompletable()
)
}
)
.andThen(self.api.subscribe(event: NvimView.rpcEventName))

View File

@ -129,7 +129,7 @@ extension NvimView: NSTouchBarDelegate, NSScrubberDataSource, NSScrubberDelegate
let window = tab.currentWindow ?? tab.windows[0]
self.api
.setCurrentWin(window: Api.Window(window.handle))
.setCurrentWin(window: RxNeovimApi.Window(window.handle))
.subscribeOn(self.scheduler)
.subscribe(onError: { error in
self.eventsSubject.onNext(.apiError(msg: "Could not set current window to \(window.handle).", cause: error))

View File

@ -572,7 +572,7 @@ extension NvimView {
.currentBuffer()
.flatMap { curBuf -> Single<NvimView.Buffer> in
self.neoVimBuffer(
for: Api.Buffer(handle), currentBuffer: curBuf.apiBuffer
for: RxNeovimApi.Buffer(handle), currentBuffer: curBuf.apiBuffer
)
}
.subscribe(onSuccess: {

View File

@ -4,7 +4,6 @@
*/
import Cocoa
import RxNeovimApi
import RxSwift
import MessagePack
import os
@ -349,7 +348,7 @@ public class NvimView: NSView,
// MARK: - Internal
let bridge: UiBridge
let api = RxNeovimApi.Api()
let api = RxNeovimApi()
let ugrid = UGrid()
let cellAttributesCollection = CellAttributesCollection()

View File

@ -1,102 +0,0 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
import RxSwift
extension PrimitiveSequence
where Element == Never, TraitType == CompletableTrait {
func wait(
onCompleted: (() -> Void)? = nil,
onError: ((Error) -> Void)? = nil
) throws {
var trigger = false
var err: Error? = nil
let condition = NSCondition()
condition.lock()
defer { condition.unlock() }
let disposable = self.subscribe(onCompleted: {
onCompleted?()
condition.lock()
defer { condition.unlock() }
trigger = true
condition.broadcast()
}, onError: { error in
onError?(error)
err = error
condition.lock()
defer { condition.unlock() }
trigger = true
condition.broadcast()
})
while !trigger { condition.wait(until: Date(timeIntervalSinceNow: 5)) }
disposable.dispose()
if let e = err {
throw e
}
}
}
extension PrimitiveSequence where TraitType == SingleTrait {
static func fromSinglesToSingleOfArray(
_ singles: [Single<Element>]
) -> Single<[Element]> {
return Observable
.merge(singles.map { $0.asObservable() })
.toArray()
.asSingle()
}
func flatMapCompletable(
_ selector: @escaping (Element) throws -> Completable
) -> Completable {
return self
.asObservable()
.flatMap { try selector($0).asObservable() }
.ignoreElements()
}
func syncValue() -> Element? {
var trigger = false
var value: Element?
let condition = NSCondition()
condition.lock()
defer { condition.unlock() }
let disposable = self.subscribe(onSuccess: { result in
value = result
condition.lock()
defer { condition.unlock() }
trigger = true
condition.broadcast()
}, onError: { error in
condition.lock()
defer { condition.unlock() }
trigger = true
condition.broadcast()
})
while !trigger { condition.wait(until: Date(timeIntervalSinceNow: 5)) }
disposable.dispose()
return value
}
func asCompletable() -> Completable {
return self.asObservable().ignoreElements()
}
}

View File

@ -8,7 +8,7 @@ import RxSwift
import MessagePack
import Socket
public final class MsgpackRpc {
public final class RxMsgpackRpc {
public typealias Value = MessagePackValue
@ -61,7 +61,7 @@ public final class MsgpackRpc {
public var streamResponses = false
public var queue = DispatchQueue(
label: String(reflecting: MsgpackRpc.self),
label: String(reflecting: RxMsgpackRpc.self),
qos: .userInitiated
)
@ -346,7 +346,8 @@ public final class MsgpackRpc {
}
}
private typealias SingleResponseObserver = (SingleEvent<MsgpackRpc.Response>) -> Void
private typealias SingleResponseObserver
= (SingleEvent<RxMsgpackRpc.Response>) -> Void
fileprivate extension NSLocking {

View File

@ -8,14 +8,14 @@ import RxSwift
class RxMsgpackRpcTests: XCTestCase {
private var connection: MsgpackRpc!
private var connection: RxMsgpackRpc!
private let disposeBag = DisposeBag()
override func setUp() {
super.setUp()
// $ NVIM_LISTEN_ADDRESS=/tmp/nvim.sock nvim --headless $SOMEFILE
connection = MsgpackRpc()
connection = RxMsgpackRpc()
connection.stream
.subscribe(onNext: { msg in
switch msg {

File diff suppressed because it is too large Load Diff

135
RxPack/RxNeovimApi.swift Normal file
View File

@ -0,0 +1,135 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Foundation
import RxSwift
public final class RxNeovimApi {
public enum Event {
case error(msg: String)
}
public struct Buffer: Equatable {
public static func ==(lhs: Buffer, rhs: Buffer) -> Bool {
return lhs.handle == rhs.handle
}
public let handle: Int
public init(_ handle: Int) {
self.handle = handle
}
}
public struct Window: Equatable {
public static func ==(lhs: Window, rhs: Window) -> Bool {
return lhs.handle == rhs.handle
}
public let handle: Int
public init(_ handle: Int) {
self.handle = handle
}
}
public struct Tabpage: Equatable {
public static func ==(lhs: Tabpage, rhs: Tabpage) -> Bool {
return lhs.handle == rhs.handle
}
public let handle: Int
public init(_ handle: Int) {
self.handle = handle
}
}
public typealias Value = RxMsgpackRpc.Value
public var streamResponses: Bool {
get {
return self.msgpackRpc.streamResponses
}
set {
self.msgpackRpc.streamResponses = newValue
}
}
public var streamRawResponses: Bool {
get {
return self.msgpackRpc.streamResponses
}
set {
self.msgpackRpc.streamResponses = newValue
}
}
public var msgpackRawStream: Observable<RxMsgpackRpc.Message> {
return self.msgpackRpc.stream
}
public var queue = DispatchQueue(label: String(reflecting: RxNeovimApi.self), qos: .userInitiated) {
didSet {
self.msgpackRpc.queue = self.queue
}
}
public init() {
self.msgpackRpc.queue = self.queue
}
public func run(at path: String) -> Completable {
return self.msgpackRpc.run(at: path)
}
public func stop() -> Completable {
return self.msgpackRpc.stop()
}
public func checkBlocked<T>(_ single: Single<T>) -> Single<T> {
return self
.getMode()
.flatMap { dict -> Single<T> in
guard (dict["blocking"]?.boolValue ?? false) == false else {
throw RxNeovimApi.Error.blocked
}
return single
}
}
public func rpc(method: String,
params: [RxNeovimApi.Value],
expectsReturnValue: Bool = true) -> Single<RxNeovimApi.Value> {
return self.msgpackRpc
.request(method: method, params: params, expectsReturnValue: expectsReturnValue)
.map { response -> RxMsgpackRpc.Value in
guard response.error.isNil else {
throw RxNeovimApi.Error(response.error)
}
return response.result
}
}
private let msgpackRpc = RxMsgpackRpc()
}
fileprivate extension NSLocking {
@discardableResult
func withLock<T>(_ body: () -> T) -> T {
self.lock()
defer { self.unlock() }
return body()
}
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,46 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import XCTest
import RxSwift
import MessagePack
class NvimMsgPackTests: XCTestCase {
var nvim = RxNeovimApi()
let disposeBag = DisposeBag()
override func setUp() {
super.setUp()
// $ NVIM_LISTEN_ADDRESS=/tmp/nvim.sock nvim $SOME_FILES
try? nvim.run(at: "/tmp/nvim.sock").wait()
}
override func tearDown() {
super.tearDown()
try? self.nvim.stop().wait()
}
func testExample() {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .full
let now = Date()
let dispose = DisposeBag()
for i in 0...5 {
nvim
.command(
command: "echo '\(formatter.string(from: now)) \(i)'",
expectsReturnValue: true,
checkBlocked: true
)
.subscribe(onCompleted: { print("\(i) handled") })
.disposed(by: dispose)
}
sleep(1)
}
}

View File

@ -24,6 +24,18 @@
4B0226B4224B5A310052362B /* ReadersWriterLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B022683224ACFCB0052362B /* ReadersWriterLock.swift */; };
4B0226B5224B5A310052362B /* RxMsgpackRpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDD5380FFB00320A20C9 /* RxMsgpackRpc.swift */; };
4BB1EF8C224B62BB00A5CD5A /* RxSwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1EF8B224B625700A5CD5A /* RxSwiftCommons.swift */; };
4BB1EF98224B66AB00A5CD5A /* RxNeovimApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1EF97224B66AB00A5CD5A /* RxNeovimApiTests.swift */; };
4BB1EF9D224B66BB00A5CD5A /* RxNeovimApi.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1EF90224B662E00A5CD5A /* RxNeovimApi.generated.swift */; };
4BB1EF9E224B66BB00A5CD5A /* RxNeovimApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1EF8E224B662E00A5CD5A /* RxNeovimApi.swift */; };
4BB1EFA0224B66BB00A5CD5A /* RxSwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1EF8B224B625700A5CD5A /* RxSwiftCommons.swift */; };
4BB1EFA1224B66BB00A5CD5A /* ReadersWriterLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B022683224ACFCB0052362B /* ReadersWriterLock.swift */; };
4BB1EFA2224B66BB00A5CD5A /* RxMsgpackRpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BDD5380FFB00320A20C9 /* RxMsgpackRpc.swift */; };
4BB1EFA3224B66C700A5CD5A /* MessagePack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B02268D224B56F10052362B /* MessagePack.framework */; };
4BB1EFA4224B66C700A5CD5A /* Socket.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B02268E224B56F10052362B /* Socket.framework */; };
4BB1EFA5224B66C700A5CD5A /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B02266D224ACCE10052362B /* RxSwift.framework */; };
4BB1EFA7224B66D700A5CD5A /* MessagePack.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B02268D224B56F10052362B /* MessagePack.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
4BB1EFA8224B66D700A5CD5A /* Socket.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B02268E224B56F10052362B /* Socket.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
4BB1EFA9224B66D700A5CD5A /* RxSwift.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B02266D224ACCE10052362B /* RxSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@ -50,6 +62,18 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4BB1EFA6224B66CC00A5CD5A /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
4BB1EFA7224B66D700A5CD5A /* MessagePack.framework in CopyFiles */,
4BB1EFA8224B66D700A5CD5A /* Socket.framework in CopyFiles */,
4BB1EFA9224B66D700A5CD5A /* RxSwift.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
@ -68,6 +92,11 @@
4B0226A7224B58DB0052362B /* RxMsgpackRpcTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxMsgpackRpcTests.swift; sourceTree = "<group>"; };
4B0226A9224B58DB0052362B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4BB1EF8B224B625700A5CD5A /* RxSwiftCommons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxSwiftCommons.swift; sourceTree = "<group>"; };
4BB1EF8E224B662E00A5CD5A /* RxNeovimApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxNeovimApi.swift; sourceTree = "<group>"; };
4BB1EF90224B662E00A5CD5A /* RxNeovimApi.generated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxNeovimApi.generated.swift; sourceTree = "<group>"; };
4BB1EF95224B66AA00A5CD5A /* RxNeovimApiTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RxNeovimApiTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
4BB1EF97224B66AB00A5CD5A /* RxNeovimApiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxNeovimApiTests.swift; sourceTree = "<group>"; };
4BB1EF99224B66AB00A5CD5A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -89,17 +118,29 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4BB1EF92224B66AA00A5CD5A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4BB1EFA3224B66C700A5CD5A /* MessagePack.framework in Frameworks */,
4BB1EFA4224B66C700A5CD5A /* Socket.framework in Frameworks */,
4BB1EFA5224B66C700A5CD5A /* RxSwift.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
4B02263A224AB11A0052362B = {
isa = PBXGroup;
children = (
4BB1EF8D224B660E00A5CD5A /* RxNeovimApi */,
4BB1EF8B224B625700A5CD5A /* RxSwiftCommons.swift */,
4B022683224ACFCB0052362B /* ReadersWriterLock.swift */,
4B022684224ACFCB0052362B /* RxMessagePort.swift */,
4B02265D224AB1490052362B /* RxMessagePortDemo */,
4B0226A6224B58DB0052362B /* RxMsgpackRpcTests */,
4BB1EF96224B66AB00A5CD5A /* RxNeovimApiTests */,
4B02266C224ACCD20052362B /* Frameworks */,
4B022644224AB11A0052362B /* Products */,
1929BDD5380FFB00320A20C9 /* RxMsgpackRpc.swift */,
@ -111,6 +152,7 @@
children = (
4B02265C224AB1490052362B /* RxMessagePortDemo.app */,
4B0226A5224B58DB0052362B /* RxMsgpackRpcTests.xctest */,
4BB1EF95224B66AA00A5CD5A /* RxNeovimApiTests.xctest */,
);
name = Products;
sourceTree = "<group>";
@ -145,6 +187,24 @@
path = RxMsgpackRpcTests;
sourceTree = "<group>";
};
4BB1EF8D224B660E00A5CD5A /* RxNeovimApi */ = {
isa = PBXGroup;
children = (
4BB1EF90224B662E00A5CD5A /* RxNeovimApi.generated.swift */,
4BB1EF8E224B662E00A5CD5A /* RxNeovimApi.swift */,
);
name = RxNeovimApi;
sourceTree = "<group>";
};
4BB1EF96224B66AB00A5CD5A /* RxNeovimApiTests */ = {
isa = PBXGroup;
children = (
4BB1EF97224B66AB00A5CD5A /* RxNeovimApiTests.swift */,
4BB1EF99224B66AB00A5CD5A /* Info.plist */,
);
path = RxNeovimApiTests;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -184,6 +244,24 @@
productReference = 4B0226A5224B58DB0052362B /* RxMsgpackRpcTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
4BB1EF94224B66AA00A5CD5A /* RxNeovimApiTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 4BB1EF9A224B66AB00A5CD5A /* Build configuration list for PBXNativeTarget "RxNeovimApiTests" */;
buildPhases = (
4BB1EF91224B66AA00A5CD5A /* Sources */,
4BB1EF92224B66AA00A5CD5A /* Frameworks */,
4BB1EF93224B66AA00A5CD5A /* Resources */,
4BB1EFA6224B66CC00A5CD5A /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = RxNeovimApiTests;
productName = RxNeovimApiTests;
productReference = 4BB1EF95224B66AA00A5CD5A /* RxNeovimApiTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@ -200,6 +278,9 @@
4B0226A4224B58DB0052362B = {
CreatedOnToolsVersion = 10.2;
};
4BB1EF94224B66AA00A5CD5A = {
CreatedOnToolsVersion = 10.2;
};
};
};
buildConfigurationList = 4B02263E224AB11A0052362B /* Build configuration list for PBXProject "RxPack" */;
@ -217,6 +298,7 @@
targets = (
4B02265B224AB1490052362B /* RxMessagePortDemo */,
4B0226A4224B58DB0052362B /* RxMsgpackRpcTests */,
4BB1EF94224B66AA00A5CD5A /* RxNeovimApiTests */,
);
};
/* End PBXProject section */
@ -238,6 +320,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4BB1EF93224B66AA00A5CD5A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -262,6 +351,19 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4BB1EF91224B66AA00A5CD5A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4BB1EF9D224B66BB00A5CD5A /* RxNeovimApi.generated.swift in Sources */,
4BB1EF9E224B66BB00A5CD5A /* RxNeovimApi.swift in Sources */,
4BB1EFA0224B66BB00A5CD5A /* RxSwiftCommons.swift in Sources */,
4BB1EFA1224B66BB00A5CD5A /* ReadersWriterLock.swift in Sources */,
4BB1EFA2224B66BB00A5CD5A /* RxMsgpackRpc.swift in Sources */,
4BB1EF98224B66AB00A5CD5A /* RxNeovimApiTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
@ -428,8 +530,6 @@
4B0226AB224B58DB0052362B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
INFOPLIST_FILE = RxMsgpackRpcTests/Info.plist;
@ -448,8 +548,6 @@
4B0226AC224B58DB0052362B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
INFOPLIST_FILE = RxMsgpackRpcTests/Info.plist;
@ -465,6 +563,40 @@
};
name = Release;
};
4BB1EF9B224B66AB00A5CD5A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
INFOPLIST_FILE = RxNeovimApiTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.RxNeovimApiTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
4BB1EF9C224B66AB00A5CD5A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../Carthage/Build/Mac";
INFOPLIST_FILE = RxNeovimApiTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.qvacua.RxNeovimApiTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@ -495,6 +627,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
4BB1EF9A224B66AB00A5CD5A /* Build configuration list for PBXNativeTarget "RxNeovimApiTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
4BB1EF9B224B66AB00A5CD5A /* Debug */,
4BB1EF9C224B66AB00A5CD5A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 4B02263B224AB11A0052362B /* Project object */;

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
version = "1.3">
<BuildAction>
<BuildActionEntries>
<BuildActionEntry
buildForRunning = "YES"
buildForTesting = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4BB1EF94224B66AA00A5CD5A"
BuildableName = "RxNeovimApiTests.xctest"
BlueprintName = "RxNeovimApiTests"
ReferencedContainer = "container:RxPack.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug">
<Testables>
<TestableReference>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4BB1EF94224B66AA00A5CD5A"
BuildableName = "RxNeovimApiTests.xctest"
BlueprintName = "RxNeovimApiTests"
ReferencedContainer = "container:RxPack.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
useCustomWorkingDirectory = "NO"
allowLocationSimulation = "YES">
<LocationScenarioReference
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
referenceType = "1">
</LocationScenarioReference>
</LaunchAction>
</Scheme>

38
RxPack/bin/generate.sh Executable file
View File

@ -0,0 +1,38 @@
#!/bin/bash
BUILD_DIR=".deps"
mkdir -p ${BUILD_DIR}
nvim="./${BUILD_DIR}/nvim-osx64/bin/nvim"
version="$($nvim --version | grep ^NVIM | awk '{print $2}')" || "n/a"
target_version=$(cat ./nvim-version.txt | awk '{$1=$1}1')
echo "Downloaded version: $version"
echo "Target version: $target_version"
download=false
if [[ "$target_version" == "nightly" ]]; then
echo "Target version is nightly => Downloading..."
download=true
else
if ! [[ "$version" =~ "$target_version".* ]]; then
echo "Target version differs from the downloaded version => Downloading..."
download=true
fi
fi
if [[ "$download" == true ]]; then
curl -L -o ./${BUILD_DIR}/nvim-macos.tar.gz "https://github.com/neovim/neovim/releases/download/$target_version/nvim-macos.tar.gz"
echo "Downloaded $target_version"
pushd ./${BUILD_DIR}
tar xjf nvim-macos.tar.gz
popd
echo "Extracted $target_version"
else
echo "No download necessary"
fi
echo "Generating sources..."
NVIM_PATH="$nvim" ./bin/generate_api_methods.py
echo "Generated sources"

View File

@ -0,0 +1,432 @@
#!/usr/bin/env python3
import subprocess
import msgpack
from string import Template
import re
import textwrap
import os
import io
void_func_template = Template('''\
func ${func_name}(${args}
expectsReturnValue: Bool = true,
checkBlocked: Bool = true
) -> Completable {
let params: [RxNeovimApi.Value] = [
${params}
]
if expectsReturnValue && checkBlocked {
return self
.checkBlocked(
self.rpc(method: "${nvim_func_name}", params: params, expectsReturnValue: expectsReturnValue)
)
.asCompletable()
}
return self
.rpc(method: "${nvim_func_name}", params: params, expectsReturnValue: expectsReturnValue)
.asCompletable()
}
''')
get_mode_func_template = Template('''\
func ${func_name}(${args}
) -> Single<${result_type}> {
let params: [RxNeovimApi.Value] = [
${params}
]
return self
.rpc(method: "${nvim_func_name}", params: params, expectsReturnValue: true)
.map { value in
guard let result = (${return_value}) else {
throw RxNeovimApi.Error.conversion(type: ${result_type}.self)
}
return result
}
}
''')
func_template = Template('''\
func ${func_name}(${args}
checkBlocked: Bool = true
) -> Single<${result_type}> {
let params: [RxNeovimApi.Value] = [
${params}
]
func transform(_ value: Value) throws -> ${result_type} {
guard let result = (${return_value}) else {
throw RxNeovimApi.Error.conversion(type: ${result_type}.self)
}
return result
}
if checkBlocked {
return self
.checkBlocked(
self.rpc(method: "${nvim_func_name}", params: params, expectsReturnValue: true)
)
.map(transform)
}
return self
.rpc(method: "${nvim_func_name}", params: params, expectsReturnValue: true)
.map(transform)
}
''')
extension_template = Template('''\
// Auto generated for nvim version ${version}.
// See bin/generate_api_methods.py
import Foundation
import MessagePack
import RxSwift
extension RxNeovimApi {
public enum Error: Swift.Error {
${error_types}
case exception(message: String)
case validation(message: String)
case blocked
case conversion(type: Any.Type)
case unknown
init(_ value:RxNeovimApi.Value?) {
let array = value?.arrayValue
guard array?.count == 2 else {
self = .unknown
return
}
guard let rawValue = array?[0].unsignedIntegerValue, let message = array?[1].stringValue else {
self = .unknown
return
}
switch rawValue {
${error_cases}
default: self = .unknown
}
}
}
}
extension RxNeovimApi {
$body
}
extension RxNeovimApi.Buffer {
init?(_ value:RxNeovimApi.Value) {
guard let (type, data) = value.extendedValue else {
return nil
}
guard type == ${buffer_type} else {
return nil
}
guard let handle = (try? unpack(data))?.value.integerValue else {
return nil
}
self.handle = Int(handle)
}
}
extension RxNeovimApi.Window {
init?(_ value:RxNeovimApi.Value) {
guard let (type, data) = value.extendedValue else {
return nil
}
guard type == ${window_type} else {
return nil
}
guard let handle = (try? unpack(data))?.value.integerValue else {
return nil
}
self.handle = Int(handle)
}
}
extension RxNeovimApi.Tabpage {
init?(_ value:RxNeovimApi.Value) {
guard let (type, data) = value.extendedValue else {
return nil
}
guard type == ${tabpage_type} else {
return nil
}
guard let handle = (try? unpack(data))?.value.integerValue else {
return nil
}
self.handle = Int(handle)
}
}
fileprivate func msgPackDictToSwift(_ dict: Dictionary<RxNeovimApi.Value, RxNeovimApi.Value>?) -> Dictionary<String, RxNeovimApi.Value>? {
return dict?.compactMapToDict { k, v in
guard let strKey = k.stringValue else {
return nil
}
return (strKey, v)
}
}
fileprivate func msgPackArrayDictToSwift(_ array: [RxNeovimApi.Value]?) -> [Dictionary<String, RxNeovimApi.Value>]? {
return array?
.compactMap { v in v.dictionaryValue }
.compactMap { d in msgPackDictToSwift(d) }
}
extension Dictionary {
fileprivate func mapToDict<K, V>(_ transform: ((key: Key, value: Value)) throws -> (K, V)) rethrows -> Dictionary<K, V> {
let array = try self.map(transform)
return tuplesToDict(array)
}
fileprivate func compactMapToDict<K, V>(_ transform: ((key: Key, value: Value)) throws -> (K, V)?) rethrows -> Dictionary<K, V> {
let array = try self.compactMap(transform)
return tuplesToDict(array)
}
fileprivate func tuplesToDict<K:Hashable, V, S:Sequence>(_ sequence: S)
-> Dictionary<K, V> where S.Iterator.Element == (K, V) {
var result = Dictionary<K, V>(minimumCapacity: sequence.underestimatedCount)
for (key, value) in sequence {
result[key] = value
}
return result
}
}
''')
def snake_to_camel(snake_str):
components = snake_str.split('_')
return components[0] + "".join(x.title() for x in components[1:])
def nvim_type_to_swift(nvim_type):
if nvim_type == 'Boolean':
return 'Bool'
if nvim_type == 'Integer':
return 'Int'
if nvim_type == 'Float':
return nvim_type
if nvim_type == 'void':
return 'Void'
if nvim_type == 'String':
return 'String'
if nvim_type == 'Array':
return 'RxNeovimApi.Value'
if nvim_type == 'Dictionary':
return 'Dictionary<String, RxNeovimApi.Value>'
if nvim_type == 'Buffer':
return 'RxNeovimApi.Buffer'
if nvim_type == 'Window':
return 'RxNeovimApi.Window'
if nvim_type == 'Tabpage':
return 'RxNeovimApi.Tabpage'
if nvim_type == 'Object':
return 'RxNeovimApi.Value'
if nvim_type.startswith('ArrayOf('):
match = re.match(r'ArrayOf\((.*?)(?:, \d+)*\)', nvim_type)
return '[{}]'.format(nvim_type_to_swift(match.group(1)))
return 'RxNeovimApi.Value'
def msgpack_to_swift(msgpack_value_name, type):
if type == 'Bool':
return f'{msgpack_value_name}.boolValue'
if type == 'Int':
return f'({msgpack_value_name}.integerValue == nil ? nil : Int({msgpack_value_name}.integerValue!))'
if type == 'Float':
return f'{msgpack_value_name}.floatValue'
if type == 'Void':
return f'()'
if type == 'String':
return f'{msgpack_value_name}.stringValue'
if type == 'RxNeovimApi.Value':
return f'Optional({msgpack_value_name})'
if type in 'RxNeovimApi.Buffer':
return f'RxNeovimApi.Buffer({msgpack_value_name})'
if type in 'RxNeovimApi.Window':
return f'RxNeovimApi.Window({msgpack_value_name})'
if type in 'RxNeovimApi.Tabpage':
return f'RxNeovimApi.Tabpage({msgpack_value_name})'
if type.startswith('Dictionary<'):
return f'msgPackDictToSwift({msgpack_value_name}.dictionaryValue)'
if type.startswith('[Dictionary<'):
return f'msgPackArrayDictToSwift({msgpack_value_name}.arrayValue)'
if type.startswith('['):
element_type = re.match(r'\[(.*)\]', type).group(1)
return f'{msgpack_value_name}.arrayValue?.compactMap({{ v in {msgpack_to_swift("v", element_type)} }})'
return 'RxNeovimApi.Value'
def swift_to_msgpack_value(name, type):
if type == 'Bool':
return f'.bool({name})'
if type == 'Int':
return f'.int(Int64({name}))'
if type == 'Float':
return f'.float({name})'
if type == 'Void':
return f'.nil()'
if type == 'String':
return f'.string({name})'
if type == 'Dictionary<String, RxNeovimApi.Value>':
return f'.map({name}.mapToDict({{ (Value.string($0), $1) }}))'
if type == 'RxNeovimApi.Value':
return name
if type in ['RxNeovimApi.Buffer', 'RxNeovimApi.Window', 'RxNeovimApi.Tabpage']:
return f'.int(Int64({name}.handle))'
if type.startswith('['):
match = re.match(r'\[(.*)\]', type)
test = '$0'
return f'.array({name}.map {{ {swift_to_msgpack_value(test, match.group(1))} }})'
def parse_args(raw_params):
types = [nvim_type_to_swift(p[0]) for p in raw_params]
names = [p[1] for p in raw_params]
params = dict(zip(names, types))
result = '\n'.join([n + ': ' + t + ',' for n, t in params.items()])
if not result:
return ''
return '\n' + textwrap.indent(result, ' ')
def parse_params(raw_params):
types = [nvim_type_to_swift(p[0]) for p in raw_params]
names = [p[1] for p in raw_params]
params = dict(zip(names, types))
result = '\n'.join([swift_to_msgpack_value(n, t) + ',' for n, t in params.items()])
return textwrap.indent(result, ' ').strip()
def parse_function(f):
args = parse_args(f['parameters'])
template = void_func_template if f['return_type'] == 'void' else func_template
template = get_mode_func_template if f['name'] == 'nvim_get_mode' else template
result = template.substitute(
func_name=snake_to_camel(f['name'][5:]),
nvim_func_name=f['name'],
args=args,
params=parse_params(f['parameters']),
result_type=nvim_type_to_swift(f['return_type']),
return_value=msgpack_to_swift('value', nvim_type_to_swift(f['return_type']))
)
return result
def parse_version(version):
return '.'.join([str(v) for v in [version['major'], version['minor'], version['patch']]])
def parse_error_types(error_types):
return textwrap.indent(
'\n'.join(
[f'private static let {t.lower()}RawValue = UInt64({v["id"]})' for t, v in error_types.items()]
),
' '
).lstrip()
def parse_error_cases(error_types):
return textwrap.indent(
'\n'.join(
[f'case Error.{t.lower()}RawValue: self = .{t.lower()}(message: message)' for t, v in error_types.items()]
),
' '
).lstrip()
if __name__ == '__main__':
result_file_path = './RxNeovimApi.generated.swift'
nvim_path = os.environ['NVIM_PATH'] if 'NVIM_PATH' in os.environ else 'nvim'
nvim_output = subprocess.run([nvim_path, '--api-info'], stdout=subprocess.PIPE)
api = msgpack.unpackb(nvim_output.stdout, encoding='utf-8')
version = parse_version(api['version'])
functions = [f for f in api['functions'] if 'deprecated_since' not in f]
body = '\n'.join([parse_function(f) for f in functions])
result = extension_template.substitute(
body=body,
version=version,
error_types=parse_error_types(api['error_types']),
error_cases=parse_error_cases(api['error_types']),
buffer_type=api['types']['Buffer']['id'],
window_type=api['types']['Window']['id'],
tabpage_type=api['types']['Tabpage']['id']
)
with io.open(result_file_path, 'w') as api_methods_file:
api_methods_file.write(result)

105
RxPack/bin/release.sh Executable file
View File

@ -0,0 +1,105 @@
#!/bin/bash
set -e
export PATH=/usr/local/bin:$PATH
# This script is used by Jenkins to release the framework.
# BRANCH = "master"
# PUBLISH = true
# NVIM_VERSION = "v0.2.2"
if [[ "$NVIM_VERSION" == "" ]]; then
echo "NVIM_VERSION may not be blank: Exiting..."
exit 1
fi
rm -rf RxNeovimApi.framework.zip
pip3 install msgpack
git checkout -B temporary "origin/$BRANCH"
[[ "$NVIM_VERSION" == "nightly" ]] && nightly=true || nightly=false
if [[ "$nightly" != true ]]; then
git tag | grep -q $NVIM_VERSION && exists=true || exists=false
if [[ "$exists" == true && "$OVERRIDE_EXISTING" == false ]]; then
echo "Release $NVIM_VERSION already exists: Exiting..."
exit 1
fi
fi
echo $NVIM_VERSION > nvim-version.txt
git add nvim-version.txt
./bin/generate.sh
git add RxNeovimApi/ApiMethods.generated.swift
token=$(cat ~/.local/secrets/github.qvacua.release.token)
version="$(./.build/nvim-osx64/bin/nvim --version | grep ^NVIM | awk '{print $2}')"
target_version=$NVIM_VERSION
marketing_version=$target_version
if [[ "$nightly" == true ]]; then
agvtool new-marketing-version "$version"
else
version=$target_version
agvtool new-marketing-version "$target_version"
fi
git add RxNeovimApi/Info.plist RxNeovimApiTests/Info.plist
git commit -m "Release $version" || true
carthage update --platform osx
carthage build --no-skip-current --cache-builds --platform osx
carthage archive RxNeovimApi
if [[ "$PUBLISH" != true ]]; then
echo "Do not publish: Exiting..."
exit 0
fi
[[ "$target_version" == "nightly" ]] && tag="nightly" || tag=$target_version
echo "Deleting old release ${version}..."
GITHUB_TOKEN="$token" github-release delete \
--user qvacua \
--repo RxNeovimApi \
--tag $tag || true
git push origin :refs/tags/$tag || true
if [[ "$nightly" == true ]]; then
git tag -fam "Nightly: $version" $tag
else
git tag -fam "$target_version" $target_version
fi
git push origin temporary:$BRANCH
git push origin $tag
echo "Creating release..."
if [[ "$nightly" == true ]]; then
GITHUB_TOKEN="$token" github-release release \
--pre-release \
--user qvacua \
--repo RxNeovimApi \
--tag nightly \
--name Nightly \
--description "Nightly: Neovim $version"
else
GITHUB_TOKEN="${token}" github-release release \
--user qvacua \
--repo RxNeovimApi \
--tag "$target_version" \
--name "$target_version" \
--description "Neovim $version"
fi
echo "Uploading build..."
GITHUB_TOKEN="${token}" github-release upload \
--user qvacua \
--repo RxNeovimApi \
--tag $tag \
--name "RxNeovimApi.framework.zip" \
--file "RxNeovimApi.framework.zip"

1
RxPack/nvim-version.txt Normal file
View File

@ -0,0 +1 @@
v0.3.4