<?xml version="1.0" encoding="utf-8" ?>


<feed xmlns="http://www.w3.org/2005/Atom">
  <title>imAtlas</title>

  <description>javascript、css、html等web前端的技术分享与讨论</description>

  <link href="http://imatlas.com/"></link>

  <link ref="self" href="http://imatlas.com/feed"></link>

  <id>572b438be4fe268e15072c45eb72fe71879d3e10-blog.imatlas.com</id>


  <updated>2026-10-10T07:19:00Z</updated>


  <entry>


    <title>Ghostty + 远程 Linux 终端开发环境全套配置</title>

    <link href="http://imatlas.com/post/ghostty-remote-coding"  rel="alternate"></link>

    <updated>2026-10-10T07:19:00Z</updated>
    <id>ghostty-remote-coding</id>

    <author>
      <name>iAzrael</name>

    </author>
    <summary type="html">&lt;p class="md_block md_block_as_opening md_has_block_below md_has_block_below_ol"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;本文档为标准落地配置方案，旨在供开发者或 AI Agent 直接读取并一键执行配置。配置完成后，将具备：&lt;/span&gt;
&lt;/p&gt;


&lt;ol&gt;
&lt;li class="md_li"&gt;&lt;span&gt;&lt;strong&gt;眼科级抗疲劳体验&lt;/strong&gt;：微温浅抹茶豆沙绿护眼底色 + 墨迹黑字 + 焦糖琥珀色思考字，彻底告别反光与视疲劳；
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt;&lt;strong&gt;1 步直达战场&lt;/strong&gt;：敲 &lt;code&gt;cx&lt;/code&gt; 自动免密登录、自动进工作区、自动挂入后台保活会话，配置与代码解耦，换服务器零成本；
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt;&lt;strong&gt;跨机器剪贴板与文件瞬移&lt;/strong&gt;：Mac 截图在服务器敲 &lt;code&gt;pi&lt;/code&gt; 或 Yazi 敲 &lt;code&gt;P&lt;/code&gt; 秒级落地；本地文件拖入终端直接拉取上传；
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt;&lt;strong&gt;全能终端管理&lt;/strong&gt;：Yazi 终端看图自动铺满并支持自由缩放、Glow 2.0 原生 Markdown 彩色宽幅排版、路径双击 &lt;code&gt;c c&lt;/code&gt; 秒拷回 Mac；
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt;&lt;strong&gt;跨 Worktree 智能文件直达 (&lt;code&gt;wto&lt;/code&gt;)&lt;/strong&gt;：解决 Claude Code 在独立 worktree 中改动代码后路径不匹配痛点，fzf 上下键直接挑选，回车秒开 Yazi 定位高亮。
&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;hr&gt;
&lt;h2 id="toc_0" class="h16"&gt;架构拓扑&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;+-------------------------------------------------------------+
| Mac 本地工作站 (macOS)                                      |
|                                                             |
| 1. Ghostty 终端 (MesloLGL Nerd Font + 中值护眼豆沙绿)       |
| 2. 本地桥接服务: ~/.config/cx/mac_bridge.py (监听 127.0.0.1:19222)|
| 3. SSH 客户端: ~/.ssh/config (RemoteForward 19222)          |
| 4. Shell 极简引入: ~/.zshrc -&amp;gt; ~/.config/cx/ (工具/配置/桥接一体)|
+------------------------------+------------------------------+
                               |  SSH (反向隧道 19222)
                               v
+-------------------------------------------------------------+
| 远程 Linux 服务器 (Ubuntu / Debian / CentOS)                |
|                                                             |
| 1. Tmux 3.5a: 开启 allow-passthrough (Kitty 图形穿透)       |
| 2. 交互工具: pi (剪贴板图), up (拖拽上传), cb (拷回 Mac),     |
|             wto (跨 Worktree 智能检索直通 Yazi)              |
| 3. Yazi (v26.9+): zoom 缩放、piper + glow 2.0、copy-mac     |
+-------------------------------------------------------------+&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;&lt;blockquote class="blockquote_lines_5"&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start"&gt;&lt;strong&gt;参数占位符约定&lt;/strong&gt;：&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;- &lt;code&gt;&amp;lt;SERVER_HOST&amp;gt;&lt;/code&gt;：服务器 SSH 别名（示例：&lt;code&gt;dev-server&lt;/code&gt;）&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;- &lt;code&gt;&amp;lt;SERVER_IP&amp;gt;&lt;/code&gt;：服务器真实 IP（示例：&lt;code&gt;10.0.0.10&lt;/code&gt;）&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;- &lt;code&gt;&amp;lt;REMOTE_USER&amp;gt;&lt;/code&gt;：远程服务器登录用户名（示例：&lt;code&gt;developer&lt;/code&gt;）&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line md_line_end"&gt;- &lt;code&gt;&amp;lt;PROJECT_NAME&amp;gt;&lt;/code&gt;：默认主项目目录名（示例：&lt;code&gt;my_project&lt;/code&gt;）&lt;/span&gt;
&lt;/p&gt;

&lt;/blockquote&gt;

&lt;hr&gt;
&lt;h2 id="toc_1" class="h16"&gt;第一部分：Mac 本地配置（AI 自动执行指南）&lt;/h2&gt;&lt;h3 id="toc_2" class="h16"&gt;1.1 安装必要 CLI 工具&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;通过 Homebrew 安装剪贴板提取器及终端工具：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;brew install pngpaste glow lazygit
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;&lt;h3 id="toc_3" class="h16"&gt;1.2 配置 Ghostty 终端&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;写入或覆盖 &lt;code&gt;~/.config/ghostty/config&lt;/code&gt;：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_ini  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# ==============================================================================&lt;/span&gt;
&lt;span class="c1"&gt;# Ghostty 配置 - 眼科防疲劳浅豆沙绿定制版&lt;/span&gt;
&lt;span class="c1"&gt;# ==============================================================================&lt;/span&gt;

&lt;span class="c1"&gt;# 1. 主题与色彩（经典草木豆沙绿中值色 #c1d9c3，明度 80%，防反光不刺眼）&lt;/span&gt;
&lt;span class="na"&gt;background&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;#c1d9c3&lt;/span&gt;
&lt;span class="na"&gt;foreground&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;#1c2c21&lt;/span&gt;
&lt;span class="na"&gt;cursor-color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;#286349&lt;/span&gt;
&lt;span class="na"&gt;cursor-text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;#c1d9c3&lt;/span&gt;
&lt;span class="na"&gt;selection-background&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;#a2cca6&lt;/span&gt;
&lt;span class="na"&gt;selection-foreground&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;#1c2c21&lt;/span&gt;

&lt;span class="c1"&gt;# ANSI 16 色调色板（墨水纸感：黄色调为深焦糖色 #7a3e00，确保 Claude 思考文字凝实清晰）&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;0=#1c2c21&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1=#ba3838&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;2=#2a752e&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;3=#7a3e00&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;4=#175983&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;5=#762c8e&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;6=#10766d&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;7=#cedecf&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;8=#44584a&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;9=#cf2828&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;10=#328537&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;11=#7a3e00&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;12=#176ebd&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;13=#871fa2&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;14=#008273&lt;/span&gt;
&lt;span class="na"&gt;palette&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;15=#f0f7f0&lt;/span&gt;

&lt;span class="c1"&gt;# 智能对比度防护（确保状态栏小字和辅助灰色绝对清晰）&lt;/span&gt;
&lt;span class="na"&gt;minimum-contrast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1.15&lt;/span&gt;

&lt;span class="c1"&gt;# 2. 窗口外观（浅色模式设为 1.0 纯色不透，杜绝桌面杂色重影干扰）&lt;/span&gt;
&lt;span class="na"&gt;background-opacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1.0&lt;/span&gt;
&lt;span class="na"&gt;background-blur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;window-padding-x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;14&lt;/span&gt;
&lt;span class="na"&gt;window-padding-y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;12&lt;/span&gt;
&lt;span class="na"&gt;window-padding-balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;macos-titlebar-style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;transparent&lt;/span&gt;

&lt;span class="c1"&gt;# 3. 字体配置&lt;/span&gt;
&lt;span class="na"&gt;font-family&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;MesloLGL Nerd Font&lt;/span&gt;
&lt;span class="na"&gt;font-size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;14.5&lt;/span&gt;

&lt;span class="c1"&gt;# 4. 光标与按键&lt;/span&gt;
&lt;span class="na"&gt;cursor-style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;block&lt;/span&gt;
&lt;span class="na"&gt;cursor-style-blink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;macos-option-as-alt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;

&lt;span class="c1"&gt;# 5. 滚动与控速（驯服触控板暴冲）&lt;/span&gt;
&lt;span class="na"&gt;scrollback-limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;100000&lt;/span&gt;
&lt;span class="na"&gt;mouse-scroll-multiplier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;precision:1,discrete:1&lt;/span&gt;

&lt;span class="c1"&gt;# 6. 剪贴板交互&lt;/span&gt;
&lt;span class="na"&gt;clipboard-read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;allow&lt;/span&gt;
&lt;span class="na"&gt;clipboard-write&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;allow&lt;/span&gt;
&lt;span class="na"&gt;copy-on-select&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;clipboard&lt;/span&gt;

&lt;span class="c1"&gt;# 7. 终端环境&lt;/span&gt;
&lt;span class="na"&gt;term&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;xterm-256color&lt;/span&gt;

&lt;span class="c1"&gt;# 8. 分屏快捷键&lt;/span&gt;
&lt;span class="na"&gt;keybind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;super+d=new_split:right&lt;/span&gt;
&lt;span class="na"&gt;keybind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;super+shift+d=new_split:down&lt;/span&gt;
&lt;span class="na"&gt;keybind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;super+[=goto_split:previous&lt;/span&gt;
&lt;span class="na"&gt;keybind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;super+]=goto_split:next&lt;/span&gt;
&lt;span class="na"&gt;keybind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;super+shift+enter=toggle_split_zoom&lt;/span&gt;
&lt;span class="na"&gt;keybind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;super+ctrl+==equalize_splits&lt;/span&gt;
&lt;span class="na"&gt;keybind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;super+enter=unbind&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;&lt;h3 id="toc_4" class="h16"&gt;1.3 部署 Mac 本地跨端桥接服务&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;创建本地桥接脚本 &lt;code&gt;~/.config/cx/mac_bridge.py&lt;/code&gt;：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_python  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ch"&gt;#!/usr/bin/env python3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;http.server&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;urllib.parse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;19222&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;detect_clipboard&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# 1. 尝试检测 Finder 复制的文件 (Cmd+C)&lt;/span&gt;
    &lt;span class="n"&gt;script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;    try&lt;/span&gt;
&lt;span class="s2"&gt;        set singleItem to (the clipboard as «class furl»)&lt;/span&gt;
&lt;span class="s2"&gt;        return POSIX path of singleItem&lt;/span&gt;
&lt;span class="s2"&gt;    on error&lt;/span&gt;
&lt;span class="s2"&gt;        try&lt;/span&gt;
&lt;span class="s2"&gt;            set theList to (the clipboard as list)&lt;/span&gt;
&lt;span class="s2"&gt;            set res to {}&lt;/span&gt;
&lt;span class="s2"&gt;            repeat with itm in theList&lt;/span&gt;
&lt;span class="s2"&gt;                try&lt;/span&gt;
&lt;span class="s2"&gt;                    set end of res to POSIX path of itm&lt;/span&gt;
&lt;span class="s2"&gt;                end try&lt;/span&gt;
&lt;span class="s2"&gt;            end repeat&lt;/span&gt;
&lt;span class="s2"&gt;            set AppleScript&amp;#39;s text item delimiters to linefeed&lt;/span&gt;
&lt;span class="s2"&gt;            return res as text&lt;/span&gt;
&lt;span class="s2"&gt;        on error&lt;/span&gt;
&lt;span class="s2"&gt;            return &amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;        end try&lt;/span&gt;
&lt;span class="s2"&gt;    end try&lt;/span&gt;
&lt;span class="s2"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;osascript&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-e&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
            &lt;span class="n"&gt;valid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="s2"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;files&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="s2"&gt;&amp;quot;files&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;size&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. 尝试检测剪贴板原生图片 (截屏数据)&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;png_check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/opt/homebrew/bin/pngpaste&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;png_check&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returncode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;png_check&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;image&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;size&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;png_check&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;

    &lt;span class="c1"&gt;# 3. 尝试检测 pbpaste 文本内容是否指向有效本地文件&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pbpaste&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;files&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s2"&gt;&amp;quot;files&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;size&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)}]&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;preview&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;empty&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BridgeHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseHTTPRequestHandler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urlparse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/ping&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pong&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;

        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/clipboard-status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detect_clipboard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ensure_ascii&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;application/json; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Length&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;

        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/clipboard-image&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/opt/homebrew/bin/pngpaste&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returncode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;image/png&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Length&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;text/plain; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Clipboard does not contain an image&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;text/plain; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/fetch-file&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_qs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;filepath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;path&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;filepath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expanduser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;text/plain; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;File not found: {filepath}&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;application/octet-stream&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Length&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;65536&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;PermissionError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;text/plain; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Permission denied on Mac: {e}&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;text/plain; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/open-remote-vscode&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_qs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;remote_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;path&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;host&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;SERVER_HOST&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;remote_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;vscode://vscode-remote/ssh-remote+{host}{remote_path}&amp;quot;&lt;/span&gt;
                    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;open&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ok&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt;
                &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;

        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/open-browser&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_qs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;target_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;url&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;target_url&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;target_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
                &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;open&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_url&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ok&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt;
                &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;invalid url&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;

        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/preview&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;preview_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/tmp/wto_preview.html&amp;#39;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preview_file&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preview_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;text/html; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Length&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt;
                &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;text/plain; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;text/plain; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;No preview available&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;

        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urlparse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/set-clipboard&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Length&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pbcopy&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;communicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ok&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/preview-upload&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Length&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;preview_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/tmp/wto_preview.html&amp;#39;&lt;/span&gt;
                &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preview_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                
                &lt;span class="n"&gt;preview_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://127.0.0.1:{PORT}/preview&amp;quot;&lt;/span&gt;
                &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;open&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;preview_url&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;application/json; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;url&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;preview_url&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;text/plain; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;/save-file&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_qs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;raw_filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;filename&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;downloaded_file&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;clean_filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;downloaded_file&amp;#39;&lt;/span&gt;
            &lt;span class="n"&gt;dest_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expanduser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;~/Downloads&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;makedirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exist_ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            
            &lt;span class="c1"&gt;# 重名处理：若已存在则追加 (1), (2) 防覆盖&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splitext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clean_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;target_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clean_filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;target_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dest_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;{name} ({counter}){ext}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

            &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Length&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;chunk_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;65536&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                            &lt;span class="k"&gt;break&lt;/span&gt;
                        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="c1"&gt;# 自动在 Mac Finder 中高亮选中该文件&lt;/span&gt;
                &lt;span class="n"&gt;reveal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;reveal&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;reveal&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;open&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-R&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_path&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;application/json; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="s1"&gt;&amp;#39;ok&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="s1"&gt;&amp;#39;filename&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="s1"&gt;&amp;#39;path&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;target_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="s1"&gt;&amp;#39;size&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getsize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ensure_ascii&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;text/plain; charset=utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;utf-8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ThreadingHTTPServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;BridgeHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serve_forever&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;赋权、创建软链并启动：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;chmod +x ~/.config/cx/mac_bridge.py
ln -sf ~/.config/cx/mac_bridge.py ~/.local/bin/mac_bridge.py
pkill -f mac_bridge.py 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
nohup python3 ~/.config/cx/mac_bridge.py &amp;gt;/dev/null 2&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;&lt;h3 id="toc_5" class="h16"&gt;1.4 配置 SSH 客户端反向转发 (&lt;code&gt;~/.ssh/config&lt;/code&gt;)&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;在 &lt;code&gt;~/.ssh/config&lt;/code&gt; 中针对目标服务器添加配置（请替换 &lt;code&gt;&amp;lt;SERVER_HOST&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;SERVER_IP&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;REMOTE_USER&amp;gt;&lt;/code&gt;）：&lt;/span&gt;
&lt;/p&gt;


&lt;pre class="lang_ssh-config"&gt;&lt;code&gt;Host &amp;lt;SERVER_HOST&amp;gt;
    HostName &amp;lt;SERVER_IP&amp;gt;
    User &amp;lt;REMOTE_USER&amp;gt;
    RequestTTY yes
    RemoteForward 19222 127.0.0.1:19222&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;&lt;h3 id="toc_6" class="h16"&gt;1.5 配置 Mac 本地 Shell 直达函数与解耦配置 (&lt;code&gt;cx&lt;/code&gt;)&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;为了在更换服务器或换项目时&lt;strong&gt;彻底解耦、无需频繁修改 &lt;code&gt;~/.zshrc&lt;/code&gt;&lt;/strong&gt;，我们将连接目标参数独立抽取到单独的配置文件中。&lt;/span&gt;
&lt;/p&gt;

&lt;h4 id="toc_7" class="h16"&gt;1.5.1 创建目标服务器配置文件 (&lt;code&gt;~/.config/cx/config&lt;/code&gt;)&lt;/h4&gt;&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mkdir -p ~/.config/cx
cat &lt;span class="s"&gt;&amp;lt;&amp;lt; &amp;#39;EOF&amp;#39; &amp;gt; ~/.config/cx/config&lt;/span&gt;
&lt;span class="s"&gt;# ==============================================================================&lt;/span&gt;
&lt;span class="s"&gt;# cx 远程开发环境配置 (~/.config/cx/config)&lt;/span&gt;
&lt;span class="s"&gt;# 以后换服务器或换项目，直接修改这里的参数即可！&lt;/span&gt;
&lt;span class="s"&gt;# ==============================================================================&lt;/span&gt;

&lt;span class="s"&gt;# SSH 目标主机别名（对应 ~/.ssh/config 里的 Host）&lt;/span&gt;
&lt;span class="s"&gt;CX_HOST=&amp;quot;&amp;lt;SERVER_HOST&amp;gt;&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;# 远程默认主项目名称&lt;/span&gt;
&lt;span class="s"&gt;CX_PROJECT=&amp;quot;&amp;lt;PROJECT_NAME&amp;gt;&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;# 远程工作区主目录&lt;/span&gt;
&lt;span class="s"&gt;CX_REMOTE_WORKSPACES=&amp;quot;$HOME/workspaces&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;# 远程环境入口脚本（若不存在自动降级）&lt;/span&gt;
&lt;span class="s"&gt;CX_REMOTE_BASH=&amp;quot;~/.local/bin/azbash&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;&lt;h4 id="toc_8" class="h16"&gt;1.5.2 创建独立工具脚本 (&lt;code&gt;~/.config/cx/cx.zsh&lt;/code&gt;)&lt;/h4&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;将快捷别名与 &lt;code&gt;cx&lt;/code&gt; 完整函数写入独立文件，彻底避免频繁修改 &lt;code&gt;~/.zshrc&lt;/code&gt;：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;cat &lt;span class="s"&gt;&amp;lt;&amp;lt; &amp;#39;EOF&amp;#39; &amp;gt; ~/.config/cx/cx.zsh&lt;/span&gt;
&lt;span class="s"&gt;# ==============================================================================&lt;/span&gt;
&lt;span class="s"&gt;# cx 远程终端与开发工具包 (~/.config/cx/cx.zsh)&lt;/span&gt;
&lt;span class="s"&gt;# 集中管理 cx 函数、快捷别名及本地跨机器桥接守护服务&lt;/span&gt;
&lt;span class="s"&gt;# ==============================================================================&lt;/span&gt;

&lt;span class="s"&gt;# 1. 自动守护本地跨机器桥接服务 (监听 127.0.0.1:19222)&lt;/span&gt;
&lt;span class="s"&gt;_cx_bridge_script=&amp;quot;$HOME/.config/cx/mac_bridge.py&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;pgrep -f &amp;quot;mac_bridge.py&amp;quot; &amp;gt;/dev/null || ([ -f &amp;quot;$_cx_bridge_script&amp;quot; ] &amp;amp;&amp;amp; nohup python3 &amp;quot;$_cx_bridge_script&amp;quot; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp; disown)&lt;/span&gt;

&lt;span class="s"&gt;# 2. 本地常用快捷别名与函数&lt;/span&gt;
&lt;span class="s"&gt;alias lg=&amp;#39;lazygit&amp;#39;&lt;/span&gt;

&lt;span class="s"&gt;md() {&lt;/span&gt;
&lt;span class="s"&gt;  if [ -z &amp;quot;$1&amp;quot; ]; then&lt;/span&gt;
&lt;span class="s"&gt;    glow&lt;/span&gt;
&lt;span class="s"&gt;  else&lt;/span&gt;
&lt;span class="s"&gt;    glow -p &amp;quot;$@&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;  fi&lt;/span&gt;
&lt;span class="s"&gt;}&lt;/span&gt;
&lt;span class="s"&gt;alias gw=&amp;#39;glow&amp;#39;&lt;/span&gt;

