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

Branch scanner incorrectly serves as fallback scanner #186

Closed
KarlJoad opened this issue Aug 30, 2024 · 23 comments
Closed

Branch scanner incorrectly serves as fallback scanner #186

KarlJoad opened this issue Aug 30, 2024 · 23 comments
Assignees
Labels
bug Something isn't working
Milestone

Comments

@KarlJoad
Copy link
Contributor

I just came across this package and want to start using it. But, I am hitting one final little snafu when using magit-todos. When opening or refreshing the magit-status buffer, I get the following error raised (Actual todo items removed for reading clarity). Despite the error being raised, TODOs and FIXMEs still show up in magit-status.

Debugger entered--Lisp error: (wrong-type-argument stringp nil)
  propertize(nil face magit-section-heading)
  magit-todos--insert-items(#<buffer magit: vcode-rocc> (#s(magit-todos-item :filename ...)) :branch-p t)
  magit-todos--git-diff-callback(:callback magit-todos--insert-items :magit-status-buffer #<buffer magit: vcode-rocc> :results-regexp "\\(?:^\\(?8:[^:]+\\):\\(?2:[[:digit:]]+\\):\\(?:\\(?1:\\*+..." :search-regexp-elisp "\\(?:^\\(\\*+\\)[[:blank:]]+\\(\\(?:DONT\\|F\\(?:AIL\\|IXME..." :heading nil :exclude-globs (".git/") :process #<process magit-todos--scan-with-git-diff>)
  apply(magit-todos--git-diff-callback (:callback magit-todos--insert-items :magit-status-buffer #<buffer magit: vcode-rocc> :results-regexp "\\(?:^\\(?8:[^:]+\\):\\(?2:[[:digit:]]+\\):\\(?:\\(?1:\\*+..." :search-regexp-elisp "\\(?:^\\(\\*+\\)[[:blank:]]+\\(\\(?:DONT\\|F\\(?:AIL\\|IXME..." :heading nil :exclude-globs (".git/") :process #<process magit-todos--scan-with-git-diff>))
  #f(compiled-function (&rest args2) #<bytecode -0x1e20688d4a326bd1>)(#<process magit-todos--scan-with-git-diff>)
  magit-todos--async-when-done(#<process magit-todos--scan-with-git-diff> "finished\n")

I did some debugging, and came across Issue #171, which helped solve this by having me specify the git clone depth to elpaca, (:depth nil). Despite this fix, I still run into this insert-items issue.

I have attempted to create a minimum-reproducible example, and have attached a lockfile alongside it, to make sure others can test it.

Relevant Emacs configuration information (I am using emacs-pgtk from Guix):

GNU Emacs 29.4 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.41, cairo version 1.18.0)
"CONFIG_SHELL=/gnu/store/v9p25q9l5nnaixkhpap5rnymmwbhf9rp-bash-minimal-5.1.16/bin/bash SHELL=/gnu/store/v9p25q9l5nnaixkhpap5rnymmwbhf9rp-bash-minimal-5.1.16/bin/bash --prefix=/gnu/store/pmzlw58r74703schh4b58lm302dm58dr-emacs-pgtk-29.4 --enable-fast-install --with-pgtk --with-cairo --with-modules --with-native-compilation=aot --disable-build-details"

$ guix describe
Generation 37	Jul 23 2024 19:50:16	(current)
  guix d007b64
    repository URL: https://git.savannah.gnu.org/git/guix.git
    branch: master
    commit: d007b64356764f49677c78d82643f1125b5353b7

The MRE init.el and elpaca lockfile are attached as text files (because of GitHub upload reasons).
elpaca.lock.txt
init.el.txt
Elpaca sometimes makes Emacs hang when fetching repository information and updating some of the built-in packages. I don't know why this happens. Try deleting things from elpaca/ until things work. I can confirm that this MRE does build with just emacs --init-directory="$PWD", where this init.el is in $PWD.

@alphapapa
Copy link
Owner

As far as I can tell, you need to follow Nic's comment: #171 (comment) If you are having a problem with Elpaca, you need to talk to the maintainer of Elpaca. I cannot offer support for various Emacs package installers.

@alphapapa alphapapa closed this as not planned Won't fix, can't repro, duplicate, stale Aug 30, 2024
@alphapapa alphapapa added the invalid This doesn't seem right label Aug 30, 2024
@KarlJoad
Copy link
Contributor Author

@alphapapa, I'm sorry, I uploaded an old version of init.el that did not have Nic's changes from #171. I made Nic's suggested change, and the problem still remains.

To further rule out the possibility that elpaca is the problem, I made another init.el using straight.el to manage packages, and I observed the exact same behavior.

To completely remove the possibility of any package manager being the problem I also did this by hand, cloning elpa's recipes, dash, async, f, and all the other packages manually, and I still encounter this issue. This time, I did get a different error, but the same result (an error message printed, but TODOs still showing up in magit-status). The new stacktrace is:

Debugger entered--Lisp error: (wrong-type-argument stringp nil)
  propertize(nil face magit-section-heading)
  (format "%s (%s)%s" (propertize magit-todos-section-heading 'face 'magit-section-heading) num-items reminder)
  (magit-todos--insert-groups :type 'todos :heading (format "%s (%s)%s" (propertize magit-todos-section-heading 'face 'magit-section-heading) num-items reminder) :group-fns group-fns :items items :depth 0)
  (let ((section (magit-todos--insert-groups :type 'todos :heading (format "%s (%s)%s" (propertize magit-todos-section-heading 'face 'magit-section-heading) num-items reminder) :group-fns group-fns :items items :depth 0))) (magit-todos--set-visibility :section section :num-items num-items))
  (if (not items) (if magit-todos-update nil (let ((magit-insert-section--parent magit-root-section)) (let* ((type296 'todos) (section297 (funcall (if ... type296 ...) :type (or ... type296) :value nil :start (point-marker) :parent magit-insert-section--parent))) (eieio-oset section297 'hidden (let ((value ...)) (if value (eq value ...) (let ... ...)))) (let ((magit-insert-section--current section297) (magit-insert-section--parent section297) (magit-insert-section--oldroot (or magit-insert-section--oldroot ...))) (catch 'cancel-section (magit-insert-heading (concat ... " (0)" reminder "\n")) (run-hooks 'magit-insert-section-hook) (magit-insert-child-count section297) (set-marker-insertion-type (eieio-oref section297 ...) t) (let* (... ... ... ... ...) (save-excursion ... ...)) (if (eq section297 magit-root-section) (let ... ...) (eieio-oset ... ... ...))) section297)))) (let ((section (magit-todos--insert-groups :type 'todos :heading (format "%s (%s)%s" (propertize magit-todos-section-heading 'face 'magit-section-heading) num-items reminder) :group-fns group-fns :items items :depth 0))) (magit-todos--set-visibility :section section :num-items num-items)))
  (let* ((group-fns (cond ((eq magit-todos-auto-group-items 'never) 'nil) ((eq magit-todos-auto-group-items 'always) (let nil magit-todos-group-by)) ((integerp magit-todos-auto-group-items) (let nil (if (> num-items magit-todos-auto-group-items) (progn magit-todos-group-by)))) (t (let nil (error "Invalid value for magit-todos-auto-group-items"))))) (magit-todos-show-filenames (not (member 'magit-todos-item-filename group-fns))) (reminder (if magit-todos-update "" " (update manually)"))) (if (not items) (if magit-todos-update nil (let ((magit-insert-section--parent magit-root-section)) (let* ((type296 'todos) (section297 (funcall ... :type ... :value nil :start ... :parent magit-insert-section--parent))) (eieio-oset section297 'hidden (let (...) (if value ... ...))) (let ((magit-insert-section--current section297) (magit-insert-section--parent section297) (magit-insert-section--oldroot ...)) (catch 'cancel-section (magit-insert-heading ...) (run-hooks ...) (magit-insert-child-count section297) (set-marker-insertion-type ... t) (let* ... ...) (if ... ... ...)) section297)))) (let ((section (magit-todos--insert-groups :type 'todos :heading (format "%s (%s)%s" (propertize magit-todos-section-heading ... ...) num-items reminder) :group-fns group-fns :items items :depth 0))) (magit-todos--set-visibility :section section :num-items num-items))))
  (save-excursion (goto-char (point-min)) (goto-char (or (let* ((--cl-var-- magit-todos-insert-after) (section nil) (pos nil) (--cl-var-- t) (--cl-var-- t) --cl-var--) (while (and (consp --cl-var--) (progn (setq section ...) (setq pos ...) (if pos ... t))) (setq --cl-var-- (cdr --cl-var--)) (setq --cl-var-- nil)) --cl-var--) (magit-todos--section-end 'bottom))) (let* ((group-fns (cond ((eq magit-todos-auto-group-items 'never) 'nil) ((eq magit-todos-auto-group-items 'always) (let nil magit-todos-group-by)) ((integerp magit-todos-auto-group-items) (let nil (if ... ...))) (t (let nil (error "Invalid value for magit-todos-auto-group-items"))))) (magit-todos-show-filenames (not (member 'magit-todos-item-filename group-fns))) (reminder (if magit-todos-update "" " (update manually)"))) (if (not items) (if magit-todos-update nil (let ((magit-insert-section--parent magit-root-section)) (let* ((type296 ...) (section297 ...)) (eieio-oset section297 'hidden (let ... ...)) (let (... ... ...) (catch ... ... ... ... ... ... ...) section297)))) (let ((section (magit-todos--insert-groups :type 'todos :heading (format "%s (%s)%s" ... num-items reminder) :group-fns group-fns :items items :depth 0))) (magit-todos--set-visibility :section section :num-items num-items)))))
  (save-current-buffer (set-buffer magit-status-buffer) (if branch-p nil (if magit-todos-updating (progn (if (or (null magit-todos-update) (integerp magit-todos-update)) (progn (setq magit-todos-item-cache items) (setq magit-todos-last-update-time (current-time)))) (setq magit-todos-updating nil)))) (save-excursion (goto-char (point-min)) (goto-char (or (let* ((--cl-var-- magit-todos-insert-after) (section nil) (pos nil) (--cl-var-- t) (--cl-var-- t) --cl-var--) (while (and (consp --cl-var--) (progn ... ... ...)) (setq --cl-var-- (cdr --cl-var--)) (setq --cl-var-- nil)) --cl-var--) (magit-todos--section-end 'bottom))) (let* ((group-fns (cond ((eq magit-todos-auto-group-items ...) 'nil) ((eq magit-todos-auto-group-items ...) (let nil magit-todos-group-by)) ((integerp magit-todos-auto-group-items) (let nil ...)) (t (let nil ...)))) (magit-todos-show-filenames (not (member 'magit-todos-item-filename group-fns))) (reminder (if magit-todos-update "" " (update manually)"))) (if (not items) (if magit-todos-update nil (let ((magit-insert-section--parent magit-root-section)) (let* (... ...) (eieio-oset section297 ... ...) (let ... ... section297)))) (let ((section (magit-todos--insert-groups :type ... :heading ... :group-fns group-fns :items items :depth 0))) (magit-todos--set-visibility :section section :num-items num-items))))))
  (progn (save-current-buffer (set-buffer magit-status-buffer) (if branch-p nil (if magit-todos-updating (progn (if (or (null magit-todos-update) (integerp magit-todos-update)) (progn (setq magit-todos-item-cache items) (setq magit-todos-last-update-time ...))) (setq magit-todos-updating nil)))) (save-excursion (goto-char (point-min)) (goto-char (or (let* ((--cl-var-- magit-todos-insert-after) (section nil) (pos nil) (--cl-var-- t) (--cl-var-- t) --cl-var--) (while (and ... ...) (setq --cl-var-- ...) (setq --cl-var-- nil)) --cl-var--) (magit-todos--section-end 'bottom))) (let* ((group-fns (cond (... ...) (... ...) (... ...) (t ...))) (magit-todos-show-filenames (not (member ... group-fns))) (reminder (if magit-todos-update "" " (update manually)"))) (if (not items) (if magit-todos-update nil (let (...) (let* ... ... ...))) (let ((section ...)) (magit-todos--set-visibility :section section :num-items num-items)))))))
  (if (buffer-live-p magit-status-buffer) (progn (save-current-buffer (set-buffer magit-status-buffer) (if branch-p nil (if magit-todos-updating (progn (if (or ... ...) (progn ... ...)) (setq magit-todos-updating nil)))) (save-excursion (goto-char (point-min)) (goto-char (or (let* (... ... ... ... ... --cl-var--) (while ... ... ...) --cl-var--) (magit-todos--section-end 'bottom))) (let* ((group-fns (cond ... ... ... ...)) (magit-todos-show-filenames (not ...)) (reminder (if magit-todos-update "" " (update manually)"))) (if (not items) (if magit-todos-update nil (let ... ...)) (let (...) (magit-todos--set-visibility :section section :num-items num-items))))))))
  (let* ((items (magit-todos--sort items)) (num-items (length items)) (magit-section-show-child-count t) (magit-insert-section--parent magit-root-section) (inhibit-read-only t)) (if (buffer-live-p magit-status-buffer) (progn (save-current-buffer (set-buffer magit-status-buffer) (if branch-p nil (if magit-todos-updating (progn (if ... ...) (setq magit-todos-updating nil)))) (save-excursion (goto-char (point-min)) (goto-char (or (let* ... ... --cl-var--) (magit-todos--section-end ...))) (let* ((group-fns ...) (magit-todos-show-filenames ...) (reminder ...)) (if (not items) (if magit-todos-update nil ...) (let ... ...))))))))
  (progn (if (not (buffer-live-p magit-status-buffer)) (progn (message "`magit-todos--insert-items-callback': Callback cal..."))) (let* ((items (magit-todos--sort items)) (num-items (length items)) (magit-section-show-child-count t) (magit-insert-section--parent magit-root-section) (inhibit-read-only t)) (if (buffer-live-p magit-status-buffer) (progn (save-current-buffer (set-buffer magit-status-buffer) (if branch-p nil (if magit-todos-updating (progn ... ...))) (save-excursion (goto-char (point-min)) (goto-char (or ... ...)) (let* (... ... ...) (if ... ... ...))))))))
  (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) '(:branch-p :allow-other-keys)) (if (cdr --cl-keys--) nil (error "Missing argument for %s" (car --cl-keys--))) (setq --cl-keys-- (cdr (cdr --cl-keys--)))) ((car (cdr (memq ... --cl-rest--))) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:branch-p)" (car --cl-keys--)))))) (progn (if (not (buffer-live-p magit-status-buffer)) (progn (message "`magit-todos--insert-items-callback': Callback cal..."))) (let* ((items (magit-todos--sort items)) (num-items (length items)) (magit-section-show-child-count t) (magit-insert-section--parent magit-root-section) (inhibit-read-only t)) (if (buffer-live-p magit-status-buffer) (progn (save-current-buffer (set-buffer magit-status-buffer) (if branch-p nil (if magit-todos-updating ...)) (save-excursion (goto-char ...) (goto-char ...) (let* ... ...))))))))
  (let* ((branch-p (car (cdr (plist-member --cl-rest-- ':branch-p))))) (progn (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) '...) (if (cdr --cl-keys--) nil (error "Missing argument for %s" ...)) (setq --cl-keys-- (cdr ...))) ((car (cdr ...)) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:branch-p)" (car --cl-keys--)))))) (progn (if (not (buffer-live-p magit-status-buffer)) (progn (message "`magit-todos--insert-items-callback': Callback cal..."))) (let* ((items (magit-todos--sort items)) (num-items (length items)) (magit-section-show-child-count t) (magit-insert-section--parent magit-root-section) (inhibit-read-only t)) (if (buffer-live-p magit-status-buffer) (progn (save-current-buffer (set-buffer magit-status-buffer) (if branch-p nil ...) (save-excursion ... ... ...))))))))
  magit-todos--insert-items(#<buffer magit: vcode-rocc> (#s(magit-todos-item :filename <edited for clarity> ...) :branch-p t)
  (let ((magit-todos-section-heading heading)) (let* ((v magit-status-buffer) (v items)) (save-current-buffer (set-buffer v) (set (make-local-variable 'magit-todos-branch-item-cache) v))) (magit-todos--insert-items magit-status-buffer items :branch-p t))
  (let ((glob-regexps (mapcar #'wildcard-to-regexp exclude-globs)) items filename file-end hunk-end line-number) (while (re-search-forward "^diff --git " nil t) (while (setq filename (if (re-search-forward "^\\+\\+\\+ b/\\(.+\\)" nil t) (progn (match-string 1)))) (if (and (let (needle) (let (... ... elt) (while ... ... ...)) needle) t) nil (setq file-end (or (save-excursion (if ... ...)) (point-max))) (while (setq line-number (if (re-search-forward "^@@ -[[:digit:]]+\\(?:,[[:digit:]]+\\)?[[:space:]]+\\..." file-end t) (progn ...))) (setq hunk-end (or (save-excursion ...) (point-max))) (while (re-search-forward "^\\+" hunk-end t) (if (re-search-forward search-regexp-elisp ... t) (progn ...)) (setq line-number (1+ line-number))))))) (let ((magit-todos-section-heading heading)) (let* ((v magit-status-buffer) (v items)) (save-current-buffer (set-buffer v) (set (make-local-variable 'magit-todos-branch-item-cache) v))) (magit-todos--insert-items magit-status-buffer items :branch-p t)))
  (save-current-buffer (set-buffer (process-buffer process)) (goto-char (point-min)) (let ((glob-regexps (mapcar #'wildcard-to-regexp exclude-globs)) items filename file-end hunk-end line-number) (while (re-search-forward "^diff --git " nil t) (while (setq filename (if (re-search-forward "^\\+\\+\\+ b/\\(.+\\)" nil t) (progn (match-string 1)))) (if (and (let (needle) (let ... ...) needle) t) nil (setq file-end (or (save-excursion ...) (point-max))) (while (setq line-number (if ... ...)) (setq hunk-end (or ... ...)) (while (re-search-forward "^\\+" hunk-end t) (if ... ...) (setq line-number ...)))))) (let ((magit-todos-section-heading heading)) (let* ((v magit-status-buffer) (v items)) (save-current-buffer (set-buffer v) (set (make-local-variable 'magit-todos-branch-item-cache) v))) (magit-todos--insert-items magit-status-buffer items :branch-p t))))
  (let* ((magit-status-buffer (car (cdr (plist-member --cl-rest-- ':magit-status-buffer)))) (results-regexp (car (cdr (plist-member --cl-rest-- ':results-regexp)))) (search-regexp-elisp (car (cdr (plist-member --cl-rest-- ':search-regexp-elisp)))) (process (car (cdr (plist-member --cl-rest-- ':process)))) (heading (car (cdr (plist-member --cl-rest-- ':heading)))) (exclude-globs (car (cdr (plist-member --cl-rest-- ':exclude-globs))))) (save-current-buffer (set-buffer (process-buffer process)) (goto-char (point-min)) (let ((glob-regexps (mapcar #'wildcard-to-regexp exclude-globs)) items filename file-end hunk-end line-number) (while (re-search-forward "^diff --git " nil t) (while (setq filename (if (re-search-forward "^\\+\\+\\+ b/\\(.+\\)" nil t) (progn ...))) (if (and (let ... ... needle) t) nil (setq file-end (or ... ...)) (while (setq line-number ...) (setq hunk-end ...) (while ... ... ...))))) (let ((magit-todos-section-heading heading)) (let* ((v magit-status-buffer) (v items)) (save-current-buffer (set-buffer v) (set (make-local-variable ...) v))) (magit-todos--insert-items magit-status-buffer items :branch-p t)))))
  magit-todos--git-diff-callback(:callback magit-todos--insert-items :magit-status-buffer #<buffer magit: vcode-rocc> :results-regexp "\\(?:^\\(?8:[^:]+\\):\\(?2:[[:digit:]]+\\):\\(?:\\(?1:\\*+..." :search-regexp-elisp "\\(?:^\\(\\*+\\)[[:blank:]]+\\(\\(?:DONT\\|F\\(?:AIL\\|IXME..." :heading nil :exclude-globs (".git/") :process #<process magit-todos--scan-with-git-diff>)
  apply(magit-todos--git-diff-callback (:callback magit-todos--insert-items :magit-status-buffer #<buffer magit: vcode-rocc> :results-regexp "\\(?:^\\(?8:[^:]+\\):\\(?2:[[:digit:]]+\\):\\(?:\\(?1:\\*+..." :search-regexp-elisp "\\(?:^\\(\\*+\\)[[:blank:]]+\\(\\(?:DONT\\|F\\(?:AIL\\|IXME..." :heading nil :exclude-globs (".git/") :process #<process magit-todos--scan-with-git-diff>))
  #f(compiled-function (&rest args2) #<bytecode 0x1ee24515b69e0fe3>)(#<process magit-todos--scan-with-git-diff>)
  funcall(#f(compiled-function (&rest args2) #<bytecode 0x1ee24515b69e0fe3>) #<process magit-todos--scan-with-git-diff>)
  (prog1 (funcall async-callback proc) (if async-debug nil (kill-buffer (current-buffer))))
  (if async-callback (prog1 (funcall async-callback proc) (if async-debug nil (kill-buffer (current-buffer)))) (set (make-local-variable 'async-callback-value) proc) (set (make-local-variable 'async-callback-value-set) t))
  (if async-callback-for-process (if async-callback (prog1 (funcall async-callback proc) (if async-debug nil (kill-buffer (current-buffer)))) (set (make-local-variable 'async-callback-value) proc) (set (make-local-variable 'async-callback-value-set) t)) (goto-char (point-max)) (backward-sexp) (async-handle-result async-callback (read (current-buffer)) (current-buffer)))
  (if (memq (process-exit-status proc) (process-get proc :allow-exit-codes)) (if async-callback-for-process (if async-callback (prog1 (funcall async-callback proc) (if async-debug nil (kill-buffer (current-buffer)))) (set (make-local-variable 'async-callback-value) proc) (set (make-local-variable 'async-callback-value-set) t)) (goto-char (point-max)) (backward-sexp) (async-handle-result async-callback (read (current-buffer)) (current-buffer))) (error "magit-todos--async-when-done: Process %S failed wi..." (process-name proc) (process-exit-status proc) (buffer-string)))
  (let ((async-current-process proc)) (if (memq (process-exit-status proc) (process-get proc :allow-exit-codes)) (if async-callback-for-process (if async-callback (prog1 (funcall async-callback proc) (if async-debug nil (kill-buffer (current-buffer)))) (set (make-local-variable 'async-callback-value) proc) (set (make-local-variable 'async-callback-value-set) t)) (goto-char (point-max)) (backward-sexp) (async-handle-result async-callback (read (current-buffer)) (current-buffer))) (error "magit-todos--async-when-done: Process %S failed wi..." (process-name proc) (process-exit-status proc) (buffer-string))))
  (save-current-buffer (set-buffer (process-buffer proc)) (let ((async-current-process proc)) (if (memq (process-exit-status proc) (process-get proc :allow-exit-codes)) (if async-callback-for-process (if async-callback (prog1 (funcall async-callback proc) (if async-debug nil (kill-buffer ...))) (set (make-local-variable 'async-callback-value) proc) (set (make-local-variable 'async-callback-value-set) t)) (goto-char (point-max)) (backward-sexp) (async-handle-result async-callback (read (current-buffer)) (current-buffer))) (error "magit-todos--async-when-done: Process %S failed wi..." (process-name proc) (process-exit-status proc) (buffer-string)))))
  (progn (save-current-buffer (set-buffer (process-buffer proc)) (let ((async-current-process proc)) (if (memq (process-exit-status proc) (process-get proc :allow-exit-codes)) (if async-callback-for-process (if async-callback (prog1 (funcall async-callback proc) (if async-debug nil ...)) (set (make-local-variable ...) proc) (set (make-local-variable ...) t)) (goto-char (point-max)) (backward-sexp) (async-handle-result async-callback (read (current-buffer)) (current-buffer))) (error "magit-todos--async-when-done: Process %S failed wi..." (process-name proc) (process-exit-status proc) (buffer-string))))))
  (if (and (memq (process-status proc) '(exit signal)) (buffer-live-p (process-buffer proc))) (progn (save-current-buffer (set-buffer (process-buffer proc)) (let ((async-current-process proc)) (if (memq (process-exit-status proc) (process-get proc :allow-exit-codes)) (if async-callback-for-process (if async-callback (prog1 ... ...) (set ... proc) (set ... t)) (goto-char (point-max)) (backward-sexp) (async-handle-result async-callback (read ...) (current-buffer))) (error "magit-todos--async-when-done: Process %S failed wi..." (process-name proc) (process-exit-status proc) (buffer-string)))))))
  magit-todos--async-when-done(#<process magit-todos--scan-with-git-diff> "finished\n")

@alphapapa
Copy link
Owner

As you can see from the git log, this package has not changed in months. It is known to work correctly, including the branch scanner.

To further rule out the possibility that elpaca is the problem, I made another init.el using straight.el to manage packages, and I observed the exact same behavior.

I cannot offer support for Straight, either.

To completely remove the possibility of any package manager being the problem I also did this by hand, cloning elpa's recipes, dash, async, f, and all the other packages manually, and I still encounter this issue.

That would be the least advisable way to install the package. Have you considered M-x package-install, the standard way? I would suggest using https://github.com/alphapapa/with-emacs.sh to do so in a clean configuration. If with-emacs.sh -i magit-todos produces the same error, then you may have found a bug.

@alphapapa
Copy link
Owner

I just ran with-emacs.sh -i magit-todos and enabled magit-todos-mode and tested both the main and branch scanners. They work fine, no errors.

@KarlJoad
Copy link
Contributor Author

That would be the least advisable way to install the package. Have you considered M-x package-install, the standard way? I would suggest using https://github.com/alphapapa/with-emacs.sh to do so in a clean configuration. If with-emacs.sh -i magit-todos produces the same error, then you may have found a bug.

I agree. That really was the worst way to do it, but it was the fastest way I could think of to create a package-manager-free environment.

I just ran with-emacs.sh -i magit-todos and enabled magit-todos-mode and tested both the main and branch scanners. They work fine, no errors.

I tried this exact same thing, and I still get the error. My sequence of events is:

./with-emacs.sh -i magit-todos
M-x magit-todos-mode
C-u M-x magit-status <RET> path/to/repo <RET>

If I do M-x toggle-debug-on-error before executing magit-status, this is the stack trace I get:

Debugger entered--Lisp error: (wrong-type-argument stringp nil)
  propertize(nil face magit-section-heading)
  magit-todos--insert-items(#<buffer magit: vcode-rocc> (#s(magit-todos-item :filename ...) ...) :branch-p t)
  magit-todos--git-diff-callback(:callback magit-todos--insert-items :magit-status-buffer #<buffer magit: vcode-rocc> :results-regexp "\\(?:^\\(?8:[^:]+\\):\\(?2:[[:digit:]]+\\):\\(?:\\(?1:\\*+..." :search-regexp-elisp "\\(?:^\\(\\*+\\)[[:blank:]]+\\(\\(?:DONT\\|F\\(?:AIL\\|IXME..." :heading nil :exclude-globs (".git/") :process #<process magit-todos--scan-with-git-diff>)
  apply(magit-todos--git-diff-callback (:callback magit-todos--insert-items :magit-status-buffer #<buffer magit: vcode-rocc> :results-regexp "\\(?:^\\(?8:[^:]+\\):\\(?2:[[:digit:]]+\\):\\(?:\\(?1:\\*+..." :search-regexp-elisp "\\(?:^\\(\\*+\\)[[:blank:]]+\\(\\(?:DONT\\|F\\(?:AIL\\|IXME..." :heading nil :exclude-globs (".git/") :process #<process magit-todos--scan-with-git-diff>))
  #f(compiled-function (&rest args2) #<bytecode 0xd6bb2c2489a95d3>)(#<process magit-todos--scan-with-git-diff>)
  magit-todos--async-when-done(#<process magit-todos--scan-with-git-diff> "finished\n")
  sit-for(2)
  #f(compiled-function () #<bytecode 0x19a11732df78aa1e>)()
  apply(#f(compiled-function () #<bytecode 0x19a11732df78aa1e>) nil)
  timer-event-handler([t 26322 35617 833867 nil #f(compiled-function () #<bytecode 0x19a11732df78aa1e>) nil nil 395000 nil])

@KarlJoad
Copy link
Contributor Author

KarlJoad commented Aug 31, 2024

If I execute M-x debug-on-variable-change <RET> magit-todos-section-heading <RET> while using ./with-emacs.sh -i magit-todos, then I can see all changes made to this variable during execution. There are two events when I refresh the magit-status buffer (magit-refresh).

The first:

Debugger entered--let-binding magit-todos-section-heading to "TODOs (branched from master)": 
  debug--implement-debug-watch(magit-todos-section-heading "TODOs (branched from master)" let nil)
  magit-todos--git-diff-callback(:callback nil :magit-status-buffer #<buffer magit: vcode-rocc> :results-regexp "\\(?:^\\(?8:[^:]+\\):\\(?2:[[:digit:]]+\\):\\(?:\\(?1:\\*+..." :search-regexp-elisp "\\(?:^\\(\\*+\\)[[:blank:]]+\\(\\(?:DONT\\|F\\(?:AIL\\|IXME..." :heading "TODOs (branched from master)" :exclude-globs (".git/") :process #<process magit-todos--scan-with-git-diff<1>>)
  apply(magit-todos--git-diff-callback (:callback nil :magit-status-buffer #<buffer magit: vcode-rocc> :results-regexp "\\(?:^\\(?8:[^:]+\\):\\(?2:[[:digit:]]+\\):\\(?:\\(?1:\\*+..." :search-regexp-elisp "\\(?:^\\(\\*+\\)[[:blank:]]+\\(\\(?:DONT\\|F\\(?:AIL\\|IXME..." :heading "TODOs (branched from master)" :exclude-globs (".git/") :process #<process magit-todos--scan-with-git-diff<1>>))
  #f(compiled-function (&rest args2) #<bytecode 0x15e639c2489a95de>)(#<process magit-todos--scan-with-git-diff<1>>)
  magit-todos--async-when-done(#<process magit-todos--scan-with-git-diff<1>> "finished\n")

The second event, which is the one that sets magit-todos-section-heading to nil and eventually causes the error:

Debugger entered--let-binding magit-todos-section-heading to nil: 
  debug--implement-debug-watch(magit-todos-section-heading nil let nil)
  magit-todos--git-diff-callback(:callback magit-todos--insert-items :magit-status-buffer #<buffer magit: vcode-rocc> :results-regexp "\\(?:^\\(?8:[^:]+\\):\\(?2:[[:digit:]]+\\):\\(?:\\(?1:\\*+..." :search-regexp-elisp "\\(?:^\\(\\*+\\)[[:blank:]]+\\(\\(?:DONT\\|F\\(?:AIL\\|IXME..." :heading nil :exclude-globs (".git/") :process #<process magit-todos--scan-with-git-diff>)
  apply(magit-todos--git-diff-callback (:callback magit-todos--insert-items :magit-status-buffer #<buffer magit: vcode-rocc> :results-regexp "\\(?:^\\(?8:[^:]+\\):\\(?2:[[:digit:]]+\\):\\(?:\\(?1:\\*+..." :search-regexp-elisp "\\(?:^\\(\\*+\\)[[:blank:]]+\\(\\(?:DONT\\|F\\(?:AIL\\|IXME..." :heading nil :exclude-globs (".git/") :process #<process magit-todos--scan-with-git-diff>))
  #f(compiled-function (&rest args2) #<bytecode 0xd6bb2c2489a95d3>)(#<process magit-todos--scan-with-git-diff>)
  magit-todos--async-when-done(#<process magit-todos--scan-with-git-diff> "finished\n")

@KarlJoad
Copy link
Contributor Author

KarlJoad commented Aug 31, 2024

It seems that the repository I have been testing against causes 2 magit-todo operations to happen, one with the heading TODOs (branched from master) and the other with an :heading set to nil.

I made a small modification to the magit-todos-defscanner macro, and seem to have fixed my problem by providing a default value for :heading if the callback does not provide a heading to use.

diff --git a/magit-todos.el b/magit-todos.el
index dd30488..9978e9f 100644
--- a/magit-todos.el
+++ b/magit-todos.el
@@ -1266,7 +1266,7 @@ It also adds the scanner to the customization variable
        ;; NOTE: Both the macro and the macro-defined function have `callback' arguments.  Pay attention to unquoting.
        ;; FIXME: That is confusing.

-       (cl-defun ,scan-fn-symbol (&key magit-status-buffer directory depth heading sync callback)
+       (cl-defun ,scan-fn-symbol (&key magit-status-buffer directory depth (heading magit-todos-section-heading) sync callback)
          ,(format "Scan for to-dos with %s.
 Then calls CALLBACK.  MAGIT-STATUS-BUFFER is what it says.  DIRECTORY
 is the directory in which to run the scan.  DEPTH should be an

Now when git diff scans are requested by magit-todos, if :heading is not provided, it will use magit-todos' default section heading. Though this does have a problem where there are now two sections with TODOs in them.

@KarlJoad
Copy link
Contributor Author

I tested this patch with the ./with-emacs.sh -i magit-todos version of Emacs by modifying the downloaded magit-todos.el file, then calling eval-buffer on it. This completely removed the error message. Though the duplicated magit-status section headers still happen.

@alphapapa
Copy link
Owner

C-u M-x magit-status path/to/repo

Why are you calling magit-status with a prefix argument?

@KarlJoad
Copy link
Contributor Author

C-u M-x magit-status path/to/repo

Why are you calling magit-status with a prefix argument?

I cloned the with-emacs.sh repository and am executing ./with-emacs.sh -i magit-todos from inside of there. The default behavior of magit-status is to find the repository of the buffer's default-directory, which would end up opening with-emacs.sh in magit-status, rather than the repository I have been using for testing.

@alphapapa
Copy link
Owner

I made a small modification to the magit-todos-defscanner macro, and seem to have fixed my problem by providing a default value for :heading if the callback does not provide a heading to use.

I can't see any way in the source code for that argument to have a nil value at runtime. Have you tried it on any other git repo?

@KarlJoad
Copy link
Contributor Author

Every other repo I try on never gets magit-todos populating in the magit-status buffer, even though I can see the TODO comments.

For example:

examples/ideal.chil
44:    ;; TODO: What should we do about function objects?

But the magit-status buffer does not show this TODO, nor any other in that repository.

In fact, the repository with weird behavior that I have been testing with is the only one where I can get magit-todos to show up at all (in the magit-status buffer as a section or as its own standalone list).

@alphapapa
Copy link
Owner

Something seems to be wrong. I can't imagine what it could be. Everything works fine for me and thousands of other users.

@alphapapa
Copy link
Owner

My best guess is that, since you're using Guix, something weird is going on in the environment. I'd suggest trying the Guix-packaged version of magit-todos. If that still doesn't work, then I don't know what else to suggest.

OTOH, I use Guix on top of Debian, and have Emacs installed through Guix (though with a package definition that allows Emacs to native-compile packages installed outside of Guix, since Guix's default forbids it now), and everything works fine.

@KarlJoad
Copy link
Contributor Author

You're right. My Guix was the differing factor. I do not have ripgrep installed in my standard user environment. I only have Guix's default GNU Grep, coming from the system's %base-packages. If I add ripgrep with guix shell and then do the same steps as before, everything works perfectly without error.

The problem actually comes down to Guix not providing a GNU Grep with PCRE support by default.
You can reproduce this fact with the following:

$ guix shell grep --pure
[env] $ grep -P '[[:alnum:]]'
grep: Perl matching not supported in a --disable-perl-regexp build

Oddly enough, git grep supports PCRE by default on Guix. You must be in a repository for the snippet below to work.

$ guix shell git --pure
[env] $ git grep -P '[[:alnum:]]'
A whole lot of output.

I don't understand why I was seeing an error from magit-todos--git-diff-callback, which is from git-diff and never ends up calling grep, but that is a non-issue. I can just add ripgrep to my environment.

@alphapapa
Copy link
Owner

I don't understand why I was seeing an error from magit-todos--git-diff-callback, which is from git-diff and never ends up calling grep,

Me neither. I wonder what the value of magit-todos-scanner was being set to. Apparently it should have gotten set to the git-grep scanner in your environment, which should have worked.

@alphapapa alphapapa changed the title magit-todos--insert-items and Elpaca still failing? Error on Guix without ripgrep installed Aug 31, 2024
@KarlJoad
Copy link
Contributor Author

I was curious about the same thing, and figured out the problem was that git grep does not have --perl-regexp printed by git-grep's help string. magit-todos uses the deliberately incorrect command git grep --magit-todos-testing-git-grep to invoke git grep -h. On my system (Git 2.45.2), the portion of the help output relevant to the string-match in the git grep scanner's :test is:

$ git grep --magit-todos-testing-git-grep
error: unknown option `magit-todos-testing-git-grep'
usage: git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]
...
    -E, --[no-]extended-regexp
                          use extended POSIX regular expressions
    -G, --[no-]basic-regexp
                          use basic POSIX regular expressions (default)
    -F, --[no-]fixed-strings
                          interpret patterns as fixed strings
    -P, --[no-]perl-regexp
                          use Perl-compatible regular expressions
...

The test always returns nil, because the string being matched against "--perl-regexp" does not have any regexps in it, it can never match against git-grep's help output.

(string-match "--perl-regexp" (shell-command-to-string "git grep --magit-todos-testing-git-grep"))
nil

@KarlJoad
Copy link
Contributor Author

To further complicate this, the help message includes information about --perl-regexp regardless of whether or not git was actually compiled with PCRE2 support, meaning this test does not actually check if PCRE2 support is available in git-grep.

I have been writing an alternative :test function, which seems to exhibit the behavior we want.

(magit-todos-defscanner "git grep"
  ;; This test is evaluated at Emacs start! To allow the git grep :test to work
  ;; regardless of whether or not Emacs was started inside of a Git repository,
  ;; we use --no-index and - (STDIN). --no-index makes "git grep" behave like
  ;; "grep -r". We then use - as the input (STDIN) so that we do not rely on
  ;; specifying any actual files.
  ;; git-grep exits this test with 128 if PCRE is not supported.
  :test (>= 1 (call-process-shell-command "git grep --no-index --quiet --perl-regexp '\\d' -- -"))
  :test (not (string-match "fatal" (shell-command-to-string "git grep --no-index --quiet --perl-regexp '\\d' -- -")))
  ;; Rest of defscanner is unchanged.
...

Both :tests achieve the same behavior, but the first one relies on exit code value and the second relies on the string printed when git is not compiled with PCRE2 support.

When Git is compiled without PCRE2 support, the test prints out the following:

$ /tmp/git/build/bin/git grep --no-index --quiet --perl-regexp '\d' -- -
fatal: cannot use Perl-compatible regexes when not compiled with USE_LIBPCRE

$ echo $?
128

If you use a Git that is compiled with PCRE2 support, this is the output of the same test:

$ git grep --no-index --quiet --perl-regexp '\d' -- -

$ echo $?
1

@KarlJoad
Copy link
Contributor Author

When I use either of those :tests, this is what I see.

PCRE2-enabled Git:

$ emacs
M-: magit-todos-scanner
magit-todos--scan-with-git-grep

# Repositories work as expected and no errors occur

Git without PCRE2

PATH="$(realpath /tmp/git/build/)/bin":$PATH emacs
M-: magit-todos-scanner
magit-todos--scan-with-git-diff

# Repositories work as described earlier in this Issue thread.

I also tested this change with with-emacs.sh -i magit-todos, editing magit-todos.el once Emacs loaded, and re-evaluating the file. The correct behavior happens (TODOs printed) and no errors raised at all.

@KarlJoad
Copy link
Contributor Author

I think tracked down the issue with the git-diff scanner raising an error too. heading is just never provided to magit-todos--scan-with-git-diff when magit-todos-scanner is magit-todos--scan-with-git-diff.

magit-todos/magit-todos.el

Lines 748 to 752 in 501c8db

(setq magit-todos-active-scan (funcall magit-todos-scanner
:callback #'magit-todos--insert-items
:magit-status-buffer (current-buffer)
:directory default-directory
:depth magit-todos-depth))

(pp-macroexpand-expression '(magit-todos-defscanner "git diff"
		;; NOTE: This scanner implements the regexp *searching* in elisp rather than in the
		;; external process because, unlike "git grep", "git diff" does not support PCRE.
		:test t
		:command (progn
			   ;; Silence byte-compiler warnings about these vars we don't use in this scanner.
			   (ignore search-regexp-elisp search-regexp-pcre extra-args directory depth)
			   (let ((merge-base-ref (-> "git merge-base HEAD "
						     (concat (or magit-todos-branch-list-merge-base-ref (magit-main-branch)))
						     shell-command-to-string
						     string-trim)))
			     (unless (string-empty-p merge-base-ref)
			       (list "git" "--no-pager" "diff" "--no-color" "-U0" merge-base-ref))))
		:callback 'magit-todos--git-diff-callback))

(progn
  (defcustom magit-todos-git-diff-extra-args nil "Extra arguments passed to git diff." :type
    '(repeat string))
  (cl-defun magit-todos--scan-with-git-diff
      (&key magit-status-buffer directory depth heading sync callback)
    "Scan for to-dos with git-diff.\nThen calls CALLBACK.  MAGIT-STATUS-BUFFER is what it says.  DIRECTORY\nis the directory in which to run the scan.  DEPTH should be an\ninteger, typically the value of `magit-todos-depth'.  HEADING is\npassed to CALLBACK.\n\nWhen SYNC is nil, the scanner process is returned, and CALLBACK\nis a function which is called by the process sentinel with one\nargument, a list of match items.\n\nWhen SYNC is non-nil, match items are returned."
    (let*
	((process-connection-type 'pipe)
	 (directory
	  (f-relative directory default-directory))
	 (extra-args
	  (when magit-todos-git-diff-extra-args
	    (--map
	     (s-split
	      (rx
	       (1+ space))
	      it 'omit-nulls)
	     magit-todos-git-diff-extra-args)))
	 (keywords magit-todos-keywords-list)
	 (search-regexp-elisp
	  (rx-to-string
	   `(or
	     (seq bol
		  (group
		   (1+ "*"))
		  (1+ blank)
		  (group
		   (or ,@keywords))
		  (1+ space)
		  (group
		   (1+ not-newline)))
	     (seq
	      (or bol
		  (1+ blank))
	      (group
	       (or ,@keywords))
	      (regexp ,magit-todos-keyword-suffix)
	      (optional
	       (1+ blank)
	       (group
		(1+ not-newline)))))))
	 (search-regexp-pcre
	  (rxt-elisp-to-pcre search-regexp-elisp))
	 (results-regexp
	  (or nil
	      (rx-to-string
	       `(seq bol
		     (group-n 8
		       (1+
			(not
			 (any ":"))))
		     ":"
		     (group-n 2
		       (1+ digit))
		     ":"
		     (or
		      (seq
		       (group-n 1
			 (1+ "*"))
		       (1+ blank)
		       (group-n 4
			 (or ,@keywords))
		       (1+ blank)
		       (group-n 5
			 (1+ not-newline)))
		      (seq
		       (optional
			(1+ not-newline))
		       (group-n 4
			 (or ,@keywords))
		       (optional
			(group-n 6
			  (regexp ,magit-todos-keyword-suffix)))
		       (optional
			(1+ blank))
		       (optional
			(group-n 5
			  (1+ not-newline)))))))))
	 (command
	  (-flatten
	   (-non-nil
	    (progn
	      (ignore search-regexp-elisp search-regexp-pcre extra-args directory depth)
	      (let
		  ((merge-base-ref
		    (-> "git merge-base HEAD "
			(concat
			 (or magit-todos-branch-list-merge-base-ref
			     (magit-main-branch)))
			shell-command-to-string string-trim)))
		(unless
		    (string-empty-p merge-base-ref)
		  (list "git" "--no-pager" "diff" "--no-color" "-U0" merge-base-ref))))))))
      (cl-loop for elt in-ref command when
	       (numberp elt)
	       do
	       (setf elt
		     (number-to-string elt)))
      (when command
	(when magit-todos-nice
	  (setf command
		(append
		 (list "nice" "-n5")
		 command)))
	(if sync
	    (with-temp-buffer
	      (unless
		  (member
		   (apply #'call-process
			  (car command)
			  nil
			  (current-buffer)
			  nil
			  (cdr command))
		   '(9))
		(user-error
		 (concat
		  (car command)
		  " failed")))
	      (magit-todos--buffer-items results-regexp))
	  (let
	      ((process
		(magit-todos--async-start-process "magit-todos--scan-with-git-diff" :command command :finish-func
		  (apply-partially 'magit-todos--git-diff-callback :callback callback :magit-status-buffer magit-status-buffer :results-regexp results-regexp :search-regexp-elisp search-regexp-elisp :heading heading :exclude-globs magit-todos-exclude-globs :process))))
	    (setf
	     (process-get process :allow-exit-codes)
	     '(9))
	    process)))))
  (magit-todos--add-to-custom-type 'magit-todos-scanner
    (list 'const :tag "git diff" #'magit-todos--scan-with-git-diff))
  (add-to-list 'magit-todos-scanners
	       (list
		(cons 'name "git diff")
		(cons 'function #'magit-todos--scan-with-git-diff)
		(cons 'test 't))
	       'append))

This nil value for heading then propagates to magit-todos--git-diff-callbackthrough the apply-partially.

If we add a default value for heading to magit-todos--git-diff-callback, then the error goes away.

@alphapapa
Copy link
Owner

alphapapa commented Aug 31, 2024

magit-todos uses the deliberately incorrect command git grep --magit-todos-testing-git-grep to invoke git grep -h.

It does so because git grep does not offer a help option for -h nor --help:

usage: git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]

    -h                    don't show filenames

To further complicate this, the help message includes information about --perl-regexp regardless of whether or not git was actually compiled with PCRE2 support, meaning this test does not actually check if PCRE2 support is available in git-grep.

This means that git grep has changed its usage output. On my system I have git 2.30.2, and the usage output contains:

    -P, --perl-regexp     use Perl-compatible regular expressions

So we need to update the test expression, but it needs to work for both the old and new usage output.

Git without PCRE2


PATH="$(realpath /tmp/git/build/)/bin":$PATH emacs
M-: magit-todos-scanner
magit-todos--scan-with-git-diff
 
# Repositories work as described earlier in this Issue thread.

This is the bug, then, that you discovered: because that scanner's test expression is always non-nil, it (incorrectly) functions as a fallback, but it's only intended to work for scanning branch diffs, not as a main scanner function. Because of that, the warning that should be displayed when no compatible scanner is found is never displayed, and the branch scanner function is called without the expected heading argument.

@alphapapa alphapapa reopened this Aug 31, 2024
@alphapapa alphapapa changed the title Error on Guix without ripgrep installed Branch scanner incorrectly serves as fallback scanner Aug 31, 2024
@alphapapa alphapapa self-assigned this Aug 31, 2024
@alphapapa alphapapa added bug Something isn't working and removed invalid This doesn't seem right labels Aug 31, 2024
@alphapapa alphapapa added this to the 1.8 milestone Aug 31, 2024
@KarlJoad
Copy link
Contributor Author

I have git 2.30.2

I just recompiled your version of Git without PCRE2 and this is what I see:

$ /tmp/git/build/bin/git --version
git version 2.30.2

$ /tmp/git/build/bin/git grep --no-index --quiet --perl-regexp '\d' -- -
fatal: cannot use Perl-compatible regexes when not compiled with USE_LIBPCRE

$ echo $?
128

Git 2.30.2 with PCRE2 is:

$ /tmp/git/build/bin/git --version
git version 2.30.2

$ /tmp/git/build/bin/git grep --no-index --quiet --perl-regexp '\d' -- -

$ echo $?
1

So I think the test should be backwards compatible.

This is the bug, then, that you discovered: because that scanner's test expression is always non-nil, it (incorrectly) functions as a fallback, but it's only intended to work for scanning branch diffs, not as a main scanner function. Because of that, the warning that should be displayed when no compatible scanner is found is never displayed, and the branch scanner function is called without the expected heading argument.

Because the git-grep scanner's test is always nil, magit-todos falls back to the git-diff scanner, because the git-diff scanner's test is unconditionally t, yes.

KarlJoad added a commit to KarlJoad/Emacs_dotfiles that referenced this issue Sep 1, 2024
I discovered a bug that appears in magit-todos when Git upgraded their
"help" output. See [1] for the discussion where the problem was
identified.
See [2] for the PR that needs to be merged into upstream before I can
switch my configuration back to upstream's.

[1] alphapapa/magit-todos#186
[2] alphapapa/magit-todos#188
alphapapa added a commit that referenced this issue Sep 9, 2024
See #186.

Reported-by: Karl Hallsby <karl@hallsby.com>
@alphapapa
Copy link
Owner

This should be fixed now. Will wait a week or two before tagging v1.8. Thanks for your help, @KarlJoad.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants