I am using ergoemacs(emacs) on windows. I would like to use org-screenshot(org-screenshot.el) to capture the screenshot. I have used cygwin-mount to use cygwin. Unfortunately the "import %f" does not work. I believe it works only when x-server is on. Let me know if i am wrong :). Anyways, I am trying to use a windows tool which accepts the filepath as a parameter to capture screenshot. But the problem is that emacs is passing the filepath with "/" slash, but the tool is expecting "\". I have tried using (replace-regexp-in-string "/" "\" args) before call-process in the below code (code from org-screenshot.el), but it does not work. Any suggestion? Let me know if you need any more information regarding the same.
(let* ((arglst (split-string org-screenshot-command-line " "))
(cmd (car arglst))
(scrpath (convert-standard-filename (expand-file-name scrfilename)))
(args (mapcar (lambda (x) (replace-regexp-in-string "%f" scrpath x))
(cdr arglst))))
(setq status (apply 'call-process cmd nil nil nil args))
(unless prfx (make-frame-visible))
(unless (equal status 0)
(error "screenshot command exited with status %d: %s" status
(mapconcat 'identity (cons cmd args) " ")) )
(message "wrote screenshot to %s" scrpath))
(org-display-inline-images nil t)))
Related
While I've seen a lot of SO questions regarding archiving sub-trees, I use org-journal to create a daily file each day with a template (eg. 2018-09-14.org) which then I then record todos in a pre-templated structure for personal, work or what have you which go through various states till they are either finished DONE or cancelled KILL (I find this approach works for me since it also allows me visually to see in the agenda view how long a task has been hanging around since started).
I am trying to write an interactive function which:
processes a list of all my .org agenda files, and
if it detects all TODOs and DONE or KILL in the file (or there are none present),
prompts me y, n, skip to move the entire file to its whatever.org_archive
(starting to see slowdowns with agenda builds 5 months into using org-mode).
I'm assuming someone else already uses a similar approach ('cause emacs) but was wondering if anyone could point me at a similar function or approach that would be helpful for sussing this out. Googling and thrashing on the elisp has been unproductive so far.
=== One month later ===
Well, teaching myself some lisp has helped but am now at the point where I have the 3 independent functions working, but for some reason am getting an error on calling the final function.
However, I'm getting an error on line 28 with invalid function: on the call to rename-file-buffer-to-org-archive. If someone can see what the problem is, this solves my use case (and probably someone else's which is why I pasted it back here.).
(defun archive-done-org-journal-files ()
"Cycles all org files through checking function."
(interactive)
(save-excursion
(mapc 'check-org-file-finito (directory-files "~/Desktop/test_archives/" t ".org$"))
))
(defun check-org-file-finito (f)
"Checks TODO keyword items are DONE then archives."
(interactive)
(find-file f)
;; Shows open Todo items whether agenda or todo
(let (
(kwd-re
(cond (org-not-done-regexp)
(
(let ((kwd
(completing-read "Keyword (or KWD1|KWD2|...): "
(mapcar #'list org-todo-keywords-1))))
(concat "\\("
(mapconcat 'identity (org-split-string kwd "|") "\\|")
"\\)\\>")))
((<= (prefix-numeric-value) (length org-todo-keywords-1))
(regexp-quote (nth (1- (prefix-numeric-value))
org-todo-keywords-1)))
(t (user-error "Invalid prefix argument: %s")))))
(if (= (org-occur (concat "^" org-outline-regexp " *" kwd-re )) 0)
((rename-file-buffer-to-org-archive)
(kill-buffer (current-buffer)))
(kill-buffer (current-buffer))
)))
(defun rename-file-buffer-to-org-archive ()
"Renames current buffer and file it's visiting."
(interactive)
(let ((name (buffer-name))
(filename (buffer-file-name))
)
(if (not (and filename (file-exists-p filename)))
(error "Buffer '%s' is not visiting a file!" name)
(let ((new-name (concat (file-name-sans-extension filename) ".org_archive")))
(if (get-buffer new-name)
(error "A buffer named '%s' already exists!" new-name)
(rename-file filename new-name 1)
(rename-buffer new-name)
(set-visited-file-name new-name)
(set-buffer-modified-p nil)
(message "File '%s' successfully archived as '%s'."
name (file-name-nondirectory new-name)))))))
So, in the end, this is how I solved it. I'm sure there are optimizations and refactoring to be done here, but this definitely works and is reasonably modular if you need to figure it out. Just change the directory you use (mine is in Dropbox) for your org-files in the archive-done-org-journal-files and this should work for you. I highly recommend testing this on a test archive as per the ~/Desktop/test_archives/ directory as per the actual function just so you can make sure it works as advertised. YMMV. Hope it helps someone!
(defun archive-done-org-journal-files ()
"Cycles all org files through checking function."
(interactive)
(save-excursion
(mapc 'check-org-file-finito (directory-files "~/Desktop/test_archives/" t ".org$"))
))
(defun check-org-file-finito (f)
"Checks TODO keyword items are DONE then archives."
(interactive)
(find-file f)
;; Shows open Todo items whether agenda or todo
(let (
(kwd-re
(cond (org-not-done-regexp)
(
(let ((kwd
(completing-read "Keyword (or KWD1|KWD2|...): "
(mapcar #'list org-todo-keywords-1))))
(concat "\\("
(mapconcat 'identity (org-split-string kwd "|") "\\|")
"\\)\\>")))
((<= (prefix-numeric-value) (length org-todo-keywords-1))
(regexp-quote (nth (1- (prefix-numeric-value))
org-todo-keywords-1)))
(t (user-error "Invalid prefix argument: %s")))))
(if (= (org-occur (concat "^" org-outline-regexp " *" kwd-re )) 0)
(rename-file-buffer-to-org-archive)
(kill-buffer (current-buffer))
)))
(defun rename-file-buffer-to-org-archive ()
"Renames current buffer and file it's visiting."
(interactive)
(let ((name (buffer-name))
(filename (buffer-file-name))
)
(if (not (and filename (file-exists-p filename)))
(error "Buffer '%s' is not visiting a file!" name)
(let ((new-name (concat (file-name-sans-extension filename) ".org_archive")))
(if (get-buffer new-name)
(error "A buffer named '%s' already exists!" new-name)
(rename-file filename new-name 1)
(rename-buffer new-name)
(set-visited-file-name new-name)
(set-buffer-modified-p nil)
(kill-buffer (current-buffer))
(message "File '%s' successfully archived as '%s'."
name (file-name-nondirectory new-name)))))))
I have a small ELisp package that adds an External Tools menu to Emacs. It works on Microsoft Windows but I am having difficulty getting it to work on other operating systems. On Microsoft Windows I use the w32-shell-execute function. On other operating systems I use the start-process function.
My external-tools--exec function is as follows.
(defvar external-tools--exec-count 0)
(defun external-tools--exec (command &rest args)
(if args
(message "(external-tools--exec %s %s) called" command (mapconcat 'identity args " "))
(message "(external-tools--exec %s) called" command)
)
(setq external-tools--exec-count (+ external-tools--exec-count 1))
(cond
((fboundp 'w32-shell-execute)
(if args
(w32-shell-execute "open" command (mapconcat 'identity args " "))
(w32-shell-execute "open" command)
)
)
(t
(let ((external-tools--exec-process-name (format "external-tools--exec-%i" external-tools--exec-count)))
(if args
(apply 'start-process external-tools--exec-process-name nil command args)
(start-process external-tools--exec-process-name nil command)
)
)
)
)
)
This is an example of how I am using it.
(defun external-tools--explore-here ()
"Opens Windows Explorer in the current directory."
(interactive)
(let ((dir (external-tools--get-default-directory)))
(when (fboundp 'w32-shell-execute)
(w32-shell-execute "explore" (format "\"%s\"" dir))
)
(when (and (not (fboundp 'w32-shell-execute)) (executable-find "nautilus"))
(external-tools--exec (executable-find "nautilus") "-w" (format "\"%s\"" dir))
)
)
)
The external-tools--exec function works if args is nil, but it does not work if arguments are specified.
I would appreciate any advice on how to fix the external-tools--exec function.
Edit: I modified the function so that it does not use the convert-standard-filename function as Stefan recommended but the function still does not work. When I use the external-tools--explore-here function on GNU/Linux, I get the following error.
Unable to find the requested file. Please check the spelling and try again.
Unhandled error message: Error when getting information for file '/home/bkey/src/SullivanAndKey.com/SnK/Emacs/Home/.emacs.d/"/home/bkey/src/SullivanAndKey.com/SnK/Emacs/Home/.emacs.d/"': No such file or directory
I figured it out. The bug was not in the external-tools--exec function. It was in the calling function, external-tools--explore-here. I enclosed the directory in quotes, thinking it was necessary to deal with the possibility that there may be spaces in the directory path.
This turned out to be unnecessary.
The new function is as follows.
(defun external-tools--explore-here ()
"Opens Windows Explorer or Nautilus in the current directory."
(interactive)
(let ((dir (external-tools--get-default-directory)))
(when (fboundp 'w32-shell-execute)
(w32-shell-execute "explore" dir)
)
(when (and (not (fboundp 'w32-shell-execute)) (executable-find "nautilus"))
(external-tools--exec (executable-find "nautilus") "-w" dir)
)
)
)
I want to have a variable that keeps the default directory a user enters and keep using it throughout the run of emacs.
Basically, when the user executes a custom command, the prompt will ask for a default directory path to execute the command (only once) and whenever the user calls the same command emacs uses the same path onward.
How can I program that snippet of code in lisp?
I basically want this code in the igrep library to accept the input from user once and not ask again:
(defvar default-files-string-new "*.[sch]")
(defun igrep-read-files (&optional prompt-prefix)
"Read and return a file name pattern from the minibuffer.
If `current-prefix-arg' is '(16) or '(64), read multiple file name
patterns and return them in a list. Optional PROMPT-PREFIX is
prepended to the \"File(s): \" prompt."
(let* ((default-files (igrep-default-files))
(default-files-string (mapconcat 'identity default-files " "))
(insert-default-directory igrep-insert-default-directory)
(file (igrep-read-file-name
(igrep-prefix prompt-prefix
(if default-files
(format "File(s) [default: %s]: "
default-files-string)
"File(s): "))
nil (if default-files default-files-string "") nil nil
'igrep-files-history))
(files (list file)))
(if (or igrep-read-multiple-files
(and (consp current-prefix-arg)
(memq (prefix-numeric-value current-prefix-arg)
'(16 64))))
(let* ((key (igrep-default-key 'exit-minibuffer
minibuffer-local-completion-map
"\r"))
(prompt
(igrep-prefix prompt-prefix
(if igrep-verbose-prompts
(format "File(s): [Type `%s' when done] "
(key-description key))
"File(s): "))))
(while (and (setq file
(igrep-read-file-name prompt
nil "" nil nil
'igrep-files-history))
(not (equal file "")))
(setq files (cons file files)))))
(mapcar (lambda (file)
(if (file-directory-p file)
;; really should map expand-file-name over default-files:
(expand-file-name (if default-files default-files-string-new "*")
file)
file))
(nreverse files))))
You could use advices to do that:
(defvar wd-alist nil)
(mapc
(lambda (function)
(eval
`(defadvice ,function (around ,(intern (format "%s-wd" function)) activate)
(let ((wd (cdr (assoc ',function wd-alist))))
(unless wd
(setq wd (read-file-name "Default directory: "))
(push (cons ',function wd) wd-alist))
(let ((default-directory wd))
ad-do-it)))))
'(grep-find))
The variable wd-list stores the association (FUNCTION . PATH). The list mapc iterate over are the advised functions. Now, when calling find-grep, it asks for the working directory (after interactive arguments, so you first have to type the pattern and enter...) and stores it in wd-list for further use. Now your find-grep are always done in that directory.
You could have a custom variable for the sane default, and then have the user enter the path or accept the default on the first call.
(defcustom default-path "/tmp/foo" "Path")
(setq current-path nil)
(defun foo ()
(interactive)
(unless current-path
(setq current-path
(read-from-minibuffer
(format "Path [%s]" default-path) nil nil t nil default-path)))
(message "Path is: %s" current-path))
The first time you do M-x foo, it prompts for the path. A common idiom is to allow the user to specify a prefix argument when they want to change the value (after the first time.) This code will have the desired effect:
(defun foo (choose)
(interactive "P")
(when (or choose (not current-path))
(setq current-path
(read-from-minibuffer
(format "Path [%s]" default-path) nil nil t nil default-path)))
(message "Path is: %s" current-path))
Now doing M-x foo is the same as before, but C-0 M-x foo will prompt for a new value.
In your example, something like this will work.
(defun igrep-read-files (&optional prompt-prefix)
(interactive "P")
(when (or prompt-prefix (not current-path ))
(setq current-path
(read-file-name "Dir: " default-path nil t)))
(message (expand-file-name default-files-string-new current-path)))
Have a look at the code of sendmail-query-once.
Although it's not very fashionable to do this sort of thing.
Usually package writers pick a sane default and let the user
customize it as they want.
I'm trying to create a function that will revert buffers from emacs' *Buffer List* buffer. As far as I can tell from the documentation, there's no way to do this quickly (in the manner of the save/mark/visit functions built in to buff-menu.el). So I'm writing some elisp. Here's my current attempt:
(defun frobnitz ()
"Call in buffer list to revert buffer at point to file."
(interactive)
(let ((buf (buffer-menu-buffer t)))
(if (y-or-n-p (concat "Revert " (buffer-name (buf)) " ?"))
(with-current-buffer buf
(let (())
(revert-buffer t t t)
(message
(concat "Reverted " (buffer-name (buf)) "to last saved state."))
)))))
Unfortunately, the above defun doesn't seem to work, and I'm having trouble figuring out why. If I eval the above, switch to the *Buffer List* buffer, and invoke M-: (frobnitz), then it errors out with the following.
Debugger entered--Lisp error: (void-function buffer-menu-buffer)
(buffer-menu-buffer t)
(let ((buf (buffer-menu-buffer t))) (if (y-or-n-p (concat "Revert " (buffer-name (buf)) " ?")) (with-current-buffer buf (let (nil) (revert-buffer t t t) (message (concat "Reverted " (buffer-name (buf)) "to last saved state."))))))
frobnitz()
eval((frobnitz) nil)
eval-expression((frobnitz) nil)
call-interactively(eval-expression nil nil)
It seems like that's telling me that there's no function buffer-menu-buffer - but that also seems gratuitously unlikely, since buffer-menu-buffer is a pretty central function in getting the buffer menu to work! For similar reasons, I'm deeply wary of messing with buffer-menu-buffer myself - I don't want to break the buffer menu.
Bearing in mind that the answer might be "invoke this function that you overlooked," how can I get this defun to accomplish its stated purpose of reverting a buffer directly from the buffer menu?
Update: as answerer Sean points out, the correct name of the function I was having a hard time with is Buffer-menu-buffer with a capital initial B. Having fixed that problem, I came across another:
(let (nil) (revert-buffer t t t) (message (concat "Reverted " buf-name "to last saved state.")))
(save-current-buffer (set-buffer buf) (let (nil) (revert-buffer t t t) (message (concat "Reverted " buf-name "to last saved state."))))
(with-current-buffer buf (let (nil) (revert-buffer t t t) (message (concat "Reverted " buf-name "to last saved state."))))
(if (y-or-n-p (concat "Revert " buf-name " ?")) (with-current-buffer buf (let (nil) (revert-buffer t t t) (message (concat "Reverted " buf-name "to last saved state.")))))
(let ((buf (Buffer-menu-buffer t)) (buf-name (concat "" (buffer-name (Buffer-menu-buffer t))))) (if (y-or-n-p (concat "Revert " buf-name " ?")) (with-current-buffer buf (let (nil) (revert-buffer t t t) (message (concat "Reverted " buf-name "to last saved state."))))))
frobnitz()
eval((frobnitz) nil)
eval-expression((frobnitz) nil)
call-interactively(eval-expression nil nil)
My guess is that with-current-buffer tries to save the current buffer and that's a no-no on *Buffer List*. So now I'm looking for an alternative - maybe just switch, revert, and invoke (buffer-list) to switch back.
Update 2:
For future readers: The working function and a single-key binding to invoke it in buffer-menu-mode:
;; Enhance the buffer menu's capabilities.
(defun revert-buffer-from-buffer-list ()
"Call in buffer list to revert buffer at point to file.
Bind this to a key in `buffer-menu-mode' to use it there - not productive in
other modes because it depends on the `Buffer-menu-buffer' function. Undefined
behavior if you invoke it on a buffer not associated with a file: that's why it
has a confirmation gate. Buffers not associated with files get to play by their
own rules when it comes to `revert-buffer' (which see)."
(interactive)
(let (
(buf (Buffer-menu-buffer t))
(buf-name (concat "" (buffer-name(Buffer-menu-buffer t))))
)
(if (y-or-n-p (concat "Revert " buf-name " ?"))
(with-current-buffer buf
(let ()
(revert-buffer t t t)
(message (concat "Reverted " buf-name " to last saved state."))
)))))
(add-hook 'Buffer-menu-mode-hook
(lambda ()
(define-key Buffer-menu-mode-map (kbd "R") revert-buffer-from-buffer-list)
))
Also an exhortation to caution: add-hook is not idempotent, so if you add things to foo-mode-hook that you don't intend to or which don't work, you risk breaking foo-mode until you zorch foo-mode-hook or prune the broken elements out of it. Ask me how I know!
My Emacs has a function Buffer-menu-buffer, but no buffer-menu-buffer. I imagine that's what's tripping you up.
EDIT:
I found two more problems with your code, after which I was able to revert buffers from the buffer menu with it.
I had to change (buf) to buf in two places. buf is a variable, not a function to call.
The (let (()) ...) construct causes an error. Either eliminate it, or change it to (let () ...) (although I don't know why you'd want to).
I am using the openwith package in emacs. I would like to open .fig files with xfig with some additional options, for example:
xfig -specialtext -latexfont -startlatexFont default file.fig
openwith is working for me with other file associations where I don't need to pass additional options. I tried the following in my .emacs file
(setq
openwith-associations
'(("\\.fig\\'" "xfig" (file))))
which works, but
(setq
openwith-associations
'(("\\.fig\\'" "xfig -specialtext -latexfont -startlatexFont default" (file))))
does not work (error: Wrong type argument: arrayp, nil), also
(setq
openwith-associations
'(("\\.fig\\'" "xfig" (" -specialtext -latexfont -startlatexFont default " file))))
does not work, although here I don't get any error. It says "Opened file.fig in external program" but nothing happens. In this case, I notice that there is an xfig process running with all these options.
Could someone let me know how to fix this?
Thanks for the help.
I have no clue how this works, so I just document how one can figure it by reading the code:
The important code in openwith.el is the call to start-process in:
(dolist (oa openwith-associations)
(let (match)
(save-match-data
(setq match (string-match (car oa) (car args))))
(when match
(let ((params (mapcar (lambda (x)
(if (eq x 'file)
(car args)
(format "%s" x))) (nth 2 oa))))
(apply #'start-process "openwith-process" nil
(cadr oa) params))
(kill-buffer nil)
(throw 'openwith-done t))))
The in your case oa would have the following structure, and the cadr is "xfig":
(cadr '("\.fig\'" "xfig" (file))) ;; expands to => xfig
This is the definition and doc of start-process:
Function: start-process name buffer-or-name program &rest args
http://www.gnu.org/software/emacs/elisp/html_node/Asynchronous-Processes.html
args, are strings that specify command line arguments for the program.
An example:
(start-process "my-process" "foo" "ls" "-l" "/user/lewis/bin")
Now we need to figure out how params is constructed. With your example the argument to the mapcar is:
(nth 2 '("\.fig\'" "xfig" (file))) ;=> (file)
By the way you can write such lines in the scratch buffer in emacs and run them with C-M-x.
The (car args) refers to the parameter you give to openwith-association, note how the occurance of 'file in (nth 2 oa) is replaced by that. I'll just replace it with "here.txt" for now:
(mapcar (lambda (x)
(if (eq x 'file)
"here.txt"
(format "%s" x))) (nth 2 '("\.fig\'" "xfig" (file)))) ;=> ("here.txt")
Okay, now we see how the argument should be constructed:
(mapcar (lambda (x)
(if (eq x 'file)
"here.txt"
(format "%s" x)))
(nth 2 '("\.fig\'" "xfig"
("-specialtext" "-latexfont" "-startlatexFont" "default" file))))
; => ("-specialtext" "-latexfont" "-startlatexFont" "default" "here.txt")
Try this:
(setq openwith-associations
'(("\\.fig\\'" "xfig" ("-specialtext" "-latexfont" "-startlatexFont" "default" file))))
You have to supply each word as a single string in the list of parameters.