AdaCore / ada_language_server

Server implementing the Microsoft Language Protocol for Ada and SPARK
GNU General Public License v3.0
239 stars 55 forks source link

[Bug]: Finding root of nested alire project #1214

Closed simonjwright closed 1 month ago

simonjwright commented 1 month ago

Environment

Bug Summary and Reproducer

Bug Summary: I have a project where the main crate directory has a subdirectory test/ containing a test crate.

If I open a file test/src/vectors_test.adb, ALS log shows

[ALS.MAIN] In Message_Handler Text_Document_Did_Open URI:
[ALS.MAIN] file:///Users/simon/Developer/minimal_containers/test/src/maps_tests.adb
[ALS.MAIN] Looking for a project... Root:
[ALS.MAIN] file:///Users/simon/Developer/minimal_containers
[ALS.MAIN] Check alire:
[ALS.MAIN] Project:
[ALS.MAIN] minimal_containers.gpr

Steps to reproduce: see above.

Expected behavior: It should find the immediate test/ directory.

Configuration and Logs

[ALS.MAIN] In Message_Handler Text_Document_Did_Open URI:
[ALS.MAIN] file:///Users/simon/Developer/minimal_containers/test/src/maps_tests.adb
[ALS.MAIN] Looking for a project... Root:
[ALS.MAIN] file:///Users/simon/Developer/minimal_containers
[ALS.MAIN] Check alire:
[ALS.MAIN] Project:
[ALS.MAIN] minimal_containers.gpr

Other VS Code Extensions

No response

Additional context

No response

simonjwright commented 1 month ago

This isn’t a bug, nor is it an issue with ALS!

eglot uses project, and project’s only provided root-finding method is to look for a repo. We need to tell it to look first for alire.toml, next for *.gpr, and then for a repo.

eliericha commented 1 month ago

I'm not familiar with eglot, but I can say that upon startup, if ALS finds a alire.toml at the root workspace, it queries Alire for the project to use.

In your project if ALS was started at the root of the repository, it will use the root alire.toml even if you open a source file from the test/ sub-directory.

Is eglot able to intervene earlier to start the ALS under the test/ sub-directory when relevant?

simonjwright commented 1 month ago

My use case is that the Alire crate’s top level (the repo) has a sub-crate containing the test suite. So when I open a file under the test crate, I want ALS to find the sub-crate, not the main one, which is indeed the default in eglot.

This below sets project.el to look first for alire.toml, if not found for *.gpr, if not found for a repo. It works a treat with ALS!

(defun ada-mode--find-alire (dir)
  (let ((alire (locate-dominating-file dir "alire.toml")))
    (if alire
      (cons 'transient alire)
      nil)))

(defun ada-mode--find-gpr (dir)
  (let ((gpr (locate-dominating-file
              dir
              (lambda (dir) (directory-files dir nil "gpr"))
              )))
    (if gpr
      (cons 'transient gpr)
      nil)))

(use-package project
  :config
  ;; last-in, first-used
  (add-hook 'project-find-functions #'ada-mode--find-gpr)
  (add-hook 'project-find-functions #'ada-mode--find-alire)
  )