From 09b8e689c893c23921660baf489d4fe31ab92ba7 Mon Sep 17 00:00:00 2001 From: Dmitry Dzhus Date: Sat, 24 Mar 2018 19:20:08 +0000 Subject: [PATCH 01/13] markdown-for-all-refs macro, markdown-get-all-refs function --- markdown-mode.el | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/markdown-mode.el b/markdown-mode.el index 790b5a24..9d5a5467 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -5766,6 +5766,35 @@ the link, and line is the line number on which the link appears." (cl-pushnew (list text start line) links :test #'equal)))) links)) +(defmacro markdown-for-all-refs (f) + `(let ((result)) + (save-excursion + (goto-char (point-min)) + (while + (re-search-forward markdown-regex-link-reference nil t) + (let* ((text (match-string-no-properties 3)) + (reference (match-string-no-properties 6)) + (target (downcase (if (string= reference "") text reference)))) + (,f text target result)))) + (reverse result))) + +(defmacro markdown-collect-always (_ target result) + `(cl-pushnew ,target ,result :test #'equal)) + +(defmacro markdown-collect-undefined (text target result) + `(unless (markdown-reference-definition target) + (let ((entry (assoc ,target ,result))) + (if (not entry) + (cl-pushnew + (cons ,target (list (cons ,text (markdown-line-number-at-pos)))) + ,result :test #'equal) + (setcdr entry + (append (cdr entry) (list (cons ,text (markdown-line-number-at-pos))))))))) + +(defun markdown-get-all-refs () + "Return a list of all Markdown references." + (markdown-for-all-refs markdown-collect-always)) + (defun markdown-get-undefined-refs () "Return a list of undefined Markdown references. Result is an alist of pairs (reference . occurrences), where @@ -5773,23 +5802,7 @@ occurrences is itself another alist of pairs (label . line-number). For example, an alist corresponding to [Nice editor][Emacs] at line 12, \[GNU Emacs][Emacs] at line 45 and [manual][elisp] at line 127 is \((\"emacs\" (\"Nice editor\" . 12) (\"GNU Emacs\" . 45)) (\"elisp\" (\"manual\" . 127)))." - (let ((missing)) - (save-excursion - (goto-char (point-min)) - (while - (re-search-forward markdown-regex-link-reference nil t) - (let* ((text (match-string-no-properties 3)) - (reference (match-string-no-properties 6)) - (target (downcase (if (string= reference "") text reference)))) - (unless (markdown-reference-definition target) - (let ((entry (assoc target missing))) - (if (not entry) - (cl-pushnew - (cons target (list (cons text (markdown-line-number-at-pos)))) - missing :test #'equal) - (setcdr entry - (append (cdr entry) (list (cons text (markdown-line-number-at-pos)))))))))) - (reverse missing)))) + (markdown-for-all-refs markdown-collect-undefined)) (defconst markdown-reference-check-buffer "*Undefined references for %buffer%*" From cf69f40c12e12888fd1a96a383f7f245caf790f5 Mon Sep 17 00:00:00 2001 From: Dmitry Dzhus Date: Sat, 24 Mar 2018 21:05:08 +0000 Subject: [PATCH 02/13] Include line numbers in markdown-get-defined-references result --- markdown-mode.el | 9 ++++++--- tests/markdown-test.el | 10 +++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/markdown-mode.el b/markdown-mode.el index 9d5a5467..550d5261 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -2781,13 +2781,16 @@ intact additional processing." (match-beginning 5) (match-end 5))))))))) (defun markdown-get-defined-references () - "Return a list of all defined reference labels (not including square brackets)." + "Return all defined reference labels and their line numbers (not including square brackets)." (save-excursion (goto-char (point-min)) (let (refs) (while (re-search-forward markdown-regex-reference-definition nil t) (let ((target (match-string-no-properties 2))) - (cl-pushnew target refs :test #'equal))) + (cl-pushnew + (cons target + (markdown-line-number-at-pos (match-beginning 2))) + refs :test #'equal :key #'car))) (reverse refs)))) (defun markdown-get-used-uris () @@ -3938,7 +3941,7 @@ This is an internal function called by (let* ((ref (when ref (concat "[" ref "]"))) (defined-refs (append (mapcar (lambda (ref) (concat "[" ref "]")) - (markdown-get-defined-references)))) + (mapcar #'car (markdown-get-defined-references))))) (used-uris (markdown-get-used-uris)) (uri-or-ref (completing-read "URL or [reference]: " diff --git a/tests/markdown-test.el b/tests/markdown-test.el index f818b38c..a73d2f5f 100644 --- a/tests/markdown-test.el +++ b/tests/markdown-test.el @@ -3605,7 +3605,15 @@ only partially propertized." "Test `markdown-get-defined-references'." (markdown-test-file "syntax.text" (should (equal (markdown-get-defined-references) - '("src" "1" "2" "3" "4" "5" "6" "bq" "l")))) + '(("src" . 37) + ("1" . 55) + ("2" . 56) + ("3" . 57) + ("4" . 58) + ("5" . 59) + ("6" . 60) + ("bq" . 205) + ("l" . 206))))) (markdown-test-file "outline.text" (should (equal (markdown-get-defined-references) nil))) (markdown-test-file "wiki-links.text" From e2624e43b1eb5edeaa592869e330c5cb9469d8ba Mon Sep 17 00:00:00 2001 From: Dmitry Dzhus Date: Sat, 24 Mar 2018 23:34:43 +0000 Subject: [PATCH 03/13] Add markdown-unused-refs Modeled after markdown-check-refs, it performs the opposite check: finding references which are defined but not used anywhere in the buffer. --- CHANGES.md | 2 ++ README.md | 5 ++++ markdown-mode.el | 62 ++++++++++++++++++++++++++++++++++++++++++ tests/markdown-test.el | 26 ++++++++++++++++++ tests/refs.text | 11 ++++++++ 5 files changed, 106 insertions(+) create mode 100644 tests/refs.text diff --git a/CHANGES.md b/CHANGES.md index 76b5eba8..ed39ecd4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -43,6 +43,8 @@ - Add custom variables `markdown-xhtml-body-preamble` and `markdown-xhtml-body-epilogue` for wrapping additional XHTML tags around the output. ([GH-280][], [GH-281][]) + - Add `markdown-unused-refs` command to list and clean up unused + references (available via `C-c C-c u`) * Improvements: diff --git a/README.md b/README.md index 4ff11345..8a3bc1b9 100644 --- a/README.md +++ b/README.md @@ -355,6 +355,11 @@ can obtain a list of all keybindings by pressing C-c C-h. end of the buffer. Similarly, selecting the line number will jump to the corresponding line. + C-c C-c u will check for unused references. This will + also open a small buffer if any are found, similar to undefined + reference checking. The buffer for unused references will contain + `X` buttons that remove unused references when selected. + C-c C-c n renumbers any ordered lists in the buffer that are out of sequence. diff --git a/markdown-mode.el b/markdown-mode.el index 550d5261..55ee851f 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -5291,6 +5291,7 @@ Assumes match data is available for `markdown-regex-italic'." (propertize "e" 'face 'markdown-bold-face) "xport, " "export & pre" (propertize "v" 'face 'markdown-bold-face) "iew, " (propertize "c" 'face 'markdown-bold-face) "heck refs, " + (propertize "u" 'face 'markdown-bold-face) "nused refs, " "C-h = more"))) (defvar markdown-mode-style-map @@ -5335,6 +5336,7 @@ Assumes match data is available for `markdown-regex-italic'." (define-key map (kbd "l") 'markdown-live-preview-mode) (define-key map (kbd "w") 'markdown-kill-ring-save) (define-key map (kbd "c") 'markdown-check-refs) + (define-key map (kbd "u") 'markdown-unused-refs) (define-key map (kbd "n") 'markdown-cleanup-list-numbers) (define-key map (kbd "]") 'markdown-complete-buffer) (define-key map (kbd "^") 'markdown-table-sort-lines) @@ -5591,6 +5593,7 @@ See also `markdown-mode-map'.") :keys "C-c C-s w"] "---" ["Check References" markdown-check-refs] + ["Find Unused References" markdown-unused-refs] ["Toggle URL Hiding" markdown-toggle-url-hiding :style radio :selected markdown-hide-urls] @@ -5807,6 +5810,31 @@ For example, an alist corresponding to [Nice editor][Emacs] at line 12, \((\"emacs\" (\"Nice editor\" . 12) (\"GNU Emacs\" . 45)) (\"elisp\" (\"manual\" . 127)))." (markdown-for-all-refs markdown-collect-undefined)) +(defun markdown-get-unused-refs () + (cl-set-difference + (markdown-get-defined-references) (markdown-get-all-refs) + :test (lambda (e1 e2) (equal (car e1) e2)))) + +(defconst markdown-unused-references-buffer + "*Unused references for %buffer%*" + "Pattern for name of buffer for listing unused references. +The string %buffer% will be replaced by the corresponding +`markdown-mode' buffer name.") + +(defun markdown-unused-references-buffer (&optional buffer-name) + "Name and return buffer for unused reference checking. +BUFFER-NAME is the name of the main buffer being visited." + (or buffer-name (setq buffer-name (buffer-name))) + (let ((refbuf (get-buffer-create (markdown-replace-regexp-in-string + "%buffer%" buffer-name + markdown-unused-references-buffer)))) + (with-current-buffer refbuf + (when view-mode + (View-exit-and-edit)) + (use-local-map button-buffer-map) + (erase-buffer)) + refbuf)) + (defconst markdown-reference-check-buffer "*Undefined references for %buffer%*" "Pattern for name of buffer for listing undefined references. @@ -5912,6 +5940,17 @@ as by `markdown-get-undefined-refs'." (insert ")") (newline))) +(defun markdown-insert-unused-reference-button (reference oldbuf) + "Insert a button for creating REFERENCE in buffer OLDBUF. +REFERENCE must be a pair of (ref . line-number)." + (let ((label (car reference))) + ;; Create a reference button + (insert-button label + :type 'markdown-goto-line-button + 'target-buffer oldbuf + 'target-line (cdr reference)) + (insert (format " (%d)\n" (cdr reference))))) + (defun markdown-insert-link-button (link oldbuf) "Insert a button for jumping to LINK in buffer OLDBUF. LINK should be a list of the form (text char line) containing @@ -5974,6 +6013,29 @@ defined." (goto-char (point-min)) (forward-line 2))))) +(defun markdown-unused-refs (&optional silent) + "Show all unused Markdown references in current `markdown-mode' buffer. +If SILENT is non-nil, do not message anything when no unused +references found." + (interactive "P") + (when (not (memq major-mode '(markdown-mode gfm-mode))) + (user-error "Not available in current mode")) + (let ((oldbuf (current-buffer)) + (refs (markdown-get-unused-refs)) + (refbuf (markdown-unused-references-buffer))) + (if (null refs) + (progn + (when (not silent) + (message "No unused references found")) + (kill-buffer refbuf)) + (with-current-buffer refbuf + (insert "The following references are not used:\n\n") + (dolist (ref refs) + (markdown-insert-unused-reference-button ref oldbuf)) + (view-buffer-other-window refbuf) + (goto-char (point-min)) + (forward-line 2))))) + ;;; Lists ===================================================================== diff --git a/tests/markdown-test.el b/tests/markdown-test.el index a73d2f5f..26eae338 100644 --- a/tests/markdown-test.el +++ b/tests/markdown-test.el @@ -3833,6 +3833,13 @@ puts 'hello, world' ;;; Reference Checking: +(ert-deftest test-markdown-references/get-unused-refs () + "Test `markdown-get-unused-refs'." + (markdown-test-file "refs.text" + (should (equal (markdown-get-unused-refs) + '(("logorrhea" . 8) + ("orphan" . 11)))))) + (ert-deftest test-markdown-references/goto-line-button () "Create and test a goto line button." (markdown-test-string "line 1\nline 2\n" @@ -3865,6 +3872,25 @@ puts 'hello, world' (should (equal (local-key-binding (kbd "TAB")) 'forward-button)) (should (equal (local-key-binding (kbd "")) 'backward-button)))))) +(ert-deftest test-markdown-references/undefined-refs-killing () + "Test that buttons in unused references buffer delete lines when pushed." + (markdown-test-file "refs.text" + (let* ((target (buffer-name)) + (check (markdown-replace-regexp-in-string + "%buffer%" target + markdown-unused-references-buffer)) + (original-unused-refs (markdown-get-unused-refs))) + (markdown-unused-refs) + ;; Push X + (with-current-buffer (get-buffer check) + (forward-button 1) + (call-interactively 'push-button)) + ;; The first orphan should now be gone with the rest of orphans + ;; moved up by one line + (should (equal (markdown-get-unused-refs) + (mapcar (lambda (o) (cons (car o) (1- (cdr o)))) + (cdr original-unused-refs))))))) + ;;; Lists: (ert-deftest test-markdown-lists/nested-list-file () diff --git a/tests/refs.text b/tests/refs.text new file mode 100644 index 00000000..34f3d077 --- /dev/null +++ b/tests/refs.text @@ -0,0 +1,11 @@ +Now this a pretty [long][graphomania] text. Written to conclude a +period of intensive thinking, it spans many paragraphs, expressing the +author's original views on numerous [problems][] of our society. Once +published, it will draw international attention and spark +[controversy][problems] for months to follow. + +[graphomania]: https://en.wikipedia.org/wiki/Graphomania +[logorrhea]: https://en.wikipedia.org/wiki/Logorrhea_(psychology) + + +[orphan]: http://some.link From 73c4d54dde3af179c929984954ec36328ac81b04 Mon Sep 17 00:00:00 2001 From: Dmitry Dzhus Date: Sat, 24 Mar 2018 22:04:33 +0000 Subject: [PATCH 04/13] Downcase reference labels in markdown-get-defined-references As per https://daringfireball.net/projects/markdown/syntax#link and http://spec.commonmark.org/0.28/#matches link labels are case-insensitive, so it shouldn't make sense to have [mylink]: http://foo1.bar [MyLink]: http://baz1.foo defined in the same document. By downcasing everything in markdown-get-defined-references we make sure that such duplicate links don't show up in markdown-insert-link completion list --- markdown-mode.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/markdown-mode.el b/markdown-mode.el index 55ee851f..d9f88feb 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -2788,7 +2788,7 @@ intact additional processing." (while (re-search-forward markdown-regex-reference-definition nil t) (let ((target (match-string-no-properties 2))) (cl-pushnew - (cons target + (cons (downcase target) (markdown-line-number-at-pos (match-beginning 2))) refs :test #'equal :key #'car))) (reverse refs)))) From 733ff5c23bfd8baba18080ba84b938146dcf3bd9 Mon Sep 17 00:00:00 2001 From: Dmitry Dzhus Date: Sat, 24 Mar 2018 21:48:58 +0000 Subject: [PATCH 05/13] Use defun-markdown-buffer macro to define markdown-reference-check-buffer markdown-unused-references-buffer markdown-reference-links-buffer --- markdown-mode.el | 81 +++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 45 deletions(-) diff --git a/markdown-mode.el b/markdown-mode.el index d9f88feb..afd60240 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -5815,25 +5815,26 @@ For example, an alist corresponding to [Nice editor][Emacs] at line 12, (markdown-get-defined-references) (markdown-get-all-refs) :test (lambda (e1 e2) (equal (car e1) e2)))) -(defconst markdown-unused-references-buffer - "*Unused references for %buffer%*" - "Pattern for name of buffer for listing unused references. -The string %buffer% will be replaced by the corresponding -`markdown-mode' buffer name.") - -(defun markdown-unused-references-buffer (&optional buffer-name) - "Name and return buffer for unused reference checking. -BUFFER-NAME is the name of the main buffer being visited." - (or buffer-name (setq buffer-name (buffer-name))) - (let ((refbuf (get-buffer-create (markdown-replace-regexp-in-string - "%buffer%" buffer-name - markdown-unused-references-buffer)))) - (with-current-buffer refbuf - (when view-mode - (View-exit-and-edit)) - (use-local-map button-buffer-map) - (erase-buffer)) - refbuf)) +(defmacro defun-markdown-buffer (name docstring) + "Define a function to name and return a buffer. + +By convention, NAME must be a name of a string constant with +%buffer% placeholder used to name the buffer, and will also be +used as a name of the function defined. + +DOCSTRING will be used as the first part of the docstring." + `(defun ,name (&optional buffer-name) + ,(concat docstring "\n\nBUFFER-NAME is the name of the main buffer being visited.") + (or buffer-name (setq buffer-name (buffer-name))) + (let ((refbuf (get-buffer-create (markdown-replace-regexp-in-string + "%buffer%" buffer-name + ,name)))) + (with-current-buffer refbuf + (when view-mode + (View-exit-and-edit)) + (use-local-map button-buffer-map) + (erase-buffer)) + refbuf))) (defconst markdown-reference-check-buffer "*Undefined references for %buffer%*" @@ -5841,38 +5842,28 @@ BUFFER-NAME is the name of the main buffer being visited." The string %buffer% will be replaced by the corresponding `markdown-mode' buffer name.") -(defun markdown-reference-check-buffer (&optional buffer-name) - "Name and return buffer for reference checking. -BUFFER-NAME is the name of the main buffer being visited." - (or buffer-name (setq buffer-name (buffer-name))) - (let ((refbuf (get-buffer-create (markdown-replace-regexp-in-string - "%buffer%" buffer-name - markdown-reference-check-buffer)))) - (with-current-buffer refbuf - (when view-mode - (View-exit-and-edit)) - (use-local-map button-buffer-map) - (erase-buffer)) - refbuf)) +(defun-markdown-buffer + markdown-reference-check-buffer + "Name and return buffer for reference checking.") + +(defconst markdown-unused-references-buffer + "*Unused references for %buffer%*" + "Pattern for name of buffer for listing unused references. +The string %buffer% will be replaced by the corresponding +`markdown-mode' buffer name.") + +(defun-markdown-buffer + markdown-unused-references-buffer + "Name and return buffer for unused reference checking.") (defconst markdown-reference-links-buffer "*Reference links for %buffer%*" "Pattern for name of buffer for listing references. The string %buffer% will be replaced by the corresponding buffer name.") -(defun markdown-reference-links-buffer (&optional buffer-name) - "Name, setup, and return a buffer for listing links. -BUFFER-NAME is the name of the main buffer being visited." - (or buffer-name (setq buffer-name (buffer-name))) - (let ((linkbuf (get-buffer-create (markdown-replace-regexp-in-string - "%buffer%" buffer-name - markdown-reference-links-buffer)))) - (with-current-buffer linkbuf - (when view-mode - (View-exit-and-edit)) - (use-local-map button-buffer-map) - (erase-buffer)) - linkbuf)) +(defun-markdown-buffer + markdown-reference-links-buffer + "Name, setup, and return a buffer for listing links.") ;; Add an empty Markdown reference definition to buffer ;; specified in the 'target-buffer property. The reference name is From 8f5ad9d1fdce5d4023ab7aa1f6e350083b1f323f Mon Sep 17 00:00:00 2001 From: Dmitry Dzhus Date: Sun, 25 Mar 2018 02:46:05 +0100 Subject: [PATCH 06/13] Use defun-markdown-ref-checker macro to define markdown-check-refs markdown-unused-refs --- markdown-mode.el | 99 +++++++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 43 deletions(-) diff --git a/markdown-mode.el b/markdown-mode.el index afd60240..e98f2334 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -5979,53 +5979,66 @@ the link text, location, and line number." (t (error "No links for reference %s" reference))))) -(defun markdown-check-refs (&optional silent) +(defmacro defun-markdown-ref-checker + (name docstring checker-function buffer-function none-message buffer-header insert-reference) + "Define a function NAME acting on result of CHECKER-FUNCTION. + +DOCSTRING is used as a docstring for the defined function. + +BUFFER-FUNCTION should name and return an auxiliary buffer to put +results in. + +NONE-MESSAGE is used when CHECKER-FUNCTION returns no results. + +BUFFER-HEADER is put into the auxiliary buffer first, followed by +calling INSERT-REFERENCE for each element in the list returned by +CHECKER-FUNCTION." + `(defun ,name (&optional silent) + ,(concat + docstring + "\n\nIf SILENT is non-nil, do not message anything when no +such references found.") + (interactive "P") + (when (not (memq major-mode '(markdown-mode gfm-mode))) + (user-error "Not available in current mode")) + (let ((oldbuf (current-buffer)) + (refs (,checker-function)) + (refbuf (,buffer-function))) + (if (null refs) + (progn + (when (not silent) + (message ,none-message)) + (kill-buffer refbuf)) + (with-current-buffer refbuf + (insert ,buffer-header) + (dolist (ref refs) + (,insert-reference ref oldbuf)) + (view-buffer-other-window refbuf) + (goto-char (point-min)) + (forward-line 2)))))) + +(defun-markdown-ref-checker + markdown-check-refs "Show all undefined Markdown references in current `markdown-mode' buffer. -If SILENT is non-nil, do not message anything when no undefined -references found. + Links which have empty reference definitions are considered to be defined." - (interactive "P") - (when (not (memq major-mode '(markdown-mode gfm-mode))) - (user-error "Not available in current mode")) - (let ((oldbuf (current-buffer)) - (refs (markdown-get-undefined-refs)) - (refbuf (markdown-reference-check-buffer))) - (if (null refs) - (progn - (when (not silent) - (message "No undefined references found")) - (kill-buffer refbuf)) - (with-current-buffer refbuf - (insert "The following references are undefined:\n\n") - (dolist (ref refs) - (markdown-insert-undefined-reference-button ref oldbuf)) - (view-buffer-other-window refbuf) - (goto-char (point-min)) - (forward-line 2))))) + markdown-get-undefined-refs + markdown-reference-check-buffer + "No undefined references found" + "The following references are undefined:\n\n" + markdown-insert-undefined-reference-button) + + +(defun-markdown-ref-checker + markdown-unused-refs + "Show all unused Markdown references in current `markdown-mode' buffer." + markdown-get-unused-refs + markdown-unused-references-buffer + "No unused references found" + "The following references are unused:\n\n" + markdown-insert-unused-reference-button) -(defun markdown-unused-refs (&optional silent) - "Show all unused Markdown references in current `markdown-mode' buffer. -If SILENT is non-nil, do not message anything when no unused -references found." - (interactive "P") - (when (not (memq major-mode '(markdown-mode gfm-mode))) - (user-error "Not available in current mode")) - (let ((oldbuf (current-buffer)) - (refs (markdown-get-unused-refs)) - (refbuf (markdown-unused-references-buffer))) - (if (null refs) - (progn - (when (not silent) - (message "No unused references found")) - (kill-buffer refbuf)) - (with-current-buffer refbuf - (insert "The following references are not used:\n\n") - (dolist (ref refs) - (markdown-insert-unused-reference-button ref oldbuf)) - (view-buffer-other-window refbuf) - (goto-char (point-min)) - (forward-line 2))))) ;;; Lists ===================================================================== From 2ae93b6a56f2203af62856a5e272d08d3b7e6226 Mon Sep 17 00:00:00 2001 From: Dmitry Dzhus Date: Sat, 24 Mar 2018 22:12:56 +0000 Subject: [PATCH 07/13] Use bold face for unused-reference buttons too --- markdown-mode.el | 1 + 1 file changed, 1 insertion(+) diff --git a/markdown-mode.el b/markdown-mode.el index e98f2334..e65647c1 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -5938,6 +5938,7 @@ REFERENCE must be a pair of (ref . line-number)." ;; Create a reference button (insert-button label :type 'markdown-goto-line-button + 'face 'bold 'target-buffer oldbuf 'target-line (cdr reference)) (insert (format " (%d)\n" (cdr reference))))) From 52b2a05f8c01c6b73ce53a02e8efc0cb7c96560c Mon Sep 17 00:00:00 2001 From: Dmitry Dzhus Date: Sat, 24 Mar 2018 21:36:16 +0000 Subject: [PATCH 08/13] Docstring minor fix --- markdown-mode.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/markdown-mode.el b/markdown-mode.el index e65647c1..38d441e1 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -5883,7 +5883,7 @@ The string %buffer% will be replaced by the corresponding buffer name.") (markdown-check-refs t)))) ;; Jump to line in buffer specified by 'target-buffer property. -;; Line number is button's 'line property. +;; Line number is button's 'target-line property. (define-button-type 'markdown-goto-line-button 'help-echo "mouse-1, RET: go to line" 'follow-link t @@ -5911,7 +5911,7 @@ The string %buffer% will be replaced by the corresponding buffer name.") (defun markdown-insert-undefined-reference-button (reference oldbuf) "Insert a button for creating REFERENCE in buffer OLDBUF. REFERENCE should be a list of the form (reference . occurrences), -as by `markdown-get-undefined-refs'." +as returned by `markdown-get-undefined-refs'." (let ((label (car reference))) ;; Create a reference button (insert-button label From ea51e59a78eb204ca8f3541388d68151a29e83a2 Mon Sep 17 00:00:00 2001 From: Dmitry Dzhus Date: Sat, 24 Mar 2018 23:35:34 +0000 Subject: [PATCH 09/13] whitespace-cleanup --- markdown-mode.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/markdown-mode.el b/markdown-mode.el index 38d441e1..9205acf5 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -409,9 +409,9 @@ nil to disable this." The car is used for subscript, the cdr is used for superscripts." :group 'markdown :type '(cons (choice (sexp :tag "Subscript form") - (const :tag "No lowering" nil)) - (choice (sexp :tag "Superscript form") - (const :tag "No raising" nil))) + (const :tag "No lowering" nil)) + (choice (sexp :tag "Superscript form") + (const :tag "No raising" nil))) :package-version '(markdown-mode . "2.4")) (defcustom markdown-unordered-list-item-prefix " * " From bc2c66a618c077657647faa4c09e246864504ddc Mon Sep 17 00:00:00 2001 From: Dmitry Dzhus Date: Sat, 24 Mar 2018 22:16:48 +0000 Subject: [PATCH 10/13] Remove debugging from markdown-goto-line-button Lefover from 0bd97a26d26bb18fa0c931fc1e631700094ed131 --- markdown-mode.el | 1 - 1 file changed, 1 deletion(-) diff --git a/markdown-mode.el b/markdown-mode.el index 9205acf5..e0a8fb26 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -5889,7 +5889,6 @@ The string %buffer% will be replaced by the corresponding buffer name.") 'follow-link t 'face 'italic 'action (lambda (b) - (message (button-get b 'buffer)) (switch-to-buffer-other-window (button-get b 'target-buffer)) ;; use call-interactively to silence compiler (let ((current-prefix-arg (button-get b 'target-line))) From f8bbf311690a5fef0bd69826cd2e0f3e654c030d Mon Sep 17 00:00:00 2001 From: Dmitry Dzhus Date: Sat, 24 Mar 2018 22:27:53 +0000 Subject: [PATCH 11/13] Add links to kill unused reference lines --- markdown-mode.el | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/markdown-mode.el b/markdown-mode.el index e0a8fb26..10c82fe8 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -5894,6 +5894,20 @@ The string %buffer% will be replaced by the corresponding buffer name.") (let ((current-prefix-arg (button-get b 'target-line))) (call-interactively 'goto-line)))) +;; Kill a line in buffer specified by 'target-buffer property. +;; Line number is button's 'target-line property. +(define-button-type 'markdown-kill-line-button + 'help-echo "mouse-1, RET: kill line" + 'follow-link t + 'face 'italic + 'action (lambda (b) + (switch-to-buffer-other-window (button-get b 'target-buffer)) + ;; use call-interactively to silence compiler + (let ((current-prefix-arg (button-get b 'target-line))) + (call-interactively 'goto-line)) + (kill-line 1) + (markdown-unused-refs t))) + ;; Jumps to a particular link at location given by 'target-char ;; property in buffer given by 'target-buffer property. (define-button-type 'markdown-location-button @@ -5933,14 +5947,22 @@ as returned by `markdown-get-undefined-refs'." (defun markdown-insert-unused-reference-button (reference oldbuf) "Insert a button for creating REFERENCE in buffer OLDBUF. REFERENCE must be a pair of (ref . line-number)." - (let ((label (car reference))) + (let ((label (car reference)) + (line (cdr reference))) ;; Create a reference button (insert-button label :type 'markdown-goto-line-button 'face 'bold 'target-buffer oldbuf - 'target-line (cdr reference)) - (insert (format " (%d)\n" (cdr reference))))) + 'target-line line) + (insert (format " (%d) [" line)) + (insert-button "X" + :type 'markdown-kill-line-button + 'face 'bold + 'target-buffer oldbuf + 'target-line line) + (insert "]") + (newline))) (defun markdown-insert-link-button (link oldbuf) "Insert a button for jumping to LINK in buffer OLDBUF. From 94901f8830d9e3d378ececbb03e686293d71c1fc Mon Sep 17 00:00:00 2001 From: Dmitry Dzhus Date: Sat, 24 Mar 2018 23:11:31 +0000 Subject: [PATCH 12/13] Add a test for markdown-get-undefined-refs --- tests/markdown-test.el | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/markdown-test.el b/tests/markdown-test.el index 26eae338..78503370 100644 --- a/tests/markdown-test.el +++ b/tests/markdown-test.el @@ -3840,6 +3840,12 @@ puts 'hello, world' '(("logorrhea" . 8) ("orphan" . 11)))))) +(ert-deftest test-markdown-references/get-undefined-refs () + "Test `markdown-get-undefined-refs'." + (markdown-test-file "refs.text" + (should (equal (markdown-get-undefined-refs) + '(("problems" ("problems" . 3) ("controversy" . 5))))))) + (ert-deftest test-markdown-references/goto-line-button () "Create and test a goto line button." (markdown-test-string "line 1\nline 2\n" From c319bf88ca49112acfb582612a6df03a77653e59 Mon Sep 17 00:00:00 2001 From: Dmitry Dzhus Date: Sun, 25 Mar 2018 00:10:45 +0000 Subject: [PATCH 13/13] Sort results of markdown-get-unused-refs Apparently cl-set-difference result contains elements in the reverse order on Emacs 24.x, so we sort the list to by line number for consistency --- markdown-mode.el | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/markdown-mode.el b/markdown-mode.el index 10c82fe8..5d527939 100644 --- a/markdown-mode.el +++ b/markdown-mode.el @@ -5811,9 +5811,11 @@ For example, an alist corresponding to [Nice editor][Emacs] at line 12, (markdown-for-all-refs markdown-collect-undefined)) (defun markdown-get-unused-refs () - (cl-set-difference - (markdown-get-defined-references) (markdown-get-all-refs) - :test (lambda (e1 e2) (equal (car e1) e2)))) + (cl-sort + (cl-set-difference + (markdown-get-defined-references) (markdown-get-all-refs) + :test (lambda (e1 e2) (equal (car e1) e2))) + #'< :key #'cdr)) (defmacro defun-markdown-buffer (name docstring) "Define a function to name and return a buffer.