10

I save the kill-ring using the savehist package. savehist saves the kill ring with text-properties intact.

Unfortunately, this is a problem.

I have a rather large emacs config, and I use a lot of highlighting. Here is the first element of my kill-ring

#("avehist-printable value)\n         (prin1 `(setq ,symbol ',value) (current-buffer))\n          (insert ?\\n))))))\n    ;; If autosaving, avoid writing if nothing has changed since the\n    ;; last write." 0 23   (fontified t wrap-prefix     #("     " 0 5        (fontified t)))   23 24   (fontified t face     (rainbow-delimiters-depth-8-face)     wrap-prefix     #("      " 0 5        (fontified t)))   24 25   (fontified t wrap-prefix     #("     " 0 5        (fontified t)))   25 32   (fontified t wrap-prefix     #("       " 0 7        (fontified t)))   32 33   (fontified t face     (rainbow-delimiters-depth-8-face)     wrap-prefix     #("          " 0 7        (fontified t)))   33 40   (fontified t wrap-prefix     #("         " 0 7        (fontified t)))   40 41   (fontified t face     (rainbow-delimiters-depth-9-face)     wrap-prefix     #("          " 0 7        (fontified t)))   41 61   (fontified t wrap-prefix     #("         " 0 7        (fontified t)))   61 62   (fontified t face     (rainbow-delimiters-depth-9-face)     wrap-prefix     #("          " 0 7        (fontified t)))   62 63   (fontified t wrap-prefix     #("         " 0 7        (fontified t)))   63 64   (fontified t face     (rainbow-delimiters-depth-9-face)     wrap-prefix     #("          " 0 7        (fontified t)))   64 78   (fontified t wrap-prefix     #("         " 0 7        (fontified t)))   78 79   (fontified t face     (rainbow-delimiters-depth-9-face)     wrap-prefix     #("          " 0 7        (fontified t)))   79 80   (fontified t face     (rainbow-delimiters-depth-8-face)     wrap-prefix     #("          " 0 7        (fontified t)))   80 81   (fontified t wrap-prefix     #("         " 0 7        (fontified t)))   81 88   (fontified t wrap-prefix     #("         " 0 7        (fontified t)))   88 89   (fontified t face     (rainbow-delimiters-depth-8-face)     wrap-prefix     #("          " 0 7        (fontified t)))   89 99   (fontified t wrap-prefix     #("         " 0 7        (fontified t)))   99 100   (fontified t face     (rainbow-delimiters-depth-8-face)     wrap-prefix     #("         " 0 7        (fontified t)))   100 101   (fontified t face     (rainbow-delimiters-depth-7-face)     wrap-prefix     #("        " 0 7        (fontified t)))   101 102   (fontified t face     (rainbow-delimiters-depth-6-face)     wrap-prefix     #("        " 0 7        (fontified t)))   102 103   (fontified t face     (rainbow-delimiters-depth-5-face)     wrap-prefix     #("        " 0 7        (fontified t)))   103 104   (fontified t face     (rainbow-delimiters-depth-4-face)     wrap-prefix     #("        " 0 7        (fontified t)))   104 105   (fontified t face     (rainbow-delimiters-depth-3-face)     wrap-prefix     #("        " 0 7        (fontified t)))   105 106   (fontified t wrap-prefix     #("       " 0 7        (fontified t)))   106 110   (fontified t wrap-prefix     #("    ;; " 0 4        (fontified t)        4 7        (fontified t face font-lock-comment-delimiter-face)))   110 113   (fontified t face font-lock-comment-delimiter-face wrap-prefix     #("    ;; " 0 4        (fontified t)        4 7        (fontified t face font-lock-comment-delimiter-face)))   113 175   (fontified t face font-lock-comment-face wrap-prefix     #("    ;; " 0 4        (fontified t)        4 7        (fontified t face font-lock-comment-delimiter-face)))   175 179   (fontified t wrap-prefix     #("    ;; " 0 4        (fontified t)        4 7        (fontified t face font-lock-comment-delimiter-face)))   179 182   (fontified t face font-lock-comment-delimiter-face wrap-prefix     #("    ;; " 0 4        (fontified t)        4 7        (fontified t face font-lock-comment-delimiter-face)))   182 193   (fontified t face font-lock-comment-face wrap-prefix     #("    ;; " 0 4        (fontified t)        4 7        (fontified t face font-lock-comment-delimiter-face))))

In essence, text properties bloat my ~/.emacs.d/savehist by almost a factor of 100. I'm looking at ~30MB of kill ring. This is bad for all sorts of reasons. Not least because it makes emacs very slow.

How can I tell savehist to strip text properties from the kill-ring before saving, without deleting the properties for the current session?

PythonNut
  • 10,243
  • 2
  • 29
  • 75

2 Answers2

15

Add the following to your init-file:

(defun unpropertize-kill-ring ()
  (setq kill-ring (mapcar 'substring-no-properties kill-ring)))

(add-hook 'kill-emacs-hook 'unpropertize-kill-ring)

How it works

substring-no-properties removes any text properties from a given string. kill-ring is a list of strings; we're using mapcar to apply substring-no-properties to each string that is currently in the kill ring. The result of the mapcar call (i.e., a list of strings without any text properties) is used to override the original value of kill-ring.

savehist-mode saves the minibuffer history and any additional variables in savehist-additional-variables when you quit Emacs. So in the last line we simply tell Emacs to "unpropertize" the kill ring on quit. Note that this happens before savehist does its thing because add-hook prepends functions by default, so unpropertize-kill-ring will be called before savehist-autosave (which is the actual function that gets executed when you quit Emacs).

itsjeyd
  • 14,586
  • 3
  • 58
  • 87
  • 1
    Are you aware of `savehist-save-hook`? – PythonNut Dec 08 '14 at 04:57
  • 3
    @PythonNut Yes I am. If you never call `savehist-save` manually, you can add the function for "unpropertizing" strings to `savehist-save-hook` instead of `kill-emacs-hook`. But if you want to preserve the option of calling `savehist-save` during an editing session without losing text properties of recent kill ring entries, `kill-emacs-hook` is a better choice. – itsjeyd Dec 08 '14 at 12:04
  • Thank you, I just wanted to make sure that _wasn't_ a solution. – PythonNut Dec 09 '14 at 19:34
  • Thank you very much for the solution. :) – narendraj9 Aug 25 '20 at 11:16
6

One simple solution is to use savehist-20.el.

It is a version of savehist.el that works with all Emacs versions (20+). It automatically strips history elements of properties, and it does not save variables in savehist-additional-variables whose values are propertized strings.

In other words, you can read the file it saves even in an Emacs version (e.g. 20) that barfs on propertized strings.

Drew
  • 75,699
  • 9
  • 109
  • 225
  • Basically all of the elements of `kill-ring` are propertied, so it sounds like this would trow away the `kill-ring` wholesale. – PythonNut Dec 07 '14 at 22:13
  • Yes. (If you don't want that then you can tweak one line of the code.) – Drew Dec 07 '14 at 23:15