savedra1 / clipse

Configurable TUI clipboard manager for Unix
MIT License
349 stars 14 forks source link

Build Last Commit GitHub closed issues

https://github.com/savedra1/clipse/assets/99875823/40af797c-2297-49b5-88ec-b8c04e8c829b

nix AUR

Table of contents

Release information

If moving to a new release of clipse please review the changelog.

About 📋

clipse is a configurable, TUI-based clipboard manager application written in Go with minimal dependency. Though the app is optimized for a Linux OS using a dedicated window manager, clipse can also be used on any Unix-based system. Simply install the package and bind the open command to get your desired clipboard behavior. Further instructions for setting this up can be found below.

Dependency info and libraries used

atotto/clipboard

This requires a system clipboard. I would recommend using wl-clipboard (Wayland) or xclip (X11/macOs) to get the best results. You can also use xsel and termux-clipboard, but these will not allow you to copy images.

BubbleTea

Does not require any additional dependency, but may require you to use a terminal environment that's compatible with termenv.

Features ✨

Customization 🧰

A customizable TUI allows you to easily match your system's theme. The app is based on your terminal's theme by default but is editable from a custom_theme.json file that gets created when the program is run for the first time. See the library for some example themes to give you inspiration.

An example custom_theme.json file:

{
 "UseCustom":          true,
 "TitleFore":          "#ffffff",
 "TitleBack":          "#6F4CBC",
 "TitleInfo":          "#3498db",
 "NormalTitle":        "#ffffff",
 "DimmedTitle":        "#808080",
 "SelectedTitle":      "#FF69B4",
 "NormalDesc":         "#808080",
 "DimmedDesc":         "#808080",
 "SelectedDesc":       "#FF69B4",
 "StatusMsg":          "#2ecc71",
 "PinIndicatorColor":  "#FFD700",
 "SelectedBorder":     "#3498db",
 "SelectedDescBorder": "#3498db",
 "FilteredMatch":      "#ffffff",
 "FilterPrompt":       "#2ecc71",
 "FilterInfo":         "#3498db",
 "FilterText":         "#ffffff",
 "FilterCursor":       "#FFD700",
 "HelpKey":            "#999999",
 "HelpDesc":           "#808080",
 "PageActiveDot":      "#3498db",
 "PageInactiveDot":    "#808080",
 "DividerDot":         "#3498db",
 "PreviewedText":      "#ffffff",
 "PreviewBorder":      "#3498db",
}

You can also easily specify source config like custom paths and max history limit in the apps config.json file. For more information see Configuration section.

Versatility 🌐

The clipse binary, installable from the repository, can run on pretty much any Unix-based OS, though currently optimized for Linux. Being terminal-based also allows for easy integration with a window manager and configuration of how the TUI behaves. For example, binding a floating window to the clipse command as shown at the top of the page using Hyprland window manager on NixOs.

Note that working with image files will require one of the following dependencies to be installed on your system:

Setup & installation 🏗️

See below for instructions on getting clipse installed and configured effectively.

Installation

Installing on NixOs

Due to how irregularly the stable branch of Nixpkgs is updated, you may find the unstable package is more up to date. The Nix package for clipse can be found here

Direct install

nix-env -iA nixpkgs.clipse # OS == NixOs
nix-env -f channel:nixpkgs -iA clipse # OS != NixOs

Nix shell

nix shell -p clipse

System package

environment.systemPackages = [
    pkgs.clipse
  ];

If building clipse from the unstable branch as a system package, I would suggest referencing this article for best practice. The derivation can also be built from source using the following:

{ lib
, buildGoModule
, fetchFromGitHub
}:

buildGoModule rec {
  pname = "clipse";
  version = "1.1.0";

  src = fetchFromGitHub {
    owner = "savedra1";
    repo = "clipse";
    rev = "v${version}";
    hash = "sha256-Kpe/LiAreZXRqh6BHvUIn0GcHloKo3A0WOdlRF2ygdc=";
  };

  vendorHash = "sha256-Hdr9NRqHJxpfrV2G1KuHGg3T+cPLKhZXEW02f1ptgsw=";

  meta = {
    description = "Useful clipboard manager TUI for Unix";
    homepage = "https://github.com/savedra1/clipse";
    license = lib.licenses.mit;
    mainProgram = "clipse";
    maintainers = [ lib.maintainers.savedra1 ];
  };
}

Installing on Arch

Thank you @raininja for creating and maintaining the AUR package!

Installing with yay

yay -S clipse

Installing from pkg source

git clone https://aur.archlinux.org/clipse.git && cd clipse && makepkg -si

Installing on Fedora/Rhel

Thank you @RadioAndrea for creating and maintaining the COPR package!

dnf copr enable azandure/clipse

Installing with wget

