Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documents with no level-1 heading subsume all level-2 headings under the first level-2 heading #571

Closed
DivineDominion opened this issue Dec 17, 2020 · 4 comments

Comments

@DivineDominion
Copy link

DivineDominion commented Dec 17, 2020

Sample document

---
title: Wat
---
## Section a

### Sub 1

### Sub 11

## Section b

### Sub 2

The imenu output of counsel-imenu and also the outline in treemacs shows this hierarchy:

image

I expected Section b and Section a to be siblings, but Section b is demoted to a child of Section a.

The code that is responsible for this is likely this parser:

markdown-mode/markdown-mode.el

Lines 5532 to 5587 in 4d7f525

(defun markdown-imenu-create-nested-index ()
"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)
(save-excursion
;; Headings
(goto-char (point-min))
(while (re-search-forward markdown-regex-header (point-max) t)
(unless (markdown-code-block-at-point-p)
(cond
((match-string-no-properties 2) ;; level 1 setext
(setq heading (match-string-no-properties 1))
(setq pos (match-beginning 1)
level 1))
((match-string-no-properties 3) ;; level 2 setext
(setq heading (match-string-no-properties 1))
(setq pos (match-beginning 1)
level 2))
((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))))))
;; Footnotes
(let ((fn (markdown-get-defined-footnotes)))
(if (or (zerop (length fn))
(null markdown-add-footnotes-to-imenu))
(cdr root)
(nconc (cdr root) (list (cons "Footnotes" fn))))))))

I may or may not be able to adjust this myself, we'll see, as my elisp isn't that good :) So I'm posting this issue to track the behavior. If someone else chimes in, great!.

@DivineDominion
Copy link
Author

If all headings are level-2 headings, the nested display won't occur. In the parser, level-1 and level-2 are handled separately.

So the level-3 match starting at line 5555 affects the result.

@syohex
Copy link
Collaborator

syohex commented Dec 18, 2020

It looks markdown imenu function assumes there is at least one level1 header when there is a level2 header. I suppose the imenu function should be re-written.

@syohex
Copy link
Collaborator

syohex commented Dec 20, 2020

@DivineDominion I have merged #574. Please check latest version

@syohex syohex closed this as completed Dec 20, 2020
@DivineDominion
Copy link
Author

That was super quick and helpful, thank you a thousandfold @syohex! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants