diff --git a/config/niri/.config/niri/config/binds.kdl b/config/niri/.config/niri/config/binds.kdl index e844e99..7b783ee 100644 --- a/config/niri/.config/niri/config/binds.kdl +++ b/config/niri/.config/niri/config/binds.kdl @@ -36,7 +36,7 @@ binds { Alt+Space { spawn-sh "pkill -x rofi || rofi -show drun"; } // Actions - Mod+V { spawn-sh "pkill -x rofi || rofi-cliphist"; } + Mod+V { spawn-sh "pkill -x shorin-cliphist || ghostty -e shorin-cliphist"; } Mod+Period { spawn-sh "pkill -x rofi || rofi-emoji"; } Ctrl+Alt+Delete { spawn-sh "pkill -x wlogout || wlogout -p layer-shell"; } Print { spawn "niri" "msg" "action" "screenshot-screen"; } diff --git a/config/scripts/.local/scripts/rofi-cliphist b/config/scripts/.local/scripts/rofi-cliphist index ec5369a..e5d194b 100755 --- a/config/scripts/.local/scripts/rofi-cliphist +++ b/config/scripts/.local/scripts/rofi-cliphist @@ -1,7 +1,30 @@ -#!/bin/sh +#!/usr/bin/env bash # Description: -# Quick snippet for cliphist + rofi + wl-copy +# ~~Quick~~ snippet for cliphist + rofi + wl-copy -cliphist list | rofi -dmenu -config ~/.config/rofi/dmenu.rasi -display-columns 2 -i | \ - cliphist decode | wl-copy \ No newline at end of file +tmp_dir="/tmp/cliphist" +trap 'rm -rf "$tmp_dir"' EXIT +mkdir -p "$tmp_dir" + +read -r -d '' prog <$tmp_dir/"grp[1]"."grp[3]) + print \$0"\0icon\x1f$tmp_dir/"grp[1]"."grp[3] + next +} +1 +EOF + +# Pipeline logic: +# 1. cliphist list: gives "ID Content" +# 2. gawk: adds icon paths +# 3. rofi -dmenu: shows list, hides column 1 (ID), returns "ID Content" on select +# 4. cliphist decode: reads ID from line, gets original content + +result=$(cliphist list | gawk "$prog" | rofi -dmenu -display-columns 2 -config "$HOME/.config/rofi/dmenu.rasi" -show-icons -p "Clipboard") + +if [[ -n "$result" ]]; then + echo "$result" | cliphist decode | wl-copy +fi diff --git a/config/scripts/.local/scripts/shorin-cliphist b/config/scripts/.local/scripts/shorin-cliphist new file mode 100755 index 0000000..265f5f5 --- /dev/null +++ b/config/scripts/.local/scripts/shorin-cliphist @@ -0,0 +1,269 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2016 + +# Credit: https://github.com/SHORiN-KiWATA/shorinclip +# +# MIT License +# +# Copyright (c) 2026 shorinkiwata +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +set -euo pipefail + +CACHE_DIR=$(mktemp -d) +export CACHE_DIR +trap 'rm -rf "$CACHE_DIR"' EXIT + +# 颜色变量 +export C_TERTIARY='\x1b[1;35m' +export C_PRIMARY='\x1b[1;34m' +export C_CYAN='\x1b[1;36m' +export C_RESET='\x1b[0m' + +# 过滤无法复制粘贴的信息 +filter_clip_list() { + grep -vP "(?s)(?i)\t.* 直接复制图片数据 + if [[ "$mime" =~ image ]]; then + # 直接复制 + echo "$input" | cliphist decode | wl-copy + + # 2. QQ HTML -> 提取路径 -> 存入缓存 -> 复制 file:// 缓存路径 + elif [ "$mime" = "text/html" ]; then + local qq_src + qq_src=$(echo "$decoded" | grep -oP "^ 直接复制为文件链接 + elif [[ "$decoded" == file://* ]]; then + echo "$decoded" | wl-copy --type text/uri-list + + # 3. 绝对路径 -> 转 file:// -> 复制为URL链接 + elif [[ "$decoded" == /* ]] && [ -e "$decoded" ]; then + local encoded_path + encoded_path=$(url_encode "$decoded") + echo "file://$encoded_path" | wl-copy --type text/uri-list + + # 5. 其他 -> 普通文本复制 + else + echo "$input" | cliphist decode | wl-copy + fi +} +export -f copy_selection +# 自动刷新机制 +FZF_PORT=$(shuf -i 10000-60000 -n 1) +RELOAD_CMD="cliphist list | format_clip_list | add_num" +wl-paste --watch bash -c "curl -s -X POST -d 'reload($RELOAD_CMD)' http://localhost:$FZF_PORT" >/dev/null 2>&1 & +WATCH_PID=$! +trap 'kill $WATCH_PID 2>/dev/null' EXIT + +# 读取窗口大小,避免窗口过小的时候就打开fzf导致菜单错位 +# 50次循环超时 +wait_timeout=50 +# 循环检测终端的长和宽 +while [[ $(tput cols) -lt 35 || $(tput lines) -lt 25 ]]; do + echo "Waiting for terminal resize to at least 35x25..." + sleep 1 + # 每循环一次减少超时时间 + ((wait_timeout--)) + [ "$wait_timeout" -eq 0 ] && { + echo "Timeout waiting for terminal resize. Exiting." + exit 1 + } +done + + +#=== FZF 主程序 === +cliphist list | format_clip_list | add_num | fzf \ + --ansi \ + --listen "$FZF_PORT" \ + --bind "ctrl-r:reload($RELOAD_CMD)" \ + --bind "ctrl-x:execute-silent(bash -c 'cliphist delete <<< \"\$1\"' -- {})+reload($RELOAD_CMD)" \ + --prompt="󰅍 > " \ + --header='CTRL-X: Delete | CTRL-R: Reload | ENTER: Copy' \ + --color='header:italic:yellow,prompt:blue,pointer:blue' \ + --info=hidden \ + --no-sort \ + --layout=reverse \ + --with-nth 2.. \ + --delimiter '\t' \ + --preview-window=down:50% \ + --preview ' + # 获取当期剪贴版项目的id + id=$(echo {} | cut -f1) + content=$(echo {} | cut -f2-) + # 通过decode数据获取mimetype + mimeType=$(echo {} | cliphist decode | file -b --mime-type -) + # 获取文件后缀名 + ext=$(echo $mimeType | awk -F"/" "{print \$2}") + + # 通过mimetype判断数据/类型 + # 如果是二进制图片 + if [[ $mimeType =~ image ]]; then + # 生成缓存文件 + img_hash=$(echo {} | cliphist decode | md5sum | cut -d" " -f1) + cache_file="$CACHE_DIR/$img_hash.$ext" + echo {} | cliphist decode > "$cache_file" + kitty +kitten icat --clear --image-id=10 --transfer-mode=file \ + --place="${FZF_PREVIEW_COLUMNS}x${FZF_PREVIEW_LINES}@0x0" "$cache_file" /dev/null;then + ffmpegthumbnailer -i "$path" -o "$thumb_file" -s 480 -t 0 >/dev/null 2>&1 + else + echo "ffmpegthumbnailer not installed." + fi + fi + # 如果缩略图文件存在且大小不为零 + if [ -s "$thumb_file" ]; then + kitty +kitten icat --transfer-mode=file --image-id=10 \ + --place="${FZF_PREVIEW_COLUMNS}x${FZF_PREVIEW_LINES}@${FZF_PREVIEW_LEFT}x${FZF_PREVIEW_TOP}" \ + "$thumb_file" /dev/null 2>&1; then + ffmpegthumbnailer -i "$raw_path" -o "$raw_thumb_file" -s 480 -t 0 >/dev/null 2>&1 + else + echo "ffmpegthumbnailer not installed" + fi + fi + # 如果缩略图文件存在且大小不为零 + if [ -s "$raw_thumb_file" ]; then + kitty +kitten icat --transfer-mode=file --image-id=10 \ + --place="${FZF_PREVIEW_COLUMNS}x${FZF_PREVIEW_LINES}@${FZF_PREVIEW_LEFT}x${FZF_PREVIEW_TOP}" \ + "$raw_thumb_file" /dev/tty 2>/dev/null + # 直接预览 + echo "[$mimeType]" + echo --- + echo {} | cliphist decode + fi + ' \ + --bind "enter:execute-silent(bash -c 'copy_selection \"\$1\"' -- {})+accept" + +# 粘贴已经绑定到了fzf的enter键,脚本会自动退出,必须写在fzf的按键绑定,否则wl-copy会导致浮动终端卡住(niri下)。