Files
wehub-resource-sync 1d1286fadb
Build / Build and test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:18:38 +08:00

232 lines
10 KiB
Swift

import Foundation
import MacToolsPluginKit
// MARK: - ZshConfigFileType
/// Standard zsh configuration files in the user's home directory.
enum ZshConfigFileType: String, CaseIterable, Identifiable, Codable {
case zshrc = ".zshrc"
case zshenv = ".zshenv"
case zprofile = ".zprofile"
case zlogin = ".zlogin"
case zlogout = ".zlogout"
var id: String { rawValue }
var filename: String { rawValue }
/// One-sentence description of the file's role.
var role: String {
role()
}
func role(localization: PluginLocalization = PluginLocalization(bundle: .main)) -> String {
switch self {
case .zshrc:
return localization.string("file.zshrc.role", defaultValue: "交互式 Shell 配置:别名、函数、提示符等")
case .zshenv:
return localization.string("file.zshenv.role", defaultValue: "所有 Shell 的环境变量,最先被加载")
case .zprofile:
return localization.string("file.zprofile.role", defaultValue: "登录 Shell 初始化,早于 .zshrc")
case .zlogin:
return localization.string("file.zlogin.role", defaultValue: "登录 Shell 完成初始化后执行")
case .zlogout:
return localization.string("file.zlogout.role", defaultValue: "退出登录 Shell 时执行的清理脚本")
}
}
/// Describes when zsh loads this file.
var whenLoaded: String {
whenLoaded()
}
func whenLoaded(localization: PluginLocalization = PluginLocalization(bundle: .main)) -> String {
switch self {
case .zshrc:
return localization.string("file.zshrc.whenLoaded", defaultValue: "每次打开新终端窗口/标签页时")
case .zshenv:
return localization.string("file.zshenv.whenLoaded", defaultValue: "每次启动 zsh(包括脚本、非交互式)时")
case .zprofile:
return localization.string("file.zprofile.whenLoaded", defaultValue: "登录时(SSH、macOS 登录等),早于 .zshrc")
case .zlogin:
return localization.string("file.zlogin.whenLoaded", defaultValue: "登录时,晚于 .zshrc")
case .zlogout:
return localization.string("file.zlogout.whenLoaded", defaultValue: "登录 Shell 退出时(`exit` 或关闭终端)")
}
}
/// Recommended uses for this file.
var recommendedUse: String {
recommendedUse()
}
func recommendedUse(localization: PluginLocalization = PluginLocalization(bundle: .main)) -> String {
switch self {
case .zshrc:
return localization.string("file.zshrc.recommendedUse", defaultValue: "alias、函数、主题(Oh My Zsh / Starship 等)、PATH")
case .zshenv:
return localization.string("file.zshenv.recommendedUse", defaultValue: "EDITOR、LANG、必须对所有子进程可见的变量")
case .zprofile:
return localization.string("file.zprofile.recommendedUse", defaultValue: "Homebrew 的环境初始化、一次性登录脚本")
case .zlogin:
return localization.string("file.zlogin.recommendedUse", defaultValue: "欢迎信息、tmux 自动启动等")
case .zlogout:
return localization.string("file.zlogout.recommendedUse", defaultValue: "清理临时文件、记录会话日志")
}
}
/// Absolute URL under the user's home directory.
var fileURL: URL {
FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent(rawValue)
}
}
// MARK: - ZshFileStatus
/// Current status snapshot for a zsh configuration file.
struct ZshFileStatus {
let type: ZshConfigFileType
let exists: Bool
let isWritable: Bool
let byteSize: Int
let modifiedDate: Date?
var formattedSize: String {
guard exists else { return "" }
if byteSize < 1024 { return "\(byteSize) B" }
return String(format: "%.1f KB", Double(byteSize) / 1024)
}
/// Probes the actual file status through FileManager.
static func probe(_ type: ZshConfigFileType) -> ZshFileStatus {
let url = type.fileURL
let fm = FileManager.default
var isDir: ObjCBool = false
let exists = fm.fileExists(atPath: url.path, isDirectory: &isDir) && !isDir.boolValue
let isWritable: Bool
if exists {
isWritable = fm.isWritableFile(atPath: url.path)
} else {
isWritable = fm.isWritableFile(atPath: url.deletingLastPathComponent().path)
}
var byteSize = 0
var modifiedDate: Date? = nil
if exists,
let attrs = try? fm.attributesOfItem(atPath: url.path) {
byteSize = (attrs[.size] as? Int) ?? 0
modifiedDate = attrs[.modificationDate] as? Date
}
return ZshFileStatus(
type: type,
exists: exists,
isWritable: isWritable,
byteSize: byteSize,
modifiedDate: modifiedDate
)
}
}
// MARK: - ZshSnippet
/// Quick-insert snippet template.
struct ZshSnippet: Identifiable, Sendable {
let id: String
let icon: String
let title: String
let description: String
let placeholder: String
/// Builds the text to insert from user input.
let buildContent: @Sendable (String) -> String
static let all: [ZshSnippet] = localizedSnippets()
static func localizedSnippets(
localization: PluginLocalization = PluginLocalization(bundle: .main)
) -> [ZshSnippet] {
[
ZshSnippet(
id: "alias",
icon: "arrow.uturn.right",
title: localization.string("snippet.alias.title", defaultValue: "别名"),
description: localization.string("snippet.alias.description", defaultValue: "为命令创建快捷方式"),
placeholder: localization.string("snippet.alias.placeholder", defaultValue: "名称=命令,例:gs=git status"),
buildContent: { input in
let trimmed = input.trimmingCharacters(in: .whitespaces)
let parts = trimmed.split(separator: "=", maxSplits: 1).map(String.init)
if parts.count == 2 {
return "alias \(parts[0].trimmingCharacters(in: .whitespaces))='\(parts[1].trimmingCharacters(in: .whitespaces))'"
}
return "alias \(trimmed)=''"
}
),
ZshSnippet(
id: "export",
icon: "square.and.arrow.up",
title: localization.string("snippet.export.title", defaultValue: "环境变量"),
description: localization.string("snippet.export.description", defaultValue: "设置或覆盖环境变量"),
placeholder: localization.string("snippet.export.placeholder", defaultValue: "变量名=值,例:EDITOR=nvim"),
buildContent: { input in
let trimmed = input.trimmingCharacters(in: .whitespaces)
let parts = trimmed.split(separator: "=", maxSplits: 1).map(String.init)
if parts.count == 2 {
return "export \(parts[0].trimmingCharacters(in: .whitespaces))=\(parts[1].trimmingCharacters(in: .whitespaces))"
}
return "export \(trimmed)="
}
),
ZshSnippet(
id: "path",
icon: "folder.badge.plus",
title: localization.string("snippet.path.title", defaultValue: "PATH 路径"),
description: localization.string("snippet.path.description", defaultValue: "将目录追加到 $PATH"),
placeholder: localization.string("snippet.path.placeholder", defaultValue: "目录路径,例:/opt/homebrew/bin"),
buildContent: { input in
let path = input.trimmingCharacters(in: .whitespaces)
guard !path.isEmpty else { return "export PATH=\"$PATH:/your/path\"" }
return "export PATH=\"$PATH:\(path)\""
}
),
ZshSnippet(
id: "source",
icon: "doc.badge.plus",
title: localization.string("snippet.source.title", defaultValue: "加载文件"),
description: localization.string("snippet.source.description", defaultValue: "在当前 Shell 中执行另一个脚本"),
placeholder: localization.string("snippet.source.placeholder", defaultValue: "文件路径,例:~/.config/secrets.sh"),
buildContent: { input in
let path = input.trimmingCharacters(in: .whitespaces)
guard !path.isEmpty else { return "source ~/.your-script.sh" }
return "source \(path)"
}
),
ZshSnippet(
id: "function",
icon: "f.cursive",
title: localization.string("snippet.function.title", defaultValue: "函数"),
description: localization.string("snippet.function.description", defaultValue: "定义一个可复用的 Shell 函数"),
placeholder: localization.string("snippet.function.placeholder", defaultValue: "函数名称,例:mkcd"),
buildContent: { input in
let name = input.trimmingCharacters(in: .whitespaces)
let funcName = name.isEmpty ? "my_func" : name
let comment = localization.string("snippet.function.bodyComment", defaultValue: "在此填写函数内容")
return "\(funcName)() {\n # \(comment)\n \n}"
}
),
ZshSnippet(
id: "eval",
icon: "terminal",
title: localization.string("snippet.eval.title", defaultValue: "初始化工具"),
description: localization.string("snippet.eval.description", defaultValue: "执行工具的 eval 初始化命令"),
placeholder: localization.string("snippet.eval.placeholder", defaultValue: "工具命令,例:$(brew shellenv)"),
buildContent: { input in
let cmd = input.trimmingCharacters(in: .whitespaces)
guard !cmd.isEmpty else { return "eval \"$(your-tool init zsh)\"" }
if cmd.hasPrefix("$(") || cmd.hasPrefix("`") {
return "eval \"\(cmd)\""
}
return "eval \"$(\(cmd))\""
}
),
]
}
}