sentriz / cliphist

wayland clipboard manager with support for multimedia
GNU General Public License v3.0
675 stars 21 forks source link

Can I donate these scripts to you? #54

Closed koraa closed 1 year ago

koraa commented 1 year ago

The following scripts support:

They do not support informing cliphist about the mime type; they are also a bit inefficient as many commands are started to make this setup work. A pure go/rust solution might be better suited for efficiency.

~/.config/systemd/user/cliphist.helper.sh

#! /bin/bash

# This script is designed to preserve the exact contents of th
# A note about newline preserving string handling in bash
#
# $ mycommand <<< "${foo}" – # appends a newline
# $ echo -n "${foo}" | mycommand # preserves newline
# $ foo="$(cat)" # preserves newline
# $ foo="$(</dev/stdin)" # preserves newline
# $ $'\n' # String literal with explicit newline handling
# $ LF=$'\n' # Line feed (newline) as a variable
# $ "${LF}" # Regular string literal with newlines
# $ wl-copy -n # trims newlines - DOES NOT PRESERVE NEWLINES
# $ wl-copy # preserves newlines
# $ wl-paste -n # preserves newlines
# $ wl-paste # adds a newline - DOES NOT PRESERVE NEWLINES

set -e
SCRIPT_SOURCE="$0"
DEBUG="falsfalse"
LF=$'\n'

log() {
  echo >&2 "$@"
}

dbg() {
  if check "${DEBUG}"; then
    log "$@"
  fi
}

show_newlines() {
  printf "%q" "$1"
}

exc() {
  if check "${DEBUG}"; then
    local stdin; stdin="$(cat)"
    log -e "$ $*\n< $(show_newlines "${stdin}")"
    echo -n "${stdin}" | "$@"
  else
    "$@"
  fi
}

panic() {
  log "Panic:" "$@"
  exit 1
}

bool() {
  if "$@"; then
    echo true
  else
    echo false
  fi
}

check() {
  test "$1" = "true"
}

cmd_sync_write() {

  local src_args; src_args=()
  local dst_args; dst_args=()

  local remember; remember="false"
  local primary; primary="false"

  while (( "$#" > 0 )); do
    case "$1" in
      "--primary") # Write to primary selection
        primary="true"
        ;;
      "--remember") # Notify cliphist
        remember="true"
        ;;
      *)
        panic "Unknown sync parameter: $1"
    esac
    shift
  done

  if check "${primary}"; then
    dst_args+=("--primary")
  else
    src_args+=("--primary")
  fi

  local nu; nu="$(</dev/stdin)"
  local nu_mime; nu_mime="$(wl-paste --list "${src_args[@]}" | head -n1)"
  local cur; cur="$(wl-paste -n "${dst_args[@]}")"
  local cur_mime; cur_mime="$(wl-paste --list "${dst_args[@]}" | head -n1)"
  local novel; novel="$(bool test "${nu}" != "${cur}" -o "${nu_mime}" != "${cur_mime}")"

  if check "${DEBUG}"; then
    dbg "sync_write!" \
      "remember=${remember}" \
      "novel=${novel}" \
      "primary=${primary}" \
      "nu=${nu_mime}:$(show_newlines "${nu}")" \
      "cur=${cur_mime}:$(show_newlines "${cur}")" \
      -- src_args = "${src_args[@]}" \
      -- dst_args = "${dst_args[@]}" \
      -- '$@' = "$@"
  fi

  # Send clipboard data to cliphist
  if check "${remember}"; then
    # TODO: Support mime
    echo -n "${nu}" | exc cliphist store
  fi

  # Avoid infinite update loops by detecting if the destination clipboard contains the data already
  if check "${novel}"; then
    echo -n "${nu}" | exc exec wl-copy --type "${nu_mime}" "${dst_args[@]}"
  fi

}

cmd_watch() {
  if (( "$#" > 1 )); then
    panic -e "Spurious arguments: ${*}${LF}Just specify a single argument --primary or --clipboard"
  fi

  local mode; mode="$1"; shift || panic "Please specify --primary or --clipboard"
  local primary; primary="false"
  case "${mode}" in
    "--primary")
      # From primary, to cliboard; to cliphist via the clipboard handler
      primary="false"
      ;;
    "--clipboard")
      # From clipboard, to primary and cliphist
      primary="true"
      ;;
    *)
      panic "Unknown mode: ${mode}. Please specify --primary or --clipboard"
  esac

  local watch_opts; watch_opts=()
  local sync_opts; sync_opts=()

  if [[ "$primary" = "true" ]]; then
    # primary -> clipboard -> cliphist
    watch_opts=("--primary" "${watch_opts[@]}")
  else
    # clipboard -> primary, cliphist
    sync_opts=("--remember" "${sync_opts[@]}")
    sync_opts=("--primary" "${sync_opts[@]}")
  fi

  exc exec wl-paste -n "${watch_opts[@]}" -w bash "${SCRIPT_SOURCE}" sync_write "${sync_opts[@]}"
}

main() {
  local cmd; cmd="$1"; shift || panic "Specify a command"
  if [[ "$cmd" = "sync_write" ]]; then
    cmd_sync_write "$@"
  elif [[ "$cmd" = "watch" ]]; then
    cmd_watch "$@"
  else
    panic "Unknown command ${cmd}"
  fi
}

main "$@"

~/.config/systemd/user/cliphist.service

[Unit]
Description=Cliphist clipboard manager
After=sway.target
Wants=sway.target
Requires=cliphist-watch-primary.service
Requires=cliphist-watch-clipboard.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/true
ExecReload=/bin/true

[Install]
WantedBy=default.target

~/.config/systemd/user/cliphist-watch-primary.service

[Unit]
Description=Cliphist clipboard manager
PartOf=cliphist.service
ReloadPropagatedFrom=cliphist.service

[Service]
Type=simple
ExecStart=/usr/bin/bash "%Y/cliphist.helper.sh" watch --primary
Restart=always
RestartSec=1
TimeoutStopSec=10
KillMode=mixed

~/.config/systemd/user/cliphist-watch-clipboard.service

[Unit]
Description=Cliphist clipboard manager
PartOf=cliphist.service
ReloadPropagatedFrom=cliphist.service

[Service]
Type=simple
ExecStart=/usr/bin/bash "%Y/cliphist.helper.sh" watch --clipboard
Restart=always
RestartSec=1
TimeoutStopSec=10
KillMode=mixed
sentriz commented 1 year ago

hi I'm not sure why special handing of newlines is required, that's what cliphist decode is for

koraa commented 1 year ago

hi I'm not sure why special handing of newlines is required, that's what cliphist decode is for

There is no special handling. Bash and wl-copy are simply erasing the information about whether there is a trailing newline by default…

sentriz commented 1 year ago

ah ok i think i see it now :+1:

there is already a contrib/ dir here but i was thinking of moving that stuff to a wiki instead of checking them in - since i don't use these scripts personally and don't want to have to maintain them as cliphist evolves

i just changed the github settings and i think you can edit the wiki now. does that work?

thanks!

koraa commented 1 year ago

Since neither you nor I wish to maintain them they will have to go to the abyss of forgotten software. It is a shame really, cliphist is of very limited use without them %)

koraa commented 1 year ago

In case anyone else wishes to pick these scripts up, I hereby license them under a CC0 (Public Domain) license.