29

I want to add a markup and formatting for such markup, i.e. <kbd>...</kbd> with a box surrounds such markup. I also want the mark up to be compatible with (setq org-hide-emphasis-markers t). That is, when the variable is set to t, the <kbd> and </kbd>tags should disappear, leaving the text between it with the specified formatting above.

The answer posted in this question: How to highlight text permanently in org-mode does not solve this problem, since it is only applicable for existing markups, not extending Org with new markups.

NickD
  • 27,023
  • 3
  • 23
  • 42
Tu Do
  • 6,772
  • 20
  • 39
  • 3
    http://endlessparentheses.com/inserting-the-kbd-tag-in-org-mode.html – Kaushal Modi May 31 '15 at 15:11
  • 1
    @kaushalmodi I asked how to add a mark up that when Org sees it, it adds text properties accordingly and in a way such that the markup can be hidden with `org-hide-emphasis-markers`, not how to quickly insert a `kbd` tag. – Tu Do May 31 '15 at 15:33
  • 1
    I agree. I put this as a comment as it was related to kbd tags. – Kaushal Modi May 31 '15 at 16:27
  • 2
    possible duplicate of [How to highlight text permanently in org-mode](http://emacs.stackexchange.com/questions/5889/how-to-highlight-text-permanently-in-org-mode) – erikstokes May 31 '15 at 16:59
  • 1
    @erikstokes that solution is only applicable for existing markups, not new ones. – Tu Do May 31 '15 at 17:13
  • 1
    starting points with this question: [Color-code a new generic character combination](http://emacs.stackexchange.com/questions/8211/color-code-a-new-generic-character-combination) – Joe Corneli Jun 01 '15 at 00:41

3 Answers3

29

I have done something similar. It's in French, but the code should speak for itself. I use for the marker (I use a bepo layout), and when I do, the marked text as a pressed-button style.

I am not fluent in lisp, so there may be room for improvement.

What I have done is that, when using for marker, the marked text has a pressed-button style, and when exported it is translated to <kbd>

First, I had to define a new face:

(defface my-face-org-keystroke
  '((t (:inherit shadow 
        :box (:line-width -2 ;neg. in order to keep the same size of lines
              :color "grey75"
              :style pressed-button)))) "Face for keystrokes"
        :group 'org-faces)

Then customize org-emphasis-alist :

(("*" bold)
 ("/" italic)
 ("_" underline)
 ("=" org-code verbatim)
 ("~" org-verbatim verbatim)
 ("+"
  (:strike-through t))
 ("‰" my-face-org-keystroke verbatim));This line is what you want to add

