ziro 0.0.21

跨平台端口管理工具 - 快速查找和终止占用端口的进程
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
use crate::cli::Cli;
use std::process::Command;
use std::{env, sync::OnceLock};

#[derive(Clone, Debug)]
pub struct TerminalProfile {
    pub plain: bool,
    pub ascii_icons: bool,
    pub no_color: bool,
    pub narrow: bool,
    pub alt_screen: bool,
    pub incremental: bool,
}

impl Default for TerminalProfile {
    fn default() -> Self {
        Self {
            plain: false,
            ascii_icons: false,
            no_color: false,
            narrow: false,
            alt_screen: true,
            incremental: true,
        }
    }
}

static GLOBAL_PROFILE: OnceLock<TerminalProfile> = OnceLock::new();

pub fn set_global_profile(profile: TerminalProfile) {
    let _ = GLOBAL_PROFILE.set(profile);
}

pub fn global_profile() -> TerminalProfile {
    GLOBAL_PROFILE
        .get()
        .cloned()
        .unwrap_or_else(TerminalProfile::default)
}

pub fn detect_profile(cli: &Cli) -> TerminalProfile {
    // 用户显式参数优先
    let mut profile = TerminalProfile {
        plain: cli.plain || is_truthy_env("ZIRO_PLAIN"),
        ascii_icons: cli.ascii || is_truthy_env("ZIRO_ASCII_ICONS"),
        no_color: cli.no_color || is_truthy_env("ZIRO_NO_COLOR") || is_truthy_env("NO_COLOR"),
        narrow: cli.narrow || is_truthy_env("ZIRO_NARROW"),
        ..TerminalProfile::default()
    };

    // 检测终端能力
    let is_windows = cfg!(target_os = "windows");
    let vt_supported = has_virtual_terminal_processing();

    let looks_modern = env::var("WT_SESSION").is_ok()
        || env::var("TERM")
            .map(|t| {
                let t = t.to_lowercase();
                t.contains("xterm")
                    || t.contains("cygwin")
                    || t.contains("screen")
                    || t.contains("tmux")
            })
            .unwrap_or(false)
        || env::var("ConEmuANSI").is_ok()
        || env::var("ANSICON").is_ok()
        || env::var("TERM_PROGRAM").is_ok()
        || vt_supported
        || is_modern_terminal();
    let utf8_ok = if is_windows {
        detect_windows_utf8()
            || env::var("LC_ALL")
                .or_else(|_| env::var("LANG"))
                .map(|v| v.to_lowercase().contains("65001") || v.to_lowercase().contains("utf-8"))
                .unwrap_or(false)
    } else {
        env::var("LC_ALL")
            .or_else(|_| env::var("LANG"))
            .map(|v| v.to_lowercase().contains("utf-8"))
            .unwrap_or(true)
    };

    // 改进的智能降级策略
    // 自动降级条件分析:
    // 1. 用户显式要求 plain 模式
    // 2. 非 Windows 系统且非 UTF-8 环境(大概率会乱码)
    // 3. Windows 系统下的不安全组合:
    //    - 既非 UTF-8 又非现代终端
    //    - Windows PowerShell 5.1 但不在现代终端中
    //    - 检测到传统控制台环境(conhost)
    let should_degrade = profile.plain
        || (!is_windows && !utf8_ok)
        || (is_windows && should_degrade_on_windows(utf8_ok, looks_modern, vt_supported));

    if should_degrade {
        profile.plain = true;
        profile.ascii_icons = true;
        profile.no_color = true;
        profile.narrow = true;
        profile.alt_screen = false;
        profile.incremental = false;
    }

    profile
}

pub fn apply_profile_env(profile: &TerminalProfile) {
    unsafe {
        env::set_var("ZIRO_PLAIN", bool_to_flag(profile.plain));
        env::set_var(
            "ZIRO_ASCII_ICONS",
            bool_to_flag(profile.ascii_icons || profile.plain),
        );
        env::set_var(
            "ZIRO_NO_COLOR",
            bool_to_flag(profile.no_color || profile.plain),
        );
        env::set_var("ZIRO_NARROW", bool_to_flag(profile.narrow || profile.plain));
    }
}

fn is_truthy_env(key: &str) -> bool {
    env::var(key)
        .map(|v| matches!(v.to_lowercase().as_str(), "1" | "true" | "yes" | "on"))
        .unwrap_or(false)
}

