CodeEditApp / CodeEditApp/CodeEdit

Using directory local environment for language servers and other functionality

未關閉
#2,069 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
enhancement extensions workspace
主要語言
Swift
星號
23k
分支
1.2k
PR 合併指標
30 天內沒有已合併 PR

描述

### Description

Environment providers.

I propose a new struct: `EnvironmentProviderStore`, for the environment providers, which would be used to get the environment for the current directory. This should be implemented in two stages:
a) Implement the API inside of CodeEdit to iron out rough edges, implement support for direnv, venv, asdf and dotenv using it.
b) Create an extension API allowing users to extend CodeEdit with their own environment providers, move existing ones to the extensions

The protocol is as follows:
```swift
protocol EnvironmentProvider {
var displayName { get }
func update_env(_ env: [String : String], for directory: FilePath) async throws -> [String: String]
}
```

Then, based on this protocol, projects should use functions reliant on it to find binaries in path, as well as passing the environment to executed processes

### Alternatives Considered

Install everything globally

### Additional Context

An example implementation for `direnv`
```swift
import Foundation

struct DirenvProvider: EnvironmentProvider {
let displayName = "direnv"

func update_env(_ env: [String: String], for directory: FilePath) async throws -> [String: String] {
let process = Process()
process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
process.arguments = ["direnv", "export", "json"]
process.currentDirectoryURL = URL(fileURLWithPath: directory.string)
process.environment = env

let pipe = Pipe()
process.standardOutput = pipe
process.standardError = Pipe()

try process.run()
process.waitUntilExit()

guard process.terminationStatus == 0 else {
throw DirenvError.commandFailed(exitCode: process.terminationStatus)
}

let data = pipe.fileHandleForReading.readDataToEndOfFile()
guard let jsonString = String(data: data, encoding: .utf8) else {
throw DirenvError.invalidOutput
}

guard let jsonData = jsonString.data(using: .utf8),
let exportedEnv = try JSONSerialization.jsonObject(with: jsonData) as? [String: String] else {
throw DirenvError.jsonParsingFailed
}

var updatedEnv = env
for (key, value) in exportedEnv {
updatedEnv[key] = value
}

return updatedEnv
}
}

enum DirenvError: Error, LocalizedError {
case commandFailed(exitCode: Int32)
case invalidOutput
case jsonParsingFailed

var errorDescription: String? {
switch self {
case .commandFailed(let exitCode):
return "direnv command failed with exit code \(exitCode)"
case .invalidOutput:
return "direnv produced invalid output"
case .jsonParsingFailed:
return "Failed to parse direnv JSON output"
}
}
}
```

This should of course be made to asynchronously execute the direnv process but that's mostly details

Zed implementation for reference (it hardcodes direnv and relies on a shell hook for everything else which is explicitly **not** what I want to do here:
https://github.com/zed-industries/zed/blob/main/crates/util/src/shell_env.rs
https://github.com/zed-industries/zed/blob/main/crates/project/src/environment.rs#L178

### Screenshots

_No response_

貢獻指南

開啟貢獻指南

評估

這個 Issue 還沒有評估資料。

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。