1
1
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:
Tae Won Ha 2018-07-03 07:47:58 +02:00
parent 36b0359ae1
commit 8504bdbba8
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
4 changed files with 103 additions and 66 deletions

View File

@ -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;
};

View 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]
}
}
}

View File

@ -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

View File

@ -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 {