-
Notifications
You must be signed in to change notification settings - Fork 0
/
clipmon.el
596 lines (518 loc) · 23.9 KB
/
clipmon.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
;;; 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