Re: markdown-ts-mode not recognized after updating built-in packages
Rahul Martim Juliato <[email protected]> Sun, 28 Jun 2026 14:20:00 -0300
| Newsgroups | gmane.emacs.help |
|---|---|
| Message-ID | <[email protected]> |
Stéphane Marks <[email protected]> writes: > On Fri, Jun 26, 2026 at 5:55 AM Ashish Panigrahi <[email protected]> > wrote: > >> Hi, >> >> I noticed recently that after updating the built-in packages (emacs >> 31.0.90), opening a markdown file with the built-in markdown-ts-mode >> doesn't not enable the major mode. An echo area message appears >> mentioning to uninstall the package since it is built-in since emacs 31. >> >> This is not an issue with the corresponding tagged releases of the >> built-in packages when installing emacs 31.0.90 from scratch. I also >> have an `:ensure nil` keyword in my use-package macro for >> markdown-ts-mode. >> >> Is this behaviour expected? Thanks. > > > Yes. The MELPA release has been deprecated for Emacs 31+ since this commit > https://github.com/LionyxML/markdown-ts-mode/commit/801579b9b955f63673dd6dc9742c1fd5311b76c9 > > Perhaps someone I cc'd (or someone else) can recommend a good/best way to > handle sharing a configuration across pre 31 and 31+ where 31+ will use the > built-in package and pre 31 from your 'package-user-dir'. Hi, As Stéphane already pointed out, this is expected behaviour: the MELPA release deliberately refuses to load on Emacs 31+, since markdown-ts-mode is built in from Emacs 31 on. It's documented here: https://github.com/LionyxML/markdown-ts-mode#if-you-still-opt-to-use-this-package That deprecation guard is what prints the message you see in the echo area. I separated in topics some possible problems/solutions: What is most likely happening on user side ------------------------------------------ The built-in package is being shadowed by a copy of the deprecated MELPA release sitting in your elpa/ directory. Once such a copy is present, package.el activates it and puts its directory ahead of the built-in on load-path, so the deprecated stub is what gets loaded. This could possibly sneak in via an upgrade: `M-x package-upgrade' lists built-in packages as candidates too, and since the deprecated MELPA release still carries a high (date-based) version, package.el sees it as a newer version than the built-in 1.0 and "upgrades" the built-in by installing the stub into elpa/. From then on the built-in is shadowed. (`package-upgrade-all' does not touch built-ins by default, but a manual `package-upgrade', or an install left over from Emacs 30, has the same effect.) Recommended fix (works with one shared config and one shared elpa/) ------------------------------------------------------------------- Tell package.el to ignore the elpa/ copy on Emacs 31, so the built-in wins. With `package-load-list' you can disable just that package. This must go in your early-init.el, because packages are activated between early-init.el and init.el -- setting it in init.el would be too late, the elpa/ copy would already be active: ;; early-init.el (when (>= emacs-major-version 31) (add-to-list 'package-load-list '(markdown-ts-mode nil))) This way: - the built-in is used on Emacs 31; - the elpa/ copy is left in place, so Emacs 30 keeps using the MELPA package as before (no need to delete anything); - because the package is "disabled", a later `package-upgrade' can't quietly bring the stub back. Configuration ------------- On Emacs 31 the expected configuration is something like the following (opt-in, since the built-in version is still experimental). Note the explicit load: the built-in file currently has no ;;;###autoload cookie, so the `markdown-ts-mode' command does not exist until the file is loaded, and a bare auto-mode-alist entry gives you "Ignoring unknown mode 'markdown-ts-mode'": (use-package markdown-ts-mode :ensure nil :mode ("\\.md\\'" "\\.mdx\\'" "\\.markdown\\'") :init (load-library "markdown-ts-mode")) A single configuration shared between Emacs 30 (the MELPA package) and Emacs 31 (the built-in, revamped and feature-full package). The two pieces go in different files: ;; early-init.el -- disable the elpa/ copy on 31 so the built-in wins (when (>= emacs-major-version 31) (add-to-list 'package-load-list '(markdown-ts-mode nil))) ;; init.el (if (>= emacs-major-version 31) ;; Built-in: no autoload cookie -> force-load so the command exists. (use-package markdown-ts-mode :ensure nil :mode ("\\.md\\'" "\\.mdx\\'" "\\.markdown\\'") :init (load-library "markdown-ts-mode")) ;; Emacs <31: not built-in -> pull from MELPA (it ships autoloads). (use-package markdown-ts-mode :ensure t :mode ("\\.md\\'" "\\.mdx\\'" "\\.markdown\\'"))) Other ways to deal with the shadowing ------------------------------------- - Just delete the elpa/ copy: M-x package-delete RET markdown-ts-mode RET. This only removes the MELPA copy from package-user-dir, never the built-in. The drawback is that a later upgrade can reinstall it. - Give each Emacs version its own package directory (this also avoids .elc incompatibilities between versions), set in early-init.el (again, before packages are activated): ;; early-init.el (setq package-user-dir (locate-user-emacs-file (format "elpa-%d" emacs-major-version))) Emacs 30 then installs into elpa-30/ and Emacs 31 uses elpa-31/ (without the MELPA package), so the built-in wins. Hope this helps. Best, -- Rahul Martim Juliato