Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Best practices for overriding settings in doom modules #88

Closed
cthachuk opened this Issue May 30, 2017 · 13 comments

Comments

Projects
None yet
5 participants

@hlissner First, thanks for sharing a wonderful emacs config and welcome alternative to spacemacs.

Do you suggest a best practice for overriding settings in the modules that ship with doom? For example, a user customizing the +org-dir variable. Some possibilities I could think of but am unsure of all of the side effects:

  1. Modifying the modules directly, but possibly creating future conflicts with upstream changes.
  2. Defining defvars early in the init.el, before the module is loaded.
  3. Simply overriding the variables in a private layer, after the modules have been loaded.

Thanks in advance for your thoughts on this.

Contributor

orther commented May 30, 2017

I have been meaning to ask this question in an issue but haven't gotten around to it. In my case I was looking to change the font by setting +doom-font and change the theme by setting +doom-theme. I'm very new to Emacs so I can't say for sure but it seems like these variables weren't intended to be set outside the the modules they are defined in (up/doom/config.el).

Also I want to thank you for sharing this emacs config. It's really easy to understand and learn from!

Contributor

gilbertw1 commented May 31, 2017

I've been maintaining my own fork that you can probably use as an example of how not to do it ;)

https://github.com/gilbertw1/bmacs

I normally make module specific changes directly in the modules themselves with a comment like ;; BMACS - reason for change and then I just cherry pick + merge the changes from the upstream repo as they're made. In some cases, I've made significant departures in certain modules which can make merges a bit more difficult.

I generally try to stay as hands off as possible with the core files and try to limit core changes to the config in my personal/gilbertw1 and core/gdoom modules. I'm still figuring it out the best approach for me, but this is working reasonably well. A nice side effect of manually merging in the changes (especially when there are conflicts) is that I'm improving my understanding of elisp at a rapid pace.

Contributor

orther commented May 31, 2017

Thanks @gilbertw1 for your explanation. I actually started my config by mostly copying your setup a few weeks back. I was aiming to have my own private module and not customize anything outside of it but after a few weeks I realize that might not be possible or practical.

Owner

hlissner commented May 31, 2017 edited

  1. Simply overriding the variables in a private layer, after the modules have been loaded.

That's what I'm striving for. That you're unable to do so entirely is an oversight I'll soon correct, especially +doom-theme.

Owner

hlissner commented Jun 4, 2017 edited

I'm considering combining 2 and 3 into the following changes:

  1. Private modules named after your username (user-login-name) will be loaded automatically after all other modules. If you don't want to use your username like that, or you use multiple machines with different usernames, you could use symlinks or forcibly change user-login-name in init.el.

  2. Your private module will have a unique file, let's say private/<user-login-name>/init.el, which DOOM will load early, before any modules are activated (but after DOOM core), giving you an opportunity to override defvars and, optionally, pre-configure other packages with after! (or use-package-inject-hooks for more precise control). For example:

    (setq use-package-inject-hooks t)
    
    (add-hook! 'use-package--PACKAGE--pre-init-hook ...)
    (add-hook! 'use-package--PACKAGE--post-init-hook ...)
    (add-hook! 'use-package--PACKAGE--pre-config-hook ...)
    (add-hook! 'use-package--PACKAGE--post-config-hook ...)
    
    ;; Or use this macro:
    (defmacro configure! (package when &rest body)
      "Configure a package using use-package hooks (see `use-package-inject-hooks').
    
    PACKAGE is the package name.
    WHEN should be one of the following: :pre-init :post-init :pre-config :post-config"
      (declare (indent defun))
      `(add-hook!
         ',(intern (format "use-package--%s--%s-hook"
                           package
                           (substring (symbol-name when) 1)))
         ,@body))
    
    (configure! PACKAGE :post-config
      (message "Hello world"))

    If you don't need that level of control, `after!' is a simpler alternative.

    (after! PACKAGE ...)

Any thoughts on/objections to this?

Contributor

gilbertw1 commented Jun 4, 2017

No objections here.

Regarding 1, I think that I'll probably end up forcibly changing the user-login-name to keep it consistent regardless of location.

Regarding 2, I think this is a very beneficial change. This will make it pretty easy to move several of my smaller package customizations into a private module.

Thanks!

cthachuk commented Jun 5, 2017

This seems like a great solution, thanks!

Owner

hlissner commented Jun 5, 2017 edited

And done!

In summary:

  1. private/<user-login-name>/config.el is loaded automatically, after all other modules. Keeping :private <user-login-name> in init.el is harmless, but does nothing.

  2. private/<user-login-name>/init.el is loaded before all modules.

  3. If your needs are simple, use after! to reconfigure packages.

  4. If your needs are complex, the new def-package-hook! macro can help. It is essentially the configure! macro I offered above, but can also be used to disable the original def-package blocks entirely:

    (def-package-hook! evil-goggles :disable)
  5. If a :pre-init or :pre-config hook returns nil, you overwrite the original :init/:config block. So make sure they return non-nil (or exploit that to rewrite DOOM's config/init blocks for your own purposes).

  6. package! now supports the :ignore property. Use this in your private packages.el to stop certain packages from being installed. (package! some-plugin :ignore t)

I think that covers everything. Let me know if I've missed something!

@hlissner hlissner closed this Jun 5, 2017

Contributor

gilbertw1 commented Jun 5, 2017

Holy cow 👍

My merges about to get much simpler!

gilbertw1 added a commit to gilbertw1/bmacs that referenced this issue Jun 5, 2017

keoko pushed a commit to keoko/.emacs.d that referenced this issue Jun 9, 2017

Contributor

vsr625 commented Jun 10, 2017

Just a small issue here, if there is a packages.el file in the private module as specified by the username, then "make install", doesn't recognize the packages to be installed. It will only get recognized when we explicitly specify the private module name in the init.el

Owner

hlissner commented Jun 10, 2017

Oops! You're right. Consider that...

@hlissner hlissner reopened this Jun 10, 2017

@hlissner hlissner closed this in 688aef1 Jun 10, 2017

Owner

hlissner commented Jun 10, 2017

...fixed!

Contributor

vsr625 commented Jun 10, 2017

Woah, that was fast. I just have to say that you have made it very easy for other people to override anything they want. You are doing good work. Your config improves days by day, thanks man!

Luladjiev added a commit to Luladjiev/dotfiles that referenced this issue Jun 11, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment