1

At work, I mostly use Emacs for all my programming and text editing but I wouldn't really say I'm a pro. I'm more like beginner or intermediate so I'm not sure if this is really even a question.

I have been tasked with migrating our documentation from LaTeX to Markdown (Our own flavor of Markdown) and after converting to vanilla markdown with pandoc, I have found myself repeating the following pattern a lot.

Say I need to include an image in the .md file from the figures/ directory. My markdown will look something like this

![Fission gas release experimental comparison of IFA-535 rod 809 during
the ramp test.](rod809_fgr){width="4in"}

And I need to convert it to this

!media figures/rod809_fgr.png 
    id=rod809_fgr 
    caption=Fission gas release experimental comparison of IFA-535 rod 809 during the ramp test. 
    style=width:50%

Notice how the file name in the parenths (rod809_fgr) became figures/rod809_fgr.png and id=rod809_fgr and the description was put into the caption. Also the text was indented a specific way.

How can I write a Lisp function that highlights the original markdown and gives me the output I want? Once again, not too familiar with Lisp and still a beginner with Emacs.

Drew
  • 77,472
  • 10
  • 114
  • 243
dylanjm
  • 323
  • 2
  • 10

2 Answers2

1

Just put your cursor at "!" (or anywhere before "}") and run adl/md-converting, that should solve.

(defun adl/md-converting ()
  (interactive)
  (save-restriction
    (adl/md-remove-new-lines)
    (adl/md-bas ?\{ "style=width:50%")
    (adl/md-bas ?\[ "caption=")
    (adl/md-bas ?\( "id=")))

(defun adl/md-remove-new-lines ()
  (let ((beg (point)))
    (search-forward "}")
    (narrow-to-region beg (point)))
  (goto-char (point-min))
  (while (search-forward "\n" nil t) (replace-match " " nil t))
  (search-backward "!" nil t))

(defun adl/md-bas (delim tag)
  (search-forward (string delim))
  (let
      ((beg (point))
       (compl-delim
    (cond ((eq delim ?\() ?\))
          ((eq delim ?\[) ?\])
          ((eq delim ?\{) ?\}))))
    (search-forward (string compl-delim))
    (delete-char -1)
    (kill-region beg (point)))
  (delete-char -1)
  (end-of-line)
  (newline)
  (insert (concat "    " tag))
  (unless (eq delim ?{) (yank))
  (search-backward "!" nil t)
  (when (eq delim ?\()
    (forward-char)
    (insert "media figures/")
    (yank)
    (insert ".png")))

EDIT: You can map it to C-x C-m with (global-set-key (kbd "C-x C-m") 'adl/md-converting). You should put these codes in your init file.

It is worth noting that C-m is RET so C-x C-m is equal to C-x RET (C-x + ENTER).

adl
  • 646
  • 3
  • 6
1

Here's a regexp-based approach. Useful documentation links:

(defun markdown-to-dylanjm-image ()
  "Convert a Markdown image element to dylanjm's house markup format."
  (interactive "@*")
  ;; Look for a Markdown image element before the cursor or immediately
  ;; after the cursor. Don't look any further than the start of the current
  ;; paragraph.
  (let ((limit (save-excursion
                 (backward-paragraph)
                 (point)))
        (regexp "\\s-*!\\[\\([^][]*\\)\\](\\([^()]*\\))\\({[^}{]*}\\)?"))
    (if (and (eq ?! (char-after (1- (point))))
             (eq ?\[ (char-after (point))))
        (backward-char))
    (while (not (looking-at regexp))
      (search-backward "![" limit))
    ;; If the search didn't error out, then we exited the loop with
    ;; `looking-at' matching `regexp'. The match data therefore contains
    ;; the parts of the image link.
    (skip-syntax-forward "-")
    (let ((caption (subst-char-in-string ?\n ?\  (match-string 1)))
          (id (match-string 2))
          (style (and (match-string 3)
                      (substring (match-string 3) 1 -1))))
      ;; Remove the Markdown syntax.
      (delete-region (- (match-beginning 1) 2) (match-end 0))
      ;; Add line breaks before and after if it looks like there aren't any.
      (unless (eolp)
        (open-line 1))
      (unless (<= (point) (save-excursion
                            (back-to-indentation)
                            (point)))
        (insert "\n"))
      ;; Insert the new syntax.
      (insert "!media figures/" id ".png\n"
              "    id=" id "\n"
              "    caption=" caption)
      (when style
        (insert "\n    style=" style)))))

To bind this command to a C-c i after loading the markdown-mode package, put this in your init file:

(defun my-eval-after-load-markdown-mode ()
  (define-key markdown-mode-map "\C-ci" 'markdown-to-dylanjm-image))
(eval-after-load "markdown-mode" '(my-eval-after-load-markdown-mode))