Linux arm64 ```shell wget -c https://github.com/savedra1/clipse/releases/download/v1.1.0/clipse_1.1.0_linux_arm64.tar.gz -O - | tar -xz ```
Linux amd64 ```shell wget -c https://github.com/savedra1/clipse/releases/download/v1.1.0/clipse_1.1.0_linux_amd64.tar.gz -O - | tar -xz ```
Linux 836 ```shell wget -c https://github.com/savedra1/clipse/releases/download/v1.1.0/clipse_1.1.0_linux_836.tar.gz -O - | tar -xz ```
Darwin arm64 ```shell wget -c https://github.com/savedra1/clipse/releases/download/v1.1.0/clipse_1.1.0_darwin_arm64.tar.gz -O - | tar -xz ```
Darwin amd64 ```shell wget -c https://github.com/savedra1/clipse/releases/download/v1.1.0/clipse_1.1.0_darwin_amd64.tar.gz -O - | tar -xz ```

Installing with Go

go install github.com/savedra1/clipse@v1.1.0

Building from source

git clone https://github.com/savedra1/clipse
cd clipse
go mod tidy
go build -o clipse

Set up

As mentioned earlier, to get the most out of clipse, it's recommended to bind the two primary key commands to your system's config. The first key command is to open the clipboard history TUI:

clipse

The second command doesn't need to be bound to a key combination, but rather to the system boot to run the background listener on start-up:

clipse -listen  

The above command creates a nohup process of clipse --listen-shell, which if called on its own will start a listener in your current terminal session instead. If nohup is not supported on your system, you can use your preferred method of running clipse --listen-shell in the background instead.

Note: The following examples are based on bash/zsh shell environments. If you use something else like foot or fish, you may need to construct the command differently, referencing the relevant documentation.

Hyprland

Add the following lines to your Hyprland config file:


exec-once = clipse -listen # run listener on startup

windowrulev2 = float,class:(clipse) # ensure you have a floating window class set if you want this behavior
windowrulev2 = size 622 652,class:(clipse) # set the size of the window as necessary

bind = SUPER, V, exec,  <terminal name> --class clipse -e 'clipse' 

# Example: bind = SUPER, V, exec, alacritty --class clipse -e 'clipse'

Hyprland reference

i3

Add the following commands to your ~/.config/i3/config file:

exec --no-startup-id clipse -listen                                                           # run listener on startup
bindsym $mod+V exec --no-startup-id urxvt -e "$SHELL" -c "i3-msg 'floating enable' && clipse" # Bind floating shell with TUI selection to something nice 

i3 reference

Sway

Add the following config to your ~/.config/sway/config file:

exec clipse -listen                                                                                                                     # run the background listener on startup
bindsym $mod+V exec <terminal name> -e sh -c "swaymsg floating enable, move position center; swaymsg resize set 80ppt 80ppt && clipse"  # Bind floating shell with TUI selection to something nice

Sway reference

MacOs

The native terminal on MacOs will not close once the clipse program completes, even when using the -fc argument. You will therefore need to use a different terminal environment like Alacritty to achieve the "close on selection" effect. The bindings used to open the TUI will then need to be defined in your settings/window manager.

Other

Every system/window manager is different and hard to determine exactly how to achieve the more ‘GUI-like’ behavior. If using something not mentioned above, just refer to your systems documentation to find how to:

If you're not calling clipse with a command like exec <terminal name> -e sh -c and want to force the terminal window to close on selection of an item, use the -fc arg to pass in the $PPID variable so the program can force kill the shell session. EG clipse -fc $PPID. _Note that the $PPID variable is not available in every terminal environment, like fish terminal where you'd need to use $fishpid instead.

Configuration

The configuration capabilities of clipse will change as clipse evolves and grows. Currently, clipse supports the following configuration:

clipse looks for a base config file in $CONFIG_DIR/clipse/config.json _($CONFIG_DIR being $XDG_DATA_HOME or $HOME/.config)_, and creates a default file if it does not find anything. The default config looks like this:

{
    "historyFile": "clipboard_history.json",
    "maxHistory": 100,
    "allowDuplicates": false,
    "themeFile": "custom_theme.json",
    "tempDir": "tmp_files",
    "logFile": "clipse.log",
    "keyBindings": {
        "choose": "enter",
        "clearSelected": "S",
        "down": "down",
        "end": "end",
        "filter": "/",
        "home": "home",
        "more": "?",
        "nextPage": "right",
        "prevPage": "left",
        "preview": "t",
        "quit": "q",
        "remove": "x",
        "selectDown": "ctrl+down",
        "selectSingle": "s",
        "selectUp": "ctrl+up",
        "togglePin": "p",
        "togglePinned": "tab",
        "up": "up",
        "yankFilter": "ctrl+s"
     },
    "imageDisplay": {
        "type": "basic",
        "scaleX": 9,
        "scaleY": 9,
        "heightCut": 2
     }
}

