How to ZIP files recursively in Emacs - emacs

How can I zip files in Dired, where trying to add a folder to the zip, it will also add the files in that folder recursively?

Mark the files with m, then press ! and type zip -r yourfile.zip *.

You can (un)compress individual files using Z which runs the command dired-do-compress.
You can also do something like this:
(defun sds-dired-zip-file ()
"ZIP the current file and all subdir's; or unZIP if already a ZIP."
(interactive)
(let* ((fn (dired-get-filename)) (nd (file-name-nondirectory fn)) cmd msg)
(cond ((and (string-match ".zip$" fn)
(y-or-n-p (format "unzip %s? " fn)))
(setq msg "unZIPing file %s..." cmd (concat "unzip " nd)))
((and (or (string-match ".tgz$" fn) (string-match ".tar.gz$" fn))
(y-or-n-p (format "tar xfz `%s'? " fn)))
(setq msg "unTAR/GZIPing file %s..." cmd (concat "tar xfz " nd)))
((and (or (string-match ".tbz2$" fn) (string-match ".tar.bz2$" fn))
(y-or-n-p (format "tar xfj `%s'? " fn)))
(setq msg "unTAR/BZIPing file %s..." cmd (concat "tar xfj " nd)))
((and (string-match ".tar$" fn)
(y-or-n-p (format "tar xf `%s'? " fn)))
(setq msg "unTARing file %s..." cmd (concat "tar xf " nd)))
((and (string-match ".rar$" fn)
(y-or-n-p (format "unrar x `%s'? " fn)))
(setq msg "unRARing file %s..." cmd (concat "unrar x " nd)))
((and (file-directory-p fn)
(y-or-n-p (format "zip -rmv9 `%s'? " fn)))
(setq msg "ZIPing directory %s..."
cmd (concat "zip -rmv9 " nd ".zip " nd)))
((y-or-n-p "(un?)compress? ") (dired-do-compress)))
(when cmd
(message msg fn)
(shell-command (concat "cd " (file-name-directory fn) " && " cmd))
(revert-buffer))))
(define-key dired-mode-map "I" 'sds-dired-zip-file)

Related

Org-mode archive entire file if all TODOs DONE

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)))))))

dired-read-file-name: pop-up dired mode to read-file-name

