emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* [RFC] [export] synctex support for ox-latex
@ 2013-10-28 18:17 Aaron Ecay
  2013-10-29 11:11 ` Rasmus
  2013-11-05 10:54 ` Bastien
  0 siblings, 2 replies; 5+ messages in thread
From: Aaron Ecay @ 2013-10-28 18:17 UTC (permalink / raw)
  To: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 920 bytes --]

Hello,

Some months ago, I proposed a patch to implement synctex support for the
latex exporter.  Following feedback from Nicolas, I was working on
converting that code to use hooks and advice, without modifying core
org-mode functions.  It was a frustrating but very educational task, and
it is now complete.  I attach the patch (which consists only of a single
file addition to the contrib directory) to this message.

It is very simple to use: load the file, and then M-x
ox-synctex-activate.  Now every time you export latex to a pdf, the code
will patch the resultant synctex file so you can jump from a pdf viewer
to the (approximate) org source line that generated it.  The hooks and
advice can all be removed with M-x ox-synctex-deactivate.

Aaron

PS Note that you must do the latex compilation within org (C-c C-e l p);
you can’t export the .tex file and compile it from the command line.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-add-synctex-support.patch --]
[-- Type: text/x-diff, Size: 9953 bytes --]

From 43d4bc0ee82874d4389dd7ead7fccd3c81c68418 Mon Sep 17 00:00:00 2001
From: Aaron Ecay <aaronecay@gmail.com>
Date: Wed, 23 Oct 2013 15:29:56 -0400
Subject: [PATCH] add synctex support

* contrib/lisp/ox-synctex.el: new file
---
 contrib/lisp/ox-synctex.el | 252 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 252 insertions(+)
 create mode 100644 contrib/lisp/ox-synctex.el

