From 791a41a9cb97ae9a237b74c839a1fc2c0f4970db Mon Sep 17 00:00:00 2001 From: Aditya Siram Date: Sat, 14 Sep 2013 11:47:17 -0500 Subject: [PATCH 2/2] Detangling and jumping back now correctly compensate for padded chunks --- lisp/ob-tangle.el | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 5 deletions(-) diff --git a/lisp/ob-tangle.el b/lisp/ob-tangle.el index 8141943..42fa31c 100644 --- a/lisp/ob-tangle.el +++ b/lisp/ob-tangle.el @@ -506,8 +506,8 @@ which enable the original code blocks to be found." "Jump from a tangled code file to the related Org-mode file." (interactive) (let ((mid (point)) - start body-start end done - target-buffer target-char link path block-name body) + start body-start end done depadded-body + target-buffer offset target-char link path block-name body) (save-window-excursion (save-excursion (while (and (re-search-backward org-bracket-link-analytic-regexp nil t) @@ -526,7 +526,7 @@ which enable the original code blocks to be found." (setq end (point-at-bol)))))))) (unless (and start (< start mid) (< mid end)) (error "Not in tangled code")) - (setq body (org-babel-trim (buffer-substring start end)))) + (setq body (buffer-substring start end))) (when (string-match "::" path) (setq path (substring path 0 (match-beginning 0)))) (find-file path) (setq target-buffer (current-buffer)) @@ -537,12 +537,18 @@ which enable the original code blocks to be found." (org-babel-goto-named-src-block block-name)) ;; position at the beginning of the code block body (goto-char (org-babel-where-is-src-block-head)) + (let* ((pad-adjusted-values + (org-babel-detangle-adjust-for-padlines start mid body)) + (depadded-body (car pad-adjusted-values)) + (depadded-point (cdr pad-adjusted-values))) + (progn + (setq offset depadded-point) + (setq body depadded-body))) (forward-line 1) - ;; Use org-edit-special to isolate the code. (org-edit-special) ;; Then move forward the correct number of characters in the ;; code buffer. - (forward-char (- mid body-start)) + (forward-char offset) ;; And return to the Org-mode buffer with the point in the right ;; place. (org-edit-src-exit) @@ -550,6 +556,92 @@ which enable the original code blocks to be found." (org-src-switch-to-buffer target-buffer t) (prog1 body (goto-char target-char)))) +(defun org-babel-detangle-adjust-for-padlines (chunk-start desired-point chunk-body) + "Check if :padline was enabled for this chunk and then +adjust point and body accordingly. Also account for the user +editing the tangled file and removing the padded lines. + +Returns a tuple (body . offset) where body is an adjusted source chunk +with padded newlines possibly removed and offset is how far into +that chunk point is. If point was on either of the padlines, point +is set to the first or last character of the chunk depending on what's +closer." + (save-excursion + (let* ((org-block (org-babel-get-src-block-info)) + (params (nth 2 org-block)) + (org-body (nth 1 org-block)) + (should-be-padded (not (string= "no" (cdr (assoc :padline params))))) + (minimal-padded-chunk-length (+ 1 ; end of first delimiter + 1 ; newline from first padline + 1 ; newline from second padline + 1 ; start of second delimiter + )) + (possibly-padded (>= (length chunk-body) minimal-padded-chunk-length)) + (char-at (lambda (pos str) (substring str pos (+ pos 1)))) + (actually-padded (and (not (= (length chunk-body) 0)) + (string= "\n" (funcall char-at + 1 + chunk-body)) + (string= "\n" (funcall char-at + (- (length chunk-body) + 1 ; start of second delimiter + 1 ; newline from second padline + ) + chunk-body))))) + (if should-be-padded + (if possibly-padded + (if actually-padded + (let* ((start-offset (+ 1 ; end of first delimiter + 1 ; newline from first padline + 1 ; first character of body + )) + (end-offset (+ 1 ; newline from second padline + 1 ; eol character after last character of body + )) + (start-index (- start-offset 1)) + (end-index (- (length chunk-body) end-offset)) + (depadded-body (substring chunk-body + start-index + end-index)) + (distance-from-start (- desired-point chunk-start)) + (on-first-padline (= distance-from-start 1)) + (on-last-padline (= distance-from-start + (- (length chunk-body) 1))) + (adjusted-distance + (cond (on-first-padline 0) + (on-last-padline (length depadded-body)) + (t (- distance-from-start + (- start-offset + 1 ; compensate for the fact that + ; start-offset includes the first + ; character + ))))) + (distance-within-org-body (< adjusted-distance + (- (length org-body) 1)))) + ;; If this chunk and the org source chunk match + ;; send this chunk back and preserve the desired point + (if (string= org-body depadded-body) + `(,depadded-body . ,adjusted-distance) + ;; if the chunks match before the desired point + ;; we can still preserve the point + (if (and distance-within-org-body + (string= (substring org-body + 0 + adjusted-distance) + (substring depadded-body + 0 + adjusted-distance))) + `(,depadded-body . ,adjusted-distance) + ;; otherwise we can't preserve the point + `(,depadded-body . 0)) + `(,depadded-body . 0))) + ;; The user didn't respect the padlines + ;; so the whole body goes back unchanged + `(,chunk-body . 0)) + `(,chunk-body . 0)) + ;; No adjustment needed + `(,chunk-body . ,desired-point))))) + (provide 'ob-tangle) ;; Local variables: -- 1.8.1.2