Skip to content
New issue

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

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider making Crafted's modules directory fully independent of init.el and early-init.el #251

Closed
mattmc3 opened this issue Nov 30, 2022 · 13 comments
Assignees

Comments

@mattmc3
Copy link
Contributor

mattmc3 commented Nov 30, 2022

Crafted Emacs assumes that you'll use it as your primary emacs.d, but as a user grows in their Emacs acumen it would be really beneficial for them to be able to use crafted-emacs modules independently, rather than the whole project. That would mean users could have control of their own emacs.d, and have crafted-emacs located somewhere else (submodule, subdirectory, etc).

In order to do this, anything in the modules directory shouldn't assume that Crafted's init.el is run. Things like defvar and defconst statements in Crafted's init.el could be separated out into to modules/crafted-init.el, and then the user could have their own init.el and early-init.el. Of course, then they would need to add a statement like this to their own init.el:

(add-to-list 'load-path (expand-file-name "crafted-emacs/modules" user-emacs-directory))
(require 'crafted-init)
(require 'crafted-whatever-else...)

In order for this to not be a breaking change, Crafted's init.el would (require crafted-init). Things like gc settings would remain in Crafted's init.el, as well as anything that else that isn't a pre-req for a module to work. A user could then truly customize their own Emacs experience and this would allow Crafted to continue to grow with a user as they get more experience with Emacs, which seems well aligned with this project's stated goals.

@daviwil
Copy link
Member

daviwil commented Nov 30, 2022

This was one thing I hoped to do eventually when I started this project. I'd love to see it happen!

@mattmc3
Copy link
Contributor Author

mattmc3 commented Nov 30, 2022

Awesome! If what I described is an acceptable implementation of this feature, I’d happily work on a PR. I’m gonna need a little advice on how to deal with factoring things out of early-init though. It has some things in it I would have expected to just be in init, so I’m not sure how to proceed there. Does early-init need its own module too? Any suggestions on that part?

@jeffbowman
Copy link
Contributor

I look forward to seeing your PR!

To answer your question, no, early-init.el does not need it's own module as well. As I'm sure you know, early-init.el is run early in the Emacs startup process, before things like a full load-path, package system, or window system are initialized. Settings within early-init.el are there to allow configuration before init.el, config.el, packages, window system, etc are realized. The users early-config.el file is the intended location to override settings in the early-init.el file. Similarly, the users config.el file is the intended location to override settings in the init.el file.

The guix related code you refer to is probably there to allow for users who use that system to have guix provide the packages desired rather than pulling them from a package repository (GNU Elpa et. al) or from version control (when using straight.el).

The variable for loading the custom.el file is there to allow it to be overridden before the init.el (and the users config.el) are loaded.

Path variables, crafted-config-path, crafted-config-var-directory, and crafted-config-etc-directory are intended to create a structure for users to put files in their own config, managed by their own version control, but which provide a Crafted Emacs opinionated view, thus configuration within the modules/ folder depend on these being set to move things out of the user-emacs-directory as an attempt to avoid littering there, and to keep things "in one place" for the user to find more easily. The crafted-config-path has to be set in the early-init.el file because it has to be able to find and load the users early-config.el file. Eventually, the config.el file and custom.el file are loaded from this path also.

There is currently a way to achieve the goals of this issue without any changes though: a user could have their own configuration in .emacs.d or .config/emacs with their own early-init.el and init.el and have Crafted Emacs checked out on the side somewhere. To use the modules from Crafted Emacs independently, the following things need to be done (I would suggest this is probably best handled in the users early-init.el file, but could be in the users init.el file or whatever custom file they choose as long as it is loaded before any crafted-* modules):

  1. Set the crafted-config-path appropriately, possibly with (setq crafted-config-path 'user-emacs-directory), and then set the crafted-config-var-directory and crafted-config-etc-directory from that or override as seems appropriate.
  2. Override the macros crafted-package-install-package and crafted-package-installed-p (examples in the bootstrap/ folder).
  3. Add the path/to/crafted-emacs/modules to the load-path

Then the goal of being able to use the modules independently of Crafted Emacs can be realized.

Hope you find that useful!

@ajxn
Copy link
Contributor

ajxn commented Dec 3, 2022 via email

@mattmc3
Copy link
Contributor Author

mattmc3 commented Dec 14, 2022

There are definitely places where crafted-emacs assumes it's in user-emacs-directory, so at the very least a new crafted-emacs-directory variable needs introduced and used in modules:

  • ,(expand-file-name "modules" user-emacs-directory))
  • (defun crafted-updates--find-init-el ()
    (find-file-noselect (expand-file-name "init.el" user-emacs-directory)))
    (defun crafted-updates-check-for-latest ()
    "Fetches the latest Crafted Emacs commits from GitHub and
    notifies you if there are any updates."
    (interactive)
    (message "Checking for Crafted Emacs updates...")
    (when (crafted-updates--call-git #' "fetch" "origin")
    (crafted-updates--notify-of-updates)))
    (defun crafted-updates-show-latest ()
    "Shows a buffer containing a log of the latest commits to
    Crafted Emacs."
    (interactive)
    (message "Fetching latest commit log for Crafted Emacs...")
    (with-current-buffer (find-file-noselect (expand-file-name "init.el" user-emacs-directory))
    (vc-log-incoming)))
    (defun crafted-updates--pull-commits ()
    (message "Pulling latest commits to Crafted Emacs...")
    (with-current-buffer (find-file-noselect (expand-file-name "init.el" user-emacs-directory))
    (vc-pull)))

It's also unfortunate that $CRAFTED_EMACS_HOME was used to mean the crafted-config-path, because it's a more appropriate environment variable name for this new crafted-emacs-directory. Perhaps something like $CRAFTED_EMACS_BASE, $CRAFTED_EMACS_ROOT, or $CRAFTED_EMACS_MODULES would suffice.

@jeffbowman
Copy link
Contributor

There are definitely places where crafted-emacs assumes it's in user-emacs-directory, so at the very least a new crafted-emacs-directory variable needs introduced and used in modules:

Yes, of course, if you look at the code, we assume the user followed the read me, cloned the repo and is running Emacs with the cloned code in the user-emacs-directory ala $HOME/.config/emacs or $HOME/.emacs.d. The first example compiles Crafted Emacs modules which are found in the user-emacs-directory. The second example is for pulling changes to Crafted Emacs from GitHub, again because we expect the code for the project to be cloned in the user-emacs-directory which is where the init.el file would reside.

A new variable crafted-emacs-directory would be appropriate if this project were more of a library (or a package) than a starter kit. At the moment, crafted-emacs-directory would be an alias for user-emacs-directory. As Crafted Emacs is not a package, modules or other configuration assuming the usage of user-emacs-directory is appropriate.

It's also unfortunate that $CRAFTED_EMACS_HOME was used to mean the crafted-config-path, because it's a more appropriate environment variable name for this new crafted-emacs-directory. Perhaps something like $CRAFTED_EMACS_BASE, $CRAFTED_EMACS_ROOT, or $CRAFTED_EMACS_MODULES would suffice.

Thank you for voicing your opinion. My opinion is the choice of name is appropriate for the intended use. I do make an effort to please as many as possible with the updates and changes and initial decisions on this project, however, it's impossible to please everyone.

@mattmc3
Copy link
Contributor Author

mattmc3 commented Dec 14, 2022

Thank you for voicing your opinion. My opinion is the choice of name is appropriate for the intended use. I do make an effort to please as many as possible with the updates and changes and initial decisions on this project, however, it's impossible to please everyone.

I meant no offense - perhaps I wasn't clear. I was actually looking for your input on what your preference was for an environment variable name for this new crafted-emacs-directory variable should be since $CRAFTED_EMACS_HOME was already taken. This will help me as I work on a PR.

@jeffbowman
Copy link
Contributor

I meant no offense

None taken. :-)

I was actually looking for your input on what your preference was for an environment variable name for this new crafted-emacs-directory variable should be since $CRAFTED_EMACS_HOME was already taken. This will help me as I work on a PR.

If your intention is to be able to use the modules independently of Crafted Emacs, perhaps a crafted-module-directory with possibly $CRAFTED_MODULE_DIRECTORY as an environment variable. In theory, such a variable could be added to the load-path by the user in their own init.el or whatever they are using when configuring their Emacs.

Assume this snippet in early-init.el (in Crafted Emacs):
(customize-set-variable crafted-module-directory (expand-file-name "modules" user-emacs-directory))

Then in init.el
(add-to-list 'load-path crafted-module-directory)

Then in appropriate modules (for example the crafted-compile.el you mention above)
,crafted-module-directory

crafted-updates.el becomes more interesting as it is looking for the cloned repo, so something like:
(directory-file-name (expand-file-name ".." crafted-module-directory)) might be needed to set the default-directory or some variable to be used through-out that module so the correct folder is used when running the vc commands.

Does this help?

@ajxn
Copy link
Contributor

ajxn commented Dec 31, 2022

So if I understand this correctly, if one want to use Crafted-emacs modules, they can as easy be placed in Emacs load path.

Except for crafted-compile.el that needs to know where the modules are if it should be able to work outside of Crafted-emacs default installation. And there one could set crafted-module-directory to tell where modules are localted to compile. By default crafted-module-directory would be set to user-emacs-directory/modules .

But are crafted-compile that useful outside of Crafted-emacs?

@jeffbowman
Copy link
Contributor

So if I understand this correctly, if one want to use Crafted-emacs modules, they can as easy be placed in Emacs load path.

Pretty much. There are a couple of variables that need to be set and a couple of macro definitions, but basically that's the idea.

Except for crafted-compile.el that needs to know where the modules are if it should be able to work outside of Crafted-emacs default installation. And there one could set crafted-module-directory to tell where modules are localted to compile. By default crafted-module-directory would be set to user-emacs-directory/modules .

But are crafted-compile that useful outside of Crafted-emacs?

That one specifically may not be as useful outside of Crafted Emacs, at least not in it's current form. With Emacs 29 possibly bringing native compilation as the default, that module may have less of a future than when it was originally written.

@Remillard
Copy link

Teeing off @jeffbowman's comment earlier, using a Crafted module from my own init.el really didn't take a whole lot, most of which was ripped almost verbatim out of ~/.config/emacs/early.init.el)

;;
;; Additional modules (some from Crafted Emacs)
;;
(add-to-list 'load-path (expand-file-name "site-lisp/" user-emacs-directory))
(add-to-list 'load-path (expand-file-name "crafted-lisp/" user-emacs-directory))
;;
;; Setting up package retrieval with `package.el` and using Crafted Emacs
;; bootstrap file.
;;
(defvar crafted-config-path user-emacs-directory)
(defvar crafted-config-var-directory (expand-file-name "var/" crafted-config-path))
(defvar crafted-config-etc-directory (expand-file-name "etc/" crafted-config-path))
(defvar crafted-bootstrap-directory (expand-file-name "crafted-lisp/" crafted-config-path)
  "Package system bootstrap configuration.")
(load (expand-file-name "crafted-package.el" crafted-bootstrap-directory))
(crafted-package-bootstrap crafted-package-system)
;;
;; ... Time passes ...
;;
(require 'crafted-completion)

The reason was much as expressed above. I had a pretty involved init.el already, but I wanted some slightly more modern features without a great deal of fuss (there's a whole saga of company being a butt and wanting some sane defaults for vertico, marginalia, etc). Not super wild about having the modules I desired culled out of version control, but with a little extra work I could easily put the repo somewhere convenient and then alter the defvars to point there and I think it'd work just as well.

@jeffbowman jeffbowman self-assigned this Feb 10, 2023
@jeffbowman
Copy link
Contributor

This will close when I release the next version of crafted-emacs. See my blog for what is happening:

@jeffbowman
Copy link
Contributor

Closing in anticipation of Crafted Emacs v2, which (should) resolve this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants