diff --git a/lisp/ChangeLog b/lisp/ChangeLog index fefc06589..f2b497489 100755 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,10 @@ +2010-04-09 Jan Böcker + + * org.el (org-file-apps-ex): new variable. + (org-open-file): Before considering org-file-apps, first match the + regexps from org-file-apps-ex against the whole link. See + docstring of org-file-apps-ex. + 2010-04-09 Carsten Dominik * org-mobile.el (org-mobile-check-setup): Make sure that there is diff --git a/lisp/org.el b/lisp/org.el index 16d969be0..fee1b72f7 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -1518,6 +1518,42 @@ For more examples, see the system specific constants (string :tag "Command") (sexp :tag "Lisp form"))))) + + +(defcustom org-file-apps-ex + '() + "This variable is like org-file-apps, except that the regular +expressions are matched against the whole link, and you can use +subexpressions to capture parts of the matched link to use as +command line arguments or in a custom lisp form. + +In a command string to be executed, access the subexpression +matches with %1, %2, etc. In a custom lisp form, you can access +them with (match-string n link). + +Example: +To allow linking to page 5 in a PDF using the following syntax: + +file:document.pdf::5 + +use the following entry: + +Regular Expression: \.pdf::\([0-9]+\)\' +Command: evince %s -p %1 + +The first (and only) subexpression captures the page number, +which is passed to evince as the -p argument." + :group 'org-link-follow + :type '(repeat + (cons (choice :value "" + (string :tag "Regular Expression")) + (choice :value "" + (const :tag "Visit with Emacs" emacs) + (string :tag "Command") + (sexp :tag "Lisp form"))))) + + + (defgroup org-refile nil "Options concerning refiling entries in Org-mode." :tag "Org Refile" @@ -9124,10 +9160,9 @@ With a double C-c C-u prefix arg, Org tries to avoid opening in Emacs and to use an external application to visit the file. Optional LINE specifies a line to go to, optional SEARCH a string to -search for. If LINE or SEARCH is given, the file will always be -opened in Emacs. +search for. If LINE or SEARCH is given, the file will be +opened in Emacs, unless one of the entries in org-file-apps-ex matches. If the file does not exist, an error is thrown." - (setq in-emacs (or in-emacs line search)) (let* ((file (if (equal path "") buffer-file-name (substitute-in-file-name (expand-file-name path)))) @@ -9139,10 +9174,19 @@ If the file does not exist, an error is thrown." file)) (a-m-a-p (assq 'auto-mode apps)) (dfile (downcase file)) + ;; reconstruct the original file: link from the PATH, LINE and SEARCH args + (link (cond ((and (eq line nil) + (eq search nil)) + file) + (line + (concat file "::" (number-to-string line))) + (search + (concat file "::" search)))) + (dlink (downcase link)) (old-buffer (current-buffer)) (old-pos (point)) (old-mode major-mode) - ext cmd) + ext cmd link-match-data) (if (string-match "^.*\\.\\([a-zA-Z0-9]+\\.gz\\)$" dfile) (setq ext (match-string 1 dfile)) (if (string-match "^.*\\.\\([a-zA-Z0-9]+\\)$" dfile) @@ -9154,6 +9198,17 @@ If the file does not exist, an error is thrown." (t (setq cmd (or (and remp (cdr (assoc 'remote apps))) (and dirp (cdr (assoc 'directory apps))) + ; first, try matching against org-file-apps-ex + ; if we get a match here, store the match data for later + (let ((match (assoc-default dlink org-file-apps-ex + 'string-match))) + (if match + (progn (setq link-match-data (match-data)) + match) + (progn (setq in-emacs (or in-emacs line search)) + nil)) ; if we have no match in org-file-apps-ex, + ; always open the file in emacs if line or search + ; is given (for backwards compatibility) (assoc-default dfile (org-apps-regexp-alist apps a-m-a-p) 'string-match) (cdr (assoc ext apps)) @@ -9185,6 +9240,19 @@ If the file does not exist, an error is thrown." (shell-quote-argument (convert-standard-filename file))) t t cmd))) + + ;; Replace "%1", "%2" etc. in command with group matches from regex + (save-match-data + (let ((match-index 1) + (number-of-groups (- (/ (length link-match-data) 2) 1))) + (set-match-data link-match-data) + (while (<= match-index number-of-groups) + (let ((regex (concat "%" (number-to-string match-index))) + (replace-with (match-string match-index dlink))) + (while (string-match regex cmd) + (setq cmd (replace-match replace-with t t cmd)))) + (setq match-index (+ match-index 1))))) + (save-window-excursion (start-process-shell-command cmd nil cmd) (and (boundp 'org-wait) (numberp org-wait) (sit-for org-wait)) @@ -9197,7 +9265,9 @@ If the file does not exist, an error is thrown." (if search (org-link-search search)))) ((consp cmd) (let ((file (convert-standard-filename file))) - (eval cmd))) + (save-match-data + (set-match-data link-match-data) + (eval cmd)))) (t (funcall (cdr (assq 'file org-link-frame-setup)) file))) (and (org-mode-p) (eq old-mode 'org-mode) (or (not (equal old-buffer (current-buffer)))