is there a way to keep only source code inside source code, that is make #+BEGIN_SRC and #+END_SRC invisible? It's cosmetic but it makes things clearer when one have to deal with a lot of short code snippets. For exemple:

(defun org-xor (a b)
          "Exclusive or."
          (if a (not b) b))

instead of :

  #+BEGIN_SRC emacs-lisp
       (defun org-xor (a b)
          "Exclusive or."
          (if a (not b) b))
  • My comment underneath the question in this semi-related thread shows how to programmatically hide the source block headers/footers. emacs.stackexchange.com/q/26163/2287 -- i.e., (save-excursion (goto-char (point-max)) (while (re-search-backward "#\\+BEGIN_SRC\\|#\\+END_SRC" nil t) (let ((ov (make-overlay (line-beginning-position) (1+ (line-end-position))))) (overlay-put ov 'invisible t)))) To unhide everything, use (remove-overlays). Further work needs to be done for individual entries, and removing only select overlays (instead of all overlays), but that is the general idea.
    – lawlist
    Sep 30, 2016 at 14:51
  • Thanks, this is interesting...I will play around with this.
    – loukios
    Sep 30, 2016 at 18:59

6 Answers 6


The face for all lines starting with #+ is called org-meta-line.

You can customize this face smaller, darker, etc. to make it less visible.

  • 1
    Indeed. As an example, I have it set up using (set-face-attribute 'org-meta-line nil :height 0.8 :slant 'normal). I find it helps quite a bit. Sep 30, 2016 at 13:37
  • Thanks for your answer, it does help. I've changed the height btw but it does not have any effect...
    – loukios
    Sep 30, 2016 at 18:59
  • See this Emacs Lisp documentation on the options you can assign to org-meta-line gnu.org/software/emacs/manual/html_node/elisp/…
    – salotz
    Oct 6, 2016 at 14:12

I use the following piece of code that goes some of the way. It's not perfect. Maybe it will become a proper minor-mode some day. (source).

Screenshot of the resulting code

(with-eval-after-load 'org
  (defvar-local rasmus/org-at-src-begin -1
    "Variable that holds whether last position was a ")

  (defvar rasmus/ob-header-symbol ?☰
    "Symbol used for babel headers")

  (defun rasmus/org-prettify-src--update ()
    (let ((case-fold-search t)
          (re "^[ \t]*#\\+begin_src[ \t]+[^ \f\t\n\r\v]+[ \t]*")
        (goto-char (point-min))
        (while (re-search-forward re nil t)
          (goto-char (match-end 0))
          (let ((args (org-trim
                       (buffer-substring-no-properties (point)
            (when (org-string-nw-p args)
              (let ((new-cell (cons args rasmus/ob-header-symbol)))
                (cl-pushnew new-cell prettify-symbols-alist :test #'equal)
                (cl-pushnew new-cell found :test #'equal)))))
        (setq prettify-symbols-alist
              (cl-set-difference prettify-symbols-alist
                                   (lambda (elm)
                                     (eq (cdr elm) rasmus/ob-header-symbol))
                                  found :test #'equal)))
        ;; Clean up old font-lock-keywords.
        (font-lock-remove-keywords nil prettify-symbols--keywords)
        (setq prettify-symbols--keywords (prettify-symbols--make-keywords))
        (font-lock-add-keywords nil prettify-symbols--keywords)
        (while (re-search-forward re nil t)
          (font-lock-flush (line-beginning-position) (line-end-position))))))

  (defun rasmus/org-prettify-src ()
    "Hide src options via `prettify-symbols-mode'.

  `prettify-symbols-mode' is used because it has uncollpasing. It's
  may not be efficient."
    (let* ((case-fold-search t)
           (at-src-block (save-excursion
                           (looking-at "^[ \t]*#\\+begin_src[ \t]+[^ \f\t\n\r\v]+[ \t]*"))))
      ;; Test if we moved out of a block.
      (when (or (and rasmus/org-at-src-begin
                     (not at-src-block))
                ;; File was just opened.
                (eq rasmus/org-at-src-begin -1))
      ;; Remove composition if at line; doesn't work properly.
      ;; (when at-src-block
      ;;   (with-silent-modifications
      ;;     (remove-text-properties (match-end 0)
      ;;                             (1+ (line-end-position))
      ;;                             '(composition))))
      (setq rasmus/org-at-src-begin at-src-block)))

  (defun rasmus/org-prettify-symbols ()
    (mapc (apply-partially 'add-to-list 'prettify-symbols-alist)
          (cl-reduce 'append
                     (mapcar (lambda (x) (list x (cons (upcase (car x)) (cdr x))))
                             `(("#+begin_src" . ?✎) ;; ➤ 🖝 ➟ ➤ ✎
                               ("#+end_src"   . ?□) ;; ⏹
                               ("#+header:" . ,rasmus/ob-header-symbol)
                               ("#+begin_quote" . ?»)
                               ("#+end_quote" . ?«)))))
    (add-hook 'post-command-hook 'rasmus/org-prettify-src t t))
  (add-hook 'org-mode-hook #'rasmus/org-prettify-symbols))

The org-present package does this. Specifically, it is taken care of by (org-present-add-overlays), which then uses (overlay-put) to make the text invisible. This approach is further described in section 39.6 of the Emacs Lisp manual.


Yet another way to do this is using hide-lines.

The following code is from my emacs config (with a few modifications because I have a lot of self-written macros).

(use-package hide-lines :commands hide-lines hide-lines-matching)

;; The line ~(overlay-put overlay 'invisible 'hl)~ in [[helpfn:][hide-lines-add-overlay]] wouldn't
;; work with the argument =hl=. It works when you set it to =t= instead. Maybe =hl= is
;; depreciated.

(define-advice hide-lines-add-overlay (:override (start end) fix-adding-overlay)
  "Add an overlay from `start' to `end' in the current buffer.
Push the overlay into `hide-lines-invisible-areas'."
  (let ((overlay (make-overlay start end)))
    (setq hide-lines-invisible-areas (cons overlay hide-lines-invisible-areas))
    (overlay-put overlay 'invisible t)))

(defun org/hide-source-block-delimiters ()
  "Hide property drawers."
  (let (selective-display-ellipses org-ellipsis)
    ;; If properties are folded, ellipsis will show.
    (hide-lines-matching (rx "#+" (or "begin" "end") "_src" (* nonl) "\n"))))
  ;; Org mode
  (add-hook 'org-mode-hook
            '(lambda ()
               ;; Hide org block lines

               ;; Unset any previous customization for the background color
               (set-face-attribute 'org-block-begin-line nil :background 'unspecified)
               (set-face-attribute 'org-block-end-line nil :background 'unspecified)

               ;; Set the foreground color to the value of the background color
               (set-face-attribute 'org-block-begin-line nil
                :foreground (face-background 'org-block-begin-line nil 'default))
               (set-face-attribute 'org-block-end-line nil
                :foreground (face-background 'org-block-end-line nil 'default))

Sets the foreground color to the background color, which effectively means hiding the text.

Note: you might need to restart emacs (instead of just reloading the config) for the changes to take effect.


The face for #+BEGIN is org-block-begin-line and for #+END is org-block-end-line. If you already have a dark theme, something like this will make it well nigh invisible, and can be tweaked to your liking or to fit a light theme (hint for light, start with #ffffff):

(set-face-attribute 'org-block-begin-line nil :foreground "#000000")
(set-face-attribute 'org-block-end-line nil :foreground "#000000")

For example, here is the code you posted, with these face attributes set, on top of the Spacemacs dark theme:

begin and end nearly invisible

Note that this will apply not only to SRC blocks but also to QUOTE blocks, etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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