在emacs中,我通过使用Cx Cf访问文件来创建文件。假设我要创建/home/myself/new_directory/file.txt
。
如果new_directory还不存在,有没有办法在创建过程中创建它,file.txt
而无需执行任何其他步骤?(我正在考虑使用在Linux中使用-p
flag的方法mkdir
。)
我觉得可以使用Cf Cf代替Cx Cf,但是我不记得它是什么。
M-!
例如。
在emacs中,我通过使用Cx Cf访问文件来创建文件。假设我要创建/home/myself/new_directory/file.txt
。
如果new_directory还不存在,有没有办法在创建过程中创建它,file.txt
而无需执行任何其他步骤?(我正在考虑使用在Linux中使用-p
flag的方法mkdir
。)
我觉得可以使用Cf Cf代替Cx Cf,但是我不记得它是什么。
M-!
例如。
Answers:
您还可以建议函数find-file
透明地创建必要的目录。
(defadvice find-file (before make-directory-maybe (filename &optional wildcards) activate)
"Create parent directory if not exists while visiting file."
(unless (file-exists-p filename)
(let ((dir (file-name-directory filename)))
(unless (file-exists-p dir)
(make-directory dir)))))
只需将其放在您的.emacs
某个地方并C-x C-f照常使用即可。
defadvice
)。
在伊多模式提供ido-find-file
这是一个替代的find-file
,给你更多的功能。例如,它允许您在打开文件的同时创建新目录。
键入C-x C-f照常(其被重新映射到ido-find-file
),
提供不存在的路径,
按M-m,这将提示您创建新目录,
然后在新创建的目录中指定要访问的文件名。
M-m
在某个时候按一下,C-x C-f
如果根本不能自动创建所有内容,那就按吧?如果系统提示您创建目录,M-! mkdir
或将目录设置为
ido-find-file
自动创建目录?甚至更好,问我是否要创建它?我试着用在Török的Gabor的答复意见,但我无法弄清楚哪些功能,将它应用到(如IDO不调用find-file
直接。
我的解决方案有一个额外的好处:如果您在不保存缓冲区的情况下就取消了缓冲区,Emacs将提供删除已创建的那些空目录(但前提是它们在调用之前不存在find-file
):
;; Automatically create any nonexistent parent directories when
;; finding a file. If the buffer for the new file is killed without
;; being saved, then offer to delete the created directory or
;; directories.
(defun radian--advice-find-file-automatically-create-directory
(original-function filename &rest args)
"Automatically create and delete parent directories of files.
This is an `:override' advice for `find-file' and friends. It
automatically creates the parent directory (or directories) of
the file being visited, if necessary. It also sets a buffer-local
variable so that the user will be prompted to delete the newly
created directories if they kill the buffer without saving it."
;; The variable `dirs-to-delete' is a list of the directories that
;; will be automatically created by `make-directory'. We will want
;; to offer to delete these directories if the user kills the buffer
;; without saving it.
(let ((dirs-to-delete ()))
;; If the file already exists, we don't need to worry about
;; creating any directories.
(unless (file-exists-p filename)
;; It's easy to figure out how to invoke `make-directory',
;; because it will automatically create all parent directories.
;; We just need to ask for the directory immediately containing
;; the file to be created.
(let* ((dir-to-create (file-name-directory filename))
;; However, to find the exact set of directories that
;; might need to be deleted afterward, we need to iterate
;; upward through the directory tree until we find a
;; directory that already exists, starting at the
;; directory containing the new file.
(current-dir dir-to-create))
;; If the directory containing the new file already exists,
;; nothing needs to be created, and therefore nothing needs to
;; be destroyed, either.
(while (not (file-exists-p current-dir))
;; Otherwise, we'll add that directory onto the list of
;; directories that are going to be created.
(push current-dir dirs-to-delete)
;; Now we iterate upwards one directory. The
;; `directory-file-name' function removes the trailing slash
;; of the current directory, so that it is viewed as a file,
;; and then the `file-name-directory' function returns the
;; directory component in that path (which means the parent
;; directory).
(setq current-dir (file-name-directory
(directory-file-name current-dir))))
;; Only bother trying to create a directory if one does not
;; already exist.
(unless (file-exists-p dir-to-create)
;; Make the necessary directory and its parents.
(make-directory dir-to-create 'parents))))
;; Call the original `find-file', now that the directory
;; containing the file to found exists. We make sure to preserve
;; the return value, so as not to mess up any commands relying on
;; it.
(prog1 (apply original-function filename args)
;; If there are directories we want to offer to delete later, we
;; have more to do.
(when dirs-to-delete
;; Since we already called `find-file', we're now in the buffer
;; for the new file. That means we can transfer the list of
;; directories to possibly delete later into a buffer-local
;; variable. But we pushed new entries onto the beginning of
;; `dirs-to-delete', so now we have to reverse it (in order to
;; later offer to delete directories from innermost to
;; outermost).
(setq-local radian--dirs-to-delete (reverse dirs-to-delete))
;; Now we add a buffer-local hook to offer to delete those
;; directories when the buffer is killed, but only if it's
;; appropriate to do so (for instance, only if the directories
;; still exist and the file still doesn't exist).
(add-hook 'kill-buffer-hook
#'radian--kill-buffer-delete-directory-if-appropriate
'append 'local)
;; The above hook removes itself when it is run, but that will
;; only happen when the buffer is killed (which might never
;; happen). Just for cleanliness, we automatically remove it
;; when the buffer is saved. This hook also removes itself when
;; run, in addition to removing the above hook.
(add-hook 'after-save-hook
#'radian--remove-kill-buffer-delete-directory-hook
'append 'local)))))
;; Add the advice that we just defined.
(advice-add #'find-file :around
#'radian--advice-find-file-automatically-create-directory)
;; Also enable it for `find-alternate-file' (C-x C-v).
(advice-add #'find-alternate-file :around
#'radian--advice-find-file-automatically-create-directory)
;; Also enable it for `write-file' (C-x C-w).
(advice-add #'write-file :around
#'radian--advice-find-file-automatically-create-directory)
(defun radian--kill-buffer-delete-directory-if-appropriate ()
"Delete parent directories if appropriate.
This is a function for `kill-buffer-hook'. If
`radian--advice-find-file-automatically-create-directory' created
the directory containing the file for the current buffer
automatically, then offer to delete it. Otherwise, do nothing.
Also clean up related hooks."
(when (and
;; Stop if there aren't any directories to delete (shouldn't
;; happen).
radian--dirs-to-delete
;; Stop if `radian--dirs-to-delete' somehow got set to
;; something other than a list (shouldn't happen).
(listp radian--dirs-to-delete)
;; Stop if the current buffer doesn't represent a
;; file (shouldn't happen).
buffer-file-name
;; Stop if the buffer has been saved, so that the file
;; actually exists now. This might happen if the buffer were
;; saved without `after-save-hook' running, or if the
;; `find-file'-like function called was `write-file'.
(not (file-exists-p buffer-file-name)))
(cl-dolist (dir-to-delete radian--dirs-to-delete)
;; Ignore any directories that no longer exist or are malformed.
;; We don't return immediately if there's a nonexistent
;; directory, because it might still be useful to offer to
;; delete other (parent) directories that should be deleted. But
;; this is an edge case.
(when (and (stringp dir-to-delete)
(file-exists-p dir-to-delete))
;; Only delete a directory if the user is OK with it.
(if (y-or-n-p (format "Also delete directory `%s'? "
;; The `directory-file-name' function
;; removes the trailing slash.
(directory-file-name dir-to-delete)))
(delete-directory dir-to-delete)
;; If the user doesn't want to delete a directory, then they
;; obviously don't want to delete any of its parent
;; directories, either.
(cl-return)))))
;; It shouldn't be necessary to remove this hook, since the buffer
;; is getting killed anyway, but just in case...
(radian--remove-kill-buffer-delete-directory-hook))
(defun radian--remove-kill-buffer-delete-directory-hook ()
"Clean up directory-deletion hooks, if necessary.
This is a function for `after-save-hook'. Remove
`radian--kill-buffer-delete-directory-if-appropriate' from
`kill-buffer-hook', and also remove this function from
`after-save-hook'."
(remove-hook 'kill-buffer-hook
#'radian--kill-buffer-delete-directory-if-appropriate
'local)
(remove-hook 'after-save-hook
#'radian--remove-kill-buffer-delete-directory-hook
'local))
规范版在这里。
除了@Chris建议的Mx生成目录之外,您还可以编写一个简短的elisp函数,该函数将先执行查找文件,然后生成目录。您可以尝试以下操作:
(defun bp-find-file(filename &optional wildcards)
"finds a file, and then creates the folder if it doesn't exist"
(interactive (find-file-read-args "Find file: " nil))
(let ((value (find-file-noselect filename nil nil wildcards)))
(if (listp value)
(mapcar 'switch-to-buffer (nreverse value))
(switch-to-buffer value)))
(when (not (file-exists-p default-directory))
(message (format "Creating %s" default-directory))
(make-directory default-directory t))
)
它不是很漂亮,在显示“正在创建目录...”之前,它会闪烁“ it MX make-directory ....”,但是如果没有其他要求,它应该可以助您一臂之力。
find-file
函数,而不是定义一个新函数,这样find-file
直接调用其他函数甚至可以从修改后的行为中受益。
(make-directory "~/bunch/of/dirs" t)
如果您的目录已经存在,它将发出警告。
在(C-h f make-directory RET
)手册中:
make-directory是一个交互式已编译的Lisp函数。
(make-directory DIR &optional PARENTS)
创建目录
DIR
以及可选的任何不存在的父目录。如果DIR
已经作为目录存在,则发出错误信号,除非PARENTS
非null。以交互方式,要创建的目录的默认选择是当前缓冲区的默认目录。当您访问不存在的目录中的文件时,这很有用。
非交互地,第二个(可选)参数
PARENTS
(如果不为nil)表示是否创建不存在的父目录。以交互方式,默认情况下会发生这种情况。如果创建目录失败,将引发错误。
:!mkdir -p ~/new_dir/to/some/crazy/path