With no special header argument values, I have

#+BEGIN_SRC emacs-lisp
(propertize "abc" 'face 'italic)

: abc

whereas C-x C-e on the form gives me

#("abc" 0 3 (face italic))

why is there this discrepancy? Is there a difference between org mode source C-c C-c and C-x C-e?


C-c C-c has the key-binding org-ctrl-c-ctrl-c which runs org-babel-exec-src-block if point is inside a source block.
C-x C-e runs eval-last-sexp which has nothing to do with Orgmode.

org-babel-execute-src-block uses org-babel-insert-result for inserting the result into the Org buffer. There, org-no-properties removes the text properties from the result string.

I assume that they remove text properties because many of the properties would immediately be overwritten by font-lock fontification anyway.

The following advice of org-babel-insert-result defines a new :result flag props (or properties). Source blocks where the :results header argument contains that flag keep the text properties on the result string.

(require 'find-func)
    (find-file-noselect (find-library-name "ob-core.el"))
  ;; This is a hack.
  ;; `org-no-properties' is defined by `defsubst' and the byte-compiler replaces the symbol with the lambda.
  ;; We need the definition of `org-babel-insert-result' containing the symbol `org-no-properties'.
  ;; Therefore, we eval the defun for `org-babel-insert-result' in the source file.
  (goto-char (point-min))
  (re-search-forward "(defun org-babel-insert-result")
  (eval-defun nil))

(defun org+-babel-insert-result-with-props (fun result result-params &rest args)
  "Avoid removing text properties in `org-babel-insert-result'.

Add the new result type \"raw-props\" to Org source blocks.
With this result type text properties are not removed from the result.

This is an :around advice for `org-babel-insert-result' as FUN.
RESULT, RESULT-PARAMS, and ARGS are passed to FUN."
  (if (or (member "props" result-params)
      (member "properties" result-params))
      (cl-letf* (((symbol-function 'org-no-properties)
          (lambda (str &rest _args) str)))
    (apply fun result
           (delete "properties" (remove "props" result-params))
    (apply fun result result-params args)))

(advice-add 'org-babel-insert-result :around #'org+-babel-insert-result-with-props)

But that only works reliably with :result type raw. For an example the result string of the following source block is colored red:

#+BEGIN_SRC emacs-lisp :results raw drawer props
(propertize "string" 'font-lock-face 'hi-red-b)
  • Another idea is use prin1-to-string to escape the value as string.
    – xuchunyang
    Mar 28 '20 at 23:06
  • @xuchunyang Sorry, prin1-to-string does not work: If you wrap the propertized string in prin1-to-string the read-representation of the string is inserted as result and not the propertized string.
    – Tobias
    Mar 28 '20 at 23:44
  • It seems that's OP wanted as C-x C-e.
    – xuchunyang
    Mar 29 '20 at 10:31
  • @xuchunyang Please, post an alternative answer if you assume that is what the OP wanted.
    – Tobias
    Mar 29 '20 at 13:08
  • Sorry for the bother. I posted my own answer.
    – xuchunyang
    Mar 29 '20 at 13:50

why is there this discrepancy? Is there a difference between org mode source C-c C-c and C-x C-e?

As Tobias's answer mentioned, C-x C-e and Org Mode's C-c C-c are two different commands, so it's not a surprise if their results are different. For example, C-x C-e after 42 prints 42 (#o52, #x2a, ?*), as you can see, C-x C-e decides to print 42 not only in decimal form but also octal, hex and character form, however, no one asks Org Mode's C-c C-c to do the same.

As for your particular example, you can escape the string value once more to prevent Org from removing the text properties with prin1-to-string or format:

#+begin_src elisp
(prin1-to-string (propertize "abc" 'face 'italic))

: #("abc" 0 3 (face italic))

#+begin_src elisp
(format "%S" (propertize "abc" 'face 'italic))

: #("abc" 0 3 (face italic))
  • You could mention your prin1-to-string version of the source block. Maybe, the OP really wants to have that instead of the propertized string.
    – Tobias
    Mar 29 '20 at 14:06
  • @Tobias Thanks for the reminder. I've done that.
    – xuchunyang
    Mar 29 '20 at 16:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.