Note that all the paths provided (the theme, historyFile, and tempDir) are all relative paths. They are relative to the location of the config file that holds them. Thus, a file config.json at location $HOME/.config/clipse/config.json will have all relative paths defined in it relative to its directory of $HOME/.config/clipse.

Absolute paths starting with /, paths relative to the user home dir using ~, or any environment variables like $HOME and $XDG_CONFIG_HOME are also valid paths that can be used in this file instead.

Currently these are the supported options for imageDisplay.type:

All commands 💻

clipse is more than just a TUI. It also offers a number of CLI commands for managing clipboard content directly from the terminal.

# Operational commands 

clipse -a <arg>       # Adds <arg> directly to the clipboard history without copying to system clipboard (string

clipse -a             # Adds any standard input directly to the clipboard history without copying to the system clipboard.

                      # For example: echo "some data" | clipse -a

clipse -c <arg>       # Copy the <arg> to the system clipboard (string). This also adds to clipboard history if currently listening. 

clipse -c             # Copies any standard input directly to the system clipboard.

                      # For example: echo "some data" | clipse -c

clipse -p             # Prints the current clipboard content to the console. 

                      # Example: clipse -p > file.txt

# TUI management commands

clipse                # Open Clipboard TUI in persistent/debug mode

clipse -fc $PPID      # Open Clipboard TUI in 'force kill' mode 

clipse -listen        # Run a background listener process

clipse --listen-shell # Run a listener process in the current terminal (useful for debugging)

clipse -help          # Display menu option

clipse -v             # Get version

clipse -clear         # Wipe all clipboard history except for pinned items

clipse -clear-images  # Wipe all images from the history 

clipse -clear-text    # Wipe all text items from the clipboard history

clipse -clear-all     # Wipe entire clipboard history

clipse keep           # Keep the TUI open after selecting an item to copy (useful for debugging)

clipse -kill          # Kill any existing background processes

You can also view the full list of TUI key commands by hitting the ? key when the clipse UI is open.

How it works 🤔

When the app is run for the first time it creates a /home/$USER/.config/clipse dir containing config.json, clipboard_history.json, custom_theme.json and a dir called tmp_files for storing image data. After the clipse -listen command is executed, a background process will be watching for clipboard activity and adding any changes to the clipboard_history.json file, unless a different path is specified in config.json.

The TUI that displays the clipboard history with the defined theme should then be called with the clipse command. Operations within the TUI are defined with the BubbleTea framework, allowing for efficient concurrency and a smooth UX. delete operations will remove the selected item from the TUI view and the storage file, select operations will copy the item to the systems clipboard and exit the program.

The maximum item storage limit defaults at 100 but can be customized to anything you like in the config.json file.

Contributing 🙏

I would love to receive contributions to this project and welcome PRs from everyone. The following is a list of example future enhancements I'd like to implement:

FAQ

My terminal window does not close on selection, even when using clipse -fc $PPID

Some terminal environments reference system variables differently. For example, the fish terminal will need to use $fish_pid instead. To debug this error you can run echo $PPID to see what gets returned. To get the "close on selection" effect for macOs, you will need to install a different terminal environment like Alacritty._

Is there risk of multiple parallel processes running?

No. The clipse command kills any existing TUI processes before opening up and the clipse -listen command kills any existing background listeners before starting a new one.

High CPU usage?

When an image file has an irregular binary data pattern it can cause a lot of strain on the program when clipse reads its history file (even when the TUI is not open). If this happens, you will need to remove the image file from the TUI or by using clipse -clear-images. See issue #33 for an example.

My copied entries are not recorded when starting the clipse listener on boot with a systemd service

There may be a few ways around this but the workaround discovered in issue #41 was to use a .desktop file, stored in ~/.config/autostart/. Eg:

  [Desktop Entry]
  Name=clipse
  Comment=Clipse event listener autostart.
  Exec=/home/usrname/Applications/bin/clipse/clipse_1.1.0_linux_amd64/clipse --listen %f
  Terminal=false
  Type=Application


Copying images from a browser does not work correctly

Depending on the clipboard utility you are using (wl-clipboard/xclip etc) the data sent to the system clipboard is read differently when copying from browser locations.
If using wayland, copying images from your browser should now work from most sites if using v1.0.4 or later. This may copy the binary data as well as the metadata sting as a separate entry. Some sites/browsers may add the browser image data to the stdin in a way that wl-clipboard does not recognize.
If using x11, MacOs or other and copying browser images does not work, feel free to raise and issue (or a PR) detailing which sites/browser engines this does not work with for you.