mirror of
https://github.com/qvacua/vimr.git
synced 2024-12-25 06:43:24 +03:00
Refactor nvim launching
- First execute env in login shell and use the resulting env vars to launch nvim
This commit is contained in:
parent
36b0359ae1
commit
8504bdbba8
@ -13,6 +13,7 @@
|
||||
1929B8CA73D3702364903BB7 /* SimpleCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD86668017F804408E3A /* SimpleCache.swift */; };
|
||||
1929BA70C221E3C199833B8C /* UiBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B52174EC68D2974B5BAE /* UiBridge.swift */; };
|
||||
1929BA93BDEA029011F034FF /* RxSwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929B6F4B70B90F7CFB7B523 /* RxSwiftCommons.swift */; };
|
||||
1929BCA615324C58582BFC3C /* ProcessUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1929BD167BE7C6BB788DAE2A /* ProcessUtils.swift */; };
|
||||
4B177886201220F300E32FF0 /* SharedTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 1929B4F32708E99C40A57020 /* SharedTypes.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
4B17E549209E3E4100265C1D /* RxNeovimApi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B17E548209E3E4100265C1D /* RxNeovimApi.framework */; };
|
||||
4B8662E81FDC3F9F007F490D /* vimr.vim in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B8662E41FDC3D4F007F490D /* vimr.vim */; };
|
||||
@ -100,6 +101,7 @@
|
||||
1929B52174EC68D2974B5BAE /* UiBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UiBridge.swift; sourceTree = "<group>"; };
|
||||
1929B6F4B70B90F7CFB7B523 /* RxSwiftCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxSwiftCommons.swift; sourceTree = "<group>"; };
|
||||
1929BBD7F88AE4F01E626691 /* NvimApiExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NvimApiExtension.swift; sourceTree = "<group>"; };
|
||||
1929BD167BE7C6BB788DAE2A /* ProcessUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcessUtils.swift; sourceTree = "<group>"; };
|
||||
1929BD86668017F804408E3A /* SimpleCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleCache.swift; sourceTree = "<group>"; };
|
||||
4B17E548209E3E4100265C1D /* RxNeovimApi.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxNeovimApi.framework; path = ../Carthage/Build/Mac/RxNeovimApi.framework; sourceTree = "<group>"; };
|
||||
4B8662E41FDC3D4F007F490D /* vimr.vim */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = vimr.vim; sourceTree = "<group>"; };
|
||||
@ -228,6 +230,7 @@
|
||||
1929B6F4B70B90F7CFB7B523 /* RxSwiftCommons.swift */,
|
||||
1929B44323D6611E2927EC3B /* MessagePackCommons.swift */,
|
||||
1929BD86668017F804408E3A /* SimpleCache.swift */,
|
||||
1929BD167BE7C6BB788DAE2A /* ProcessUtils.swift */,
|
||||
);
|
||||
path = NvimView;
|
||||
sourceTree = "<group>";
|
||||
@ -409,6 +412,7 @@
|
||||
1929BA93BDEA029011F034FF /* RxSwiftCommons.swift in Sources */,
|
||||
1929B30D6C4175835D1F5B21 /* MessagePackCommons.swift in Sources */,
|
||||
1929B8CA73D3702364903BB7 /* SimpleCache.swift in Sources */,
|
||||
1929BCA615324C58582BFC3C /* ProcessUtils.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
51
NvimView/NvimView/ProcessUtils.swift
Normal file
51
NvimView/NvimView/ProcessUtils.swift
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
|
||||
class ProcessUtils {
|
||||
|
||||
static func envVars(of shellPath: URL, usingInteractiveMode: Bool) -> [String: String] {
|
||||
let shellName = shellPath.lastPathComponent
|
||||
var shellArgs = [String]()
|
||||
|
||||
if shellName != "tcsh" {
|
||||
shellArgs.append("-l")
|
||||
}
|
||||
|
||||
if usingInteractiveMode {
|
||||
shellArgs.append("-i")
|
||||
}
|
||||
|
||||
shellArgs.append(contentsOf: ["-c", "env"])
|
||||
|
||||
let outputPipe = Pipe()
|
||||
let errorPipe = Pipe()
|
||||
|
||||
let process = Process()
|
||||
process.launchPath = shellPath.path
|
||||
process.arguments = shellArgs
|
||||
process.standardOutput = outputPipe
|
||||
process.standardError = errorPipe
|
||||
process.currentDirectoryPath = NSHomeDirectory()
|
||||
process.launch()
|
||||
|
||||
let readHandle = outputPipe.fileHandleForReading
|
||||
guard let output = String(data: readHandle.readDataToEndOfFile(), encoding: .utf8) else {
|
||||
return [:]
|
||||
}
|
||||
readHandle.closeFile()
|
||||
|
||||
process.terminate()
|
||||
process.waitUntilExit()
|
||||
|
||||
return output
|
||||
.split(separator: "\n")
|
||||
.reduce(into: [:]) { result, entry in
|
||||
let split = entry.split(separator: "=", maxSplits: 1, omittingEmptySubsequences: false).map { String($0) }
|
||||
result[split[0]] = split[1]
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
//
|
||||
// Created by Tae Won Ha on 21.05.18.
|
||||
// Copyright (c) 2018 Tae Won Ha. All rights reserved.
|
||||
//
|
||||
/**
|
||||
* Tae Won Ha - http://taewon.de - @hataewon
|
||||
* See LICENSE
|
||||
*/
|
||||
|
||||
|
||||
import Foundation
|
||||
|
||||
|
@ -71,13 +71,13 @@ class UiBridge {
|
||||
self.server.queue = self.queue
|
||||
|
||||
self.server.stream
|
||||
.subscribe(onNext: { message in
|
||||
self.handleMessage(msgId: message.msgid, data: message.data)
|
||||
}, onError: { error in
|
||||
self.logger.error("There was an error on the local message port server: \(error)")
|
||||
self.streamSubject.onError(Error.ipc(error))
|
||||
})
|
||||
.disposed(by: self.disposeBag)
|
||||
.subscribe(onNext: { message in
|
||||
self.handleMessage(msgId: message.msgid, data: message.data)
|
||||
}, onError: { error in
|
||||
self.logger.error("There was an error on the local message port server: \(error)")
|
||||
self.streamSubject.onError(Error.ipc(error))
|
||||
})
|
||||
.disposed(by: self.disposeBag)
|
||||
}
|
||||
|
||||
func runLocalServerAndNvim(width: Int, height: Int) -> Completable {
|
||||
@ -85,15 +85,15 @@ class UiBridge {
|
||||
self.initialHeight = height
|
||||
|
||||
return self.server
|
||||
.run(as: self.localServerName)
|
||||
.andThen(Completable.create { completable in
|
||||
self.runLocalServerAndNvimCompletable = completable
|
||||
self.launchNvimUsingLoginShell()
|
||||
.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(timeout, scheduler: self.scheduler)
|
||||
// This will be completed in .nvimReady branch of handleMessage()
|
||||
return Disposables.create()
|
||||
})
|
||||
.timeout(timeout, scheduler: self.scheduler)
|
||||
}
|
||||
|
||||
func vimInput(_ str: String) -> Completable {
|
||||
@ -150,11 +150,11 @@ class UiBridge {
|
||||
|
||||
case .serverReady:
|
||||
self
|
||||
.establishNvimConnection()
|
||||
.subscribe(onError: { error in
|
||||
self.streamSubject.onError(Error.ipc(error))
|
||||
})
|
||||
.disposed(by: self.disposeBag)
|
||||
.establishNvimConnection()
|
||||
.subscribe(onError: { error in
|
||||
self.streamSubject.onError(Error.ipc(error))
|
||||
})
|
||||
.disposed(by: self.disposeBag)
|
||||
|
||||
case .nvimReady:
|
||||
self.runLocalServerAndNvimCompletable?(.completed)
|
||||
@ -310,7 +310,7 @@ class UiBridge {
|
||||
let dict = (try? unpack(d))?.value.dictionaryValue,
|
||||
let key = dict.keys.first?.stringValue,
|
||||
let value = dict.values.first
|
||||
else {
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -331,31 +331,31 @@ class UiBridge {
|
||||
|
||||
private func closePorts() -> Completable {
|
||||
return self.client
|
||||
.stop()
|
||||
.andThen(self.server.stop())
|
||||
.stop()
|
||||
.andThen(self.server.stop())
|
||||
}
|
||||
|
||||
private func quit(using body: @escaping () -> Void) -> Completable {
|
||||
return self
|
||||
.closePorts()
|
||||
.andThen(Completable.create { completable in
|
||||
body()
|
||||
.closePorts()
|
||||
.andThen(Completable.create { completable in
|
||||
body()
|
||||
|
||||
completable(.completed)
|
||||
return Disposables.create()
|
||||
})
|
||||
completable(.completed)
|
||||
return Disposables.create()
|
||||
})
|
||||
}
|
||||
|
||||
private func establishNvimConnection() -> Completable {
|
||||
return self.client
|
||||
.connect(to: self.remoteServerName)
|
||||
.andThen(self.sendMessage(msgId: .agentReady, data: [self.initialWidth, self.initialHeight].data()))
|
||||
.connect(to: self.remoteServerName)
|
||||
.andThen(self.sendMessage(msgId: .agentReady, data: [self.initialWidth, self.initialHeight].data()))
|
||||
}
|
||||
|
||||
private func sendMessage(msgId: NvimBridgeMsgId, data: Data?) -> Completable {
|
||||
return self.client
|
||||
.send(msgid: Int32(msgId.rawValue), data: data, expectsReply: false)
|
||||
.asCompletable()
|
||||
.send(msgid: Int32(msgId.rawValue), data: data, expectsReply: false)
|
||||
.asCompletable()
|
||||
}
|
||||
|
||||
private func forceExitNvimServer() {
|
||||
@ -363,47 +363,28 @@ class UiBridge {
|
||||
self.nvimServerProc?.terminate()
|
||||
}
|
||||
|
||||
private func launchNvimUsingLoginShell() {
|
||||
private func launchNvimUsingLoginShellEnv() {
|
||||
let selfEnv = ProcessInfo.processInfo.environment
|
||||
let shellUrl = URL(fileURLWithPath: selfEnv["SHELL"] ?? "/bin/bash")
|
||||
|
||||
let shellPath = URL(fileURLWithPath: selfEnv["SHELL"] ?? "/bin/bash")
|
||||
let shellName = shellPath.lastPathComponent
|
||||
var shellArgs = [String]()
|
||||
if shellName != "tcsh" {
|
||||
// tcsh does not like the -l option
|
||||
shellArgs.append("-l")
|
||||
}
|
||||
if self.useInteractiveZsh && shellName == "zsh" {
|
||||
shellArgs.append("-i")
|
||||
}
|
||||
let interactiveMode = shellUrl.lastPathComponent == "zsh" && !self.useInteractiveZsh ? false : true
|
||||
var env = ProcessUtils.envVars(of: shellUrl, usingInteractiveMode: interactiveMode)
|
||||
|
||||
let listenAddress = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("vimr_\(self.uuid).sock")
|
||||
var env = selfEnv
|
||||
env["NVIM_LISTEN_ADDRESS"] = listenAddress.path
|
||||
|
||||
let inputPipe = Pipe()
|
||||
let outPipe = Pipe()
|
||||
let errorPipe = Pipe()
|
||||
let process = Process()
|
||||
process.environment = env
|
||||
process.standardInput = inputPipe
|
||||
process.standardError = errorPipe
|
||||
process.standardOutput = outPipe
|
||||
process.currentDirectoryPath = self.cwd.path
|
||||
process.launchPath = shellPath.path
|
||||
process.arguments = shellArgs
|
||||
process.launchPath = self.nvimServerExecutablePath()
|
||||
process.arguments = [self.localServerName, self.remoteServerName] + self.nvimArgs + ["--headless"]
|
||||
process.launch()
|
||||
|
||||
self.nvimServerProc = process
|
||||
|
||||
nvimArgs.append("--headless")
|
||||
let cmd = "exec '\(self.nvimServerExecutablePath())' '\(self.localServerName)' '\(self.remoteServerName)' "
|
||||
.appending(self.nvimArgs.map { "'\($0)'" }.joined(separator: " "))
|
||||
|
||||
self.logger.debug(cmd)
|
||||
|
||||
let writeHandle = inputPipe.fileHandleForWriting
|
||||
guard let cmdData = cmd.data(using: .utf8) else {
|
||||
preconditionFailure("Could not get Data from the string '\(cmd)'")
|
||||
}
|
||||
writeHandle.write(cmdData)
|
||||
writeHandle.closeFile()
|
||||
}
|
||||
|
||||
private func nvimServerExecutablePath() -> String {
|
||||
|
Loading…
Reference in New Issue
Block a user