fxbois / web-mode

web template editing mode for emacs
https://web-mode.org
GNU General Public License v3.0
1.64k stars 260 forks source link

Re: Setting web-mode-engines-alist in .dir-locals.el has no effect #1118

Closed mohkale closed 4 years ago

mohkale commented 4 years ago

This is a continuation of #799.

I've found that web-mode calls (web-mode-guess-engine-and-content-type) prematurely in regards to a files local variables. Specifically variables assigned through .dir-locals.el.

What this means is that if you assign web-mode-engines-alist inside of .dir-locals.el for your project, eg:

((nil . ((web-mode-engines-alist . (("liquid" . "\\.html")))
              )))

the values from it aren't assigned until after web-mode has been setup, meaning web-mode-engines-alist is nil (the global default value for it) while web-mode is being setup and then it's set to non-nil afterwards. What this in affect does is skip a users settings which is far from ideal.

I've managed to fix the issue by adding:

(add-hook 'hack-local-variables-hook
          (defun web-mode-fix-dirlocals+ (&rest _)
            (when (derived-mode-p major-mode 'web-mode)
              (web-mode-guess-engine-and-content-type))))

This hook should be invoked regardless of whether a file or directory has local variables, so I suggest we replace the call to (web-mode-guess-engine-and-content-type) inside the body of the web-mode definition, and instead add it to this hook. At the moment (web-mode-guess-engine-and-content-type) is being invoked twice for every file so it's annoyingly slow.

I believe there shouldn't be any problem if we make hack-local-variables-hook buffer local when web-mode is invoked and then add web-mode-fix-dirlocals+ to it.

fxbois commented 4 years ago

@mohkale do you have any idea where should I put my call to (web-mode-guess-engine-and-content-type) ?

mohkale commented 4 years ago

hack-local-variables-hook has been working for me. is there some where else you feel would be better for it?

fxbois commented 4 years ago

I was wondering if I could reorganize my code in a way that would not require users to add a hook

mohkale commented 4 years ago

Do you mean so users don't have to add a hook to hack-local-variables-hook? Wouldn't the only way to get around that be to add the hook ourselves? So we replace this line by adding a hook to hack-local-variables-hook or find-file-hook (I just noticed that's also run after a files local variables have been set). The hook function should just check whether the current mode is web-mode and if so call web-mode-guess-engine-and-content-type.

The issue here, I believe, is that the major modes setup logic is run before the local variables are assigned. So we just need to run the setup logic that's dependent on local variables afterwards. Unless I'm misunderstanding something ❓.

fxbois commented 4 years ago

In fact I've never used dir-locals and have quite often some questions about web-mode not being compatible with it. So next time I'll point to this issue to solve the problem.

YievCkim commented 4 years ago

I don't know If it will help you but this is what I have done to have an engine per project: https://emacs.stackexchange.com/questions/32585/set-web-mode-engine-per-directory/59709#59709

cvdub commented 1 year ago

This works if anyone is still having trouble setting web-mode-engine in .dir-locals:

(web-mode . ((eval . (web-mode-set-engine "django"))))