Skip to content

Commit

Permalink
Fix creating imenu index when there is no level1 header
Browse files Browse the repository at this point in the history
  • Loading branch information
syohex committed Dec 19, 2020
1 parent 4d7f525 commit 91a25f5
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 38 deletions.
4 changes: 3 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
- Fix wrong fontification words between strong markups [GH-534][]
- Fix wrong italic fontification just after code block [GH-548][]
- Fix too indended list face issue [GH-569][]
- Fix creating imenu index issue when there is no level-1 header too[GH-571][]

[gh-290]: https://github.com/jrblevin/markdown-mode/issues/290
[gh-311]: https://github.com/jrblevin/markdown-mode/issues/311
Expand All @@ -52,7 +53,8 @@
[gh-548]: https://github.com/jrblevin/markdown-mode/issues/548
[gh-553]: https://github.com/jrblevin/markdown-mode/issues/553
[gh-560]: https://github.com/jrblevin/markdown-mode/issues/560
[gh-560]: https://github.com/jrblevin/markdown-mode/issues/569
[gh-569]: https://github.com/jrblevin/markdown-mode/issues/569
[gh-571]: https://github.com/jrblevin/markdown-mode/issues/571

# Markdown Mode 2.4

Expand Down
83 changes: 46 additions & 37 deletions markdown-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -5533,52 +5533,61 @@ See also `markdown-mode-map'.")
"Create and return a nested imenu index alist for the current buffer.
See `imenu-create-index-function' and `imenu--index-alist' for details."
(let* ((root '(nil . nil))
cur-alist
(cur-level 0)
(empty-heading "-")
(self-heading ".")
hashes pos level heading)
(min-level 9999)
hashes headers)
(save-excursion
;; Headings
(goto-char (point-min))
(while (re-search-forward markdown-regex-header (point-max) t)
(unless (markdown-code-block-at-point-p)
(unless (or (markdown-code-block-at-point-p)
(and (match-beginning 3)
(get-text-property (match-beginning 3) 'markdown-yaml-metadata-end)))
(cond
((match-string-no-properties 2) ;; level 1 setext
(setq heading (match-string-no-properties 1))
(setq pos (match-beginning 1)
level 1))
(setq min-level 1)
(push (list :heading (match-string-no-properties 1)
:point (match-beginning 1)
:level 1) headers))
((match-string-no-properties 3) ;; level 2 setext
(setq heading (match-string-no-properties 1))
(setq pos (match-beginning 1)
level 2))
(setq min-level (min min-level 2))
(push (list :heading (match-string-no-properties 1)
:point (match-beginning 1)
:level (- 2 (1- min-level))) headers))
((setq hashes (markdown-trim-whitespace
(match-string-no-properties 4)))
(setq heading (match-string-no-properties 5)
pos (match-beginning 4)
level (length hashes))))
(let ((alist (list (cons heading pos))))
(cond
((= cur-level level) ; new sibling
(setcdr cur-alist alist)
(setq cur-alist alist))
((< cur-level level) ; first child
(dotimes (_ (- level cur-level 1))
(setq alist (list (cons empty-heading alist))))
(if cur-alist
(let* ((parent (car cur-alist))
(self-pos (cdr parent)))
(setcdr parent (cons (cons self-heading self-pos) alist)))
(setcdr root alist)) ; primogenitor
(setq cur-alist alist)
(setq cur-level level))
(t ; new sibling of an ancestor
(let ((sibling-alist (last (cdr root))))
(dotimes (_ (1- level))
(setq sibling-alist (last (cdar sibling-alist))))
(setcdr sibling-alist alist)
(setq cur-alist alist))
(setq cur-level level))))))
(setq min-level (min min-level (length hashes)))
(push (list :heading (match-string-no-properties 5)
:point (match-beginning 4)
:level (- (length hashes) (1- min-level))) headers)))))
(cl-loop with cur-level = 0
with cur-alist = nil
with empty-heading = "-"
with self-heading = "."
for header in (reverse headers)
for level = (plist-get header :level)
do
(let ((alist (list (cons (plist-get header :heading) (plist-get header :point)))))
(cond
((= cur-level level) ; new sibling
(setcdr cur-alist alist)
(setq cur-alist alist))
((< cur-level level) ; first child
(dotimes (_ (- level cur-level 1))
(setq alist (list (cons empty-heading alist))))
(if cur-alist
(let* ((parent (car cur-alist))
(self-pos (cdr parent)))
(setcdr parent (cons (cons self-heading self-pos) alist)))
(setcdr root alist)) ; primogenitor
(setq cur-alist alist)
(setq cur-level level))
(t ; new sibling of an ancestor
(let ((sibling-alist (last (cdr root))))
(dotimes (_ (1- level))
(setq sibling-alist (last (cdar sibling-alist))))
(setcdr sibling-alist alist)
(setq cur-alist alist))
(setq cur-level level)))))
;; Footnotes
(let ((fn (markdown-get-defined-footnotes)))
(if (or (zerop (length fn))
Expand Down
20 changes: 20 additions & 0 deletions tests/markdown-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -6510,6 +6510,26 @@ https://github.com/jrblevin/markdown-mode/issues/235"
(should-not (member "^fn1" entries))
(should-not (member "^fn2" entries)))))

(ert-deftest test-markdown-imenu/no-level-one-header ()
"Create imenu entries if there is no level-1 header
https://github.com/jrblevin/markdown-mode/issues/571"
(markdown-test-string "---
title: Wat
---

## Section a

### Sub 1

### Sub 11

## Section b

### Sub 2"
(let ((entries (markdown-imenu-create-nested-index)))
(should (string= (car (nth 0 entries)) "Section a"))
(should (string= (car (nth 1 entries)) "Section b")))))

(ert-deftest test-markdown-command/function ()
"Test ‘markdown’ with ‘markdown-command’ being a function."
(markdown-test-string "foo"
Expand Down

0 comments on commit 91a25f5

Please sign in to comment.