You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
596 lines
24 KiB
596 lines
24 KiB
;;; clipmon.el --- Clipboard monitor - watch system clipboard, add changes to kill ring/autoinsert
|
|
;;
|
|
;; Copyright (c) 2015-2016 Brian Burns
|
|
;;
|
|
;; Author: Brian Burns <bburns.km@gmail.com>
|
|
;; URL: https://github.com/bburns/clipmon
|
|
;; Keywords: convenience
|
|
;; Version: 20160925
|
|
;;
|
|
;; This package is NOT part of GNU Emacs.
|
|
;;
|
|
;; This program is free software; you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
;; (at your option) any later version.
|
|
;;
|
|
;; This program is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
;;
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
;;
|
|
;;
|
|
;;; Commentary:
|
|
;;
|
|
;;;; Description
|
|
;; ----------------------------------------------------------------------------
|
|
;;
|
|
;; Clipmon is a clipboard monitor - it watches the system clipboard and can
|
|
;; automatically insert any new text into the current location in Emacs.
|
|
;;
|
|
;; It also adds changes to the system clipboard to the kill ring, making Emacs
|
|
;; into a clipboard manager for text - you can then use a package like
|
|
;; browse-kill-ring or helm-ring to view and manage your clipboard history.
|
|
;;
|
|
;; **Warning (2015-12-24): in an X-windows system with clipmon-mode on, bringing
|
|
;; up a graphical menu (e.g. Shift+Mouse-1) will cause Emacs to hang. See
|
|
;; http://debbugs.gnu.org/cgi/bugreport.cgi?bug=22214.
|
|
;; X-windows starts a timer when checking the contents of the clipboard, which
|
|
;; interferes with the clipmon timer.**
|
|
;;
|
|
;; Update (2016-01-27): in an X-windows system, Clipmon now uses the clipboard
|
|
;; instead of the primary selection - see https://github.com/bburns/clipmon/issues/4.
|
|
;;
|
|
;; You can use Clipmon for taking notes from a webpage, for example - just copy the
|
|
;; text you want to save and it will be added to Emacs. It helps to have an
|
|
;; autocopy feature or addon for the browser, e.g. AutoCopy 2 for Firefox - then
|
|
;; you can just select text to add it to Emacs.
|
|
;;
|
|
;; Here's a diagram - text flows from the top to the bottom:
|
|
;;
|
|
;; +---------------------+
|
|
;; | Other programs |+
|
|
;; +---------------------+|
|
|
;; +---------------------+
|
|
;; /
|
|
;; +-----------+
|
|
;; | System |
|
|
;; | clipboard |
|
|
;; +-----------+
|
|
;; OS /
|
|
;; ---------------------------------------------------
|
|
;; Emacs /
|
|
;; /
|
|
;; +--------------+ +---------------+
|
|
;; | clipmon-mode |......| autoinsert |
|
|
;; +--------------+ +---------------+
|
|
;; | .
|
|
;; +-----------+ .
|
|
;; | Emacs ++ .
|
|
;; | kill ring ++ +--------------+
|
|
;; +-----------+|+ | transforms |
|
|
;; +-----------+| +--------------+
|
|
;; +-----------+ .
|
|
;; | .
|
|
;; | yank . autoinsert
|
|
;; +--------------------------+
|
|
;; | Emacs buffer |
|
|
;; +--------------------------+
|
|
;;
|
|
;;
|
|
;; The solid line is turned on and off with `clipmon-mode', while the dotted
|
|
;; line is turned on and off with `clipmon-autoinsert-toggle', usually bound to a key.
|
|
;; There are also various transformations you can perform on the text, e.g.
|
|
;; adding newlines to the end.
|
|
;;
|
|
;; (Emacs's kill-ring is like the system clipboard but with multiple items in
|
|
;; it. If you copy a bunch of things in another program, Emacs normally only
|
|
;; knows about the last one copied, but with clipmon mode on, it will monitor
|
|
;; the system clipboard and add any new text it sees to the kill ring.)
|
|
;;
|
|
;;
|
|
;;;; Installation
|
|
;; ----------------------------------------------------------------------------
|
|
;;
|
|
;; It's simplest to use the package manager:
|
|
;;
|
|
;; M-: (package-install 'clipmon)
|
|
;;
|
|
;; It will then be ready to use, and will also be available the next time you
|
|
;; start Emacs.
|
|
;;
|
|
;;
|
|
;;;; Usage
|
|
;; ----------------------------------------------------------------------------
|
|
;;
|
|
;; To give it a try, do M-: (clipmon-autoinsert-toggle) - this will turn on
|
|
;; autoinsert. Then go to another application and copy some text to the
|
|
;; clipboard - clipmon should detect it after a second or two and make a beep.
|
|
;; If you switch back to Emacs, the text should be there in your buffer.
|
|
;;
|
|
;; Note that you can still yank and pull text in Emacs as usual while autoinsert
|
|
;; is on, since it only monitors the system clipboard.
|
|
;;
|
|
;; You can turn off autoinsert with the same command - to add a keybinding to it
|
|
;; add something like this to your init file:
|
|
;;
|
|
;; (global-set-key (kbd "<M-f2>") 'clipmon-autoinsert-toggle)
|
|
;;
|
|
;; You can also turn it on and off from the Options menu.
|
|
;;
|
|
;; Also, if no change is detected after a certain number of minutes, autoinsert will
|
|
;; turn itself off automatically with another beep. This is so you don't forget
|
|
;; that autoinsert is on and accidentally add text to your buffer.
|
|
;;
|
|
;; And note: if you happen to copy the same text to the clipboard twice, clipmon
|
|
;; won't know about the second time, as it only detects changes. And if you copy
|
|
;; text faster than the timer interval is set it may miss some changes, but you
|
|
;; can adjust the interval.
|
|
;;
|
|
;;
|
|
;;;; Using as a clipboard manager
|
|
;; ----------------------------------------------------------------------------
|
|
;;
|
|
;; To try out clipmon as a clipboard manager, make sure clipmon-mode is on by
|
|
;; doing M-: (clipmon-mode 1) (also accessible from the Options menu) and that
|
|
;; autoinsert is off, then copy a few pieces of text from another program (more
|
|
;; slowly than the default timer interval of 2 seconds though). Switch back to
|
|
;; Emacs, and see that you can yank any of the text back with C-y, M-y, M-y...
|
|
;;
|
|
;; Note that when you turn on autoinsert, it also turns on clipmon-mode, to
|
|
;; capture text to the kill ring, but if you'd like to turn on clipmon-mode
|
|
;; automatically, you can add this to your init file:
|
|
;;
|
|
;; ;; monitor the system clipboard and add any changes to the kill ring
|
|
;; (add-to-list 'after-init-hook 'clipmon-mode-start)
|
|
;;
|
|
;; You can also use the package browse-kill-ring to manage the kill ring - you
|
|
;; can install it with M-: (package-install 'browse-kill-ring), then call
|
|
;; `browse-kill-ring' to see the contents of the kill ring, insert from it,
|
|
;; delete items, etc. Helm also has a package called helm-ring, with the
|
|
;; function `helm-show-kill-ring'.
|
|
;;
|
|
;; You can persist the kill ring between sessions if you'd like (though note
|
|
;; that this might involve writing sensitive information like passwords to the
|
|
;; disk - although you could always delete such text from the kill ring with
|
|
;; `browse-kill-ring-delete'). To do so, add this to your init file:
|
|
;;
|
|
;; ;; persist the kill ring between sessions
|
|
;; (add-to-list 'after-init-hook 'clipmon-persist)
|
|
;;
|
|
;; This will use Emacs's savehist library to save the kill ring, both at the end
|
|
;; of the session and at set intervals. However, savehist also saves various
|
|
;; other settings by default, including the minibuffer history - see
|
|
;; `savehist-mode' for more details. To change the autosave interval, add
|
|
;; something like this:
|
|
;;
|
|
;; (setq savehist-autosave-interval (* 5 60)) ; save every 5 minutes (default)
|
|
;;
|
|
;; The kill ring has a fixed number of entries which you can set, depending on
|
|
;; how much history you want to save between sessions:
|
|
;;
|
|
;; (setq kill-ring-max 500) ; default is 60 in Emacs 24.4
|
|
;;
|
|
;; To see how much space the kill-ring is taking up, you can call this function:
|
|
;;
|
|
;; (clipmon-kill-ring-total)
|
|
;; => 29670 characters
|
|
;;
|
|
;;
|
|
;;;; Options
|
|
;; ----------------------------------------------------------------------------
|
|
;;
|
|
;; There are various options you can set with customize:
|
|
;;
|
|
;; (customize-group 'clipmon)
|
|
;;
|
|
;; or set them in your init file - these are the default values:
|
|
;;
|
|
;; (setq clipmon-timer-interval 2) ; check system clipboard every n secs
|
|
;; (setq clipmon-autoinsert-sound t) ; t for included beep, or path or nil
|
|
;; (setq clipmon-autoinsert-color "red") ; color of cursor when autoinsert is on
|
|
;; (setq clipmon-autoinsert-timeout 5) ; stop autoinsert after n mins inactivity
|
|
;;
|
|
;; before inserting the text, transformations are performed on it in this order:
|
|
;;
|
|
;; (setq clipmon-transform-trim t) ; remove leading whitespace
|
|
;; (setq clipmon-transform-remove ; remove text matching this regexp
|
|
;; "\\[[0-9][0-9]?[0-9]?\\]\\|\\[citation needed\\]\\|\\[by whom?\\]")
|
|
;; (setq clipmon-transform-prefix "") ; add to start of text
|
|
;; (setq clipmon-transform-suffix "\n\n") ; add to end of text
|
|
;; (setq clipmon-transform-function nil) ; additional transform function
|
|
;;
|
|
;;
|
|
;;;; Todo
|
|
;; ----------------------------------------------------------------------------
|
|
;;
|
|
;; - Prefix with C-u to set a target point, then allow cut/copy/pasting from
|
|
;; within Emacs, eg to take notes from another buffer, or move text elsewhere.
|
|
;;
|
|
;;
|
|
;;; Code:
|
|
|
|
;;;; Renamings
|
|
;; ----------------------------------------------------------------------------
|
|
|
|
;; just renaming some things here - must come before defcustoms.
|
|
;; could remove after some time though.
|
|
|
|
(eval-when-compile ; because it's a macro
|
|
(defalias 'clipmon--rename 'define-obsolete-variable-alias))
|
|
|
|
;; rename old to new
|
|
(clipmon--rename 'clipmon-interval 'clipmon-timer-interval "20150211")
|
|
(clipmon--rename 'clipmon-cursor-color 'clipmon-autoinsert-color "20150211")
|
|
(clipmon--rename 'clipmon-sound 'clipmon-autoinsert-sound "20150211")
|
|
(clipmon--rename 'clipmon-timeout 'clipmon-autoinsert-timeout "20150211")
|
|
(clipmon--rename 'clipmon-trim 'clipmon-transform-trim "20150211")
|
|
(clipmon--rename 'clipmon-remove-regexp 'clipmon-transform-remove "20150211")
|
|
(clipmon--rename 'clipmon-prefix 'clipmon-transform-prefix "20150211")
|
|
(clipmon--rename 'clipmon-suffix 'clipmon-transform-suffix "20150211")
|
|
|
|
;; FIXME how just mark as obsolete/removed?
|
|
(clipmon--rename 'clipmon-action 'clipmon-action-obsolete "20150211")
|
|
|
|
|
|
;;;; Public settings
|
|
;; ----------------------------------------------------------------------------
|
|
|
|
(defgroup clipmon nil
|
|
"Clipboard monitor - add clipboard contents to kill ring and automatically insert."
|
|
:group 'convenience
|
|
:group 'killing)
|
|
|
|
(defcustom clipmon-timer-interval 2
|
|
"Interval for checking system clipboard for changes, in seconds."
|
|
:group 'clipmon
|
|
:type 'integer)
|
|
|
|
(defcustom clipmon-autoinsert-color "red"
|
|
"Color to set cursor when clipmon autoinsert is on. Set to nil for no change."
|
|
:group 'clipmon
|
|
:type 'color)
|
|
|
|
(defcustom clipmon-autoinsert-sound t
|
|
"Path to sound file to play on autoinsert, t for included file, or nil.
|
|
Use t for the included sound file (see
|
|
`clipmon--included-sound-file'), nil for no sound, or path to an
|
|
audio file - Emacs can play .wav or .au files."
|
|
; Note: can't use `ding' here because it doesn't make a sound when Emacs
|
|
; doesn't have focus.
|
|
:group 'clipmon
|
|
:type '(radio
|
|
(string :tag "Audio file (.wav or .au)")
|
|
(boolean :tag "Included sound file")))
|
|
|
|
(defcustom clipmon-autoinsert-timeout 5
|
|
"Stop autoinsert if no system clipboard activity after this many minutes.
|
|
Set to nil for no timeout."
|
|
:group 'clipmon
|
|
:type 'integer)
|
|
|
|
|
|
;; transforms on text - these are performed in this order
|
|
|
|
(defcustom clipmon-transform-trim t
|
|
"If non-nil, remove leading whitespace from string before autoinserting.
|
|
Often it's hard to select text without grabbing a leading space,
|
|
so this will remove it."
|
|
:group 'clipmon
|
|
:type 'boolean)
|
|
|
|
(defcustom clipmon-transform-remove
|
|
"\\[[0-9][0-9]?[0-9]?\\]\\|\\[citation needed\\]\\|\\[by whom?\\]"
|
|
"Any text matching this regexp will be removed before autoinserting.
|
|
e.g. Wikipedia-style references with 1-3 digits - [3], [115]."
|
|
:group 'clipmon
|
|
:type 'regexp)
|
|
|
|
(defcustom clipmon-transform-prefix ""
|
|
"String to add to start of clipboard contents before autoinserting."
|
|
:group 'clipmon
|
|
:type 'string)
|
|
|
|
(defcustom clipmon-transform-suffix "\n\n"
|
|
"String to add to end of clipboard contents before autoinserting.
|
|
Default is two newlines, which leaves a blank line between clips.
|
|
\(To add a newline in the customize interface, type \\[quoted-insert] C-j)."
|
|
:group 'clipmon
|
|
:type 'string)
|
|
|
|
(defcustom clipmon-transform-function nil
|
|
"Function to perform additional transformations on text before autoinserting.
|
|
Receives one argument, the clipboard text - should return the changed text.
|
|
E.g. to make the text lowercase before pasting,
|
|
(setq clipmon-transform-function (lambda (s) (downcase s)))"
|
|
:group 'clipmon
|
|
:type 'function
|
|
:risky t)
|
|
|
|
|
|
;;;; Initialize
|
|
;; ----------------------------------------------------------------------------
|
|
|
|
; add items to Options menu
|
|
;;;###autoload
|
|
(define-key-after global-map [menu-bar options clipmon-separator] ; path to new item
|
|
'(menu-item "---")
|
|
'highlight-paren-mode) ; add after this
|
|
|
|
;;;###autoload
|
|
(define-key-after global-map [menu-bar options clipmon-killring] ; path to new item
|
|
'(menu-item "Clipboard Monitor (Add to Kill Ring)"
|
|
clipmon-mode ; function to call on click
|
|
:help "Add changes to the system clipboard to Emacs's kill ring."
|
|
:button (:toggle . clipmon-mode)) ; show checkmark on/off
|
|
'clipmon-separator) ; add after this
|
|
|
|
;;;###autoload
|
|
(define-key-after global-map [menu-bar options clipmon-autoinsert] ; path to new item
|
|
'(menu-item "Clipboard Monitor Autoinsert"
|
|
clipmon-autoinsert-toggle ; function to call on click
|
|
:help "Automatically insert changes to the system clipboard at the current location."
|
|
:button (:toggle . clipmon--autoinsert)) ; show checkmark on/off
|
|
'clipmon-killring) ; add after this
|
|
|
|
|
|
;;;; Private variables
|
|
;; ----------------------------------------------------------------------------
|
|
|
|
(defvar clipmon--timer nil
|
|
"Timer handle for clipboard monitor to watch system clipboard.")
|
|
|
|
(defvar clipmon--autoinsert nil
|
|
"Non-nil if autoinsert is on.")
|
|
|
|
(defvar clipmon--autoinsert-timeout-start nil
|
|
"Time that autoinsert timeout timer was started.")
|
|
|
|
(defvar clipmon--previous-contents nil
|
|
"Last contents of the system clipboard.")
|
|
|
|
(defvar clipmon--cursor-color-original nil
|
|
"Original cursor color.")
|
|
|
|
(defconst clipmon--folder
|
|
(file-name-directory (or load-file-name (file-name-directory (buffer-file-name))))
|
|
"Path to clipmon install folder, or current buffer's location.")
|
|
|
|
(defconst clipmon--included-sound-file
|
|
(expand-file-name "clipmon.wav" clipmon--folder)
|
|
"Path to included audio file.")
|
|
|
|
|
|
|
|
;;;; Public functions
|
|
;; ----------------------------------------------------------------------------
|
|
|
|
;;;###autoload
|
|
(define-minor-mode clipmon-mode
|
|
"Start/stop clipboard monitor - watch system clipboard, add changes to kill ring.
|
|
|
|
To also insert the changes to the system clipboard at the current
|
|
location, call `clipmon-autoinsert-toggle' to turn autoinsert on
|
|
and off. See commentary in source file for more information -
|
|
M-: (find-library 'clipmon).
|
|
|
|
Upgrade note (2015-02-11): you'll need to bind your shortcut key to
|
|
`clipmon-autoinsert-toggle' instead of `clipmon-mode'."
|
|
:global t
|
|
:lighter ""
|
|
; value of clipmon-mode is toggled before this implicitly
|
|
(if clipmon-mode (clipmon-mode-start) (clipmon-mode-stop)))
|
|
|
|
|
|
;;;###autoload
|
|
(defun clipmon-mode-start ()
|
|
"Start clipboard monitor - watch system clipboard, add changes to kill ring."
|
|
(interactive)
|
|
(setq clipmon-mode t) ; in case called outside of clipmon-mode fn
|
|
(unless clipmon--timer
|
|
(setq clipmon--previous-contents (clipmon--clipboard-contents))
|
|
(setq clipmon--timer
|
|
(run-at-time nil clipmon-timer-interval 'clipmon--check-clipboard))
|
|
(message "Clipboard monitor started - watching system clipboard, adding changes to kill ring.")
|
|
))
|
|
|
|
|
|
(defun clipmon-mode-stop ()
|
|
"Stop clipboard monitor and autoinsert modes."
|
|
(interactive)
|
|
(setq clipmon-mode nil) ; in case called outside of clipmon-mode fn
|
|
(when clipmon--timer
|
|
(cancel-timer clipmon--timer)
|
|
(setq clipmon--timer nil)
|
|
(if clipmon--autoinsert (clipmon-autoinsert-stop)) ; turn off autoinsert also
|
|
(message "Clipboard monitor stopped.")
|
|
))
|
|
|
|
|
|
;;;###autoload
|
|
(defun clipmon-autoinsert-toggle ()
|
|
"Turn autoinsert on/off - watch system clipboard and insert changes.
|
|
Will change cursor color and play a sound. Text will be
|
|
transformed before insertion according to various settings - see
|
|
`clipmon--transform-text'."
|
|
(interactive)
|
|
;; note: a minor mode would toggle the value here rather than in the fns
|
|
(if clipmon--autoinsert (clipmon-autoinsert-stop) (clipmon-autoinsert-start)))
|
|
|
|
|
|
(defun clipmon-autoinsert-start ()
|
|
"Turn on autoinsert - change cursor color, play sound, insert changes."
|
|
(interactive)
|
|
(if (null clipmon--timer) (clipmon-mode-start)) ; make sure clipmon is on
|
|
(if clipmon--autoinsert
|
|
(message "Clipboard monitor autoinsert already on.")
|
|
(setq clipmon--autoinsert-timeout-start (current-time))
|
|
(when clipmon-autoinsert-color
|
|
(setq clipmon--cursor-color-original (face-background 'cursor))
|
|
(set-face-background 'cursor clipmon-autoinsert-color))
|
|
(message
|
|
"Clipboard monitor autoinsert started with timer interval %g seconds. Stop with %s."
|
|
clipmon-timer-interval
|
|
(substitute-command-keys "\\[clipmon-autoinsert-toggle]")) ; eg "<M-f2>"
|
|
(clipmon--play-sound)
|
|
(setq clipmon--autoinsert t)
|
|
))
|
|
|
|
|
|
(defun clipmon-autoinsert-stop (&optional msg)
|
|
"Turn off autoinsert - restore cursor color and play sound.
|
|
Show optional message MSG, or default message."
|
|
(interactive)
|
|
(if (null clipmon--autoinsert)
|
|
(message "Clipboard monitor autoinsert already off.")
|
|
(if clipmon--cursor-color-original
|
|
(set-face-background 'cursor clipmon--cursor-color-original))
|
|
(message (or msg "Clipboard monitor autoinsert stopped."))
|
|
(clipmon--play-sound)
|
|
(setq clipmon--autoinsert nil)
|
|
))
|
|
|
|
|
|
;;;###autoload
|
|
(defun clipmon-persist ()
|
|
"Persist the kill ring to disk using Emacs's savehist library.
|
|
Will save the kill ring at the end of the session and at various
|
|
intervals as specified by variable `savehist-autosave-interval'.
|
|
Note that savehist also includes various other Emacs settings by
|
|
default, including the minibuffer history - see function
|
|
`savehist-mode' for more details."
|
|
(require 'savehist)
|
|
(defvar savehist-additional-variables) ; for compiler warning
|
|
(add-to-list 'savehist-additional-variables 'kill-ring)
|
|
(savehist-mode 1))
|
|
|
|
|
|
;;;; Private functions
|
|
;; ----------------------------------------------------------------------------
|
|
|
|
(defun clipmon--check-clipboard ()
|
|
"Check the clipboard and call `clipmon--on-clipboard-change' if changed.
|
|
Otherwise check autoinsert idle timer and stop if it's been idle a while."
|
|
(let ((s (clipmon--clipboard-contents))) ; s may actually be nil here
|
|
(if (and s (not (string-equal s clipmon--previous-contents))) ; if not nil, and changed
|
|
(clipmon--on-clipboard-change s) ; add to kill-ring, autoinsert
|
|
;; otherwise stop autoinsert if clipboard has been idle a while
|
|
(if (and clipmon--autoinsert clipmon-autoinsert-timeout)
|
|
(let ((idle-seconds (clipmon--seconds-since clipmon--autoinsert-timeout-start)))
|
|
(when (>= idle-seconds (* 60 clipmon-autoinsert-timeout))
|
|
(clipmon-autoinsert-stop (format
|
|
"Clipboard monitor autoinsert stopped after %g minutes of inactivity."
|
|
clipmon-autoinsert-timeout))
|
|
))))))
|
|
|
|
|
|
(defun clipmon--on-clipboard-change (s)
|
|
"Clipboard changed - add text S to kill ring, and optionally insert it."
|
|
(setq clipmon--previous-contents s) ; save contents
|
|
(kill-new s) ; add to kill ring
|
|
(when clipmon--autoinsert
|
|
(setq s (clipmon--autoinsert-transform-text s))
|
|
(insert s)
|
|
(undo-boundary) ; mark a boundary between undo units
|
|
(clipmon--play-sound)
|
|
(setq clipmon--autoinsert-timeout-start (current-time)))) ; reset timeout
|
|
|
|
|
|
(defun clipmon--autoinsert-transform-text (s)
|
|
"Apply autoinsert transformations to clipboard text S."
|
|
(if clipmon-transform-trim (setq s (clipmon--trim-left s)))
|
|
(if clipmon-transform-remove
|
|
(setq s (replace-regexp-in-string clipmon-transform-remove "" s)))
|
|
(if clipmon-transform-prefix (setq s (concat clipmon-transform-prefix s)))
|
|
(if clipmon-transform-suffix (setq s (concat s clipmon-transform-suffix)))
|
|
(if clipmon-transform-function (setq s (funcall clipmon-transform-function s)))
|
|
s)
|
|
|
|
|
|
(defun clipmon--play-sound ()
|
|
"Play a user-specified sound file, the included sound file, or nothing."
|
|
(if clipmon-autoinsert-sound
|
|
(if (stringp clipmon-autoinsert-sound)
|
|
;; play-sound-file can throw an error if no sound device found
|
|
(ignore-errors (play-sound-file clipmon-autoinsert-sound))
|
|
(ignore-errors (play-sound-file clipmon--included-sound-file)))))
|
|
|
|
|
|
|
|
;;;; Library functions
|
|
;; ----------------------------------------------------------------------------
|
|
|
|
(defun clipmon-kill-ring-total ()
|
|
"Get total size of kill ring, in characters."
|
|
(let ((sum 0))
|
|
(mapc (lambda (s) (setq sum (+ sum (length s)))) kill-ring) sum))
|
|
|
|
|
|
(defun clipmon--remove-properties (s)
|
|
"Remove formatting properties from string S."
|
|
(if (null s) nil
|
|
(substring-no-properties s)))
|
|
|
|
|
|
(defun clipmon--get-selection ()
|
|
"Get the clipboard contents"
|
|
;; Note: When the OS is first started these functions will throw
|
|
;; (error "No selection is available"), so need to ignore errors.
|
|
(cond ((boundp 'mac-carbon-version-string) ; emacs mac port
|
|
;; Need to have this before emacs25 since `gui-get-selection' is also
|
|
;; bound in the mac port, but it doesn't work right
|
|
(ignore-errors (funcall interprogram-paste-function)))
|
|
((fboundp 'gui-get-selection) ; emacs25
|
|
; better to (setq selection-coding-system 'utf-8) to handle chinese,
|
|
; which is the default value for gui-get-selection etc
|
|
; because windows needs STRING. same below.
|
|
; (ignore-errors (gui-get-selection 'CLIPBOARD 'UTF8_STRING)))
|
|
(ignore-errors (gui-get-selection 'CLIPBOARD))) ; for windows needs STRING
|
|
((eq window-system 'w32) ; windows/emacs24
|
|
;; Note: (x-get-selection 'CLIPBOARD) doesn't work on Windows.
|
|
(ignore-errors (x-get-selection-value))) ; can be nil
|
|
(t ; linux+osx/emacs24
|
|
; (ignore-errors (x-get-selection 'CLIPBOARD 'UTF8_STRING)))))
|
|
(ignore-errors (x-get-selection 'CLIPBOARD)))))
|
|
|
|
|
|
(defun clipmon--clipboard-contents ()
|
|
"Get current contents of system clipboard - returns a string, or nil."
|
|
;;. do we really need to remove the text properties?
|
|
(let ((text (clipmon--remove-properties (clipmon--get-selection)))
|
|
(top-of-kill-ring (clipmon--remove-properties (car kill-ring))))
|
|
(cond ((null text) nil)
|
|
;; don't return the text if user just copied/cut it from emacs
|
|
((string= text top-of-kill-ring) nil)
|
|
(t text))))
|
|
|
|
|
|
(defun clipmon--trim-left (s)
|
|
"Remove leading spaces from string S."
|
|
(replace-regexp-in-string "^[ \t]+" "" s))
|
|
|
|
|
|
(defun clipmon--seconds-since (time)
|
|
"Return number of seconds elapsed since the given TIME.
|
|
TIME should be in Emacs time format (see `current-time').
|
|
Includes approximate number of milliseconds also.
|
|
Valid for up to 2**16 seconds = 65536 secs ~ 18hrs."
|
|
(let* ((elapsed (time-subtract (current-time) time))
|
|
(seconds (nth 1 elapsed))
|
|
(microseconds (nth 2 elapsed)) ; accurate to milliseconds on my system, anyway
|
|
(total (+ seconds (/ microseconds 1.0e6))))
|
|
total))
|
|
|
|
|
|
;;;; Footer
|
|
;; ----------------------------------------------------------------------------
|
|
|
|
(provide 'clipmon)
|
|
|
|
;; Local Variables:
|
|
;; indent-tabs-mode: nil
|
|
;; End:
|
|
;;; clipmon.el ends here
|