前言

我本地是一台 Windows 11 的 ThinkPad T480,开发环境运行在一台 Linux 服务器上,基于 SSH 的方式进行访问和控制。我希望在 Linux 服务器的 Vim 中,通过 y 复制代码到本地 Windows 11 的剪切板内,通过 p 将本地 Windows 11 剪切板中最新的内容黏贴到服务器的 vim 内。本文将提供一种低成本的解决方案。

思路

Windows 的 WSL 支持直接运行 Linux X11 GUI 程序,并且在 Linux X11 GUI 中,是可以直接访问 Windows 本地的剪切板的。这意味着在 WSL 内,我们可以通过 SSH 的 X11Forward 将远端的 X11 转发到 WSL 内,这样 Linux 服务器上的 X11 GUI 程序就可以经 WSL 中转,访问 Windows 11 本地的剪切板了。

因此,我们只需:

  1. 基于 WSL 来登录 Linux 服务器
  2. 开启 SSH 的 X11Forward
  3. 将 Linux 服务器的 Vim 包用 GVim 包替换

即可。

效果如下:

参考配置

下面是我在 WSL 中的 SSH 客户端配置:

Host m7
User jinmiaoluo
HostName m7.jinmiaoluo.com
ForwardX11 yes
ForwardX11Trusted yes
RequestTTY force
RemoteCommand tmux -u new -A -s default -n default

下面是我在 Linux 服务器(也就是上面中的 m7.jinmiaoluo.com )上 X11 相关的 SSH 服务端配置:


# Part of the code has been omitted

X11Forwarding yes
X11UseLocalhost yes
AllowTcpForwarding yes

下面是我在 Windows Terminal 中的 Linux 服务器相关的启动命令:

C:\Windows\system32\wsl.exe -d Ubuntu ssh m7

如下图所示:

windows terminal m7 rofile

有了上面的配置,在 Windows Terminal 内就可以通过:ctrl+alt+<number> 这类快捷键快速的打开这台远程服务器。

windows terminal profile shortcut

当然,你也可以直接跟我一样,把这台服务器作为默认的 terminal profile,这样,一打开 Windows Terminal 就会自动连接这台服务器(或者通过 ctrl+shift+t 快速创建新的会话时也会基于默认的 profile)。

windows terminal default profile

我将 Vim 作为 man 的分页器,配置如下(添加到 ~/.bashrc):

# 通过 vim 来查看 man 文档
export MANPAGER="vim +MANPAGER --not-a-term -"

这样我就可以在 Vim 内浏览 man docs,并将 man 中的示例代码,通过 vim 的远程剪切板复制到 Windows 11 本地的剪切板内,最终的效果如下:

拓展

因为我们本质上是通过 X11Forward 打通了系统剪切板的同步,所以我们可以有很多拓展。

Tmux 整合

基于 Tmux 实现拷贝内容到本地 Windows 11 剪切板的全键盘操作。

VSCode 整合

实现 VSCode 内嵌 Terminal 拷贝内容到本地 Windows 11 剪切板的全键盘操作。

上面的解决方案,需要经过 WSL 进行中转,因此 VSCode Remote-SSH 这种不基于 WSL 的场景 X11Forward 会失效。我希望在 VSCode 内嵌的 Terminal 内,也能有 Tmux 拷贝内容的全键盘操作。

思路如下:

  1. 在 Windows 上单独跑一个 X11 环境,这里我选择的是 VcXsrv
  2. 通过 Windows 内置的 ssh.exe 将 X11 转发给本地的 VcXsrv

下面是我的 VSCode 相关的配置:

{
    "terminal.integrated.profiles.linux": {
        "tmux": {
            "path": "tmux",
            "icon": "terminal-tmux",
            "args": ["-u", "new", "-A", "-s", "${workspaceFolderBasename}", "-n", "default"]
        }
    },
    "terminal.integrated.defaultProfile.linux": "tmux"
}

VcXsrv 需要在 PowerShell 内添加一个环境变量才能实现 X11Forward:

# 通过:vim $PROFILE 来添加
$env:DISPLAY="127.0.0.1:0.0"

VSCode SSH 配置文件的配置如下:

Host m7
User jinmiaoluo
HostName m7.jinmiaoluo.com
ForwardX11 yes
ForwardX11Trusted yes
RequestTTY force
RemoteCommand tmux -u new -A -s default -n default

效果如下:

如果你遇到这样的报错:

vscode integrated terminal with tmux error

在你的 .tmux.conf 内添加如下配置:

# 兼容 vscode integrated terminal
set -ga update-environment 'VSCODE_GIT_ASKPASS_EXTRA_ARGS'
set -ga update-environment 'VSCODE_GIT_ASKPASS_NODE'
set -ga update-environment 'VSCODE_IPC_HOOK_CLI'
set -ga update-environment 'VSCODE_GIT_ASKPASS_MAIN'
set -ga update-environment 'VSCODE_GIT_IPC_HANDLE'
set -ga update-environment 'VSCODE_SHELL_INTEGRATION'

即可。

如果你希望避免 VSCode Debug Launch 功能误操作你的 Tmux,可以添加如下 VSCode 配置:

{
    // 省略了其他不相关的 VSCode 配置
    "terminal.integrated.automationProfile.linux": {
        "path": "/bin/bash",
        "icon": "debug",
    }
}

这样 Debug 操作的启动操作将会在独立的 Terminal 窗口内,而不是复用你的 Tmux 窗口。

Emacs 整合

其实就是把整个 Emacs GUI 跑在服务器上,通过 X11Forward 转发回本地。效果如下:

结束语

有段时间,我热衷于实现无图形界面的 Linux 远程开发环境(类似现在 GitPod 这类方案的完全命令行版本),当时解决远程剪切板的方案还是通过 Lemonade 配合 NeoVim 来实现。没想到几年后的今天,Windows 上已经可以不依赖任何服务即实现远程剪切板了。