Skip to content

Commit

Permalink
Toggle GFM checkboxes using mouse-1 or RET
Browse files Browse the repository at this point in the history
GitHub Flavored Markdown checkboxes are turned into buttons that can
be toggled with mouse-1 or RET. This behavior is controlled by a new
custom variable, `markdown-make-gfm-checkboxes-buttons`. If non-nil
the buttons are enabled.

Thanks to Howard Melman <hmelman@gmail.com> for the patch.
  • Loading branch information
hmelman authored and jrblevin committed Aug 13, 2015
1 parent ae89ff6 commit 4121324
Showing 1 changed file with 80 additions and 0 deletions.
80 changes: 80 additions & 0 deletions markdown-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
;; Copyright (C) 2013 Matus Goljer <dota.keys@gmail.com>
;; Copyright (C) 2015 Google, Inc. (Contributor: Samuel Freilich <sfreilich@google.com>)
;; Copyright (C) 2015 Antonis Kanouras <antonis@metadosis.gr>
;; Copyright (C) 2015 Howard Melman <hmelman@gmail.com>

;; Author: Jason R. Blevins <jrblevin@sdf.org>
;; Maintainer: Jason R. Blevins <jrblevin@sdf.org>
Expand Down Expand Up @@ -571,6 +572,11 @@
;; this variable buffer-local allows `markdown-mode' to override
;; the default behavior induced when the global variable is non-nil.
;;
;; * `markdown-make-gfm-checkboxes-buttons' - Whether GitHub Flavored
;; Markdown style checkboxes should be turned into buttons that can
;; be toggled with mouse-1 or RET. If non-nil buttons are enabled, the
;; default is t. This works in `markdown-mode' as well as `gfm-mode'.
;;
;; Additionally, the faces used for syntax highlighting can be modified to
;; your liking by issuing `M-x customize-group RET markdown-faces`
;; or by using the "Markdown Faces" link at the bottom of the mode
Expand Down Expand Up @@ -734,6 +740,8 @@
;; * Roger Bolsius <roger.bolsius@gmail.com> for ordered list improvements.
;; * Google's Open Source Programs Office for recognizing the project with
;; a monetary contribution in June 2015.
;; * Howard Melman <hmelman@gmail.com> for supporting GFM checkboxes
;; as buttons.

;;; Bugs:

Expand Down Expand Up @@ -965,6 +973,11 @@ to `nil' instead. See `font-lock-support-mode' for more details."
(const :tag "lazy lock" lazy-lock-mode)
(const :tag "jit lock" jit-lock-mode)))

(defcustom markdown-make-gfm-checkboxes-buttons t
"When non-nil, make GFM checkboxes into buttons."
:group 'markdown
:type 'boolean)


;;; Font Lock =================================================================

Expand Down Expand Up @@ -1054,6 +1067,12 @@ to `nil' instead. See `font-lock-support-mode' for more details."
(defvar markdown-metadata-value-face 'markdown-metadata-value-face
"Face name to use for metadata values.")

(defvar markdown-gfm-checkbox-face 'markdown-gfm-checkbox-face
"Face name to use for GFM checkboxes.")

(defvar markdown-highlight-face 'markdown-highlight-face
"Face name to use for mouse highlighting.")

(defgroup markdown-faces nil
"Faces used in Markdown Mode"
:group 'markdown
Expand Down Expand Up @@ -1199,6 +1218,16 @@ to `nil' instead. See `font-lock-support-mode' for more details."
"Face for metadata values."
:group 'markdown-faces)

(defface markdown-gfm-checkbox-face
'((t (:inherit font-lock-builtin-face)))
"Face for GFM checkboxes."
:group 'markdown-faces)

(defface markdown-highlight-face
'((t (:inherit highlight)))
"Face for mouse highlighting."
:group 'markdown-faces)

(defconst markdown-regex-link-inline
"\\(!\\)?\\(\\[\\([^]^][^]]*\\|\\)\\]\\)\\((\\([^)]*?\\)\\(?:\\s-+\\(\"[^\"]*\"\\)\\)?)\\)"
"Regular expression for a [text](file) or an image link ![text](file).
Expand Down Expand Up @@ -1368,6 +1397,11 @@ on the value of `markdown-wiki-link-alias-first'.")
"\\|" markdown-regex-angle-uri "\\)")
"Regular expression for matching any recognized link.")

(defconst markdown-regex-gfm-checkbox
" \\(\\[[ xX]\\]\\) "
"Regular expression for matching GFM checkboxes.
Group 1 matches the text to become a button.")

(defconst markdown-regex-block-separator
"\\(\\`\\|\\(\n[ \t]*\n\\)[^\n \t]\\)"
"Regular expression for matching block boundaries.")
Expand Down Expand Up @@ -4841,6 +4875,47 @@ before regenerating font-lock rules for extensions."
(assoc 'markdown-enable-math file-local-variables-alist))
(markdown-reload-extensions)))


;;; GFM Checkboxes as Buttons =================================================

(require 'button)

(define-button-type 'markdown-gfm-checkbox-button
'follow-link t
'face 'markdown-gfm-checkbox-face
'mouse-face 'markdown-highlight-face
'action #'markdown-toggle-gfm-checkbox)

(defun markdown-toggle-gfm-checkbox (button)
"Toggle a GFM checkbox clicked on."
(save-match-data
(save-excursion
(goto-char (button-start button))
(cond ((looking-at "\\[ \\]")
(replace-match "[x]" nil t))
((looking-at "\\[[xX]\\]")
(replace-match "[ ]" nil t))))))

(defun markdown-make-gfm-checkboxes-buttons (start end)
"Make GFM checkboxes buttons in region between START and END."
(save-excursion
(goto-char start)
(let ((case-fold-search t))
(save-excursion
(while (re-search-forward markdown-regex-gfm-checkbox end t)
(make-button (match-beginning 1) (match-end 1)
:type 'markdown-gfm-checkbox-button))))))

;; Called when any modification is made to buffer text.
(defun markdown-gfm-checkbox-after-change-function (beg end old-len)
"Add to `after-change-functions' to setup GFM checkboxes as buttons."
(save-excursion
(save-match-data
;; Rescan between start of line from `beg' and start of line after `end'.
(markdown-make-gfm-checkboxes-buttons
(progn (goto-char beg) (beginning-of-line) (point))
(progn (goto-char end) (forward-line 1) (point))))))


;;; Mode Definition ==========================================================

Expand Down Expand Up @@ -4953,6 +5028,11 @@ before regenerating font-lock rules for extensions."
;; Anytime text changes make sure it gets fontified correctly
(add-hook 'after-change-functions 'markdown-check-change-for-wiki-link t t)

;; Make checkboxes buttons
(when markdown-make-gfm-checkboxes-buttons
(markdown-make-gfm-checkboxes-buttons (point-min) (point-max))
(add-hook 'after-change-functions 'markdown-gfm-checkbox-after-change-function t t))

;; If we left the buffer there is a really good chance we were
;; creating one of the wiki link documents. Make sure we get
;; refontified when we come back.
Expand Down

0 comments on commit 4121324

Please sign in to comment.