scottaj / old-emacs-config

My old emacs config -- no longer maintained or used. See here for the new one:
https://github.com/scottaj/new-emacs-config
15 stars 2 forks source link

shared repo, personal config #22

Open englishm opened 11 years ago

englishm commented 11 years ago

One of the things I like about https://github.com/atomicobject/atomic_vim is the pattern of keeping a personal config in the shared repo. This makes it really easy to share your config without stomping on what someone else wants to do differently. Eventually it might be nice to move to something like that here, too.

(There are downsides to this approach as well, mostly around how you may or may not want to keep your config up to date in source control and the merge conflicts that can arise from these different usage patterns. It's also problematic if you want to keep your customizations in source control separately for some reason–e.g. as part of a dotfiles repo, or a private repo that contains secrets.)

Food for thought.

scottaj commented 11 years ago

I like this idea, and I've thought about it before. One issue I had with doing this is figuring out how to preserve the organization of the config files, while still allowing for separate user customizations. The other issue is in the way el-get stores and loads packages. I'm going to talk a bit about each of those issues and maybe we can come up with a solution.

For reference, the config is currently laid out like this:

|
↳ init.el
↳ user.el
↳ custom.el
|
↳ init/
|      ↳ init-some-package-name.el
|      ↳ init-another-package-name.el
|      ↳ ...
|
↳ el-get/
|      ↳ el-get packages installed into their own 
|      ↳ directories here...
|
↳ snippets/

Problem 1

The main problem with this layout is that a particular user's customizations might need to be spread out over a large number of potential files. Also, there needs to be some way to preserve defaults in these files while still allowing for extension.

I see a few of potential solutions:

Solution 1

  1. Move init.el, user.el, and custom.el to user prefixed files for each user with a config, e.g. english-init.el, english-user.el, english-custom.el.
  2. Use a custom .emacs or .emacs.d/init.el file to load the -init.el package you want (as well as any additional files you want to load.)
  3. Flatten the config and remove the init/ directory for specific package customizations; move all these customizations into <username>-user.el

This option would make the setup very similar to the atomic-vim setup. Pros and cons that I see:

PROS:

CONS:

The directory structure for this solution would look like this:

|
↳ userA-init.el
↳ userA-user.el
↳ userA-custom.el
↳ userB-init.el
↳ ...
|
↳ el-get/
|      ↳ el-get packages installed into their own 
|      ↳ directories here...
|
↳ snippets/

Solution 2

The second solution is sort of the opposite, instead of simplifying the config's structure we make it more complicated, but also more flexible.

  1. Same as step 1 from the first solution
  2. Same as step 2 from the first solution
  3. Change the init directory as follows: a. move the setting for each package into init/package-name/common-init-package-name.el b. have init/package-name.el load the above file.

With this structure, you can put a user specific load file into each init/package-name/ directory.

With this solution, the directory structure would look like this:

|
↳ userA-init.el
↳ userA-user.el
↳ userA-custom.el
↳ userB-init.el
↳ ...
|
↳ init/
|      ↳ init-some-package-name.el
|      ↳ some-package-name/
|      |       ↳ common-init-some-package-name.el
|      |       ↳ userA-init-some-package-name.el
|      ↳ init-another-package-name.el
|      ↳ ...
|
↳ el-get/
|      ↳ el-get packages installed into their own 
|      ↳ directories here...
|
↳ snippets/

I like the structure of this solution better, but the problem is that it would require some work to implement. Specifically, how do we get emacs to load <username>-init-some-package.el without putting it into the main el-get init file.

I think this could probably be overcome with some elisp magic, maybe something like setting a username variable and then loading all files that are prefixed with that username?

Pros and cons:

PROS:

CONS:

Solution 3

Go really crazy. Instead of trying to warp el-get and emacs into a directory structure that allows easy overriding, abstract to whole configuration away into some type of meta-language which can be used to generate a configuration using a script.

PROS:

CONS:

Problem 2

The current implementation stores copies of all the needed el-get packages in the repository. This is problematic for customization because el-get will load any package in that directory, even if you remove it from your package list in init.el. This means that the system is currently very hostile to adding new packages or to users who want to disable a currently installed package.

I think this is a sign of the unsustainability of keeping copies of all the packages in the repository. I am going to address this by opening another Github issue to explore alternatives.


As far as problem 1 goes, what are your thoughts about the problem and the potential solutions I proposed?

scottaj commented 11 years ago

I have to say, after reading over my response again, I am thinking really hard about my solution 3. While it is potentially a ton of work, the implications seem really awesome.

englishm commented 11 years ago

My gut-check says that solution 3 is likely to be a yak-filed trap. I could see something like 1 or 2 working though. One other "problem" not in your list is the issue of allowing flexibility for users who may want to have customizations, but not keep them in this shared repo. Ideally, I'd have the flexibility to check my personal configuration settings into the repo, keep them separate from the repo, and optionally even keep them in another repo (e.g. my personal dotfiles repo). I wonder if there's a way we could use a combination of environment variables, "*.d"-style config directories, .gitignore, symlinks, and a bit of elisp to make this all possible. I haven't come up with anything particularly elegant yet, but I think it can be done.

scottaj commented 11 years ago

Agreed.

What if we had the concepts of "load-dirs" for users. Load dirs would mirror the direcory structure of the normal config, and could be located anywhere. We could then introduce a load-dirs function that would take a list of the load-dirs to initalize emacs with in order.

This means you could have an init file that looked like this:

(def config-dirs '(
  "someone/you/likes/config/dir"
  "your/config/dir"))
