├── .gitignore ├── go.mod ├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ └── release.yml ├── go.sum ├── LICENSE ├── .goreleaser.yml ├── main.go └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | shcopy 3 | manpages -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/aymanbagabas/shcopy 2 | 3 | go 1.19 4 | 5 | // replace github.com/aymanbagabas/go-osc52 => ../go-osc52 6 | 7 | require ( 8 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 9 | github.com/muesli/mango v0.2.0 10 | github.com/muesli/mango-pflag v0.2.0 11 | github.com/muesli/roff v0.1.0 12 | github.com/spf13/pflag v1.0.10 13 | ) 14 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gomod" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | labels: 8 | - "dependencies" 9 | commit-message: 10 | prefix: "feat" 11 | include: "scope" 12 | - package-ecosystem: "github-actions" 13 | directory: "/" 14 | schedule: 15 | interval: "daily" 16 | labels: 17 | - "dependencies" 18 | commit-message: 19 | prefix: "chore" 20 | include: "scope" 21 | - package-ecosystem: "docker" 22 | directory: "/" 23 | schedule: 24 | interval: "daily" 25 | labels: 26 | - "dependencies" 27 | commit-message: 28 | prefix: "feat" 29 | include: "scope" -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= 2 | github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= 3 | github.com/muesli/mango v0.2.0 h1:iNNc0c5VLQ6fsMgAqGQofByNUBH2Q2nEbD6TaI+5yyQ= 4 | github.com/muesli/mango v0.2.0/go.mod h1:5XFpbC8jY5UUv89YQciiXNlbi+iJgt29VDC5xbzrLL4= 5 | github.com/muesli/mango-pflag v0.2.0 h1:QViokgKDZQCzKhYe1zH8D+UlPJzBSGoP9yx0hBG0t5k= 6 | github.com/muesli/mango-pflag v0.2.0/go.mod h1:X9LT1p/pbGA1wjvEbtwnixujKErkP0jVmrxwrw3fL0Y= 7 | github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8= 8 | github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig= 9 | github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= 10 | github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 11 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | pull_request: 6 | branches: 7 | - master 8 | 9 | jobs: 10 | build: 11 | strategy: 12 | matrix: 13 | go-version: [^1] 14 | os: [ubuntu-latest, macos-latest, windows-latest] 15 | runs-on: ${{ matrix.os }} 16 | env: 17 | GO111MODULE: "on" 18 | steps: 19 | - name: Checkout code 20 | uses: actions/checkout@v6 21 | - name: Install Go 22 | uses: actions/setup-go@v6 23 | with: 24 | go-version: ${{ matrix.go-version }} 25 | - uses: actions/cache@v5 26 | with: 27 | path: ~/go/pkg/mod 28 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 29 | restore-keys: | 30 | ${{ runner.os }}-go- 31 | - name: Download Go modules 32 | run: go mod download 33 | - name: Build 34 | run: go build -v ./... 35 | - name: Test 36 | run: go test ./... 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Ayman Bagabas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | push: 5 | tags: 6 | - v*.*.* 7 | 8 | jobs: 9 | release: 10 | permissions: 11 | contents: write 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v6 15 | with: 16 | fetch-depth: 0 17 | - uses: actions/setup-go@v6 18 | with: 19 | go-version: ^1 20 | - uses: actions/cache@v5 21 | with: 22 | path: ~/go/pkg/mod 23 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 24 | restore-keys: | 25 | ${{ runner.os }}-go- 26 | - uses: docker/setup-qemu-action@v3 27 | - uses: docker/setup-buildx-action@v3 28 | - uses: goreleaser/goreleaser-action@v6 29 | with: 30 | version: latest 31 | distribution: goreleaser 32 | args: release 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }} 36 | SCOOP_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }} 37 | AUR_KEY: ${{ secrets.AUR_KEY }} 38 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json 2 | 3 | version: 2 4 | 5 | project_name: shcopy 6 | env: 7 | - GO111MODULE=on 8 | - CGO_ENABLED=0 9 | before: 10 | hooks: 11 | - go mod tidy 12 | - rm -rf manpages 13 | - mkdir manpages 14 | - sh -c 'go run . --man | gzip -c >./manpages/{{ .ProjectName }}.1.gz' 15 | builds: 16 | - ldflags: -s -w -X main.ProjectName={{ .ProjectName }} -X main.Version=v{{ .Version }} -X main.CommitSHA={{ .ShortCommit }} 17 | goos: 18 | - linux 19 | - darwin 20 | - windows 21 | - freebsd 22 | - openbsd 23 | - netbsd 24 | goarch: 25 | - amd64 26 | - arm64 27 | - "386" 28 | - arm 29 | - ppc64le 30 | - riscv64 31 | goarm: 32 | - "7" 33 | ignore: 34 | - goos: windows 35 | goarm: "7" 36 | 37 | archives: 38 | - format_overrides: 39 | - goos: windows 40 | format: zip 41 | name_template: >- 42 | {{ .ProjectName }}_ 43 | {{- .Version }}_ 44 | {{- title .Os }}_ 45 | {{- if eq .Arch "amd64" }}x86_64 46 | {{- else if eq .Arch "386" }}i386 47 | {{- else }}{{ .Arch }}{{ end }} 48 | {{- with .Arm}}v{{ . }}{{ end }} 49 | files: 50 | - README* 51 | - LICENSE* 52 | - manpages/* 53 | 54 | nix: 55 | - repository: 56 | owner: aymanbagabas 57 | name: nur 58 | homepage: "https://github.com/aymanbagabas/{{ .ProjectName }}" 59 | description: "Copy text to clipboard from anywhere using ANSI OSC 52 sequence" 60 | license: mit 61 | 62 | nfpms: 63 | - vendor: aymanbagabas 64 | homepage: "https://github.com/aymanbagabas/shcopy" 65 | maintainer: "Ayman Bagabas " 66 | description: "Copy text to clipboard from anywhere using ANSI OSC 52 sequence" 67 | license: MIT 68 | formats: 69 | - deb 70 | - rpm 71 | bindir: /usr/bin 72 | contents: 73 | - src: ./manpages/{{ .ProjectName }}.1.gz 74 | dst: /usr/share/man/man1/{{ .ProjectName }}.1.gz 75 | 76 | brews: 77 | - repository: 78 | owner: "aymanbagabas" 79 | name: homebrew-tap 80 | token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}" 81 | commit_author: 82 | name: "Ayman Bagabas" 83 | email: "ayman.bagabas@gmail.com" 84 | homepage: "https://github.com/aymanbagabas/shcopy" 85 | description: "Copy text to clipboard from anywhere using ANSI OSC 52 sequence" 86 | install: |- 87 | bin.install "{{ .ProjectName }}" 88 | man1.install "manpages/{{ .ProjectName }}.1.gz" 89 | 90 | aurs: 91 | - maintainers: ["Ayman Bagabas "] 92 | description: "Copy text to clipboard from anywhere using ANSI OSC 52 sequence" 93 | name: "{{ .ProjectName }}-bin" 94 | homepage: "https://github.com/aymanbagabas/shcopy" 95 | license: MIT 96 | private_key: "{{ .Env.AUR_KEY }}" 97 | git_url: "ssh://aur@aur.archlinux.org/{{ .ProjectName }}-bin.git" 98 | package: |- 99 | # bin 100 | install -Dm755 "./{{ .ProjectName }}" "${pkgdir}/usr/bin/{{ .ProjectName }}" 101 | # license 102 | mkdir -p "${pkgdir}/usr/share/licenses/{{ .ProjectName }}/" 103 | install -Dm644 ./LICENSE* "${pkgdir}/usr/share/licenses/{{ .ProjectName }}/" 104 | # man pages 105 | install -Dm644 "./manpages/{{ .ProjectName }}.1.gz" "${pkgdir}/usr/share/man/man1/{{ .ProjectName }}.1.gz" 106 | 107 | scoops: 108 | - repository: 109 | owner: aymanbagabas 110 | name: scoop-bucket 111 | token: "{{ .Env.SCOOP_TAP_GITHUB_TOKEN }}" 112 | commit_author: 113 | name: "Ayman Bagabas" 114 | email: "ayman.bagabas@gmail.com" 115 | homepage: "https://github.com/aymanbagabas/shcopy" 116 | description: "Copy text to clipboard from anywhere using ANSI OSC 52 sequence" 117 | license: MIT 118 | 119 | checksum: 120 | name_template: "checksums.txt" 121 | 122 | source: 123 | enabled: true 124 | 125 | snapshot: 126 | name_template: "{{ incpatch .Version }}-snapshot" 127 | 128 | changelog: 129 | sort: asc 130 | filters: 131 | exclude: 132 | - "^docs:" 133 | - "^test:" 134 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "log" 8 | "os" 9 | "strings" 10 | 11 | "github.com/aymanbagabas/go-osc52/v2" 12 | "github.com/muesli/mango" 13 | mpflag "github.com/muesli/mango-pflag" 14 | "github.com/muesli/roff" 15 | "github.com/spf13/pflag" 16 | ) 17 | 18 | var ( 19 | ProjectName = "shcopy" 20 | Version = "unknown" 21 | CommitSHA = "build from source" 22 | 23 | term = pflag.StringP("term", "t", "", "Terminal type: (default), tmux, screen.") 24 | clear = pflag.BoolP("clear", "c", false, "Clear the clipboard and exit.") 25 | primary = pflag.BoolP("primary", "p", false, "Use the primary clipboard instead system clipboard.") 26 | version = pflag.BoolP("version", "v", false, "Print version and exit.") 27 | help = pflag.BoolP("help", "h", false, "Print help and exit.") 28 | debug = pflag.BoolP("debug", "d", false, "Print debug information.") 29 | man = pflag.Bool("man", false, "Generate man pages.") 30 | ) 31 | 32 | func usage(isError bool) { 33 | out := os.Stdout 34 | if isError { 35 | out = os.Stderr 36 | } 37 | fmt.Fprintf(out, `Usage: 38 | %[1]s [options] [text] 39 | %[1]s [options] < [file] 40 | 41 | Copy text to the system clipboard from any supported terminal using 42 | ANSI OSC 52 sequence. 43 | 44 | Options: 45 | `, ProjectName) 46 | pflag.PrintDefaults() 47 | } 48 | 49 | func main() { 50 | pflag.Usage = func() { 51 | usage(true) 52 | } 53 | pflag.Parse() 54 | pflag.Lookup("debug").Hidden = true 55 | pflag.Lookup("man").Hidden = true 56 | 57 | if *version { 58 | fmt.Printf("%s version %s (%s)\n", ProjectName, Version, CommitSHA) 59 | return 60 | } 61 | 62 | if *help { 63 | usage(false) 64 | return 65 | } 66 | 67 | if *man { 68 | manPage := mango.NewManPage(1, ProjectName, "Copy text to the system clipboard from any supported terminal using ANSI OSC 52 sequence."). 69 | WithLongDescription(ProjectName+" a utility that copies text to your clipboard from anywhere using ANSI OSC 52 sequence."). 70 | WithSection("Terminal", "shcopy should work in any terminal that supports OSC 52. There are some exceptions below."). 71 | WithSection("Kitty", "Kitty, version 0.22.0 and below, had a bug where it appends to the"+ 72 | "clipboard instead of replacing it. To workaround this bug, clear"+ 73 | "the clipboard before copying any text."+ 74 | "\n"+ 75 | "shcopy -c; shcopy \"Hello World\"", 76 | ). 77 | WithSection("Screen", "To use shcopy within a screen session, make sure that the outer"+ 78 | "terminal supports OSC 52. If your '$TERM' environment variable is"+ 79 | "not set to 'screen-*', use '--term screen' to force shcopy to work"+ 80 | "with screen.", 81 | ). 82 | WithSection("Tmux", 83 | "To use shcopy within a tmux session, make sure that the outer "+ 84 | "terminal supports OSC 52, and use one of the following options:"+ 85 | "\n"+ 86 | "1. Configure tmux to allow programs to access the clipboard "+ 87 | "(recommended). The tmux 'set-clipboard' option was added in tmux 1.5 with a "+ 88 | "default of 'on'; the default was changed to 'external' when "+ 89 | "'external' was added in tmux 2.6. Setting 'set-clipboard' to 'on' "+ 90 | "allows external programs in tmux to access the clipboard. To enable "+ 91 | "this option, add 'set -s set-clipboard on' to your tmux config."+ 92 | "\n"+ 93 | "2. Use '--term tmux' option to force shcopy to work with tmux. This "+ 94 | "option requires the 'allow-passthrough' option to be enabled in tmux. "+ 95 | "Starting with tmux 3.3a, the 'allow-passthrough' option is no "+ 96 | "longer enabled by default. This option allows tmux to pass an ANSI "+ 97 | "escape sequence to the outer terminal by wrapping it in another "+ 98 | "special tmux escape sequence. This means the '--term tmux' option "+ 99 | "won't work unless you're running an older version of tmux or you "+ 100 | "have enabled 'allow-passthrough' in tmux. Add the following to your "+ 101 | "tmux config to enable passthrough 'set -g allow-passthrough on'."+ 102 | "\n"+ 103 | "Refer to https://github.com/tmux/tmux/wiki/Clipboard for more info.", 104 | ). 105 | WithSection("Bugs", "Report bugs to https://github.com/aymanbagabas/shcopy/issues"). 106 | WithSection("Copyright", "(C) 2024 Ayman Bagabas.\n"+ 107 | "Released under MIT license.") 108 | 109 | pflag.VisitAll(mpflag.PFlagVisitor(manPage)) 110 | fmt.Println(manPage.Build(roff.NewDocument())) 111 | return 112 | } 113 | 114 | var str string 115 | args := pflag.Args() 116 | // read from stdin if no arguments are provided and we are not clearing the 117 | // clipboard or reading the clipboard contents. 118 | if len(args) == 0 && !*clear { 119 | reader := bufio.NewReader(os.Stdin) 120 | var b strings.Builder 121 | 122 | for { 123 | r, _, err := reader.ReadRune() 124 | if err != nil && err == io.EOF { 125 | break 126 | } 127 | _, err = b.WriteRune(r) 128 | if err != nil { 129 | fmt.Fprintf(os.Stderr, "Failed to write rune: %v", err) 130 | os.Exit(1) 131 | } 132 | } 133 | 134 | // input 135 | str = b.String() 136 | } else { 137 | str = strings.Join(args, " ") 138 | } 139 | 140 | // the sequence string to be sent to the terminal 141 | seq := osc52.New(str) 142 | 143 | if *primary { 144 | seq = seq.Primary() 145 | } 146 | 147 | // Detect `screen` terminal type 148 | if term := os.Getenv("TERM"); term != "" { 149 | if strings.HasPrefix(term, "screen") { 150 | if sty := os.Getenv("STY"); sty != "" { 151 | // only when `STY` has been set 152 | // it's normal to see `TERM` is `screen` in tmux 153 | seq = seq.Screen() 154 | } 155 | } 156 | } 157 | 158 | if *term != "" { 159 | switch strings.ToLower(*term) { 160 | case "screen": 161 | seq = seq.Screen() 162 | case "tmux": 163 | seq = seq.Tmux() 164 | default: 165 | seq = seq.Mode(osc52.DefaultMode) 166 | } 167 | } 168 | 169 | if *clear { 170 | seq = seq.Clear() 171 | } 172 | 173 | if *debug { 174 | log.Printf("Sequence: %q", seq) 175 | } 176 | 177 | // send the sequence to the terminal 178 | _, _ = seq.WriteTo(os.Stderr) 179 | } 180 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # shcopy 2 | 3 |