Could anyone please give me a hand to briefly pop-up a dired buffer for the purposes of read-file-name:
(defun dired-insert-file ()
(interactive)
(setq filename (dired-read-file-name "~/Desktop"))
(kill-buffer dired)
(get-buffer-create "*foo*")
(set-buffer "*foo*")
(insert-file filename))
EDIT: Revised example:
(require 'dired)
(defvar open-with-variable nil)
(defvar save-as-variable nil)
(defvar save-as-buffer-filename nil)
(defun dired-read-file-name (&optional directory)
(let* (
output-filename
(working-buffer (buffer-name)))
(if directory
(dired directory)
(dired nil))
(if save-as-buffer-filename
(progn
(goto-char (point-min))
(re-search-forward (file-name-nondirectory save-as-buffer-filename) nil t)))
(recursive-edit)
(switch-to-buffer working-buffer)
output-filename))
(defun dired-insert-file ()
(interactive)
(let* (
(save-as-variable t)
(lawlist-filename (dired-read-file-name)))
(insert-file-contents lawlist-filename)))
;; Open with external application.
(define-key dired-mode-map (kbd "C-c o") (lambda () (interactive)
(let* (
(open-with-variable t)
(lawlist-filename (dired-get-file-for-visit))
(application (dired-read-file-name "/Applications")))
(start-process "external-application" nil "open" "-a" application lawlist-filename))))
(defun lawlist-save-as ()
(interactive)
(let* (
save-as-filename
(save-as-variable t)
(save-as-buffer-filename (if (buffer-file-name) (buffer-file-name)))
(proposed-filename (dired-read-file-name)))
(when proposed-filename ;; needed if aborting recursive-edit
(setq save-as-filename (read-string "Save-As: "
(if (file-directory-p proposed-filename)
(concat proposed-filename (buffer-name))
proposed-filename)))
(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))))
;; delete the buffer after selecting file | application | directory
(define-key dired-mode-map (kbd "<return>") (lambda () (interactive)
(select-file-application-directory t)))
;; do not delete the buffer after selecting file | application | directory
(define-key dired-mode-map (kbd "<C-M-s-return>") (lambda () (interactive)
(select-file-application-directory nil)))
;; select file | application | directory
(defun select-file-application-directory (&optional delete-buffer)
(let* (
(fn-list (dired-get-marked-files))
(rfn-list (mapcar (function dired-make-relative) fn-list))
(dired-one-file (and (consp fn-list) (null (cdr fn-list)) (car fn-list)))
(input-filename (if dired-one-file dired-one-file fn-list))
(ext
(cond
((stringp input-filename)
(file-name-extension input-filename))
((listp input-filename)
(file-name-extension (car input-filename)))))
(path (if (stringp input-filename) (file-name-directory input-filename)))
(dired-buffer-name (buffer-name))
(msword "/Applications/Microsoft Office 2011/Microsoft Word.app/Contents/MacOS/Microsoft Word")
(ooo "/Applications/OpenOffice.org.app")
(excel "/Applications/Microsoft Office 2011/Microsoft Excel.app/Contents/MacOS/Microsoft Excel")
(adobe "/Applications/Adobe Acrobat 9 Pro/Adobe Acrobat Pro.app/Contents/MacOS/AdobeAcrobat")
(preview "/Applications/Preview.app/Contents/MacOS/Preview")
(skim "/Applications/Skim.app/Contents/MacOS/Skim")
(input-regexp '("odt" "wpd" "docx" "doc" "xls" "pdf" "tif" "bmp" "jpg"))
(pdf-regexp '("pdf" "tif" "bmp" "jpg"))
(ooo-regexp '("odt" "wpd"))
(msword-regexp '("doc" "docx")))
(cond
;; only use current path a save-as situation.
((and
(equal input-filename (concat path "."))
save-as-variable)
(setq output-filename (expand-file-name default-directory))
(if delete-buffer (kill-buffer dired-buffer-name))
(throw 'exit nil))
;; save-as (stringp) | dired-insert-file
((and
(stringp input-filename)
(not (file-directory-p input-filename))
(file-exists-p input-filename)
(not (equal input-filename (concat path ".")))
save-as-variable)
(setq output-filename input-filename)
(if delete-buffer (kill-buffer dired-buffer-name))
(throw 'exit nil))
;; open just one file, except input-regexp
((and
(stringp input-filename)
(not (file-directory-p input-filename))
(file-exists-p input-filename)
(not (equal input-filename (concat path ".")))
(not save-as-variable)
(not (regexp-match-p input-regexp ext)))
(if delete-buffer (kill-buffer dired-buffer-name))
(find-file input-filename))
;; open numerous files, except input-regexp
((and
(listp input-filename)
(not (regexp-match-p input-regexp ext)))
(if delete-buffer (kill-buffer dired-buffer-name))
(mapc 'find-file input-filename))
;; open OpenOfficeOrg
((and
(stringp input-filename)
(not (file-directory-p input-filename))
(file-exists-p input-filename)
(not (equal input-filename (concat path ".")))
(not save-as-variable)
(regexp-match-p ooo-regexp ext))
(start-process "ooo-view" nil "open" "-a" ooo input-filename)
(if delete-buffer (kill-buffer dired-buffer-name)))
;; open msword
((and
(stringp input-filename)
(not (file-directory-p input-filename))
(file-exists-p input-filename)
(not (equal input-filename (concat path ".")))
(not save-as-variable)
(regexp-match-p msword-regexp ext))
(start-process "msword-view" nil "open" "-a" msword input-filename)
(if delete-buffer (kill-buffer dired-buffer-name)))
;; open excel
((and
(stringp input-filename)
(not (file-directory-p input-filename))
(file-exists-p input-filename)
(not (equal input-filename (concat path ".")))
(not save-as-variable)
(equal ext "xls"))
(start-process "excel-view" nil "open" "-a" excel input-filename)
(if delete-buffer (kill-buffer dired-buffer-name)))
;; *.pdf -- open just one *.pdf file.
((and
(stringp input-filename)
(not (file-directory-p input-filename))
(file-exists-p input-filename)
(not (equal input-filename (concat path ".")))
(not save-as-variable)
(regexp-match-p pdf-regexp ext))
(lawlist-message "[a]dobe | [p]review | [s]kim")
(let* ((select-pdf-viewer (read-char-exclusive)))
(cond
((eq select-pdf-viewer ?a)
(start-process "pdf-with-adobe" nil "open" "-a" adobe input-filename)
(if delete-buffer (kill-buffer dired-buffer-name)))
((eq select-pdf-viewer ?p)
(start-process "pdf-with-preview" nil "open" "-a" preview input-filename)
(if delete-buffer (kill-buffer dired-buffer-name)))
((eq select-pdf-viewer ?s)
(start-process "pdf-with-adobe" nil "open" "-a" skim input-filename)
(if delete-buffer (kill-buffer dired-buffer-name)))
(t (message "You have exited the sub-function.")) )) )
;; *.pdf -- open more than just one *.pdf file.
((and
(listp input-filename)
(not save-as-variable)
(regexp-match-p pdf-regexp ext))
(lawlist-message "[a]dobe | [p]review | [s]kim")
(let* ((select-pdf-viewer (read-char-exclusive)))
(cond
((eq select-pdf-viewer ?a)
(mapcar (lambda (x)
(start-process "pdf-with-adobe" nil "open" "-a" adobe x) )
input-filename)
(if delete-buffer (kill-buffer dired-buffer-name)))
((eq select-pdf-viewer ?p)
(mapcar (lambda (x)
(start-process "pdf-with-preview" nil "open" "-a" preview x) )
input-filename)
(if delete-buffer (kill-buffer dired-buffer-name)))
((eq select-pdf-viewer ?s)
(mapcar (lambda (x)
(start-process "pdf-with-adobe" nil "open" "-a" skim x) )
input-filename)
(if delete-buffer (kill-buffer dired-buffer-name)))
(t (message "You have exited the sub-function.")) )) )
;; open with external application, because the `open-with-variable` is t.
((and
open-with-variable
(equal ext "app"))
(setq output-filename input-filename)
(if delete-buffer (kill-buffer dired-buffer-name))
(throw 'exit nil))
;; Enter the directory; or, open an application
((and
(file-directory-p input-filename)
(not (equal input-filename (concat path ".")))
(not open-with-variable))
(if (equal ext "app")
(progn
(message "[d]eeper | [o]pen")
(let* ((deeper-open (read-char-exclusive)))
(cond
((eq deeper-open ?d)
(dired-find-file)
(goto-char (point-min))
(re-search-forward " \\.\\.$" nil t)
(if delete-buffer (kill-buffer dired-buffer-name)))
((eq deeper-open ?o)
(start-process "application" nil "open" "-a" input-filename)
(if delete-buffer (kill-buffer dired-buffer-name)))
(t (message "You have exited the sub-function.")) )) )
(dired-find-file)
(goto-char (point-min))
(re-search-forward " \\.\\.$" nil t)
(if delete-buffer (kill-buffer dired-buffer-name)))) )))
;; https://github.com/kentaro/auto-save-buffers-enhanced
;; `regexp-match-p` function modified by #sds on stackoverflow
;; http://stackoverflow.com/questions/20343048/distinguishing-files-with-extensions-from-hidden-files-and-no-extensions
(defun regexp-match-p (regexps string)
(and string
(catch 'matched
(let ((inhibit-changing-match-data t)) ; small optimization
(dolist (regexp regexps)
(when (string-match regexp string)
(throw 'matched t)))))))
(defun lawlist-message (input)
(interactive)
(message
(propertize input 'face 'font-lock-warning-face)))
You'll want to look into recursive-edit: pop up a dired buffer in which you add a way to exit (which works by performing a (throw 'exit <value>)), and then call (recursive-edit) which will return the <value> passed to throw.

How to concatenate double quotes to be used in a start-process

Could anyone please give me a hand concatenating double quotes:
In this example, I'm writing a function to be used with Emacs on a Windows operating system. File names with spaces need to be enclosed in double-quotes.
The buffer-file-name is: c:/Documents and Settings/All Users/Desktop/foo.tex
I'm trying to use:
(setq pdf-file
(concat "\"" (car (split-string (buffer-file-name) "\\.tex")) ".pdf" "\""))
When I call (start-process "display" nil c:/SumatraPDF.exe pdf-file), the pdf viewer tries to open this instead:
c:\Documents and Settings\All Users\Desktop"c:\Documents and Settings\All Users\Desktop\foo.pdf"
EDIT: This is the function that I was trying to modify. As set forth in my answer below, the error was caused by my unwittingly having double-double-quoted the file name -- i.e., start-process treats a variable as being double-quoted, so there was never any need for me to concatenate another set of double quotes.
(defun latexmk ()
".latexmkrc contains the following entries:
$pdflatex = 'pdflatex -file-line-error -synctex=1 %O %S';
$pdf_mode = 1;
$recorder = 0;
$clean_ext = 'synctex.gz synctex.gz(busy) aux fdb_latexmk log';"
(interactive)
(setq tex-file (file-name-nondirectory buffer-file-name))
(setq base-file (car (split-string (file-name-nondirectory buffer-file-name) "\\.tex")))
(setq pdf-file (concat base-file ".pdf"))
(setq line (format "%d" (line-number-at-pos)))
(setq sumatra "C:/SumatraPDF/SumatraPDF.exe")
(setq tex-output (concat "*" (file-name-nondirectory buffer-file-name) "*") )
(setq latexmk "c:/texlive/2013/bin/win32/latexmk.exe")
(setq latexmkrc "c:/Documents and Settings/Administrator/Application Data/.emacs.d/.latexmkrc")
(if (buffer-modified-p)
(save-buffer))
(delete-other-windows)
(set-window-buffer (split-window-horizontally) (get-buffer-create tex-output))
(with-current-buffer tex-output (erase-buffer))
(start-process "tskill" nil "c:/WINDOWS/system32/tskill.exe" "SumatraPDF")
(set-process-sentinel
(start-process "deep-clean" nil latexmk "-C" "-r" latexmkrc tex-file)
(lambda (p e) (when (= 0 (process-exit-status p))
(set-process-sentinel
(start-process "compile" tex-output latexmk "-r" latexmkrc tex-file)
(lambda (p e) (when (= 0 (process-exit-status p))
(set-process-sentinel
(start-process "displayline" nil sumatra "-forward-search" tex-file line pdf-file)
(lambda (p e) (when (= 0 (process-exit-status p))
(start-process "clean" nil latexmk "-c" "-r" latexmkrc tex-file)
(switch-to-buffer (get-file-buffer tex-file))
(if (get-buffer-process (get-buffer tex-output))
(process-kill-without-query (get-buffer-process (get-buffer tex-output))))
(kill-buffer tex-output)
(delete-other-windows)))))))))))
I'm guessing you want:
(replace-regexp-in-string
"\\.tex$"
".pdf"
"c:/Documents and Settings/All Users/Desktop/foo.tex")
(setq pdf-file (concat (file-name-sans-extension (buffer-file-name)) ".pdf"))
Also, if you need to quote an argument passed to a shell, use shell-quote-argument.
start-process treats a variable as if it were double-quoted. In essence, my variable ended up being double-double-quoted -- which is what was preventing me from using the absolute path to the file. So, in a nutshell, when using a variable with start-process, it need not be double-quoted.
Thank you to everyone who helped me to troubleshoot the issue -- greatly appreciated !
Here is the revised working function:
(defun latexmk ()
".latexmkrc contains the following entries:
$pdflatex = 'pdflatex -file-line-error -synctex=1 %O %S';
$pdf_mode = 1;
$recorder = 0;
$clean_ext = 'synctex.gz synctex.gz(busy) aux fdb_latexmk log';"
(interactive)
(setq tex-file (buffer-file-name))
(setq base-file (car (split-string (buffer-file-name) "\\.tex")))
(setq pdf-file (concat base-file ".pdf"))
(setq line (format "%d" (line-number-at-pos)))
(setq sumatra "c:/Program Files/SumatraPDF/SumatraPDF.exe")
(setq tex-output (concat "*" (file-name-nondirectory buffer-file-name) "*") )
(setq latexmk "c:/texlive/2013/bin/win32/latexmk.exe")
(setq latexmkrc "c:/Documents and Settings/Administrator/Application Data/.emacs.d/.latexmkrc")
(if (buffer-modified-p)
(save-buffer))
(delete-other-windows)
(set-window-buffer (split-window-horizontally) (get-buffer-create tex-output))
(with-current-buffer tex-output (erase-buffer))
(start-process "tskill" nil "c:/WINDOWS/system32/tskill.exe" "SumatraPDF")
(set-process-sentinel
(start-process "deep-clean" nil latexmk "-C" "-r" latexmkrc tex-file)
(lambda (p e) (when (= 0 (process-exit-status p))
(set-process-sentinel
(start-process "compile" tex-output latexmk "-r" latexmkrc tex-file)
(lambda (p e) (when (= 0 (process-exit-status p))
(start-process "displayline" nil sumatra "-forward-search" tex-file line pdf-file)
(start-process "clean" nil latexmk "-c" "-r" latexmkrc tex-file)
(switch-to-buffer (get-file-buffer tex-file))
(if (get-buffer-process (get-buffer tex-output))
(process-kill-without-query (get-buffer-process (get-buffer tex-output))))
(kill-buffer tex-output)
(delete-other-windows))))))))

Adding a file-exists-p condition inside an interactive list of a function

I'm having difficulty trying to add an if file-exists-p condition inside the interactive list of this print-to-pdf function. The error message is: file-name-sans-extension: Wrong type argument: stringp, t. I have commented out the section that works, but which nevertheless overwrites an existing file without prompting for a yes or no. I've tried replacing hello-world with pdf-file-name, but that didn't fix the error.
Emacs Trunk developer build --with-ns on OSX, using ns-read-file-name, likes to overwrite files without prompting unless an additional file-exists-p is included in the function.
(defun print-to-pdf (pdf-file-name)
"Print the current file to the given file."
;; (interactive (list (ns-read-file-name "Write PDF file: " "~/" nil ".pdf")
(interactive (list
(let ((hello-world (ns-read-file-name "Write PDF file: " "~/" nil ".pdf")))
(if (file-exists-p hello-world)
(or (yes-or-no-p (format "File %s exists. Save anyway? " hello-world))
(error ""))))
))
(let (
(ps-file-name (concat (file-name-sans-extension pdf-file-name) ".ps"))
(wbuf (generate-new-buffer "*Wrapped*"))
(sbuf (current-buffer)))
(jit-lock-fontify-now)
(save-current-buffer
(set-buffer wbuf)
(insert-buffer sbuf)
(longlines-mode t)
(harden-newlines)
(message (buffer-name sbuf))
(spool-buffer-given-name (buffer-name sbuf))
(kill-buffer wbuf)
(switch-to-buffer "*PostScript*")
(write-file ps-file-name)
(kill-buffer (current-buffer)))
(call-process "/usr/local/bin/ps2pdf14" nil nil nil ps-file-name pdf-file-name)
(delete-file ps-file-name)
(message "PDF saved to %s" pdf-file-name))
)
Why do you want to add it to interactive in the first place? Wouldn't something like this work for you?
(defun print-to-pdf (pdf-file-name)
"Print the current buffer to the given file as PDF."
(interactive (list (ns-read-file-name "Write PDF file: " "~/" nil ".pdf")))
(when (and pdf-file-name
(or (not (file-exists-p pdf-file-name))
(yes-or-no-p "File exists. Overwrite? ")))
(let ((ps-file-name (concat (file-name-sans-extension pdf-file-name) ".ps"))
(wbuf (generate-new-buffer "*Wrapped*"))
(sbuf (current-buffer)))
(jit-lock-fontify-now)
(save-current-buffer
(set-buffer wbuf)
(insert-buffer sbuf)
(longlines-mode t)
(harden-newlines)
(message (buffer-name sbuf))
(spool-buffer-given-name (buffer-name sbuf))
(kill-buffer wbuf)
(switch-to-buffer "*PostScript*")
(write-file ps-file-name)
(kill-buffer (current-buffer)))
(call-process "/usr/local/bin/ps2pdf14" nil nil nil ps-file-name pdf-file-name)
(delete-file ps-file-name)
(message "PDF saved to %s" pdf-file-name))))

Elisp: get quotation marks in format/echo

In .mailrc, I would like to get the first row, but I get the second row
alias UIF "UIF Boxning <uifboxning#boxing.se>" # cool (written manually by me)
alias test_alias test_name <test_mail> # no quotation marks (written by below defun)
I am unsure if the problem is with format or echo. Have a look:
(defun save-mail-address (address name alias)
"add an alias to the .mailrc file"
(interactive "sMail address: \nsFull name: \nsAlias: ")
(let ((compl-alias (format "alias %s \"%s \<%s\>\"" alias name address)))
(shell-command (concat "echo " compl-alias " >> .mailrc")) ))
(defalias 'sma 'save-mail-address)
Edit:
OK, the goal is keep it like this:
alias long "Long Long <long#long.long>" # 123456
alias s "S S <s#s.s>" # 1
Also, made I check so not to include duplicates:
(defun append-blanks (str len)
(concat str (make-string (- len (length str)) ? )) )
(defun save-mail-address (mail name alias phone)
"add an alias to the .mailrc file"
(interactive "sMail mail: \nsFull name: \nsAlias: \nnPhone: ")
(let*(
(alias-alias (format "alias %s" alias))
(alias-alias-blanks (append-blanks alias-alias 16))
(mail-str (append-blanks (format "\"%s \<%s\>\"" name mail) 48))
(line (format "%s%s\# %d\n" alias-alias-blanks mail-str phone))
(file "~/.mailrc") )
(with-temp-buffer
(insert-file file)
(if
(search-forward alias-alias (point-max) t) ; t = return nil on fail
(message (format "Error: The alias %s is already in use." alias))
(progn
(insert line)
(sort-columns nil (point-min) (point-max)) ; nil = not reversed
(write-file file nil) ))))) ; nil = inhibit confirm
You need to ensure that variable arguments passed to a shell command are always appropriately escaped.
(shell-command (concat "echo " (shell-quote-argument compl-alias)))
Just appending the text through Elisp would look like this:
(defun save-mail-address (address name alias)
"add an alias to the .mailrc file"
(interactive "sMail address: \nsFull name: \nsAlias: ")
(let ((compl-alias (format "alias %s \"%s \<%s\>\"" alias name address)))
(with-temp-buffer
(insert compl-alias "\n")
(write-region (point-min) (point-max) "~/.mailrc" t))))