(load-dirs config-dirs)

We could combine this with specifying a "username" variable (or environment variable) that init.el would read.

Emacs would then be set up to:

  1. Load the default config
  2. Load an init file based on the "username variable", e.g. english-init.el if the username was "english"
  3. Load each config dir you specified in the order you provided in your init file.

Thoughts?

englishm commented 11 years ago

Yes, that's exactly the type of thing I was thinking. It would allow someone to keep their configs in this shared repo or someplace else ( e.g. ~/dotfiles/emacsconfig/). It should also fall back to the default config if "username" is undefined or invalid.

What convention(s) would we pair with this for users who do want to keep their config in this shared repo? Would we use what you suggested above in Solution 2?

Also, re-reading, would this require {username}-init.el to be in this repo? I can't think of a simple way around that, unless perhaps the ENV variable was actually a path to that file... ?

scottaj commented 11 years ago

Agree on it falling back, that way it's zero configuration if you just want the defaults.

Solution 2 would work, but I think it would be simpler to have a mirrored directory with a username prefix as a convention. This makes it less messy overall and to find/remove/etc. a specific user's settings.

so the directory structure would be something like this:

|
↳ init.el
↳ user.el
↳ custom.el
↳ init-english.el
↳ init-scott.el
|
↳ init/
|  ↳ init-some-package-name.el
|  ↳ init-another-package-name.el
|  ↳ ...
|
↳ el-get/
|  ↳ el-get packages installed into their own 
|  ↳ directories here...
|
↳ english/
|  ↳ init.el
|  ↳ user.el
|  ↳ custom.el
|  ↳ init/
|    ↳ init-some-package.el
|    ↳ ...
|
↳ scott/
|  ↳ ...
|
↳ snippets/

We could have a second, optional ENV var that is a directory to look for the init file in for users that require that behavior, how does that sound?

englishm commented 11 years ago

That sounds good to me.

So, assuming that I have emacs-config checked out to ~/.emacs.d, then in my .zprofile I'll be able to... export AO_EMACS_USER="english" and it will source ~/.emacs.d/init-english.el which will presumably set up my config_dir to load ~/.emacs.d/english/init.el etc.

If I also have in my .zprofile: export AO_EMACS_CONFIGPATH="~/dotfiles/ao_emacs_config" then it would instead load ~/dotfiles/ao_emacs_config/english-init.el which could set my config_dir to load ~/dotfiles/ao_emacs_config/english/init.el etc.

Is that right?

scottaj commented 11 years ago

Yep, thats what I was thinking.