1176 days of war! Please support the people of Ukraine in their struggle.
Ruby: sane sorbet-ls setup in Emacs
14 May, 2025 — London
I’m generally not a huge fan of static type checking, so I do not use Sorbet in my personal Ruby and Rails projects. At work, however, we do use it: our project includes Sorbet in its Gemfile.
This creates a situation where I would sometimes have two projects open in Emacs: one with Sorbet, and one without. When working on the project that does not use Sorbet, each new open buffer would try to start sorbet-ls, and fail, complaining about not being able to find the srb executable in the project bundle.
It’s of course possible to disable the lsp-mode client for sorbet-ls entirely, by adding it to lsp-disabled-clients, but this will also disable it in the project that does use Sorbet.
Below is the workaround I’ve come up with, I publish it here in the hopes it will be useful for someone else.
- We disable the default
lsp-modeclient config forsorbet-lsso it won’t auto-start everywhere. - We create a function that checks whether the project associated with the current buffer uses Sorbet. It checks for the presence of a
sorbetdirectory, and for any mention of Sorbet in theGemfile.lockfile. - We register a new LSP client that will start in all ruby buffers, but only if that buffer belongs to a project that uses Sorbet.
Please note that I’m using Doom Emacs (which provides the after! macro), and lsp-mode rather than eglot.(after! lsp-mode (require 'lsp-sorbet) (add-to-list 'lsp-disabled-clients 'sorbet-ls) (defun gt/project-has-sorbet-p () "Does this project use Sorbet?" (or (locate-dominating-file default-directory "sorbet") (when-let* ((root (locate-dominating-file default-directory "Gemfile.lock")) (gemfile-lock (expand-file-name "Gemfile.lock" root))) (with-temp-buffer (insert-file-contents gemfile-lock) (search-forward-regexp "^ *sorbet \\|^ *sorbet-static " nil t))))) (lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection (lambda () (when (gt/project-has-sorbet-p) (if (file-exists-p "Gemfile") '("bundle" "exec" "srb" "tc" "--lsp") '("srb" "tc" "--lsp"))))) :activation-fn (lambda (filename _mode) (and (eq major-mode 'ruby-mode) (gt/project-has-sorbet-p))) :priority -1 :add-on? t :server-id 'gt/sorbet-ls)))
Please adapt as needed, and do let me know if you’ve come up with a simpler and/or more elegant solution for this problem. Have a comment? Please get in touch by email, or on Mastodon.
© 2007–2025 Gosha Tcherednitchenko
Colophon
Accessibility statement
Source code
Subscribe to RSS
Merveilles Webring (Random)
Support my work on Ko-Fi
Je pense pas à demain, parce que demain, c’est loin

Leave a comment