On Mon, Nov 3, 2025 at 3:21 PM Hongyi Zhao <[email protected]> wrote:
>
> On Mon, Nov 3, 2025 at 4:06 AM Arash Esbati <[email protected]> wrote:
> >
> > Hongyi Zhao <[email protected]> writes:
> >
> > > First, I'd like to express my immense appreciation for your incredible
> > > work on AUCTeX. It is an indispensable tool.
> >
> > Thanks for your kind words.
> >
> > > **The Problem:**
> > > In my setup, the standard automatic completion chain
> > > (`completion-at-point-functions`) is unreliable for file paths inside
> > > commands like `\include{./}` or `\addbibresource{./}`.
> >
> > What is in this case unreliable?
> >
> > > My extensive debugging suggests this is due to a "short-circuiting" 
> > > effect:
> > > 1.  Higher-priority completion backends (like `lsp-mode` or
> > > `cape-dabbrev`) are triggered first.
> > > 2.  Even if they find no relevant candidates for a prefix like `./`,
> > > they seem to return a "successful but empty" result.
> > > 3.  This "successful" result prevents the completion chain from
> > > proceeding to lower-priority, more specialized backends like
> > > `completion-file-name-table`. The file completion backend is never
> > > given a chance to run.
> >
> > You should try to assemble a minimal recipe how to reproduce this,
> > starting with "emacs -Q", and then report that as a bug to the relevant
> > developers.
> >
> > > **My Questions:**
> > >
> > > While my solution is effective, I am keen to know if it is the optimal
> > > or most idiomatic approach.
> > >
> > > 1.  Is my analysis of the "short-circuit" problem in the automatic
> > > completion chain correct?
> >
> > How can others tell without knowing your setup?  Again, the only way to
> > track this down is a reproduceable recipe, starting with "emacs -Q".
> >
> > > 2.  Is this manual, key-bound command the recommended way to solve
> > > this problem within the AUCTeX ecosystem?
> > > 3.  Does AUCTeX perhaps have a built-in command, variable, or
> > > mechanism to handle this exact scenario, which I may have missed in
> > > the documentation?
> >
> > No, AUCTeX simply adds 2 functions to `completion-at-point-functions',
> > so you're basically free to add or remove any function from it.
> >
> > > 4.  Is there a more elegant way to configure
> > > `completion-at-point-functions` itself to grant file completion higher
> > > priority in these specific command-argument contexts?
> >
> > This is my setup for the cape package:
> >
> > (use-package cape
> >   :defer t
> >   :init
> >   (add-hook 'completion-at-point-functions #'cape-file 95)
> >
> >   :custom
> >   (cape-file-prefix '("file:" "./" "../" "~/"))
> >
> >   :bind (:map corfu-map
> >               ("C-c p f" . cape-file)))
> >
> > Not sure if it is an elegant way, but it works for me.
> >
> > Best, Arash
>
> Dear Arash,
>
> Thank you once again for your invaluable guidance. Following your
> advice, I conducted the `emacs -Q` test with a minimal recipe. The
> results were both surprising and incredibly illuminating, and they
> have led me to a definitive conclusion.
>
> The test rigorously demonstrates the "short-circuiting" problem I
> described. I present the complete, step-by-step recipe below for your
> review.
>
> ---
>
> ### **Minimal Reproducible Recipe**
>
> #### **1. Prerequisites**
>
> *   A recent version of Emacs (e.g., Emacs 29+).
> *   The `texlab` LSP server installed and available in the system's `PATH`.
>
> #### **2. Minimal Init File (`~/mini-init.el`)**
>
> Save the following code as `~/mini-init.el`. This configuration sets
> up a completion chain where `lsp-mode` and `cape-dabbrev` are grouped
> in a high-priority `cape-super-capf`, with `cape-file` as a
> lower-priority fallback.
>
> ```emacs-lisp
> ;; -*- lexical-binding: t; -*-
>
> ;; Step 1: Bootstrap straight.el
> (defvar bootstrap-version)
> (let ((bootstrap-file
>        (expand-file-name "straight/repos/straight.el/bootstrap.el"
>                          (or (bound-and-true-p straight-base-dir)
>                              user-emacs-directory)))
>       (bootstrap-version 7))
>   (unless (file-exists-p bootstrap-file)
>     (with-current-buffer
>         (url-retrieve-synchronously
>          
> "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el";
>          'silent 'inhibit-cookies)
>       (goto-char (point-max))
>       (eval-print-last-sexp)))
>   (load bootstrap-file nil 'nomessage))
>
> (setq straight-use-package-by-default t
>       package-enable-at-startup nil)
>
> ;; Step 2: Configure core completion packages
> (use-package corfu
>   :init (global-corfu-mode)
>   :custom (corfu-auto t))
>
> ;; ===================================================================
> ;; Core Fix: Add :demand t to ensure cape functions are available
> ;; ===================================================================
> (use-package cape
>   :demand t)
>
> ;; Step 3: Configure AUCTeX
> (use-package auctex
>   :mode ("\\.tex\\'" . LaTeX-mode))
>
> ;; Step 4: Configure lsp-mode with the exact setup causing the issue
> (use-package lsp-mode
>   :hook (LaTeX-mode . lsp-deferred)
>   :commands (lsp lsp-deferred)
>   :config
>   ;; Helper functions
>   (defun my/completing-latex-command-p ()
>     (when-let* ((bounds (bounds-of-thing-at-point 'symbol))
>                 (start (car bounds)))
>       (and (> start (point-min))
>            (eq (char-before start) ?\\))))
>
>   (defun my/capf-unless (predicate capf)
>     (lambda ()
>       (when-let* ((fn (symbol-function capf)))
>         (unless (funcall predicate)
>           (funcall fn)))))
>
>   ;; The core advice function that creates the complex completion chain
>   (defun my/lsp-add-cape-advice (&rest _)
>     "Set up a completion chain with lsp-mode, dabbrev, and cape-file."
>     (when (and (bound-and-true-p lsp-mode)
>                (boundp 'completion-at-point-functions))
>       ;; This `(require 'cape)` is good practice, but :demand t is more robust
>       (require 'cape nil t)
>       (let ((lsp-capf (car completion-at-point-functions)))
>         (setq-local completion-at-point-functions
>                     (list
>                      (cape-capf-buster
>                       (cape-super-capf
>                        lsp-capf
>                        (my/capf-unless #'my/completing-latex-command-p
> #'cape-dabbrev)))
>                      ;; Fallback for file completion
>                      #'cape-file
>                      t)))))
>   (advice-add 'lsp-completion--enable :after #'my/lsp-add-cape-advice))
> ```
>
> #### **3. Test Project Setup**
>
> Create a temporary directory with the following structure:
>
> ```bash
> mkdir -p ~/emacs-test/subdir
> cd ~/emacs-test
> touch test.tex subdir/another-file.tex
> ```
>
> The content of `~/emacs-test/test.tex` should be:
>
> ```latex
> \documentclass{article}
>
> \addbibresource{my-references.bib}
>
> \begin{document}
>
> \include{}
>
> \end{document}
> ```
>
> #### **4. Steps to Reproduce and Test Results**
>
> 1.  Start Emacs from within the test directory using the minimal 
> configuration:
>     ```bash
>     cd ~/emacs-test/
>     emacs -Q -l ~/mini-init.el
>     ```

In this step, the following command should be used for conducting
straight.el based isolation testing:

```bash
cd ~/emacs-test/ && emacs -Q --eval '(setq user-emacs-directory
"~/emacs-test-straight/")' -l ~/mini-init.el
```

Regards,
Zhao

> 2.  Open the test file: `C-x C-f test.tex RET`.
> 3.  When prompted by `lsp-mode` to select a project root, press `.` to
> import the current directory.
> 4.  Wait for the mode line to show that `lsp-mode` has connected to `texlab`.
>
> Now, perform the following three tests:
>
>
> **Test A: File Path Completion (The Surprising, Primitive Success)**
>
> *   **Action:** Move the cursor inside `\include{}` and type `./`.
> *   **Result:** A Corfu popup **appears**, offering the primitive path
> candidates: `subdir` and `test`. **Crucially, note the missing
> trailing slash for the directory and the `.tex` extension for the
> file.**
> *   **Analysis:** This completion is provided by `lsp-mode` itself.
> This proves that `lsp-mode` *can* handle basic file paths, but its
> implementation is rudimentary and lacks the rich detail (like a
> trailing `/`) that a dedicated file backend provides. Most
> importantly, it still successfully "claims" the completion request,
> explaining why the fallback `cape-file` is not reached.
>
> **Test B: LaTeX Command Completion (The Control Test)**
>
> *   **Action:** On a new line, type `\sec`.
> *   **Result:** A Corfu popup **appears**, correctly offering
> `section`, `section*`, etc.
> *   **Analysis:** This confirms that the primary function of
> `lsp-mode`'s semantic completion is working as expected.
>
> **Test C: Dabbrev Completion (The Definitive Proof of the Problem)**
>
> *   **Action:** On a new line, type `resou`.
> *   **Result:** **Nothing happens.** No completion popup appears.
> *   **Analysis:** This is the crucial evidence. `cape-dabbrev` should
> have completed `resource` from the word `\addbibresource`. Its failure
> to trigger proves that `lsp-capf`, despite having no semantic
> candidates for `resou`, still "claimed" the completion request and
> returned an "empty success". This action within the `cape-super-capf`
> block **short-circuited** the process, preventing `cape-dabbrev` from
> ever being called.
>
> **(I have attached the screenshots from these three tests for your 
> reference.)**
>
> ---
>
> ### **Final Analysis**
>
> These tests definitively confirm that the "short-circuiting" problem
> is real and is caused by the aggressive behavior of the `lsp-capf`
> backend.
>
> Therefore, my final conclusion is now even stronger:
>
> For a complex, modern Emacs setup that includes `lsp-mode`, a
> **manual, key-bound command that completely bypasses the automatic
> `completion-at-point-functions` chain is the only robust and reliable
> solution** for file path completion. It is superior not only in
> **reliability** (it never gets short-circuited) but also in
> **functionality** (it provides richer, more user-friendly candidates
> than `lsp-mode`'s basic implementation).
>
> Thank you again for your time and for guiding me toward this rigorous
> and illuminating investigation.
>
> Best regards,
> Zhao

Reply via email to