Open org-mode heading from treemacs broken (Something went wrong when finding tag)
I encounter problems, when trying to open a heading from treemacs. Wehen double-clicking, it would report:
[Treemacs] Something went wrong when finding tag 'xxxx': (wrong-type-argument integer-or-marker-p nil)
Moreover it would close the buffer.
My setup:
- emacs 28.2
- win10
- treemacs 20221107.2105
Message window is not really very talkative. What can I do to track this down or fix?
Eval this code.
(defun treemacs--imenu-tag-noselect (file tag-path)
(let ((tag (-last-item tag-path))
(path (-butlast tag-path)))
(progn
(find-file-noselect file)
(let ((index (treemacs--get-imenu-index file)))
(dolist (path-item path)
(setq index (cdr (assoc path-item index))))
(-let [(buf . pos)
(treemacs--extract-position (cdr (--first (equal (car it) tag) index)) path)]
;; some imenu implementations, like markdown, will only provide
;; a raw buffer position (an int) to move to
(list (or buf (get-file-buffer file)) pos))))))
It's the function where the error happens, without the error cordon. That way you'll see a full stack trace when you enable debug on error.
Based on a quick test tag navigation does work on my end, so other than the stack trace it'd be useful if I had an example org file where the error happens for you.
Finally I also need to know your org-version.
I use org-version 9.6
I don't receive a stack-trace with debug-on-error, loading the function provided above. This the message window output:
treemacs--imenu-tag-noselect
Debug on Error enabled globally
c:/dummy.org and s:/Projekt/dummy.org are the same file
[Treemacs] Something went wrong when finding tag 'Head 1': (wrong-type-argument integer-or-marker-p nil)
treemacs--imenu-tag-noselect
c:/dummy.org and s:/Projekt/dummy.org are the same file
[Treemacs] Something went wrong when finding tag 'Head 1': (wrong-type-argument integer-or-marker-p nil)
Please find attached the very simple example file:
Thanks!
I accidentally gave you the mouse interface version of the tag code. Here's the correct defun:
(defun treemacs--call-imenu-and-goto-tag (tag-path &optional org?)
(let* ((file (car tag-path))
(path (-butlast (cdr tag-path)))
(tag (-last-item tag-path)))
(progn
(find-file-noselect file)
(let ((index (treemacs--get-imenu-index file)))
(dolist (path-item path)
(setq index (cdr (assoc path-item index))))
(-let [(buf . pos) (treemacs--extract-position
(-let [item (--first
(equal (car it) tag)
index)]
(if org? item (cdr item)))
(car tag-path))]
;; some imenu implementations, like markdown, will only provide
;; a raw buffer position (an int) to move to
(switch-to-buffer (or buf (get-file-buffer file)))
(if (functionp pos)
(funcall pos)
(goto-char pos))
;; a little bit of convenience - reveal those nested headlines
(when (and (eq major-mode 'org-mode)
(fboundp 'org-reveal))
(org-reveal)))))))
I've upgraded to org 9.6, but couldn't reproduce the error with that either, so we have to debug on your side. Other than the stack trace what does calling this on your dummy file output for you?
(treemacs--get-imenu-index "..../Dummy.org")
Thanks for the update, this time it has worked:
Debugger entered--Lisp error: (wrong-type-argument integer-or-marker-p nil)
goto-char(nil)
(if (functionp pos) (funcall pos) (goto-char pos))
(let* ((--dash-source-47-- (treemacs--extract-position (let* ((item (let ... ... needle))) (if org\? item (cdr item))) (car tag-path))) (buf (car-safe (prog1 --dash-source-47-- (setq --dash-source-47-- (cdr --dash-source-47--))))) (pos --dash-source-47--)) (switch-to-buffer (or buf (get-file-buffer file))) (if (functionp pos) (funcall pos) (goto-char pos)) (if (and (eq major-mode 'org-mode) (fboundp 'org-reveal)) (progn (org-reveal))))
(let ((index (treemacs--get-imenu-index file))) (let ((--dolist-tail-- path) path-item) (while --dolist-tail-- (setq path-item (car --dolist-tail--)) (setq index (cdr (assoc path-item index))) (setq --dolist-tail-- (cdr --dolist-tail--)))) (let* ((--dash-source-47-- (treemacs--extract-position (let* ((item ...)) (if org\? item (cdr item))) (car tag-path))) (buf (car-safe (prog1 --dash-source-47-- (setq --dash-source-47-- (cdr --dash-source-47--))))) (pos --dash-source-47--)) (switch-to-buffer (or buf (get-file-buffer file))) (if (functionp pos) (funcall pos) (goto-char pos)) (if (and (eq major-mode 'org-mode) (fboundp 'org-reveal)) (progn (org-reveal)))))
(progn (find-file-noselect file) (let ((index (treemacs--get-imenu-index file))) (let ((--dolist-tail-- path) path-item) (while --dolist-tail-- (setq path-item (car --dolist-tail--)) (setq index (cdr (assoc path-item index))) (setq --dolist-tail-- (cdr --dolist-tail--)))) (let* ((--dash-source-47-- (treemacs--extract-position (let* (...) (if org\? item ...)) (car tag-path))) (buf (car-safe (prog1 --dash-source-47-- (setq --dash-source-47-- ...)))) (pos --dash-source-47--)) (switch-to-buffer (or buf (get-file-buffer file))) (if (functionp pos) (funcall pos) (goto-char pos)) (if (and (eq major-mode 'org-mode) (fboundp 'org-reveal)) (progn (org-reveal))))))
(let* ((file (car tag-path)) (path (-butlast (cdr tag-path))) (tag (-last-item tag-path))) (progn (find-file-noselect file) (let ((index (treemacs--get-imenu-index file))) (let ((--dolist-tail-- path) path-item) (while --dolist-tail-- (setq path-item (car --dolist-tail--)) (setq index (cdr (assoc path-item index))) (setq --dolist-tail-- (cdr --dolist-tail--)))) (let* ((--dash-source-47-- (treemacs--extract-position (let* ... ...) (car tag-path))) (buf (car-safe (prog1 --dash-source-47-- ...))) (pos --dash-source-47--)) (switch-to-buffer (or buf (get-file-buffer file))) (if (functionp pos) (funcall pos) (goto-char pos)) (if (and (eq major-mode 'org-mode) (fboundp 'org-reveal)) (progn (org-reveal)))))))
treemacs--call-imenu-and-goto-tag(("c:/mnt/iav/Projekt/KOV2/Fremdvergabe/project.org" #("Planung" 0 7 (org-imenu-marker #<marker in no buffer> org-imenu t)) #("KW17" 0 4 (org-imenu-marker #<marker in no buffer> org-imenu t))))
treemacs--goto-tag(#<marker (moves after insertion) at 338 in *Treemacs-Scoped-Buffer-#<frame GNU Emacs at 20IAV502790N-0 0000027eea6ad3c0>*>)
treemacs-visit-node-in-most-recently-used-window()
treemacs-doubleclick-action((double-mouse-1 (#<window 10 on *Treemacs-Scoped-Buffer-#<frame GNU Emacs at 20IAV502790N-0 0000027eea6ad3c0>*> 339 (90 . 649) 7247312 nil 339 (9 . 26) nil (4 . 11) (8 . 16)) 2))
funcall-interactively(treemacs-doubleclick-action (double-mouse-1 (#<window 10 on *Treemacs-Scoped-Buffer-#<frame GNU Emacs at 20IAV502790N-0 0000027eea6ad3c0>*> 339 (90 . 649) 7247312 nil 339 (9 . 26) nil (4 . 11) (8 . 16)) 2))
command-execute(treemacs-doubleclick-action)
Please also find the requested output for the imenu index:
((#("Head 1" 0 6 (org-imenu t org-imenu-marker #<marker in no buffer>)) . #<marker in no buffer>)
(#("Head 2" 0 6 (org-imenu t org-imenu-marker #<marker in no buffer>)) . #<marker in no buffer>))
Thanks!
Still nothing suspicious. Let's produce some debug output next. Eval this and try again:
(defun treemacs--call-imenu-and-goto-tag (tag-path &optional org?)
"Call the imenu index of the tag at TAG-PATH and go to its position.
ORG? should be t when this function is called for an org buffer and index since
org requires a slightly different position extraction because the position of a
headline with sub-elements is saved in an `org-imenu-marker' text property."
(treemacs-log "Goto-Tag Path %s Org? %s" tag-path org?)
(let* ((file (car tag-path))
(path (-butlast (cdr tag-path)))
(tag (-last-item tag-path)))
(treemacs-log "File %s" file)
(treemacs-log "Path %s" path)
(treemacs-log "Tag %s" tag)
(condition-case e
(progn
(find-file-noselect file)
(let ((index (treemacs--get-imenu-index file)))
(treemacs-log "Index %s" index)
(dolist (path-item path)
(setq index (cdr (assoc path-item index))))
(treemacs-log "Postprocess Index %s" index)
(-let [(buf . pos) (treemacs--extract-position
(-let [item (--first
(equal (car it) tag)
index)]
(if org? item (cdr item)))
(car tag-path))]
(treemacs-log "Extracted Position %s %s" buf pos)
;; some imenu implementations, like markdown, will only provide
;; a raw buffer position (an int) to move to
(switch-to-buffer (or buf (get-file-buffer file)))
(treemacs-log "Switched to %s" (current-buffer))
(if (functionp pos)
(funcall pos)
(goto-char pos))
;; a little bit of convenience - reveal those nested headlines
(when (and (eq major-mode 'org-mode)
(fboundp 'org-reveal))
(org-reveal)))))
(error
(treemacs-log-err "Something went wrong when finding tag '%s': %s"
(propertize tag 'face 'treemacs-tags-face)
e)))))
The output should look like this:
[Treemacs] Goto-Tag Path (/home/am/Downloads/dummy.org Head 2) Org? nil
[Treemacs] File /home/am/Downloads/dummy.org
[Treemacs] Path nil
[Treemacs] Tag Head 2
[Treemacs] Index ((Head 1 . #<marker at 1 in dummy.org>) (Head 2 . #<marker at 10 in dummy.org>))
[Treemacs] Postprocess Index ((Head 1 . #<marker at 1 in dummy.org>) (Head 2 . #<marker at 10 in dummy.org>))
[Treemacs] Extracted Position dummy.org 10
[Treemacs] Switched to dummy.org
[Treemacs] Goto-Tag Path (.../dummy.org Head 1) Org? nil
[Treemacs] File .../dummy.org
[Treemacs] Path nil
[Treemacs] Tag Head 1
.../dummy.org and mnt/dummy.org are the same file
[Treemacs] Index ((Head 1 . #<marker in no buffer>) (Head 2 . #<marker in no buffer>))
[Treemacs] Postprocess Index ((Head 1 . #<marker in no buffer>) (Head 2 . #<marker in no buffer>))
[Treemacs] Extracted Position nil nil
[Treemacs] Switched to project.org
[Treemacs] Something went wrong when finding tag 'Head 1': (wrong-type-argument integer-or-marker-p nil)
Apparently emacs claims that the same file exists on two locations. This is intentionally by using symbolic link. I checked with a file not having symbolic link and here treemacs perfectly works. I am sure that this setup has worked before, but this could have been also with older emacs version (i.e. 27). As workaround I can simply re-configure my treemacs workspaces by avoiding the symbolic link. Anyway, I know that this is off-topic from treemacs perspective now, but do you have an idea why this happens?
Thanks!
Are both the original file and the symlink together in the same workspace? If yes then that could be the cause of the problem. Long story short treemacs treats a file's absolute path as basically a unique primary key, and getting rid of that restriction would be a Long and Unpleasant undertaking. A symlink is not quite the same thing, but I think it's close enough to potentially cause some confusion.
I am not sure however, and couldn't reproduce the problem with symlinks of my own, so let's take a look why we can't extract that headline position. Try this:
(defun treemacs--extract-position (item file)
(declare (side-effect-free t))
(treemacs-log "Extract Item %s %s File %s" (type-of item) item file)
(pcase (type-of item)
('marker
(cons (marker-buffer item) (marker-position item)))
('overlay
(cons (overlay-buffer item) (overlay-start item)))
('integer
(cons nil item))
('cons
(cond
((eq 'pdf-outline-imenu-activate-link (cadr item))
(with-no-warnings
(cons (find-buffer-visiting file) (lambda () (apply #'pdf-outline-imenu-activate-link item)))))
((get-text-property 0 'org-imenu-marker (car item))
(-let [org-marker (get-text-property 0 'org-imenu-marker (car item))]
(cons (marker-buffer org-marker) (marker-position org-marker))))))))
treemacs--extract-position
[Treemacs] Extract Item marker #<marker in no buffer> File /mnt/dummy.org
/mnt/dummy.org and /dummy.org are the same file
[Treemacs] Extract Item marker #<marker in no buffer> File /mnt/dummy.org
[Treemacs] Something went wrong when finding tag 'Head 1': (wrong-type-argument integer-or-marker-p nil)
I configured my workspace by using the sym-linked location. There is no overlap with actual file location from workspace perspective.
Thanks!
Ok, I think I know when the problem happens - you need to have the real file already opened, and then to try and get the tag in the linked file. Try this version, it'll resolve the link before looking for tags and looked like it fixed the issue on my end:
(defun treemacs--call-imenu-and-goto-tag (tag-path &optional org?)
(let* ((file (car tag-path))
(path (-butlast (cdr tag-path)))
(tag (-last-item tag-path)))
(condition-case e
(progn
(-when-let (link-target (file-symlink-p file))
(setf file link-target))
(find-file-noselect file)
(let ((index (treemacs--get-imenu-index file)))
(dolist (path-item path)
(setq index (cdr (assoc path-item index))))
(-let [(buf . pos) (treemacs--extract-position
(-let [item (--first
(equal (car it) tag)
index)]
(if org? item (cdr item)))
(car tag-path))]
;; some imenu implementations, like markdown, will only provide
;; a raw buffer position (an int) to move to
(switch-to-buffer (or buf (get-file-buffer file)))
(if (functionp pos)
(funcall pos)
(goto-char pos))
;; a little bit of convenience - reveal those nested headlines
(when (and (eq major-mode 'org-mode)
(fboundp 'org-reveal))
(org-reveal)))))
(error
(treemacs-log-err "Something went wrong when finding tag '%s': %s"
(propertize tag 'face 'treemacs-tags-face)
e)))))
Thanks, but I think that did't work:
treemacs--call-imenu-and-goto-tag
.../dummy.org and /mnt/dummy.org are the same file
[Treemacs] Something went wrong when finding tag 'Head 1': (wrong-type-argument integer-or-marker-p nil)
This issue has been automatically marked as stale because it has not had recent activity.
I've pushed a potential fix and can no longer reproduce the problem. What I tried is:
- Open the original file outside of treemacs with a simple
find-file - Have the linked file, and only the linked file, as part of a treemacs project
- Look up the tags of the symlink in treemacs
If you still have problems I'll need recipe like this to know exactly what to try.
One additional remark: Since I am on windows I tried directory sym-links vs junctions. Apparently the latter performs better, i.e. I suspect the symbolic link (created with mklink /D <target> <source> vs. mklink /J <target> <source>.
This issue has been automatically marked as stale because it has not had recent activity.