diff --git a/contrib/lisp/ox-synctex.el b/contrib/lisp/ox-synctex.el
new file mode 100644
index 0000000..6f04c14
--- /dev/null
+++ b/contrib/lisp/ox-synctex.el
@@ -0,0 +1,252 @@
+;;; ox-synctex.el --- Synctex functionality for org LaTeX export
+
+;; Copyright (C) 2013 Aaron Ecay
+
+;; Author: Aaron Ecay <aaronecay@gmail.com>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This code provides synctex support for org mode export to latex.
+;; To activate, execute (ox-synctex-activate).  To deactivate,
+;; (ox-synctex-deactivate)
+
+;; TODOs:
+;; - support multi-file documents through #+include and friends
+;; - do something so that clicks on a minted source code block go to
+;;   the .org file and not the .pyg intermediate
+;; - ...
+
+;;; Code:
+
+;;;; Internal functions and variable
+
+(defvar ox-synctex--concordance nil
+  "The concordance resulting from the last export operation.")
+
+(defun ox-synctex--read-concordance (concordance src-line)
+  "Get the output line number from CONCORDANCE for input line SRC-LINE."
+  ;; TODO: not robust against malformed concordances
+  (while (and (caadr concordance)
+              (<= (caadr concordance) src-line))
+    (setq concordance (cdr concordance)))
+  (cdar concordance))
+
+(defun ox-synctex--propertize-buffer ()
+  "Put line-number text properties on a buffer.
+
+Each line gets a org-line-num-pre property, which is its line
+number in the buffer.  When export operations change the buffer,
+the text property will still reflect the original state of affairs."
+  (save-restriction
+    (widen)
+    (while (= 0 (forward-line 1))
+      (put-text-property (point) (point-at-eol)
+			 'ox-synctex-line-num
+			 (line-number-at-pos)))))
+
+(defun ox-synctex--line-number-at-pos (pos)
+  "Return the buffer line number at POS, widening if necessary.
+
+This function first looks for text properties set by
+`ox-synctex--propertize-buffer' which allow it to return an
+accurate line number in a buffer copy modified during export.  It
+falls back to the usual method of calculating line numbers if no
+text properties are found."
+  (or (get-text-property pos 'ox-synctex-line-num)
+      (save-excursion
+        (widen)
+        (line-number-at-pos pos))))
+
+(defun ox-synctex--add-line-to-element (element)
+  "Add begin and end line numbers to an element as returned by `org-element'."
+  (let* ((plist (cadr element))
+	 (beg (plist-get plist :begin))
+	 (end (plist-get plist :end)))
+    (and beg (plist-put plist :begin-line (ox-synctex--line-number-at-pos beg)))
+    (and end (plist-put plist :end-line (ox-synctex--line-number-at-pos end)))
+    element))
+
+
+(defun ox-synctex--propertize-string (data string)
+  "Add line number text properties to STRING, based on DATA.
+
+The function works by copying the properties added by
+`ox-synctex--add-line-to-element' to the string.  This will allow
+the construction of a concordance from the exported string."
+  (let ((len (length string)))
+    (when (> len 1)
+      (put-text-property 0 1 'org-line-num
+                         (org-element-property :begin-line data)
+                         string)
+      (put-text-property (1- len) len 'org-line-num
+                         (org-element-property :end-line data)
+                         string)))
+  string)
+
+(defun ox-synctex--build-concordance ()
+  "Build a concordance, based on text properties added by
+`ox-synctex--propertize-string' and accumulated in in an export
+result buffer.
+
+Has the form ((OUT-LINE . IN-LINE) ...)"
+  (save-excursion
+    (let ((res '())
+          next)
+      (goto-char (point-min))
+      (while (setq next (next-single-property-change (point) 'org-line-num))
+        (goto-char next)
+	(let ((ln (get-text-property (point) 'org-line-num)))
+	  ;; TODO: `ln' should never be nil, but sometimes it is.  For
+	  ;; now, we hack around that with this `when'.
+	  (when ln
+	    (setq res (cons (cons (line-number-at-pos) ln)
+			    res))))
+        (forward-char 1))
+      (setq res (nreverse res))
+      (setq next res)
+      (while (cdr next)
+        (if (equal (caar next) (caadr next))
+            (setcdr next (cddr next))
+          (setq next (cdr next))))
+      res)))
+
+(defun ox-synctex--patch-synctex (file)
+  "Patch the synctex file resulting from the last export
+operation, using the information stored in
+`ox-synctex--concordance'."
+  (let* ((file-base (file-name-nondirectory
+		     (replace-regexp-in-string "\\.tex\\'" "." file)))
+	 (synctex-file (concat file-base "synctex.gz")))
+    (cond
+     ((not ox-synctex--concordance)
+      (message "No concordance, not patching."))
+     ((not (file-exists-p synctex-file))
+      (message "No synctex file found, not patching."))
+     (t
+      (let* ((conc ox-synctex--concordance)
+	     (buf (find-file-noselect synctex-file)))
+	(with-current-buffer buf
+	  (let ((max-index 0)
+		the-index extra-path new-index)
+	    (goto-char (point-min))
+	    (while (re-search-forward "^Input:\\([0-9]+\\):" nil t)
+	      (setq max-index (max max-index (string-to-number (match-string 1)))))
+	    (setq new-index (number-to-string (1+ max-index)))
+	    (goto-char (point-min))
+	    (when (re-search-forward (concat "^Input:\\([0-9]+\\):\\(.*\\)"
+					     (regexp-quote file-base) "tex$")
+				     nil t)
+	      (setq the-index (string-to-number (match-string 1)))
+	      (setq extra-path (match-string 2))
+	      (goto-char (line-end-position))
+	      (insert (format "\nInput:%s:%s%sorg" new-index extra-path file-base)))
+	    (goto-char (point-min))
+	    (while (re-search-forward (format "^[vhxkgr$[()]\\(%s\\),\\([0-9]+\\):"
+					      the-index)
+				      nil t)
+	      (let ((new-line (ox-synctex--read-concordance
+			       ox-synctex--concordance
+			       (string-to-number (match-string 2)))))
+		(when new-line
+		  (replace-match new-index nil t nil 1)
+		  (replace-match (int-to-string new-line)
+				 nil t nil 2))))
+	    (save-buffer)))
+	(kill-buffer buf))))))
+
+;;;; Hooks and advice
+
+(defun ox-synctex--before-processing-hook (&rest ignore)
+  (ox-synctex--propertize-buffer))
+
+(defconst ox-synctex--parsers-to-patch
+  (append org-element-greater-elements org-element-all-elements))
+
+;;; Patch all `org-element' parsers to add line number info to their
+;;; return values.
+(dolist (parser ox-synctex--parsers-to-patch)
+  (let ((parser-fn (intern (format "org-element-%s-parser"
+				   (symbol-name parser)))))
+    (eval `(defadvice ,parser-fn (around ox-synctex)
+	     "Advice added by `ox-synctex'."
+	     ad-do-it
+	     (setq ad-return-value (ox-synctex--add-line-to-element
+				    ad-return-value))))))
+
+;;; Patch element->string conversion to carry through the line numbers
+;;; added above
+(defadvice org-export-transcoder (around ox-synctex)
+  ad-do-it
+  (when (and ad-return-value
+	     (org-export-derived-backend-p
+	      (plist-get (ad-get-arg 1) :back-end)
+	      'latex))
+    (setq ad-return-value
+	  `(lambda (data contents &optional info)
+	     (ox-synctex--propertize-string
+	      data
+	      (if info
+		  (,ad-return-value data contents info)
+		;; The plain text transcoder takes only 2 arguments;
+		;; here contents is really info.  I couldn't find a
+		;; better way to inspect the arity of elisp
+		;; functions...?
+		(,ad-return-value data contents)))))))
+
+;;; Patch to build the concordance once we have the export result.  We
+;;; need to hack around the fact that the original function strips
+;;; text properties from its return value which we need.
+(defadvice org-export-as (around ox-synctex)
+  (cl-letf (((symbol-function 'org-no-properties)
+	     (lambda (s &optional _restricted) s)))
+    ad-do-it)
+  (when (org-export-derived-backend-p (ad-get-arg 0) 'latex)
+    (with-temp-buffer
+      (insert ad-return-value)
+      (setq ox-synctex--concordance (ox-synctex--build-concordance))))
+  (setq ad-return-value (org-no-properties ad-return-value)))
+
+;;; Actually do the patching after compilation
+(defadvice org-latex-compile (around ox-synctex)
+  ad-do-it
+  (ox-synctex--patch-synctex (ad-get-arg 0))
+  ;; Some PDF viewers (eg evince) don't notice changes to the synctex
+  ;; file, so we need to poke them to reload the pdf after we've
+  ;; finished changing it.
+  (call-process dired-touch-program nil nil nil
+		(replace-regexp-in-string "\\.tex\\'" "." (ad-get-arg 0))))
+
+;;;; User-facing functions
+
+(defun ox-synctex-activate ()
+  (interactive)
+  (add-hook 'org-export-before-processing-hook
+            #'ox-synctex--before-processing-hook)
+  (ad-activate-regexp "ox-synctex"))
+
+(defun ox-synctex-deactivate ()
+  (interactive)
+  (remove-hook 'org-export-before-processing-hook
+	       #'ox-synctex--before-processing-hook)
+  (ad-deactivate-regexp "ox-synctex"))
+
+(provide 'ox-synctex)
+
+;; Local Variables:
+;; lexical-binding: t
+;; End:
+
+;;; ox-synctex.el ends here
-- 
1.8.4.1


[-- Attachment #3: Type: text/plain, Size: 15 bytes --]

-- 
Aaron Ecay

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [RFC] [export] synctex support for ox-latex
  2013-10-28 18:17 [RFC] [export] synctex support for ox-latex Aaron Ecay
@ 2013-10-29 11:11 ` Rasmus
  2013-10-30  4:59   ` Aaron Ecay
  2013-11-05 10:54 ` Bastien
  1 sibling, 1 reply; 5+ messages in thread
From: Rasmus @ 2013-10-29 11:11 UTC (permalink / raw)
  To: emacs-orgmode

Hi Aaron,

Thanks for your work on this patch.

Aaron Ecay <aaronecay@gmail.com> writes:

> It is very simple to use: load the file, and then M-x
> ox-synctex-activate.  Now every time you export latex to a pdf, the code
> will patch the resultant synctex file so you can jump from a pdf viewer
> to the (approximate) org source line that generated it.  The hooks and
> advice can all be removed with M-x ox-synctex-deactivate.

Still a nice idea.  

It doesn't work for me however.  Or perhaps I just don't get it.  I am
expecting it to work similarly to AUCTeX-synctex and other non-Emacs
editors supporting synctex.  E.g. a red box usually pops up,
highlighting the correct line and I'm able to jump back from the pdf
to the source.  Neither works.

I tested it with emacs -q.  

Note, there should probably be some require statement in the top of
your file.  ox-latex would work, but you might only need org-element.

Software:

Org-mode version 8.2.1 (release_8.2.1-86-gbe3dad @
/usr/share/emacs/site-lisp/org/)

GNU Emacs 24.3.50.1 (x86_64-unknown-linux-gnu, GTK+ Version 3.10.0) of
2013-10-03 on pank

Evince 3.10.  

Texlive 2013, up to date.

–Rasmus

-- 
You people at the NSA are becoming my new best friends!

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [RFC] [export] synctex support for ox-latex
  2013-10-29 11:11 ` Rasmus
@ 2013-10-30  4:59   ` Aaron Ecay
  2013-10-30 13:14     ` Rasmus
  0 siblings, 1 reply; 5+ messages in thread
From: Aaron Ecay @ 2013-10-30  4:59 UTC (permalink / raw)
  To: Rasmus, emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 2175 bytes --]

Hi Rasmus,

Thank you very much for testing the patch!

2013ko urriak 29an, Rasmus-ek idatzi zuen:

[...]

> It doesn't work for me however.  Or perhaps I just don't get it.  I am
> expecting it to work similarly to AUCTeX-synctex and other non-Emacs
> editors supporting synctex.  E.g. a red box usually pops up,
> highlighting the correct line and I'm able to jump back from the pdf
> to the source.  Neither works.

Indeed, the jump from emacs -> pdf is not implemented.  I’ve got some
complicated dbus voodoo (attached to this email, in case it is useful
for you or others) in my init.el to get that working with AucTeX – I am
also using evince as the viewer).  So I will have to investigate how to
add that feature.

The jump from pdf viewer -> org should be working though, assuming it
does for you in auctex.  (I also have some dbus arcana for that portion
in my init.el file; I assume you do too).

Ideally, I think ox-synctex should eventually include the configurations
for as many pdf viewers as possible, so that users do not need to
configure this themselves.  (Ideally x 2, some external library would
already provide this...)

> 
> I tested it with emacs -q.  
> 
> Note, there should probably be some require statement in the top of
> your file.  ox-latex would work, but you might only need org-element.

This is right; I added both just to be safe (and dired, which was also
needed since I borrow a defcustom from there).

One thing I forgot to mention in my last email is that you need to
customize your org-latex-pdf-process to make the latex compiler generate
a synctex file.  (This is a command line switch, but it differs across
(pdf/xe/lua)tex.)  So this could be why it does not work for you in
emacs -q.  The following bit of code suffices, after M-x load-library
ox-latex:

(setq org-latex-pdf-process 
      '("pdflatex -synctex=1 -interaction nonstopmode -output-directory %o %f"))

I attach another version of the patch, with the missing requires as well
as some more logging code.  If it doesn’t work for you, could you
perhaps send me the lines in *Messages* generated by the export?


[-- Attachment #2: evince.el --]
[-- Type: application/emacs-lisp, Size: 2381 bytes --]

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-add-synctex-support.patch --]
[-- Type: text/x-diff, Size: 10279 bytes --]

From 05333e2cde7520d81daec986bdab3235a5d0c348 Mon Sep 17 00:00:00 2001
From: Aaron Ecay <aaronecay@gmail.com>
Date: Wed, 23 Oct 2013 15:29:56 -0400
Subject: [PATCH] add synctex support

* contrib/lisp/ox-synctex.el: new file
---
 contrib/lisp/ox-synctex.el | 260 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 260 insertions(+)
 create mode 100644 contrib/lisp/ox-synctex.el

diff --git a/contrib/lisp/ox-synctex.el b/contrib/lisp/ox-synctex.el
new file mode 100644
index 0000000..e0ef4a3
--- /dev/null
+++ b/contrib/lisp/ox-synctex.el
@@ -0,0 +1,260 @@
+;;; ox-synctex.el --- Synctex functionality for org LaTeX export
+
+;; Copyright (C) 2013 Aaron Ecay
+
+;; Author: Aaron Ecay <aaronecay@gmail.com>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This code provides synctex support for org mode export to latex.
+;; To activate, execute (ox-synctex-activate).  To deactivate,
+;; (ox-synctex-deactivate)
+
+;; TODOs:
+;; - support multi-file documents through #+include and friends
+;; - do something so that clicks on a minted source code block go to
+;;   the .org file and not the .pyg intermediate
+;; - ...
+
+;;; Code:
+
+(require 'org-element)
+(require 'ox-latex)
+(require 'dired) ;; for `dired-touch-program'
+
+;;;; Internal functions and variable
+
+(defvar ox-synctex--concordance nil
+  "The concordance resulting from the last export operation.")
+
+(defun ox-synctex--read-concordance (concordance src-line)
+  "Get the output line number from CONCORDANCE for input line SRC-LINE."
+  ;; TODO: not robust against malformed concordances
+  (while (and (caadr concordance)
+              (<= (caadr concordance) src-line))
+    (setq concordance (cdr concordance)))
+  (cdar concordance))
+
+(defun ox-synctex--propertize-buffer ()
+  "Put line-number text properties on a buffer.
+
+Each line gets a org-line-num-pre property, which is its line
+number in the buffer.  When export operations change the buffer,
+the text property will still reflect the original state of affairs."
+  (save-restriction
+    (widen)
+    (while (= 0 (forward-line 1))
+      (put-text-property (point) (point-at-eol)
+			 'ox-synctex-line-num
+			 (line-number-at-pos)))))
+
+(defun ox-synctex--line-number-at-pos (pos)
+  "Return the buffer line number at POS, widening if necessary.
+
+This function first looks for text properties set by
+`ox-synctex--propertize-buffer' which allow it to return an
+accurate line number in a buffer copy modified during export.  It
+falls back to the usual method of calculating line numbers if no
+text properties are found."
+  (or (get-text-property pos 'ox-synctex-line-num)
+      (save-excursion
+        (widen)
+        (line-number-at-pos pos))))
+
+(defun ox-synctex--add-line-to-element (element)
+  "Add begin and end line numbers to an element as returned by `org-element'."
+  (let* ((plist (cadr element))
+	 (beg (plist-get plist :begin))
+	 (end (plist-get plist :end)))
+    (and beg (plist-put plist :begin-line (ox-synctex--line-number-at-pos beg)))
+    (and end (plist-put plist :end-line (ox-synctex--line-number-at-pos end)))
+    element))
+
+
+(defun ox-synctex--propertize-string (data string)
+  "Add line number text properties to STRING, based on DATA.
+
+The function works by copying the properties added by
+`ox-synctex--add-line-to-element' to the string.  This will allow
+the construction of a concordance from the exported string."
+  (let ((len (length string)))
+    (when (> len 1)
+      (put-text-property 0 1 'org-line-num
+                         (org-element-property :begin-line data)
+                         string)
+      (put-text-property (1- len) len 'org-line-num
+                         (org-element-property :end-line data)
+                         string)))
+  string)
+
+(defun ox-synctex--build-concordance ()
+  "Build a concordance, based on text properties added by
+`ox-synctex--propertize-string' and accumulated in in an export
+result buffer.
+
+Has the form ((OUT-LINE . IN-LINE) ...)"
+  (save-excursion
+    (let ((res '())
+          next)
+      (goto-char (point-min))
+      (while (setq next (next-single-property-change (point) 'org-line-num))
+        (goto-char next)
+	(let ((ln (get-text-property (point) 'org-line-num)))
+	  ;; TODO: `ln' should never be nil, but sometimes it is.  For
+	  ;; now, we hack around that with this `when'.
+	  (when ln
+	    (setq res (cons (cons (line-number-at-pos) ln)
+			    res))))
+        (forward-char 1))
+      (setq res (nreverse res))
+      (setq next res)
+      (while (cdr next)
+        (if (equal (caar next) (caadr next))
+            (setcdr next (cddr next))
+          (setq next (cdr next))))
+      res)))
+
+(defun ox-synctex--patch-synctex (file)
+  "Patch the synctex file resulting from the last export
+operation, using the information stored in
+`ox-synctex--concordance'."
+  (let* ((file-base (file-name-nondirectory
+		     (replace-regexp-in-string "\\.tex\\'" "." file)))
+	 (synctex-file (concat file-base "synctex.gz")))
+    (cond
+     ((not ox-synctex--concordance)
+      (message "ox-synctex: no concordance, not patching."))
+     ((not (file-exists-p synctex-file))
+      (message "ox-synctex: no synctex file found, not patching."))
+     (t
+      (message "ox-synctex: patching synctex file")
+      (let* ((conc ox-synctex--concordance)
+	     (buf (find-file-noselect synctex-file)))
+	(with-current-buffer buf
+	  (let ((max-index 0)
+		the-index extra-path new-index)
+	    (goto-char (point-min))
+	    (while (re-search-forward "^Input:\\([0-9]+\\):" nil t)
+	      (setq max-index (max max-index (string-to-number (match-string 1)))))
+	    (setq new-index (number-to-string (1+ max-index)))
+	    (goto-char (point-min))
+	    (when (re-search-forward (concat "^Input:\\([0-9]+\\):\\(.*\\)"
+					     (regexp-quote file-base) "tex$")
+				     nil t)
+	      (setq the-index (string-to-number (match-string 1)))
+	      (setq extra-path (match-string 2))
+	      (goto-char (line-end-position))
+	      (insert (format "\nInput:%s:%s%sorg" new-index extra-path file-base)))
+	    (goto-char (point-min))
+	    (while (re-search-forward (format "^[vhxkgr$[()]\\(%s\\),\\([0-9]+\\):"
+					      the-index)
+				      nil t)
+	      (let ((new-line (ox-synctex--read-concordance
+			       ox-synctex--concordance
+			       (string-to-number (match-string 2)))))
+		(when new-line
+		  (replace-match new-index nil t nil 1)
+		  (replace-match (int-to-string new-line)
+				 nil t nil 2))))
+	    (save-buffer)))
+	(kill-buffer buf))))))
+
+;;;; Hooks and advice
+
+(defun ox-synctex--before-processing-hook (&rest ignore)
+  (ox-synctex--propertize-buffer))
+
+(defconst ox-synctex--parsers-to-patch
+  (append org-element-greater-elements org-element-all-elements))
+
+;;; Patch all `org-element' parsers to add line number info to their
+;;; return values.
+(dolist (parser ox-synctex--parsers-to-patch)
+  (let ((parser-fn (intern (format "org-element-%s-parser"
+				   (symbol-name parser)))))
+    (eval `(defadvice ,parser-fn (around ox-synctex)
+	     "Advice added by `ox-synctex'."
+	     ad-do-it
+	     (setq ad-return-value (ox-synctex--add-line-to-element
+				    ad-return-value))))))
+
+;;; Patch element->string conversion to carry through the line numbers
+;;; added above
+(defadvice org-export-transcoder (around ox-synctex)
+  ad-do-it
+  (when (and ad-return-value
+	     (org-export-derived-backend-p
+	      (plist-get (ad-get-arg 1) :back-end)
+	      'latex))
+    (setq ad-return-value
+	  `(lambda (data contents &optional info)
+	     (ox-synctex--propertize-string
+	      data
+	      (if info
+		  (,ad-return-value data contents info)
+		;; The plain text transcoder takes only 2 arguments;
+		;; here contents is really info.  I couldn't find a
+		;; better way to inspect the arity of elisp
+		;; functions...?
+		(,ad-return-value data contents)))))))
+
+;;; Patch to build the concordance once we have the export result.  We
+;;; need to hack around the fact that the original function strips
+;;; text properties from its return value which we need.
+(defadvice org-export-as (around ox-synctex)
+  (cl-letf (((symbol-function 'org-no-properties)
+	     (lambda (s &optional _restricted) s)))
+    ad-do-it)
+  (when (org-export-derived-backend-p (ad-get-arg 0) 'latex)
+    (message "ox-synctex: patching org-export-as return")
+    (with-temp-buffer
+      (insert ad-return-value)
+      (setq ox-synctex--concordance (ox-synctex--build-concordance))))
+  (setq ad-return-value (org-no-properties ad-return-value)))
+
+;;; Actually do the patching after compilation
+(defadvice org-latex-compile (around ox-synctex)
+  (message "ox-synctex: active during latex compile")
+  ad-do-it
+  (ox-synctex--patch-synctex (ad-get-arg 0))
+  ;; Some PDF viewers (eg evince) don't notice changes to the synctex
+  ;; file, so we need to poke them to reload the pdf after we've
+  ;; finished changing it.
+  (call-process dired-touch-program nil nil nil
+		(replace-regexp-in-string "\\.tex\\'" "." (ad-get-arg 0)))
+  (message "ox-synctex: done, hoorah!"))
+
+;;;; User-facing functions
+
+(defun ox-synctex-activate ()
+  (interactive)
+  (add-hook 'org-export-before-processing-hook
+            #'ox-synctex--before-processing-hook)
+  (ad-activate-regexp "ox-synctex"))
+
+(defun ox-synctex-deactivate ()
+  (interactive)
+  (remove-hook 'org-export-before-processing-hook
+	       #'ox-synctex--before-processing-hook)
+  (ad-deactivate-regexp "ox-synctex"))
+
+(provide 'ox-synctex)
+
+;; Local Variables:
+;; lexical-binding: t
+;; End:
+
+;;; ox-synctex.el ends here
-- 
1.8.4.2


[-- Attachment #4: Type: text/plain, Size: 25 bytes --]


Thanks,

-- 
Aaron Ecay

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [RFC] [export] synctex support for ox-latex
  2013-10-30  4:59   ` Aaron Ecay
@ 2013-10-30 13:14     ` Rasmus
  0 siblings, 0 replies; 5+ messages in thread
From: Rasmus @ 2013-10-30 13:14 UTC (permalink / raw)
  To: emacs-orgmode

Hi Aaron,

Aaron Ecay <aaronecay@gmail.com> writes:

>> It doesn't work for me however.  Or perhaps I just don't get it.  I am
>> expecting it to work similarly to AUCTeX-synctex and other non-Emacs
>> editors supporting synctex.  E.g. a red box usually pops up,
>> highlighting the correct line and I'm able to jump back from the pdf
>> to the source.  Neither works.
>
> Indeed, the jump from emacs -> pdf is not implemented.  I’ve got some
> complicated dbus voodoo (attached to this email, in case it is useful
> for you or others) in my init.el to get that working with AucTeX – I am
> also using evince as the viewer).  So I will have to investigate how to
> add that feature.

For me it works out of the box.

The relevant bits to get Synctex in AUCTeX working for me are:

   (setq TeX-source-correlate-mode t
         TeX-source-correlate-method 'synctex)

using AUCTeX-git from May 27 this year.

> The jump from pdf viewer -> org should be working though, assuming it
> does for you in auctex.  (I also have some dbus arcana for that portion
> in my init.el file; I assume you do too).

No dbus stuff in my Emacs.  The only dbus thing I do is when I start
my window manager in xinitrc:

   exec dbus-launch --exit-with-session i3

Further, I run the following standard  Archlinux xinit stuff:

# launches a session dbus instance
if [ -z "$DBUS_SESSION_BUS_ADDRESS" ] && type dbus-launch >/dev/null; then
  eval $(dbus-launch --sh-syntax --exit-with-session)
fi

That's it.

> Ideally, I think ox-synctex should eventually include the configurations
> for as many pdf viewers as possible, so that users do not need to
> configure this themselves.  (Ideally x 2, some external library would
> already provide this...)

I think AUCTeX is the reference here.  It works as well as TeXWorks
wrt. Synctex now.

>> I tested it with emacs -q.  
>> 
>> Note, there should probably be some require statement in the top of
>> your file.  ox-latex would work, but you might only need org-element.
>
> This is right; I added both just to be safe (and dired, which was also
> needed since I borrow a defcustom from there).

Something is still missing.  When running the following test from
emacs -q I get the
included error

#+BEGIN_SRC emacs-lisp
(load "~/.emacs.d/lisp/ox-synctex.el")
(setq org-latex-pdf-process 
      '("pdflatex -synctex=1 -interaction nonstopmode -output-directory %o %f"))
(ox-synctex-activate)
(org-latex-export-to-pdf)
#+END_SRC
* test
results in 
: ad-Advice-org-export-as: Invalid function: ((symbol-function (quote org-no-properties)) (lambda (s &optional _restricted) s))

It works with my normal Emacs.

> One thing I forgot to mention in my last email is that you need to
> customize your org-latex-pdf-process to make the latex compiler generate
> a synctex file.  (This is a command line switch, but it differs across
> (pdf/xe/lua)tex.)  So this could be why it does not work for you in
> emacs -q.  The following bit of code suffices, after M-x load-library
> ox-latex:
>
> (setq org-latex-pdf-process 
>       '("pdflatex -synctex=1 -interaction nonstopmode -output-directory %o %f"))
>
> I attach another version of the patch, with the missing requires as well
> as some more logging code.  If it doesn’t work for you, could you
> perhaps send me the lines in *Messages* generated by the export?

I think I also added it yesterday when I tested it.

ox-synctex: active during latex compile
Processing LaTeX file ./test.tex...
Process completed.
ox-synctex: no concordance, not patching.
ox-synctex: done, hoorah!
Running evince /home/rasmus/download/tmp/test.pdf...done

I'm still not able to go to the source from Evince.

Perhaps I'll have time to do proper debugging over the weekend, but no
promises.

–Rasmus


-- 
El Rey ha muerto. ¡Larga vida al Rey!

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [RFC] [export] synctex support for ox-latex
  2013-10-28 18:17 [RFC] [export] synctex support for ox-latex Aaron Ecay
  2013-10-29 11:11 ` Rasmus
@ 2013-11-05 10:54 ` Bastien
  1 sibling, 0 replies; 5+ messages in thread
From: Bastien @ 2013-11-05 10:54 UTC (permalink / raw)
  To: Aaron Ecay; +Cc: emacs-orgmode

Hi Aaron,

Aaron Ecay <aaronecay@gmail.com> writes:

> Some months ago, I proposed a patch to implement synctex support for the
> latex exporter.  Following feedback from Nicolas, I was working on
> converting that code to use hooks and advice, without modifying core
> org-mode functions.  It was a frustrating but very educational task, and
> it is now complete.  I attach the patch (which consists only of a single
> file addition to the contrib directory) to this message.

Please feel free to add this to the contrib/ directory or ask for
someone to do it.

Thanks!

-- 
 Bastien

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-11-05 10:54 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-10-28 18:17 [RFC] [export] synctex support for ox-latex Aaron Ecay
2013-10-29 11:11 ` Rasmus
2013-10-30  4:59   ` Aaron Ecay
2013-10-30 13:14     ` Rasmus
2013-11-05 10:54 ` Bastien

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).