Emacs Lisp: A list inside a mapcar - emacs

I'm using a function that uses a mapcar to apply a (simple) function to all members of a list, like this :
(mapcar 'my-concat-function '(
"/path/one.php"
"/path/two.php"))
But I want to use directory-files to generate the file list and filter it, something like this :
(mapcar 'my-concat-function '(
(directory-files "/path/" nil "\\.php$")))
But I always get a
find-file-noselect: Wrong type argument: stringp, (directory-files "/path/" nil "\\.php$")
When I evaluate
(directory-files "/path/" nil "\\.php$")
It returns
("one.php" "two.php" "three.php" ...)
(I did not add the "..." ; Emacs did. No matter the size of the list, it seems to always end with "...")
Question :
How can I format the output of directory-files so that it produces exactly what mapcar wants, a single list of atoms, I don't really know how to call this form :
"one.php" "two.php" "three.php"
Without the parenthesis, and without those weird "..."?
EDIT
When I try the forms suggested (thank you guys) the quoted function as 1st arg of mapcar does not work (the regexp don't find anything, all files end up open in empty (?) buffers) anymore :(
Here is the full code, thank you very much for helping, it's weird, this function took very little time to write, and now i'm blocked since hours on this simple list issue, arg.
(defun px-bpm-parse (fname)
"Extract elements. Basic Project Management."
(setq in-buf (set-buffer (find-file fname)))
(setq u1 '())
(setq u2 '())
(setq u3 '())
(setq project-dir "/var/www/html/microlabel.git/")
(beginning-of-buffer)
(while
(re-search-forward "^.*<link.*href=\"\\([^\"]+\\)\".*rel=\"stylesheet\"" nil t)
(when (match-string 0)
(setq url (match-string 1) )
(setq u3 (cons (concat "[[file:" project-dir url "][" url "]]\n") u3))))
(beginning-of-buffer)
(while
(re-search-forward "^.*<a.*href=\"\\([^\"]+\\)\"[^>]+>\\([^<]+\\)</a>" nil t)
(when (match-string 0)
(setq url (match-string 1) )
(setq title (match-string 2) )
(setq u1 (cons (concat "[[file:" project-dir url "][" title "]]\n") u1))))
(beginning-of-buffer)
(while
(re-search-forward "^.*<script.*src=\"\\([^\"]+\\)\"" nil t)
(when (match-string 0)
(setq url (match-string 1) )
(setq u2 (cons (concat "[[file:" project-dir url "][" url "]]\n") u2))))
(beginning-of-buffer)
(progn
(with-current-buffer "BPM.org"
(insert "** File: ")
;; (org-insert-link &optional COMPLETE-FILE LINK-LOCATION DEFAULT-DESCRIPTION)
(insert fname)
(insert "\n*** HREF Links (by name)\n")
(mapcar 'insert u1)
(insert "\n*** SCRIPT Links\n")
(mapcar 'insert u2)
(insert "\n*** CSS Links\n")
(mapcar 'insert u3)
(insert "\n\n"))
(switch-to-buffer "BPM.org")
(org-mode)))
(defun px-bpm ()
;; (defun px-bpm (prj-root)
"List all links"
(interactive)
;; (interactive "sEnter project root directory ")
(progn
(with-current-buffer (get-buffer-create "BPM.org")
(insert "* File dependencies\n\n"))
;; (mapcar 'px-bpm-parse '(
;; "/var/www/html/microlabel.git/add.php"
;; ))
(mapcar 'px-bpm-parse (directory-files "/var/www/html/microlabel.git/" nil "\\.php$"))
))

When you evaluate a form and see a result of the form (x y z ...), it's just printed in that way because the output is long. The result is actually the list that you'd expect. For instance,
(list 1 2 3 4 5 6 7 8 9 10 11 12 13)
;=> (1 2 3 4 5 6 7 8 9 10 11 12 ...)
Yet, the last element of the list is what it should be:
(last (list 1 2 3 4 5 6 7 8 9 10 11 12 13))
;=> (13)
Since (directory-files "/path/" nil "\\.php$") returns a list and the second argument to mapcar should be a list, you can make it the second argument:
(mapcar 'my-concat-function (directory-files "/path/" nil "\\.php$"))

Related

Fine-tuning: `set-process-sentinel` | `set-process-filter` | `start-process`

There are very few examples on the internet involving all three of the functions at issue in this question -- i.e., set-process-sentinel; set-process-filter; and start-process.
I've tried a few different methods of fine-tuning the the processes in an effort to force process number 1 (push) to finish prior to the commencement of process number 2 (push). In all of my attempts, the second process always runs and finishes before I have finished entering my password for process number 1. Process number 2 has a password stored in the osxkeychain.
The first method I tried was with Magit, both synchronous and asynchronous processes. The second method I tried was with using the function while . . . to search the list of remotes in the buffer containing said list. The third attempt is listed below -- it uses a list of remotes that is created at the outset of the function and then mapcars down the list to push with Git.
Any ideas on how to better control process number 1 (push) so that it successfully finishes prior the commencement of process number 2 (push) would be greatly appreciated.
It is not the end of the world that process number 2 starts and finishes too early, but it is a matter of learning how to take control over Emacs processes -- rather than the processes taking control of me.
EDIT (April 23, 2014):  Added a doc-string. Revised handling of buffer *REMOTES* -- i.e., kill-local-variable 'git-remote-list and erase-buffer now works correctly by using with-current-buffer ...
(defvar git-remote-list nil
"List of remote locations -- e.g., lawlist_remote or github_remote.")
(make-variable-buffer-local 'git-remote-list)
(defvar git-commit-message (format "Committed -- %s" (current-time-string))
"The predetermined Git commit message.")
(make-variable-buffer-local 'git-commit-message)
(defun my-process-filter (proc string)
(when (string-match "password" string)
(process-send-string
proc
(concat (read-passwd "Password: ") "\n"))))
(defun my-process-sentinel (proc string)
(when (= 0 (process-exit-status proc))
(message "Process `%s` has finished." proc)))
(defun stage-commit-push-all ()
"This function does the following:
* Save the current working buffer if it has been modified.
* Gather a list of all remotes associated with working directory Git project.
* Stage all -- `/usr/local/git/bin/git add .`
* Commit all -- `/usr/local/git/bin/git commit -m [git-commit-message]`
* Push to all remotes: `/usr/local/git/bin/git push -v [remote] [current-branch]`
Obtaining the current branch presently requires installation of Magit."
(interactive)
(when (buffer-modified-p)
(save-buffer))
(when (get-buffer "*REMOTES*")
(with-current-buffer (get-buffer "*REMOTES*")
(kill-local-variable 'git-remote-list)
(erase-buffer)))
(set-process-sentinel
(start-process
"list-remotes"
"*REMOTES*"
"/usr/local/git/bin/git"
"remote"
"-v")
(lambda (p e) (when (= 0 (process-exit-status p))
(let* (
beg
end
git-remote-name)
(with-current-buffer (get-buffer "*REMOTES*")
(goto-char (point-max))
(while (re-search-backward "\(push\)" nil t)
(beginning-of-line 1)
(setq beg (point))
(re-search-forward "\t" nil t)
(setq end (- (point) 1))
(setq git-remote-name (buffer-substring-no-properties beg end))
(setq git-remote-list
(append (cons git-remote-name git-remote-list)))) ))
(set-process-sentinel
(start-process
"stage-all"
"*OUTPUT*"
"/usr/local/git/bin/git"
"add"
".")
(lambda (p e) (when (= 0 (process-exit-status p))
(set-process-sentinel
(start-process
"commit-all"
"*OUTPUT*"
"/usr/local/git/bin/git"
"commit"
"-m"
git-commit-message)
(lambda (p e) (when (= 0 (process-exit-status p))
(mapcar (lambda (x)
(let ((proc
(start-process
"push-process"
"*OUTPUT*"
"/usr/local/git/bin/git"
"push"
"-v"
(format "%s" x)
(magit-get-current-branch))))
(set-process-filter proc 'my-process-filter)
(set-process-sentinel proc 'my-process-sentinel) ))
(with-current-buffer (get-buffer "*REMOTES*") git-remote-list)
)))))))))))
The approach that springs to mind is simply to make each call to start-process dependent on the sentinel for the previous process.
In essence, generate a queue of things you want to do, trigger the processing of the first queue item, and let each sentinel trigger start the process for the next queue item (if any) once its own process has completed.
In order to obtain more precise control over set-process-sentinel | set-process-filter | start-process, one may wish to consider incorporating recursive-edit to pause an elisp function while a process is pending -- and either use exit-recursive-edit or (throw 'exit nil) to return control to the elisp function that was paused.
EDIT (April 23, 2014): Redacted to create a minimal example incorporating recursive-edit. A working example will be maintained and updated in a related thread: https://stackoverflow.com/a/23178396/2112489
(defun my-git-password-process-filter (proc string)
(when (string-match "password" string)
(process-send-string
proc
(concat (read-passwd "Password: ") "\n"))))
(defun my-process-sentinel (proc string)
(when (= 0 (process-exit-status proc))
(message "Process `%s` has finished pushing to `%s`." proc git-remote-name)
(throw 'exit nil)))
(defun example-using-recursive-edit ()
;;
;; For a more detailed working example, please see this related thread:
;; https://stackoverflow.com/a/23178396/2112489
;;
;; * * * REDACTED TO CREATE MINIMAL WORKING EXAMPLE * * *
;;
(set-process-sentinel
(start-process
"commit-all"
"*Messages*"
"/usr/local/git/bin/git"
"commit"
"-m"
git-commit-message)
(lambda (p e) (when (= 0 (process-exit-status p))
(mapcar (lambda (git-remote-name)
(let ((proc
(start-process
"push-process"
"*Messages*"
"/usr/local/git/bin/git"
"push"
"-v"
(format "%s" git-remote-name)
(format "%s"
(with-current-buffer (get-buffer "*REMOTES*")
git-branch-name)) )))
(set-process-filter proc 'my-git-password-process-filter)
(set-process-sentinel proc 'my-process-sentinel)
(recursive-edit) ))
(with-current-buffer (get-buffer "*REMOTES*")
git-remote-list) )))))
The following is an example of throwing a result at the end of a function, when that result is dependent upon the process finishing beforehand. As the other answer in this thread indicates, using recursive-edit is helpful -- in this case, it solves the dilemma by preventing the result from being thrown until the process concludes.
This particular example uses a version of ls found in coreutils-8.21 for OSX, which may have some options not available in other versions. This example also contains a creative method to obtain the absolute paths/file-names using start-process, which would not ordinarily permit regexp arguments such as is used to obtain files that are both visible and hidden.
NOTE:  A process-filter does not work reliably to create an exact list (including spaces between ls columns), however, that explanation is beyond the scope of this example. The process output buffer, on the other hand, is reliable. [I may submit a bug report regarding the process filter at some point in the future when I have the time.]
;;; EXAMPLE: (dolist (x (create-ls-list "~/")) (message "%s" x))
(defun create-ls-list (&optional dir)
(interactive)
(let* (
result
(directory
(cond
(dir
(if (equal dir "/") nil (directory-file-name dir)))
(t
(directory-file-name default-directory))))
(output-buffer "*LS-OUTPUT*")
(ls-command (concat
;;; Some versions of `ls` do not support TIME-STYLE argument.
"/Users/HOME/.0.data/.0.emacs/.0.macports/bin/gls"
" "
"-lhd" ;; listing switches
" "
directory ;; `nil` if root "/"
"/.*" ;; hidden files
" "
directory ;; `nil` if root "/"
"/*" ;; everything except hidden fies
" "
"--time-style=\"+%m-%d-%Y %H:%M:%S\""
" "
"--group-directories-first")) )
(when (get-buffer output-buffer)
(with-current-buffer (get-buffer output-buffer)
(erase-buffer)))
(set-process-sentinel
(start-process
"ls-process"
output-buffer
"/bin/bash"
"-c"
ls-command)
(lambda (p e) (when (= 0 (process-exit-status p))
(let* (
(output-buffer (get-buffer "*LS-OUTPUT*"))
(regexp (concat
"\\(^[sldrwxt+-]+\\)" ;; 1
"\\(\s+\\)" ;; 2
"\\([0-9]+\\)" ;; 3
"\\(\s+\\)" ;; 4
"\\([a-zA-Z]+\\)" ;; 5
"\\(\s+\\)" ;; 6
"\\([a-zA-Z]+\\)" ;; 7
"\\(\s+\\)" ;; 8
"\\([0-9.kKMGT]+\\)" ;; 9
"\\(\s+\\)" ;; 10
"\\([0-9-]+\\)" ;; 11
"\\(\s+\\)" ;; 12
"\\([0-9:]+\\)" ;; 13
"\\(\s+\\)" ;; 14
"\\(.*$\\)" ))) ;; 15
(with-current-buffer output-buffer
(save-excursion
(goto-char (point-max))
(while (re-search-backward regexp nil t)
(let* (
(one (match-string 1))
(two (match-string 2))
(three (match-string 3))
(four (match-string 4))
(five (match-string 5))
(six (match-string 6))
(seven (match-string 7))
(eight (match-string 8))
(nine (match-string 9))
(ten (match-string 10))
(eleven (match-string 11))
(twelve (match-string 12))
(thirteen (match-string 13))
(fourteen (match-string 14))
(fifteen (match-string 15)) )
(push
(list
one two three four five six seven eight nine
ten eleven twelve thirteen fourteen fifteen)
result)))))
(throw 'exit nil)))))
(recursive-edit)
result))

Generate Org-mode objects programmatically

I want to generate strings containing Org-mode text without actually hard-coding the syntax. For example i want to run a function such as (org-generate (org-generate-heading "heading" (org-generate-plain-list '("foo" "bar" "baz"))) and it will return:
* heading
- foo
- bar
- baz
In other words, i want to create Org-mode documents of arbitrary complexity without micromanaging syntactic features like asterisks and indentation, only via calling functions with parameters, that return some Org objects. Is it possible to do that? Maybe via org-element?
INITIAL (March 14, 2014):  First rough draft.
EDIT (March 15, 2014):  Created and revised the function named example. The path of the let-bound variable org-file must coincide with an existing org-mode file. The let-bound variables main-heading and sub-heading are not being used at this time due to an apparent limitation with using variables in a list that begins with '( -- i.e., those two variables are not recognized under this circumstance. The function org-capture from org-capture.el has been modified to include the contents of the function org-capture-set-plist, which in turn has been modified to eliminate the first two elements of org-capture-entry (aka org-capture-templates) -- both entries (i.e., :key and :description) are for manually selecting a template from the user-interface, and are not needed when generating an org buffer programmatically as is being done with this example. In addition, the portions of the function org-capture relating to manually selecting a template have been removed.
EDIT (March 16, 2014):  Revised variables and list handling based upon lessons provided by #sds and #lunaryorn in the following thread: https://stackoverflow.com/a/22440518/2112489  Added four optional incoming variables -- (1) main-heading; (2) sub-heading-headline; (3) sub-heading-complete; and (4) plain-list. The example now work either interactively, or by evaluating the function using the following format:  (org-generate "PROJECT" "Thesis" "** Thesis\n:PROPERTIES:\n:END:" '("a" "b" "c"))
EDIT (March 19, 2014):  org-generate is now a non-interactive function that requires incoming variables -- the doc-string has been updated. Created a function named example that utilizes the new format for org-generate.
;; EXAMPLES:
;; (org-generate 'entry "/Users/HOME/Desktop/myproject.org" "PROJECT" "Thesis" "** Thesis\n :PROPERTIES:\n :END:")
;; (org-generate 'item "/Users/HOME/Desktop/myproject.org" "PROJECT" "Thesis" nil '("a" "b" "c"))
(defun example ()
(interactive)
(let* (
(org-file "/Users/HOME/Desktop/myproject.org")
(level-one "TASKS")
(level-two
"Active [\#A] Generate Org-mode objects programmatically.")
(full-level-two (concat
"** Active [\#A] Generate Org-mode objects programmatically.\n"
" DEADLINE: <%<%Y-%m-%d %a>>\n"
" :PROPERTIES:\n"
" :ToodledoFolder: TASKS\n"
" :END:"))
(plain-list '("foo" "bar" "baz")) )
(org-generate 'entry org-file level-one level-two full-level-two)
(org-generate 'item org-file level-one level-two nil plain-list) ))
(defun org-generate (type org-file level-one
&optional level-two full-level-two plain-list)
"Formating options for `org-capture-entry` are similar to `org-capture-templates`.
However, the first two elements (i.e., `:key` and `:description`) are NOT used.
Please see the doc-string of the variable `org-capture-templates` for more info.
(1) `type`: required -- 'entry | 'item
(2) `org-file`: required -- path to the org-mode file.
(3) `level-one`: required -- main heading.
(4) `level-two`: optional -- sub-heading headline (only).
(5) `full-level-two`: optional -- complete sub-heading.
(6) `plain-list`: optional -- a list.
EXAMPLES:
`(org-generate 'entry org-file level-one level-two full-level-two)`
`(org-generate 'item org-file level-one level-two nil plain-list)` "
(require 'org-capture)
(let (org-capture-entry)
(cond
((eq type 'entry)
(setq org-capture-entry
`(entry
(file+headline ,org-file ,level-one)
,full-level-two :empty-lines 1 :immediate-finish t))
(lawlist-org-capture))
((eq type 'item)
(setq org-capture-entry
`(item
(file+olp ,org-file ,level-one ,level-two)
nil :empty-lines 1 :immediate-finish t))
(mapcar (lambda (x)
(progn
(setcar (nthcdr 2 org-capture-entry) x)
(lawlist-org-capture) ))
plain-list)))))
(defun lawlist-org-capture ()
(let* ((orig-buf (current-buffer))
(annotation (if (and (boundp 'org-capture-link-is-already-stored)
org-capture-link-is-already-stored)
(plist-get org-store-link-plist :annotation)
(ignore-errors (org-store-link nil))))
(entry org-capture-entry)
initial)
(setq initial (or org-capture-initial
(and (org-region-active-p)
(buffer-substring (point) (mark)))))
(when (stringp initial)
(remove-text-properties 0 (length initial) '(read-only t) initial))
(when (stringp annotation)
(remove-text-properties 0 (length annotation)
'(read-only t) annotation))
(setq org-capture-plist (copy-sequence (nthcdr 3 entry)))
(org-capture-put :target (nth 1 entry))
(let ((txt (nth 2 entry)) (type (or (nth 0 entry) 'entry)))
(when (or (not txt) (and (stringp txt) (not (string-match "\\S-" txt))))
(cond
((eq type 'item) (setq txt "- %?"))
((eq type 'checkitem) (setq txt "- [ ] %?"))
((eq type 'table-line) (setq txt "| %? |"))
((member type '(nil entry)) (setq txt "* %?\n %a"))))
(org-capture-put :template txt :type type))
(org-capture-get-template)
(org-capture-put :original-buffer orig-buf
:original-file (or (buffer-file-name orig-buf)
(and (featurep 'dired)
(car (rassq orig-buf
dired-buffers))))
:original-file-nondirectory
(and (buffer-file-name orig-buf)
(file-name-nondirectory
(buffer-file-name orig-buf)))
:annotation annotation
:initial initial
:return-to-wconf (current-window-configuration)
:default-time
(or org-overriding-default-time
(org-current-time)))
(org-capture-set-target-location)
(condition-case error
(org-capture-put :template (org-capture-fill-template))
((error quit)
(if (get-buffer "*Capture*") (kill-buffer "*Capture*"))
(error "Capture abort: %s" error)))
(setq org-capture-clock-keep (org-capture-get :clock-keep))
(condition-case error
(org-capture-place-template
(equal (car (org-capture-get :target)) 'function))
((error quit)
(if (and (buffer-base-buffer (current-buffer))
(string-match "\\`CAPTURE-" (buffer-name)))
(kill-buffer (current-buffer)))
(set-window-configuration (org-capture-get :return-to-wconf))
(error "Error.")))
(if (and (derived-mode-p 'org-mode)
(org-capture-get :clock-in))
(condition-case nil
(progn
(if (org-clock-is-active)
(org-capture-put :interrupted-clock
(copy-marker org-clock-marker)))
(org-clock-in)
(org-set-local 'org-capture-clock-was-started t))
(error
"Could not start the clock in this capture buffer")))
(if (org-capture-get :immediate-finish)
(org-capture-finalize))))
(source: lawlist.com)

How to search for a complete org headline that was saved as a variable

The function (org-heading-components) and (org-element-property) produce integers for the number of stars and also for the priority. I'd like to store the entire headline as a variable and then use re-search-forward (or a similar function) to go back to that heading, but I foresee the problem that will occur when it cannot find an integer. I need to store the whole heading as a variable, because I often have todo entries with duplicate titles but the other components are diferent.
For example, the following todo:
** Active [#A] Ask the geniuses on stackoverflow how to do this. :lawlist:
when evaluated with (org-heading-components) looks like this:
(2 2 "Active" 65 "Ask the geniuses on stackoverflow how to do this." ":lawlist:")
So, when storing that as a variable and later using re-search-forward there will be problems because 2 2 is not the same as **, and 65 is not the same as [#A].
(defun lawlist ()
(interactive)
(let* (
(beg (point))
(complete-heading (org-heading-components) ))
* * *
(goto-char (point-min))
(re-search-forward complete-heading nil t) ))
You should be able to convert the output as follows:
The first # is the current level (# of stars)
The second number is the reduced headline level, applicable if org-odd-levels-only is set, but this is not regarding output.
Todo keyword
Priority character (65 is ASCII code for A)
Headline text
Tags or nil
The following will return the headline string as shown in the buffer. It will not work with re-search-forward but will work with search-forward (It does not escape any characters).
(defun zin/search-test ()
(interactive)
(let ((head (org-element-interpret-data (org-element-at-point))))
(message "%s" (format "%s" (car (split-string head "\n"))))))
This does not set it to any variable, you'll have to wrap it in an appropriate function that will set your desired variable. Then use (search-forward <var> nil t) to match it, without it erroring out if it cannot find it.
There's a brilliant part of org that might suit you: org-id-copy and
org-id-goto. It works with precision across buffers and sessions:
org-id-copy produces a string. You can feed that string to
org-id-goto which will take you to that heading. Even if you've
closed the original buffer. Even if you've restarted Emacs.
EDIT (December 15, 2013):  Updated solution based upon the variable org-heading-regexp (defined within org.el) and a modification thereof to include (if it exists) a second line containing a deadline - i.e., lawlist-org-heading-regexp. The revision also includes a nifty function regexp-quote that was just taught to me by #Drew over on superuser: https://superuser.com/questions/688781/how-to-highlight-string-and-unhighlight-string-in-buffer-make-overlay?noredirect=1#comment874515_688781  (buffer-substring-no-properties beg end) is used to set the string as a variable.
EDIT (December 17, 2013):   Added isearch-highlight and isearch-dehighlight, and commented out highlight-regexp and unhighlight-regexp. When moving the point around with more complex functions, highlight-regexp does not reliably highlight the entire string -- this may be because the screen has not refreshed, or it may also be caused by other factors -- e.g., hl-line-mode, etc.) -- placing various sit-for 0 did not fix the issue with highlight-regexp -- isearch-highlight works better.
EDIT (January 6, 2014):  See also this related thread for a complete regexp to match any element of the entire todo from stars through to the end of the notes:  https://stackoverflow.com/a/20960301/2112489
(require 'org)
(defvar lawlist-org-heading-regexp
"^\\(\\*+\\)\\(?: +\\(.*?\\)\\)?[ \t]*\\(\n.*DEADLINE.*$\\)"
"Match headline, plus second line with a deadline.")
(defun example ()
(interactive)
(switch-to-buffer (get-buffer-create "foo"))
(org-mode)
(insert "* Example\n\n")
(insert "** Active [#A] This is an active todo. :lawlist:\n")
(insert " DEADLINE: <2013-12-15 Sun 08:00> SCHEDULED: <2013-12-15 Sun>\n\n")
(insert "** Next-Action [#B] This is an inactive todo. :lawlist:\n")
(insert " DEADLINE: <2013-12-16 Mon 08:00> SCHEDULED: <2013-12-16 Mon>")
(goto-char (point-min))
(sit-for 2)
(re-search-forward (regexp-quote "** Active [#A] "))
(sit-for 2)
(let ((init-pos (point)))
(org-back-to-heading t)
(let* (
lawlist-item-whole
lawlist-item-partial
(beg (point)))
(if (and
(looking-at org-heading-regexp)
(and (looking-at lawlist-org-heading-regexp) (match-string 3)))
(re-search-forward lawlist-org-heading-regexp nil t)
(re-search-forward org-heading-regexp nil t))
(let ((end (point)))
(setq lawlist-item-whole (buffer-substring-no-properties beg end))
(setq lawlist-item-partial (buffer-substring-no-properties beg init-pos))
(re-search-backward (regexp-quote lawlist-item-whole) nil t)
;; (highlight-regexp (regexp-quote lawlist-item-whole))
(isearch-highlight beg end)
(sit-for 2)
;; (unhighlight-regexp (regexp-quote lawlist-item-whole))
(isearch-dehighlight)
(re-search-forward (regexp-quote lawlist-item-partial) nil t)
(sit-for 2)
(kill-buffer "foo")))))
EDIT (October 27, 2013):  Prior solution that is being preserved temporarily as a historical part of the evolution process towards a final answer. However, it is no longer a preferred method.
(defun lawlist-org-heading-components ()
(org-back-to-heading t)
(if (let (case-fold-search) (looking-at org-complex-heading-regexp))
(concat
(cond
((equal (org-match-string-no-properties 1) "**")
"^[*][*]")
((equal (org-match-string-no-properties 1) "*")
"^[*]"))
(cond
((and (match-end 2) (aref (match-string 2) 1))
(concat " " (org-match-string-no-properties 2))))
(cond
((and (match-end 3) (aref (match-string 3) 2))
(concat " \\" (org-match-string-no-properties 3))))
(cond
((and (match-end 4) (aref (match-string 4) 3))
(concat " " (org-match-string-no-properties 4))))
(cond
((and (match-end 5) (aref (match-string 5) 4))
(concat " " (org-match-string-no-properties 5)))))))

In elisp, how to evaluate a string of "var=value\n..." into lisp variables of the same name?

An mplayer tool (midentify) outputs "shell-ready" lines intended to be evaluated by a bash/sh/whatever interpreter.
How can I assign these var-names to their corresponding values as elisp var-names in emacs?
The data is in a string (via shell-command-to-string)
Here is the data
ID_AUDIO_ID=0
ID_FILENAME=/home/axiom/abc.wav
ID_DEMUXER=audio
ID_AUDIO_FORMAT=1
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=0
ID_AUDIO_NCH=1
ID_LENGTH=3207.00
ID_SEEKABLE=1
ID_CHAPTERS=0
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=32000
ID_AUDIO_NCH=1
ID_AUDIO_CODEC=pcm
ID_EXIT=EOF
Here's a routine that takes a string containing midentify output, and returns an association list of the key-value pairs (which is safer than setting Emacs variables willy-nilly). It also has the advantage that it parses numeric values into actual numbers:
(require 'cl) ; for "loop"
(defun midentify-output-to-alist (str)
(setq str (replace-regexp-in-string "\n+" "\n" str))
(setq str (replace-regexp-in-string "\n+\\'" "" str))
(loop for index = 0 then (match-end 0)
while (string-match "^\\(?:\\([A-Z_]+\\)=\\(?:\\([0-9]+\\(?:\\.[0-9]+\\)?\\)\\|\\(.*\\)\\)\\|\\(.*\\)\\)\n?" str index)
if (match-string 4 str)
do (error "Invalid line: %s" (match-string 4 str))
collect (cons (match-string 1 str)
(if (match-string 2 str)
(string-to-number (match-string 2 str))
(match-string 3 str)))))
You'd use this function like so:
(setq alist (midentify-output-to-alist my-output))
(if (assoc "ID_LENGTH" alist)
(setq id-length (cdr (assoc "ID_LENGTH" alist)))
(error "Didn't find an ID_LENGTH!"))
EDIT: Modified function to handle blank lines and trailing newlines correctly.
The regexp is indeed a beast; Emacs regexps are not known for their easiness on the eyes. To break it down a bit:
The outermost pattern is ^(?:valid-line)|(.*). It tries to match a valid line, or else matches the entire line (the .*) in match-group 4. If (match-group 4 str) is not nil, that indicates that an invalid line was encountered, and an error is raised.
valid-line is (word)=(?:(number)|(.*)). If this matches, then the name part of the name-value pair is in match-string 1, and if the rest of the line matches a number, then the number is in match-string 2, otherwise the entire rest of the line is in match-string 3.
There's probably a better way but this should do it:
(require 'cl)
(let ((s "ID_AUDIO_ID=0
ID_FILENAME=/home/axiom/abc.wav
ID_DEMUXER=audio
ID_AUDIO_FORMAT=1
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=0
ID_AUDIO_NCH=1
ID_LENGTH=3207.00
ID_SEEKABLE=1
ID_CHAPTERS=0
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=32000
ID_AUDIO_NCH=1
ID_AUDIO_CODEC=pcm
ID_EXIT=EOF"))
(loop for p in (split-string s "\n")
do
(let* ((elements (split-string p "="))
(key (elt elements 0))
(value (elt elements 1)))
(set (intern key) value))))
Here's a function you can run on the output buffer:
(defun set-variables-from-shell-assignments ()
(goto-char (point-min))
(while (< (point) (point-max))
(and (looking-at "\\([A-Z_]+\\)=\\(.*\\)$")
(set (intern (match-string 1)) (match-string 2)))
(forward-line 1)))
I don't think regexp is what really need. You need to split your string by \n and =, so you just say exactly the same to interpreter.
I think you can also use intern to get symbol from string(and set variables). I use it for the first time, so comment here if i am wrong. Anyways, if list is what you want, just remove top-level mapcar.
(defun set=(str)
(mapcar (lambda(arg)
(set
(intern (car arg))
(cadr arg)))
(mapcar (lambda(arg)
(split-string arg "=" t))
(split-string
str
"\n" t))))
(set=
"ID_AUDIO_ID=0
ID_FILENAME=/home/axiom/abc.wav
ID_DEMUXER=audio
ID_AUDIO_FORMAT=1
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=0
ID_AUDIO_NCH=1
ID_LENGTH=3207.00
ID_SEEKABLE=1
ID_CHAPTERS=0
ID_AUDIO_BITRATE=512000
ID_AUDIO_RATE=32000
ID_AUDIO_NCH=1
ID_AUDIO_CODEC=pcm
ID_EXIT=EOF")

emacs/openwith how to pass arguments to program?

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.