universal-ctags / citre

A superior code reading & auto-completion tool with pluggable backends.
GNU General Public License v3.0
320 stars 26 forks source link

error: Backend nil not exist in TABLE #139

Closed masatake closed 1 year ago

masatake commented 1 year ago

During reading linux kernel with the latest Citre, I got the following error. I have just updated Citre today from its git repo. I'm using ctags backend.

Debugger entered--Lisp error: (error "Backend nil not exist in TABLE")
  error("Backend %s not exist in TABLE" nil)
  citre--get-prop-of-backend(nil get-definitions-for-id-func #<hash-table eq 2/5 0xe48c69>)
  citre-get-definitions-of-id("sysfs_ops" nil)
  #f(compiled-function (backend symbol) "Method for xref to find definitions of SYMBOL." #<bytecode 0x1897647af82eab42>)(citre "sysfs_ops")
  apply(#f(compiled-function (backend symbol) "Method for xref to find definitions of SYMBOL." #<bytecode 0x1897647af82eab42>) citre "sysfs_ops")
  xref-backend-definitions(citre "sysfs_ops")
  #f(compiled-function () #<bytecode -0x11f03db115960528>)()
  xref-show-definitions-buffer(#f(compiled-function () #<bytecode -0x11f03db115960528>) ((window . #<window 23 on sysfs.rst>) (display-action) (auto-jump)))
  xref--show-defs(#f(compiled-function () #<bytecode -0x11f03db115960528>) nil)
  xref--find-definitions("sysfs_ops" nil)
  xref-find-definitions("sysfs_ops")
  funcall-interactively(xref-find-definitions "sysfs_ops")
  command-execute(xref-find-definitions)
AmaiKinono commented 1 year ago

This one is hard.

Xref get the identifier from xref-backend-identifier-completion-table, then pass it to xref-definitions to find the definition.

Since Citre tries different backends in turn, and "list of identifiers" and "the definition of an identifier in the list" should be provided by the same backend, we want to encode the backend in use in the identifier, so xref-definitions could see it. The only way to encode additional information in a string is using text properties.

But when getting the identifier, xref uses completing-read, see xref--read-identifier, which removes the text properties. This breaks our plan.

AmaiKinono commented 1 year ago

This is a rather dirty fix:

diff --git a/citre.el b/citre.el
index c4b7d45..ecd33ac 100644
--- a/citre.el
+++ b/citre.el
@@ -364,6 +364,8 @@ is a valid return value of `completion-at-point-functions'."
 (declare-function xref-make "xref" (summary location))
 (declare-function xref-make-file-location "xref" (file line column))

+(defvar-local citre--recent-xref-identifier-table-backend nil)
+
 ;; NOTE: In the worst situation, this will create and kill a temporary buffer
 ;; when processing every tag.  If we get bug report on the performance, we
 ;; could use the temp buffer technique in citre-peek, so we only need to do
@@ -439,6 +441,9 @@ The returned value is a valid return value for
     (let* ((result (with-selected-window (or (minibuffer-selected-window)
                                              (selected-window))
                      (citre-get-backend-and-id-list))))
+      (with-selected-window (or (minibuffer-selected-window)
+                                (selected-window))
+        (setq citre--recent-xref-identifier-table-backend (car result)))
       (complete-with-action action (cdr result) str pred))))

 (cl-defmethod xref-backend-definitions ((_backend (eql 'citre)) symbol)
@@ -449,7 +454,7 @@ The returned value is a valid return value for
       (with-current-buffer buf
         (citre-xref--make-collection (citre-get-definitions)))
     (let ((defs (citre-get-definitions-of-id
-                 symbol (citre-get-property 'backend symbol))))
+                 symbol citre--recent-xref-identifier-table-backend)))
       (citre-xref--make-collection defs))))

 (cl-defmethod xref-backend-references ((_backend (eql 'citre)) symbol)

We have to do this if there's no better way.

masatake commented 1 year ago

It seems that this bug makes citre completely unuseful. Under what kinds of conditions does this issue reproduce? I did M-. in a buffer in rst mode.

AmaiKinono commented 1 year ago

Pressing M-. when the cursor is not on a symbol should reproduce this, and should work fine when the cursor is on a symbol.

masatake commented 1 year ago

Oh, I see. I remembered that C-u M-. caused the error. Now it is understandable.

masatake commented 1 year ago
DEFUN ("completing-read", Fcompleting_read, Scompleting_read, 2, 8, 0,
       doc: /* Read a string in the minibuffer, with completion.
PROMPT is a string to prompt with; normally it ends in a colon and a space.
COLLECTION can be a list of strings, an alist, an obarray or a hash table.
...
  (Lisp_Object prompt, Lisp_Object collection, Lisp_Object predicate, Lisp_Object require_match, Lisp_Object initial_input, Lisp_Object hist, Lisp_Object def, Lisp_Object inherit_input_method)
{
  return CALLN (Ffuncall,
        Fsymbol_value (intern ("completing-read-function")),
        prompt, collection, predicate, require_match, initial_input,
        hist, def, inherit_input_method);
}

Doesn't hijacking completing-read-function help us?

  DEFVAR_BOOL ("minibuffer-allow-text-properties",
           minibuffer_allow_text_properties,
...
AmaiKinono commented 1 year ago

Should be fixed, please test.

I did it by fixing the contract of backends, see the change of citre-backend-interface.el in https://github.com/universal-ctags/citre/commit/bf0ff61e143f6002cb223a0c8dfb1439e256b1a1.

masatake commented 1 year ago

It works fine. Thank you.