Pārlūkot izejas kodu

Merge branch 'master' of git+ssh://repo.or.cz/srv/git/org-mode

Carsten Dominik 14 gadi atpakaļ
vecāks
revīzija
72a4aeebd3
11 mainītis faili ar 233 papildinājumiem un 114 dzēšanām
  1. 4 2
      .gitignore
  2. 1 1
      ORGWEBPAGE/index.org
  3. 78 57
      lisp/ob-R.el
  4. 2 0
      lisp/ob-exp.el
  5. 4 2
      lisp/ob-keys.el
  6. 1 8
      lisp/ob-lob.el
  7. 2 2
      lisp/ob-python.el
  8. 63 13
      lisp/ob.el
  9. 9 10
      lisp/org-agenda.el
  10. 8 17
      lisp/org-feed.el
  11. 61 2
      lisp/org-src.el

+ 4 - 2
.gitignore

@@ -8,23 +8,25 @@
 *.bak
 *.cp
 *.cps
+*.diff
 *.dvi
 *.elc
 *.fn
 *.fns
 *.html
+*.info
 *.ky
 *.kys
 *.log
+*.patch
 *.pdf
 *.pg
 *.pgs
+*.ps
 *.toc
 *.tp
 *.vr
 *.vrs
-*.dvi
-*.ps
 orgcard_letter.tex
 orgcard.txt
 org

+ 1 - 1
ORGWEBPAGE/index.org

@@ -152,7 +152,7 @@ the command line....):
 
 Some more information about this can be found in the [[http://orgmode.org/worg/org-faq.php][FAQ]], under [[http://orgmode.org/worg/org-faq.php#keeping-current-with-Org-mode-development][How do
 I keep current with Org mode development?]].  For people who cannot use
-git, we provide [[file:org-latest.zip][zip]] or [[file:org-latest.tar.gz][tar.gz]] snapshot release files updated each hour
+git, we provide [[file:org-latest.zip][zip]] or [[file:org-latest.tar.gz][tar.gz]] snapshot release files updated each day
 and corresponding to the latest git version.
 
 ** Alternative distributions

+ 78 - 57
lisp/ob-R.el

