I think the title can't describe the question clearly. But I will try to describe in more detail words.
Here is my Emacs lisp code to set the backup folder:
(setq backup-directory-alist '(("" . "/hom/test/.backups")))
But if I want to do this job by generating the backup path in a dynamic way, which generates the path based on the user's path.
Here is what I am trying to do:
(setq temp-file-folder "/home/test")
(setq backups-save-folder (concat temp-file-folder "/.backups"))
(setq backup-directory-alist '(("" . backups-save-folder)))
But it doesn't work. The final output of above code is:
(("" . backups-save-folder))
I think what I am trying to get should be:
(("" . "/home/test/.backups"))
So, what's the right code to generate the path dynamic? What's the meaning of . in the code?
Thanks
First, a point. You can use the format function instead of concat to do this (it's similar to printf). Here is an example
(let ((home_dir "/home/noufal")
(posts_dir "posts"))
(format "%s/%s" home_dir posts_dir))
evaluates to "/home/noufal/posts"
It's not idiomatic lisp to setq temporary variables. You should work within the scope of a let construct which can bind values to a few temporary symbols and then get your work done.
In your last case, you've used a ' before your second parameter. This will prevent it from being evaluated (it's synonymous to "quote literally") and so, the backups-save-folder will not be replaced with the value. If you want do that, do something like this.
(setq backup-directory-alist (list (cons "" backups-save-folder)))
The . is a way of representing lists whose cdr is not a list. Refer the elisp documentation for more details.
seems you don't need an associated list, designed to store paired values, but a simple list:
get the current user directory (getenv "HOME")
maybe combined with another arbitrary string "-BACKSTAGE-AREA"
(setq my-dir (list (concat (getenv "HOME")"-BACKSTAGE-AREA")))
get the directory name stored that way with
(car my-dir)
According to Noufal Ibrahim's answer, here is my final code:
(setq backup-directory-alist (list (cons ""
(let ((backups_dir "/.backups")
(temp_folder desktop-temp-file-folder))
(format "%s/%s" temp_folder backups_dir)))))
It works.
Thanks
Related
Sometimes I want to create a duplicate of a number of files (say, config files), which initially should have the same content as the initial files. Therefore I'd like to be able mark some files in dired and "duplicate" them, this duplication procedure could work similar like the duplication procedure utilised by most file managers, when pasting to the original directory: The file names of the duplicated get "(Copy)" appended (just before the file extension).
I can't seem to find a built-in dired function that does this, maybe someone can help/has already created a function like this?
Help is much appreciated!
There is one function that does what you want: dired-do-copy-regexp
Example of use:
mark the files
M-x dired-do-copy-regexp
\(.*\)\.\(.*\)
\1 (copy).\2
For a file named foo.txt you will be creating another named foo (copy).txt
Note that my first regexp has two groups, and the second regexp references them. You can do much more complicated things, if needed.
Maybe you will want to rename the functions (I didn't come up with better names), maybe some more elaborate formatting, if you wish...
(defcustom dired-keep-marker-version ?V
"Controls marking of versioned files.
If t, versioned files are marked if and as the corresponding original files were.
If a character, copied files are unconditionally marked with that character."
:type '(choice (const :tag "Keep" t)
(character :tag "Mark"))
:group 'dired-mark)
(defun dired-version-file (from to ok-flag)
(dired-handle-overwrite to)
(dired-copy-file-recursive from to ok-flag dired-copy-preserve-time t
dired-recursive-copies))
(defun dired-do-version (&optional arg)
"Search for numeric pattern in file name and create a version of that file
with that number incremented by one, or, in case such file already exists,
will search for a file with the similar name, incrementing the counter each
time by one.
Additionally, if called with prefix argument, will prompt for number format.
The formatting is the same as is used with `format' function."
(interactive "P")
(let ((fn-list (dired-get-marked-files nil nil)))
(dired-create-files
(function dired-version-file) "Version" fn-list
(function
(lambda (from)
(let (new-name (i 0) (fmt (if arg (read-string "Version format: " "%d") "%d")))
(while (or (null new-name) (file-exists-p new-name))
(setq new-name
(if (string-match "^\\([^0-9]*\\)\\([0-9]+\\)\\(.*\\)$" from)
(concat (match-string 1 from)
(format fmt
(+ (string-to-number (match-string 2 from)) (1+ i)))
(match-string 3 from))
(concat from (format (concat "." fmt) i)))
i (1+ i))) new-name)))
dired-keep-marker-version)))
(define-key dired-mode-map (kbd "c") 'dired-do-version)
Also, I've originally used v to bind this function because I don't use dired-view, but you would need to bind that inside direds hook. c just was the first undefined key, so I used it.
In the Dired mode, put cursor on the file you want to duplicate or mark that file, then press "C". You will be prompted for new name.
You can use this feature to copy files between Dired buffers as well. To make it possible put into your init file:
(setq dired-dwim-target t)
I found the function here for replace filen at point but it doesn't seem to work properly: http://www.emacswiki.org/emacs/InsertFileName. It correctly finds the file-at-point but the replace appears to take the file you input and not the file detected originally from what I can see. I'm not sure how to fix this.
If I Run the function on /home/testfile
First it says file to replace so for example: /home/secondfile
Then it says replace '/home/secondfile' with: /home/secondfile
and then it says: No file at point
Any ideas??
Here is the function:
(autoload 'ffap-guesser "ffap")
(autoload 'ffap-read-file-or-url "ffap")
(defun my-replace-file-at-point (currfile newfile)
"Replace CURRFILE at point with NEWFILE.
When interactive, CURRFILE will need to be confirmed by user
and will need to exist on the file system to be recognized,
unless it is a URL.
NEWFILE does not need to exist. However, Emacs's minibuffer
completion can help if it needs to be.
"
(interactive
(let ((currfile (ffap-read-file-or-url "Replace filename: "
(ffap-guesser))))
(list currfile
(ffap-read-file-or-url (format "Replace `%s' with: "
currfile) currfile))))
(save-match-data
(if (or (looking-at (regexp-quote currfile))
(let ((filelen (length currfile))
(opoint (point))
(limit (+ (point) (length currfile))))
(save-excursion
(goto-char (1- filelen))
(and (search-forward currfile limit
'noerror)
(< (match-beginning 0) opoint))
(>= (match-end 0) opoint))))
(replace-match newfile)
(error "No file at point to replace"))))
There are probably a few things wrong/going on here. The first is, your point position when you are executing this. The second is, if you are using /home/user/something, that there is a strong possibility you will have mismatch between /home/user/something and ~/something (ffap returns the latter while at the point you may have written the former).
First:
The use of looking-at with the regexp quoted filename expects the point to be at the beginning: e.g. |/home/user/something.
Its partner, looking-back expects /home/user/something|. Being somewhere in the middle will throw this error.
One quick fix for this is changing looking-at to thing-at-point-looking-at.
Second:
If you have written /home/user/something, ffap functions (in my case) shorten this using ~.
There are probably some settings that govern this, but the easiest, quick fix I know of is using expand-file-name. This will take care of the first case, and if it is written as ~/something, the save-excursion body will replace it in the alternate case.
The only negative result I see is that, you might sometimes replace:
/home/user/something with ~/somethingelse
But, anyways, these two quick fixes just result in this complete change:
(thing-at-point-looking-at (regexp-quote (expand-file-name currfile)))
can't see where "ffap-guesser" is defined. Looks like a bug.
Maybe try instead
"find-file-at-point"
Currently i am using the load-history variable to find the file from which a feature came from.
suppose to find the file the feature gnus came from.
I execute the following code in scratch buffer which prints filename and the symbols in separate lines consecutively.
(dolist (var load-history)
(princ (format "%s\n" (car var)))
(princ (format "\t%s\n" (cdr var))))
and then search for "(provide . gnus)" and then move the point to the start of line(Ctrl+A).
The file name in the previous line is the file from which the feature came from.
Is there any thing wrong with this method, or does a better method exist.
I don't really know what you're trying to do with this, but here are some notes.
Your method is fine. Any way to hack your own solution to a problem is good in my book.
#Tom is correct that you shouldn't really need to do this, because the problem is already solved for you by the help system. i.e. C-h f
But that's not so interesting. Let's say you really want an automatic, more elegant solution. You want a function -- locate-feature with this signature:
(defun locate-feature (feature)
"Return file-name as string where `feature' was provided"
...)
Method 1 load-history approach
I'll just describe the steps I took to solve this:
You've already got the most important part -- find the variable with the information you need.
I notice immediately that this variable has a lot of data. If I insert it into a buffer as a single line, Emacs will not be happy, because it's notoriously bad at handling long lines. I know that the prett-print package will be able to format this data nicely. So I open up my *scratch* buffer and run
M-: (insert (pp-to-string load-history))
I can now see the data structure I'm dealing with. It seems to be (in pseudo code):
((file-name
((defun|t|provide . symbol)|symbol)*)
...)
Now I just write the function
(eval-when-compile (require 'cl))
(defun locate-feature (feature)
"Return file name as string where `feature' was provided"
(interactive "Sfeature: ")
(dolist (file-info load-history)
(mapc (lambda (element)
(when (and (consp element)
(eq (car element) 'provide)
(eq (cdr element) feature))
(when (called-interactively-p 'any)
(message "%s defined in %s" feature (car file-info)))
(return (car file-info))))
(cdr file-info))))
The code here is pretty straight forward. Ask Emacs about the functions you don't understand.
Method 2 help approach
Method one works for features. But what if by I want to know where any
available function is defined? Not just features.
C-h f already tells me that, but I want the file-name in a string, not all of the verbose help text. I want this:
(defun locate-function (func)
"Return file-name as string where `func' was defined or will be autoloaded"
...)
Here we go.
C-h f is my starting point, but I really want to read the code that defines describe-function. I do this:
C-h k C-h f C-x o tab enter
Now I'm in help-fns.el at the definition of describe-function. I want to work only with this function definition. So narrowing is in order:
C-x n d
I have a hunch that the interesting command will have "find" or "locate" in its name, so I use occur to search for interesting lines:
M-s o find\|locate
No matches. Hmmm. Not a lot of lines in this defun. describe-function-1 seems to be doing the real work, so we try that.
I can visit the definition of describe-function-1 via C-h f. But I already have the file open. imenu is available now:
C-x n w M-x imenu desc*1 tab enter
Narrow and search again:
C-x n d M-s o up enter
I see find-lisp-object-file-name which looks promising.
After reading C-h f find-lisp-object-file-name I come up with:
(defun locate-function (func)
"Return file-name as string where `func' was defined or will be autoloaded"
(interactive "Ccommand: ")
(let ((res (find-lisp-object-file-name func (symbol-function func))))
(when (called-interactively-p 'any)
(message "%s defined in %s" func res))
res))
Now go have some fun exploring Emacs.
There is locate-library for that.
Try...
M-: (locate-library "my-feature")
eg: (locate-library "gnus")
Just use symbol-file. It scan load-history which has format:
Each entry has the form `(provide . FEATURE)',
`(require . FEATURE)', `(defun . FUNCTION)', `(autoload . SYMBOL)',
`(defface . SYMBOL)', or `(t . SYMBOL)'. Entries like `(t . SYMBOL)'
may precede a `(defun . FUNCTION)' entry, and means that SYMBOL was an
autoload before this file redefined it as a function. In addition,
entries may also be single symbols, which means that SYMBOL was
defined by `defvar' or `defconst'.
So call it as:
(symbol-file 'scheme 'provide) ; Who provide feature.
(symbol-file 'nxml-mode-hook 'defvar) ; Where variable defined.
(symbol-file 'message-send 'defun) ; Where function defined.
(symbol-file 'scheme) ; Look for symbol despite its type.
There is nothing wrong with it, but why is it simpler than getting help on a key or a function? If you use a gnus command for example and you want to know where it comes from then you can use C-h k and it tells you from which elisp file its definition comes.
I know how to configure emacs to keep numbered backups. I don't know the most canonical way to find those numbered backups.
The emacs function "find-backup-file-name" seems like it is the closest. Its documentation states:
This function computes the file name for a new backup file for filename. It may also propose certain existing backup files for deletion. find-backup-file-name returns a list whose CAR is the name for the new backup file and whose CDR is a list of backup files whose deletion is proposed.
However, this is not what I am looking for. I'm looking for a list of ALL previously created backup files. Here's the code (paraphrased) I have written to accomplish this:
(defvar backup-directory "~/emacs.d/backups/")
(defun get-backup-pattern (file-name)
(concat "*" (replace-regexp-in-string "\/" "\\!" file-name t t) ".~*"))
(butlast
(split-string
(shell-command-to-string
(concat "find "
backup-directory
" -name \""
(get-backup-pattern (buffer-file-name))
"\""))
"\n"))
This method works fine. However, shelling out to "find" seems a like a hack to me; Especially since this method is platform specific.
Is there a built-in method I should use or at least something more idiomatic?
Personally, I don't save backup files in a central folder so I can't provide working code, but if you want to search the contents of a directory, use directory-files.
So here is the solution I've decided on. I went away from using the *nix find command and am using directory-files as suggested.
(defun get-filter-pattern (file-name)
(concat (replace-regexp-in-string "\/" "!" file-name t t)
".~[0-9]*~*$"))
(defun filter (condp lst)
(delq nil
(mapcar (lambda (x) (and (funcall condp x) x)) lst)))
(defun filter-files (backup-directory buffer-file-name)
(mapcar (lambda (backup-name) (concat backup-directory backup-name))
(filter (lambda (backup-name)
(string-match (get-filter-pattern buffer-file-name) backup-name))
(directory-files backup-directory))))
Perhaps this isn't quite as optimized as using find. However, it should be platform independent (ie can use on Windows).
I really love org-mode in emacs and want to customize a few things. While reading thru org.el, I'm finding several references to filename but can't find filename using describe-function?
I'm sure there's a simple answer, but I'm just learning elisp and it's not obvious. Any insight into where filename is defined? And/or if it's not a function, what is it?
For example, filename on line 25502:
(filename (if to-buffer
(expand-file-name
(concat
(file-name-sans-extension
(or (and subtree-p
(org-entry-get (region-beginning)
"EXPORT_FILE_NAME" t))
(file-name-nondirectory buffer-file-name)))
"." html-extension)
(file-name-as-directory
(or pub-dir (org-export-directory :html opt-plist))))))
That's not a function, that's a local variable created by the let special form.
Note: This is, of course, a wild guess since I cannot find the code you posted in the versions of org.el I can find, and none of them are even close to 25502 lines long.