持久化相关的问题

我想把一个变量存在文件中。重启时再从文件中读取。

我是这样存的:

    ;;; save variable `ivy-views' to file, it will overide the file
    (with-temp-file "/tmp/elisp.el"
      (insert (format "%s" ivy-views)))

这样读出来:

(with-temp-buffer 
          (insert-file-contents "/tmp/elisp.el")
          (goto-char (point-min))
          (read (current-buffer)))

但是我发现读出来内容里面原来的 . 号前面都加了一个 \,变成了 \. 。

我发现问题出在read这个函数上。比如下面这段:

(read "(haha nihao.py)")

我期待是返回这样的一个list:

(haha nihao.py)

结果回来的是:

(haha nihao\.py)

请问有人知道这是什么原因吗?有没有什么办法可以实现我的目标?谢谢

用 “%S” 试一试

(format "%s" ...)princ 产生的是让人容易理解的结果,比如一个 Buffer 对象返回的它的名字、一个字符串返回的是它的内容(没有 Quote 了),所以 read 也不能处理它的结果。

或者 pp 之类(即 prin1)都行,它们产生的结果 read 能处理。


不过应该有专门处理这个需求的包,另外,像 Emacs 自带的 savehist-mode 或者 desktop-save-mode,如果用的话,可以直接用它们来存储,估计分别像这样:

(setq savehist-additional-variables '(ivy-views))

(add-to-list 'desktop-globals-to-save 'ivy-views)
1 个赞

谢谢。

因为我把变量存入文件后再读出来是带引号的字符串。而变量的值实际是和该字符串对应的lisp对象。我觉得它应该就是一个list。所以我觉得我应该找到从字符串转到list的方法。

然后我想到了bookmark是可以持久化的,所以我去看了下它的代码。它大概是用:

(read (current-buffer))

这样的形式来读的。而read我看也支持string。所以就试了:

(read "(haha nihao.py)")

发现结果会多出一个 \ 。感觉就差最后一步了。

我试了下面这些:

#+BEGIN_SRC elisp
  (read "(haha nihao.py)")
  (read (format "%S" "(haha nihao.py)"))
  (read (format "%s" "(haha nihao.py)"))
  (read (prin1 "(haha nihao.py)"))
  (read (pp "(haha nihao.py)"))
  (format "%S" (read "(haha nihao.py)"))
  (read (prin1 "xiepeng.py"))
  (read (princ "xiepeng.py"))
#+END_SRC

但是都没达到我的目的。

desktop-save-mode我一般没开。savehist-mode还没有用过。

谢谢二呆。我其实就是想把字符串转为list。不过这个我应该怎么用呢?

(read (format "%S" "(haha nihao.py)"))
(read (format "%s" "(haha nihao.py)"))

第一种出来还是一个字符串。第二种出来还是有 \ 。

读取变量不该用 load 么。

Execute a file of Lisp code named FILE.

查了下help。它应该是执行一个文件中的elisp代码。

Costume variable 就是向文件写入一个做 setq 的表达式,读取的时候就用 load,执行表达式,就可以直接用绑定的变量名调用数据了。还有个 Emacs rouge like 游戏就是这样保存数据的。如果不想要副作用,你可以看看 load 是不是有返回值。

除非对保存数据的文件格式有特别要求,比如必须要 YAML 格式又要用 Emacs 读取。

谢谢。不过我对custom不是太熟。不知道我是应该直接 M-x customize然后找到变量save呢?还是有对应的elisp函数?我试了下:

(custom-variable-save 'ivy-views)
(custom-variable-set 'ivy-views)
(custom-variable-backup-value 'ivy-views)

都有错。不好意思elisp比较菜。:slight_smile:

Custom 要用 defcustom 定义变量。这样才能在自定义面板被找到。

我只是举个例子。一般自定义部分之间写配置机酒可以了。

明白了。谢谢啦

我用类似的方法管理 elpa 镜像

init.el

(defun expand-file (file)
  "Expand FILE content in place."
  (read-from-whole-string
   (with-temp-buffer
     (insert-file-contents file)
     (buffer-string))))

~/.elpa.el

(("gnu"          . "http://mirrors.tuna.tsinghua.edu.cn/elpa/gnu/")
 ("melpa"        . "http://mirrors.tuna.tsinghua.edu.cn/elpa/melpa/")
 ("melpa-Stable" . "http://mirrors.tuna.tsinghua.edu.cn/elpa/melpa-stable/")
 ("marmalade"    . "http://mirrors.tuna.tsinghua.edu.cn/elpa/marmalade/")
 ("org"          . "http://mirrors.tuna.tsinghua.edu.cn/elpa/org/"))

展开文件内容到变量

(setq elpas `',(expand-file "~/.elpa.el"))

谢谢。但是我这样读出来还是有 \ 。

/tmp/elisp.el中的内容是这样的:

(({} *Help* Upgrade.py (vert (file /Users/pengpengxp/src/asp/build/Upgrade.py 16481) (buffer *Help* 1))) ({} *Help* *scratch* (vert (buffer *scratch* 304) (buffer *Help* 1))))

这样读出来的Upgrade.py前面还是有个 \ 。难道是我环境的问题?

你这个文件的写法不对,该引号的加引号,该 quote 的 quote,就跟普通的 .el 文件一样写

这个文件我是这样直接把变量写入的:

(with-temp-file "/tmp/elisp.el"
  (insert (format "%s" ivy-views)))

你应该不需要管 Lisp 对象和文件(字符串)之间的转换,那是 prin1read 的事情。可以试试:

ivy-views
     => (("{} *scratch*" (buffer "*scratch*" 1)))

(with-temp-file "/tmp/foo.el"
  (prin1 ivy-views (current-buffer)))

(equal ivy-views
       (with-temp-buffer
         (insert-file-contents "/tmp/foo.el")
         (read (current-buffer))))
     => t

~ $ cat /tmp/foo.el
(("{} *scratch*" (buffer "*scratch*" 1)))
2 个赞

format 之后当然一切都变了,楼上是 prin1 的写法正解。或者前面提到的 defcustom:

(defcustom foo nil
  "Blablabla..."
  :group 'test
  :type 'alist)

然后持久化写入到 custom.el:

(customize-save-variable 'foo '("bar" . 123))

下次 emacs 启动加载 custom.el, 读取 foo 的值

1 个赞

(read (format “%S” '(haha nihao.py))) 一般是这麽用吧?

明白了。其实我就是有时候想把ivy-views存起来,重启后可以恢复。非常感谢。

需要hack一个小功能哈