@@ -168,6 +168,14 @@ This function is called by `org-babel-execute-src-block'."
 	       (buffer-name))))
 	  (current-buffer))))))
 
+(defun org-babel-R-associate-session (session)
+  "Associate R code buffer with an R session.
+Make SESSION be the inferior ESS process associated with the
+current code buffer."
+  (setq ess-local-process-name
+	(process-name (get-buffer-process session)))
+  (ess-make-buffer-current))
+
 (defun org-babel-R-construct-graphics-device-call (out-file params)
   "Construct the call to the graphics device."
   (let ((devices
@@ -211,63 +219,76 @@ write.table(main(), file=\"%s\", sep=\"\\t\", na=\"nil\",row.names=%s, col.names
 
 (defun org-babel-R-evaluate
   (session body result-type column-names-p row-names-p)
-  "Pass BODY to the R process in SESSION.
-If RESULT-TYPE equals 'output then return a list of the outputs
-of the statements in BODY, if RESULT-TYPE equals 'value then
-return the value of the last statement in BODY, as elisp."
-  (if (not session)
-      ;; external process evaluation
-      (case result-type
-	(output (org-babel-eval org-babel-R-command body))
-	(value
-	 (let ((tmp-file (make-temp-file "org-babel-R-results-")))
-	   (org-babel-eval org-babel-R-command
-			   (format org-babel-R-wrapper-method
-				   body tmp-file
-				   (if row-names-p "TRUE" "FALSE")
-				   (if column-names-p
-				       (if row-names-p "NA" "TRUE")
-				     "FALSE")))
-	   (org-babel-R-process-value-result
-	    (org-babel-import-elisp-from-file
-	     (org-babel-maybe-remote-file tmp-file) '(16)) column-names-p))))
-    ;; comint session evaluation
-    (case result-type
-      (value
-       (let ((tmp-file (make-temp-file "org-babel-R"))
-	     broke)
-	 (org-babel-comint-with-output (session org-babel-R-eoe-output)
-	   (insert (mapconcat
-		    #'org-babel-chomp
-		    (list
-		     body
-		     (format org-babel-R-wrapper-lastvar
-			     tmp-file
-			     (if row-names-p "TRUE" "FALSE")
-			     (if column-names-p
-				 (if row-names-p "NA" "TRUE")
-			       "FALSE"))
-		     org-babel-R-eoe-indicator) "\n"))
-	   (inferior-ess-send-input))
-	 (org-babel-R-process-value-result
-	  (org-babel-import-elisp-from-file
-	   (org-babel-maybe-remote-file tmp-file) '(16))  column-names-p)))
-      (output
-       (mapconcat
-	#'org-babel-chomp
-	(butlast
-	 (delq nil
-	       (mapcar
-		(lambda (line) ;; cleanup extra prompts left in output
-		  (if (string-match
-		       "^\\([ ]*[>+][ ]?\\)+\\([[0-9]+\\|[ ]\\)" line)
-		      (substring line (match-end 1))
-		    line))
-		(org-babel-comint-with-output (session org-babel-R-eoe-output)
-		  (insert (mapconcat #'org-babel-chomp
-				     (list body org-babel-R-eoe-indicator)
-				     "\n"))
-		  (inferior-ess-send-input)))) 2) "\n")))))
+  "Evaluate R code in BODY."
+  (if session
+      (org-babel-R-evaluate-session
+       session body result-type column-names-p row-names-p)
+    (org-babel-R-evaluate-external-process
+     body result-type column-names-p row-names-p)))
+
+(defun org-babel-R-evaluate-external-process
+  (body result-type column-names-p row-names-p)
+  "Evaluate BODY in external R process.
+If RESULT-TYPE equals 'output then return standard output as a
+string. If RESULT-TYPE equals 'value then return the value of the
+last statement in BODY, as elisp."
+  (case result-type
+    (value
+     (let ((tmp-file (make-temp-file "org-babel-R-results-")))
+       (org-babel-eval org-babel-R-command
+		       (format org-babel-R-wrapper-method
+			       body tmp-file
+			       (if row-names-p "TRUE" "FALSE")
+			       (if column-names-p
+				   (if row-names-p "NA" "TRUE")
+				 "FALSE")))
+       (org-babel-R-process-value-result
+	(org-babel-import-elisp-from-file
+	 (org-babel-maybe-remote-file tmp-file) '(16)) column-names-p)))
+    (output (org-babel-eval org-babel-R-command body))))
+
+(defun org-babel-R-evaluate-session
+  (session body result-type column-names-p row-names-p)
+  "Evaluate BODY in SESSION.
+If RESULT-TYPE equals 'output then return standard output as a
+string. If RESULT-TYPE equals 'value then return the value of the
+last statement in BODY, as elisp."
+  (case result-type
+    (value
+     (let ((tmp-file (make-temp-file "org-babel-R"))
+	   broke)
+       (org-babel-comint-with-output (session org-babel-R-eoe-output)
+	 (insert (mapconcat
+		  #'org-babel-chomp
+		  (list
+		   body
+		   (format org-babel-R-wrapper-lastvar
+			   tmp-file
+			   (if row-names-p "TRUE" "FALSE")
+			   (if column-names-p
+			       (if row-names-p "NA" "TRUE")
+			     "FALSE"))
+		   org-babel-R-eoe-indicator) "\n"))
+	 (inferior-ess-send-input))
+       (org-babel-R-process-value-result
+	(org-babel-import-elisp-from-file
+	 (org-babel-maybe-remote-file tmp-file) '(16))  column-names-p)))
+    (output
+     (mapconcat
+      #'org-babel-chomp
+      (butlast
+       (delq nil
+	     (mapcar
+	      (lambda (line) ;; cleanup extra prompts left in output
+		(if (string-match
+		     "^\\([ ]*[>+][ ]?\\)+\\([[0-9]+\\|[ ]\\)" line)
+		    (substring line (match-end 1))
+		  line))
+	      (org-babel-comint-with-output (session org-babel-R-eoe-output)
+		(insert (mapconcat #'org-babel-chomp
+				   (list body org-babel-R-eoe-indicator)
+				   "\n"))
+		(inferior-ess-send-input)))) 2) "\n"))))
 
 (defun org-babel-R-process-value-result (result column-names-p)
   "R-specific processing of return value.

+ 2 - 0
lisp/ob-exp.el

@@ -178,6 +178,8 @@ options are taken from `org-babel-default-header-args'."
 		   (list "emacs-lisp" "results"
 			 (org-babel-merge-params
 			  org-babel-default-header-args
+			  (org-babel-params-from-buffer)
+			  (org-babel-params-from-properties)
 			  (org-babel-parse-header-arguments
 			   (org-babel-clean-text-properties
 			    (concat ":var results="

+ 4 - 2
lisp/ob-keys.el

@@ -74,10 +74,12 @@ functions which are assigned key bindings, and see
     ("\C-i" . org-babel-lob-ingest)
     ("i" . org-babel-lob-ingest)
     ("\C-z" . org-babel-switch-to-session)
-    ("z" . org-babel-switch-to-session)
+    ("z" . org-babel-switch-to-session-with-code)
     ("\C-a" . org-babel-sha1-hash)
     ("a" . org-babel-sha1-hash)
-    ("h" . org-babel-describe-bindings))
+    ("h" . org-babel-describe-bindings)
+    ("\C-x" . org-babel-do-key-sequence-in-edit-buffer)
+    ("x" . org-babel-do-key-sequence-in-edit-buffer))
   "Alist of key bindings and interactive Babel functions.
 This list associates interactive Babel functions
 with keys.  Each element of this list will add an entry to the

+ 1 - 8
lisp/ob-lob.el

@@ -79,14 +79,7 @@ if so then run the appropriate source block from the Library."
 
 ;;;###autoload
 (defun org-babel-lob-get-info ()
-  "Return a Library of Babel function call as a string.
-
-This function is analogous to org-babel-get-src-block-name. For
-both functions, after they are called, (match-string 1) matches
-the function name, and (match-string 2) matches the function
-arguments inside the parentheses. I think perhaps these functions
-should be renamed to bring out this similarity, perhaps involving
-the word 'call'."
+  "Return a Library of Babel function call as a string."
   (let ((case-fold-search t))
     (save-excursion
       (beginning-of-line 1)

+ 2 - 2
lisp/ob-python.el

@@ -150,10 +150,10 @@ then create.  Return the initialized session."
     (let* ((session (if session (intern session) :default))
            (python-buffer (org-babel-python-session-buffer session)))
       (cond
-       ((and (equal 'python org-babel-python-mode)
+       ((and (eq 'python org-babel-python-mode)
 	     (fboundp 'run-python)) ; python.el
 	(run-python))
-       ((and (equal 'python-mode org-babel-python-mode)
+       ((and (eq 'python-mode org-babel-python-mode)
 	     (fboundp 'py-shell)) ; python-mode.el
 	;; `py-shell' creates a buffer whose name is the value of
 	;; `py-which-bufname' with '*'s at the beginning and end

+ 63 - 13
lisp/ob.el

@@ -434,12 +434,12 @@ session."
     (end-of-line 1)))
 
 ;;;###autoload
-(defun org-babel-switch-to-session (&optional arg info)
-  "Switch to the session of the current source-code block.
+(defun org-babel-initiate-session (&optional arg info)
+  "Initiate session for current code block.
 If called with a prefix argument then evaluate the header arguments
-for the source block before entering the session. Copy the body
-of the source block to the kill ring."
-  (interactive)
+for the code block before entering the session. Copy the body
+of the code block to the kill ring."
+  (interactive "P")
   (let* ((info (or info (org-babel-get-src-block-info)))
          (lang (nth 0 info))
          (body (nth 1 info))
@@ -450,21 +450,71 @@ of the source block to the kill ring."
 	   (or (and dir (file-name-as-directory dir)) default-directory))
 	 (cmd (intern (format "org-babel-%s-initiate-session" lang)))
 	 (cmd2 (intern (concat "org-babel-prep-session:" lang))))
+    (if (and (stringp session) (string= session "none"))
+	(error "This block is not using a session!"))
     (unless (fboundp cmd)
       (error "No org-babel-initiate-session function for %s!" lang))
-    ;; copy body to the kill ring
     (with-temp-buffer (insert (org-babel-trim body))
                       (copy-region-as-kill (point-min) (point-max)))
-    ;; if called with a prefix argument, then process header arguments
-    (unless (fboundp cmd2)
-      (error "No org-babel-prep-session function for %s!" lang))
-    (when arg (funcall cmd2 session params))
-    ;; just to the session using pop-to-buffer
-    (pop-to-buffer (funcall cmd session params))
-    (end-of-line 1)))
+    (when arg
+      (unless (fboundp cmd2)
+	(error "No org-babel-prep-session function for %s!" lang))
+      (funcall cmd2 session params))
+    (funcall cmd session params)))
+
+;;;###autoload
+(defun org-babel-switch-to-session (&optional arg info)
+  "Switch to the session of the current code block.
+Uses `org-babel-initiate-session' to start the session. If called
+with a prefix argument then this is passed on to
+`org-babel-initiate-session'."
+  (interactive "P")
+  (pop-to-buffer (org-babel-initiate-session arg info))
+  (end-of-line 1))
 
 (defalias 'org-babel-pop-to-session 'org-babel-switch-to-session)
 
+;;;###autoload
+(defun org-babel-switch-to-session-with-code (&optional arg info)
+    "Switch to code buffer and display session."
+    (interactive "P")
+    (flet ((swap-windows
+	    ()
+	    (let ((other-window-buffer (window-buffer (next-window))))
+	      (set-window-buffer (next-window) (current-buffer))
+	      (set-window-buffer (selected-window) other-window-buffer))
+	    (other-window 1)))
+      (let ((info (org-babel-get-src-block-info))
+	    (org-src-window-setup 'reorganize-frame))
+	(save-excursion
+	  (org-babel-switch-to-session arg info))
+	(org-edit-src-code))
+      (swap-windows)))
+
+(defmacro org-babel-do-in-edit-buffer (&rest body)
+  "Evaluate BODY in edit buffer if there is a code block at point.
+Return t if a code block was found at point, nil otherwise."
+  `(let ((org-src-window-setup 'switch-invisibly))
+     (when (org-edit-src-code nil nil nil 'quietly)
+       ,@body
+       (if (org-bound-and-true-p org-edit-src-from-org-mode)
+	   (org-edit-src-exit))
+       t)))
+
+(defun org-babel-do-key-sequence-in-edit-buffer (key)
+  "Read key sequence and execute the command in edit buffer.
+Enter a key sequence to be executed in the language major-mode
+edit buffer. For example, TAB will alter the contents of the
+Org-mode code block according to the effect of TAB in the
+language major-mode buffer. For languages that support
+interactive sessions, this can be used to send code from the Org
+buffer to the session for evaluation using the native major-mode
+evaluation mechanisms."
+  (interactive "kEnter key-sequence to execute in edit buffer: ")
+  (org-babel-do-in-edit-buffer
+   (call-interactively
+    (key-binding (or key (read-key-sequence nil))))))
+
 (defvar org-bracket-link-regexp)
 ;;;###autoload
 (defun org-babel-open-src-block-result (&optional re-run)

+ 9 - 10
lisp/org-agenda.el

@@ -2503,16 +2503,15 @@ higher priority settings."
   (interactive "FWrite agenda to file: \nP")
   (if (not (file-writable-p file))
       (error "Cannot write agenda to file %s" file))
-  (cond
-   ((string-match "\\.html?\\'" file) (require 'htmlize))
-   ((string-match "\\.ps\\'" file) (require 'ps-print)))
   (org-let (if nosettings nil org-agenda-exporter-settings)
-    `(save-excursion
+    '(save-excursion
        (save-window-excursion
 	 (org-agenda-mark-filtered-text)
 	 (let ((bs (copy-sequence (buffer-string))) beg)
 	   (org-agenda-unmark-filtered-text)
 	   (with-temp-buffer
+	     (rename-buffer "Agenda View" t)
+	     (set-buffer-modified-p nil)
 	     (insert bs)
 	     (org-agenda-remove-marked-text 'org-filtered)
 	     (while (setq beg (text-property-any (point-min) (point-max)
@@ -2525,6 +2524,7 @@ higher priority settings."
 	      ((org-bound-and-true-p org-mobile-creating-agendas)
 	       (org-mobile-write-agenda-for-mobile file))
 	      ((string-match "\\.html?\\'" file)
+	       (require 'htmlize)
 	       (set-buffer (htmlize-buffer (current-buffer)))
 
 	       (when (and org-agenda-export-html-style
@@ -2539,18 +2539,17 @@ higher priority settings."
 	       (message "HTML written to %s" file))
 	      ((string-match "\\.ps\\'" file)
 	       (require 'ps-print)
-	       ,(flet ((ps-get-buffer-name () "Agenda View"))
-		  (ps-print-buffer-with-faces file))
+	       (ps-print-buffer-with-faces file)
 	       (message "Postscript written to %s" file))
 	      ((string-match "\\.pdf\\'" file)
 	       (require 'ps-print)
-	       ,(flet ((ps-get-buffer-name () "Agenda View"))
-		  (ps-print-buffer-with-faces
-		   (concat (file-name-sans-extension file) ".ps")))
+	       (ps-print-buffer-with-faces
+		(concat (file-name-sans-extension file) ".ps"))
 	       (call-process "ps2pdf" nil nil nil
 			     (expand-file-name
 			      (concat (file-name-sans-extension file) ".ps"))
 			     (expand-file-name file))
+	       (delete-file (concat (file-name-sans-extension file) ".ps"))
 	       (message "PDF written to %s" file))
 	      ((string-match "\\.ics\\'" file)
 	       (require 'org-icalendar)
@@ -7140,7 +7139,7 @@ The cursor may be at a date in the calendar, or in the Org agenda."
 
 (defun org-agenda-clock-out ()
   "Stop the currently running clock."
-  (interactive "P")
+  (interactive)
   (unless (marker-buffer org-clock-marker)
     (error "No running clock"))
   (let ((marker (make-marker)) newhead)

+ 8 - 17
lisp/org-feed.el

@@ -99,7 +99,7 @@
 (declare-function xml-get-children "xml" (node child-name))
 (declare-function xml-get-attribute "xml" (node attribute))
 (declare-function xml-get-attribute-or-nil "xml" (node attribute))
-(defvar xml-entity-alist)
+(declare-function xml-substitute-special "xml" (string))
 
 (defgroup org-feed  nil
   "Options concerning RSS feeds as inputs for Org files."
@@ -269,17 +269,6 @@ have been saved."
 (defvar org-feed-buffer "*Org feed*"
   "The buffer used to retrieve a feed.")
 
-(defun org-feed-unescape (s)
-  "Unescape protected entities in S."
-  (require 'xml)
-  (let ((re (concat "&\\("
-		    (mapconcat 'car xml-entity-alist "\\|")
-		    "\\);")))
-    (while (string-match re s)
-      (setq s (replace-match
-	       (cdr (assoc (match-string 1 s) xml-entity-alist)) nil nil s)))
-    s))
-
 ;;;###autoload
 (defun org-feed-update-all ()
   "Get inbox items from all feeds in `org-feed-alist'."
@@ -553,7 +542,8 @@ If that property is already present, nothing changes."
 		  (setq tmp (org-feed-make-indented-block
 			     tmp (org-get-indentation))))))
 	    (replace-match tmp t t))))
-	(buffer-string)))))
+	(decode-coding-string
+	 (buffer-string) (detect-coding-region (point-min) (point-max) t))))))
 
 (defun org-feed-make-indented-block (s n)
   "Add indentation of N spaces to a multiline string S."
@@ -613,6 +603,7 @@ containing the properties `:guid' and `:item-full-text'."
 
 (defun org-feed-parse-rss-entry (entry)
   "Parse the `:item-full-text' field for xml tags and create new properties."
+  (require 'xml)
   (with-temp-buffer
     (insert (plist-get entry :item-full-text))
     (goto-char (point-min))
@@ -620,7 +611,7 @@ containing the properties `:guid' and `:item-full-text'."
 			      nil t)
       (setq entry (plist-put entry
 			     (intern (concat ":" (match-string 1)))
-			     (org-feed-unescape (match-string 2)))))
+			     (xml-substitute-special (match-string 2)))))
     (goto-char (point-min))
     (unless (re-search-forward "isPermaLink[ \t]*=[ \t]*\"false\"" nil t)
       (setq entry (plist-put entry :guid-permalink t))))
@@ -654,7 +645,7 @@ formatted as a string, not the original XML data."
 			    'href)))
     ;; Add <title/> as :title.
     (setq entry (plist-put entry :title
-			   (org-feed-unescape
+			   (xml-substitute-special
 			    (car (xml-node-children
 				  (car (xml-get-children xml 'title)))))))
     (let* ((content (car (xml-get-children xml 'content)))
@@ -664,12 +655,12 @@ formatted as a string, not the original XML data."
 	 ((string= type "text")
 	  ;; We like plain text.
 	  (setq entry (plist-put entry :description
-				 (org-feed-unescape
+				 (xml-substitute-special
 				  (car (xml-node-children content))))))
 	 ((string= type "html")
 	  ;; TODO: convert HTML to Org markup.
 	  (setq entry (plist-put entry :description
-				 (org-feed-unescape
+				 (xml-substitute-special
 				  (car (xml-node-children content))))))
 	 ((string= type "xhtml")
 	  ;; TODO: convert XHTML to Org markup.

+ 61 - 2
lisp/org-src.el

@@ -34,6 +34,8 @@
 
 (require 'org-macs)
 (require 'org-compat)
+(require 'ob-keys)
+(require 'ob-comint)
 (eval-when-compile
   (require 'cl))
 
@@ -165,6 +167,7 @@ For example, there is no ocaml-mode in Emacs, but the mode to use is
 
 (defvar org-src-mode-map (make-sparse-keymap))
 (define-key org-src-mode-map "\C-c'" 'org-edit-src-exit)
+
 (defvar org-edit-src-force-single-line nil)
 (defvar org-edit-src-from-org-mode nil)
 (defvar org-edit-src-allow-write-back-p t)
@@ -181,6 +184,8 @@ For example, there is no ocaml-mode in Emacs, but the mode to use is
   immediately; otherwise it will ask whether you want to return
   to the existing edit buffer.")
 
+(defvar org-src-babel-info nil)
+
 (define-minor-mode org-src-mode
   "Minor mode for language major mode buffers generated by org.
 This minor mode is turned on in two situations:
@@ -189,7 +194,7 @@ This minor mode is turned on in two situations:
 There is a mode hook, and keybindings for `org-edit-src-exit' and
 `org-edit-src-save'")
 
-(defun org-edit-src-code (&optional context code edit-buffer-name)
+(defun org-edit-src-code (&optional context code edit-buffer-name quietp)
   "Edit the source code example at point.
 The example is copied to a separate buffer, and that buffer is switched
 to the correct language mode.  When done, exit with \\[org-edit-src-exit].
@@ -203,6 +208,7 @@ the edited version. Optional argument CONTEXT is used by
 	(col (current-column))
 	(case-fold-search t)
 	(info (org-edit-src-find-region-and-lang))
+	(babel-info (org-babel-get-src-block-info))
 	(org-mode-p (eq major-mode 'org-mode))
 	(beg (make-marker))
 	(end (make-marker))
@@ -272,6 +278,8 @@ the edited version. Optional argument CONTEXT is used by
 	(set (make-local-variable 'org-edit-src-from-org-mode) org-mode-p)
 	(set (make-local-variable 'org-edit-src-allow-write-back-p) allow-write-back-p)
 	(set (make-local-variable 'org-src-preserve-indentation) preserve-indentation)
+	(when babel-info
+	  (set (make-local-variable 'org-src-babel-info) babel-info))
 	(when lfmt
 	  (set (make-local-variable 'org-coderef-label-format) lfmt))
 	(when org-mode-p
@@ -290,7 +298,7 @@ the edited version. Optional argument CONTEXT is used by
 	(set-buffer-modified-p nil)
 	(and org-edit-src-persistent-message
 	     (org-set-local 'header-line-format msg)))
-      (message "%s" msg)
+      (unless quietp (message "%s" msg))
       t)))
 
 (defun org-edit-src-continue (e)
@@ -321,6 +329,8 @@ the edited version. Optional argument CONTEXT is used by
      (if (eq context 'edit) (delete-other-windows))
      (org-switch-to-buffer-other-window buffer)
      (if (eq context 'exit) (delete-other-windows)))
+    ('switch-invisibly
+     (set-buffer buffer))
     (t
      (message "Invalid value %s for org-src-window-setup"
 	      (symbol-name org-src-window-setup))
@@ -654,6 +664,55 @@ the language, a switch telling if the content should be in a single line."
 
 (org-add-hook 'org-src-mode-hook 'org-src-mode-configure-edit-buffer)
 
+
+(defun org-src-associate-babel-session (info)
+  "Associate edit buffer with comint session."
+  (interactive)
+  (let ((session (cdr (assoc :session (nth 2 info)))))
+    (and session (not (string= session "none"))
+	 (org-babel-comint-buffer-livep session)
+	 ((lambda (f) (and (fboundp f) (funcall f session)))
+	  (intern (format "org-babel-%s-associate-session" (nth 0 info)))))))
+
+(defun org-src-babel-configure-edit-buffer ()
+  (when org-src-babel-info
+    (org-src-associate-babel-session org-src-babel-info)))
+
+(org-add-hook 'org-src-mode-hook 'org-src-babel-configure-edit-buffer)
+(defmacro org-src-do-at-code-block (&rest body)
+  "Execute a command from an edit buffer in the Org-mode buffer."
+  `(let ((beg-marker org-edit-src-beg-marker))
+     (if beg-marker
+	 (with-current-buffer (marker-buffer beg-marker)
+	   (goto-char (marker-position beg-marker))
+	   ,@body))))
+
+(defun org-src-do-key-sequence-at-code-block (&optional key)
+  "Execute key sequence at code block in the source Org buffer.
+The command bound to KEY in the Org-babel key map is executed
+remotely with point temporarily at the start of the code block in
+the Org buffer.
+
+This command is not bound to a key by default, to avoid conflicts
+with language major mode bindings. To bind it to C-c @ in all
+language major modes, you could use
+
+  (add-hook 'org-src-mode-hook
+            (lambda () (define-key org-src-mode-map \"\\C-c@\"
+                    'org-src-do-key-sequence-at-code-block)))
+
+In that case, for example, C-c @ t issued in code edit buffers
+would tangle the current Org code block, C-c @ e would execute
+the block and C-c @ h would display the other available
+Org-babel commands."
+  (interactive "kOrg-babel key: ")
+  (if (equal key (kbd "C-g")) (keyboard-quit)
+    (org-edit-src-save)
+    (org-src-do-at-code-block
+     (call-interactively
+      (lookup-key org-babel-map key)))))
+
+
 (provide 'org-src)
 
 ;; arch-tag: 6a1fc84f-dec7-47be-a416-64be56bea5d8