diff --git a/scripts/menu/menu-bookmarks b/scripts/menu/menu-bookmarks index e064964..e3c3dd0 100755 --- a/scripts/menu/menu-bookmarks +++ b/scripts/menu/menu-bookmarks @@ -7,4 +7,4 @@ name="$(sed '/^Watch\slater:\s/d;/^\s*$/d;/^#/d;s/-.*$//g' "$BOOKMARKS" | menu " [ -z "$name" ] && exit grep "$name" $BOOKMARKS | sed -z 's/^.*-//g;s/\n//g' | - wl-copy && notify-send "󰃀 Bookmarks" "'$name' copied to clipboard" + xsel -ib && notify-send "󰃀 Bookmarks" "'$name' copied to clipboard" diff --git a/scripts/menu/xclipmenu/clipctl b/scripts/menu/xclipmenu/clipctl new file mode 100755 index 0000000..4249fe2 --- /dev/null +++ b/scripts/menu/xclipmenu/clipctl @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +: "${CM_DIR:="${XDG_RUNTIME_DIR-"${TMPDIR-/tmp}"}"}" + +if [[ -z $1 ]] || [[ $1 == --help ]] || [[ $1 == -h ]]; then + cat << 'EOF' +clipctl provides controls for the clipmenud daemon. + +Commands: + enable: enable clip collection + disable: disable clip collection + status: returns "enabled" or "disabled" + toggle: toggles clip collection + version: returns major version + cache-dir: returns the directory used for caching +EOF + exit 0 +fi + +clipmenud_pid=$(pgrep -u "$(id -u)" -nf 'clipmenud$') + +case $1 in + enable|disable|toggle|status) + if [[ -z "$clipmenud_pid" ]]; then + echo "clipmenud is not running" >&2 + exit 2 + fi + ;; +esac + +major_version=6 +cache_dir=$CM_DIR/clipmenu.$major_version.$USER +status_file=$cache_dir/status + +case $1 in + enable) kill -USR2 "$clipmenud_pid" ;; + disable) kill -USR1 "$clipmenud_pid" ;; + status) cat "$status_file" ;; + toggle) + if [[ $(clipctl status) == "enabled" ]]; then + clipctl disable + else + clipctl enable + fi + ;; + version) echo "$major_version" ;; + cache-dir) echo "$cache_dir" ;; + *) + printf 'Unknown command: %s\n' "$1" >&2 + exit 1 + ;; +esac diff --git a/scripts/menu/xclipmenu/clipdel b/scripts/menu/xclipmenu/clipdel new file mode 100755 index 0000000..459e213 --- /dev/null +++ b/scripts/menu/xclipmenu/clipdel @@ -0,0 +1,95 @@ +#!/usr/bin/env bash + +CM_REAL_DELETE=0 +if [[ $1 == -d ]]; then + CM_REAL_DELETE=1 + shift +fi + +shopt -s nullglob + +cache_dir=$(clipctl cache-dir) +cache_file=$cache_dir/line_cache +lock_file=$cache_dir/lock +lock_timeout=2 + +if [[ $1 == --help ]] || [[ $1 == -h ]]; then + cat << 'EOF' +clipdel deletes clipmenu entries matching a regex. By default, just lists what +it would delete, pass -d to do it for real. If no pattern is passed as an argument, +it will try to read one from standard input. + +".*" is special, it will just nuke the entire data directory, including the +line caches and all other state. + +Arguments: + + -d Delete for real. + +Environment variables: + +- $CM_DIR: specify the base directory to store the cache dir in (default: $XDG_RUNTIME_DIR, $TMPDIR, or /tmp) +EOF + exit 0 +fi + +if ! [[ -f $cache_file ]]; then + printf '%s\n' "No line cache file found, no clips exist" >&2 + exit 0 # Well, this is a kind of success... +fi + +if [[ -n $1 ]]; then + raw_pattern=$1 +elif ! [[ -t 0 ]]; then + IFS= read -r raw_pattern +fi + +esc_pattern=${raw_pattern//\#/'\#'} + +# We use 2 separate sed commands so "esc_pattern" matches only the 'clip' text +# without the timestamp (e.g. $> clipdel '^delete_exact_match$') +sed_common_command="s#^[0-9]\+ ##;\\#${esc_pattern}#" + +if ! [[ $raw_pattern ]]; then + printf '%s\n' 'No pattern provided, see --help' >&2 + exit 2 +elif [[ "$raw_pattern" == ".*" ]]; then + delete_cache_dir=1 +else + mapfile -t matches < <( + sed -n "${sed_common_command}p" "$cache_file" | + sort -u + ) +fi + +exec {lock_fd}> "$lock_file" + +if (( CM_REAL_DELETE )); then + if (( delete_cache_dir )); then + flock -x -w "$lock_timeout" "$lock_fd" || exit + rm -rf -- "$cache_dir" + mkdir -p -- "$cache_dir" + exit 0 + else + flock -x -w "$lock_timeout" "$lock_fd" || exit + + for match in "${matches[@]}"; do + ck=$(cksum <<< "$match") + rm -f -- "$cache_dir/$ck" + done + + temp=$(mktemp) + # sed 'h' and 'g' here means save and restore the line, so + # timestamps are not removed from non-deleted lines. 'd' deletes the + # line and restarts, skipping 'g'/restore. + # https://www.gnu.org/software/sed/manual/html_node/Other-Commands.html#Other-Commands + sed "h;${sed_common_command}d;g" "$cache_file" > "$temp" + mv -- "$temp" "$cache_file" + + flock -u "$lock_fd" + fi +elif (( delete_cache_dir )); then + printf 'delete cache dir: %s\n' "$cache_dir" +elif (( ${#matches[@]} )); then + printf '%s\n' "${matches[@]}" +fi diff --git a/scripts/menu/xclipmenu/clipfsck b/scripts/menu/xclipmenu/clipfsck new file mode 100755 index 0000000..a9c749d --- /dev/null +++ b/scripts/menu/xclipmenu/clipfsck @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +shopt -s nullglob + +cache_dir=$(clipctl cache-dir) +cache_file=$cache_dir/line_cache + +declare -A cksums + +while IFS= read -r line; do + cksum=$(cksum <<< "$line") + cksums["$cksum"]="$line" + + # Are all cache entries represented by a file? + full_file=$cache_dir/$cksum + if ! [[ -f $full_file ]]; then + printf 'cache entry without file: %s -> %s\n' "$line" "$full_file" >&2 + fi +done < <(cut -d' ' -f2- < "$cache_file") + +# Are all files represented by a cache entry? +for file in "$cache_dir"/[012346789]*; do + cksum=${file##*/} + line=${cksums["$cksum"]-_missing_} + if [[ $line == _missing_ ]]; then + printf 'file without cache entry: %s\n' "$file" + fi +done diff --git a/scripts/menu/xclipmenu/clipmenu b/scripts/menu/xclipmenu/clipmenu new file mode 100755 index 0000000..07d985e --- /dev/null +++ b/scripts/menu/xclipmenu/clipmenu @@ -0,0 +1,72 @@ +#!/usr/bin/env bash + +: "${CM_LAUNCHER=dmenu}" +: "${CM_HISTLENGTH=8}" + +shopt -s nullglob + +cache_dir=$(clipctl cache-dir) +cache_file=$cache_dir/line_cache + +# Not -h, see #142 +if [[ $1 == --help ]]; then + cat << 'EOF' +clipmenu is a simple clipboard manager using dmenu and xsel. Launch this +when you want to select a clip. + +All arguments are passed through to dmenu itself. + +Environment variables: + +- $CM_DIR: specify the base directory to store the cache dir in (default: $XDG_RUNTIME_DIR, $TMPDIR, or /tmp) +- $CM_HISTLENGTH: specify the number of lines to show in dmenu/rofi (default: 8) +- $CM_LAUNCHER: specify a dmenu-compatible launcher (default: dmenu) +- $CM_OUTPUT_CLIP: if set, output clip selection to stdout +EOF + exit 0 +fi + +if ! [[ -f "$cache_file" ]]; then + printf '%s\n' 'No cache file yet, did you run clipmenud?' + exit 2 +fi + +# Blacklist of non-dmenu launchers +launcher_args=(-l "${CM_HISTLENGTH}") +if [[ "$CM_LAUNCHER" == fzf ]]; then + launcher_args=() +fi + +# rofi supports dmenu-like arguments through the -dmenu flag. -p wastes space +# in real dmenu, but rofi shows "dmenu:" anyway, so pass it here only. +[[ "$CM_LAUNCHER" == rofi ]] && set -- -dmenu -p clipmenu "$@" + +list_clips() { + LC_ALL=C sort -rnk 1 < "$cache_file" | cut -d' ' -f2- | awk '!seen[$0]++' +} + +if [[ "$CM_LAUNCHER" == rofi-script ]]; then + if (( $# )); then + chosen_line="${!#}" + else + list_clips + exit + fi +else + chosen_line=$(list_clips | "$CM_LAUNCHER" "${launcher_args[@]}" "$@") + launcher_exit=$? +fi + +[[ $chosen_line ]] || exit 1 +file=$cache_dir/$(cksum <<< "$chosen_line") +[[ -f "$file" ]] || exit 2 + +for selection in clipboard primary; do + xsel --logfile /dev/null -i --"$selection" < "$file" +done + +if (( CM_OUTPUT_CLIP )); then + cat "$file" +fi + +exit "${launcher_exit:-"$?"}" diff --git a/scripts/menu/xclipmenu/clipmenud b/scripts/menu/xclipmenu/clipmenud new file mode 100755 index 0000000..a7a4109 --- /dev/null +++ b/scripts/menu/xclipmenu/clipmenud @@ -0,0 +1,272 @@ +#!/usr/bin/env bash + +: "${CM_ONESHOT=0}" +: "${CM_OWN_CLIPBOARD=0}" +: "${CM_SYNC_PRIMARY_TO_CLIPBOARD=0}" +: "${CM_SYNC_CLIPBOARD_TO_PRIMARY=0}" +: "${CM_DEBUG=0}" + +: "${CM_MAX_CLIPS:=1000}" +# Buffer to batch to avoid calling too much. Only used if CM_MAX_CLIPS >0. +CM_MAX_CLIPS_THRESH=$(( CM_MAX_CLIPS + 10 )) + +: "${CM_SELECTIONS:=clipboard primary}" +read -r -a selections <<< "$CM_SELECTIONS" + +cache_dir=$(clipctl cache-dir) +cache_file=$cache_dir/line_cache +status_file=$cache_dir/status + +# lock_file: lock for *one* iteration of clipboard capture/propagation +# session_lock_file: lock to prevent multiple clipmenud daemons +lock_file=$cache_dir/lock +session_lock_file=$cache_dir/session_lock +lock_timeout=2 +has_xdotool=0 + +_xsel() { timeout 1 xsel --logfile /dev/null "$@"; } + +error() { printf 'ERROR: %s\n' "${1?}" >&2; } +info() { printf 'INFO: %s\n' "${1?}"; } +die() { + error "${2?}" + exit "${1?}" +} + +make_line_cksums() { while read -r line; do cksum <<< "${line#* }"; done; } + +get_first_line() { + data=${1?} + + # We look for the first line matching regex /./ here because we want the + # first line that can provide reasonable context to the user. + awk -v limit=300 ' + BEGIN { printed = 0; } + printed == 0 && NF { + $0 = substr($0, 0, limit); + printf("%s", $0); + printed = 1; + } + END { + if (NR > 1) + printf(" (%d lines)", NR); + printf("\n"); + }' <<< "$data" +} + +debug() { (( CM_DEBUG )) && printf '%s\n' "$@" >&2; } + +sig_disable() { + if (( _CM_DISABLED )); then + info "Received disable signal but we're already disabled, so doing nothing" + return + fi + + info "Received disable signal, suspending clipboard capture" + _CM_DISABLED=1 + echo "disabled" > "$status_file" +} + +sig_enable() { + if ! (( _CM_DISABLED )); then + info "Received enable signal but we're already enabled, so doing nothing" + return + fi + + # Still store the last data so we don't end up eventually putting it in the + # clipboard if it wasn't changed + for selection in "${selections[@]}"; do + data=$(_xsel -o --"$selection"; printf x) + last_data_sel[$selection]=${data%x} + done + + info "Received enable signal, resuming clipboard capture" + _CM_DISABLED=0 + echo "enabled" > "$status_file" +} + +kill_background_jobs() { + # While we usually _are_, there are no guarantees that we're the process + # group leader. As such, all we can do is look at the pending jobs. Bash + # avoids a subshell here, so the job list is in the right shell. + local -a bg + readarray -t bg < <(jobs -p) + + # Don't log `kill' failures, since with KillMode=control-group, we're + # racing with init. + (( ${#bg[@]} )) && kill -- "${bg[@]}" 2>/dev/null +} + +# Avoid clipmenu showing "no cache file yet" if we launched it before selecting +# anything +touch -- "$cache_file" + +if [[ $1 == --help ]] || [[ $1 == -h ]]; then + cat << 'EOF' +clipmenud collects and caches what's on the clipboard. You can manage its +operation with clipctl. + +Environment variables: + +- $CM_DEBUG: turn on debugging output (default: 0) +- $CM_DIR: specify the base directory to store the cache dir in (default: $XDG_RUNTIME_DIR, $TMPDIR, or /tmp) +- $CM_MAX_CLIPS: soft maximum number of clips to store, 0 for inf. At $CM_MAX_CLIPS + 10, the number of clips is reduced to $CM_MAX_CLIPS (default: 1000) +- $CM_ONESHOT: run once immediately, do not loop (default: 0) +- $CM_OWN_CLIPBOARD: take ownership of the clipboard. Note: this may cause missed copies if some other application also handles the clipboard directly (default: 0) +- $CM_SELECTIONS: space separated list of the selections to manage (default: "clipboard primary") +- $CM_SYNC_PRIMARY_TO_CLIPBOARD: sync selections from primary to clipboard immediately (default: 0) +- $CM_SYNC_CLIPBOARD_TO_PRIMARY: sync selections from clipboard to primary immediately (default: 0) +- $CM_IGNORE_WINDOW: disable recording the clipboard in windows where the windowname matches the given regex (e.g. a password manager), do not ignore any windows if unset or empty (default: unset) +EOF + exit 0 +fi + +[[ $DISPLAY ]] || die 2 'The X display is unset, is your X server running?' + +# It's ok that this only applies to the final directory. +# shellcheck disable=SC2174 +mkdir -p -m0700 "$cache_dir" +echo "enabled" > "$status_file" + +exec {session_lock_fd}> "$session_lock_file" +flock -x -n "$session_lock_fd" || + die 2 "Can't lock session file -- is another clipmenud running?" + +declare -A last_data_sel +declare -A updated_sel + +command -v clipnotify >/dev/null 2>&1 || die 2 "clipnotify not in PATH" +command -v xdotool >/dev/null 2>&1 && has_xdotool=1 + +if [[ $CM_IGNORE_WINDOW ]] && ! (( has_xdotool )); then + echo "WARN: CM_IGNORE_WINDOW does not work without xdotool, which is not installed" >&2 +fi + +exec {lock_fd}> "$lock_file" + +trap '_CM_TRAP=1; sig_disable' USR1 +trap '_CM_TRAP=1; sig_enable' USR2 +trap 'trap - INT TERM EXIT; kill_background_jobs; exit 0' INT TERM EXIT + +while true; do + if ! (( CM_ONESHOT )); then + # Make sure we're interruptible for the sig_{en,dis}able traps + clipnotify & + _CM_CLIPNOTIFY_PID="$!" + if ! wait "$_CM_CLIPNOTIFY_PID" && ! (( _CM_TRAP )); then + # X server dead? + sleep 10 + continue + fi + fi + + # Trapping a signal breaks the `wait` + if (( _CM_TRAP )); then + # Prevent spawning another clipnotify job restarting the loop + kill_background_jobs + unset _CM_TRAP + continue + fi + + if (( _CM_DISABLED )); then + info "Got a clipboard notification, but we are disabled, skipping" + continue + fi + + if [[ $CM_IGNORE_WINDOW ]] && (( has_xdotool )); then + windowname="$(xdotool getactivewindow getwindowname)" + if [[ "$windowname" =~ $CM_IGNORE_WINDOW ]]; then + debug "ignoring clipboard because windowname \"$windowname\" matches \"${CM_IGNORE_WINDOW}\"" + continue + fi + fi + + if ! flock -x -w "$lock_timeout" "$lock_fd"; then + if (( CM_ONESHOT )); then + die 1 "Timed out waiting for lock" + else + error "Timed out waiting for lock, skipping this iteration" + continue + fi + fi + + for selection in "${selections[@]}"; do + updated_sel[$selection]=0 + + data=$(_xsel -o --"$selection"; printf x) + data=${data%x} # avoid trailing newlines being stripped + + [[ $data == *[^[:space:]]* ]] || continue + [[ $last_data == "$data" ]] && continue + [[ ${last_data_sel[$selection]} == "$data" ]] && continue + + if [[ $last_data && $data == "$last_data"* ]] || + [[ $last_data && $data == *"$last_data" ]]; then + # Don't actually remove the file yet, because it might be + # referenced by an older entry. These will be dealt with at vacuum. + debug "$selection: $last_data is a possible partial of $data" + previous_size=$(wc -c <<< "$last_cache_file_output") + truncate -s -"$previous_size" "$cache_file" + fi + + first_line=$(get_first_line "$data") + debug "New clipboard entry on $selection selection: \"$first_line\"" + + cache_file_output="$(date +%s%N) $first_line" + filename="$cache_dir/$(cksum <<< "$first_line")" + last_cache_file_output=$cache_file_output + last_data=$data + last_data_sel[$selection]=$data + updated_sel[$selection]=1 + + debug "Writing $data to $filename" + printf '%s' "$data" > "$filename" + debug "Writing $cache_file_output to $cache_file" + printf '%s\n' "$cache_file_output" >> "$cache_file" + + if (( CM_OWN_CLIPBOARD )) && [[ $selection == clipboard ]]; then + # Only clipboard, since apps like urxvt will unhilight for PRIMARY + _xsel -o --clipboard | _xsel -i --clipboard + fi + done + + if (( CM_SYNC_PRIMARY_TO_CLIPBOARD )) && (( updated_sel[primary] )); then + _xsel -o --primary | _xsel -i --clipboard + fi + if (( CM_SYNC_CLIPBOARD_TO_PRIMARY )) && (( updated_sel[clipboard] )); then + _xsel -o --clipboard | _xsel -i --primary + fi + + # The cache file may not exist if this is the first run and data is skipped + if (( CM_MAX_CLIPS )) && [[ -f "$cache_file" ]] && (( "$(wc -l < "$cache_file")" > CM_MAX_CLIPS_THRESH )); then + info "Trimming clip cache to CM_MAX_CLIPS ($CM_MAX_CLIPS)" + trunc_tmp=$(mktemp) + tail -n "$CM_MAX_CLIPS" "$cache_file" | uniq > "$trunc_tmp" + mv -- "$trunc_tmp" "$cache_file" + + # Vacuum up unreferenced clips. They may either have been + # unreferenced by the above CM_MAX_CLIPS code, or they may be old + # possible partials. + declare -A cksums + while IFS= read -r line; do + cksum=$(cksum <<< "$line") + cksums["$cksum"]="$line" + done < <(cut -d' ' -f2- < "$cache_file") + + num_vacuumed=0 + for file in "$cache_dir"/[012346789]*; do + cksum=${file##*/} + if [[ ${cksums["$cksum"]-_missing_} == _missing_ ]]; then + debug "Vacuuming due to lack of reference: $file" + (( ++num_vacuumed )) + rm -- "$file" + fi + done + unset cksums + info "Vacuumed $num_vacuumed clip files." + fi + + flock -u "$lock_fd" + + (( CM_ONESHOT )) && break +done diff --git a/scripts/menu/xclipmenu/clipnotify-master/LICENSE b/scripts/menu/xclipmenu/clipnotify-master/LICENSE new file mode 100644 index 0000000..ea9256a --- /dev/null +++ b/scripts/menu/xclipmenu/clipnotify-master/LICENSE @@ -0,0 +1,5 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. diff --git a/scripts/menu/xclipmenu/clipnotify-master/Makefile b/scripts/menu/xclipmenu/clipnotify-master/Makefile new file mode 100644 index 0000000..ae81666 --- /dev/null +++ b/scripts/menu/xclipmenu/clipnotify-master/Makefile @@ -0,0 +1,17 @@ +PREFIX ?= /usr/local + +x11_bsd_flags = -I/usr/X11R6/include -L/usr/X11R6/lib + +all: + ${CC} ${CFLAGS} ${LDFLAGS} clipnotify.c -o clipnotify $(x11_bsd_flags) -lX11 -lXfixes + +install: all + mkdir -p ${DESTDIR}${PREFIX}/bin + cp -f clipnotify ${DESTDIR}${PREFIX}/bin + chmod 755 ${DESTDIR}${PREFIX}/bin/clipnotify + +uninstall: + rm -f ${DESTDIR}${PREFIX}/bin/clipnotify + +clean: + rm -f *.o *~ clipnotify diff --git a/scripts/menu/xclipmenu/clipnotify-master/README.md b/scripts/menu/xclipmenu/clipnotify-master/README.md new file mode 100644 index 0000000..9c20582 --- /dev/null +++ b/scripts/menu/xclipmenu/clipnotify-master/README.md @@ -0,0 +1,27 @@ +clipnotify is a simple program that, using the +[XFIXES](https://cgit.freedesktop.org/xorg/proto/fixesproto/plain/fixesproto.txt) +extension to X11, waits until a new selection is available and then exits. + +It was primarily designed for [clipmenu](https://github.com/cdown/clipmenu), to +avoid polling for new selections. + +Here's how it's intended to be used: + + while read; do + [an event happened, do something with the selection] + done < <(clipnotify -l) + +Or: + + while clipnotify; do + [an event happened, do something with the selection] + done + +clipnotify doesn't try to print anything about the contents of the selection, +it just exits when it changes. This is intentional -- X11's selection API is +verging on the insane, and there are plenty of others who have already lost +their sanity to bring us xclip/xsel/etc. Use one of those tools to complement +clipnotify. + +You can choose a particular selection with `-s`, and loop instead of exiting +with `-l`. See `clipmenu -h` for more information. diff --git a/scripts/menu/xclipmenu/clipnotify-master/clipnotify.c b/scripts/menu/xclipmenu/clipnotify-master/clipnotify.c new file mode 100644 index 0000000..c5de7ac --- /dev/null +++ b/scripts/menu/xclipmenu/clipnotify-master/clipnotify.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include +#include + +static enum selections { + NONE = 0, + SELECTION_CLIPBOARD = (1 << 0), + SELECTION_PRIMARY = (1 << 1), + SELECTION_SECONDARY = (1 << 2) +} selections = NONE; + +static int loop; + +int main(int argc, char *argv[]) { + static const char *usage = + "%s: Notify by exiting on clipboard events.\n\n" + " -l Instead of exiting, print a newline when a new selection is available.\n" + " -s The selection to use. Available selections:\n" + " clipboard, primary, secondary\n" + " The default is to monitor clipboard and primary.\n"; + Display *disp; + Window root; + Atom clip; + XEvent evt; + int opt; + + while ((opt = getopt(argc, argv, "hs:l")) != -1) { + switch (opt) { + case 'h': + printf(usage, argv[0]); + return EXIT_SUCCESS; + case 'l': + loop = 1; + break; + case 's': { + char *token = strtok(optarg, ","); + while (token != NULL) { + if (strcmp(token, "clipboard") == 0) { + selections |= SELECTION_CLIPBOARD; + } else if (strcmp(token, "primary") == 0) { + selections |= SELECTION_PRIMARY; + } else if (strcmp(token, "secondary") == 0) { + selections |= SELECTION_SECONDARY; + } else { + fprintf(stderr, "Unknown selection '%s'\n", token); + return EXIT_FAILURE; + } + token = strtok(NULL, ","); + } + break; + } + default: + fprintf(stderr, usage, argv[0]); + return EXIT_FAILURE; + } + } + + disp = XOpenDisplay(NULL); + if (!disp) { + fprintf(stderr, "Can't open X display\n"); + return EXIT_FAILURE; + } + + root = DefaultRootWindow(disp); + + clip = XInternAtom(disp, "CLIPBOARD", False); + + /* <= 1.0.2 backwards compatibility */ + if (!selections) + selections = SELECTION_CLIPBOARD | SELECTION_PRIMARY; + + if (selections & SELECTION_CLIPBOARD) + XFixesSelectSelectionInput(disp, root, clip, + XFixesSetSelectionOwnerNotifyMask); + if (selections & SELECTION_PRIMARY) + XFixesSelectSelectionInput(disp, root, XA_PRIMARY, + XFixesSetSelectionOwnerNotifyMask); + if (selections & SELECTION_SECONDARY) + XFixesSelectSelectionInput(disp, root, XA_SECONDARY, + XFixesSetSelectionOwnerNotifyMask); + + if (loop) { + (void)setvbuf(stdout, NULL, _IONBF, 0); + do { + XNextEvent(disp, &evt); + printf("\n"); + } while (1); + } else { + XNextEvent(disp, &evt); + } + XCloseDisplay(disp); +} diff --git a/shell/keybinds b/shell/keybinds index 81d420d..ab66200 100644 --- a/shell/keybinds +++ b/shell/keybinds @@ -1,6 +1,5 @@ #!/bin/bash bind '"\C-e":"dragon -x \* 2>/dev/null\C-m"' -bind '"\C-y":"copy_history\C-m"' +bind '"\C-h":"copy_history\C-m"' bind '"\C-f":"fzf_nav\C-m"' -bind '"\C-n":"fzf_nav\C-m"' diff --git a/vim/vimrc b/vim/vimrc index 26f7875..a29591c 100644 --- a/vim/vimrc +++ b/vim/vimrc @@ -122,7 +122,6 @@ Plug 'junegunn/goyo.vim' Plug 'mhinz/vim-signify' Plug 'ibhagwan/fzf-lua' Plug 'morhetz/gruvbox' -Plug 'jalvesaq/Nvim-R' Plug 'instant-markdown/vim-instant-markdown' call plug#end() diff --git a/wrappers/rstudio b/wrappers/rstudio new file mode 100755 index 0000000..4619270 --- /dev/null +++ b/wrappers/rstudio @@ -0,0 +1,5 @@ +#!/usr/bin/env sh + +HOME=$HOME/.local/share/Rstudio +mkdir -p "$HOME" +exec /usr/bin/rstudio "$@"