Un peu de typographie et marquer les raccourcis clavier dans org-mode

Utilisant la disposition de clavier bépo, et soucieux d’écrire le plus correctement possible, j’ai pris l’habitude de mettre des espaces insécables lorsque c’est nécessaire (même si, je l’avoue, je n’utilise pas les espaces fines… désolé). Depuis plusieurs jours, j’utilise également les apostrophes courbes (!wfr) et plus celles qui se trouve sur la touche 4 des claviers azerty, des droites : l’apostrophe courbe vs l'apostrophe droite.

Ajouter des caractères autorisés à org-emphasis-regexp-components

Le souci avec org-mode, c’est que mettre des espaces insécables après des signes d’emphases (mise en gras *, italique /, etc.) n’est pas possible par défaut : « =chose=﹏: » où ﹏ est une espace insécable n’affichera pas « chose : », mais s’affichera tel quel. Dans mes précédents articles, je remplaçais l’espace insécable par une espace « normale ». Et c’est quelque chose que je ne voulais pas. J’ai donc regardé dans le code, et dans org.el est trouvé la variable org-emphasis-regexp-components. Malheureusement, elle est précédée du commentaire suivant :

;; This used to be a defcustom (Org <8.0) but allowing the users to
;; set this option proved cumbersome.  See this message/thread:
;; http://article.gmane.org/gmane.emacs.orgmode/68681

Comme j’utilise maintenant une version ≥ 8.0, je suis obligé de la modifier « en dur » dans un fichier org-conf.el (ou dans le .emacs, mais je vais en fait faire plusieurs modifications ; je crée un fichier à part pour ma configuration d’org-mode). La documentation de la variable indique clairement les différents parties : les caractères possibles avant le signe de début, après le signe le fin, interdits après le signe de début/avant le signe de fin, etc.

Ce qui m’intéresse, ce sont les signes autorisés avant et après. Voilà donc ce que j’ai dans mon fichier :

;on ajoute _ et … dans post, ’ dans pre
(defvar org-emphasis-regexp-components
  '(" \t ’('\"{" "- \t ….,:!?;'\")}\\" " \t\r\n,'" "." 1)
  "support for ' ', '…' and '’'")

Mes modifications sont les deux caractères qui suivent la tabulation.

Indiquer les appuis sur des touches

Une autre modification que je souhaitais depuis quelques temps, est celle de séparer la façon dont je mets en avant les noms de fonctions des raccourcis clavier. Avant, j’utilisais (essayais d’utiliser) ~ (verbatim) pour marquer les raccourcis, et = (code) pour les fonctions. Mais cela ne me satisfaisait pas. Et puis, j’ai découvert la balise <kbd> (w3.org), et je me suis dit que j’allais utiliser ça pour l’export. Sauf que je voulais garder la signification de ~ et =. Je me suis dit qu’il me fallait un nouveau marqueur. J’utilise dorénavant pour mettre les commandes qu’il faut taper. ‰C-x C-s‰ sera alors exporté en <kbd>C-x C-s</kbd>. Il faudrait que ce soit <kbd><kbd>C</kbd>-<kbd>x</kbd> <kbd>C</kbd>-<kbd>s</kbd></kbd> pour que ce soit plus juste, mais je m’en passerai pour l’instant.

J’avais dans l’idée de modifier mon css pour que le raccourci apparaisse avec un beau petit cadre autour. Et puis je me suis dit que ce serait sympa d’avoir la même chose dans Emacs. Du coup, je me suis créé une face pour cela :

(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)

Pour indiquer que est un marqueur, il faut customizer la variable org-emphasis-alist. La mienne vaut maintenant :

(("*" bold)
 ("/" italic)
 ("_" underline)
 ("=" org-code verbatim)
 ("~" org-verbatim verbatim)
 ("+"
  (:strike-through t))
 ("‰" my-face-org-keystroke verbatim));cette ligne correspond à mon ajout

Il faut maintenant définir/modifier plusieurs fonctions pour qu’org-mode se comporte comme attendu lors de l’export.

Dans mon org-conf.el, il me faut charger ox.el sous peine d’avoir des erreurs :

(require 'ox) 
;;otherwise org-element--parse-objects: Symbol's function definition is void: org-element-my-object-keystroke-parser

J’ai ensuite défini les fonctions qui existent pour bold ou code et modifié celles où apparaissent tous les objets concernés par l’export :

;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) ;a ajouter
               (t (error "Unknown marker at %d" (match-beginning 3))))
              (match-beginning 2))))))

Et voilà, on a ce qu’il faut pour exporter ‰C-x C-s‰ en « C-x C-s » et pour que dans Emacs ça y ressemble également.

Reste maintenant l’export via C-c C-e. On peut redéfinir le backend html en copiant/collant les lignes d’ox-html.el qui commencent par (org-export-define-backend 'html et en ajoutant (my-object-keystroke . org-html-keystroke) dans la liste qui va bien. Mais ça fait un peu long. Et puis on perd l’export par défaut.

J’ai préféré définir mon propre export, vu que ce n’est pas très difficile :

(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))

Je n’ai plus qu’à faire un C-c C-e h r pour exporter comme il faut.

Il m’a fallu également modifier ma configuration pour publier, mais vu que je suis en train de faire des modifications, j’y reviendrai un autre jour.

Il va falloir maintenant que je reprenne mes anciens articles pour changer les ~ par des , mais ça, ça viendra plus tard :þ

Autres billets

Date: <2014-05-18>

Generated by Emacs 24.3.1 (Org mode 8.2.4) - Show Org source (htmlized)

CSS inspired by Tontof, colors by Chaotic Soul

Validate