In order for this to scale, I need to solve two things: 1. Ad-hoc ignore fill-column rules for URLs and other exceptions. 2. Run Elisp flychecker without evaluating my Elisp code and firing its side-effects.
		
			
				
	
	
		
			138 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			EmacsLisp
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			EmacsLisp
		
	
	
	
	
	
| ;;; ivy-clipmenu.el --- Emacs client for clipmenu -*- lexical-binding: t -*-
 | |
| 
 | |
| ;; Author: William Carroll <wpcarro@gmail.com>
 | |
| ;; Version: 0.0.1
 | |
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase
 | |
| ;; Package-Requires: ((emacs "25.1"))
 | |
| 
 | |
| ;;; Commentary:
 | |
| ;; Ivy integration with the clipboard manager, clipmenu.  Essentially, clipmenu
 | |
| ;; turns your system clipboard into a list.
 | |
| ;;
 | |
| ;; To use this module, you must first install clipmenu and ensure that the
 | |
| ;; clipmenud daemon is running.  Refer to the installation instructions at
 | |
| ;; github.com/cdown/clipmenu for those details.
 | |
| ;;
 | |
| ;; This module intentionally does not define any keybindings since I'd prefer
 | |
| ;; not to presume my users' preferences.  Personally, I use EXWM as my window
 | |
| ;; manager, so I call `exwm-input-set-key' and map it to `ivy-clipmenu-copy'.
 | |
| ;;
 | |
| ;; Usually clipmenu integrates with rofi or dmenu.  This Emacs module integrates
 | |
| ;; with ivy.  Launch this when you want to select a clip.
 | |
| ;;
 | |
| ;; Clipmenu itself supports a variety of environment variables that allow you to
 | |
| ;; customize its behavior.  These variables are respected herein.  If you'd
 | |
| ;; prefer to customize clipmenu's behavior from within Emacs, refer to the
 | |
| ;; variables defined in this module.
 | |
| ;;
 | |
| ;; For more information:
 | |
| ;; - See `clipmenu --help`.
 | |
| ;; - Visit github.com/cdown/clipmenu.
 | |
| 
 | |
| ;;; Code:
 | |
| 
 | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | |
| ;; Dependencies
 | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | |
| 
 | |
| (require 'f)
 | |
| (require 's)
 | |
| (require 'dash)
 | |
| (require 'ivy)
 | |
| 
 | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | |
| ;; Variables
 | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | |
| 
 | |
| (defgroup ivy-clipmenu nil
 | |
|   "Ivy integration for clipmenu."
 | |
|   :group 'ivy)
 | |
| 
 | |
| (defcustom ivy-clipmenu-directory
 | |
|   (or (getenv "XDG_RUNTIME_DIR")
 | |
|       (getenv "TMPDIR")
 | |
|       "/tmp")
 | |
|   "Base directory for clipmenu's data."
 | |
|   :type 'string
 | |
|   :group 'ivy-clipmenu)
 | |
| 
 | |
| (defconst ivy-clipmenu-executable-version 5
 | |
|    "The major version number for the clipmenu executable.")
 | |
| 
 | |
| (defconst ivy-clipmenu-cache-directory
 | |
|   (f-join ivy-clipmenu-directory
 | |
|           (format "clipmenu.%s.%s"
 | |
|                   ivy-clipmenu-executable-version
 | |
|                   (getenv "USER")))
 | |
|   "Directory where the clips are stored.")
 | |
| 
 | |
| (defconst ivy-clipmenu-cache-file-pattern
 | |
|   (f-join ivy-clipmenu-cache-directory "line_cache_*")
 | |
|   "Glob pattern matching the locations on disk for clipmenu's labels.")
 | |
| 
 | |
| (defcustom ivy-clipmenu-history-length
 | |
|   (or (getenv "CM_HISTLENGTH") 25)
 | |
|   "Limit the number of clips in the history.
 | |
| This value defaults to 25.")
 | |
| 
 | |
| (defvar ivy-clipmenu-history nil
 | |
|   "History for `ivy-clipmenu-copy'.")
 | |
| 
 | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | |
| ;; Functions
 | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | |
| 
 | |
| (defun ivy-clipmenu-parse-content (x)
 | |
|   "Parse the label from the entry, X, in clipmenu's line-cache."
 | |
|   (->> (s-split " " x)
 | |
|        (-drop 1)
 | |
|        (s-join " ")))
 | |
| 
 | |
| (defun ivy-clipmenu-list-clips ()
 | |
|   "Return a list of the content of all of the clips."
 | |
|   (->> ivy-clipmenu-cache-file-pattern
 | |
|        f-glob
 | |
|        (-map (lambda (path)
 | |
|                (s-split "\n" (f-read path) t)))
 | |
|        -flatten
 | |
|        (-reject #'s-blank?)
 | |
|        (-sort #'string>)
 | |
|        (-map #'ivy-clipmenu-parse-content)
 | |
|        delete-dups
 | |
|        (-take ivy-clipmenu-history-length)))
 | |
| 
 | |
| (defun ivy-clipmenu-checksum (content)
 | |
|   "Return the CRC checksum of CONTENT."
 | |
|   (s-trim-right
 | |
|    (with-temp-buffer
 | |
|      (call-process "/bin/bash" nil (current-buffer) nil "-c"
 | |
|                    (format "cksum <<<'%s'" content))
 | |
|      (buffer-string))))
 | |
| 
 | |
| (defun ivy-clipmenu-line-to-content (line)
 | |
|   "Map the chosen LINE from the line cache its content from disk."
 | |
|   (->> line
 | |
|        ivy-clipmenu-checksum
 | |
|        (f-join ivy-clipmenu-cache-directory)
 | |
|        f-read))
 | |
| 
 | |
| (defun ivy-clipmenu-do-copy (x)
 | |
|   "Copy string, X, to the system clipboard."
 | |
|   (kill-new x)
 | |
|   (message "[ivy-clipmenu.el] Copied!"))
 | |
| 
 | |
| (defun ivy-clipmenu-copy ()
 | |
|   "Use `ivy-read' to select and copy a clip.
 | |
| It's recommended to bind this function to a globally available keymap."
 | |
|   (interactive)
 | |
|   (let ((ivy-sort-functions-alist nil))
 | |
|     (ivy-read "Clipmenu: "
 | |
|               (ivy-clipmenu-list-clips)
 | |
|               :history 'ivy-clipmenu-history
 | |
|               :action (lambda (line)
 | |
|                         (->> line
 | |
|                              ivy-clipmenu-line-to-content
 | |
|                              ivy-clipmenu-do-copy)))))
 | |
| 
 | |
| (provide 'ivy-clipmenu)
 | |
| ;;; ivy-clipmenu.el ends here
 |