/// 检测是否为现代终端(改进版本)
fn is_modern_terminal() -> bool {
    // 1. PowerShell 环境的精确检测
    if is_powershell_core() {
        // PowerShell Core 通常是现代的
        return true;
    }

    if is_windows_powershell_legacy() {
        // Windows PowerShell 5.1 在传统控制台中可能不支持 ANSI
        return is_windows_terminal_or_conemu();
    }

    // 2. 检查 Windows Terminal 或其他现代终端
    if is_windows_terminal_or_conemu() {
        return true;
    }

    // 3. 更广泛的现代终端检测
    if let Ok(term_program) = env::var("TERM_PROGRAM") {
        let term_program = term_program.to_lowercase();
        // 支持更多现代终端
        if [
            "vscode",
            "hyper",
            "terminus",
            "windowsterminal",
            "warp",
            "wt",
            "warpterminal",
            "iterm",
            "alacritty",
            "kitty",
            "wezterm",
        ]
        .contains(&term_program.as_str())
        {
            return true;
        }
    }

    // 4. TERM 变量检测(Unix-like 终端模拟器)
    if let Ok(term) = env::var("TERM") {
        let term = term.to_lowercase();
        if term.contains("xterm")
            || term.contains("screen")
            || term.contains("tmux")
            || term.contains("256color")
            || term.contains("alacritty")
            || term.contains("kitty")
        {
            return true;
        }
    }

    // 5. 其他现代终端指标
    if env::var("COLORTERM").is_ok() || env::var("TERM_PROGRAM_VERSION").is_ok() {
        return true;
    }

    false
}

/// 检测是否为 PowerShell Core (6+)
fn is_powershell_core() -> bool {
    // PowerShell Core 会在 PSVersionTable 中设置版本
    env::var("PSVersionTable").map(|_| true).unwrap_or(false)
}

/// 检测是否为 Windows PowerShell (5.1 及以下)
fn is_windows_powershell_legacy() -> bool {
    // Windows PowerShell 5.1 特有环境变量检测
    env::var("PSModulePath").is_ok()
        && env::var("PSVersionTable").is_err()
        && (env::var("PSHOME").is_ok() || env::var("PSExecutionPolicyPreference").is_ok())
}

/// 检测是否在 Windows Terminal 或 ConEmu 中运行
fn is_windows_terminal_or_conemu() -> bool {
    // Windows Terminal - 最可靠的检测
    if env::var("WT_SESSION").is_ok() {
        return true;
    }

    // ConEmu with ANSI support
    if env::var("ConEmuANSI").is_ok() {
        return true;
    }

    // ANSICON - ANSI 支持层
    if env::var("ANSICON").is_ok() {
        return true;
    }

    // TERM_PROGRAM - 需要更严格的验证
    if let Ok(term_program) = env::var("TERM_PROGRAM") {
        let term_program = term_program.to_lowercase();
        // 只确认是已知的现代终端程序
        if [
            "vscode",
            "hyper",
            "terminus",
            "windowsterminal",
            "warp",
            "wt",
            "warpterminal",
        ]
        .contains(&term_program.as_str())
        {
            return true;
        }
    }

    false
}

/// Windows 环境下的降级决策函数
fn should_degrade_on_windows(utf8_ok: bool, looks_modern: bool, vt_supported: bool) -> bool {
    // 已经确认支持虚拟终端处理,直接认为安全
    if vt_supported {
        return false;
    }

    // 情况1:既非 UTF-8 又非现代终端 -> 明确降级
    if !utf8_ok && !looks_modern {
        return true;
    }

    // 情况2:Windows PowerShell 5.1 且不在现代终端中
    if is_windows_powershell_legacy() && !is_windows_terminal_or_conemu() {
        return true;
    }

    // 情况3:检测到传统控制台环境(conhost)
    if is_traditional_console() {
        return true;
    }

    // 情况4:非 UTF-8 环境,即使看起来现代也要保守处理
    if !utf8_ok && !is_very_modern_terminal() {
        return true;
    }

    // 情况5:边缘情况 - 无法明确识别环境,采用保守策略
    // 如果不是明确支持的现代终端,也不是明确的传统终端,则降级
    if !is_very_modern_terminal() && !is_windows_terminal_or_conemu() && !is_powershell_core() {
        return true;
    }

    false
}

