guix-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Creating an Emacs Home Configuration Service


From: Zain Jabbar
Subject: Re: Creating an Emacs Home Configuration Service
Date: Mon, 17 Oct 2022 13:12:29 -1000

Aloha Guix Development Team,

Thank you for this email. Your advice was directed very kindly and is
very helpful. I have tried to revise the code based on your email. I
also checked the setting for plaintext mode in GMail; I hope this
makes the email easier to read.

First, I define a configuration (without serialization currently).

#+BEGIN_SRC scheme
(define file-likes? (list-of file-like?))

(define-configuration/no-serialization emacs-configuration
  (emacs-packages
   (file-likes (list (specification->package "emacs-next"))) "Files")
  (early-init
   (list '()) "Early-Init")
  (init
   (list '()) "Init"))
#+END_SRC

Then, I define an =emacs-configuration-service= that takes in a
configuration. This service will add packages in the =emacs-packages=
to the profile, and append the S-Expressions in =early-init= and
=init= to $XDG_CONFIG_HOME/emacs/early-init.el and
$XDG_CONFIG_HOME/emacs/init.el respectively. The service has
definition,

#+BEGIN_SRC scheme
(define-public emacs-configuration-service
  (service-type (name (symbol-append 'emacs-configuration))
(extensions
(list (service-extension
home-profile-service-type
(lambda (config) (emacs-configuration-emacs-packages config)))
       (service-extension
home-xdg-configuration-files-service-type
(lambda (config)
  (list
   `("emacs/init.el" ,(scheme-file "init.el"
  (emacs-configuration-init config)
  #:splice? #:t))
   `("emacs/early-init.el" ,(scheme-file "early-init.el"
  (emacs-configuration-early-init config)
  #:splice? #:t)))))))
(default-value (emacs-configuration))
(description "Configures Emacs init.el")))
#+END_SRC

This version of the service is one big service that only takes in one
configuration file. So in order to configure bits and pieces of Emacs,
for example evil-mode and vertico we can append emacs-configurations
into one big configuration. I do this as follows.

#+BEGIN_SRC scheme
(define evil-configuration
  (emacs-configuration
   (emacs-packages (list (specification->package "emacs-evil")))
   (init '((evil-mode 1)))))

(define vertico-configuration
  (emacs-configuration
   (emacs-packages (list (specification->package "emacs-vertico")))
   (init '((vertico-mode 1)))))

(define-public total-emacs-configuration
  (fold (lambda (config-1 config-2) (emacs-configuration
     (init (append (emacs-configuration-init config-1)
   (emacs-configuration-init config-2)))
     (early-init (append (emacs-configuration-early-init config-1)
(emacs-configuration-early-init config-2)))
     (emacs-packages (append (emacs-configuration-emacs-packages config-1)
     (emacs-configuration-emacs-packages config-2)))))
(emacs-configuration)
(list evil-configuration vertico-configuration)))
#+END_SRC

We can actually go crazy with this idea. The next source block is a
generalization of the last one. Rather than declaring the list of
configurations, we have Guile figure out all of the bound
=emacs-configurations= in the current module and append them that way.

#+BEGIN_SRC scheme
(define-public total-emacs-configuration
  (fold (lambda (config-1 config-2) (emacs-configuration
     (init (append (emacs-configuration-init config-1)
   (emacs-configuration-init config-2)))
     (early-init (append (emacs-configuration-early-init config-1)
(emacs-configuration-early-init config-2)))
     (emacs-packages (append (emacs-configuration-emacs-packages config-1)
     (emacs-configuration-emacs-packages config-2)))))
(emacs-configuration)

(filter emacs-configuration?
(map variable-ref
     (filter variable-bound?
     (hash-map->list (lambda (x y) y) (struct-ref (current-module) 0)))))))
#+END_SRC

What further improvements could I add to this system? The end goal
(hopefully) is to help add another home service to Guix. I was
inspired by David Wilson's call to action during his Guix Home talk at
the 10 year anniversary event.



On Mon, Oct 17, 2022 at 12:09 PM <jbranso@dismail.de> wrote:
>
> October 17, 2022 2:38 AM, "Zain Jabbar" <zaijab2000@gmail.com> wrote:
>
> > Aloha Guix Development Team,
> >
> > Running =guix home search emacs= returns nothing. I also could not find an 
> > email using =C-u M-x
> > debbugs-gnu= about an Emacs configuration service.
> >
> > This is my first email to this mailing address. Please give me pointers on 
> > formatting and further
> > improvements.
>
> I think you sent an html email.  Generally you want to send plain text 
> emails.  :)
>
> > I have attempted to make an =emacs-home-service-type= so that it is 
> > possible to configure Emacs
> > using Guix home. This code is extremely preliminary hence I don't even 
> > think it is worth sending as
> > a patch. Also I have never worked on a multi person Git project before and 
> > do not know how to solve
> > the keyring error I get when using guix pull. I will outline what my code 
> > does and what features I
> > would like to add.
> >
> > #+BEGIN_SRC scheme
> > (define* (emacs-configuration-service name #:key (init '()) (early-init 
> > '()) (emacs-packages '()))
> > (service-type (name (symbol-append 'emacs- name '-configuration))
> > (extensions
> > (list (service-extension
> > home-profile-service-type
> > (lambda (config) emacs-packages))
> > (service-extension
> > home-files-service-type
> > (lambda (config)
> > (list
> > `(,(string-append
> > ".config/emacs/services/" (symbol->string name) ".el")
> > ,(scheme-file (string-append (symbol->string name) ".el")
> > init #:splice? #t))
> > `(,(string-append
> > ".config/emacs/early-services/" (symbol->string name) ".el")
> > ,(scheme-file (string-append "early-" (symbol->string name) ".el")
> > early-init #:splice? #t)))))))
> > (default-value #f)
> > (description "Configures Emacs init.el")))
> >
> > (define-public emacs-init-service-type
> > (service-type (name 'home-emacs)
> > (extensions
> > (list (service-extension
> > home-profile-service-type
> > (lambda (config) (list emacs-next)))
> > (service-extension
> > home-files-service-type
> > (lambda (config)
> > (list
> > `(".config/emacs/early-init.el"
> > ,(scheme-file
> > "early-init.el"
> > '((mapc
> > 'load (file-expand-wildcards
> > "~/.config/emacs/early-services/*.el")))
> > #:splice? #t))
> > `(".config/emacs/init.el"
> > ,(scheme-file
> > "init.el"
> > '((mapc
> > 'load (file-expand-wildcards
> > "~/.config/emacs/services/*.el")))
> > #:splice? #t)))))))
> > (default-value #f)
> > (description "Configures Emacs init.el")))
> > #+END_SRC
> >
> > I define a general configuration service generator which takes in four 
> > things:
> > 1. The =name= of the service
> > 2. The configuration to be ran in =init.el=
> > 3. The configuration to be ran in =early-init.el=
> > 4. The packages in Guix to be added to the =home-profile=.
> >
> > After giving the =name=, =packages=, and =config.el= files we get a new 
> > service type that we can
> > add to our home declaration. This service will then add a file in
> > =~/.config/emacs/services/emacs-{NAME}-configuration.el=. I then have 
> > another service that places
> > an =init.el= which loads everything in the service directory.
> >
> > If we want to install and configure =evil-mode= using this =home-service= 
> > we may define the
> > following somewhere.
> >
> > #+BEGIN_SRC scheme
> > (define-public emacs-evil-service-type
> > (emacs-configuration-service
> > 'evil #:emacs-packages (list emacs-evil)
> > #:init '((evil-mode 1))))
> > #+END_SRC
> >
> > Within our =home-environment= we may add the service using:
> >
> > #+BEGIN_SRC scheme
> > (home-environment
> > ;; ...Things in the home-environment...
> > (services
> > (list
> > ;; ...Other Services...
> > (service emacs-evil-service-type))))
> > #+END_SRC
> >
> > There are some missing features I want to add.
> >
> > 1. Have the =home-emacs-*-service-type= service-types add to the =init.el= 
> > directly rather than
> > within a folder to be loaded. I couldn't add two files with the same name 
> > to the store. So I have
> > emacs-evil.el in the store to be placed separately later rather than 
> > appending to the existing
> > init.el file.
> >
> > 2. Have Emacs update whenever the =home-environment= is updated. Meaning, 
> > if I did not add
> > =(service emacs-evil-service-type)= in my =home-environment= then obviously 
> > =M-x evil-mode= should
> > not work. But after adding the service then I want =M-x evil-mode= to work 
> > without having to
> > restart Emacs. I do not understand the Emacs loading system on Guix well 
> > enough to know why it does
> > not work. Skipping all of the =home-service= stuff, running =guix install 
> > emacs-evil-mode= then
> > =(guix-emacs-autoload-packages)= does not let emacs know that =evil-mode= 
> > is installed. I would
> > need to close Emacs and start Emacs again for Emacs to know about 
> > =evil-mode= being installed.
> >
> > 3. Use configurations somehow. I have completely neglected this feature in 
> > my system. I do not know
> > what would be useful there.
>
> I believe that you are referring to using scheme records to configure the 
> emacs service.  :)
>
> I would recommend using (define-configuration ...) procedure.
>
> (There is a define-record-type* as well, but I think the consensus is that
> define-configuration* is a little easier to use.  Does better error handling
> and can help you generate documentation from the code).
>
> You can find examples of that here:
>
> https://git.savannah.gnu.org/cgit/guix.git/tree/gnu/services/mail.scm
>
> >
> > --
> > Thank you,
> > Zain Jabbar



--
Thank you,
Zain Jabbar

On Mon, Oct 17, 2022 at 12:09 PM <jbranso@dismail.de> wrote:
>
> October 17, 2022 2:38 AM, "Zain Jabbar" <zaijab2000@gmail.com> wrote:
>
> > Aloha Guix Development Team,
> >
> > Running =guix home search emacs= returns nothing. I also could not find an 
> > email using =C-u M-x
> > debbugs-gnu= about an Emacs configuration service.
> >
> > This is my first email to this mailing address. Please give me pointers on 
> > formatting and further
> > improvements.
>
> I think you sent an html email.  Generally you want to send plain text 
> emails.  :)
>
> > I have attempted to make an =emacs-home-service-type= so that it is 
> > possible to configure Emacs
> > using Guix home. This code is extremely preliminary hence I don't even 
> > think it is worth sending as
> > a patch. Also I have never worked on a multi person Git project before and 
> > do not know how to solve
> > the keyring error I get when using guix pull. I will outline what my code 
> > does and what features I
> > would like to add.
> >
> > #+BEGIN_SRC scheme
> > (define* (emacs-configuration-service name #:key (init '()) (early-init 
> > '()) (emacs-packages '()))
> > (service-type (name (symbol-append 'emacs- name '-configuration))
> > (extensions
> > (list (service-extension
> > home-profile-service-type
> > (lambda (config) emacs-packages))
> > (service-extension
> > home-files-service-type
> > (lambda (config)
> > (list
> > `(,(string-append
> > ".config/emacs/services/" (symbol->string name) ".el")
> > ,(scheme-file (string-append (symbol->string name) ".el")
> > init #:splice? #t))
> > `(,(string-append
> > ".config/emacs/early-services/" (symbol->string name) ".el")
> > ,(scheme-file (string-append "early-" (symbol->string name) ".el")
> > early-init #:splice? #t)))))))
> > (default-value #f)
> > (description "Configures Emacs init.el")))
> >
> > (define-public emacs-init-service-type
> > (service-type (name 'home-emacs)
> > (extensions
> > (list (service-extension
> > home-profile-service-type
> > (lambda (config) (list emacs-next)))
> > (service-extension
> > home-files-service-type
> > (lambda (config)
> > (list
> > `(".config/emacs/early-init.el"
> > ,(scheme-file
> > "early-init.el"
> > '((mapc
> > 'load (file-expand-wildcards
> > "~/.config/emacs/early-services/*.el")))
> > #:splice? #t))
> > `(".config/emacs/init.el"
> > ,(scheme-file
> > "init.el"
> > '((mapc
> > 'load (file-expand-wildcards
> > "~/.config/emacs/services/*.el")))
> > #:splice? #t)))))))
> > (default-value #f)
> > (description "Configures Emacs init.el")))
> > #+END_SRC
> >
> > I define a general configuration service generator which takes in four 
> > things:
> > 1. The =name= of the service
> > 2. The configuration to be ran in =init.el=
> > 3. The configuration to be ran in =early-init.el=
> > 4. The packages in Guix to be added to the =home-profile=.
> >
> > After giving the =name=, =packages=, and =config.el= files we get a new 
> > service type that we can
> > add to our home declaration. This service will then add a file in
> > =~/.config/emacs/services/emacs-{NAME}-configuration.el=. I then have 
> > another service that places
> > an =init.el= which loads everything in the service directory.
> >
> > If we want to install and configure =evil-mode= using this =home-service= 
> > we may define the
> > following somewhere.
> >
> > #+BEGIN_SRC scheme
> > (define-public emacs-evil-service-type
> > (emacs-configuration-service
> > 'evil #:emacs-packages (list emacs-evil)
> > #:init '((evil-mode 1))))
> > #+END_SRC
> >
> > Within our =home-environment= we may add the service using:
> >
> > #+BEGIN_SRC scheme
> > (home-environment
> > ;; ...Things in the home-environment...
> > (services
> > (list
> > ;; ...Other Services...
> > (service emacs-evil-service-type))))
> > #+END_SRC
> >
> > There are some missing features I want to add.
> >
> > 1. Have the =home-emacs-*-service-type= service-types add to the =init.el= 
> > directly rather than
> > within a folder to be loaded. I couldn't add two files with the same name 
> > to the store. So I have
> > emacs-evil.el in the store to be placed separately later rather than 
> > appending to the existing
> > init.el file.
> >
> > 2. Have Emacs update whenever the =home-environment= is updated. Meaning, 
> > if I did not add
> > =(service emacs-evil-service-type)= in my =home-environment= then obviously 
> > =M-x evil-mode= should
> > not work. But after adding the service then I want =M-x evil-mode= to work 
> > without having to
> > restart Emacs. I do not understand the Emacs loading system on Guix well 
> > enough to know why it does
> > not work. Skipping all of the =home-service= stuff, running =guix install 
> > emacs-evil-mode= then
> > =(guix-emacs-autoload-packages)= does not let emacs know that =evil-mode= 
> > is installed. I would
> > need to close Emacs and start Emacs again for Emacs to know about 
> > =evil-mode= being installed.
> >
> > 3. Use configurations somehow. I have completely neglected this feature in 
> > my system. I do not know
> > what would be useful there.
>
> I believe that you are referring to using scheme records to configure the 
> emacs service.  :)
>
> I would recommend using (define-configuration ...) procedure.
>
> (There is a define-record-type* as well, but I think the consensus is that
> define-configuration* is a little easier to use.  Does better error handling
> and can help you generate documentation from the code).
>
> You can find examples of that here:
>
> https://git.savannah.gnu.org/cgit/guix.git/tree/gnu/services/mail.scm
>
> >
> > --
> > Thank you,
> > Zain Jabbar



-- 
Thank you,
Zain Jabbar



reply via email to

[Prev in Thread] Current Thread [Next in Thread]