在不使用setq
退出递归编辑时是否可以抛出一个值?
以下函数与setq
一起正常工作,但是,我的目标是消除不必要的全局变量(如果可能) - 尤其是文件名 - 并使用let
绑定变量。但是,在退出递归编辑时抛出一个值的上下文中,我无法设计一个不使用全局变量作为文件名的方法。
在此示例中,我将lawlist-save-as
与dired-read-file-name
结合使用以进入dired-mode并选择文件名或路径。按文件名上的回车键可选择文件。按目录名称上的回车键或两(2)个点向上移动一个目录。按下只有一(1)个点的行上的回车键意味着只选择当前目录中的路径。文件名或路径的值通过 lawlist-save-as
的最后一行传递回函数dired-read-file-name
。
[虽然这个例子不是必需的(但是如果有人好奇的话),使用(dired-get-marked-files)
标记文件会被用于不同的情况,例如使用Wanderlust将多个文件附加到电子邮件中 - 在这种情况下,我使用条件((listp lawlist-filename) (throw 'exit nil))
。当然,打开文件是不言自明的 - 用于定期输入dired-mode然后只需按下要打开的文件上的返回键的情况。]
(require 'dired)
(defvar lawlist-filename nil)
(defvar save-as-buffer-filename nil)
(defvar save-as-variable nil)
(defvar dired-buffer-name nil)
(defun dired-read-file-name (&optional directory)
(let ((working-buffer (buffer-name)))
(if directory
(dired directory)
(dired nil))
(let ((dired-buffer-name (buffer-name)))
(if save-as-buffer-filename
(progn
(goto-char (point-min))
(re-search-forward (file-name-nondirectory save-as-buffer-filename) nil t)))
(recursive-edit)
(kill-buffer dired-buffer-name)
(switch-to-buffer working-buffer)
lawlist-filename)))
;; select file or directory.
(define-key dired-mode-map (kbd "<return>") (lambda () (interactive)
(setq lawlist-filename
(if (or (re-search-backward "^*" nil t)
(re-search-forward "^*" nil t))
(dired-get-marked-files)
(dired-get-file-for-visit)))
(cond
((listp lawlist-filename)
(throw 'exit nil))
;; open file
((and (not (file-directory-p lawlist-filename))
(file-exists-p lawlist-filename)
(not (equal lawlist-filename (concat (file-name-directory lawlist-filename) ".")))
(not save-as-variable))
(find-file lawlist-filename))
;; save-as
((and (not (file-directory-p lawlist-filename))
(file-exists-p lawlist-filename)
(not (equal lawlist-filename (concat (file-name-directory lawlist-filename) "."))))
(throw 'exit nil))
;; go up one directory
((and (file-directory-p lawlist-filename)
(not (equal lawlist-filename (concat (file-name-directory lawlist-filename) "."))))
(setq dired-buffer-name (buffer-name))
(dired-find-file)
(goto-char (point-min))
(re-search-forward " \\.\\.$" nil t)
(kill-buffer dired-buffer-name)
(setq dired-buffer-name (buffer-name)))
;; only use current path for save-as situation.
((and (equal lawlist-filename (concat (file-name-directory lawlist-filename) "."))
save-as-variable)
(setq lawlist-filename (expand-file-name default-directory))
(throw 'exit nil)) )))
(defun lawlist-save-as ()
(interactive)
(setq save-as-variable t)
(if (buffer-file-name)
(setq save-as-buffer-filename (buffer-file-name)))
(let ((proposed-filename (dired-read-file-name)))
(when proposed-filename ;; needed if aborting recursive-edit
(setq save-as-variable nil)
(let ((save-as-filename (read-string "Save-As: "
(concat proposed-filename (when (file-directory-p proposed-filename) (buffer-name))))))
(setq save-as-buffer-filename nil)
(when (and save-as-filename (file-exists-p save-as-filename))
(or (y-or-n-p (format "File `%s' exists; overwrite? " save-as-filename))
(error "Canceled")))
(set-visited-file-name save-as-filename)
(set-buffer-modified-p t)
(and (buffer-file-name)
(file-writable-p buffer-file-name)
(setq buffer-read-only nil))
(save-buffer)))))
答案 0 :(得分:3)
recursive-edit
只是一个运行命令循环的函数。适用于lisp的所有内容都适用。
因此,如果将recursive-edit
封装到本地绑定某个变量的let
中,比如test
,如果在递归编辑会话期间setq
这个变量,则此变量只是在本地设置在let
。
实施例: 使用 C-x C-e :
运行以下命令(let (test)
(recursive-edit)
(message "test=%S" test))
您将处于递归编辑的命令循环中。然后通过 M - 设置test
: (setq test "That is my test.")
。
然后按 M-C-c 退出递归编辑会话。
消息test=\"That is my test.\"
将被打印出来,但符号test
仍未绑定。