From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Visuwesh Newsgroups: gmane.emacs.bugs Subject: bug#28407: 26.0.50; xref should use imenu Date: Mon, 16 May 2022 12:29:58 +0530 Message-ID: <87zgjic68h.fsf@gmail.com> References: <87h8wa8quw.fsf@bapiya> <3238a206-240a-aa76-87c0-bcb3bdfa00dc@yandex.ru> <87y1z35630.fsf@gmail.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="14192"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) Cc: Tom Tromey , 28407@debbugs.gnu.org To: Dmitry Gutov Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Mon May 16 09:02:27 2022 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nqUkN-0003WM-1M for geb-bug-gnu-emacs@m.gmane-mx.org; Mon, 16 May 2022 09:02:27 +0200 Original-Received: from localhost ([::1]:48100 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nqUkL-00060u-JR for geb-bug-gnu-emacs@m.gmane-mx.org; Mon, 16 May 2022 03:02:25 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:58938) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nqUj3-00060R-M8 for bug-gnu-emacs@gnu.org; Mon, 16 May 2022 03:01:07 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:57624) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nqUiz-00056Y-OS for bug-gnu-emacs@gnu.org; Mon, 16 May 2022 03:01:04 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nqUiz-0007Aq-MN for bug-gnu-emacs@gnu.org; Mon, 16 May 2022 03:01:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Visuwesh Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Mon, 16 May 2022 07:01:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 28407 X-GNU-PR-Package: emacs Original-Received: via spool by 28407-submit@debbugs.gnu.org id=B28407.165268443727537 (code B ref 28407); Mon, 16 May 2022 07:01:01 +0000 Original-Received: (at 28407) by debbugs.gnu.org; 16 May 2022 07:00:37 +0000 Original-Received: from localhost ([127.0.0.1]:51521 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nqUia-0007A5-IE for submit@debbugs.gnu.org; Mon, 16 May 2022 03:00:36 -0400 Original-Received: from mail-pj1-f68.google.com ([209.85.216.68]:38428) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nqUiY-00079m-9V for 28407@debbugs.gnu.org; Mon, 16 May 2022 03:00:34 -0400 Original-Received: by mail-pj1-f68.google.com with SMTP id o13-20020a17090a9f8d00b001df3fc52ea7so2589584pjp.3 for <28407@debbugs.gnu.org>; Mon, 16 May 2022 00:00:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=PA8gUUXaHjJ9Hw3bhPOtVi3/LL3wEkIjYiz1x+TYNyc=; b=CjZIEAxu+3wskmq+XkNJ/MwEm8qN6l3BusYu255XsHtFCzrzLOcxArgeZEWdJZOL7i 1+G6SvzxfZ2DUycDe3uD+2ZdRaFCb2BvaUic28GZLmzMzxw/VR3P7As4CSzG0qK9aa75 uFGwj9TMLAuvxzKHOmKeYbRuiBxGWMh/2anjBS1SNidfW+Yq4icZOovjasoqD5grINva kPaTo60MUmbJwllmYusZPejsTnNZkKSGTHasvCgflCPgbWJxumTPwBMvDJJUCzkgIKPe +kMaDNwOVUS0u22xhhy4MS6BRMfn19KbtMN9bD+oovvqluoCouP549AOlnQIlCt2Ajwq p+SQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=PA8gUUXaHjJ9Hw3bhPOtVi3/LL3wEkIjYiz1x+TYNyc=; b=N5q6UCTZl0m6URY3YjK0mvSYWd2oc5pWEksxFsVv8s0WR5/f78OAARIZUv/ViIyfk+ Ts+JDfiXVQYWq+tSq90QOgPib3xzx21vJvmZpefnA5AHQl4/b2uszhbQP0chgh0eS77G 7LCEoKlCtU0ZhXoNq17KE0FJCxjybT+5T7vuDy02Qq65pUIHKS67bcUNzmgo49c0KaRK t039P0u7Yh2CP+XaI+FvESsf0FB0F/Yg9j7fU3Z3ZD1dmgjEdZrWdpyeqkzYHLbUegZT fN2YHbjzbfwS8FRVeh2WpycSEbMbKMqDvQ/HzLzE2uagVfHO9zEMtR0lBtdgFMUQLeWF NbCg== X-Gm-Message-State: AOAM530YmETZqogtPfsJMfeLIeiBlYufkRSmsZ13/SAWVshplgXrkrGq TGCZ6EzjzxXYJkyhKXX2Sjs= X-Google-Smtp-Source: ABdhPJyS3+bJXlDaTuAvWLBsBdSrBQDctPJV0vwVarfK81Cg5yXFdlXyB/lv9ReCwP7/ror1Q8cOxQ== X-Received: by 2002:a17:903:124a:b0:154:c7a4:9374 with SMTP id u10-20020a170903124a00b00154c7a49374mr16178227plh.68.1652684428154; Mon, 16 May 2022 00:00:28 -0700 (PDT) Original-Received: from localhost ([49.205.85.27]) by smtp.gmail.com with ESMTPSA id cs14-20020a17090af50e00b001d75aabe050sm5735441pjb.34.2022.05.16.00.00.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 16 May 2022 00:00:27 -0700 (PDT) In-Reply-To: <87y1z35630.fsf@gmail.com> (Visuwesh's message of "Sun, 15 May 2022 18:02:14 +0530") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:232355 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable [=E0=AE=9E=E0=AE=BE=E0=AE=AF=E0=AE=BF=E0=AE=B1=E0=AF=81 =E0=AE=AE=E0=AF=87 = 15, 2022] Visuwesh wrote: > [=E0=AE=A4=E0=AE=BF=E0=AE=99=E0=AF=8D=E0=AE=95=E0=AE=B3=E0=AF=8D =E0=AE= =9A=E0=AF=86=E0=AE=AA=E0=AF=8D=E0=AE=9F=E0=AE=AE=E0=AF=8D=E0=AE=AA=E0=AE=B0= =E0=AF=8D 11, 2017] Dmitry Gutov wrote: > >> On 9/10/17 7:23 PM, Tom Tromey wrote: >>> It would be nice if imenu were a back end for xref. >>> Then M-. could also use symbols found by imenu. >>> A further wrinkle on this would be if xref, project, and imenu >>> worked >>> together, so that M-. would automatically know to look at imenu results >>> for other buffers in the same project. >> >> Agreed. It could be a nice default for when no tags table is currently >> visited. > > I tried to write a general imenu backend in attached file (extracted > from my init.el) but I hit quite a few roadblocks, > > 1. I activate the imenu backend iff there are no tags table defined > for the buffer but this means that one cannot use the imenu > backend to jump to definitions for symbols that TAGS do not know > of currently. I can think of two ways to solve this problem, > > (a) Check if the symbol is in TAGS table. > (b) Modify the etags backend so that the user can say "I have no > TAGS table for this file/project/whatever." > > (a) is definitely not clean, and (b) sounds feasible but similar > situation can also exist with other backends (like elisp). > > I'm lost on how to solve this problem. > > 2. I have not defined all the methods and the completion-table does > not handle the nested case of the index alist. AFAIU from `(elisp) > Programmed Completion', completion "ends" when `try-completion' > returns t but I seem to be mistaken. I have to rewrite > completion-table to be like `imenu--completion-buffer' but I don't > know how to pull that off. > > 3. `imenu-xref--in-alist' is mostly a 1-1 copy of `imenu--in-alist' > with the only difference being my function returns all matches of > the symbol instead of just the first one. This should be easy > enough to fix by adding an optional argument INCLUDE-ALL to > `imenu--in-alist'. > > I'm testing in python-mode with the following settings, > > (setq imenu-name-lookup-function (lambda (symbol item) (string-prefix= -p symbol item)) > python-imenu-format-parent-item-jump-label-function (lambda (_ = name) name)) I solved (2) by using an affixation function. I did (3) as well, and I'm attaching my work as a patch against imenu.el. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=imenu-xref.patch diff --git a/lisp/imenu.el b/lisp/imenu.el index 2636e77d08..69338d216a 100644 --- a/lisp/imenu.el +++ b/lisp/imenu.el @@ -52,6 +52,7 @@ ;;; Code: (require 'cl-lib) +(require 'xref) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; @@ -473,8 +474,10 @@ imenu--create-keymap (if cmd (funcall cmd item) item)))))) alist))) -(defun imenu--in-alist (str alist) - "Check whether the string STR is contained in multi-level ALIST." +(defun imenu--in-alist (str alist &optional all) + "Check whether the string STR is contained in multi-level ALIST. +If the optional argument ALL is non-nil, then return all matches +of STR in ALIST." (let (elt head tail res) (setq res nil) (while alist @@ -491,12 +494,18 @@ imenu--in-alist ;; We are only interested in the bottom-level elements, so we need to ;; recurse if TAIL is a nested ALIST. (cond ((imenu--subalist-p elt) - (if (setq res (imenu--in-alist str tail)) - (setq alist nil))) + (let ((r (imenu--in-alist str tail all))) + (if all + (setq res (append res (if (listp (cdr r)) r (list r)))) + (setq res r) + (when r + (setq alist nil))))) ((if imenu-name-lookup-function (funcall imenu-name-lookup-function str head) (string= str head)) - (setq alist nil res elt)))) + (if all + (push elt res) + (setq alist nil res elt))))) res)) ;;;###autoload @@ -550,6 +559,61 @@ imenu-default-create-index-function (t (imenu-unavailable-error "This buffer cannot use `imenu-default-create-index-function'")))) +;;; +;;; Xref backend +;;; + +;;;###autoload +(defun imenu-xref-backend () + (unless imenu--index-alist + (imenu--make-index-alist)) + (when (and imenu--index-alist + (not (progn (require 'etags) tags-table-files))) + 'imenu)) + +(cl-defmethod xref-backend-identifier-at-point ((_backend (eql 'imenu))) + (thing-at-point 'symbol)) + +(defun imenu-xref--make-summary (marker) + (with-current-buffer (marker-buffer marker) + (save-excursion + (goto-char marker) + (back-to-indentation) + (buffer-substring (point) (point-at-eol))))) + +(cl-defmethod xref-backend-definitions ((_backend (eql 'imenu)) symbol) + (let ((res (imenu--in-alist symbol imenu--index-alist t)) + defs) + (dolist (item res) + (push (xref-make (imenu-xref--make-summary (cdr item)) + (xref-make-buffer-location (marker-buffer (cdr item)) + (marker-position (cdr item)))) + defs)) + defs)) + +(cl-defmethod xref-backend-identifier-completion-ignore-case ((_backend (eql 'imenu))) + imenu-case-fold-search) + +(defun imenu-xref--make-affixations (alist &optional prefix) + (let (res) + (dolist (item alist) + (if (imenu--subalist-p item) + (setq res (append res (imenu-xref--make-affixations + (cdr item) + (concat prefix (when prefix imenu-level-separator) (car item))))) + (push (list (car item) (concat prefix (when prefix imenu-level-separator)) "") res))) + res)) + +(cl-defmethod xref-backend-identifier-completion-table ((_backend (eql 'imenu))) + (let ((affixations (imenu-xref--make-affixations imenu--index-alist))) + (lambda (string pred action) + (if (eq action 'metadata) + `(metadata (affixation-function + . ,(lambda (cmp) (mapcar (lambda (c) (assoc c affixations #'equal)) cmp)))) + ;; This works since (car AFFIXATIONS) is the completion + ;; candidate. + (complete-with-action action affixations string pred))))) + ;;; ;;; Generic index gathering function. ;;; --=-=-=--