1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-11-30 16:51:59 +03:00

check versions on starting neovim via the pipe

This commit is contained in:
George Harker 2023-12-04 12:35:33 -08:00
parent 89e5446b6b
commit 870534c83d
3 changed files with 98 additions and 10 deletions

View File

@ -71,7 +71,19 @@ extension NvimView {
self.log.info("NVIM_LISTEN_ADDRESS=\(sockPath)") self.log.info("NVIM_LISTEN_ADDRESS=\(sockPath)")
self.bridge.runLocalServerAndNvim(width: size.width, height: size.height) do {
try self.bridge.runLocalServerAndNvim(width: size.width, height: size.height)
}
catch let err as RxNeovimApi.Error {
self.eventsSubject.onNext(.ipcBecameInvalid(
"Could not launch neovim (\(err))."
))
}
catch {
self.eventsSubject.onNext(.ipcBecameInvalid(
"Could not launch neovim."
))
}
// Wait for listen and socket creation to occur // Wait for listen and socket creation to occur
let timeout = Duration.seconds(4) let timeout = Duration.seconds(4)
@ -92,7 +104,12 @@ extension NvimView {
try? try?
self.api.run(at: sockPath) self.api.run(at: sockPath)
.andThen( .andThen(
self.api.getApiInfo().map { self.api.getApiInfo()
.do(onError: { err in
throw RxNeovimApi.Error
.exception(message: "Could not connect to neovim (\(err)).")
})
.map {
value in value in
guard let info = value.arrayValue, guard let info = value.arrayValue,
info.count == 2, info.count == 2,
@ -105,13 +122,13 @@ extension NvimView {
throw RxNeovimApi.Error throw RxNeovimApi.Error
.exception(message: "Could not convert values to api info.") .exception(message: "Could not convert values to api info.")
} }
guard major >= 0 && minor >= 10 || major >= 1 guard (major >= kMinAlphaVersion && minor >= kMinMinorVersion) || major >= kMinMajorVersion
else { else {
self.eventsSubject.onNext(.ipcBecameInvalid( self.eventsSubject.onNext(.ipcBecameInvalid(
"Incompatible neovim version \(major).\(minor)" "Incompatible neovim version \(major).\(minor)"
)) ))
throw RxNeovimApi.Error throw RxNeovimApi.Error
.exception(message: "Could not convert values to api info.") .exception(message: "Incompatible neovim version.")
} }
return channel return channel

View File

@ -9,6 +9,12 @@ import MessagePack
import os import os
import RxPack import RxPack
import RxSwift import RxSwift
import RxNeovim
import RxPack
let kMinAlphaVersion = 0
let kMinMinorVersion = 10
let kMinMajorVersion = 1
final class UiBridge { final class UiBridge {
init(uuid: UUID, config: NvimView.Config) { init(uuid: UUID, config: NvimView.Config) {
@ -33,11 +39,11 @@ final class UiBridge {
} }
} }
func runLocalServerAndNvim(width: Int, height: Int) { func runLocalServerAndNvim(width: Int, height: Int) throws {
self.initialWidth = width self.initialWidth = width
self.initialHeight = height self.initialHeight = height
self.launchNvimUsingLoginShellEnv() try self.launchNvimUsingLoginShellEnv()
} }
func quit() -> Completable { func quit() -> Completable {
@ -64,7 +70,7 @@ final class UiBridge {
self.nvimServerProc?.terminate() self.nvimServerProc?.terminate()
} }
private func launchNvimUsingLoginShellEnv() { private func launchNvimUsingLoginShellEnv() throws {
var env = self.envDict var env = self.envDict
env["NVIM_LISTEN_ADDRESS"] = self.listenAddress env["NVIM_LISTEN_ADDRESS"] = self.listenAddress
@ -103,12 +109,77 @@ final class UiBridge {
do { do {
try process.run() try process.run()
} catch { } catch {
return throw RxNeovimApi.Error
.exception(message: "Could not run neovim process.")
} }
try self.doInitialVersionCheck(inPipe: inPipe, outPipe: outPipe)
self.nvimServerProc = process self.nvimServerProc = process
} }
private func doInitialVersionCheck(inPipe: Pipe, outPipe: Pipe) throws {
// Construct Msgpack query for api info
let packed = pack(
[
.uint(RxMsgpackRpc.MessageType.request.rawValue),
.uint(UInt64(0)),
.string("nvim_get_api_info"),
.array([]),
]
)
try inPipe.fileHandleForWriting.write(contentsOf: packed)
// Read responses from the pipe back
var accumulatedData : Data = Data()
var values : [MessagePackValue] = []
var remainderData: Data? = nil
while (true) {
let data = outPipe.fileHandleForReading.availableData
if data.count == 0 {
break
}
accumulatedData.append(data)
try (values, remainderData) = RxMsgpackRpc.unpackAllWithReminder(accumulatedData)
if let remainderData { accumulatedData = remainderData }
else { accumulatedData.count = 0 }
if values.count > 0 {
break
}
}
// Validate version response
guard values.count >= 1,
let firstResponse = values[0].arrayValue,
firstResponse.count == 4,
let rawType = firstResponse[0].uint64Value,
let type = RxMsgpackRpc.MessageType(rawValue: rawType),
type == RxMsgpackRpc.MessageType.response /* this is a response */,
let msgId = firstResponse[1].uint64Value,
msgId == 0 /* no confusion on stream */,
firstResponse[2] == nil /* no error */,
let info = firstResponse[3].arrayValue /* response value */,
info.count == 2,
let dict = info[1].dictionaryValue,
let version = dict["version"]?.dictionaryValue,
let major = version["major"]?.intValue,
let minor = version["minor"]?.intValue
else {
throw RxNeovimApi.Error
.exception(message: "Could not convert values to api info.")
}
guard (major >= kMinAlphaVersion && minor >= kMinMinorVersion) || major >= kMinMajorVersion
else {
throw RxNeovimApi.Error
.exception(message: "Incompatible neovim version.")
}
}
private func interactive(for shell: URL) -> Bool { private func interactive(for shell: URL) -> Bool {
if shell.lastPathComponent == "zsh" { return self.usesInteractiveZsh } if shell.lastPathComponent == "zsh" { return self.usesInteractiveZsh }
return true return true

View File

@ -202,7 +202,7 @@ public final class RxMsgpackRpc {
if readBytes > 0 { if readBytes > 0 {
dataToUnmarshall.append(readData) dataToUnmarshall.append(readData)
let (values, remainderData) = try self.unpackAllWithReminder(dataToUnmarshall) let (values, remainderData) = try RxMsgpackRpc.unpackAllWithReminder(dataToUnmarshall)
if let remainderData { dataToUnmarshall = remainderData } if let remainderData { dataToUnmarshall = remainderData }
else { dataToUnmarshall.count = 0 } else { dataToUnmarshall.count = 0 }
@ -294,7 +294,7 @@ public final class RxMsgpackRpc {
} }
} }
private func unpackAllWithReminder(_ data: Data) throws -> (values: [Value], remainder: Data?) { public static func unpackAllWithReminder(_ data: Data) throws -> (values: [Value], remainder: Data?) {
var values = [Value]() var values = [Value]()
var remainderData: Data? var remainderData: Data?