&lt;span class="s"&gt;# 3. cx 远程开发极速直达函数 (读取同目录 config 与 mac_bridge.py)&lt;/span&gt;
&lt;span class="s"&gt;unalias cx 2&amp;gt;/dev/null || true&lt;/span&gt;
&lt;span class="s"&gt;function cx() {&lt;/span&gt;
&lt;span class="s"&gt;  local cfg_dir=&amp;quot;$HOME/.config/cx&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;  local cfg_file=&amp;quot;$cfg_dir/config&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;  local bridge_script=&amp;quot;$cfg_dir/mac_bridge.py&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;  # 自动保证桥接运行&lt;/span&gt;
&lt;span class="s"&gt;  pgrep -f &amp;quot;mac_bridge.py&amp;quot; &amp;gt;/dev/null || ([ -f &amp;quot;$bridge_script&amp;quot; ] &amp;amp;&amp;amp; nohup python3 &amp;quot;$bridge_script&amp;quot; &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp; disown)&lt;/span&gt;

&lt;span class="s"&gt;  local default_host=&amp;quot;&amp;lt;SERVER_HOST&amp;gt;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;  local default_project=&amp;quot;&amp;lt;PROJECT_NAME&amp;gt;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;  local default_workspaces=&amp;quot;$HOME/workspaces&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;  local default_bash=&amp;quot;&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;  [ -f &amp;quot;$cfg_file&amp;quot; ] &amp;amp;&amp;amp; source &amp;quot;$cfg_file&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;  local host=&amp;quot;${CX_HOST:-$default_host}&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;  local project=&amp;quot;${CX_PROJECT:-$default_project}&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;  local remote_workspaces=&amp;quot;${CX_REMOTE_WORKSPACES:-$default_workspaces}&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;  local remote_bash=&amp;quot;${CX_REMOTE_BASH:-$default_bash}&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;  local arg=&amp;quot;${1:-$project}&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;  # 帮助命令支持: -h, --help, help, h, --hlep&lt;/span&gt;
&lt;span class="s"&gt;  if [[ &amp;quot;$arg&amp;quot; == &amp;quot;-h&amp;quot; || &amp;quot;$arg&amp;quot; == &amp;quot;--help&amp;quot; || &amp;quot;$arg&amp;quot; == &amp;quot;help&amp;quot; || &amp;quot;$arg&amp;quot; == &amp;quot;h&amp;quot; || &amp;quot;$arg&amp;quot; == &amp;quot;--hlep&amp;quot; ]]; then&lt;/span&gt;
&lt;span class="s"&gt;    cat &amp;lt;&amp;lt; EOF&lt;/span&gt;
cx - 远程开发环境极速直达工具 &lt;span class="o"&gt;(&lt;/span&gt;目标服务器: &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

用法:
  cx                    连入/恢复默认主会话 &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$project&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  cx new                自动新建序号递增的全新独立会话 &lt;span class="o"&gt;(&lt;/span&gt;如 &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;project&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;_1&lt;span class="o"&gt;)&lt;/span&gt;
  cx &amp;lt;序号&amp;gt;             连入/新建对应序号会话 &lt;span class="o"&gt;(&lt;/span&gt;例: cx &lt;span class="m"&gt;1&lt;/span&gt; -&amp;gt; &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;project&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;_1&lt;span class="o"&gt;)&lt;/span&gt;
  cx &amp;lt;名字&amp;gt;             连入/新建指定名称会话 &lt;span class="o"&gt;(&lt;/span&gt;例: cx &lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  cx ls                 查看当前远程所有后台保活会话 &lt;span class="o"&gt;(&lt;/span&gt;别名: list&lt;span class="o"&gt;)&lt;/span&gt;
  cx k                  弹出交互式菜单挑选关闭会话 &lt;span class="o"&gt;(&lt;/span&gt;别名: &lt;span class="nb"&gt;kill&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  cx k &amp;lt;名字&amp;gt;           直接关闭指定后台会话
  cx ka                 一键关闭全部后台保活会话 &lt;span class="o"&gt;(&lt;/span&gt;别名: kill-all&lt;span class="o"&gt;)&lt;/span&gt;
  cx bridge             查看本地跨机器传输桥接服务运行状态
  cx bridge restart     一键重启本地传输桥接服务 &lt;span class="o"&gt;(&lt;/span&gt;监听 127.0.0.1:19222&lt;span class="o"&gt;)&lt;/span&gt;
  cx raw                普通 SSH 直连服务器 &lt;span class="o"&gt;(&lt;/span&gt;不接管 tmux，别名: ssh&lt;span class="o"&gt;)&lt;/span&gt;
  cx config             查看/配置目标服务器参数 &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$cfg_file&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  cx -h, h, &lt;span class="nb"&gt;help&lt;/span&gt;        显示本帮助说明 &lt;span class="o"&gt;(&lt;/span&gt;别名: --help&lt;span class="o"&gt;)&lt;/span&gt;

常用场景:
  • 日常开发/上班:       直接敲 cx
  • 另起独立新任务:     敲 cx new 或 cx 1
  • 查后台正在跑什么:   敲 cx ls
  • 关掉用完的会话:     敲 cx k
  • 本地桥接异常/卡死: 敲 cx bridge restart
  • 更换目标服务器:     敲 cx config 修改配置
EOF
    &lt;span class="k"&gt;return&lt;/span&gt; 0
  &lt;span class="k"&gt;fi&lt;/span&gt;

  &lt;span class="c1"&gt;# 桥接服务生命周期管理&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bridge&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;br&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nv"&gt;sub&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$sub&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;restart&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$sub&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;re&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;⚡ 正在重启本地传输桥接服务...&amp;quot;&lt;/span&gt;
      pkill -f &lt;span class="s2"&gt;&amp;quot;mac_bridge.py&amp;quot;&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
      sleep 0.5
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$bridge_script&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        nohup python3 &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$bridge_script&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &amp;gt;/dev/null 2&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;disown&lt;/span&gt;
        sleep 0.5
      &lt;span class="k"&gt;fi&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$sub&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;stop&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      pkill -f &lt;span class="s2"&gt;&amp;quot;mac_bridge.py&amp;quot;&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;✔ 本地传输桥接服务已停止&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;⚠️ 桥接服务未在运行&amp;quot;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; 0
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$sub&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;start&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; pgrep -f &lt;span class="s2"&gt;&amp;quot;mac_bridge.py&amp;quot;&lt;/span&gt; &amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;✔ 本地传输桥接服务已在运行中&amp;quot;&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$bridge_script&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; nohup python3 &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$bridge_script&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &amp;gt;/dev/null 2&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;disown&lt;/span&gt;
        sleep 0.5
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;✔ 本地传输桥接服务已启动&amp;quot;&lt;/span&gt;
      &lt;span class="k"&gt;fi&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; 0
    &lt;span class="k"&gt;fi&lt;/span&gt;

    &lt;span class="c1"&gt;# 打印状态&lt;/span&gt;
    &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nv"&gt;pids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;pgrep -f &lt;span class="s2"&gt;&amp;quot;mac_bridge.py&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; tr &lt;span class="s1"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;📄 桥接服务脚本: &lt;/span&gt;&lt;span class="nv"&gt;$bridge_script&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$pids&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nv"&gt;probe&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -s --max-time &lt;span class="m"&gt;1&lt;/span&gt; http://127.0.0.1:19222/ping 2&amp;gt;/dev/null&lt;span class="k"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$probe&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;pong&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;✔ 运行状态: 正在运行 (PID: &lt;/span&gt;&lt;span class="nv"&gt;$pids&lt;/span&gt;&lt;span class="s2"&gt;, 端口 19222 响应: &lt;/span&gt;&lt;span class="nv"&gt;$probe&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;⚠️ 运行状态: 进程存在 (PID: &lt;/span&gt;&lt;span class="nv"&gt;$pids&lt;/span&gt;&lt;span class="s2"&gt;) 但端口 19222 未响应，可执行 cx bridge restart 重试&amp;quot;&lt;/span&gt;
      &lt;span class="k"&gt;fi&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;✖ 运行状态: 未运行 (可执行 cx bridge restart 启动)&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; 0
  &lt;span class="k"&gt;fi&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;config&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;conf&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;📄 当前 cx 配置文件路径: &lt;/span&gt;&lt;span class="nv"&gt;$cfg_file&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;----------------------------------------&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$cfg_file&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      cat &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$cfg_file&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;⚠️ 配置文件尚未创建，当前使用内置默认值: host=&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;, project=&lt;/span&gt;&lt;span class="nv"&gt;$project&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;----------------------------------------&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;💡 提示：使用编辑器直接修改该文件即可随时切换目标服务器/项目！&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; 0
  &lt;span class="k"&gt;fi&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;ls&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;list&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    ssh -q -o &lt;span class="nv"&gt;ClearAllForwardings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes -o &lt;span class="nv"&gt;RemoteCommand&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bash -c &amp;#39;echo \&amp;quot;=== 当前后台保活会话 ===\&amp;quot;; tmux ls 2&amp;gt;/dev/null || echo \&amp;quot;暂无运行中的会话\&amp;quot;; echo \&amp;quot;\&amp;quot;; echo \&amp;quot;💡 连接提示: cx 默认主会话 | cx new 开新会话 | cx 1/2/3 进对应序号 | cx &amp;lt;名字&amp;gt; 进指定会话 | cx -h 查看完整帮助\&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;kill&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;k&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$target&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      ssh -q -o &lt;span class="nv"&gt;ClearAllForwardings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes -o &lt;span class="nv"&gt;RemoteCommand&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none -t &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bash -i -c &amp;#39;tkill &lt;/span&gt;&lt;span class="nv"&gt;$target&lt;/span&gt;&lt;span class="s2"&gt;&amp;#39;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      ssh -q -o &lt;span class="nv"&gt;ClearAllForwardings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes -o &lt;span class="nv"&gt;RemoteCommand&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none -t &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bash -i -c &amp;#39;tkill&amp;#39;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
  &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;kill-all&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;ka&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    ssh -q -o &lt;span class="nv"&gt;ClearAllForwardings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes -o &lt;span class="nv"&gt;RemoteCommand&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bash -c &amp;#39;tmux kill-server 2&amp;gt;/dev/null; echo \&amp;quot;✔ 已关闭全部后台保活会话\&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;raw&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;ssh&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    ssh &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;new&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;add&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    ssh -o &lt;span class="nv"&gt;LogLevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ERROR -o &lt;span class="nv"&gt;RemoteCommand&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none -t &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bash -c &amp;#39;&lt;/span&gt;
&lt;span class="s2"&gt;      i=1&lt;/span&gt;
&lt;span class="s2"&gt;      while tmux has-session -t \&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;project&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_\$i\&amp;quot; 2&amp;gt;/dev/null; do&lt;/span&gt;
&lt;span class="s2"&gt;        i=\$((i+1))&lt;/span&gt;
&lt;span class="s2"&gt;      done&lt;/span&gt;
&lt;span class="s2"&gt;      sess=\&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;project&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_\$i\&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;      echo \&amp;quot;⚡ 创建全新独立会话: \$sess\&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;      cd \&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$remote_workspaces&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$project&lt;/span&gt;&lt;span class="s2"&gt;\&amp;quot; 2&amp;gt;/dev/null || cd ~&lt;/span&gt;
&lt;span class="s2"&gt;      exec tmux new-session -s \&amp;quot;\$sess\&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;    &amp;#39;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nv"&gt;sess&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ ^&lt;span class="o"&gt;[&lt;/span&gt;0-9&lt;span class="o"&gt;]&lt;/span&gt;+$ &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      &lt;span class="nv"&gt;sess&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;project&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
    ssh -o &lt;span class="nv"&gt;LogLevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ERROR -o &lt;span class="nv"&gt;RemoteCommand&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none -t &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bash -c &amp;#39;&lt;/span&gt;
&lt;span class="s2"&gt;      if tmux has-session -t \&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$sess&lt;/span&gt;&lt;span class="s2"&gt;\&amp;quot; 2&amp;gt;/dev/null; then&lt;/span&gt;
&lt;span class="s2"&gt;        exec tmux attach -t \&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$sess&lt;/span&gt;&lt;span class="s2"&gt;\&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;      fi&lt;/span&gt;
&lt;span class="s2"&gt;      proj_dir=\&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$remote_workspaces&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;\&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;      [ ! -d \&amp;quot;\$proj_dir\&amp;quot; ] &amp;amp;&amp;amp; proj_dir=\&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$remote_workspaces&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$project&lt;/span&gt;&lt;span class="s2"&gt;\&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;      [ ! -d \&amp;quot;\$proj_dir\&amp;quot; ] &amp;amp;&amp;amp; proj_dir=\&amp;quot;\$HOME\&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;      cd \&amp;quot;\$proj_dir\&amp;quot; &amp;amp;&amp;amp; exec tmux new-session -s \&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$sess&lt;/span&gt;&lt;span class="s2"&gt;\&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;    &amp;#39;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
EOF
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;&lt;h4 id="toc_9" class="h16"&gt;1.5.3 在 Mac &lt;code&gt;~/.zshrc&lt;/code&gt; 中单行载入&lt;/h4&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;在 &lt;code&gt;~/.zshrc&lt;/code&gt; 末尾仅需追加一行保护加载语句，即可完成全套工具链挂载：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# 加载 cx 远程终端与开发工具包&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.config/cx/cx.zsh&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.config/cx/cx.zsh&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;hr&gt;
&lt;h2 id="toc_10" class="h16"&gt;第二部分：远程服务器端配置（AI 自动执行指南）&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;在目标 Linux 服务器执行以下步骤（在当前用户环境下执行，无需 root 权限）。&lt;/span&gt;
&lt;/p&gt;

&lt;h3 id="toc_11" class="h16"&gt;2.1 部署 Tmux 3.5a 与 ImageMagick 桥接&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;下载并解压 tmux 3.5a 运行包：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;mkdir -p ~/.local/bin ~/.local/share /tmp/tmux_install
&lt;span class="nb"&gt;cd&lt;/span&gt; /tmp/tmux_install
curl -sL https://github.com/nelsonenzo/tmux-appimage/releases/download/3.5a/tmux.appimage -o tmux.appimage
chmod +x tmux.appimage
./tmux.appimage --appimage-extract
rm -rf ~/.local/share/tmux-3.5a
mv squashfs-root ~/.local/share/tmux-3.5a
rm -rf /tmp/tmux_install

&lt;span class="c1"&gt;# 编写 wrapper 脚本&lt;/span&gt;
cat &lt;span class="s"&gt;&amp;lt;&amp;lt; &amp;#39;BASH&amp;#39; &amp;gt; ~/.local/bin/tmux&lt;/span&gt;
&lt;span class="s"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="s"&gt;DIR=&amp;quot;$HOME/.local/share/tmux-3.5a&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;export TERMINFO=&amp;quot;$DIR/usr/share/terminfo&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;export LD_LIBRARY_PATH=&amp;quot;$DIR/usr/lib:$LD_LIBRARY_PATH&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;exec &amp;quot;$DIR/usr/bin/tmux&amp;quot; &amp;quot;$@&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;BASH&lt;/span&gt;
chmod +x ~/.local/bin/tmux

&lt;span class="c1"&gt;# 建立 ImageMagick 7 兼容软链&lt;/span&gt;
which convert &amp;gt;/dev/null &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ln -sf &lt;span class="k"&gt;$(&lt;/span&gt;which convert&lt;span class="k"&gt;)&lt;/span&gt; ~/.local/bin/magick
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;&lt;h3 id="toc_12" class="h16"&gt;2.2 配置 Tmux (&lt;code&gt;~/.tmux.conf&lt;/code&gt;)&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;写入 &lt;code&gt;~/.tmux.conf&lt;/code&gt;：&lt;/span&gt;
&lt;/p&gt;


&lt;pre class="lang_tmux"&gt;&lt;code&gt;# 1. 开启鼠标支持与高历史缓冲区
set -g mouse on
set -g history-limit 50000

# 2. 终端类型与真彩色
set -g default-terminal "xterm-256color"
set -as terminal-overrides ",*:Tc"

# 3. 编号从 1 开始
set -g base-index 1
setw -g pane-base-index 1
set -g renumber-windows on

# 4. 状态栏样式
set -g status-style "bg=#181825,fg=#cdd6f4"
set -g status-left "#[fg=#89b4fa,bold] [#S] "
set -g status-right "#[fg=#a6adc8]%Y-%m-%d %H:%M "
setw -g window-status-current-style "fg=#a6e3a1,bold"

# 5. 保留默认前缀键 Ctrl+b（严禁占用 Ctrl+a，确保命令行 Ctrl+a 跳行首、Ctrl+e 跳行末完好无损）
# （无需额外配置，tmux 默认前缀即为 Ctrl+b）

# 6. 驯服触控板滚轮速度（平稳降至 2 行）
bind-key -T copy-mode WheelUpPane select-pane \; send-keys -X -N 2 scroll-up
bind-key -T copy-mode WheelDownPane select-pane \; send-keys -X -N 2 scroll-down
bind-key -T copy-mode-vi WheelUpPane select-pane \; send-keys -X -N 2 scroll-up
bind-key -T copy-mode-vi WheelDownPane select-pane \; send-keys -X -N 2 scroll-down

# 7. 开启图形协议透传 (Kitty Graphics / Sixel 原生看图必备)
set -g allow-passthrough on
set -ga update-environment TERM
set -ga update-environment TERM_PROGRAM&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;&lt;h3 id="toc_13" class="h16"&gt;2.3 部署服务器端跨端工具 (&lt;code&gt;pi&lt;/code&gt;, &lt;code&gt;pf&lt;/code&gt;, &lt;code&gt;up&lt;/code&gt;, &lt;code&gt;down&lt;/code&gt;, &lt;code&gt;cb&lt;/code&gt;, &lt;code&gt;wto&lt;/code&gt;)&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;在 &lt;code&gt;~/.local/bin/&lt;/code&gt; 创建工具：&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_start md_line_end"&gt;&lt;strong&gt;1. &lt;code&gt;~/.local/bin/pi&lt;/code&gt; &amp;amp; &lt;code&gt;~/.local/bin/pf&lt;/code&gt;（智能粘贴：支持 Mac 截图图片 + Finder 复制的文件）&lt;/strong&gt;&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;cat &lt;span class="s"&gt;&amp;lt;&amp;lt; &amp;#39;BASH&amp;#39; &amp;gt; ~/.local/bin/pi&lt;/span&gt;
&lt;span class="s"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="s"&gt;# ==============================================================================&lt;/span&gt;
&lt;span class="s"&gt;# pi (Paste It) / pf (Paste File)&lt;/span&gt;
&lt;span class="s"&gt;# 智能粘贴：支持 Mac 截图图片、Mac Finder 复制的文件 (Cmd+C)、Mac 剪贴板文件路径&lt;/span&gt;
&lt;span class="s"&gt;# ==============================================================================&lt;/span&gt;

&lt;span class="s"&gt;STATUS_JSON=$(curl -s --max-time 3 http://127.0.0.1:19222/clipboard-status 2&amp;gt;/dev/null)&lt;/span&gt;

&lt;span class="s"&gt;if [ -z &amp;quot;$STATUS_JSON&amp;quot; ]; then&lt;/span&gt;
&lt;span class="s"&gt;    echo -e &amp;quot;\033[31m✘ [Mac ➔ Server]\033[0m 无法连接 Mac 本地桥接服务 (HTTP 19222)&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    exit 1&lt;/span&gt;
&lt;span class="s"&gt;fi&lt;/span&gt;

&lt;span class="s"&gt;TYPE=$(echo &amp;quot;$STATUS_JSON&amp;quot; | python3 -c &amp;quot;import sys, json; data=json.load(sys.stdin); print(data.get(&amp;#39;type&amp;#39;, &amp;#39;empty&amp;#39;))&amp;quot; 2&amp;gt;/dev/null)&lt;/span&gt;

&lt;span class="s"&gt;if [ &amp;quot;$TYPE&amp;quot; = &amp;quot;files&amp;quot; ]; then&lt;/span&gt;
&lt;span class="s"&gt;    echo &amp;quot;$STATUS_JSON&amp;quot; | python3 -c &amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;import sys, json, urllib.parse, subprocess, os&lt;/span&gt;

&lt;span class="s"&gt;data = json.load(sys.stdin)&lt;/span&gt;
&lt;span class="s"&gt;files = data.get(&amp;#39;files&amp;#39;, [])&lt;/span&gt;
&lt;span class="s"&gt;custom_name = sys.argv[1] if len(sys.argv) &amp;gt; 1 else &amp;#39;&amp;#39;&lt;/span&gt;

&lt;span class="s"&gt;for i, f in enumerate(files):&lt;/span&gt;
&lt;span class="s"&gt;    remote_path = f[&amp;#39;path&amp;#39;]&lt;/span&gt;
&lt;span class="s"&gt;    orig_name = f[&amp;#39;name&amp;#39;]&lt;/span&gt;
&lt;span class="s"&gt;    target_name = custom_name if (custom_name and len(files) == 1) else orig_name&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    encoded = urllib.parse.quote(remote_path)&lt;/span&gt;
&lt;span class="s"&gt;    url = f&amp;#39;http://127.0.0.1:19222/fetch-file?path={encoded}&amp;#39;&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    res = subprocess.run([&amp;#39;curl&amp;#39;, &amp;#39;-s&amp;#39;, &amp;#39;-o&amp;#39;, target_name, &amp;#39;-w&amp;#39;, &amp;#39;%{http_code}&amp;#39;, url], capture_output=True, text=True)&lt;/span&gt;
&lt;span class="s"&gt;    http_code = res.stdout.strip()&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    if http_code == &amp;#39;200&amp;#39; and os.path.exists(target_name):&lt;/span&gt;
&lt;span class="s"&gt;        size = os.path.getsize(target_name)&lt;/span&gt;
&lt;span class="s"&gt;        if size &amp;lt; 1024:&lt;/span&gt;
&lt;span class="s"&gt;            size_str = f&amp;#39;{size} B&amp;#39;&lt;/span&gt;
&lt;span class="s"&gt;        elif size &amp;lt; 1024 * 1024:&lt;/span&gt;
&lt;span class="s"&gt;            size_str = f&amp;#39;{size / 1024:.1f} KB&amp;#39;&lt;/span&gt;
&lt;span class="s"&gt;        else:&lt;/span&gt;
&lt;span class="s"&gt;            size_str = f&amp;#39;{size / (1024 * 1024):.1f} MB&amp;#39;&lt;/span&gt;
&lt;span class="s"&gt;        print(f&amp;#39;\033[32m✔ [Mac ➔ Server]\033[0m 成功从 Mac 剪贴板粘贴文件: \033[1m{target_name}\033[0m ({size_str})&amp;#39;)&lt;/span&gt;
&lt;span class="s"&gt;    else:&lt;/span&gt;
&lt;span class="s"&gt;        print(f&amp;#39;\033[31m✘ [Mac ➔ Server]\033[0m 拉取文件失败: {orig_name} (HTTP {http_code})&amp;#39;)&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot; &amp;quot;$1&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;elif [ &amp;quot;$TYPE&amp;quot; = &amp;quot;image&amp;quot; ]; then&lt;/span&gt;
&lt;span class="s"&gt;    TARGET=&amp;quot;$1&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    [ -z &amp;quot;$TARGET&amp;quot; ] &amp;amp;&amp;amp; TARGET=&amp;quot;clip_$(date +%Y%m%d_%H%M%S).png&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    HTTP_CODE=$(curl -s -o &amp;quot;$TARGET&amp;quot; -w &amp;quot;%{http_code}&amp;quot; http://127.0.0.1:19222/clipboard-image 2&amp;gt;/dev/null || echo &amp;quot;000&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;    if [ &amp;quot;$HTTP_CODE&amp;quot; = &amp;quot;200&amp;quot; ]; then&lt;/span&gt;
&lt;span class="s"&gt;        SIZE=$(ls -lh &amp;quot;$TARGET&amp;quot; | awk &amp;#39;{print $5}&amp;#39;)&lt;/span&gt;
&lt;span class="s"&gt;        echo -e &amp;quot;\033[32m✔ [Mac ➔ Server]\033[0m 成功从剪贴板粘贴图片: \033[1m$TARGET\033[0m ($SIZE)&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    else&lt;/span&gt;
&lt;span class="s"&gt;        rm -f &amp;quot;$TARGET&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;        echo -e &amp;quot;\033[31m✘ [Mac ➔ Server]\033[0m 粘贴图片失败 (HTTP $HTTP_CODE)&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;        exit 1&lt;/span&gt;
&lt;span class="s"&gt;    fi&lt;/span&gt;

&lt;span class="s"&gt;elif [ &amp;quot;$TYPE&amp;quot; = &amp;quot;text&amp;quot; ]; then&lt;/span&gt;
&lt;span class="s"&gt;    PREVIEW=$(echo &amp;quot;$STATUS_JSON&amp;quot; | python3 -c &amp;quot;import sys, json; print(json.load(sys.stdin).get(&amp;#39;preview&amp;#39;, &amp;#39;&amp;#39;))&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;    echo -e &amp;quot;\033[33mℹ [Mac ➔ Server]\033[0m Mac 剪贴板里是文本内容，非文件或图片:&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    echo -e &amp;quot;  \033[90m\&amp;quot;$PREVIEW\&amp;quot;\033[0m&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    exit 0&lt;/span&gt;

&lt;span class="s"&gt;else&lt;/span&gt;
&lt;span class="s"&gt;    echo -e &amp;quot;\033[33m⚠ [Mac ➔ Server]\033[0m Mac 剪贴板里当前没有文件或图片数据&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    exit 1&lt;/span&gt;
&lt;span class="s"&gt;fi&lt;/span&gt;
&lt;span class="s"&gt;BASH&lt;/span&gt;
chmod +x ~/.local/bin/pi
ln -sf ~/.local/bin/pi ~/.local/bin/pf
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_start md_line_end"&gt;&lt;strong&gt;2. &lt;code&gt;~/.local/bin/up&lt;/code&gt;（接收拖拽文件秒传）&lt;/strong&gt;&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;cat &lt;span class="s"&gt;&amp;lt;&amp;lt; &amp;#39;BASH&amp;#39; &amp;gt; ~/.local/bin/up&lt;/span&gt;
&lt;span class="s"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="s"&gt;if [ -z &amp;quot;$1&amp;quot; ]; then&lt;/span&gt;
&lt;span class="s"&gt;    echo -e &amp;quot;使用方法: \033[1mup [直接把 Mac 上的图片或文件拖到这里] 回车\033[0m&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    exit 1&lt;/span&gt;
&lt;span class="s"&gt;fi&lt;/span&gt;

&lt;span class="s"&gt;for FILEPATH in &amp;quot;$@&amp;quot;; do&lt;/span&gt;
&lt;span class="s"&gt;    FILEPATH=$(echo &amp;quot;$FILEPATH&amp;quot; | sed -e &amp;quot;s/^[&amp;#39;\&amp;quot;]//&amp;quot; -e &amp;quot;s/[&amp;#39;\&amp;quot;]$//&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;    FILENAME=$(basename &amp;quot;$FILEPATH&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    echo -e &amp;quot;正在从 Mac 拉取文件: \033[34m$FILENAME\033[0m ...&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    ENCODED_PATH=$(python3 -c &amp;quot;import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1]))&amp;quot; &amp;quot;$FILEPATH&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    HTTP_CODE=$(curl -s -o &amp;quot;$FILENAME&amp;quot; -w &amp;quot;%{http_code}&amp;quot; &amp;quot;http://127.0.0.1:19222/fetch-file?path=$ENCODED_PATH&amp;quot; 2&amp;gt;/dev/null)&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    if [ &amp;quot;$HTTP_CODE&amp;quot; = &amp;quot;200&amp;quot; ]; then&lt;/span&gt;
&lt;span class="s"&gt;        SIZE=$(ls -lh &amp;quot;$FILENAME&amp;quot; | awk &amp;#39;{print $5}&amp;#39;)&lt;/span&gt;
&lt;span class="s"&gt;        echo -e &amp;quot;\033[32m✔ [Mac ➔ Server]\033[0m 上传成功: \033[1m$FILENAME\033[0m ($SIZE)&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    elif [ &amp;quot;$HTTP_CODE&amp;quot; = &amp;quot;404&amp;quot; ]; then&lt;/span&gt;
&lt;span class="s"&gt;        rm -f &amp;quot;$FILENAME&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;        echo -e &amp;quot;\033[31m✘ [Mac ➔ Server]\033[0m Mac 本地找不到该文件: $FILEPATH&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    elif [ &amp;quot;$HTTP_CODE&amp;quot; = &amp;quot;403&amp;quot; ]; then&lt;/span&gt;
&lt;span class="s"&gt;        rm -f &amp;quot;$FILENAME&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;        echo -e &amp;quot;\033[31m✘ [Mac ➔ Server]\033[0m Mac 系统权限拒绝读取该文件: $FILEPATH&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    else&lt;/span&gt;
&lt;span class="s"&gt;        rm -f &amp;quot;$FILENAME&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;        echo -e &amp;quot;\033[31m✘ [Mac ➔ Server]\033[0m 拉取失败 (HTTP $HTTP_CODE)&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    fi&lt;/span&gt;
&lt;span class="s"&gt;done&lt;/span&gt;
&lt;span class="s"&gt;BASH&lt;/span&gt;
chmod +x ~/.local/bin/up
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_start md_line_end"&gt;&lt;strong&gt;3. &lt;code&gt;~/.local/bin/cb&lt;/code&gt;（把文本或管道写入 Mac 剪贴板）&lt;/strong&gt;&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;cat &lt;span class="s"&gt;&amp;lt;&amp;lt; &amp;#39;BASH&amp;#39; &amp;gt; ~/.local/bin/cb&lt;/span&gt;
&lt;span class="s"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="s"&gt;if [ -n &amp;quot;$1&amp;quot; ]; then&lt;/span&gt;
&lt;span class="s"&gt;    echo -n &amp;quot;$1&amp;quot; | curl -s -X POST --data-binary @- http://127.0.0.1:19222/set-clipboard&lt;/span&gt;
&lt;span class="s"&gt;elif [ ! -t 0 ]; then&lt;/span&gt;
&lt;span class="s"&gt;    curl -s -X POST --data-binary @- http://127.0.0.1:19222/set-clipboard&lt;/span&gt;
&lt;span class="s"&gt;else&lt;/span&gt;
&lt;span class="s"&gt;    echo &amp;quot;使用方法: echo &amp;#39;文本&amp;#39; | cb 或 cb &amp;#39;文本&amp;#39;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;fi&lt;/span&gt;
&lt;span class="s"&gt;BASH&lt;/span&gt;
chmod +x ~/.local/bin/cb
ln -sf ~/.local/bin/cb ~/.local/bin/wl-copy
ln -sf ~/.local/bin/cb ~/.local/bin/xclip
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_start md_line_end"&gt;&lt;strong&gt;4. &lt;code&gt;~/.local/bin/wto&lt;/code&gt;（跨 Git Worktree 文件快速定位，支持直通 Yazi 或原地启动 HTTP 唤醒 Mac 浏览器）&lt;/strong&gt;&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;cat &lt;span class="s"&gt;&amp;lt;&amp;lt; &amp;#39;PY&amp;#39; &amp;gt; ~/.local/bin/wto&lt;/span&gt;
&lt;span class="s"&gt;#!/usr/bin/env python3&lt;/span&gt;
&lt;span class="s"&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;wto (WorkTree Open)&lt;/span&gt;
&lt;span class="s"&gt;跨 Git Worktree 文件快速定位，fzf 上下键选择，直通 Yazi 或极速本地 HTTP 浏览器预览&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;import os&lt;/span&gt;
&lt;span class="s"&gt;import sys&lt;/span&gt;
&lt;span class="s"&gt;import shutil&lt;/span&gt;
&lt;span class="s"&gt;import socket&lt;/span&gt;
&lt;span class="s"&gt;import http.server&lt;/span&gt;
&lt;span class="s"&gt;import socketserver&lt;/span&gt;
&lt;span class="s"&gt;import urllib.parse&lt;/span&gt;
&lt;span class="s"&gt;import json&lt;/span&gt;
&lt;span class="s"&gt;import subprocess&lt;/span&gt;
&lt;span class="s"&gt;import datetime&lt;/span&gt;
&lt;span class="s"&gt;from pathlib import Path&lt;/span&gt;

&lt;span class="s"&gt;BOLD = &amp;quot;\033[1m&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;GREEN = &amp;quot;\033[38;2;40;167;69m&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;CYAN = &amp;quot;\033[38;2;23;162;184m&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;YELLOW = &amp;quot;\033[38;2;255;193;7m&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;ORANGE = &amp;quot;\033[38;2;253;126;20m&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;RED = &amp;quot;\033[38;2;220;53;69m&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;GRAY = &amp;quot;\033[38;2;108;117;125m&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;RESET = &amp;quot;\033[0m&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;def get_server_ip():&lt;/span&gt;
&lt;span class="s"&gt;    conn = os.environ.get(&amp;quot;SSH_CONNECTION&amp;quot;, &amp;quot;&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;    if conn:&lt;/span&gt;
&lt;span class="s"&gt;        parts = conn.split()&lt;/span&gt;
&lt;span class="s"&gt;        if len(parts) &amp;gt;= 3:&lt;/span&gt;
&lt;span class="s"&gt;            return parts[2]&lt;/span&gt;
&lt;span class="s"&gt;    res = subprocess.run([&amp;quot;hostname&amp;quot;, &amp;quot;-I&amp;quot;], capture_output=True, text=True)&lt;/span&gt;
&lt;span class="s"&gt;    if res.stdout.strip():&lt;/span&gt;
&lt;span class="s"&gt;        return res.stdout.strip().split()[0]&lt;/span&gt;
&lt;span class="s"&gt;    return &amp;quot;127.0.0.1&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;def get_git_repo_root():&lt;/span&gt;
&lt;span class="s"&gt;    res = subprocess.run([&amp;quot;git&amp;quot;, &amp;quot;rev-parse&amp;quot;, &amp;quot;--show-toplevel&amp;quot;], capture_output=True, text=True)&lt;/span&gt;
&lt;span class="s"&gt;    if res.returncode == 0 and res.stdout.strip():&lt;/span&gt;
&lt;span class="s"&gt;        return Path(res.stdout.strip())&lt;/span&gt;
&lt;span class="s"&gt;    return None&lt;/span&gt;

&lt;span class="s"&gt;def get_all_worktrees(repo_root):&lt;/span&gt;
&lt;span class="s"&gt;    res = subprocess.run([&amp;quot;git&amp;quot;, &amp;quot;-C&amp;quot;, str(repo_root), &amp;quot;worktree&amp;quot;, &amp;quot;list&amp;quot;, &amp;quot;--porcelain&amp;quot;], capture_output=True, text=True)&lt;/span&gt;
&lt;span class="s"&gt;    if res.returncode != 0:&lt;/span&gt;
&lt;span class="s"&gt;        return []&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    worktrees = []&lt;/span&gt;
&lt;span class="s"&gt;    current = {}&lt;/span&gt;
&lt;span class="s"&gt;    for line in res.stdout.splitlines() +[&amp;quot;&amp;quot;]:&lt;/span&gt;
&lt;span class="s"&gt;        if not line:&lt;/span&gt;
&lt;span class="s"&gt;            if current and &amp;quot;path&amp;quot; in current:&lt;/span&gt;
&lt;span class="s"&gt;                worktrees.append(current)&lt;/span&gt;
&lt;span class="s"&gt;            current = {}&lt;/span&gt;
&lt;span class="s"&gt;        elif line.startswith(&amp;quot;worktree &amp;quot;):&lt;/span&gt;
&lt;span class="s"&gt;            current[&amp;quot;path&amp;quot;] = Path(line[9:]).resolve()&lt;/span&gt;
&lt;span class="s"&gt;            current[&amp;quot;name&amp;quot;] = current[&amp;quot;path&amp;quot;].name&lt;/span&gt;
&lt;span class="s"&gt;        elif line.startswith(&amp;quot;branch &amp;quot;):&lt;/span&gt;
&lt;span class="s"&gt;            current[&amp;quot;branch&amp;quot;] = line[7:].removeprefix(&amp;quot;refs/heads/&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        elif line == &amp;quot;detached&amp;quot;:&lt;/span&gt;
&lt;span class="s"&gt;            current[&amp;quot;branch&amp;quot;] = &amp;quot;(detached)&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    return worktrees&lt;/span&gt;

&lt;span class="s"&gt;def get_file_status(wt_path, rel_path):&lt;/span&gt;
&lt;span class="s"&gt;    abs_path = wt_path / rel_path&lt;/span&gt;
&lt;span class="s"&gt;    if not abs_path.exists():&lt;/span&gt;
&lt;span class="s"&gt;        return None&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    st_res = subprocess.run([&amp;quot;git&amp;quot;, &amp;quot;-C&amp;quot;, str(wt_path), &amp;quot;status&amp;quot;, &amp;quot;-s&amp;quot;, &amp;quot;--&amp;quot;, str(rel_path)], capture_output=True, text=True)&lt;/span&gt;
&lt;span class="s"&gt;    st = st_res.stdout.strip()&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    mtime = os.path.getmtime(abs_path)&lt;/span&gt;
&lt;span class="s"&gt;    dt = datetime.datetime.fromtimestamp(mtime)&lt;/span&gt;
&lt;span class="s"&gt;    time_str = dt.strftime(&amp;quot;%m-%d %H:%M&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    if st.startswith(&amp;quot;??&amp;quot;):&lt;/span&gt;
&lt;span class="s"&gt;        status_label = &amp;quot;[?? 新增]&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;        status_color = GREEN&lt;/span&gt;
&lt;span class="s"&gt;    elif &amp;quot;M&amp;quot; in st:&lt;/span&gt;
&lt;span class="s"&gt;        status_label = &amp;quot;[M  修改]&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;        status_color = YELLOW&lt;/span&gt;
&lt;span class="s"&gt;    elif &amp;quot;D&amp;quot; in st:&lt;/span&gt;
&lt;span class="s"&gt;        status_label = &amp;quot;[D  删除]&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;        status_color = RED&lt;/span&gt;
&lt;span class="s"&gt;    elif st:&lt;/span&gt;
&lt;span class="s"&gt;        status_label = f&amp;quot;[{st[:7]:&amp;lt;7}]&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;        status_color = CYAN&lt;/span&gt;
&lt;span class="s"&gt;    else:&lt;/span&gt;
&lt;span class="s"&gt;        status_label = &amp;quot;[clean  ]&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;        status_color = GRAY&lt;/span&gt;
&lt;span class="s"&gt;        &lt;/span&gt;
&lt;span class="s"&gt;    return {&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;status_label&amp;quot;: status_label,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;status_color&amp;quot;: status_color,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;time_str&amp;quot;: time_str,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;abs_path&amp;quot;: str(abs_path),&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;rel_path&amp;quot;: str(rel_path),&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;mtime&amp;quot;: mtime&lt;/span&gt;
&lt;span class="s"&gt;    }&lt;/span&gt;

&lt;span class="s"&gt;def find_target_in_worktrees(worktrees, target_input):&lt;/span&gt;
&lt;span class="s"&gt;    if not target_input or not target_input.strip():&lt;/span&gt;
&lt;span class="s"&gt;        return []&lt;/span&gt;

&lt;span class="s"&gt;    # 1. 若传入已存在的确切物理文件（如 Yazi 传参），直接精准返回单项，绝不误弹列表&lt;/span&gt;
&lt;span class="s"&gt;    target_p = Path(target_input).resolve()&lt;/span&gt;
&lt;span class="s"&gt;    if target_p.is_file():&lt;/span&gt;
&lt;span class="s"&gt;        info = get_file_status(target_p.parent, target_p.name)&lt;/span&gt;
&lt;span class="s"&gt;        if info:&lt;/span&gt;
&lt;span class="s"&gt;            for wt in worktrees:&lt;/span&gt;
&lt;span class="s"&gt;                try:&lt;/span&gt;
&lt;span class="s"&gt;                    rel = str(target_p.relative_to(wt[&amp;quot;path&amp;quot;]))&lt;/span&gt;
&lt;span class="s"&gt;                    info[&amp;quot;wt&amp;quot;] = wt&lt;/span&gt;
&lt;span class="s"&gt;                    info[&amp;quot;rel_path&amp;quot;] = rel&lt;/span&gt;
&lt;span class="s"&gt;                    info[&amp;quot;score&amp;quot;] = 200&lt;/span&gt;
&lt;span class="s"&gt;                    return [info]&lt;/span&gt;
&lt;span class="s"&gt;                except ValueError:&lt;/span&gt;
&lt;span class="s"&gt;                    pass&lt;/span&gt;
&lt;span class="s"&gt;            info[&amp;quot;wt&amp;quot;] = {&amp;quot;name&amp;quot;: target_p.parent.name, &amp;quot;path&amp;quot;: target_p.parent}&lt;/span&gt;
&lt;span class="s"&gt;            info[&amp;quot;score&amp;quot;] = 200&lt;/span&gt;
&lt;span class="s"&gt;            return [info]&lt;/span&gt;

&lt;span class="s"&gt;    target_clean = target_input.strip(&amp;quot;/&amp;quot;).strip()&lt;/span&gt;
&lt;span class="s"&gt;    target_lower = target_clean.lower()&lt;/span&gt;
&lt;span class="s"&gt;    target_name = Path(target_clean).name.lower()&lt;/span&gt;
&lt;span class="s"&gt;    matches = []&lt;/span&gt;

&lt;span class="s"&gt;    for wt in worktrees:&lt;/span&gt;
&lt;span class="s"&gt;        wt_path = wt[&amp;quot;path&amp;quot;]&lt;/span&gt;
&lt;span class="s"&gt;        &lt;/span&gt;
&lt;span class="s"&gt;        # 1. 相对路径完全匹配&lt;/span&gt;
&lt;span class="s"&gt;        exact = wt_path / target_clean&lt;/span&gt;
&lt;span class="s"&gt;        if exact.is_file():&lt;/span&gt;
&lt;span class="s"&gt;            info = get_file_status(wt_path, target_clean)&lt;/span&gt;
&lt;span class="s"&gt;            if info:&lt;/span&gt;
&lt;span class="s"&gt;                info[&amp;quot;wt&amp;quot;] = wt&lt;/span&gt;
&lt;span class="s"&gt;                info[&amp;quot;score&amp;quot;] = 100&lt;/span&gt;
&lt;span class="s"&gt;                matches.append(info)&lt;/span&gt;
&lt;span class="s"&gt;            continue&lt;/span&gt;

&lt;span class="s"&gt;        # 2. 从 git ls-files 或文件树抓取文件列表&lt;/span&gt;
&lt;span class="s"&gt;        files = []&lt;/span&gt;
&lt;span class="s"&gt;        try:&lt;/span&gt;
&lt;span class="s"&gt;            res = subprocess.run(&lt;/span&gt;
&lt;span class="s"&gt;                [&amp;quot;git&amp;quot;, &amp;quot;-C&amp;quot;, str(wt_path), &amp;quot;ls-files&amp;quot;, &amp;quot;-c&amp;quot;, &amp;quot;-o&amp;quot;, &amp;quot;--exclude-standard&amp;quot;],&lt;/span&gt;
&lt;span class="s"&gt;                capture_output=True,&lt;/span&gt;
&lt;span class="s"&gt;                text=True&lt;/span&gt;
&lt;span class="s"&gt;            )&lt;/span&gt;
&lt;span class="s"&gt;            if res.returncode == 0 and res.stdout.strip():&lt;/span&gt;
&lt;span class="s"&gt;                files = [line.strip() for line in res.stdout.splitlines() if line.strip()]&lt;/span&gt;
&lt;span class="s"&gt;        except Exception:&lt;/span&gt;
&lt;span class="s"&gt;            pass&lt;/span&gt;

&lt;span class="s"&gt;        if not files:&lt;/span&gt;
&lt;span class="s"&gt;            for root, dirs, fnames in os.walk(wt_path):&lt;/span&gt;
&lt;span class="s"&gt;                dirs[:] = [d for d in dirs if d not in (&amp;quot;.git&amp;quot;, &amp;quot;.claude&amp;quot;, &amp;quot;node_modules&amp;quot;, &amp;quot;.venv&amp;quot;, &amp;quot;__pycache__&amp;quot;, &amp;quot;.runtime&amp;quot;)]&lt;/span&gt;
&lt;span class="s"&gt;                root_p = Path(root)&lt;/span&gt;
&lt;span class="s"&gt;                for fn in fnames:&lt;/span&gt;
&lt;span class="s"&gt;                    try:&lt;/span&gt;
&lt;span class="s"&gt;                        rel = str((root_p / fn).relative_to(wt_path))&lt;/span&gt;
&lt;span class="s"&gt;                        files.append(rel)&lt;/span&gt;
&lt;span class="s"&gt;                    except Exception:&lt;/span&gt;
&lt;span class="s"&gt;                        pass&lt;/span&gt;

&lt;span class="s"&gt;        # 3. 智能多维度打分模糊匹配&lt;/span&gt;
&lt;span class="s"&gt;        for rel in files:&lt;/span&gt;
&lt;span class="s"&gt;            p = Path(rel)&lt;/span&gt;
&lt;span class="s"&gt;            full_name = p.name.lower()&lt;/span&gt;
&lt;span class="s"&gt;            stem_name = p.stem.lower()&lt;/span&gt;
&lt;span class="s"&gt;            rel_lower = rel.lower()&lt;/span&gt;

&lt;span class="s"&gt;            score = 0&lt;/span&gt;
&lt;span class="s"&gt;            if rel_lower == target_lower or rel_lower.endswith(&amp;quot;/&amp;quot; + target_lower):&lt;/span&gt;
&lt;span class="s"&gt;                score = 100&lt;/span&gt;
&lt;span class="s"&gt;            elif full_name == target_name:&lt;/span&gt;
&lt;span class="s"&gt;                score = 90&lt;/span&gt;
&lt;span class="s"&gt;            elif stem_name == target_name:&lt;/span&gt;
&lt;span class="s"&gt;                score = 85  # 省略后缀精准命中（如输入 口播与动作对齐方案 -&amp;gt; 命中 口播与动作对齐方案.md）&lt;/span&gt;
&lt;span class="s"&gt;            elif full_name.startswith(target_name) or stem_name.startswith(target_name):&lt;/span&gt;
&lt;span class="s"&gt;                score = 70&lt;/span&gt;
&lt;span class="s"&gt;            elif target_name in stem_name or target_name in full_name:&lt;/span&gt;
&lt;span class="s"&gt;                score = 60  # 文件名部分包含关键词&lt;/span&gt;
&lt;span class="s"&gt;            elif target_lower in rel_lower:&lt;/span&gt;
&lt;span class="s"&gt;                score = 40  # 路径包含关键词&lt;/span&gt;

&lt;span class="s"&gt;            if score &amp;gt; 0:&lt;/span&gt;
&lt;span class="s"&gt;                info = get_file_status(wt_path, rel)&lt;/span&gt;
&lt;span class="s"&gt;                if info:&lt;/span&gt;
&lt;span class="s"&gt;                    info[&amp;quot;wt&amp;quot;] = wt&lt;/span&gt;
&lt;span class="s"&gt;                    info[&amp;quot;score&amp;quot;] = score&lt;/span&gt;
&lt;span class="s"&gt;                    matches.append(info)&lt;/span&gt;

&lt;span class="s"&gt;    # 去重并按匹配得分排序&lt;/span&gt;
&lt;span class="s"&gt;    seen = set()&lt;/span&gt;
&lt;span class="s"&gt;    unique = []&lt;/span&gt;
&lt;span class="s"&gt;    matches.sort(key=lambda m: (-m.get(&amp;quot;score&amp;quot;, 0), len(m[&amp;quot;rel_path&amp;quot;])))&lt;/span&gt;
&lt;span class="s"&gt;    for m in matches:&lt;/span&gt;
&lt;span class="s"&gt;        if m[&amp;quot;abs_path&amp;quot;] not in seen:&lt;/span&gt;
&lt;span class="s"&gt;            seen.add(m[&amp;quot;abs_path&amp;quot;])&lt;/span&gt;
&lt;span class="s"&gt;            unique.append(m)&lt;/span&gt;
&lt;span class="s"&gt;    return unique&lt;/span&gt;

&lt;span class="s"&gt;def list_all_dirty_files(worktrees):&lt;/span&gt;
&lt;span class="s"&gt;    all_files = []&lt;/span&gt;
&lt;span class="s"&gt;    for wt in worktrees:&lt;/span&gt;
&lt;span class="s"&gt;        wt_path = wt[&amp;quot;path&amp;quot;]&lt;/span&gt;
&lt;span class="s"&gt;        res = subprocess.run([&amp;quot;git&amp;quot;, &amp;quot;-C&amp;quot;, str(wt_path), &amp;quot;status&amp;quot;, &amp;quot;-s&amp;quot;], capture_output=True, text=True)&lt;/span&gt;
&lt;span class="s"&gt;        for line in res.stdout.splitlines():&lt;/span&gt;
&lt;span class="s"&gt;            line = line.strip()&lt;/span&gt;
&lt;span class="s"&gt;            if not line:&lt;/span&gt;
&lt;span class="s"&gt;                continue&lt;/span&gt;
&lt;span class="s"&gt;            parts = line.split(maxsplit=1)&lt;/span&gt;
&lt;span class="s"&gt;            if len(parts) == 2:&lt;/span&gt;
&lt;span class="s"&gt;                rel = parts[1]&lt;/span&gt;
&lt;span class="s"&gt;                info = get_file_status(wt_path, rel)&lt;/span&gt;
&lt;span class="s"&gt;                if info:&lt;/span&gt;
&lt;span class="s"&gt;                    info[&amp;quot;wt&amp;quot;] = wt&lt;/span&gt;
&lt;span class="s"&gt;                    all_files.append(info)&lt;/span&gt;
&lt;span class="s"&gt;    all_files.sort(key=lambda x: x[&amp;quot;mtime&amp;quot;], reverse=True)&lt;/span&gt;
&lt;span class="s"&gt;    return all_files&lt;/span&gt;

&lt;span class="s"&gt;def select_with_fzf(hits, prompt_title=&amp;quot;⚡ 选择 Worktree 文件&amp;quot;):&lt;/span&gt;
&lt;span class="s"&gt;    if not hits:&lt;/span&gt;
&lt;span class="s"&gt;        return None&lt;/span&gt;
&lt;span class="s"&gt;    if len(hits) == 1:&lt;/span&gt;
&lt;span class="s"&gt;        return hits[0]&lt;/span&gt;
&lt;span class="s"&gt;    if not sys.stdin.isatty():&lt;/span&gt;
&lt;span class="s"&gt;        return hits[0]&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    lines = []&lt;/span&gt;
&lt;span class="s"&gt;    for h in hits:&lt;/span&gt;
&lt;span class="s"&gt;        wt_name = h[&amp;quot;wt&amp;quot;][&amp;quot;name&amp;quot;]&lt;/span&gt;
&lt;span class="s"&gt;        st_color = h[&amp;quot;status_color&amp;quot;]&lt;/span&gt;
&lt;span class="s"&gt;        st_label = h[&amp;quot;status_label&amp;quot;]&lt;/span&gt;
&lt;span class="s"&gt;        time_str = h[&amp;quot;time_str&amp;quot;]&lt;/span&gt;
&lt;span class="s"&gt;        rel = h[&amp;quot;rel_path&amp;quot;]&lt;/span&gt;
&lt;span class="s"&gt;        abs_path = h[&amp;quot;abs_path&amp;quot;]&lt;/span&gt;
&lt;span class="s"&gt;        &lt;/span&gt;
&lt;span class="s"&gt;        display = f&amp;quot;🌿 {BOLD}{CYAN}{wt_name:&amp;lt;26}{RESET} {st_color}{st_label}{RESET}  {GRAY}{time_str}{RESET}  {rel}&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;        lines.append(f&amp;quot;{display}\t{abs_path}&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    input_text = &amp;quot;\n&amp;quot;.join(lines) + &amp;quot;\n&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    fzf_cmd = [&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;fzf&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        f&amp;quot;--prompt={prompt_title}: &amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;--height=40%&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;--layout=reverse&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;--border&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;--ansi&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;--delimiter=\t&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;--with-nth=1&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;--select-1&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;--exit-0&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    ]&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    try:&lt;/span&gt;
&lt;span class="s"&gt;        p = subprocess.Popen(fzf_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)&lt;/span&gt;
&lt;span class="s"&gt;        out, _ = p.communicate(input=input_text)&lt;/span&gt;
&lt;span class="s"&gt;        if p.returncode != 0 or not out.strip():&lt;/span&gt;
&lt;span class="s"&gt;            return None&lt;/span&gt;
&lt;span class="s"&gt;        selected_line = out.strip()&lt;/span&gt;
&lt;span class="s"&gt;        parts = selected_line.split(&amp;quot;\t&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        target_path = parts[-1]&lt;/span&gt;
&lt;span class="s"&gt;        matching_hit = next((h for h in hits if h[&amp;quot;abs_path&amp;quot;] == target_path), None)&lt;/span&gt;
&lt;span class="s"&gt;        return matching_hit or {&amp;quot;abs_path&amp;quot;: target_path}&lt;/span&gt;
&lt;span class="s"&gt;    except Exception as e:&lt;/span&gt;
&lt;span class="s"&gt;        print(f&amp;quot;fzf 启动失败: {e}&amp;quot;, file=sys.stderr)&lt;/span&gt;
&lt;span class="s"&gt;        return None&lt;/span&gt;

&lt;span class="s"&gt;def print_help():&lt;/span&gt;
&lt;span class="s"&gt;    print(f&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;{BOLD}{GREEN}wto (Worktree Open){RESET} - 跨 Worktree 智能文件检索与秒开工具&lt;/span&gt;

&lt;span class="s"&gt;{BOLD}用法:{RESET}&lt;/span&gt;
&lt;span class="s"&gt;  {CYAN}wto{RESET}                      扫描所有活跃 Worktree 中未提交的改动，上下键挑选后在 Yazi 打开&lt;/span&gt;
&lt;span class="s"&gt;  {CYAN}wto &amp;lt;文件名或相对路径&amp;gt;{RESET}    跨所有活跃 Worktree 智能模糊匹配该文件，回车直通 Yazi&lt;/span&gt;
&lt;span class="s"&gt;  {CYAN}wto -h &amp;lt;文件名&amp;gt;{RESET}          原地启动轻量 HTTP 服务，渲染 Markdown ({BOLD}含 Mermaid 流程图{RESET}) 或 HTML，&lt;/span&gt;
&lt;span class="s"&gt;                           并自动唤醒 Mac 浏览器打开；{GREEN}生成的内网链接可直接复制分享给同事！{RESET}&lt;/span&gt;
&lt;span class="s"&gt;  {CYAN}wto -h{RESET}                   扫描所有改动文件，上下键挑选后原地起 HTTP 服务在浏览器打开&lt;/span&gt;
&lt;span class="s"&gt;  {CYAN}wto --help{RESET}               显示本使用说明&lt;/span&gt;

&lt;span class="s"&gt;{BOLD}快捷参数:{RESET}&lt;/span&gt;
&lt;span class="s"&gt;  {YELLOW}-h, --html, --browser, -w{RESET}  启用浏览器预览模式（原地起 HTTP 服务 + 浏览器打开）&lt;/span&gt;
&lt;span class="s"&gt;  {YELLOW}--help{RESET}                     查看帮助信息&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;)&lt;/span&gt;

&lt;span class="s"&gt;def start_browser_preview(file_path, wt_info=None):&lt;/span&gt;
&lt;span class="s"&gt;    file_p = Path(file_path).resolve()&lt;/span&gt;
&lt;span class="s"&gt;    if not file_p.exists():&lt;/span&gt;
&lt;span class="s"&gt;        print(f&amp;quot;{RED}文件不存在: {file_path}{RESET}&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        return&lt;/span&gt;

&lt;span class="s"&gt;    target_dir = file_p.parent&lt;/span&gt;
&lt;span class="s"&gt;    file_name = file_p.name&lt;/span&gt;

&lt;span class="s"&gt;    # 获取仓库根目录与所有活跃 worktrees&lt;/span&gt;
&lt;span class="s"&gt;    repo_root = get_git_repo_root()&lt;/span&gt;
&lt;span class="s"&gt;    all_wts = get_all_worktrees(repo_root) if repo_root else []&lt;/span&gt;

&lt;span class="s"&gt;    # 寻找空闲端口 (3480..3500, 18080..18100)&lt;/span&gt;
&lt;span class="s"&gt;    port = 0&lt;/span&gt;
&lt;span class="s"&gt;    for p in list(range(3480, 3500)) + list(range(18080, 18100)):&lt;/span&gt;
&lt;span class="s"&gt;        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:&lt;/span&gt;
&lt;span class="s"&gt;            try:&lt;/span&gt;
&lt;span class="s"&gt;                s.bind((&amp;#39;0.0.0.0&amp;#39;, p))&lt;/span&gt;
&lt;span class="s"&gt;                port = p&lt;/span&gt;
&lt;span class="s"&gt;                break&lt;/span&gt;
&lt;span class="s"&gt;            except OSError:&lt;/span&gt;
&lt;span class="s"&gt;                continue&lt;/span&gt;
&lt;span class="s"&gt;    if not port:&lt;/span&gt;
&lt;span class="s"&gt;        port = 18080&lt;/span&gt;

&lt;span class="s"&gt;    server_ip = get_server_ip()&lt;/span&gt;

&lt;span class="s"&gt;    class RawFileHandler(http.server.SimpleHTTPRequestHandler):&lt;/span&gt;
&lt;span class="s"&gt;        def __init__(self, *args, **kwargs):&lt;/span&gt;
&lt;span class="s"&gt;            super().__init__(*args, directory=str(target_dir), **kwargs)&lt;/span&gt;

&lt;span class="s"&gt;        def guess_type(self, path):&lt;/span&gt;
&lt;span class="s"&gt;            p = str(path).lower()&lt;/span&gt;
&lt;span class="s"&gt;            if p.endswith((&amp;quot;.md&amp;quot;, &amp;quot;.markdown&amp;quot;)):&lt;/span&gt;
&lt;span class="s"&gt;                return &amp;quot;text/markdown; charset=utf-8&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;            elif p.endswith((&amp;quot;.html&amp;quot;, &amp;quot;.htm&amp;quot;)):&lt;/span&gt;
&lt;span class="s"&gt;                return &amp;quot;text/html; charset=utf-8&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;            elif p.endswith((&amp;quot;.txt&amp;quot;, &amp;quot;.log&amp;quot;, &amp;quot;.prompt&amp;quot;)):&lt;/span&gt;
&lt;span class="s"&gt;                return &amp;quot;text/plain; charset=utf-8&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;            elif p.endswith(&amp;quot;.wav&amp;quot;):&lt;/span&gt;
&lt;span class="s"&gt;                return &amp;quot;audio/wav&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;            elif p.endswith(&amp;quot;.mp3&amp;quot;):&lt;/span&gt;
&lt;span class="s"&gt;                return &amp;quot;audio/mpeg&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;            elif p.endswith(&amp;quot;.ogg&amp;quot;):&lt;/span&gt;
&lt;span class="s"&gt;                return &amp;quot;audio/ogg&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;            elif p.endswith(&amp;quot;.json&amp;quot;):&lt;/span&gt;
&lt;span class="s"&gt;                return &amp;quot;application/json; charset=utf-8&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;            return super().guess_type(path)&lt;/span&gt;

&lt;span class="s"&gt;        def translate_path(self, path):&lt;/span&gt;
&lt;span class="s"&gt;            parsed = urllib.parse.urlparse(path)&lt;/span&gt;
&lt;span class="s"&gt;            clean = urllib.parse.unquote(parsed.path).lstrip(&amp;quot;/&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;            if not clean:&lt;/span&gt;
&lt;span class="s"&gt;                return str(target_dir / file_name)&lt;/span&gt;

&lt;span class="s"&gt;            # 候选检索路径列表（按优先级依次尝试）&lt;/span&gt;
&lt;span class="s"&gt;            candidates = [&lt;/span&gt;
&lt;span class="s"&gt;                target_dir / clean,  # 1. HTML 文件同级目录&lt;/span&gt;
&lt;span class="s"&gt;            ]&lt;/span&gt;
&lt;span class="s"&gt;            if repo_root:&lt;/span&gt;
&lt;span class="s"&gt;                candidates.append(repo_root / clean)  # 2. 当前仓库/Worktree根目录（命中 /app/backend/...）&lt;/span&gt;
&lt;span class="s"&gt;            for wt in all_wts:&lt;/span&gt;
&lt;span class="s"&gt;                candidates.append(wt[&amp;quot;path&amp;quot;] / clean)  # 3. 其它活跃 Worktree 根目录&lt;/span&gt;
&lt;span class="s"&gt;            candidates.append(Path(&amp;quot;/&amp;quot; + clean))       # 4. 系统物理绝对路径&lt;/span&gt;

&lt;span class="s"&gt;            # 5. 局部后缀匹配（例如请求长路径，但资源就在当前目录或其子目录下）&lt;/span&gt;
&lt;span class="s"&gt;            for sub in[clean, Path(clean).name]:&lt;/span&gt;
&lt;span class="s"&gt;                candidates.append(target_dir / sub)&lt;/span&gt;
&lt;span class="s"&gt;            if &amp;quot;audio/&amp;quot; in clean:&lt;/span&gt;
&lt;span class="s"&gt;                audio_suffix = clean[clean.index(&amp;quot;audio/&amp;quot;):]&lt;/span&gt;
&lt;span class="s"&gt;                candidates.append(target_dir / audio_suffix)&lt;/span&gt;

&lt;span class="s"&gt;            for cand in candidates:&lt;/span&gt;
&lt;span class="s"&gt;                try:&lt;/span&gt;
&lt;span class="s"&gt;                    if cand.is_file() or cand.is_dir():&lt;/span&gt;
&lt;span class="s"&gt;                        return str(cand.resolve())&lt;/span&gt;
&lt;span class="s"&gt;                except Exception:&lt;/span&gt;
&lt;span class="s"&gt;                    pass&lt;/span&gt;

&lt;span class="s"&gt;            return super().translate_path(path)&lt;/span&gt;

&lt;span class="s"&gt;        def copyfile(self, source, outputfile):&lt;/span&gt;
&lt;span class="s"&gt;            try:&lt;/span&gt;
&lt;span class="s"&gt;                super().copyfile(source, outputfile)&lt;/span&gt;
&lt;span class="s"&gt;            except (ConnectionResetError, BrokenPipeError):&lt;/span&gt;
&lt;span class="s"&gt;                pass&lt;/span&gt;

&lt;span class="s"&gt;        def do_GET(self):&lt;/span&gt;
&lt;span class="s"&gt;            parsed = urllib.parse.urlparse(self.path)&lt;/span&gt;
&lt;span class="s"&gt;            clean_path = urllib.parse.unquote(parsed.path.lstrip(&amp;quot;/&amp;quot;))&lt;/span&gt;
&lt;span class="s"&gt;            &lt;/span&gt;
&lt;span class="s"&gt;            if not clean_path:&lt;/span&gt;
&lt;span class="s"&gt;                self.send_response(302)&lt;/span&gt;
&lt;span class="s"&gt;                self.send_header(&amp;quot;Location&amp;quot;, &amp;quot;/&amp;quot; + urllib.parse.quote(file_name))&lt;/span&gt;
&lt;span class="s"&gt;                self.end_headers()&lt;/span&gt;
&lt;span class="s"&gt;                return&lt;/span&gt;

&lt;span class="s"&gt;            try:&lt;/span&gt;
&lt;span class="s"&gt;                super().do_GET()&lt;/span&gt;
&lt;span class="s"&gt;            except (ConnectionResetError, BrokenPipeError):&lt;/span&gt;
&lt;span class="s"&gt;                pass&lt;/span&gt;

&lt;span class="s"&gt;        def end_headers(self):&lt;/span&gt;
&lt;span class="s"&gt;            self.send_header(&amp;quot;Accept-Ranges&amp;quot;, &amp;quot;bytes&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;            self.send_header(&amp;quot;Access-Control-Allow-Origin&amp;quot;, &amp;quot;*&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;            super().end_headers()&lt;/span&gt;

&lt;span class="s"&gt;        def log_message(self, format, *args):&lt;/span&gt;
&lt;span class="s"&gt;            pass&lt;/span&gt;

&lt;span class="s"&gt;    preview_url = f&amp;quot;http://{server_ip}:{port}/{urllib.parse.quote(file_name)}&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;    # 唤醒 Mac 本地默认浏览器&lt;/span&gt;
&lt;span class="s"&gt;    bridge_url = f&amp;quot;http://127.0.0.1:19222/open-browser?url={urllib.parse.quote(preview_url)}&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    notify_res = subprocess.run([&amp;quot;curl&amp;quot;, &amp;quot;-s&amp;quot;, &amp;quot;--max-time&amp;quot;, &amp;quot;2&amp;quot;, bridge_url], capture_output=True, text=True)&lt;/span&gt;
&lt;span class="s"&gt;    auto_opened = (notify_res.stdout.strip() == &amp;quot;ok&amp;quot;)&lt;/span&gt;

&lt;span class="s"&gt;    print(f&amp;quot;\n{BOLD}{GREEN}🌐 原地 HTTP 预览服务已就绪！{RESET}&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;    print(f&amp;quot;🔗 访问地址 {BOLD}: {BOLD}{CYAN}{preview_url}{RESET}&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;    if auto_opened:&lt;/span&gt;
&lt;span class="s"&gt;        print(f&amp;quot;{GREEN}✔ 成功唤醒 Mac 本地浏览器打开该文件（原样返回，交由浏览器插件高保真渲染）！{RESET}&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;    else:&lt;/span&gt;
&lt;span class="s"&gt;        print(f&amp;quot;{YELLOW}💡 提示：在 Ghostty 终端按住 Cmd 点击上方链接即可在 Mac 浏览器打开{RESET}&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;    print(f&amp;quot;{GRAY}(按 Ctrl+C 停止服务并返回终端){RESET}\n&amp;quot;)&lt;/span&gt;

&lt;span class="s"&gt;    class ThreadedHTTPServer(socketserver.ThreadingTCPServer):&lt;/span&gt;
&lt;span class="s"&gt;        daemon_threads = True&lt;/span&gt;
&lt;span class="s"&gt;        allow_reuse_address = True&lt;/span&gt;

&lt;span class="s"&gt;        def handle_error(self, request, client_address):&lt;/span&gt;
&lt;span class="s"&gt;            exc_type, _, _ = sys.exc_info()&lt;/span&gt;
&lt;span class="s"&gt;            if exc_type in (ConnectionResetError, BrokenPipeError):&lt;/span&gt;
&lt;span class="s"&gt;                return&lt;/span&gt;
&lt;span class="s"&gt;            super().handle_error(request, client_address)&lt;/span&gt;

&lt;span class="s"&gt;    try:&lt;/span&gt;
&lt;span class="s"&gt;        with ThreadedHTTPServer((&amp;quot;0.0.0.0&amp;quot;, port), RawFileHandler) as httpd:&lt;/span&gt;
&lt;span class="s"&gt;            try:&lt;/span&gt;
&lt;span class="s"&gt;                httpd.serve_forever()&lt;/span&gt;
&lt;span class="s"&gt;            except KeyboardInterrupt:&lt;/span&gt;
&lt;span class="s"&gt;                pass&lt;/span&gt;
&lt;span class="s"&gt;            finally:&lt;/span&gt;
&lt;span class="s"&gt;                try:&lt;/span&gt;
&lt;span class="s"&gt;                    httpd.server_close()&lt;/span&gt;
&lt;span class="s"&gt;                except Exception:&lt;/span&gt;
&lt;span class="s"&gt;                    pass&lt;/span&gt;
&lt;span class="s"&gt;    except Exception:&lt;/span&gt;
&lt;span class="s"&gt;        pass&lt;/span&gt;
&lt;span class="s"&gt;    print(f&amp;quot;\n{GRAY}HTTP 预览服务已关闭。{RESET}&amp;quot;, flush=True)&lt;/span&gt;
&lt;span class="s"&gt;    os._exit(0)&lt;/span&gt;

&lt;span class="s"&gt;def main():&lt;/span&gt;
&lt;span class="s"&gt;    args = sys.argv[1:]&lt;/span&gt;

&lt;span class="s"&gt;    # 处理 --help&lt;/span&gt;
&lt;span class="s"&gt;    if any(a in (&amp;quot;--help&amp;quot;, &amp;quot;-help&amp;quot;, &amp;quot;help&amp;quot;) for a in args):&lt;/span&gt;
&lt;span class="s"&gt;        print_help()&lt;/span&gt;
&lt;span class="s"&gt;        sys.exit(0)&lt;/span&gt;

&lt;span class="s"&gt;    is_http_mode = False&lt;/span&gt;
&lt;span class="s"&gt;    filtered_args = []&lt;/span&gt;
&lt;span class="s"&gt;    for arg in args:&lt;/span&gt;
&lt;span class="s"&gt;        if arg in (&amp;quot;-h&amp;quot;, &amp;quot;--html&amp;quot;, &amp;quot;--http&amp;quot;, &amp;quot;--browser&amp;quot;, &amp;quot;-w&amp;quot;):&lt;/span&gt;
&lt;span class="s"&gt;            is_http_mode = True&lt;/span&gt;
&lt;span class="s"&gt;        else:&lt;/span&gt;
&lt;span class="s"&gt;            filtered_args.append(arg)&lt;/span&gt;

&lt;span class="s"&gt;    target = filtered_args[0] if filtered_args else None&lt;/span&gt;

&lt;span class="s"&gt;    repo = get_git_repo_root()&lt;/span&gt;
&lt;span class="s"&gt;    if not repo:&lt;/span&gt;
&lt;span class="s"&gt;        print(f&amp;quot;{RED}✘ 错误：当前目录不在 Git 仓库内！{RESET}&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        sys.exit(1)&lt;/span&gt;

&lt;span class="s"&gt;    worktrees = get_all_worktrees(repo)&lt;/span&gt;
&lt;span class="s"&gt;    if not worktrees:&lt;/span&gt;
&lt;span class="s"&gt;        print(f&amp;quot;{RED}✘ 错误：未读取到任何 worktree 信息！{RESET}&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        sys.exit(1)&lt;/span&gt;

&lt;span class="s"&gt;    if target:&lt;/span&gt;
&lt;span class="s"&gt;        hits = find_target_in_worktrees(worktrees, target)&lt;/span&gt;
&lt;span class="s"&gt;    else:&lt;/span&gt;
&lt;span class="s"&gt;        hits = list_all_dirty_files(worktrees)&lt;/span&gt;

&lt;span class="s"&gt;    if not hits:&lt;/span&gt;
&lt;span class="s"&gt;        print(f&amp;quot;{YELLOW}⚠️  未在任何 Worktree 中找到匹配的文件：{target or &amp;#39;(所有工作区无未提交改动)&amp;#39;}{RESET}&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        sys.exit(0)&lt;/span&gt;

&lt;span class="s"&gt;    prompt = &amp;quot;🌐 选择文件 (回车启动 HTTP 并打开 Mac 浏览器)&amp;quot; if is_http_mode else &amp;quot;⚡ 选择文件 (回车直通 Yazi)&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    hit = select_with_fzf(hits, prompt_title=prompt)&lt;/span&gt;
&lt;span class="s"&gt;    if not hit:&lt;/span&gt;
&lt;span class="s"&gt;        sys.exit(0)&lt;/span&gt;

&lt;span class="s"&gt;    selected_file = hit[&amp;quot;abs_path&amp;quot;]&lt;/span&gt;

&lt;span class="s"&gt;    cb_bin = shutil.which(&amp;quot;cb&amp;quot;) or os.path.expanduser(&amp;quot;~/.local/bin/cb&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;    if os.path.exists(cb_bin):&lt;/span&gt;
&lt;span class="s"&gt;        subprocess.run([cb_bin, selected_file], capture_output=True)&lt;/span&gt;

&lt;span class="s"&gt;    if is_http_mode:&lt;/span&gt;
&lt;span class="s"&gt;        start_browser_preview(selected_file, hit)&lt;/span&gt;
&lt;span class="s"&gt;    else:&lt;/span&gt;
&lt;span class="s"&gt;        yazi_bin = shutil.which(&amp;quot;yazi&amp;quot;) or os.path.expanduser(&amp;quot;~/.local/bin/yazi&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        if not os.path.exists(yazi_bin):&lt;/span&gt;
&lt;span class="s"&gt;            print(f&amp;quot;{RED}✘ 错误：未找到 yazi 二进制文件！{RESET}&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;            sys.exit(1)&lt;/span&gt;
&lt;span class="s"&gt;        os.execv(yazi_bin, [yazi_bin, selected_file])&lt;/span&gt;

&lt;span class="s"&gt;if __name__ == &amp;quot;__main__&amp;quot;:&lt;/span&gt;
&lt;span class="s"&gt;    try:&lt;/span&gt;
&lt;span class="s"&gt;        main()&lt;/span&gt;
&lt;span class="s"&gt;    except KeyboardInterrupt:&lt;/span&gt;
&lt;span class="s"&gt;        sys.exit(0)&lt;/span&gt;
&lt;span class="s"&gt;PY&lt;/span&gt;
chmod +x ~/.local/bin/wto
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_start md_line_end"&gt;&lt;strong&gt;5. &lt;code&gt;~/.local/bin/down&lt;/code&gt;（一键下载：将远程服务器文件或目录秒传到 Mac 的 &lt;code&gt;~/Downloads&lt;/code&gt;）&lt;/strong&gt;&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;cat &lt;span class="s"&gt;&amp;lt;&amp;lt; &amp;#39;PY&amp;#39; &amp;gt; ~/.local/bin/down&lt;/span&gt;
&lt;span class="s"&gt;#!/usr/bin/env python3&lt;/span&gt;
&lt;span class="s"&gt;# ==============================================================================&lt;/span&gt;
&lt;span class="s"&gt;# down (Download to Mac) - 一键将服务器文件/目录极速下载到 Mac 的 ~/Downloads&lt;/span&gt;
&lt;span class="s"&gt;# ==============================================================================&lt;/span&gt;
&lt;span class="s"&gt;import sys&lt;/span&gt;
&lt;span class="s"&gt;import os&lt;/span&gt;
&lt;span class="s"&gt;import urllib.parse&lt;/span&gt;
&lt;span class="s"&gt;import urllib.request&lt;/span&gt;
&lt;span class="s"&gt;import json&lt;/span&gt;
&lt;span class="s"&gt;import tarfile&lt;/span&gt;
&lt;span class="s"&gt;import tempfile&lt;/span&gt;
&lt;span class="s"&gt;import subprocess&lt;/span&gt;
&lt;span class="s"&gt;import shutil&lt;/span&gt;

&lt;span class="s"&gt;BRIDGE_URL = &amp;quot;http://127.0.0.1:19222&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;HELP_TEXT = &amp;quot;&amp;quot;&amp;quot;\033[1mdown\033[0m (Download to Mac) - 一键将服务器文件下载到 Mac 的 ~/Downloads&lt;/span&gt;

&lt;span class="s"&gt;\033[1m用法:\033[0m&lt;/span&gt;
&lt;span class="s"&gt;  down &amp;lt;文件或目录&amp;gt;...       将一个或多个文件直接下载到 Mac 的 ~/Downloads&lt;/span&gt;
&lt;span class="s"&gt;  down                      不带参数时，交互式弹出文件列表（fzf 上下键挑选秒下载）&lt;/span&gt;
&lt;span class="s"&gt;  down --help, -h           查看帮助说明&lt;/span&gt;

&lt;span class="s"&gt;\033[1m亮点:\033[0m&lt;/span&gt;
&lt;span class="s"&gt;  • 自动识别目录：指定目录时会自动压缩为 .tar.gz 传回 Mac&lt;/span&gt;
&lt;span class="s"&gt;  • 零等待唤醒：文件传完后 Mac 会自动在 Finder 中高亮选中该文件&lt;/span&gt;
&lt;span class="s"&gt;  • 重名保护：若 Mac 的 ~/Downloads 已有同名文件，自动追加 (1), (2) 防覆盖&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;def format_size(size_bytes):&lt;/span&gt;
&lt;span class="s"&gt;    if size_bytes &amp;lt; 1024:&lt;/span&gt;
&lt;span class="s"&gt;        return f&amp;quot;{size_bytes} B&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    elif size_bytes &amp;lt; 1024 * 1024:&lt;/span&gt;
&lt;span class="s"&gt;        return f&amp;quot;{size_bytes / 1024:.1f} KB&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    else:&lt;/span&gt;
&lt;span class="s"&gt;        return f&amp;quot;{size_bytes / (1024 * 1024):.1f} MB&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;def check_bridge():&lt;/span&gt;
&lt;span class="s"&gt;    try:&lt;/span&gt;
&lt;span class="s"&gt;        req = urllib.request.Request(f&amp;quot;{BRIDGE_URL}/ping&amp;quot;, method=&amp;quot;GET&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        with urllib.request.urlopen(req, timeout=2) as resp:&lt;/span&gt;
&lt;span class="s"&gt;            return resp.status == 200&lt;/span&gt;
&lt;span class="s"&gt;    except Exception:&lt;/span&gt;
&lt;span class="s"&gt;        return False&lt;/span&gt;

&lt;span class="s"&gt;def upload_file(local_path, custom_name=None):&lt;/span&gt;
&lt;span class="s"&gt;    if not os.path.exists(local_path):&lt;/span&gt;
&lt;span class="s"&gt;        print(f&amp;quot;\033[31m✘ [Server ➔ Mac]\033[0m 文件不存在: {local_path}&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        return False&lt;/span&gt;

&lt;span class="s"&gt;    is_temp_tar = False&lt;/span&gt;
&lt;span class="s"&gt;    actual_path = local_path&lt;/span&gt;
&lt;span class="s"&gt;    filename = custom_name or os.path.basename(local_path.rstrip(&amp;quot;/\\&amp;quot;))&lt;/span&gt;

&lt;span class="s"&gt;    # 如果是目录，自动打包为 tar.gz&lt;/span&gt;
&lt;span class="s"&gt;    if os.path.isdir(local_path):&lt;/span&gt;
&lt;span class="s"&gt;        clean_dir = os.path.normpath(local_path)&lt;/span&gt;
&lt;span class="s"&gt;        base_name = os.path.basename(clean_dir) or &amp;quot;archive&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;        filename = f&amp;quot;{base_name}.tar.gz&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;        print(f&amp;quot;\033[34mℹ [Server ➔ Mac]\033[0m 检测到目录，正在打包压缩为 \033[1m{filename}\033[0m ...&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        &lt;/span&gt;
&lt;span class="s"&gt;        temp_file = tempfile.NamedTemporaryFile(suffix=&amp;quot;.tar.gz&amp;quot;, delete=False)&lt;/span&gt;
&lt;span class="s"&gt;        temp_file.close()&lt;/span&gt;
&lt;span class="s"&gt;        try:&lt;/span&gt;
&lt;span class="s"&gt;            with tarfile.open(temp_file.name, &amp;quot;w:gz&amp;quot;) as tar:&lt;/span&gt;
&lt;span class="s"&gt;                tar.add(local_path, arcname=base_name)&lt;/span&gt;
&lt;span class="s"&gt;            actual_path = temp_file.name&lt;/span&gt;
&lt;span class="s"&gt;            is_temp_tar = True&lt;/span&gt;
&lt;span class="s"&gt;        except Exception as e:&lt;/span&gt;
&lt;span class="s"&gt;            print(f&amp;quot;\033[31m✘ [Server ➔ Mac]\033[0m 打包目录失败: {e}&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;            if os.path.exists(temp_file.name):&lt;/span&gt;
&lt;span class="s"&gt;                os.unlink(temp_file.name)&lt;/span&gt;
&lt;span class="s"&gt;            return False&lt;/span&gt;

&lt;span class="s"&gt;    file_size = os.path.getsize(actual_path)&lt;/span&gt;
&lt;span class="s"&gt;    url = f&amp;quot;{BRIDGE_URL}/save-file?filename={urllib.parse.quote(filename)}&amp;amp;reveal=1&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;    try:&lt;/span&gt;
&lt;span class="s"&gt;        with open(actual_path, &amp;quot;rb&amp;quot;) as f:&lt;/span&gt;
&lt;span class="s"&gt;            req = urllib.request.Request(&lt;/span&gt;
&lt;span class="s"&gt;                url,&lt;/span&gt;
&lt;span class="s"&gt;                data=f,&lt;/span&gt;
&lt;span class="s"&gt;                headers={&lt;/span&gt;
&lt;span class="s"&gt;                    &amp;quot;Content-Type&amp;quot;: &amp;quot;application/octet-stream&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;                    &amp;quot;Content-Length&amp;quot;: str(file_size)&lt;/span&gt;
&lt;span class="s"&gt;                },&lt;/span&gt;
&lt;span class="s"&gt;                method=&amp;quot;POST&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;            )&lt;/span&gt;
&lt;span class="s"&gt;            with urllib.request.urlopen(req, timeout=180) as resp:&lt;/span&gt;
&lt;span class="s"&gt;                result = json.loads(resp.read().decode(&amp;quot;utf-8&amp;quot;))&lt;/span&gt;
&lt;span class="s"&gt;                saved_name = result.get(&amp;quot;filename&amp;quot;, filename)&lt;/span&gt;
&lt;span class="s"&gt;                size_str = format_size(result.get(&amp;quot;size&amp;quot;, file_size))&lt;/span&gt;
&lt;span class="s"&gt;                print(f&amp;quot;\033[32m✔ [Server ➔ Mac]\033[0m 成功下载到 Mac: \033[1m~/Downloads/{saved_name}\033[0m ({size_str})&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;                return True&lt;/span&gt;
&lt;span class="s"&gt;    except Exception as e:&lt;/span&gt;
&lt;span class="s"&gt;        print(f&amp;quot;\033[31m✘ [Server ➔ Mac]\033[0m 下载失败 ({filename}): {e}&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        return False&lt;/span&gt;
&lt;span class="s"&gt;    finally:&lt;/span&gt;
&lt;span class="s"&gt;        if is_temp_tar and os.path.exists(actual_path):&lt;/span&gt;
&lt;span class="s"&gt;            try:&lt;/span&gt;
&lt;span class="s"&gt;                os.unlink(actual_path)&lt;/span&gt;
&lt;span class="s"&gt;            except Exception:&lt;/span&gt;
&lt;span class="s"&gt;                pass&lt;/span&gt;

&lt;span class="s"&gt;def pick_file_fzf():&lt;/span&gt;
&lt;span class="s"&gt;    if not shutil.which(&amp;quot;fzf&amp;quot;):&lt;/span&gt;
&lt;span class="s"&gt;        print(&amp;quot;\033[31m✘ [Server ➔ Mac]\033[0m 未指定文件且系统未安装 fzf，请直接指定文件名，如: down &amp;lt;文件名&amp;gt;&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        return None&lt;/span&gt;
&lt;span class="s"&gt;    &lt;/span&gt;
&lt;span class="s"&gt;    find_cmd = [&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;find&amp;quot;, &amp;quot;.&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;-maxdepth&amp;quot;, &amp;quot;3&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;-not&amp;quot;, &amp;quot;-path&amp;quot;, &amp;quot;*/.*&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;-not&amp;quot;, &amp;quot;-path&amp;quot;, &amp;quot;*/node_modules/*&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;-not&amp;quot;, &amp;quot;-path&amp;quot;, &amp;quot;*/.venv/*&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;-not&amp;quot;, &amp;quot;-path&amp;quot;, &amp;quot;*/__pycache__/*&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;-type&amp;quot;, &amp;quot;f&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    ]&lt;/span&gt;
&lt;span class="s"&gt;    fzf_cmd = [&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;fzf&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;--height=40%&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;--reverse&amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;--prompt=选择要下载到 Mac 的文件 &amp;gt; &amp;quot;,&lt;/span&gt;
&lt;span class="s"&gt;        &amp;quot;--preview=head -n 20 {} 2&amp;gt;/dev/null&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    ]&lt;/span&gt;
&lt;span class="s"&gt;    try:&lt;/span&gt;
&lt;span class="s"&gt;        p1 = subprocess.Popen(find_cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)&lt;/span&gt;
&lt;span class="s"&gt;        p2 = subprocess.Popen(fzf_cmd, stdin=p1.stdout, stdout=subprocess.PIPE, text=True)&lt;/span&gt;
&lt;span class="s"&gt;        p1.stdout.close()&lt;/span&gt;
&lt;span class="s"&gt;        out, _ = p2.communicate()&lt;/span&gt;
&lt;span class="s"&gt;        selected = out.strip()&lt;/span&gt;
&lt;span class="s"&gt;        return selected if selected else None&lt;/span&gt;
&lt;span class="s"&gt;    except Exception:&lt;/span&gt;
&lt;span class="s"&gt;        return None&lt;/span&gt;

&lt;span class="s"&gt;def main():&lt;/span&gt;
&lt;span class="s"&gt;    args = sys.argv[1:]&lt;/span&gt;
&lt;span class="s"&gt;    if args and args[0] in (&amp;quot;-h&amp;quot;, &amp;quot;--help&amp;quot;, &amp;quot;help&amp;quot;):&lt;/span&gt;
&lt;span class="s"&gt;        print(HELP_TEXT)&lt;/span&gt;
&lt;span class="s"&gt;        return&lt;/span&gt;

&lt;span class="s"&gt;    if not check_bridge():&lt;/span&gt;
&lt;span class="s"&gt;        print(&amp;quot;\033[31m✘ [Server ➔ Mac]\033[0m 无法连接 Mac 本地桥接服务 (HTTP 19222)&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        print(&amp;quot;  提示: 请检查是否通过带有端口转发的 SSH 登录 (RemoteForward 19222 127.0.0.1:19222)&amp;quot;)&lt;/span&gt;
&lt;span class="s"&gt;        sys.exit(1)&lt;/span&gt;

&lt;span class="s"&gt;    if not args:&lt;/span&gt;
&lt;span class="s"&gt;        selected = pick_file_fzf()&lt;/span&gt;
&lt;span class="s"&gt;        if not selected:&lt;/span&gt;
&lt;span class="s"&gt;            sys.exit(0)&lt;/span&gt;
&lt;span class="s"&gt;        upload_file(selected)&lt;/span&gt;
&lt;span class="s"&gt;    else:&lt;/span&gt;
&lt;span class="s"&gt;        for path in args:&lt;/span&gt;
&lt;span class="s"&gt;            upload_file(path)&lt;/span&gt;

&lt;span class="s"&gt;if __name__ == &amp;quot;__main__&amp;quot;:&lt;/span&gt;
&lt;span class="s"&gt;    main()&lt;/span&gt;
&lt;span class="s"&gt;PY&lt;/span&gt;
chmod +x ~/.local/bin/down
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;&lt;h3 id="toc_14" class="h16"&gt;2.4 安装部署 Yazi (v26.9+) 与插件套件&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;安装最新版纯静态 Yazi：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;curl -sL https://github.com/sxyazi/yazi/releases/download/v26.9.1/yazi-x86_64-unknown-linux-musl.zip -o /tmp/yazi.zip
unzip -o /tmp/yazi.zip -d /tmp/yazi_bin
mv /tmp/yazi_bin/yazi-x86_64-unknown-linux-musl/yazi ~/.local/bin/yazi
mv /tmp/yazi_bin/yazi-x86_64-unknown-linux-musl/ya ~/.local/bin/ya
chmod +x ~/.local/bin/yazi ~/.local/bin/ya
rm -rf /tmp/yazi.zip /tmp/yazi_bin
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block md_block_as_opening md_has_block_below md_has_block_below_ol"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;安装并配置四大专属插件：&lt;/span&gt;
&lt;/p&gt;


&lt;ol&gt;
&lt;li class="md_li"&gt;&lt;span&gt;&lt;code&gt;zoom.yazi&lt;/code&gt;（自适应等比铺满与按键缩放）
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt;&lt;code&gt;piper.yazi&lt;/code&gt;（官方通用流预览）
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt;&lt;code&gt;paste-img.yazi&lt;/code&gt;（按 &lt;code&gt;P&lt;/code&gt; 直接粘贴 Mac 截图）
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt;&lt;code&gt;copy-mac.yazi&lt;/code&gt;（按 &lt;code&gt;c c&lt;/code&gt; 把绝对路径直接复制到 Mac）
&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;&lt;strong&gt;创建 &lt;code&gt;~/.config/yazi/plugins/zoom.yazi/main.lua&lt;/code&gt;&lt;/strong&gt;：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_lua  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;--- @since 26.1.22&lt;/span&gt;
&lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;Url&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hovered&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hovered&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;~=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;old_level&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preview_widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wrap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;YES&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notify&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;Zoom&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;error&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cell_size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;cw&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;cw&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_height&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;math.min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;math.floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;cw&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="nb"&gt;math.min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;math.floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;peek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;Failed to get image info: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new_level&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;tonumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;old_level&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;old_level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;max_w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;scale_w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scale_h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max_w&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_h&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;base_scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;math.min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scale_w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scale_h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;base_w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;math.max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;math.floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;base_scale&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;base_h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;math.max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;math.floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;base_scale&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;new_w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;math.min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;math.floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_w&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;new_h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;math.min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;math.floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_h&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;os.tmpname&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;magick&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;-auto-orient&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;-strip&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;-sample&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;string.format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;%dx%d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_h&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;-quality&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_quality&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;string.format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;WEBP:%s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}:&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;Failed to start `magick`: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;`magick` error %s: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;end_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;motion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tonumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;0&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;motion&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="o"&gt;~=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;0&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;Stat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stat&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;Cha&lt;/span&gt;
        &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tonumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;100644&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;peek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;area&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;preview&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
            &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lstat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;skip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;new_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;old_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;peek&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;peek&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;&lt;strong&gt;创建 &lt;code&gt;~/.config/yazi/plugins/copy-mac.yazi/main.lua&lt;/code&gt;&lt;/strong&gt;：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_lua  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;--- @sync entry&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hovered&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
        
        &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;path&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;path&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;filename&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;f&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;dirpath&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;d&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;name_without_ext&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;n&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;%.%w+$&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;

        &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;sh&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;-c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;curl -s -X POST --data-binary @- http://127.0.0.1:19222/set-clipboard&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;write_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notify&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;Copied to Mac&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;info&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notify&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;Copy Failed&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;无法连接 Mac 剪贴板&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;error&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;&lt;strong&gt;创建 &lt;code&gt;~/.config/yazi/plugins/paste-img.yazi/main.lua&lt;/code&gt;&lt;/strong&gt;：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_lua  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;--- @sync entry&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;pi&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notify&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;Paste&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;启动失败: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="nb"&gt;tostring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;error&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;

        &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notify&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;Paste&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;✔ 剪贴板内容已成功粘贴入当前目录！&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;info&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="n"&gt;ya&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notify&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;Paste&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;✘ 粘贴失败：剪贴板无数据或桥接未连接&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="s"&gt;warn&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;&lt;strong&gt;写入配置文件 &lt;code&gt;~/.config/yazi/yazi.toml&lt;/code&gt;&lt;/strong&gt;：&lt;/span&gt;
&lt;/p&gt;


&lt;pre class="lang_toml"&gt;&lt;code&gt;[preview]
max_width  = 3840
max_height = 2160
image_quality = 85

[plugin]
prepend_previewers = [
  { url = "*.{png,jpg,jpeg,webp,gif,bmp,PNG,JPG,JPEG,WEBP,GIF,BMP}", run = "zoom" },
  { mime = "image/*", run = "zoom" },
  { url = "*.md", run = 'piper -- CLICOLOR_FORCE=1 glow -w=$w -s=dark "$1"' },
  { url = "*.markdown", run = 'piper -- CLICOLOR_FORCE=1 glow -w=$w -s=dark "$1"' },
]&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;&lt;strong&gt;写入配置文件 &lt;code&gt;~/.config/yazi/keymap.toml&lt;/code&gt;&lt;/strong&gt;：&lt;/span&gt;
&lt;/p&gt;


&lt;pre class="lang_toml"&gt;&lt;code&gt;# 窗口全屏放大/恢复
[[mgr.prepend_keymap]]
on   = "T"
run  = "plugin toggle-pane max-preview"
desc = "全屏放大 / 恢复右侧预览窗口"

# 图片缩放
[[mgr.prepend_keymap]]
on   = "+"
run  = "plugin zoom 1"
desc = "图片预览放大"

[[mgr.prepend_keymap]]
on   = "="
run  = "plugin zoom 1"
desc = "图片预览放大"

[[mgr.prepend_keymap]]
on   = "-"
run  = "plugin zoom -1"
desc = "图片预览缩小"

[[mgr.prepend_keymap]]
on   = "0"
run  = "plugin zoom 0"
desc = "重置图片缩放比例"

# 从 Mac 粘贴截图
[[mgr.prepend_keymap]]
on   = "P"
run  = "plugin paste-img"
desc = "从 Mac 剪贴板直接粘贴图片或文件到当前目录"

# 路径复制直达 Mac 剪贴板
[[mgr.prepend_keymap]]
on   = [ "c", "c" ]
run  = "plugin copy-mac -- path"
desc = "复制文件绝对路径到 Mac 剪贴板"

[[mgr.prepend_keymap]]
on   = [ "c", "f" ]
run  = "plugin copy-mac -- filename"
desc = "复制文件名到 Mac 剪贴板"

[[mgr.prepend_keymap]]
on   = [ "c", "d" ]
run  = "plugin copy-mac -- dirpath"
desc = "复制当前目录路径到 Mac 剪贴板"

[[mgr.prepend_keymap]]
on   = [ "c", "n" ]
run  = "plugin copy-mac -- name_without_ext"
desc = "复制无后缀文件名到 Mac 剪贴板"

# 预览区滚动
[[mgr.prepend_keymap]]
on   = [ "&amp;lt;C-e&amp;gt;" ]
run  = "seek 5"
desc = "预览窗口向下滚动 5 行"

[[mgr.prepend_keymap]]
on   = [ "&amp;lt;C-y&amp;gt;" ]
run  = "seek -5"
desc = "预览窗口向上滚动 5 行"

# 在 Mac 浏览器中通过 HTTP 打开当前文件
[[mgr.prepend_keymap]]
on   = "B"
run  = 'shell "wto -h %h" --block'
desc = "在 Mac 浏览器中 HTTP 预览当前文件"

[[mgr.prepend_keymap]]
on   = "b"
run  = 'shell "wto -h %h" --block'
desc = "在 Mac 浏览器中 HTTP 预览当前文件"&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;&lt;h3 id="toc_15" class="h16"&gt;2.6 终端美化与极简提示符 (&lt;code&gt;~/.config/starship.toml&lt;/code&gt;)&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;采用 Catppuccin 渐变胶囊样式，并&lt;strong&gt;彻底去除 &lt;code&gt;$?:&lt;/code&gt; 等令人眼花的 Git 杂乱状态符号&lt;/strong&gt;，保持终端极致清爽：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;cat &lt;span class="s"&gt;&amp;lt;&amp;lt; &amp;#39;TOML&amp;#39; &amp;gt; ~/.config/starship.toml&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;$schema&amp;quot; = &amp;#39;https://starship.rs/config-schema.json&amp;#39;&lt;/span&gt;

&lt;span class="s"&gt;format = &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;[](red)\&lt;/span&gt;
&lt;span class="s"&gt;$os\&lt;/span&gt;
&lt;span class="s"&gt;$username\&lt;/span&gt;
&lt;span class="s"&gt;[](bg:peach fg:red)\&lt;/span&gt;
&lt;span class="s"&gt;$directory\&lt;/span&gt;
&lt;span class="s"&gt;[](bg:yellow fg:peach)\&lt;/span&gt;
&lt;span class="s"&gt;$git_branch\&lt;/span&gt;
&lt;span class="s"&gt;$git_status\&lt;/span&gt;
&lt;span class="s"&gt;[ ](yellow)\&lt;/span&gt;
&lt;span class="s"&gt;$character&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;palette = &amp;#39;catppuccin_mocha&amp;#39;&lt;/span&gt;

&lt;span class="s"&gt;[os]&lt;/span&gt;
&lt;span class="s"&gt;disabled = false&lt;/span&gt;
&lt;span class="s"&gt;style = &amp;quot;bg:red fg:crust&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;[os.symbols]&lt;/span&gt;
&lt;span class="s"&gt;Macos = &amp;quot;󰀵&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;Ubuntu = &amp;quot;󰕈&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;Linux = &amp;quot;󰌽&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;[username]&lt;/span&gt;
&lt;span class="s"&gt;show_always = true&lt;/span&gt;
&lt;span class="s"&gt;style_user = &amp;quot;bg:red fg:crust&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;style_root = &amp;quot;bg:red fg:crust&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;format = &amp;#39;[[ $user ](fg:crust bg:red)]($style)&amp;#39;&lt;/span&gt;

&lt;span class="s"&gt;[directory]&lt;/span&gt;
&lt;span class="s"&gt;style = &amp;quot;fg:crust bg:peach&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;format = &amp;quot;[ $path ]($style)&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;truncation_length = 3&lt;/span&gt;
&lt;span class="s"&gt;truncation_symbol = &amp;quot;…/&amp;quot;&lt;/span&gt;

&lt;span class="s"&gt;[git_branch]&lt;/span&gt;
&lt;span class="s"&gt;symbol = &amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;style = &amp;quot;bg:yellow&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;format = &amp;#39;[[ $symbol $branch ](fg:crust bg:yellow)]($style)&amp;#39;&lt;/span&gt;

&lt;span class="s"&gt;# 极简模式：关闭复杂的 stash/untracked 符号（$?:），仅保留干净的分支名&lt;/span&gt;
&lt;span class="s"&gt;[git_status]&lt;/span&gt;
&lt;span class="s"&gt;disabled = true&lt;/span&gt;
&lt;span class="s"&gt;style = &amp;quot;bg:yellow&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;format = &amp;#39;[[($all_status$ahead_behind )](fg:crust bg:yellow)]($style)&amp;#39;&lt;/span&gt;

&lt;span class="s"&gt;[nodejs]&lt;/span&gt;
&lt;span class="s"&gt;disabled = true&lt;/span&gt;

&lt;span class="s"&gt;[time]&lt;/span&gt;
&lt;span class="s"&gt;disabled = true&lt;/span&gt;

&lt;span class="s"&gt;[cmd_duration]&lt;/span&gt;
&lt;span class="s"&gt;disabled = true&lt;/span&gt;

&lt;span class="s"&gt;[character]&lt;/span&gt;
&lt;span class="s"&gt;disabled = false&lt;/span&gt;
&lt;span class="s"&gt;success_symbol = &amp;#39;[❯](bold green)&amp;#39;&lt;/span&gt;
&lt;span class="s"&gt;error_symbol = &amp;#39;[❯](bold red)&amp;#39;&lt;/span&gt;

&lt;span class="s"&gt;[palettes.catppuccin_mocha]&lt;/span&gt;
&lt;span class="s"&gt;rosewater = &amp;quot;#f5e0dc&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;flamingo = &amp;quot;#f2cdcd&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;pink = &amp;quot;#f5c2e7&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;mauve = &amp;quot;#cba6f7&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;red = &amp;quot;#f38ba8&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;maroon = &amp;quot;#eba0ac&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;peach = &amp;quot;#fab387&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;yellow = &amp;quot;#f9e2af&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;green = &amp;quot;#a6e3a1&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;teal = &amp;quot;#94e2d5&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;sky = &amp;quot;#89dceb&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;sapphire = &amp;quot;#74c7ec&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;blue = &amp;quot;#89b4fa&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;lavender = &amp;quot;#b4befe&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;text = &amp;quot;#cdd6f4&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;subtext1 = &amp;quot;#bac2de&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;subtext0 = &amp;quot;#a6adc8&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;overlay2 = &amp;quot;#9399b2&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;overlay1 = &amp;quot;#7f849c&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;overlay0 = &amp;quot;#6c7086&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;surface2 = &amp;quot;#585b70&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;surface1 = &amp;quot;#45475a&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;surface0 = &amp;quot;#313244&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;base = &amp;quot;#1e1e2e&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;mantle = &amp;quot;#181825&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;crust = &amp;quot;#11111b&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;TOML&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;&lt;h3 id="toc_16" class="h16"&gt;2.7 部署远程 Shell 快捷别名与工作流 (&lt;code&gt;~/.bashrc&lt;/code&gt;)&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;在远程服务器的 &lt;code&gt;~/.bashrc&lt;/code&gt; 末尾添加如下快捷别名与函数，实现工作区秒切、Tmux 窗口无痛管理与神级终端工具链集成：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_bash  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# ------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;# 远程开发快捷别名与工作流&lt;/span&gt;
&lt;span class="c1"&gt;# ------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;# 1. 项目直达&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;ai3&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cd ~/workspaces/&amp;lt;PROJECT_NAME&amp;gt; &amp;amp;&amp;amp; tmux new -A -s &amp;lt;PROJECT_NAME&amp;gt;&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;cdai&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cd ~/workspaces/&amp;lt;PROJECT_NAME&amp;gt;&amp;#39;&lt;/span&gt;

&lt;span class="c1"&gt;# 2. 终端神级工具链&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;lg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lazygit&amp;#39;&lt;/span&gt;            &lt;span class="c1"&gt;# Git TUI 神器（按 w 看/切 worktree，按 3 看 commit 树）&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;~/.local/bin/yazi&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;yazi&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;~/.local/bin/yazi&amp;#39;&lt;/span&gt; &lt;span class="c1"&gt;# 现代化文件管理器（方向键穿梭，Kitty 原生看图）&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;wt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;git worktree list&amp;#39;&lt;/span&gt;   &lt;span class="c1"&gt;# 查看当前项目所有 git worktree 工作树&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;gw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;glow&amp;#39;&lt;/span&gt;

&lt;span class="c1"&gt;# 3. Tmux 窗口快捷操作（保持当前目录）&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;new&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tmux new-window -c &amp;quot;$(pwd)&amp;quot;&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;cw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;new&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;rn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tmux rename-window&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;close&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;exit&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;tls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tmux ls&amp;#39;&lt;/span&gt;

&lt;span class="c1"&gt;# 4. 函数定义（规范无别名冲突）&lt;/span&gt;
ta&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  tmux new -A -s &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

md&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    glow
  &lt;span class="k"&gt;else&lt;/span&gt;
    glow -p &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

ws&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local&lt;/span&gt; target_dir
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="nv"&gt;target_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;find ~/workspaces -mindepth &lt;span class="m"&gt;1&lt;/span&gt; -maxdepth &lt;span class="m"&gt;1&lt;/span&gt; -type d -exec basename &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="p"&gt;|&lt;/span&gt; sort &lt;span class="p"&gt;|&lt;/span&gt; fzf --prompt&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;⚡ 选择工作区项目: &amp;quot;&lt;/span&gt; --height&lt;span class="o"&gt;=&lt;/span&gt;40% --layout&lt;span class="o"&gt;=&lt;/span&gt;reverse --border&lt;span class="k"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$target_dir&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; 0
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nv"&gt;target_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;
  &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nv"&gt;full_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/workspaces/&lt;/span&gt;&lt;span class="nv"&gt;$target_dir&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -d &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$full_path&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$full_path&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    tmux new -A -s &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$target_dir&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;未找到目录: &lt;/span&gt;&lt;span class="nv"&gt;$full_path&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

tkill&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$target&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;tmux list-sessions -F &lt;span class="s2"&gt;&amp;quot;#{session_name}&amp;quot;&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="p"&gt;|&lt;/span&gt; fzf --prompt&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;🗑️ 选择要关闭的保活会话: &amp;quot;&lt;/span&gt; --height&lt;span class="o"&gt;=&lt;/span&gt;40% --layout&lt;span class="o"&gt;=&lt;/span&gt;reverse --border&lt;span class="k"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$target&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; 0
  &lt;span class="k"&gt;fi&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$target&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;all&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    tmux kill-server
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;✔ 已关闭全部后台保活会话&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; 0
  &lt;span class="k"&gt;fi&lt;/span&gt;

  &lt;span class="c1"&gt;# 若未直接命中会话全名，智能补全序号（如 4 -&amp;gt; ai_classroom3_4）&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; ! tmux has-session -t &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$target&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nv"&gt;matched&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nv"&gt;cur_proj&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;basename &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; tmux has-session -t &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;cur_proj&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      &lt;span class="nv"&gt;matched&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;cur_proj&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="nb"&gt;local&lt;/span&gt; candidate
      &lt;span class="nv"&gt;candidate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;tmux list-sessions -F &lt;span class="s2"&gt;&amp;quot;#{session_name}&amp;quot;&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="p"&gt;|&lt;/span&gt; grep -E &lt;span class="s2"&gt;&amp;quot;(^|_)&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;$&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; head -n 1&lt;span class="k"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$candidate&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;matched&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$candidate&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
    &lt;span class="o"&gt;[&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$matched&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$matched&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; tmux kill-session -t &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$target&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;✔ 已关闭会话: &lt;/span&gt;&lt;span class="nv"&gt;$target&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;✖ 未找到会话: &lt;/span&gt;&lt;span class="nv"&gt;$target&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;tk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tkill&amp;#39;&lt;/span&gt;

&lt;span class="c1"&gt;# 加载 Starship 彩虹状态栏（Catppuccin Powerline）&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -x &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.local/bin/starship&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.local/bin/starship init bash&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;hr&gt;
&lt;h2 id="toc_17" class="h16"&gt;第三部分：完整验证核对清单（验收流程）&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;按顺序执行以下命令验证全链路是否正常：&lt;/span&gt;
&lt;/p&gt;


&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left"&gt;验证项&lt;/th&gt;
&lt;th style="text-align: left"&gt;执行命令&lt;/th&gt;
&lt;th style="text-align: left"&gt;期望输出 / 正确现象&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;1. Mac 本地桥接服务&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;&lt;code&gt;curl -s http://127.0.0.1:19222/ping&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;输出 &lt;code&gt;pong&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;2. 连入服务器反向隧道&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;&lt;code&gt;cx&lt;/code&gt; 然后在服务器执行 &lt;code&gt;curl -s http://127.0.0.1:19222/ping&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;输出 &lt;code&gt;pong&lt;/code&gt;（证明隧道通畅）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;3. Tmux 版本与选项&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;在服务器执行 &lt;code&gt;tmux -V &amp;amp;&amp;amp; tmux show -g allow-passthrough&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;输出 &lt;code&gt;tmux 3.5a&lt;/code&gt; 与 &lt;code&gt;allow-passthrough on&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;4. 粘贴 Mac 截图或文件&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;在 Mac 截图或在 Finder 复制文件后，在服务器执行 &lt;code&gt;pi&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;输出 &lt;code&gt;✔ [Mac ➔ Server] 成功从剪贴板粘贴图片/文件&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;5. 拖拽文件秒传&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;在服务器执行 &lt;code&gt;up /Users/.../test.png&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;输出 &lt;code&gt;✔ [Mac ➔ Server] 上传成功&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;6. Yazi 路径复制到 Mac&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;在服务器运行 &lt;code&gt;y&lt;/code&gt;，光标停在文件敲两次 &lt;code&gt;c&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;右上角提示 &lt;code&gt;Copied to Mac&lt;/code&gt;，回 Mac 按 &lt;code&gt;Cmd+V&lt;/code&gt; 成功粘贴&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;7. 图片看图与缩放&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;在 Yazi 停在图片上按 &lt;code&gt;T&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;图片瞬间铺满全屏，按 &lt;code&gt;+&lt;/code&gt; 进一步放大，按 &lt;code&gt;0&lt;/code&gt; 还原&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;8. 跨 Worktree 智能检索&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;在服务器执行 &lt;code&gt;wto&lt;/code&gt; 或 &lt;code&gt;wto &amp;lt;文件&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;底部弹起 40% fzf 窗口，上下键移动，回车直通 Yazi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;9. 浏览器原地文件预览&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;在服务器执行 &lt;code&gt;wto -h &amp;lt;文件&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;原地启动轻量 HTTP 服务，原样返回文件（支持浏览器 Markdown 插件高保真渲染），自动唤醒 Mac 浏览器打开，内网链接可直接发给同事，Ctrl+C 退出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;10. 服务器文件秒传回 Mac&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;在服务器执行 &lt;code&gt;down &amp;lt;文件或目录&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;输出 &lt;code&gt;✔ [Server ➔ Mac] 成功下载到 Mac: ~/Downloads/...&lt;/code&gt;，Mac Finder 自动聚焦高亮选中&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;hr&gt;
&lt;h2 id="toc_18" class="h16"&gt;第四部分：日常操作随手备忘&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;# --- 会话连接与管理 (Mac 本地，配置解耦自 ~/.config/cx/config) ---
cx                # 默认直达主项目会话
cx new            # 自动新建独立序号会话 (my_project_1, _2 ...)
cx 1 / cx 2       # 直接进对应序号会话
cx ls             # 查看后台有哪些会话在跑 (免端口转发冲突)
cx k / tk         # 交互式选择关闭会话
cx k &amp;lt;序号/名字&amp;gt;  # 按序号或名字秒杀会话 (例: cx k 4 / tk 4)
cx ka             # 一键关闭全部后台会话
cx config         # 查看/切换当前目标服务器与项目配置
cx bridge         # 查看本地跨端桥接服务运行状态 (127.0.0.1:19222)
cx bridge restart # 一键重启本地桥接服务 (解决端口阻塞或异常)
cx -h / cx h     # 查看 cx 命令行帮助与中文说明 (亦支持 help / --help)

# --- 远程工作区直达与会话调度 (远程服务器) ---
ws                # fzf 弹出工作区列表，上下键挑选回车直达项目并挂接 tmux
ws &amp;lt;项目名&amp;gt;       # 直接切到指定项目目录并挂入对应会话
ai3               # 秒进主项目并恢复/挂接主会话
cdai              # 纯切到主项目目录
ta [会话名]       # 挂接指定会话（默认 main，不存在则新建）
tls               # 查看所有后台 tmux 会话
tk / tkill        # fzf 交互式挑着杀掉会话
tk &amp;lt;序号/名字&amp;gt;    # 按序号或名字秒杀会话 (例: tk 4 关掉当前项目 _4 会话)
tk all            # 一键杀掉全部后台保活会话

# --- Tmux 窗口极速操作 (远程服务器内) ---
new / cw          # 在当前工作目录下新建 tmux 窗口（保持当前 pwd，不跳回根目录）
rn                # 重命名当前 tmux 窗口
close             # 退出当前窗格或窗口 (exit)

# --- Git Worktree 与文档速查 (远程服务器) ---
wt                # 一键查看当前仓库所有 Git Worktree 工作树及分支
lg                # 启动 Lazygit（按 w 查/切 worktree，按 3 查 commit 树）
md &amp;lt;文件&amp;gt;         # Glow 彩色高亮分页预览 Markdown 文档
md                # Glow 交互式浏览当前目录所有文档
gw                # glow 原生命令别名

# --- 跨端文件流转与 Worktree 检索 (远程服务器) ---
pi / pf           # 智能粘贴：Mac 截图像图贴图；Finder 复制文件(Cmd+C)则原名拉取！
pi test.png       # 指定文件名保存（仅单文件/截图时生效）
up [把文件拖进来] # 直接把本地文件拉取到当前目录
down &amp;lt;文件/目录&amp;gt;  # 一键秒下到 Mac ~/Downloads，目录自动打 .tar.gz，Finder 自动高亮！
down              # 不带参数：fzf 上下键挑选文件极速下载到 Mac
down --help       # 查看 down 命令行帮助
wto &amp;lt;文件名&amp;gt;      # 跨所有 Worktree 智能匹配该文件，fzf 上下键选择，回车直通 Yazi 并高亮
wto -h &amp;lt;文件名&amp;gt;   # 原地起 HTTP 服务，原样返回文件（交由浏览器 Markdown 插件高保真渲染），链接可直接发同事，Ctrl+C 退出
wto -h            # 扫描所有 Worktree 中近期改动的未提交代码，上下键挑选后起 HTTP 浏览器查看
wto --help        # 查看 wto 命令行帮助与用法说明

# --- Yazi 专属神键 (远程服务器) ---
y                 # 启动 Yazi
q                 # 普通退出
Q (大写)          # 退出并自动 cd 到最后选中的目录（极力推荐）
c c               # 复制选中文件的绝对路径到 Mac 剪贴板！
c f               # 复制文件名到 Mac 剪贴板
P (大写)          # 直接从 Mac 剪贴板粘贴最新截图或复制的文件并高亮展示
T (大写)          # 全屏放大/还原右侧预览（图片自适应撑满，文档宽幅排版）
+ / =             # 图片手动放大 15%
-                 # 图片手动缩小
0                 # 重置图片缩放为最佳贴合尺寸
Ctrl+e / Ctrl+y   # 预览窗口下滚/上滚 5 行
B / b             # 在 Mac 浏览器中通过 HTTP 原地打开当前文件（可发同事，按 Ctrl+C 秒回 Yazi）

# --- Tmux 窗口与分屏操作 (远程服务器，前缀键统一为 Ctrl+b，完全释放 Ctrl+a 跳行首) ---
Ctrl+b 然后按 }   # 当前窗口与右侧/下方窗口互换位置！
Ctrl+b 然后按 {   # 当前窗口与左侧/上方窗口互换位置！
Ctrl+b 然后按 Ctrl+o # 顺时针旋转轮换所有分屏
Ctrl+b 然后按 Space  # 一键切换分屏排版（左右、上下、网格四分屏）
Ctrl+b 然后按 !   # 把当前分屏弹射出去变成独立的新全屏窗口
Ctrl+b 然后按 z   # 当前分屏临时最大化 / 还原&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;</summary>

  </entry>


  <entry>


    <title>老码农的小感想</title>

    <link href="http://imatlas.com/post/lao-ma-nong-de-xiao-gan-xiang"  rel="alternate"></link>

    <updated>2024-02-06T14:31:00Z</updated>
    <id>lao-ma-nong-de-xiao-gan-xiang</id>

    <author>
      <name>iAzrael</name>

    </author>
    <summary type="html">&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start"&gt;我发现，现在很多计算机和软件工程相关专业的学生，&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;都不是因为喜欢计算机这个行业或者编程才选这个专业的。&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;都不是因为喜欢计算机这个行业，或者说编程才选这个专业的。&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;临近毕业了。除了课堂作业，连一个项目都没有写过&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;当年我想学医。所以报考了纯医学类的院校。&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;谁知，被调剂到了计算机专业。&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;我也不明白校长的脑洞怎么会这么大。一个医学类院校竟然会有计算机专业？&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;当我看到录取通知书，简直都要崩溃了&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;等开学后。我发现。我还是这个学院的第二届学生&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;我更加崩溃了……&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;好不容易说服自己接受现实&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;一开始选择了C++入手。然而选错了&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;在图书馆找了一个不知名作者写的不知名的书，里面用的他写的不知名的库&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line md_line_end"&gt;懵懵懂懂的搞了一个月，才写出了一个hello world。&lt;/span&gt;
&lt;/p&gt;</summary>

  </entry>


  <entry>


    <title>使用CSS mask 实现图片的斜线拼接</title>

    <link href="http://imatlas.com/post/use-css-mask-slash-achieve-image-stitching"  rel="alternate"></link>

    <updated>2016-02-04T03:50:00Z</updated>
    <id>use-css-mask-slash-achieve-image-stitching</id>

    <author>
      <name>iAzrael</name>

    </author>
    <summary type="html">&lt;h2 id="toc_0" class="h16"&gt;每次必说题外话&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;话说貌似好久没有写技术文章了，自从娃娃出来后，很少能有时间做技术研究，思考的时间也不足。不过有得必有失，世上事也就酱紫了。但是作为一个前端攻城师，不写代码，不研究技术，是会被后浪拍死在沙滩上的。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;碰巧前段时间碰到个CSS问题，一直很喜欢CSS的，能CSS解决的问题绝对不用JS，于是就抽时间整整看。&lt;/span&gt;
&lt;/p&gt;

&lt;h2 id="toc_1" class="h16"&gt;什么是斜线拼接&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;回到本文主题上，”斜线拼接“是我自创的词语，因为我也不知道怎么描述这个需求，o(╯□╰)o，实际的效果是下面所示：&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_start md_line_end"&gt;&lt;a class="md_compiled" href="/uploads/2015-09-01/example.png"&gt;&lt;img class="md_compiled " src="/uploads/2015-09-01/example.png" alt="" title="" &gt;&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;眼力好的筒子应该就能发现，上面这张图是两个帅锅拼接在一起的，看中间的斜线。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;但是呢，刚接到这个需求的时候，开发是抓狂的——第一反应就是用canvas画图，这得多累啊，只是要显示张图片而已，竟然还要动用一坨JS，O__O &amp;quot;…&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;不过依稀记得，CSS 貌似有个遮罩的特性，可以实现图片的部分显示的效果的。more&lt;/span&gt;
&lt;/p&gt;

&lt;h2 id="toc_2" class="h16"&gt;CSS mask &amp;amp; linear gradient&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;要实现这个特性，就需要用到CSS遮罩和线性渐变。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;至于这两个是什么东西，我就不班门弄斧的介绍了，毕竟这两个属性出生也挺久了的，不了解的筒子可以看这两篇文章&lt;a class="md_compiled" href="http://www.w3cplus.com/css3/css-masking.html"&gt;CSS遮罩——如何在CSS中使用遮罩&lt;/a&gt;和&lt;a class="md_compiled" href="http://www.zhangxinxu.com/wordpress/2013/09/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3css3-gradient%E6%96%9C%E5%90%91%E7%BA%BF%E6%80%A7%E6%B8%90%E5%8F%98/"&gt;深入理解css3-gradient斜向线性渐变&lt;/a&gt;。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;先看下实际的效果&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_start md_line_end"&gt;&lt;a class="md_compiled" href="http://demo.imatlas.com/use-css-mask-slash-achieve-image-stitching.html"&gt;&lt;img class="md_compiled " src="/uploads/2016-01-01/拼接效果图.png" alt="" title="" &gt;&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;大家请看妹子中间（注意表看错了，是两个妹子的中间），有一条比较明显的分界线。多说无益，我知道你们想看demo，&lt;a class="md_compiled" href="http://demo.imatlas.com/use-css-mask-slash-achieve-image-stitching.html"&gt;用力戳这里&amp;gt;&amp;gt;&lt;/a&gt;。&lt;/span&gt;
&lt;/p&gt;

&lt;h3 id="toc_3" class="h16"&gt;&lt;strong&gt;第一步，显示两张图&lt;/strong&gt;&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;OK，先看代码，然后我再来解释。&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_html  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;img-container&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;img-left&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;img-right&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;然后是CSS&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_css  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class="nc"&gt;.img-container&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;border&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#40BCFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;.img-left&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url(img/left.jpg)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;background&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;.img-right&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url(img/right.jpg)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;background&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;OK，看下效果&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_start md_line_end"&gt;&lt;a class="md_compiled" href="/uploads/2016-02-01/abcdefg.png"&gt;&lt;img class="md_compiled " src="/uploads/2016-02-01/abcdefg.png" alt="" title="" &gt;&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;小明：尼玛，这不是坑爹么，这么简单谁不会？&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;小朋友，别急，我们两个主角还没上了。&lt;/span&gt;
&lt;/p&gt;

&lt;h3 id="toc_4" class="h16"&gt;&lt;strong&gt;画个斜线&lt;/strong&gt;&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;为了实现斜线拼接，你总得有个斜线吧？把img-right的背景换成一个带有“斜线”的图，这个就不用“真”图片啦，CSS渐变就能完成，如下：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_css  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;    &lt;span class="nc"&gt;.img-right&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="nb"&gt;top&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;blue&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;white&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_with_image md_line_start md_line_end"&gt;&lt;img class="md_compiled " src="/uploads/2016-02-01/QQ截图20160204112221.png" alt="" title="" &gt;&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;好，把背景换成真实的美女，渐变图作为mask&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_css  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nc"&gt;.img-right&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url(img/right.jpg)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;background&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="nb"&gt;top&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;blue&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;white&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;But，如果你这么做了，会发现看到的是完整的图，并没有被遮盖，跟下图一样。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_start md_line_end"&gt;&lt;a class="md_compiled" href="/uploads/2016-02-01/abcdefg.png"&gt;&lt;img class="md_compiled " src="/uploads/2016-02-01/abcdefg.png" alt="" title="" &gt;&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;这是因为css mask的原理是，它只会把遮罩图里透明像素所对应的原图部分进行隐藏，而我们的渐变图是完全不透明的（我们是蓝白色相间的），所以没有遮罩效果。那么把蓝色改成透明试试。&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_css  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nc"&gt;.img-right&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url(img/right.jpg)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;background&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="nb"&gt;top&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;white&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_start md_line_end"&gt;&lt;a class="md_compiled" href="/uploads/2016-02-01/QQ%E6%88%AA%E5%9B%BE20160204113645.png"&gt;&lt;img class="md_compiled " src="/uploads/2016-02-01/QQ截图20160204113645.png" alt="" title="" &gt;&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;当当当~~美女只显示一半啦！♪(^∇^*)&lt;/span&gt;
&lt;/p&gt;

&lt;h3 id="toc_5" class="h16"&gt;&lt;strong&gt;层叠&lt;/strong&gt;&lt;/h3&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;最后，把第二张图层在第一章上面，由于第二张图左边一半都是透明的，背景里的美女也能直接透过来啦。&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_css  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nc"&gt;.img-right&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;top&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_start md_line_end"&gt;&lt;a class="md_compiled" href="http://demo.imatlas.com/use-css-mask-slash-achieve-image-stitching.html"&gt;&lt;img class="md_compiled " src="/uploads/2016-01-01/拼接效果图.png" alt="" title="" &gt;&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;看下最终img-right所需要的样式代码&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_css  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nc"&gt;.img-right&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;position&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;top&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url(img/right.jpg)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;background&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="nb"&gt;top&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;transparent&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;white&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;怎么样，很简单是吧？&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;CSS3有很多新鲜（其实这个不新鲜了~）的特性可以实现很多有趣的应用，如果你有其他方案，欢迎留言讨论，O(∩_∩)O谢谢阅读！&lt;/span&gt;
&lt;/p&gt;</summary>

  </entry>


  <entry>


    <title>肿么安装Effect Game</title>

    <link href="http://imatlas.com/post/kuai-le-de-ma-nong/zhong-yao-an-zhuang-effect-game"  rel="alternate"></link>

    <updated>2015-07-22T07:52:00Z</updated>
    <id>kuai-le-de-ma-nong/zhong-yao-an-zhuang-effect-game</id>

    <author>
      <name>iAzrael</name>

    </author>
    <summary type="html">&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;Effect Game的安装还是很麻烦的, 原作者用的时代比较久远, 有很多软件包在新的linux系统上都可能有兼容问题, 这里做个安装记录方便后人查阅.&lt;/span&gt;
&lt;/p&gt;

&lt;h2 id="toc_0" class="h16"&gt;环境准备&lt;/h2&gt;
&lt;ol&gt;
&lt;li class="md_li"&gt;&lt;span&gt;fedora 21
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt;能翻墙的比较快的网络
&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;Effect Game的需要运行在linux系统里, 理论上任何linux发行版都可以, 但是我在ubuntu上折腾了好久, 总归还是放弃了. &lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;各个发行版虽然内核一样, 但是各种软件包可能不一样, 名字也可能不一样, 包管理工具也不一样, 所以环境这里, 还是建议用 &lt;code&gt;fedora 21&lt;/code&gt;, 而且不能用最新版, 最新版的fedora把 yum 给替换成了 dnf, 还是很多问题.&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;这里的安装步骤是基本按照这个E文文档的, &lt;a class="md_compiled" href="https://github.com/jhuckaby/Effect-Games/wiki/Installation-Guide"&gt;https://github.com/jhuckaby/Effect-Games/wiki/Installation-Guide&lt;/a&gt;, 启用能用yum安装的软件包都直接用yum了.&lt;/span&gt;
&lt;/p&gt;

&lt;h2 id="toc_1" class="h16"&gt;安装各种系统依赖包&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;作者列了yum install xxx 很多包, 但是其实可以批量安装的&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;如果是第一次用yum, 先更新下yum的版本库 &lt;code&gt;yum repolist&lt;/code&gt; &lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;批量安装, &lt;strong&gt;安装完成后再敲入整个命令确认是否有安装失败的&lt;/strong&gt;(已经安装了的不会重复安装)&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;yum install zlib-devel libxml2-devel libgpg-error-devel libgcrypt-devel libxslt-devel expat-devel db4-devel e2fsprogs-devel krb5-devel openssl-devel aspell-devel rpm-build gcc screen sendmail "gcc-c++" bzip2-devel freetype-devel libpng-devel libtiff-devel libjpeg libjpeg-devel libstdc++-devel curl curl-devel libidn-devel krb5-devel e2fsprogs-devel libgcrypt-devel libgpg-error-devel&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;&lt;h2 id="toc_2" class="h16"&gt;创建 Effect Game 的安装目录&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;这里就直接按照作者的目录来设置, 大部分东东都放到这里, 避免各种引用要修改  &lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;mkdir /effect
mkdir -p /effect/perl/bin/&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;&lt;h2 id="toc_3" class="h16"&gt;安装 perl 和 cpan&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;yum install perl
yum install cpan&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;作者把 perl 放到了 /effect/perl 里, 这里做个软连就好&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;ln -s /usr/bin/perl /effect/perl/bin/perl 
ln -s /usr/bin/cpan /effect/perl/bin/cpan&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;&lt;h2 id="toc_4" class="h16"&gt;安装各种 perl 模块&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;第一次使用cpan时, 直接敲入 &lt;code&gt;cpan&lt;/code&gt; 运行一次, 按提示使用自动配置&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;为了避免安装时可能会遇到的下面这个提示, 烦它的话可以先装一下 &lt;code&gt;YAML&lt;/code&gt;.&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt; 'YAML' not installed, will not store persistent state

cpan YAML&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;然后批量安装各种模块, &lt;strong&gt;安装完成后再敲入整个命令确认是否有安装失败的&lt;/strong&gt;(已经安装了的不会重复安装)&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;cpan LWP::UserAgent Archive::Zip Archive::Tar Class::Loader Digest::SHA Digest::SHA1 Math::Pari Devel::Symdump Module::Build MIME::Lite Test::Simple Text::Wrap CGI Devel::CoreStack Cwd IO::Socket::INET Test::Harness Time::HiRes Unicode::String Date::Parse MIME::Parser Crypt::SSLeay ExtUtils::XSBuilder IO::Socket::SSL File::lockf IPC::ShareLite Syntax::Highlight::Engine::Kate Text::Aspell Net::Twitter::Lite HTTP::Daemon File::Flock&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;这个需要等很久很久, 比很久很久还要久.&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;&lt;code&gt;Text::Aspell&lt;/code&gt; 很容易安装失败, 按如下步骤重新安装&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;yum install aspell aspell-en

cpan Text::Aspell&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;&lt;h2 id="toc_5" class="h16"&gt;安装图片服务 ImageMagick&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;ImageMagic不要用yum安装, 编译时需要指定很多环境变量, 直接下载下载自己编译.&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;安装jpeg和png解码库&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;yum install libjpeg-devel libpng-devel&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;作者用的ImageMagick是6.5版本, 可能会编译失败, 这里下载&lt;strong&gt;最新版&lt;/strong&gt;(目前是6.9).&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;wget "http://www.imagemagick.org/download/ImageMagick.tar.gz"
tar zxf ImageMagick.tar.gz
cd ImageMagick-*

ln -s /usr/include/freetype2/freetype /usr/include/freetype
export CPPFLAGS="-I/usr/include/freetype2 -I/usr/local/include"
export LDFLAGS="-L/usr/local/lib"
mkdir -p /effect/fonts

./configure --prefix=/effect/magick --enable-lzw --without-threads --without-magick-plus-plus --with-perl=perl --with-fontpath=/effect/fonts --without-x --with-quantum-depth=8 --enable-shared=yes --enable-static=no

make
make install&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;添加库到系统&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;echo "/effect/magick/lib" &amp;gt; /etc/ld.so.conf.d/imagemagick.conf&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;重新加载配置&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;/sbin/ldconfig -v&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;测试是否已正常安装&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;perl -MImage::Magick -e ';'&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;没有出错就安装OK, 注意, 这里是没有什么显示&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;创建个软链&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;mkdir -p /opt/local/bin
ln -s /effect/magick/bin/convert /opt/local/bin/convert&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;&lt;h2 id="toc_6" class="h16"&gt;安装音视频模块 MPG123 and OGG Encoder&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;安装 MPG&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;wget "http://www.effectgames.com/install/mpg123-1.10.0.tar.bz2"
tar jxf mpg123-1.10.0.tar.bz2
cd mpg123-*
./configure
make
make install&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;安装 OGG&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;yum install libvorbis libvorbis-devel vorbis-tools&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;检查下面文件在不在, 有就安装正确了&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;ls /usr/local/bin/mpg123 /usr/bin/oggenc&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;&lt;h2 id="toc_7" class="h16"&gt;安装 Apache&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;先安装或更新一下openssl&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;yum install openssl&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;Apache也有很多安装选项, 自己下载来编译&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;wget "http://www.effectgames.com/install/httpd-2.2.14.tar.bz2"
tar jxf httpd-2.2.14.tar.bz2
cd httpd-*

./configure --prefix=/effect/apache --with-mpm=prefork --with-ssl=openssl --with-perl=perl --enable-so --enable-expires --enable-headers --enable-mime-magic --enable-rewrite --enable-ssl --enable-mods-shared="all authn_file authn_default authz_host authz_groupfile authz_user authz_default auth_basic include filter log_config env setenvif mime status autoindex asis cgi negotiation dir actions userdir alias expires headers ssl rewrite"

make
make install&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;之后Apache会安装到 &lt;code&gt;/effect/apache&lt;/code&gt;&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;安装 mod_perl 模块, 有些系统会缺少 perl 的一些依赖, 先用 yum 安装依赖, 然后安装最新版的 mod_perl ( 目前是2.0.9 )&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;yum install perl-ExtUtils-Embed

wget "http://mirror.bit.edu.cn/apache/perl/mod_perl-2.0.9.tar.gz"
tar zxf mod_perl-*.tar.gz
cd mod_perl-*
perl Makefile.PL MP_AP_PREFIX=/effect/apache
make
make install&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;在执行&lt;code&gt;perl Makefile.PL MP_AP_PREFIX=/effect/apache&lt;/code&gt; 时可能会报错&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;[  error] '/effect/apache/bin/apxs -q NOTEST_CPPFLAGS' failed:
[  error] Use of assignment to $[ is deprecated at /effect/apache/bin/apxs line 86.&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;问题原因是新版本的perl里面, &lt;code&gt;[&lt;/code&gt; 不能用于变量名了, 修改 /effect/apache/bin/apxs 源码, 把&lt;code&gt;$[&lt;/code&gt; 替换成 &lt;code&gt;$a&lt;/code&gt;(vi 中可以用 &lt;code&gt;%s/$\[/\$a/g&lt;/code&gt; 命令全局替换), 保存并重新执行 &lt;code&gt;perl Makefile.PL MP_AP_PREFIX=/effect/apache&lt;/code&gt;&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;增加www用户组和用户&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;/usr/sbin/groupadd www
/usr/sbin/useradd -m -g www www&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;替换配置文件, 直接用作者的配置&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;wget "http://www.effectgames.com/install/httpd.conf"
mv /effect/apache/conf/httpd.conf /effect/apache/conf/httpd.conf.bak
mv httpd.conf /effect/apache/conf/&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;&lt;h2 id="toc_8" class="h16"&gt;配置项目&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;先下载项目代码下来&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;wget "https://github.com/jhuckaby/Effect-Games/tarball/master"
tar zxf jhuckaby-Effect-Games-*.tar.gz
rm jhuckaby-Effect-Games-*.tar.gz
mv jhuckaby-Effect-Games-*/* /effect
ln -s /effect/htdocs /effect/apache/htdocs/effect&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;做一些必要配置如域名等, 具体项直接参照 &lt;a class="md_compiled" href="https://github.com/jhuckaby/Effect-Games/wiki/Installation-Guide"&gt;安装文档&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;Effect Game的主要配置文件在 &lt;code&gt;/effect/conf/Effect.xml&lt;/code&gt;, 基本上都不需要修改&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;启动测试一下是否正常&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;/effect/apache/bin/apachectl start
/effect/apache/bin/apachectl stop&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;&lt;h2 id="toc_9" class="h16"&gt;初始化各种环境&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;创建数据存储目录和配置权限&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;mkdir -p /data/effect/storage
chown www:www /data/effect/storage

mkdir -p /data/effect/cleanup
chown www:www /data/effect/cleanup&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;创建日志的目录&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;mkdir -p /logs/effect
chmod 777 /logs/effect

mkdir -p /logs/apache
chmod 777 /logs/apache&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;创建初始数据, 执行这个脚本就行, 数据的配置在 &lt;code&gt;/effect/conf/initial_data_setup.xml&lt;/code&gt;&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;/effect/bin/setup_db.pl&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;启动图片服务进程, Effect Game是使用了个后台进程来优化图片, 配置文件在 &lt;code&gt;/effect/conf/image_service.xml&lt;/code&gt;, 用下面的命令启动&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;mkdir -p /data/effect/queue
chmod 777 /data/effect/queue

/effect/bin/imageservicectl.sh start
/effect/bin/imageservicectl.sh stop&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;配置定时任务, 这个任务用来处理日志文件和数据文件, 命令行敲入 &lt;code&gt;crontab -e&lt;/code&gt;, 输入&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;00 * * * * /effect/bin/maint.pl hourly
30 00 * * * /effect/bin/maint.pl daily&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;定时任务的log输出在 &lt;code&gt;/logs/effect/maint.log&lt;/code&gt;&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;过时的日志文件会被打包存储, 默认配置下存在 &lt;code&gt;/backup/effect/logs/CATEGORY/YYYY/MM/DD/HH.gz&lt;/code&gt;, 路径可以在 &lt;code&gt;/effect/conf/Effect.xml&lt;/code&gt; 中修改&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;创建备份目录&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;mkdir -p /backup/effect
chmod 777 /backup/effect&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;&lt;h2 id="toc_10" class="h16"&gt;All Done&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;现在可以启动 Effect Game 啦&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;/effect/bin/imageservicectl.sh start
/effect/apache/bin/apachectl start&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;然后访问 &lt;code&gt;http://127.0.0.1/effect/&lt;/code&gt;, 默认用户名和密码都是 &lt;code&gt;admin&lt;/code&gt;&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;如果要配置域名, 可以在 &lt;code&gt;/effect/apache/conf/httpd.conf&lt;/code&gt; 中修改 &lt;code&gt;ServerName&lt;/code&gt; &lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;So, enjoy it!&lt;/span&gt;
&lt;/p&gt;</summary>

  </entry>


  <entry>


    <title>谈前端工程师的职业规划</title>

    <link href="http://imatlas.com/post/talk-about-the-front-end-engineering-career-planning"  rel="alternate"></link>

    <updated>2015-04-17T08:57:50Z</updated>
    <id>talk-about-the-front-end-engineering-career-planning</id>

    <author>
      <name>iAzrael</name>

    </author>
    <summary type="html">&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;在敲下这个标题的时候，心里好虚。话说我一直不太喜欢发表这些看上去很假大空的文字，每个人的职业规划都是独有的，不具有太大的可复制性，把自己的经历放出去，容易误人子弟。只是最近很多师弟们（别问我为什么都是师弟，我想静静……也不要问我静静是谁！）问起这个，也就根据自己的经历发表一下对前端工程师的看法吧，“我说的都是错的”，仅供参考。另：本篇是纯文字，密集恐惧症换成勿入！&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;从我接收第一份前端需求开始，到现在也有五个年头了。自己也从一个愣头青变成一个快到而立之年的大叔，时间真的是哗啦哗啦的快。这五年里，其实可以分成三部分：1~2, 3~4, 5。more&lt;/span&gt;
&lt;/p&gt;

&lt;h2 id="toc_0" class="h16"&gt;1~2 吸吸吸，疯狂的吸取知识&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;刚毕业时满腔热情，一门心思只往前端事业发展。刚从学校出来，看到什么都是新鲜十足，什么都想学。不断的买书看书垫枕头，最疯狂的时候一个礼拜晚上看完正本犀牛书+做笔记，后来再也达不到这种速度了。很幸运我能加入到AlloyTeam，依靠WebQQ，使得我的编码能力、项目经验duang duang duang的上去了。同时也搞了很多奇形怪状的业余项目，基本上无论遇到什么跟JS相关的“新”技术（新是对于我自己来说的），我都想去尝一尝。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;对于刚毕业的初学者来说，头两年真的真的是非常重要，学习的激情、速度以及熬夜的能力可以发挥的淋漓尽致。在这个阶段，通过大量的编码提升JS能力，同时尝试各种JS框架和库，寻找适合自己的框架，甚至自己也写了一个JS库和构建工具。“不要重复的造轮子”这句话，初学者都应该无视。你不造轮子，怎么知道别的轮子好不好用？怎么知道造一个轮子有多难？怎么知道如何改进轮子？我不认为一个新手去看jQuery的源码能看懂，反正我当时就晕晕乎乎的。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;在这个时间点里，其实还没怎么考虑以后的发展，而且也仅认为前端工程师，学好JS/CSS/HTML就够了，其他的没兴趣也没意愿去学。&lt;/span&gt;
&lt;/p&gt;

&lt;h2 id="toc_1" class="h16"&gt;3~4 大大大，扩展知识面&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;在JS/CSS/HTML里探索了2年后，突然发现越学越不懂了。出了HTML5，看了WebSocket，想学会，结果要看网络协议、要看HTTP/TCP，还要学Server开发等。顿时感觉分身10个也不一定能学好。为了跟上潮流，也得硬着头皮上。好不容易Server、网络、前端、浏览器各种知识都多少了解的时候，移动潮流来了！OMG，Android、iOS还有WP……生命不止，学习不休。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;其实到了这个阶段，多少也算是个有经验的攻城师了。开发一般需求不在话下，偶尔还能承担个架构设计。在提升JS能力的同时，开始要往多方面发展。前端工程师远远不仅是JS而已。制作一个性能高、交互好、视觉美的页面，需要从前端框架选型、架构设计、构建工具，到后端通信机制、设计与交互、网络和浏览器优化等各方面的知识。一专多长才是前端工程师的终极目标。有个人说得对：一专是指你不可替代，多长标示你可以替代别人。这样你在团队在公司的地位才更加牢固，公司也会给你提供更多的资源。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;同时还要开始提升自己的名气，可以通过发表技术博客，提交和参与开源项目，做部门级公司级还有业界分享，参加业界会议等等。在这个信息瞬息万变的互联网时代，保持交流才会让自己不落伍。同时名气大了，能找到更多志同道合的人一起研究技术（探讨生命的起源也不是不可能的），甚至想跳槽，也是放个屁的事儿（意思是简单-_-|| 这都什么比喻）。&lt;/span&gt;
&lt;/p&gt;

&lt;h2 id="toc_2" class="h16"&gt;5~ 摸摸摸，摸清前方的路&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;这个时候，如无意外，你也应该成为高级工程师了。编码在工作中比例已经不算太高，更多的工作是承担技术评审、架构设计和项目管理等事情。工作中除了完成自己的事情，可能还需要指导新人，做新人培训，带领新人完成项目。同时还会有一个抉择摆在眼前：继续深入研究技术 or 往管理方向进发。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;技术 or 管理，这里没有对错之分，只有合不合适。有的人就不善于交流，同时喜欢专研，可以继续走技术的路，发展成专家；有的人则可能有比较强的领导力，可以带领一群人完成项目，那可以转向管理，成为Team Leader等。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;不管选哪个方向，你都已经是个优秀的人，而且应该把这种优秀传承下去。成为导师，使新人变得优秀；成为面试官，挖掘优秀的人；成为讲师，让更多人学习到优秀，等等。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;总的来说，头两年一定要打好基础，找准自己的G点，深攻下去；高潮之后，往广度发展，掌握其他相关和不相关的配套知识（这不是矛盾么？Σ( ° △ °|||)︴）；然后摸到自己的目标，发售大胆的爱爱（老了，手抖打多了）吧。不仅自己爱（前端），也要让更多人一起爱（前端）哦。&lt;/span&gt;
&lt;/p&gt;</summary>

  </entry>


  <entry>


    <title>在浏览器端用JS创建和下载文件</title>

    <link href="http://imatlas.com/post/download-file-with-js"  rel="alternate"></link>

    <updated>2014-01-02T15:31:00Z</updated>
    <id>download-file-with-js</id>

    <author>
      <name>iAzrael</name>

    </author>
    <summary type="html">&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;前端很多项目中，都有文件下载的需求，特别是JS生成文件内容，然后让浏览器执行下载操作（例如在线图片编辑、在线代码编辑、&lt;a class="md_compiled" href="http://www.ipresst.com"&gt;iPresst&lt;/a&gt;等）。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;但受限于浏览器，很多情况下我们都只能给出个链接，让用户点击打开-》另存为。如下面这个链接：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_html  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;file.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;file.js&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;用户点击这个链接的时候，浏览器会打开并显示链接指向的文件内容，显然，这并没有实现我们的需求。more&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;HTML5中给a标签增加了一个download属性，只要有这个属性，点击这个链接时浏览器就不在打开链接指向的文件，而是改为下载（目前只有chrome、firefox和opera支持）。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_start md_line_end"&gt;&lt;a class="md_compiled" href="/uploads/2014-01-01/QQ20140102-2.png"&gt;&lt;img class="md_compiled " src="/uploads/2014-01-01/QQ20140102-2.png" alt="" title="" &gt;&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;下载时会直接使用链接的名字来作为文件名，但是是可以改的，只要给download加上想要的文件名即可，如：download=“not-a-file.js”。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_dom_embed md_line_start md_line_end"&gt;&lt;a class="md_compiled" href="/uploads/2014-01-01/QQ20140102-3.png"&gt;&lt;img class="md_compiled " src="/uploads/2014-01-01/QQ20140102-3.png" alt="" title="" &gt;&lt;/a&gt;&lt;/span&gt;
&lt;/p&gt;

&lt;h2 id="toc_0" class="h16"&gt;Not enough！&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;但是这样还不够，以上的方法只适合用在文件是在服务器上的情况。如果在浏览器端js生成的内容，想让浏览器进行下载要如何办到呢？&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;其实还是有办法办到的，相信很多人都多少听过了DataURI这个词，比较常见的就是图片的src，如：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_html  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;`data:image/gif;base64,R0lGOXXXXX&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;`
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;DataURI的解释可以移步&lt;a class="md_compiled" href="http://sjolzy.cn/What-is-the-data-URI-scheme-and-how-to-use-the-data-URI-scheme.html"&gt;这里&lt;/a&gt;，本人就不在解释了。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;那么，现在要将js生成的内容进行下载就有法可依了。封装成一个方法如下：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_js  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;downloadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aLink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;aLink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;download&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;aLink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;data:text/plain,&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;调用downloadFile之后，用户点击链接，就能触发浏览器下载。&lt;/span&gt;
&lt;/p&gt;

&lt;h2 id="toc_1" class="h16"&gt;Not enough！&lt;/h2&gt;
&lt;p class="md_block md_block_as_opening md_has_block_below md_has_block_below_ol"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;但是，还不够，上面的办法有两个硬伤，会导致流失很多懒人美眉：&lt;/span&gt;
&lt;/p&gt;


&lt;ol&gt;
&lt;li class="md_li"&gt;&lt;span&gt; 下载的文件类型限制死了，美眉要下载处理后的果照怎么办？
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt; 下载还要再点击一下，太麻烦啦。
&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;要解决文件类型的问题，可以用浏览器的新API（&lt;a class="md_compiled" href="https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL"&gt;URL.createObjectURL&lt;/a&gt;）来解决问题，URL.createObjectURL通常都是用来创建图片的DataURI用来显示图片，这里用来下载文件，让浏览器来帮我们设定好文件类型。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;URL.createObjectURL的参数是File对象或者Blob对象，File对象也就是通过input[type=file]选择的文件，Blob对象是二进制大对象，详细说明可参考&lt;a class="md_compiled" href="https://developer.mozilla.org/en-US/docs/Web/API/Blob"&gt;这里&lt;/a&gt;。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;现在，我们只要用content创建一个ObjectURL并赋值给aLink即可解决文件类型的限制问题。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;文件的自动下载也挺好办，自己构建一个UI点击事件，再自动触发下，就能实现自动下载啦。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;现在来看看最终代码：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_js  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;downloadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;aLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;evt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;HTMLEvents&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;click&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;aLink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;download&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;aLink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;aLink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;现在，只要一调用downloadFile，文件就自动下载了，是不是很爽咧，^_^。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;&lt;strong&gt;注：&lt;/strong&gt;目前（2014-01-02）Blob和URL.createObjectURL在标准浏览器里面都不再需要加私有前缀，可以放心使用啦啦啦～～如果你不放心，可以查查&lt;a class="md_compiled" href="http://caniuse.com/#search=Blob"&gt;Can I Use&lt;/a&gt;。&lt;/span&gt;
&lt;/p&gt;</summary>

  </entry>


  <entry>


    <title>千方百计加速Web之加速DNS解析</title>

    <link href="http://imatlas.com/post/make-dns-resolve-fast-than-web-fast"  rel="alternate"></link>

    <updated>2013-10-30T07:54:00Z</updated>
    <id>make-dns-resolve-fast-than-web-fast</id>

    <author>
      <name>iAzrael</name>

    </author>
    <summary type="html">&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;通常情况下，做移动开发时，如果要向后台请求数据，都会直接使用TCP通信。但实际上一来HTTP比TCP简单易用多了，二来有很多现有CGI如果要进行改造得花很大功夫。还是会有使用HTTP请求来拉取数据。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block md_block_as_opening md_has_block_below md_has_block_below_ol"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;在做Android QQ二维码时，扫描到二维码字符串，就是把该字符串用HTTP传给后台，后台解析后返回给客户端，客户端再进行下一步处理。在提交测试后，测试同事发现，在移动网络上，DNS解析会经常失败，导致二维码扫描功能不可用。功能测试不通过，导致无法发布。同时测试喜欢在清空DNS缓存和屏蔽了DNS解析的情况下，二维码解析功能仍然可用。因此这里增加了如下处理：&lt;/span&gt;
&lt;/p&gt;


&lt;ol&gt;
&lt;li class="md_li"&gt;&lt;span&gt; 进入“扫一扫”的界面时，客户端就开始对CGI所在域名进行解析，并把解析结果缓存到本地文件；
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt; 发起CGI请求时，还是使用原域名进行请求，如果DNS解析失败，则用第一步缓存的IP替换掉CGI中的域名再发起一次请求。
&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start"&gt;由于国内有好几个网络运营商，公司在不同的网络环境都有不一样的出口IP，因此选择最近的IP才能快速访问CGI。所以缓存域名结果时，需要区分网络分别保存。&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line"&gt;more&lt;br /&gt;&lt;/span&gt;
    &lt;span class="md_line md_line_end"&gt;这样，当用户的手机上至少成功使用了一次二维码扫描时，CGI对应的IP就保存下来了（至少有一个出口IP）。下次访问（同一次登录或者关闭手机QQ后再打开）时，即使DNS解析失败，还是能使用上一次保存的IP进行访问，可能会相应比较慢（用户从A网络切换到了B网络），但起码保证了功能的可用性。实现起来也不难，Java都有现成的接口了。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;主动发起DNS解析只要调用InetAddress的接口即可，把获取到的结果保存到SharedPreferences供下次使用：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_java  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;lookupIP&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
     &lt;span class="n"&gt;SharedPreferences&lt;/span&gt; &lt;span class="n"&gt;preferences&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSharedPreferences&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;host&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
     &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
     &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;InetAddress&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;InetAddress&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getByName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
          &lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getHostAddress&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
          &lt;span class="n"&gt;SharedPreferences&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Editor&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;preferences&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;edit&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
          &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;putString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
          &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;commit&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
          &lt;span class="n"&gt;QLog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;d&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TAG&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;lookup address: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;, ip: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
     &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UnknownHostException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
     &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;然后在HTTP请求出现DNS解析错误的时候，用IP替换掉URL中的域名即可：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_java  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
     &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IOException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
     &lt;span class="c1"&gt;//DNS错误改用ip重新发一次&lt;/span&gt;
     &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getIP&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
     &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
          &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
     &lt;span class="o"&gt;}&lt;/span&gt;
     &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;这里之所以不直接用上次保存的IP来替换域名进行访问，是因为在正常情况下，进入“扫一扫”的界面时，已经预先对所用域名进行了预解析，如果解析成功，调用openRequest时就不用DNS查询了；而如果预解析失败了，openRequest的时候还能再尝试一次，失败时才使用IP访问。同时，很多用户都会在移动网络和WIFI网络中切换，如果直接用IP替换域名，会出现用户当前是移动网络，而是用的域名IP是在教育网IP（上一次使用的是教育网WIFI）的情况，导致CGI响应变得更慢。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;当然，更好的解决方法是：先检测当前用户的网络环境，如果本地保存了对应网络的IP，直接使用IP请求；如果没有，再改用域名来请求。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;还有更进阶的方案：第一次登陆时，从服务器拉取一份host列表（每个域名包括各个网络环境的出口IP），把所有HTTP请求的域名都替换成相应IP，这样就能完美解决DNS不可用、DNS解析失败的情况了。之后维护host文件的更新即可。&lt;/span&gt;
&lt;/p&gt;</summary>

  </entry>


  <entry>


    <title>【代码分享】根据类型智能提取参数</title>

    <link href="http://imatlas.com/post/get-arguments-by-type"  rel="alternate"></link>

    <updated>2013-09-10T09:39:00Z</updated>
    <id>get-arguments-by-type</id>

    <author>
      <name>iAzrael</name>

    </author>
    <summary type="html">&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;如果你是个Javascript程序员，那一定经常写下面的代码：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_js  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;funcA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="c1"&gt;//funcA(url, callback);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;function&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
            &lt;span class="nx"&gt;callback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;//funcA(url, params);&lt;/span&gt;
            &lt;span class="c1"&gt;//......&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//......&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;当参数变化形式比较少的时候还没问题，当你的方法想对多种传参形式进行容错时，一堆的if else判断就变得很难看了。这时不妨尝试下这个 getArguments 方法。more&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_js  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;toString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;getArguments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;argus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type3&lt;/span&gt; &lt;span class="cm"&gt;/*...*/&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;srcTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;targetTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;argus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;srcTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;argus&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;targetTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;srcTypes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;targetTypes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]){&lt;/span&gt;
            &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;argus&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
            &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;使用方法如下：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_js  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;funcB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;option&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;argus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;String&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Object&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Function&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Object&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;argus&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;argus&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;argus&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;option&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;argus&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;argus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;运行结果如下：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_js  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;funcB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){})&lt;/span&gt;
&lt;span class="c1"&gt;//console: [&amp;quot;a&amp;quot;, null, function, null]&lt;/span&gt;
&lt;span class="nx"&gt;funcB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;//console: [&amp;quot;a&amp;quot;, null, function, Object]&lt;/span&gt;
&lt;span class="nx"&gt;funcB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;//console: [&amp;quot;a&amp;quot;, Object, null, null]&lt;/span&gt;
&lt;span class="nx"&gt;funcB&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;//console: [null, Object, null, null]&lt;/span&gt;
&lt;span class="nx"&gt;funcB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){})&lt;/span&gt;
&lt;span class="c1"&gt;//console: [null, null, function, null]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;怎么样，是不是简单很多咧？^_^&lt;/span&gt;
&lt;/p&gt;</summary>

  </entry>


  <entry>


    <title>Compiler@NodeJS（三）- 自定义命令</title>

    <link href="http://imatlas.com/post/nodejs-compiler-custom-cmd"  rel="alternate"></link>

    <updated>2013-03-20T15:11:00Z</updated>
    <id>nodejs-compiler-custom-cmd</id>

    <author>
      <name>iAzrael</name>

    </author>
    <summary type="html">&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;_接上篇：&lt;a class="md_compiled" href="/nodejs-compiler-pipe/" title="Compiler@NodeJS（二）- 强大的管道"&gt;Compiler@NodeJS（二）- 强大的管道&lt;/a&gt;_&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;本来早就应该写这篇文章的，只是忙的时候忙，闲的时候懒，导致拖了这么久。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;不管内置多少命令，需求总是千变万化的，这时候内置命令就不够用了，需要使用者自己编写一些命令。现在来看看怎么做。more&lt;/span&gt;
&lt;/p&gt;

&lt;h2 id="toc_0" class="h16"&gt;一、内置命令&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;先来看看内置命令的文件结构是怎样的：&lt;/span&gt;
&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;+--- compiler
    +--- cmds
        +--- copy
        +--- concat
            --- index.js
            --- README.md&lt;/code&gt;&lt;/pre&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;每个命令都是cmds下面的一个单独目录，如copy、concat等等。每个命令下面都必须有一个index.js文件，作为这个命令的入口。index.js需要export一个属性（async）和一个方法（execute)，这里拿concat命令来说明，如下：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_js  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;fs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;path&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//指示该命令是异步执行的，默认为false，命令结束后会自动调用 nextTask；&lt;/span&gt;
&lt;span class="c1"&gt;//如果为true，则需在本命令执行完成之后主动调用 nextTask&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;async&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//命令的入口函数&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;execute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;compileConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;runOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nextTask&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;//省略……&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;当concat命令被调用的时候，compiler会找到concat目录下的index.js，require之后执行它的execute方法，execute的参数说明如下：&lt;/span&gt;
&lt;/p&gt;


&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;参数名&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;task&lt;/td&gt;
&lt;td&gt;Object，这次命令调用要执行的任务，一个task包括任务id、任务要执行的命令（cmd）、任务的输入（source）、任务执行的输出目录（target）、任务的参数（params，也就是在config.json中配置的对应的params，比如下面示例代码中的custA_html中的params）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;compileConfig&lt;/td&gt;
&lt;td&gt;Object，执行compiler时传入的配置，也就是config.json内容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;runOptions&lt;/td&gt;
&lt;td&gt;Object，执行该任务时的运行时信息，包括compiler的目录、命令的目录（concat的绝对路径）、命令的文件名（index.js的目录+名字）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nextTask&lt;/td&gt;
&lt;td&gt;Function，告诉compiler继续执行下一个命令，在设置了exports.async=true时，需要该命令主动调用，如：nextTask()。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="toc_1" class="h16"&gt;二、自定义命令&lt;/h2&gt;
&lt;p class="md_block md_block_as_opening md_has_block_below md_has_block_below_ol"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;自定义命令的写法很简单：&lt;/span&gt;
&lt;/p&gt;


&lt;ol&gt;
&lt;li class="md_li"&gt;&lt;span&gt; 只要建立一个目录，比如custA（这里我放到了项目根目录下的custom_cmds），创建index.js文件，并提供execute方法；
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt; 在config.json中配置该命令，让compiler知道哪里可以找到该命令。
&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;有了自定义命令的config.json的样子应该是类似这样的：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_json  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;quot;sourceRoot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;./&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;quot;targetRoot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;./build&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;quot;fileFormat&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;js,css,html,htm,png,gif,jpg,jpeg,wav,json&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;quot;cmds&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;custA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;//配置自定义命令&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;custA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;./custom_cmds/custA/&amp;quot;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;quot;rules&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;custA_html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;cmd&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;custA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;//使用自定义命令&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;target&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;./&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;source&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;./&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;params&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
                 &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;如代码所示，只要在cmds项中，添加一个custA的json描述，给出id和根目录（root），其他事情就不用管了。&lt;/span&gt;
&lt;/p&gt;

&lt;h2 id="toc_2" class="h16"&gt;三、组合命令&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;在&lt;a class="md_compiled" href="/nodejs-compiler-pipe/" title="Compiler@NodeJS（二）- 强大的管道"&gt;上一篇&lt;/a&gt;讲到，compiler最强大的是管道特性，可以用来将命令串联组合。有时候，一些任务可能需要很多个命令来组合完成，但是在每个rule里面写又不是很方便。这时候可以使用自定义命令的另外一种形式，组合命令。使用很简单，只要在config.json配置就行。&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_json  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;quot;sourceRoot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;./&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;quot;targetRoot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;./build&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;quot;fileFormat&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;js,css,html,htm,png,gif,jpg,jpeg,wav,json&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;quot;cmds&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;custB&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;translate|copy,compress&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;custC&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;custB|ispriter&amp;quot;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;quot;rules&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;translate_html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;cmd&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;custB&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;parmas&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;/*..*/&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="err"&gt;｝&lt;/span&gt;
    &lt;span class="err"&gt;｝&lt;/span&gt;
&lt;span class="err"&gt;｝&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;其实组合命令就是把原有命令串、并联在一起，方便之后使用，同时组合命令还能再次被组合，是不是很神奇咧？哈哈。命令的组合原则可以看&lt;a class="md_compiled" href="/nodejs-compiler-pipe/"&gt;上一篇&lt;/a&gt;介绍。不过有点需要注意的，在使用组合命令时，传入的params需要一一对应，比较不顺手。如果是多次组合过的命令，params将变得更加复杂，不过暂时只能这样了。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;嗯，到这里，自定义命令的教程就结束了。如果你还是不太明白，可以到&lt;a class="md_compiled" href="https://github.com/iazrael/compiler"&gt;github&lt;/a&gt;中查看内置命令的实现，如：&lt;a class="md_compiled" href="https://github.com/iazrael/compiler/blob/master/cmds/template-picker/index.js"&gt;template-picker&lt;/a&gt;、&lt;a class="md_compiled" href="https://github.com/iazrael/compiler/blob/master/cmds/ioffline/index.js"&gt;ioffline&lt;/a&gt;、&lt;a class="md_compiled" href="https://github.com/iazrael/compiler/blob/master/cmds/concat/index.js"&gt;concat&lt;/a&gt;、&lt;a class="md_compiled" href="https://github.com/iazrael/compiler/blob/master/cmds/copy/index.js"&gt;copy&lt;/a&gt;等等，毕竟千言万语不及代码两行嘛，哈哈。有任何问题也可在本文留言，或者邮件给我，欢迎试用，^_^。&lt;/span&gt;
&lt;/p&gt;</summary>

  </entry>


  <entry>


    <title>让Java跟Javascript更加亲密</title>

    <link href="http://imatlas.com/post/make-java-communicate-with-javascript-easily"  rel="alternate"></link>

    <updated>2013-02-19T08:28:00Z</updated>
    <id>make-java-communicate-with-javascript-easily</id>

    <author>
      <name>iAzrael</name>

    </author>
    <summary type="html">&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;在移动App开发中，为了快速迭代，通常都会使用Native+Web的模式开发。具体来说就是使用Java提供接口，使用WebView控件嵌套Web页面来实现UI和交互。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;在Android中，Java可以很方便的提供接口给WebView中的Js进行调用，只要以下一行代码就能搞定：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_java  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;mWebView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addJavascriptInterface&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JavascriptInterface&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;custom_name&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;这样，JavascriptInterface的所有声明为public的方法，都能被mWebView中的Js通过以下方式调用：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_javascript  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;custom_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;xxx&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="c1"&gt;//xxx为JavascriptInterface的公有方法&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;而Java需要调用Js时，则是通过WebView实例的loadUrl方法调用：&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_java  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;mWebView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;javascript:xxx(yyy)&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;这其实跟你在浏览器的地址栏敲下“&lt;code&gt;javascript：alert（1）&lt;/code&gt;”的原理是一样的。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;一切看起来都是那么的美好，只是……&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;当Java需要传递大量字符串给Js时，URL就力不从心了。另外，从URL执行的Js，在页面没加载完成时，是有可能导致页面出现undefined错误（因为要执行的那个方法可能还没有声明呢），会引发各种奇形怪状的错误。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;more&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;那要怎么办呢？&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;再回看上面Js调用Java接口的地方，可以发现，Js是可以直接调用Java方法并取得Java给的返回值的（必须是可序列化的数据）。那么，为何不试试把Java需要执行的Js方法，保存起来，让Js来读取、执行、并把结果写回？&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block md_block_as_opening md_has_block_below md_has_block_below_ol"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;步骤如下：&lt;/span&gt;
&lt;/p&gt;


&lt;ol&gt;
&lt;li class="md_li"&gt;&lt;span&gt; Java把Js调用（命令）和回调缓存，如保存到ArrayList；
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt; Js定时轮询Java提供的getCommandList接口；
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt; Js读取到要执行命令，执行它，并把结果通过setResult写回给Java；
&lt;/span&gt;&lt;/li&gt;
&lt;li class="md_li"&gt;&lt;span&gt; Java把对应命令的回调取出并执行。
&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;如此即完成了Java调用Js的流程。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;为了方便使用，简单的封装了下，名为&lt;a class="md_compiled" href="https://github.com/iazrael/AndroidJavascriptBridge"&gt;AndroidJavascriptBridge&lt;/a&gt;，可移步到&lt;a class="md_compiled" href="https://github.com/iazrael/AndroidJavascriptBridge"&gt;Github&lt;/a&gt;查看源码和示例（MainActivity.java和test.js ）。&lt;/span&gt;
&lt;/p&gt;

&lt;h2 id="toc_0" class="h16"&gt;使用方法&lt;/h2&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;Android端调用, 加入com.imatlas.jsb 和 com.imatlas.util包, 按如下步骤调用&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_java  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;//1. 创建JavascriptBridge实例  &lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;JavascriptBridge&lt;/span&gt; &lt;span class="n"&gt;jsb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JavascriptBridge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webView&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 

&lt;span class="c1"&gt;//2. 调用Javascript方法&lt;/span&gt;
&lt;span class="n"&gt;Bundle&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Bundle&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;putString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;asdfasdf&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;123123&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;jsb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;require&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;alert&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JavascriptBridge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Callback&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onComplate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JSONObject&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Bundle&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;js response&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;//3. 提供Java方法给Javascript调用&lt;/span&gt;
&lt;span class="c1"&gt;//添加个 messagebox 方法给js&lt;/span&gt;
&lt;span class="n"&gt;jsb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addJavaMethod&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;messagebox&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JavascriptBridge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Function&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JSONObject&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Toast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;makeText&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getApplicationContext&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Toast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LENGTH_LONG&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;show&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;{\&amp;quot;ret\&amp;quot;:123}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;Javascript端的调用, 须先引入web/js/jsb.js, 之后按如下方式调用&lt;/span&gt;
&lt;/p&gt;

&lt;div class="codehilite code_lang_javascript  highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;//1. 调用Java方法&lt;/span&gt;
&lt;span class="nx"&gt;jsb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;messagebox&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;你好, messagebox!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;调用messagebox回来啦\n&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;//2. 提供Javascript方法给Java调用&lt;/span&gt;
&lt;span class="nx"&gt;jsb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addJavascriptMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;alert&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;------\n&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;\n========\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;alert ok&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;!--block_code_end--&gt;
&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;IOS的话就要反过来了，要改成由Objective-C来轮询Js，来实现Js对Native的调用。&lt;/span&gt;
&lt;/p&gt;


&lt;p class="md_block"&gt;
    &lt;span class="md_line md_line_start md_line_end"&gt;嗯，等改天有时间了，就把IOS也封装进来，用起来就简单多了。&lt;/span&gt;
&lt;/p&gt;</summary>

  </entry>


</feed>