4 | Build Status 5 | Latest Release 6 |

7 | 8 | **Sh**ell **Copy** is a simple utility that copies text to the clipboard from anywhere using [ANSI OSC52](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands) sequence. It works with local terminals (/dev/tty\*) and remote terminals (SSH, Telnet). 9 | 10 | Think of this as a tool like `xclip` or `pbcopy` but also works over SSH. 11 | 12 | ## Example 13 | 14 | ```sh 15 | # Copy text to clipboard 16 | shcopy "Hello World" 17 | 18 | # Copy text to primary clipboard (X11) 19 | shcopy -p "Hello World" 20 | 21 | # Copy command output to clipboard 22 | echo -n "Hello World" | shcopy 23 | 24 | # Copy file content to clipboard 25 | shcopy < file.txt 26 | 27 | # Copy from stdin until EOF 28 | # Ctrl+D to finish 29 | shcopy 30 | 31 | # Need help? 32 | shcopy --help 33 | ``` 34 | 35 | ## Installation 36 | 37 | ### Go Install 38 | 39 | ```sh 40 | go install github.com/aymanbagabas/shcopy@latest 41 | ``` 42 | 43 | ### Homebrew 44 | 45 | ```sh 46 | brew install aymanbagabas/tap/shcopy 47 | ``` 48 | 49 | ### Debian/Ubuntu 50 | 51 | ```sh 52 | echo 'deb [trusted=yes] https://repo.aymanbagabas.com/apt/ /' | sudo tee /etc/apt/sources.list.d/aymanbagabas.list 53 | sudo apt update && sudo apt install shcopy 54 | ``` 55 | 56 | ### Fedora 57 | 58 | ```sh 59 | echo '[aymanbagabas] 60 | name=Ayman Bagabas 61 | baseurl=https://repo.aymanbagabas.com/yum/ 62 | enabled=1 63 | gpgcheck=0' | sudo tee /etc/yum.repos.d/aymanbagabas.repo 64 | sudo yum install shcopy 65 | ``` 66 | 67 | ### Arch Linux 68 | 69 | ```sh 70 | yay -S shcopy-bin 71 | ``` 72 | 73 | ### Nix NUR 74 | 75 | ``` 76 | nix-shell -p nur.repos.aymanbagabas.shcopy 77 | ``` 78 | 79 | ### Scoop (Windows) 80 | 81 | ```sh 82 | scoop bucket add aymanbagabas https://github.com/aymanbagabas/scoop-bucket.git 83 | scoop install aymanbagabas/shcopy 84 | ``` 85 | 86 | You can also download the latest binaries and packages from the [releases page](https://github.com/aymanbagabas/shcopy/releases). 87 | 88 | ## Supported Terminals 89 | 90 | This is a non-exhaustive list of the status of popular terminal emulators regarding OSC52 [^1]: 91 | 92 | | Terminal | OSC52 support | 93 | | ----------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------: | 94 | | [Alacritty](https://github.com/alacritty/alacritty) | **yes** | 95 | | [foot](https://codeberg.org/dnkl/foot) | **yes** | 96 | | [GNOME Terminal](https://github.com/GNOME/gnome-terminal) (and other VTE-based terminals) | [not yet](https://bugzilla.gnome.org/show_bug.cgi?id=795774) | 97 | | [hterm (Chromebook)](https://chromium.googlesource.com/apps/libapps/+/master/README.md) | [**yes**](https://chromium.googlesource.com/apps/libapps/+/master/nassh/doc/FAQ.md#Is-OSC-52-aka-clipboard-operations_supported) | 98 | | [iTerm2](https://iterm2.com/) | **yes** | 99 | | [kitty](https://github.com/kovidgoyal/kitty) | **yes** | 100 | | [Konsole](https://konsole.kde.org/) | [not yet](https://bugs.kde.org/show_bug.cgi?id=372116) | 101 | | [QTerminal](https://github.com/lxqt/qterminal#readme) | [not yet](https://github.com/lxqt/qterminal/issues/839) | 102 | | [screen](https://www.gnu.org/software/screen/) | **yes** | 103 | | [st](https://st.suckless.org/) | **yes** (but needs to be enabled, see [here](https://git.suckless.org/st/commit/a2a704492b9f4d2408d180f7aeeacf4c789a1d67.html)) | 104 | | [Terminal.app]() | no, but see [workaround](https://github.com/roy2220/osc52pty) | 105 | | [tmux](https://github.com/tmux/tmux) | **yes** | 106 | | [Windows Terminal](https://github.com/microsoft/terminal) | **yes** | 107 | | [rxvt](http://rxvt.sourceforge.net/) | **yes** (to be confirmed) | 108 | | [urxvt](http://software.schmorp.de/pkg/rxvt-unicode.html) | **yes** (with a script, see [here](https://github.com/ojroques/vim-oscyank/issues/4)) | 109 | | [xterm.js](https://xtermjs.org/) (Hyper terminal) | [not yet](https://github.com/xtermjs/xterm.js/issues/3260) | 110 | | [wezterm](https://github.com/wez/wezterm) | [**yes**](https://wezfurlong.org/wezterm/escape-sequences.html#operating-system-command-sequences) | 111 | 112 | [^1]: Originally copied from [vim-oscyank](https://github.com/ojroques/vim-oscyank) 113 | 114 | ### Tmux 115 | 116 | To use shcopy within a tmux session, make sure that the outer terminal supports 117 | OSC 52, and use one of the following options: 118 | 119 | 1. Configure tmux to allow programs to access the clipboard (recommended). The 120 | tmux `set-clipboard` option was added in tmux 1.5 with a default of `on`; 121 | the default was changed to `external` when `external` was added in tmux 2.6. 122 | Setting `set-clipboard` to `on` allows external programs in tmux to access 123 | the clipboard. To enable this option, add `set -s set-clipboard on` to your 124 | tmux config. 125 | 126 | 2. Use `--term tmux` option to force shcopy to work with tmux. This option 127 | requires the `allow-passthrough` option to be enabled in tmux. Starting with 128 | tmux 3.3a, the `allow-passthrough` option is no longer enabled by default. 129 | This option allows tmux to pass an ANSI escape sequence to the outer 130 | terminal by wrapping it in another special tmux escape sequence. This means 131 | the `--term tmux` option won't work unless you're running an older version 132 | of tmux or you have enabled `allow-passthrough` in tmux. Add the following 133 | to your tmux config to enable passthrough `set -g allow-passthrough on`. 134 | 135 | Refer to https://github.com/tmux/tmux/wiki/Clipboard for more info. 136 | 137 | ## Credits 138 | 139 | This project is built on top of [go-osc52](https://github.com/aymanbagabas/go-osc52), based on [vim-oscyank](https://github.com/ojroques/vim-oscyank). 140 | --------------------------------------------------------------------------------