From mboxrd@z Thu Jan 1 00:00:00 1970 From: =?ISO-8859-1?Q?Jan_B=F6cker?= Subject: [PATCH] Allow regexps in org-file-apps to capture link parameters using groups Date: Sat, 16 Jan 2010 15:45:24 +0100 Message-ID: <4B51D104.9090502@jboecker.de> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit Return-path: Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NW9uf-00013n-Mx for emacs-orgmode@gnu.org; Sat, 16 Jan 2010 09:46:05 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NW9ub-0000xf-9s for emacs-orgmode@gnu.org; Sat, 16 Jan 2010 09:46:05 -0500 Received: from [199.232.76.173] (port=33621 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NW9ub-0000xU-5C for emacs-orgmode@gnu.org; Sat, 16 Jan 2010 09:46:01 -0500 Received: from mail7.worldserver.net ([217.13.200.27]:33900) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1NW9ua-0004i4-Ip for emacs-orgmode@gnu.org; Sat, 16 Jan 2010 09:46:01 -0500 List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: Org Mode What is this? ============= This patch changes the way extension regexps in `org-file-apps' are handled. Instead of against the file name, the regexps are now matched against the whole link, and you can use grouping to extract link parameters which you can then use in a command string to be executed. For example, to allow linking to PDF files using the syntax file:/doc.pdf::, you can add the following entry to org-file-apps: Extension: \.pdf::\([0-9]+\)\' Command: evince "%s" -p %1 In a command string to be executed, the parameters can be referenced using %1, %2, etc. Lisp forms can access them using (string-match n link). Where to get it? ================ Either apply the patch by hand or git pull git://github.com/jboecker/org-mode.git org-file-apps-parameters What's next? / Feedback ======================= - Find the bugs. Since this messes with links, a central concept of Org, I probably have missed some edge cases; so please test this and report if it works for you. I also appreciate any feedback on code quality or the design decisions made. I am learning elisp along the way, so you may be able to write some changes in a more idiomatic and/or elegant way. - Add a mechanism for org-mode modules to add default values to org-file-apps, similar to the variables org-file-apps-defaults-*. This could be used by modules to define their own extensions to the syntax of file: links. - Modify org-docview.el to use this and deprecate the docview: link syntax. What does it (intentionally) break? =================================== This patch introduces a backwards-incompatible change. If LINE or SEARCH is given, the file is no longer guaranteed to open in emacs: if IN-EMACS is nil and an entry in org-file-apps matches, that takes precedence. A grep of the lisp/ and contrib/ directories showed that no code in the org-mode distribution was relying on this behaviour; whereever LINE or SEARCH is given, IN-EMACS is also set to t. I decided against adding an additional parameter because that would be redundant; the original link as seen by org-open-at-point can be reconstructed from PATH, LINE and SEARCH. I am not that sure if this is the right way to do this, but it seems to break as little as possible while hopefully avoiding to add too much complexity. --- lisp/ChangeLog | 10 ++++++++++ lisp/org.el | 56 +++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 3f46f3c..c4605bd 100755 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,13 @@ +2010-01-16 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 + (string-match 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-01-16 Carsten Dominik * org.el (org-link-unescape, org-link-escape): Only use hexlify if diff --git a/lisp/org.el b/lisp/org.el index ee81c4d..2351419 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -1463,7 +1463,7 @@ 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 name. For backward + \"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. `directory' Matches a directory @@ -1494,9 +1494,13 @@ 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. + by the path to the file. If the file identifier is a regex, + %n will be replaced by the match of the nth subexpression (group). sexp A Lisp form which will be evaluated. The file path will - be available in the Lisp variable `file'. + 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). For more examples, see the system specific constants `org-file-apps-defaults-macosx' `org-file-apps-defaults-windowsnt' @@ -8935,10 +8939,12 @@ 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, 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. + 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)))) @@ -8950,10 +8956,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) @@ -8965,8 +8980,13 @@ 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))) - (assoc-default dfile (org-apps-regexp-alist apps a-m-a-p) - 'string-match) + ;; 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)) (cdr (assoc ext apps)) (cdr (assoc t apps)))))) (when (eq cmd 'system) @@ -8996,6 +9016,18 @@ 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 the command with group matches from the 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)) @@ -9008,7 +9040,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))) @@ -9038,7 +9072,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)))) -- 1.6.6