/// 检测是否为传统控制台(conhost)
fn is_traditional_console() -> bool {
    // 传统控制台通常没有这些现代环境变量
    env::var("WT_SESSION").is_err()
        && env::var("TERM_PROGRAM").is_err()
        && env::var("ConEmuANSI").is_err()
        && env::var("ANSICON").is_err()
        && (env::var("TERM").is_err() || env::var("TERM").unwrap_or_default().is_empty())
}

/// 检测是否为非常现代的终端(值得冒险尝试 ANSI)
fn is_very_modern_terminal() -> bool {
    // Windows Terminal - 最可靠的检测
    if env::var("WT_SESSION").is_ok() {
        return true;
    }

    // VSCode 终端
    if let Ok(term_program) = env::var("TERM_PROGRAM") {
        if term_program.to_lowercase().contains("vscode") {
            return true;
        }
    }

    // Windows Terminal 的新版本检测方式
    if env::var("WT_PROFILE_ID").is_ok() {
        return true;
    }

    // Hyper 终端
    if let Ok(term) = env::var("TERM") {
        let term = term.to_lowercase();
        if term.contains("hyper") || term.contains("xterm-256color") {
            return true;
        }
    }

    // 检测其他现代终端的环境变量
    if env::var("TERM_PROGRAM_VERSION").is_ok() {
        return true;
    }

    false
}

/// 检测控制台是否启用了虚拟终端处理(仅 Windows)
#[cfg(target_os = "windows")]
fn has_virtual_terminal_processing() -> bool {
    use winapi::um::consoleapi::GetConsoleMode;
    use winapi::um::handleapi::INVALID_HANDLE_VALUE;
    use winapi::um::processenv::GetStdHandle;
    use winapi::um::winbase::STD_OUTPUT_HANDLE;
    use winapi::um::wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING;

    unsafe {
        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
        if handle.is_null() || handle == INVALID_HANDLE_VALUE {
            return false;
        }

        let mut mode: u32 = 0;
        if GetConsoleMode(handle, &mut mode) == 0 {
            return false;
        }

        mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0
    }
}

#[cfg(not(target_os = "windows"))]
fn has_virtual_terminal_processing() -> bool {
    true
}

fn bool_to_flag(v: bool) -> &'static str {
    if v { "1" } else { "0" }
}

fn detect_windows_utf8() -> bool {
    if !cfg!(target_os = "windows") {
        return true;
    }

    // 方法1: 检查活动代码页
    if let Ok(output) = Command::new("cmd").args(["/C", "chcp"]).output() {
        if let Ok(text) = String::from_utf8(output.stdout) {
            // 查找 "活动代码页: 65001" 或类似模式
            if text.contains("65001") {
                return true;
            }
        }
    }

    // 方法2: 检查系统默认输出代码页
    if let Ok(output) = Command::new("cmd").args(["/C", "echo %LANG%"]).output() {
        if let Ok(lang) = String::from_utf8(output.stdout) {
            let lang = lang.trim().to_lowercase();
            if lang.contains("utf-8") || lang.contains("65001") {
                return true;
            }
        }
    }

    // 方法3: 检查系统环境变量
    if let Ok(locale) = env::var("LC_ALL").or_else(|_| env::var("LANG")) {
        let locale = locale.to_lowercase();
        if locale.contains("utf-8") || locale.contains("65001") {
            return true;
        }
    }

    // 方法4: 检查 Windows Terminal 或其他现代终端
    if env::var("WT_SESSION")
        .map(|v| !v.is_empty())
        .unwrap_or(false)
    {
        return true;
    }

    // 方法5: 检查终端程序
    if let Ok(term_program) = env::var("TERM_PROGRAM") {
        if [
            "vscode",
            "hyper",
            "terminus",
            "windowsterminal",
            "warp",
            "wt",
        ]
        .contains(&term_program.to_lowercase().as_str())
        {
            return true;
        }
    }

    // 方法6: 检查 TERM 变量
    if let Ok(term) = env::var("TERM") {
        let term = term.to_lowercase();
        if term.contains("xterm") || term.contains("screen") || term.contains("tmux") {
            return true;
        }
    }

    // 默认保守策略
    false
}