From cd70e855224a5d308adec59f34dc3aa3088fffb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6cker?= Date: Fri, 9 Apr 2010 18:33:53 +0200 Subject: [PATCH 1/6] Revert "Improve file opening when matching links" This reverts commit 39c91ba24a3bc34f84d66de5de20f5b10e854b84. --- lisp/ChangeLog | 1 - lisp/org.el | 18 ++++++------------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 1d13ebc74..13f707948 100755 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -9,7 +9,6 @@ frames. (org-export-latex-default-packages-alist): hyperref must be loaded late. - (org-open-file): More care with the new matching for file links. 2010-04-07 Carsten Dominik diff --git a/lisp/org.el b/lisp/org.el index c89c5acb9..68db7780c 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -9172,19 +9172,13 @@ If the file does not exist, an error is thrown." (and dirp (cdr (assoc 'directory apps))) ;; if we find a match in org-file-apps, store the match ;; data for later - (let* ((re-list1 (org-apps-regexp-alist apps nil)) - (re-list2 - (if a-m-a-p - (org-apps-regexp-alist apps a-m-a-p) - re-list1)) - (private-match - (assoc-default dlink re-list1 'string-match)) - (general-match - (assoc-default dfile re-list2 'string-match))) - (if private-match + (let ((match (assoc-default dlink (org-apps-regexp-alist + apps a-m-a-p) + 'string-match))) + (if match (progn (setq link-match-data (match-data)) - private-match) - general-match)) + match) + nil)) (cdr (assoc ext apps)) (cdr (assoc t apps)))))) (when (eq cmd 'system) From db2056e92af366b82b802f7de4598ebe587b685d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6cker?= Date: Fri, 9 Apr 2010 20:08:21 +0200 Subject: [PATCH 2/6] Revert "Allow regexps in org-file-apps to capture link parameters using groups" This reverts commit 75563bf71e6df356a5ae77a93152fcf913378107. Conflicts: lisp/ChangeLog lisp/org.el --- lisp/ChangeLog | 10 -------- lisp/org.el | 64 ++++++++++---------------------------------------- 2 files changed, 13 insertions(+), 61 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 13f707948..fefc06589 100755 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -293,16 +293,6 @@ (org-table-get, org-table-put, org-table-goto-line) (org-table-current-line): New functions. -2010-03-21 Jan Böcker - - * org.el (org-open-file): Allow regular expressions in - org-file-apps to capture link parameters using groups. In a - command string to be executed, the parameters can be referenced - using %1, %2, etc. Lisp forms can access them using - (match-string n link). - (org-apps-regexp-alist): Adopt the created regexp, as this is now - matched against a file: link instead of the file name. - 2010-03-21 Carsten Dominik * org-crypt.el (org-reveal-start-hook): Add a decryption function diff --git a/lisp/org.el b/lisp/org.el index 68db7780c..16d969be0 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -1463,10 +1463,9 @@ you can use this variable to set the application for a given file extension. The entries in this list are cons cells where the car identifies files and the cdr the corresponding command. Possible values for the file identifier are - \"regex\" Regular expression matched against the file: link. For - backward compatibility, this can also be a string with only - alphanumeric characters, which is then interpreted as an - extension. + \"regex\" Regular expression matched against the file name. For backward + compatibility, this can also be a string with only alphanumeric + characters, which is then interpreted as an extension. `directory' Matches a directory `remote' Matches a remote file, accessible through tramp or efs. Remote files most likely should be visited through Emacs @@ -1495,13 +1494,9 @@ Possible values for the command are: does define this command, but you can overrule/replace it here. string A command to be executed by a shell; %s will be replaced - by the path to the file. If the file identifier is a regex, - %n will be replaced by the match of the nth match group. + by the path to the file. sexp A Lisp form which will be evaluated. The file path will - be available in the Lisp variable `file', the link itself - in the Lisp variable `link'. If the file identifier is a regex, - the original match data will be restored, so subexpression - matches are accessible using (match-string n link). + be available in the Lisp variable `file'. For more examples, see the system specific constants `org-file-apps-defaults-macosx' `org-file-apps-defaults-windowsnt' @@ -9129,12 +9124,10 @@ 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, but IN-EMACS is nil, it will -be assumed that org-open-file was called to open a file: link, and the -original link to match against org-file-apps will be reconstructed -from PATH and whichever of LINE or SEARCH is given. - +search for. If LINE or SEARCH is given, the file will always be +opened in Emacs. 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)))) @@ -9146,19 +9139,10 @@ 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 link-match-data) + ext cmd) (if (string-match "^.*\\.\\([a-zA-Z0-9]+\\.gz\\)$" dfile) (setq ext (match-string 1 dfile)) (if (string-match "^.*\\.\\([a-zA-Z0-9]+\\)$" dfile) @@ -9170,15 +9154,8 @@ 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))) - ;; if we find a match in org-file-apps, store the match - ;; data for later - (let ((match (assoc-default dlink (org-apps-regexp-alist - apps a-m-a-p) - 'string-match))) - (if match - (progn (setq link-match-data (match-data)) - match) - nil)) + (assoc-default dfile (org-apps-regexp-alist apps a-m-a-p) + 'string-match) (cdr (assoc ext apps)) (cdr (assoc t apps)))))) (when (eq cmd 'system) @@ -9208,18 +9185,6 @@ 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)) @@ -9232,9 +9197,7 @@ If the file does not exist, an error is thrown." (if search (org-link-search search)))) ((consp cmd) (let ((file (convert-standard-filename file))) - (save-match-data - (set-match-data link-match-data) - (eval cmd)))) + (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))) @@ -9264,8 +9227,7 @@ be opened in Emacs." nil (if (string-match "\\W" (car x)) x - (cons (concat "\\." (car x) "\\(::.*\\)?\\'") - (cdr x))))) + (cons (concat "\\." (car x) "\\'") (cdr x))))) list)) (if add-auto-mode (mapcar (lambda (x) (cons (car x) 'emacs)) auto-mode-alist)))) From 55dee1d25114c67dc500be3ccaf1739ac2bb73c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6cker?= Date: Fri, 9 Apr 2010 21:10:21 +0200 Subject: [PATCH 3/6] Match regexps in the new variable org-file-apps-ex against the whole link. --- lisp/ChangeLog | 7 +++++ lisp/org.el | 80 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 82 insertions(+), 5 deletions(-) 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))) From 447552b81bc2dd16a39d05db31e6f7a3922eb9ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6cker?= Date: Fri, 9 Apr 2010 23:03:39 +0200 Subject: [PATCH 4/6] fix typo --- lisp/org.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lisp/org.el b/lisp/org.el index fee1b72f7..b6d156c11 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -9206,9 +9206,9 @@ If the file does not exist, an error is thrown." (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) + 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)) From 6deb088a5c855bd94ef2b667338821e2216a0136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6cker?= Date: Sat, 10 Apr 2010 12:22:55 +0200 Subject: [PATCH 5/6] org-open-file: decide whether to match against filename or whole link based on wether the regexp makes use of grouping --- lisp/ChangeLog | 8 +++++++ lisp/org.el | 61 +++++++++++++++++--------------------------------- 2 files changed, 28 insertions(+), 41 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index f2b497489..de18aedaf 100755 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,11 @@ +2010-04-10 Jan Böcker + + * org.el (org-file-apps-entry-uses-grouping-p): new function. + (org-file-apps-ex): remove variable. + (org-open-file): Integrate org-file-apps-ex functionality back + into org-file-apps, and decide whether to match a regexp against + the link or the filename using org-file-apps-entry-uses-grouping-p. + 2010-04-09 Jan Böcker * org.el (org-file-apps-ex): new variable. diff --git a/lisp/org.el b/lisp/org.el index b6d156c11..671037004 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -1520,40 +1520,6 @@ For more examples, see the system specific constants -(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" @@ -9159,14 +9125,17 @@ With optional prefix argument IN-EMACS, Emacs will visit the file. 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 be -opened in Emacs, unless one of the entries in org-file-apps-ex matches. +Optional LINE specifies a line to go to, optional SEARCH a string +to search for. If LINE or SEARCH is given, the file will be +opened in Emacs, unless an entry from org-file-apps that makes +use of groups in a regexp matches. If the file does not exist, an error is thrown." (let* ((file (if (equal path "") buffer-file-name (substitute-in-file-name (expand-file-name path)))) - (apps (append org-file-apps (org-default-apps))) + (file-apps (append org-file-apps (org-default-apps))) + (apps (remove-if 'org-file-apps-entry-uses-grouping-p file-apps)) + (apps-dlink (remove-if-not 'org-file-apps-entry-uses-grouping-p file-apps)) (remp (and (assq 'remote apps) (org-file-remote-p file))) (dirp (if remp nil (file-directory-p file))) (file (if (and dirp org-open-directory-means-index-dot-org) @@ -9198,15 +9167,15 @@ 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 + ; first, try matching against apps-dlink ; if we get a match here, store the match data for later - (let ((match (assoc-default dlink org-file-apps-ex + (let ((match (assoc-default dlink apps-dlink '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, + nil))) ; if we have no match in apps-dlink, ; 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) @@ -9274,6 +9243,16 @@ If the file does not exist, an error is thrown." (not (equal old-pos (point)))) (org-mark-ring-push old-pos old-buffer)))) +(defun org-file-apps-entry-uses-grouping-p (entry) + "This function returns non-nil if `entry' uses a regular + expression that has subexpressions, and which org-open-file + should therefore match against the whole link instead of the + filename." + (let ((selector (car entry))) + (if (stringp selector) + (> (regexp-opt-depth selector) 0) + nil))) + (defun org-default-apps () "Return the default applications for this operating system." (cond From dfda58d720484124f9432a09d831a9d6292908af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6cker?= Date: Sat, 10 Apr 2010 12:46:45 +0200 Subject: [PATCH 6/6] org-open-file: match against dlink only if the command to be executed actually seems to use the subexpression matches as parameters. This does not try to determine if a subexpression match is actually used in the case of a custom lisp form. --- lisp/ChangeLog | 2 +- lisp/org.el | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index de18aedaf..49e411f17 100755 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,6 +1,6 @@ 2010-04-10 Jan Böcker - * org.el (org-file-apps-entry-uses-grouping-p): new function. + * org.el (org-file-apps-entry-match-against-dlink-p): new function. (org-file-apps-ex): remove variable. (org-open-file): Integrate org-file-apps-ex functionality back into org-file-apps, and decide whether to match a regexp against diff --git a/lisp/org.el b/lisp/org.el index 671037004..73c07d2d7 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -9134,8 +9134,8 @@ If the file does not exist, an error is thrown." buffer-file-name (substitute-in-file-name (expand-file-name path)))) (file-apps (append org-file-apps (org-default-apps))) - (apps (remove-if 'org-file-apps-entry-uses-grouping-p file-apps)) - (apps-dlink (remove-if-not 'org-file-apps-entry-uses-grouping-p file-apps)) + (apps (remove-if 'org-file-apps-entry-match-against-dlink-p file-apps)) + (apps-dlink (remove-if-not 'org-file-apps-entry-match-against-dlink-p file-apps)) (remp (and (assq 'remote apps) (org-file-remote-p file))) (dirp (if remp nil (file-directory-p file))) (file (if (and dirp org-open-directory-means-index-dot-org) @@ -9243,14 +9243,23 @@ If the file does not exist, an error is thrown." (not (equal old-pos (point)))) (org-mark-ring-push old-pos old-buffer)))) -(defun org-file-apps-entry-uses-grouping-p (entry) +(defun org-file-apps-entry-match-against-dlink-p (entry) "This function returns non-nil if `entry' uses a regular - expression that has subexpressions, and which org-open-file - should therefore match against the whole link instead of the - filename." - (let ((selector (car entry))) + expression which should be matched against the whole link by + org-open-file. + + It assumes that is the case when the entry uses a regular + expression which has at least one grouping construct and the + action is either a lisp form or a command string containing + '%1', i.e. using at least one subexpression match as a + parameter." + (let ((selector (car entry)) + (action (cdr entry))) (if (stringp selector) - (> (regexp-opt-depth selector) 0) + (and (> (regexp-opt-depth selector) 0) + (or (and (stringp action) + (string-match "%1" action)) + (consp action))) nil))) (defun org-default-apps ()