For the export, you may need to load ox.el with (require 'ox).

Then each time bold or code appears in a function (in ox-org.el), I have created a similar function (or modified existing ones):

;creation
(defun org-html-keystroke (keystroke contents info)
  "Transcode KEYSTROKE from Org to HTML.
CONTENTS is nil.  INFO is a plist holding contextual
information."
  (format (or (cdr (assq 'my-object-keystroke org-html-text-markup-alist)) "%s")
          (org-html-encode-plain-text (org-element-property :value keystroke))))


;creation
(defun org-element-my-object-keystroke-parser ()
  "Parse code object at point.

Return a list whose CAR is `my-object-keystroke' and CDR is a plist with
`:value', `:begin', `:end' and `:post-blank' keywords.

Assume point is at the first tilde marker."
  (interactive)
  (save-excursion
    (unless (bolp) (backward-char 1))
    (looking-at org-emph-re)
    (let ((begin (match-beginning 2))
          (value (org-match-string-no-properties 4))
          (post-blank (progn (goto-char (match-end 2))
                             (skip-chars-forward " \t")))
          (end (point)))
      (list 'my-object-keystroke
            (list :value value
                  :begin begin
                  :end end
                  :post-blank post-blank)))))

;creation
(defun org-element-my-object-keystroke-interpreter (keystroke contents)
  "Interpret KEYSTROKE object as Org syntax.
CONTENTS is nil."
  (format "‰%s‰" (org-element-property :value keystroke)))


;modification
(defconst org-element-object-successor-alist
  '((subscript . sub/superscript) (superscript . sub/superscript)
    (bold . text-markup) (code . text-markup) (italic . text-markup)
    (strike-through . text-markup) (underline . text-markup)
    (verbatim . text-markup) (entity . latex-or-entity)
    (latex-fragment . latex-or-entity) (my-object-keystroke . text-markup))
  "Alist of translations between object type and successor name.
Sharing the same successor comes handy when, for example, the
regexp matching one object can also match the other object.")

;modification
(defconst org-element-all-objects
  '(bold code entity export-snippet footnote-reference inline-babel-call
         inline-src-block italic line-break latex-fragment link macro
         radio-target statistics-cookie strike-through subscript superscript
         table-cell target timestamp underline verbatim my-object-keystroke)
  "Complete list of object types.")


;modification
(defun org-element-text-markup-successor ()
  "Search for the next text-markup object.

Return value is a cons cell whose CAR is a symbol among `bold',
`italic', `underline', `strike-through', `code' and `verbatim'
and CDR is beginning position."
  (save-excursion
    (unless (bolp) (backward-char))
    (when (re-search-forward org-emph-re nil t)
      (let ((marker (match-string 3)))
        (cons (cond
               ((equal marker "*") 'bold)
               ((equal marker "/") 'italic)
               ((equal marker "_") 'underline)
               ((equal marker "+") 'strike-through)
               ((equal marker "~") 'code)
               ((equal marker "=") 'verbatim)
               ((equal marker "‰") 'my-object-keystroke) 
               (t (error "Unknown marker at %d" (match-beginning 3))))
              (match-beginning 2))))))

Next, I have defined a my-html backend for the export:

(org-export-define-derived-backend 'my-html 'html
  :translate-alist '((my-object-keystroke . org-html-keystroke))
  :menu-entry ' (?h 1
                    ((?r "my-html"  org-html-export-to-my-html))))

(defun org-html-export-to-my-html
  (&optional async subtreep visible-only body-only ext-plist)
  "Export current buffer to a HTML file.

Return output file's name."
  (interactive)
  (let* ((extension (concat "." org-html-extension))
         (file (org-export-output-file-name extension subtreep))
         (org-export-coding-system org-html-coding-system))
    (org-export-to-file 'my-html file
      async subtreep visible-only body-only ext-plist)))


(defun org-html-publish-to-my-html (plist filename pub-dir)
  "Publish an org file to my-html.
Return output file name."
  (org-publish-org-to 'my-html filename
                      (concat "." (or (plist-get plist :html-extension)
                                      org-html-extension "html"))
                      plist pub-dir))

(defun org-html-convert-region-to-my-html ()
  "Assume the current region has org-mode syntax, and convert it to HTML.
This can be used in any buffer.  For example, you can write an
itemized list in org-mode syntax in an HTML buffer and use this
command to convert it."
  (interactive)
  (org-export-replace-region-by 'my-html))

So when I use C-c C-e h r it's exported correctly:

enter image description here

enter image description here

enter image description here

As suggested by OP in comments, you may need to use org-mode-restart (or org-reload) or kill/reload your buffer.


Edit: This works for org-mode with versions prior 8.3 (that is till 8.2.10)

With versions ≥8.3.1, I have to modify

  • org-element-all-objects
  • possibly org-element-object-restrictions
  • org-element--set-regexps
  • org-element--object-lex

and of course still add the functions

  • org-element-my-object-keystroke-parser
  • org-element-my-object-keystroke-interpreter

but

  • org-element-object-successor-alist
  • org-element-text-markup-successor

are now deleted.

Thanks to Charles C. Berry for his help.

fredtantini
  • 741
  • 8
  • 13
  • Is `%` marker a built-in one? I cannot get it to work with latest Org. As for other markers, it works fine if I change their faces. But is there a way to really add our own markers? Nevertheless, your answer is useful. – Tu Do Jun 01 '15 at 14:32
  • `%` is not currently used as a marker. You can use it the same way I used `‰`. I don't understand your second question though, `‰` **is** a new marker. – fredtantini Jun 02 '15 at 07:59
  • Ok, I was able to make the `%` marker work, but I had to run `org-reload`. You should update the answer with that command. – Tu Do Jun 02 '15 at 15:52
  • Actually, we don't need `org-reload` but `org-mode-restart`. The thing is, we must kill previous Org buffer and create a new one for the change to take effect. – Tu Do Jun 02 '15 at 16:19
  • Thanks for the tips. I have updated my answer. Glad I could help – fredtantini Jun 03 '15 at 07:14
1

You can use org-extra-emphasis: Extra Emphasis markers for Emacs Org mode.

The solution outlined here works with org-9.5.3.

To get this

Buffer as it is

Buffer when org-extra-emphasis-mode is OFF

Buffer as it is rendered in Emacs with org-extra-emphasis-mode

Buffer as is rendered when org-extra-emphasis-mode is ON

Buffer as it is rendered in Firefox when exporter to HTML

HTML export of org-export-emphasis.org as seen in Firefox

do this

  1. emacs -Q

  2. Download org-extra-emphasis.el to say ~/Downloads/

  3. M-x load-file ~/Downloads/org-extra-emphasis.el

  4. M-x customize-group org-extra-emphasis. Customize org-extra-emphasis-alist variable and org-extra-emphasis-1 face as below.

    Customize org-extra-emphasis

  5. Open a file org-extra-emphasis.org and fill it with following content. (Note: For some reason, the global value of org-hide-emphasis-markers was not getting inherited in the org buffer. So, I had to force its value using a file local variable.)

#+TITLE: Additional Emphasis Markers to Org mode files

Start Emacs, open a file with <kbd>C-x C-f<kbd>, do some edits, and
save it with <kbd>C-x C-s<kbd>.  Once you are happy with the edits you
can close Emacs with <kbd>C-x C-c<kbd>.

# Local Variables:
# org-hide-emphasis-markers: t
# End:

  1. Steps 4 & 5 are equivalent to

    (custom-set-variables
     '(org-extra-emphasis-alist '(("<kbd>" org-extra-emphasis-1)))
     '(org-hide-emphasis-markers t))
    
    (custom-set-faces
     '(org-extra-emphasis-1
       ((t (:background "yellow"
            :box (:line-width
                  (2 . 2)
                  :color "red"
                  :style released-button))))))
    
  2. Export the above file to HTML with C-c C-e h o. You will get the output shown earlier.

  3. Export the above file to ODT with C-c C-e o O. You won't get the box around the emphasis market, but you will get the background color carried over.

  4. Repeat the above steps with M-x org-extra-emphasis-mode, and investigate the difference.

(Note org-extra-emphasis-mode, contrary to it's name is not a mode at all. Its effect is global)

When using org-extra-emphasis, you cannot use an arbitrary string as a emphasis marker. If some emphasis marker doesn't work with some export backend change the marker to something else.

For example, using "#' as an emphasis marker is a bad idea. There may be no # in your body text, but the HTML exporter may introduce attributes with #--think colors, or hrefs. The filter function cannot distinguish between # you introduced as an extra emphasis and the # that the HTML exporter itself introduced. This means that the export filter will happily mark any stretch of HTML text enclosed within a # as a span, and you will end up with a broken HTML.


Unlike, the solution shared here, which extends the parser, org-extra-emphasis uses an export filter, specifically org-export-filter-plain-text-functions. So, if something goes wrong, you--an intermediate-level user--can easily fix things.

0

I don't think it's possible to add markers for new org-mode markup options.

According to this 2012 post it looks like org-mode's "emphasis markers will be hard-coded". Doing a quick search for org-emph-re in org.el doesn't reveal any code that would actually generate org-emph-re from org-emphasis-alist. Based on that it looks like org-emph-re won't search for anything that you add to org-emphasis-alist.

This is consistent with my experience (I can redefine the existing emphasis markers, but couldn't get org-mode to recognize | or & or H).

I'm not an expert here, though, and would love to find out that I'm wrong :)

MikeTheTall
  • 659
  • 4
  • 11
  • 1
    Simply editing `org-emphasis-alist` won't add a new marker. You have to *additionally* work with `org-font-lock-extra-keywords` too. [This answer](https://emacs.stackexchange.com/questions/35626/how-to-make-my-own-org-mode-text-emphasis-work-again/35632#35632) gives a working solution. – Dean Seo Jan 24 '19 at 18:03
  • Hey, that works! At least, that achieves the same effect! :) When one uses the `org-font-lock-extra-keywords` then one doesn't need to change `org-emphasis-alist` at all, evidently (I added the `org-font-lock...` code but didn't change my `org-emphasis-alist` and now things are being formatted) – MikeTheTall Jan 26 '19 at 05:45