[PATCH] gnu: home: Add home-emacs-service-type.

  • Open
  • quality assurance status badge
Details
7 participants
  • Andrew Tropin
  • benoit
  • David Wilson
  • Jelle Licht
  • Ludovic Courtès
  • Reily Siegel
  • (
Owner
unassigned
Submitted by
David Wilson
Severity
normal
D
D
David Wilson wrote on 12 Jan 2023 15:01
(address . guix-patches@gnu.org)
87edrzzw9w.fsf@daviwil.com
This commit continues work by ( to add a home-emacs-service-type for the
purpose of configuring Emacs.

The goal here is not to configure Emacs with Scheme forms, but to make it
possible to assemble init.el and early-init.el using files from one's own personal
configuration and other Emacs Lisp snippets for further customization.

The simplest usage of the service would be to use simple strings or local
files to build init.el and early-init.el:

(home-environment
(services (list
(service home-emacs-service-type
(home-emacs-configuration
(init-file (list (local-file "init.el")))
(early-init-file '(";; This is early-init.el!\n")))))))

The `emacs-variable' function can be used to generate a g-expression which
will produce a `setq' form inside of an init file:

(home-emacs-configuration
(init-file (list (emacs-variables
'((my/font-size . 24)
(my/tab-width . 2)
(inhibit-startup-message . #t)))
(local-file "init.el"))))

If you have an existing folder of Emacs Lisp files that you `require' into
your configuration, you can use the `load-paths' field to pull in the entire
folder or reference the existing files on your system:

(home-emacs-configuration
(init-file (list "(require 'my-init)"))
(load-paths (list (local-file "emacs-modules"
#:recursive #t))))

Since Emacs loves to write files to `user-emacs-directory', we must provide a
writeable path for it so that Emacs doesn't try to write files into the
read-only store. The `user-emacs-directory' field can be used to customize
that; it defaults to `~/.cache/emacs'.

Other services can extend home-emacs-service-type with the
home-emacs-extension type to add further configuration snippets, packages, and
load paths:

(home-environment
(services
(list (service home-emacs-service-type
(home-emacs-configuration
(init-file (list "(require 'my-module)\n"))))

(simple-service 'home-emacs-extension-one
home-emacs-service-type
(home-emacs-extension
(packages (list (specification->package "emacs-evil")))
(init-file (list "(evil-mode +1)\n")))))))

Co-authored-by: ( <paren@disroot.org>
---
doc/guix.texi | 77 +++++++++++++++
gnu/home/services/emacs.scm | 188 ++++++++++++++++++++++++++++++++++++
gnu/local.mk | 1 +
3 files changed, 266 insertions(+)
create mode 100644 gnu/home/services/emacs.scm

Toggle diff (308 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 751d0957d8..62fefde1ea 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -111,6 +111,7 @@ Copyright @copyright{} 2022 (@*
Copyright @copyright{} 2022 John Kehayias@*
Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@*
Copyright @copyright{} 2023 Giacomo Leidi@*
+Copyright @copyright{} 2023 David Wilson@*

Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -41061,6 +41062,7 @@ services)}.
* Shepherd: Shepherd Home Service. Managing User's Daemons.
* SSH: Secure Shell. Setting up the secure shell client.
* Desktop: Desktop Home Services. Services for graphical environments.
+* Emacs: Emacs Home Services. Services for configuring Emacs.
* Guix: Guix Home Services. Services for Guix.
@end menu
@c In addition to that Home Services can provide
@@ -41914,6 +41916,81 @@ The package providing the @code{/bin/dbus-daemon} command.
@end table
@end deftp

+@node Emacs Home Services
+@subsection Emacs Home Services
+
+@defvr {Scheme Variable} home-emacs-service-type
+This is the service type for configuring the Emacs text editor. It
+enables you to assemble @file{init.el} and @file{early-init.el} files
+from snippets in your home configuration and other Emacs Lisp files you
+have in your personal configuration folder.
+
+This service can be extended using the @code{home-emacs-extension} type.
+
+Note that if you have an existing @file{~/.emacs} and/or
+@file{~/.emacs.d}, the configuration aspect of this service will not be
+loaded, as the former location takes precedence over
+@file{~/.config/emacs}. This service uses the latter path in the
+interest of cleanliness. To migrate to the XDG directory, run these
+commands:
+
+@example
+$ cp ~/.emacs.d $XDG_CONFIG_HOME/emacs
+$ cp ~/.emacs $XDG_CONFIG_HOME/emacs/init.el
+@end example
+@end defvr
+
+@deftp {Data Type} home-emacs-configuration
+The configuration record for @code{home-emacs-service-type}.
+
+@table @asis
+@item @code{emacs} (default: @code{emacs})
+The package providing the @file{/bin/emacs} command.
+
+@item @code{packages} (default: @code{'()})
+Additional packages required by the Emacs configuration.
+
+@item @code{user-emacs-directory} (default: @file{~/.cache/emacs})
+The directory beneath which additional per-user Emacs-specific files are placed.
+
+@item @code{init-file} (default: @code{'()})
+Configuration text or files to include in @file{init.el}.
+
+@item @code{early-init-file} (default: @code{'()})
+Configuration text or files to include in @file{early-init.el}.
+
+@item @code{load-paths} (default: @code{'()})
+Additional load paths to add to Emacs' @code{load-path} variable. Lines
+will be inserted at the beginning of @file{early-init.el}.
+
+@item @code{native-compile?} (default: @code{#f})
+Whether to compile all @code{packages}, using the provided @code{emacs}
+package in place of @code{emacs-minimal}, which will enable native
+compilation if the @code{emacs} package supports it. All
+non-@code{-minimal} Emacs packages at version 28 or above should support
+native compilation.
+@end table
+@end deftp
+
+@deftp {Data Type} home-emacs-extension
+The extension record for @code{home-emacs-service-type}.
+
+@table @asis
+@item @code{packages} (default: @code{'()})
+Additional packages required by the Emacs configuration.
+
+@item @code{init-file} (default: @code{'()})
+Configuration text or files to include in @file{init.el}.
+
+@item @code{early-init-file} (default: @code{'()})
+Configuration text or files to include in @file{early-init.el}.
+
+@item @code{load-paths} (default: @code{'()})
+Additional load paths to add to Emacs' @code{load-path} variable. Lines
+will be inserted at the beginning of @file{early-init.el}.
+@end table
+@end deftp
+
@node Guix Home Services
@subsection Guix Home Services

diff --git a/gnu/home/services/emacs.scm b/gnu/home/services/emacs.scm
new file mode 100644
index 0000000000..45b4f2a5d6
--- /dev/null
+++ b/gnu/home/services/emacs.scm
@@ -0,0 +1,188 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 ( <paren@disroot.org>
+;;; Copyright © 2023 David Wilson <david@daviwil.com>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu home services emacs)
+ #:use-module (gnu home services)
+ #:autoload (gnu packages emacs) (emacs-minimal
+ emacs)
+ #:use-module (gnu services configuration)
+ #:use-module (guix gexp)
+ #:use-module (guix packages)
+ #:use-module (guix records)
+ #:use-module (ice-9 match)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
+
+ #:export (emacs-variables
+ home-emacs-configuration
+ home-emacs-extension
+ home-emacs-service-type))
+
+(define list-of-file-likes?
+ (list-of file-like?))
+
+(define (string-or-file-like? val)
+ (or (string? val)
+ (file-like? val)))
+
+(define list-of-string-or-file-likes?
+ (list-of string-or-file-like?))
+
+(define-configuration/no-serialization home-emacs-configuration
+ (emacs
+ (file-like emacs)
+ "The package providing the @file{/bin/emacs} command.")
+ (packages
+ (list-of-file-likes '())
+ "Additional packages required by the Emacs configuration.")
+ (user-emacs-directory
+ (string "~/.cache/emacs")
+ "Directory beneath which additional per-user Emacs-specific files are placed.")
+ (init-file
+ (text-config '())
+ "Configuration text or files to include in init.el.")
+ (early-init-file
+ (text-config '())
+ "Configuration text or files to include in early-init.el.")
+ (load-paths
+ (list-of-string-or-file-likes '())
+ "Additional load paths to add to Emacs' @code{load-path} variable. Lines
+will be inserted at the beginning of early-init.el.")
+ (native-compile?
+ (boolean #f)
+ "Whether to compile the @code{packages} using the Emacs package
+provided as the value of the @code{emacs} field, which will enable
+native compilation if the @code{emacs} package supports it."))
+
+(define (home-emacs-profile-packages config)
+ (cons (home-emacs-configuration-emacs config)
+ (home-emacs-configuration-packages config)))
+
+(define (home-emacs-transformed-packages config)
+ (map (if (home-emacs-configuration-native-compile? config)
+ (package-input-rewriting
+ `((,emacs-minimal
+ . ,(home-emacs-configuration-emacs config))))
+ identity)
+ (let ((packages (home-emacs-configuration-packages config)))
+ (concatenate
+ (cons packages
+ (map (compose (cute map second <>)
+ package-transitive-propagated-inputs)
+ packages))))))
+
+(define (serialize-emacs-load-paths config)
+ #~(string-append
+ ";; Additional load paths\n"
+ #$@(map (lambda (load-path)
+ #~(format #f "(add-to-list 'load-path \"~a\")" #$load-path))
+ (home-emacs-configuration-load-paths config))
+ "\n\n"))
+
+(define (serialize-emacs-user-directory config)
+ (format #f
+ ";; Set the `user-emacs-directory` to a writeable path\n(setq user-emacs-directory \"~a\")\n\n"
+ (home-emacs-configuration-user-emacs-directory config)))
+
+(define (home-emacs-xdg-configuration-files config)
+ `(("emacs/early-init.el"
+ ,(apply mixed-text-file
+ (cons* "early-init.el"
+ (serialize-emacs-load-paths config)
+ (serialize-emacs-user-directory config)
+ (home-emacs-configuration-early-init-file config))))
+ ("emacs/init.el"
+ ,(apply mixed-text-file
+ (cons "init.el"
+ (home-emacs-configuration-init-file config))))))
+
+(define-configuration/no-serialization home-emacs-extension
+ (packages
+ (list-of-file-likes '())
+ "Additional packages required by the Emacs configuration.")
+ (init-file
+ (text-config '())
+ "Configuration text or files to include in init.el.")
+ (early-init-file
+ (text-config '())
+ "Configuration text or files to include in early-init.el.")
+ (load-paths
+ (list-of-string-or-file-likes '())
+ "Additional load paths to add to Emacs' @code{load-path} variable. Lines
+will be inserted at the beginning of early-init.el."))
+
+(define (home-emacs-extensions original-config extension-configs)
+ (match-record original-config <home-emacs-configuration>
+ (packages load-paths init-file early-init-file)
+ (home-emacs-configuration
+ (inherit original-config)
+ (packages
+ (append packages
+ (append-map
+ home-emacs-extension-packages extension-configs)))
+ (init-file
+ (append init-file
+ (append-map
+ home-emacs-extension-init-file extension-configs)))
+ (early-init-file
+ (append early-init-file
+ (append-map
+ home-emacs-extension-early-init-file extension-configs)))
+ (load-paths
+ (append load-paths
+ (append-map
+ home-emacs-extension-load-paths extension-configs))))))
+
+(define home-emacs-service-type
+ (service-type
+ (name 'home-emacs)
+ (extensions
+ (list (service-extension
+ home-profile-service-type
+ home-emacs-profile-packages)
+ (service-extension
+ home-shepherd-service-type
+ home-emacs-shepherd-services)
+ (service-extension
+ home-xdg-configuration-files-service-type
+ home-emacs-xdg-configuration-files)))
+ (default-value (home-emacs-configuration))
+ (compose identity)
+ (extend home-emacs-extensions)
+ (description
+ "Configure the GNU Emacs extensible text editor.")))
+
+(define scheme-value->emacs-value
+ (match-lambda (#t (quote 't))
+ (#f (quote 'nil))
+ (val val)))
+
+(define (emacs-variables var-alist)
+ "Converts an alist of variable names and values into a @code{setq}
+expression that can be used in an Emacs configuration. Scheme values
+@code{#t} and @code{#f} will be converted into @code{t} and @code{nil},
+respectively."
+ #~(string-append
+ "(setq"
+ #$@(map (lambda (var)
+ #~(format #f "\n ~a ~s"
+ (quote #$(car var))
+ #$(scheme-value->emacs-value (cdr var))))
+ var-alist)
+ ")\n\n"))
diff --git a/gnu/local.mk b/gnu/local.mk
index 184f43e753..35d88b4dd6 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -89,6 +89,7 @@ GNU_SYSTEM_MODULES = \
%D%/home/services.scm \
%D%/home/services/desktop.scm \
%D%/home/services/symlink-manager.scm \
+ %D%/home/services/emacs.scm \
%D%/home/services/fontutils.scm \
%D%/home/services/guix.scm \
%D%/home/services/pm.scm \
--
2.38.1
(
CPQDXQ30UBKT.1VEXSMLFNRVE2@guix-framework
On Thu Jan 12, 2023 at 2:01 PM GMT, David Wilson wrote:
Toggle quote (4 lines)
> + (service-extension
> + home-shepherd-service-type
> + home-emacs-shepherd-services)

home-emacs-shepherd-services isn't defined here :( Doesn't this cause an unbound-variable
error? (Also, most of the reason I wrote this service was to support auto-starting emacs
--daemon :))

-- (
-----BEGIN PGP SIGNATURE-----

iQGzBAABCgAdFiEE6Vh10NblKE5doNlW7ImHg/nqI20FAmPAQlsACgkQ7ImHg/nq
I23juwwAwQqaBOQpEv2kdxPodyPHIUkIdq6O26kvBMwqArXrhbBlLz/oywf6hFUU
4HKrefIRNepZAFJBPcSIWAP4yywdQ7lvzCgOBoHj2bhQ+Ollvna4CsrbAbnoehf2
uhEDI/gsxomHbdLs9GeIf7qx+Z4JWYzma296GTq7deimk0xcfyCf8O69WsnLSFry
mMyBCimuJ4JlmRgmy9ekbwdSoDqx/vqL2oCwUHUOR6GY48wB3BsSd/4lRMZvLBY2
aUr0Pa1zh3yAC+thi3OCEX9FRMGU6TOldPA9xDVMcmamJuYNjZ3Z7X8Eb3WKrLYX
H2+G9JXQ/Rqk3bHajZvpjOyFcDRNm4jrx0h7214dju89ZGq7RB6EcUMAAsUIwCX+
bmibAd5Px+Ecyf6tlfyJbZY34UTazvVnpaBD0f/xs/jmtEcg+dAM4aioexl3p99I
pC+mTFE192xB3abXPgCqM0qIomm7EdWz69+vjqGgfejl6oq+HqfreHZBhYWI5eCT
CyIYbEz5
=E5Ys
-----END PGP SIGNATURE-----


D
D
David Wilson wrote on 12 Jan 2023 18:27
(name . ()(address . paren@disroot.org)(address . 60753@debbugs.gnu.org)
87v8lby7jq.fsf@daviwil.com
Hey (!

"(" <paren@disroot.org> writes:
Toggle quote (4 lines)
> home-emacs-shepherd-services isn't defined here :( Doesn't this cause an unbound-variable
> error? (Also, most of the reason I wrote this service was to support auto-starting emacs
> --daemon :))

Whoops, in my haste to send out the patch I forgot to take that out!

Yes, I saw that you meant to run Emacs as a daemon and I think it should
be added to this service (or another daemon-specific service) in a
future patch. I figured it would be easier to get a patch accepted
without the daemon functionality just yet since there seemed to be more
feedback about that aspect in your patch thread.

Here's an update to my patch that actually works (sorry if I'm doing
this wrong, it's been a while since I worked on a patch thread!) --

Co-authored-by: ( <paren@disroot.org>
---
doc/guix.texi | 77 +++++++++++++++
gnu/home/services/emacs.scm | 185 ++++++++++++++++++++++++++++++++++++
gnu/local.mk | 1 +
3 files changed, 263 insertions(+)
create mode 100644 gnu/home/services/emacs.scm

Toggle diff (305 lines)
diff --git a/doc/guix.texi b/doc/guix.texi
index 751d0957d8..62fefde1ea 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -111,6 +111,7 @@ Copyright @copyright{} 2022 (@*
Copyright @copyright{} 2022 John Kehayias@*
Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@*
Copyright @copyright{} 2023 Giacomo Leidi@*
+Copyright @copyright{} 2023 David Wilson@*

Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -41061,6 +41062,7 @@ services)}.
* Shepherd: Shepherd Home Service. Managing User's Daemons.
* SSH: Secure Shell. Setting up the secure shell client.
* Desktop: Desktop Home Services. Services for graphical environments.
+* Emacs: Emacs Home Services. Services for configuring Emacs.
* Guix: Guix Home Services. Services for Guix.
@end menu
@c In addition to that Home Services can provide
@@ -41914,6 +41916,81 @@ The package providing the @code{/bin/dbus-daemon} command.
@end table
@end deftp

+@node Emacs Home Services
+@subsection Emacs Home Services
+
+@defvr {Scheme Variable} home-emacs-service-type
+This is the service type for configuring the Emacs text editor. It
+enables you to assemble @file{init.el} and @file{early-init.el} files
+from snippets in your home configuration and other Emacs Lisp files you
+have in your personal configuration folder.
+
+This service can be extended using the @code{home-emacs-extension} type.
+
+Note that if you have an existing @file{~/.emacs} and/or
+@file{~/.emacs.d}, the configuration aspect of this service will not be
+loaded, as the former location takes precedence over
+@file{~/.config/emacs}. This service uses the latter path in the
+interest of cleanliness. To migrate to the XDG directory, run these
+commands:
+
+@example
+$ cp ~/.emacs.d $XDG_CONFIG_HOME/emacs
+$ cp ~/.emacs $XDG_CONFIG_HOME/emacs/init.el
+@end example
+@end defvr
+
+@deftp {Data Type} home-emacs-configuration
+The configuration record for @code{home-emacs-service-type}.
+
+@table @asis
+@item @code{emacs} (default: @code{emacs})
+The package providing the @file{/bin/emacs} command.
+
+@item @code{packages} (default: @code{'()})
+Additional packages required by the Emacs configuration.
+
+@item @code{user-emacs-directory} (default: @file{~/.cache/emacs})
+The directory beneath which additional per-user Emacs-specific files are placed.
+
+@item @code{init-file} (default: @code{'()})
+Configuration text or files to include in @file{init.el}.
+
+@item @code{early-init-file} (default: @code{'()})
+Configuration text or files to include in @file{early-init.el}.
+
+@item @code{load-paths} (default: @code{'()})
+Additional load paths to add to Emacs' @code{load-path} variable. Lines
+will be inserted at the beginning of @file{early-init.el}.
+
+@item @code{native-compile?} (default: @code{#f})
+Whether to compile all @code{packages}, using the provided @code{emacs}
+package in place of @code{emacs-minimal}, which will enable native
+compilation if the @code{emacs} package supports it. All
+non-@code{-minimal} Emacs packages at version 28 or above should support
+native compilation.
+@end table
+@end deftp
+
+@deftp {Data Type} home-emacs-extension
+The extension record for @code{home-emacs-service-type}.
+
+@table @asis
+@item @code{packages} (default: @code{'()})
+Additional packages required by the Emacs configuration.
+
+@item @code{init-file} (default: @code{'()})
+Configuration text or files to include in @file{init.el}.
+
+@item @code{early-init-file} (default: @code{'()})
+Configuration text or files to include in @file{early-init.el}.
+
+@item @code{load-paths} (default: @code{'()})
+Additional load paths to add to Emacs' @code{load-path} variable. Lines
+will be inserted at the beginning of @file{early-init.el}.
+@end table
+@end deftp
+
@node Guix Home Services
@subsection Guix Home Services

diff --git a/gnu/home/services/emacs.scm b/gnu/home/services/emacs.scm
new file mode 100644
index 0000000000..7a821fed8a
--- /dev/null
+++ b/gnu/home/services/emacs.scm
@@ -0,0 +1,185 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 ( <paren@disroot.org>
+;;; Copyright © 2023 David Wilson <david@daviwil.com>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu home services emacs)
+ #:use-module (gnu home services)
+ #:autoload (gnu packages emacs) (emacs-minimal
+ emacs)
+ #:use-module (gnu services configuration)
+ #:use-module (guix gexp)
+ #:use-module (guix packages)
+ #:use-module (guix records)
+ #:use-module (ice-9 match)
+ #:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-26)
+
+ #:export (emacs-variables
+ home-emacs-configuration
+ home-emacs-extension
+ home-emacs-service-type))
+
+(define list-of-file-likes?
+ (list-of file-like?))
+
+(define (string-or-file-like? val)
+ (or (string? val)
+ (file-like? val)))
+
+(define list-of-string-or-file-likes?
+ (list-of string-or-file-like?))
+
+(define-configuration/no-serialization home-emacs-configuration
+ (emacs
+ (file-like emacs)
+ "The package providing the @file{/bin/emacs} command.")
+ (packages
+ (list-of-file-likes '())
+ "Additional packages required by the Emacs configuration.")
+ (user-emacs-directory
+ (string "~/.cache/emacs")
+ "Directory beneath which additional per-user Emacs-specific files are placed.")
+ (init-file
+ (text-config '())
+ "Configuration text or files to include in init.el.")
+ (early-init-file
+ (text-config '())
+ "Configuration text or files to include in early-init.el.")
+ (load-paths
+ (list-of-string-or-file-likes '())
+ "Additional load paths to add to Emacs' @code{load-path} variable. Lines
+will be inserted at the beginning of early-init.el.")
+ (native-compile?
+ (boolean #f)
+ "Whether to compile the @code{packages} using the Emacs package
+provided as the value of the @code{emacs} field, which will enable
+native compilation if the @code{emacs} package supports it."))
+
+(define (home-emacs-profile-packages config)
+ (cons (home-emacs-configuration-emacs config)
+ (home-emacs-configuration-packages config)))
+
+(define (home-emacs-transformed-packages config)
+ (map (if (home-emacs-configuration-native-compile? config)
+ (package-input-rewriting
+ `((,emacs-minimal
+ . ,(home-emacs-configuration-emacs config))))
+ identity)
+ (let ((packages (home-emacs-configuration-packages config)))
+ (concatenate
+ (cons packages
+ (map (compose (cute map second <>)
+ package-transitive-propagated-inputs)
+ packages))))))
+
+(define (serialize-emacs-load-paths config)
+ #~(string-append
+ ";; Additional load paths\n"
+ #$@(map (lambda (load-path)
+ #~(format #f "(add-to-list 'load-path \"~a\")" #$load-path))
+ (home-emacs-configuration-load-paths config))
+ "\n\n"))
+
+(define (serialize-emacs-user-directory config)
+ (format #f
+ ";; Set the `user-emacs-directory` to a writeable path\n(setq user-emacs-directory \"~a\")\n\n"
+ (home-emacs-configuration-user-emacs-directory config)))
+
+(define (home-emacs-xdg-configuration-files config)
+ `(("emacs/early-init.el"
+ ,(apply mixed-text-file
+ (cons* "early-init.el"
+ (serialize-emacs-load-paths config)
+ (serialize-emacs-user-directory config)
+ (home-emacs-configuration-early-init-file config))))
+ ("emacs/init.el"
+ ,(apply mixed-text-file
+ (cons "init.el"
+ (home-emacs-configuration-init-file config))))))
+
+(define-configuration/no-serialization home-emacs-extension
+ (packages
+ (list-of-file-likes '())
+ "Additional packages required by the Emacs configuration.")
+ (init-file
+ (text-config '())
+ "Configuration text or files to include in init.el.")
+ (early-init-file
+ (text-config '())
+ "Configuration text or files to include in early-init.el.")
+ (load-paths
+ (list-of-string-or-file-likes '())
+ "Additional load paths to add to Emacs' @code{load-path} variable. Lines
+will be inserted at the beginning of early-init.el."))
+
+(define (home-emacs-extensions original-config extension-configs)
+ (match-record original-config <home-emacs-configuration>
+ (packages load-paths init-file early-init-file)
+ (home-emacs-configuration
+ (inherit original-config)
+ (packages
+ (append packages
+ (append-map
+ home-emacs-extension-packages extension-configs)))
+ (init-file
+ (append init-file
+ (append-map
+ home-emacs-extension-init-file extension-configs)))
+ (early-init-file
+ (append early-init-file
+ (append-map
+ home-emacs-extension-early-init-file extension-configs)))
+ (load-paths
+ (append load-paths
+ (append-map
+ home-emacs-extension-load-paths extension-configs))))))
+
+(define home-emacs-service-type
+ (service-type
+ (name 'home-emacs)
+ (extensions
+ (list (service-extension
+ home-profile-service-type
+ home-emacs-profile-packages)
+ (service-extension
+ home-xdg-configuration-files-service-type
+ home-emacs-xdg-configuration-files)))
+ (default-value (home-emacs-configuration))
+ (compose identity)
+ (extend home-emacs-extensions)
+ (description
+ "Configure the GNU Emacs extensible text editor.")))
+
+(define scheme-value->emacs-value
+ (match-lambda (#t (quote 't))
+ (#f (quote 'nil))
+ (val val)))
+
+(define (emacs-variables var-alist)
+ "Converts an alist of variable names and values into a @code{setq}
+expression that can be used in an Emacs configuration. Scheme values
+@code{#t} and @code{#f} will be converted into @code{t} and @code{nil},
+respectively."
+ #~(string-append
+ "(setq"
+ #$@(map (lambda (var)
+ #~(format #f "\n ~a ~s"
+ (quote #$(car var))
+ #$(scheme-value->emacs-value (cdr var))))
+ var-alist)
+ ")\n\n"))
diff --git a/gnu/local.mk b/gnu/local.mk
index 184f43e753..35d88b4dd6 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -89,6 +89,7 @@ GNU_SYSTEM_MODULES = \
%D%/home/services.scm \
%D%/home/services/desktop.scm \
%D%/home/services/symlink-manager.scm \
+ %D%/home/services/emacs.scm \
%D%/home/services/fontutils.scm \
%D%/home/services/guix.scm \
%D%/home/services/pm.scm \
--
2.38.1
L
L
Ludovic Courtès wrote on 14 Jan 2023 19:00
Re: bug#60753: [PATCH] gnu: home: Add home-emacs-service-type.
(name . David Wilson)(address . david@daviwil.com)
87k01p8086.fsf_-_@gnu.org
Hello!

David Wilson <david@daviwil.com> skribis:

Toggle quote (6 lines)
> Yes, I saw that you meant to run Emacs as a daemon and I think it should
> be added to this service (or another daemon-specific service) in a
> future patch. I figured it would be easier to get a patch accepted
> without the daemon functionality just yet since there seemed to be more
> feedback about that aspect in your patch thread.

Agree, I think we should add the daemon functionality in a subsequent
patch.

Overall it looks nice to me! Some comments and suggestions:

Toggle quote (5 lines)
> +@node Emacs Home Services
> +@subsection Emacs Home Services
> +
> +@defvr {Scheme Variable} home-emacs-service-type

It would be nice if you could start the section with a few sentences
explaining the rationale and what’s being described here.

Toggle quote (5 lines)
> +This is the service type for configuring the Emacs text editor. It
> +enables you to assemble @file{init.el} and @file{early-init.el} files
> +from snippets in your home configuration and other Emacs Lisp files you
> +have in your personal configuration folder.

Maybe like so:

… to assemble the @file{init.el} (@pxref{Init File,,, emacs, GNU Emacs
Manual}) and @file{early-init.el} (@pxref{Early Init File,,, emacs,
GNU Emacs Manual}) files …

Toggle quote (5 lines)
> +@example
> +$ cp ~/.emacs.d $XDG_CONFIG_HOME/emacs
> +$ cp ~/.emacs $XDG_CONFIG_HOME/emacs/init.el
> +@end example

I’d drop the prompt.

Toggle quote (6 lines)
> +@item @code{init-file} (default: @code{'()})
> +Configuration text or files to include in @file{init.el}.
> +
> +@item @code{early-init-file} (default: @code{'()})
> +Configuration text or files to include in @file{early-init.el}.

What about accepting sexps (or gexps) instead of strings? As in:

(init-file '((require 'whatever) (setq something t)))

Also I find it confusing that it’s either text or files. In the code it
has type ‘text-config’, which means list of file-like objects IIUC, no?

Toggle quote (4 lines)
> +@item @code{load-paths} (default: @code{'()})
> +Additional load paths to add to Emacs' @code{load-path} variable. Lines
> +will be inserted at the beginning of @file{early-init.el}.

Nitpick: I think this should be ‘load-path’ (singular), because it’s one
search path (i.e., a list of directories).

And: s/Additional load paths/Additional directories/

Toggle quote (3 lines)
> +@end table
> +@end deftp

Would be nice to have a couple of commented examples here, like you had
in the first message in this thread. :-)

Toggle quote (3 lines)
> +@deftp {Data Type} home-emacs-extension
> +The extension record for @code{home-emacs-service-type}.

Would be nice to have a sentence above, like “This service type can be
extended with @code{home-emacs-extension} records, described below:”.

Toggle quote (12 lines)
> +@table @asis
> +@item @code{packages} (default: @code{'()})
> +Additional packages required by the Emacs configuration.
> +
> +@item @code{init-file} (default: @code{'()})
> +Configuration text or files to include in @file{init.el}.
> +
> +@item @code{early-init-file} (default: @code{'()})
> +Configuration text or files to include in @file{early-init.el}.
> +
> +@item @code{load-paths} (default: @code{'()})

Ditto.

Toggle quote (2 lines)
> +@end deftp

Would be great to have an example of that too. :-)

Thank you!

Ludo’.
B
B
benoit wrote on 15 Jan 2023 01:21
file like parameters not working
(address . 60753@debbugs.gnu.org)
a59c6b56dd2d0aa18fe1b78ce03d22e7@benoitj.ca
Hi,

the last patch fixed the undefined issue, now the configuration does not
work with file-like input.

this example: (init-file (list (local-file "init.el")))

the resulting ~/.config/emacs/init.el has the path of my init.el file
instead of it's content.

I'm suspecting the serialization code consider init-file list to always
be string. If I put a string instead of a local-file, I get the proper
behavior.

thanks for doing this!

I'll see if I can troubleshoot the issue later tonight.

Benoit
B
B
benoit wrote on 15 Jan 2023 03:07
issue with file-like init file
(address . 60753@debbugs.gnu.org)
cf0ead5eb618ff45c611f515cc1d1127@benoitj.ca
Hi David,

I think I found the issue. It looks like the mixed-text-file function
does not replace file-like object with their content, but instead with
their path.

if you look at the example in the documentation:

you'll see that it's being used to replace the file-like with it's path
in an "export" clause.

So it totally explain what I see in my generated init file.

When compared with home-bash-service-type in shells.scm, it calls
"serialize-configuration" on the file-like object. This is found in
add-bash-configuration.

Hope this helps.

thanks!

Benoit
A
A
Andrew Tropin wrote on 15 Jan 2023 09:02
Re: [bug#60753] [PATCH] gnu: home: Add home-emacs-service-type.
87cz7g2pkz.fsf@trop.in
On 2023-01-14 19:00, Ludovic Courtès wrote:

Toggle quote (51 lines)
> Hello!
>
> David Wilson <david@daviwil.com> skribis:
>
>> Yes, I saw that you meant to run Emacs as a daemon and I think it should
>> be added to this service (or another daemon-specific service) in a
>> future patch. I figured it would be easier to get a patch accepted
>> without the daemon functionality just yet since there seemed to be more
>> feedback about that aspect in your patch thread.
>
> Agree, I think we should add the daemon functionality in a subsequent
> patch.
>
> Overall it looks nice to me! Some comments and suggestions:
>
>> +@node Emacs Home Services
>> +@subsection Emacs Home Services
>> +
>> +@defvr {Scheme Variable} home-emacs-service-type
>
> It would be nice if you could start the section with a few sentences
> explaining the rationale and what’s being described here.
>
>> +This is the service type for configuring the Emacs text editor. It
>> +enables you to assemble @file{init.el} and @file{early-init.el} files
>> +from snippets in your home configuration and other Emacs Lisp files you
>> +have in your personal configuration folder.
>
> Maybe like so:
>
> … to assemble the @file{init.el} (@pxref{Init File,,, emacs, GNU Emacs
> Manual}) and @file{early-init.el} (@pxref{Early Init File,,, emacs,
> GNU Emacs Manual}) files …
>
>> +@example
>> +$ cp ~/.emacs.d $XDG_CONFIG_HOME/emacs
>> +$ cp ~/.emacs $XDG_CONFIG_HOME/emacs/init.el
>> +@end example
>
> I’d drop the prompt.
>
>> +@item @code{init-file} (default: @code{'()})
>> +Configuration text or files to include in @file{init.el}.
>> +
>> +@item @code{early-init-file} (default: @code{'()})
>> +Configuration text or files to include in @file{early-init.el}.
>
> What about accepting sexps (or gexps) instead of strings? As in:
>
> (init-file '((require 'whatever) (setq something t)))

A quick minor note on this approach: it won't be possible to use
#'elisp-function inside such configuration because it will be
interpreted by guile reader, but actually rde lives without this
functionality completely ok.

Do we want something like this possible?

(init-file `((require 'whatever)
(setq something t)
(load ,(local-file "old-init.el")))

Toggle quote (50 lines)
>
> Also I find it confusing that it’s either text or files. In the code it
> has type ‘text-config’, which means list of file-like objects IIUC, no?
>
>> +@item @code{load-paths} (default: @code{'()})
>> +Additional load paths to add to Emacs' @code{load-path} variable. Lines
>> +will be inserted at the beginning of @file{early-init.el}.
>
> Nitpick: I think this should be ‘load-path’ (singular), because it’s one
> search path (i.e., a list of directories).
>
> And: s/Additional load paths/Additional directories/
>
>> +@end table
>> +@end deftp
>
> Would be nice to have a couple of commented examples here, like you had
> in the first message in this thread. :-)
>
>> +@deftp {Data Type} home-emacs-extension
>> +The extension record for @code{home-emacs-service-type}.
>
> Would be nice to have a sentence above, like “This service type can be
> extended with @code{home-emacs-extension} records, described below:”.
>
>> +@table @asis
>> +@item @code{packages} (default: @code{'()})
>> +Additional packages required by the Emacs configuration.
>> +
>> +@item @code{init-file} (default: @code{'()})
>> +Configuration text or files to include in @file{init.el}.
>> +
>> +@item @code{early-init-file} (default: @code{'()})
>> +Configuration text or files to include in @file{early-init.el}.
>> +
>> +@item @code{load-paths} (default: @code{'()})
>
> Ditto.
>
>> +@end deftp
>
> Would be great to have an example of that too. :-)
>
> Thank you!
>
> Ludo’.
>
>
>

--
Best regards,
Andrew Tropin
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmPDsv0ACgkQIgjSCVjB
3rBSBA/8DXu4n7CvHgxDSaG01Yd8oZbT1I5AJdA1XPV8uXgha1t/47uTw00jNvmH
Rf0Eexc7ulasQ0VSQcqS6KwoJWSAukdUOqDuPL/zb96+Yrdd2g2tt/II38BFbzuC
1DR5f2VwpHXnP1bRLseiSn1U4o3WQfUq0B3HGa2x7gbAPY1ve85eeb6w8fYjCL8M
KoHNOrDTt4lmTUmgMAdqnzkBqvkOlHZV+SEKR5zKKqgSt9gENc4aSHf3zTT3TVGO
jQagFvifZlSVAJD63huonNy/QXMMdwk4LXVfmNHzvvfCignMY5UN70hrNbYo/duR
SwQlwUJF6s9v5tJT7vT4Nc1LbnS3iablDt6kcTCocovNI/J84qqZyjY5p+iebMjD
vvF4X9vv1Bu7zlqEKVfQky1IS0CBCN6XyLfRqOwDKo0+sj8ldbvfWgQFmANNHkbO
edB1wIapUjR784foOhGuSnPbJIf91s1JtNShoFN9CCBeT8qaT4dehZTvaY0hGc10
5ENJ+X8x50GfqxW2JbCDHc98CGmtNt5lgf0bS88dVFb5Ao0CH40NXYGAtoktRicl
O4POJLC5ugxS5TzBXTXZ3QbpM/rPETgEf3B/YzcD3nEQGIkdGzx6asNu5ZfKIVuB
+ZS+4kJNFaGcooJbWekB/gAE2d9VotYL5pjx+ujlv4mK1yDXOko=
=+wbi
-----END PGP SIGNATURE-----

D
D
David Wilson wrote on 16 Jan 2023 10:25
Re: bug#60753: [PATCH] gnu: home: Add home-emacs-service-type.
(name . Ludovic Courtès)(address . ludo@gnu.org)
87h6wqu6ss.fsf@daviwil.com
Thanks for the feedback, Ludo!

I'll make the requested changes and send them later today. I may also
try adding some tests to ensure that the output is what we expect.
There seems to be a `tests/services` folder, should I add a
`tests/home-services` folder to match?

Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (3 lines)
> It would be nice if you could start the section with a few sentences
> explaining the rationale and what’s being described here.

Will do, I'll look at other services to get an idea of the best way to
do this.

Toggle quote (7 lines)
> What about accepting sexps (or gexps) instead of strings? As in:
>
> (init-file '((require 'whatever) (setq something t)))
>
> Also I find it confusing that it’s either text or files. In the code it
> has type ‘text-config’, which means list of file-like objects IIUC, no?

Yes, this was a misunderstanding on my part!

Regarding using s-expressions for this, it would certainly look cleaner.
Andrew raises a good concern about it in his response, I'll take a look
at what RDE does for this and see if I can adopt a similar approach.

Toggle quote (5 lines)
> Nitpick: I think this should be ‘load-path’ (singular), because it’s one
> search path (i.e., a list of directories).
>
> And: s/Additional load paths/Additional directories/

Will change both of these, thanks!

Toggle quote (3 lines)
> Would be nice to have a couple of commented examples here, like you had
> in the first message in this thread. :-)

Yep, I'll add examples for all the use cases here.

Toggle quote (3 lines)
> Would be nice to have a sentence above, like “This service type can be
> extended with @code{home-emacs-extension} records, described below:”.

Will describe and give an example of how to extend the service!

David
L
L
Ludovic Courtès wrote on 17 Jan 2023 10:02
Re: [bug#60753] [PATCH] gnu: home: Add home-emacs-service-type.
(name . Andrew Tropin)(address . andrew@trop.in)
87mt6hjzyx.fsf@gnu.org
Hi,

Andrew Tropin <andrew@trop.in> skribis:

Toggle quote (9 lines)
>> What about accepting sexps (or gexps) instead of strings? As in:
>>
>> (init-file '((require 'whatever) (setq something t)))
>
> A quick minor note on this approach: it won't be possible to use
> #'elisp-function inside such configuration because it will be
> interpreted by guile reader, but actually rde lives without this
> functionality completely ok.

Specifically:

(write '#'x)
|= (syntax x)

But we can use (guix read-print) and ensure that it prints #'.

Toggle quote (6 lines)
> Do we want something like this possible?
>
> (init-file `((require 'whatever)
> (setq something t)
> (load ,(local-file "old-init.el")))

It’d be nice. In that case, we’ll want it to be a gexp though:

#~((require 'whatever) (load #$(local-file …)))

Thanks,
Ludo’.
A
A
Andrew Tropin wrote on 17 Jan 2023 15:46
(name . Ludovic Courtès)(address . ludo@gnu.org)
87wn5l8bhz.fsf@trop.in
On 2023-01-17 10:02, Ludovic Courtès wrote:

Toggle quote (21 lines)
> Hi,
>
> Andrew Tropin <andrew@trop.in> skribis:
>
>>> What about accepting sexps (or gexps) instead of strings? As in:
>>>
>>> (init-file '((require 'whatever) (setq something t)))
>>
>> A quick minor note on this approach: it won't be possible to use
>> #'elisp-function inside such configuration because it will be
>> interpreted by guile reader, but actually rde lives without this
>> functionality completely ok.
>
> Specifically:
>
> (write '#'x)
> |= (syntax x)
>
> But we can use (guix read-print) and ensure that it prints #'.
>

Do you have any links to docs/sample implementations on the topic of
extending guile reader, so we have an example to start with? Does guix
workflow language do something like that?

I think it will be cool to hook up a custom reader, ideally comment
preserving, for emacs lisp inside scheme files.

Toggle quote (11 lines)
>> Do we want something like this possible?
>>
>> (init-file `((require 'whatever)
>> (setq something t)
>> (load ,(local-file "old-init.el")))
>
> It’d be nice. In that case, we’ll want it to be a gexp though:
>
> #~((require 'whatever) (load #$(local-file …)))
>

gexps are nice, but do we really need/want them here? Do you have any
thoughts on what are the benifits over quasiquotes in this case? Maybe
some examples?

--
Best regards,
Andrew Tropin
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmPGtMgACgkQIgjSCVjB
3rBqPQ/9HKOEKud2ZBdmTEr5f5kOQ59wLdRZ4wQetzJlzs+QxF5i+P2QmUChfTlo
72GpXItoshuerESkoYBaDfZ/Gu1bY/wrQ+6SoZqsJ6rAdQnPuBvfOH5PHBgR7zAD
NSRdraSwsU8tmefpCuTP9p/Wz84+TgOBlVhe17XRNeShK34LDkpuDhBG5hEjW2Jt
po64au/TFQttWlPhL/YZiBx04OFuSTk7KEs8wlciPHGXLizuMg7aDZvHdYC0aKO4
vRaOFjikHIeb1etpuuSH8paLO7wOsq2WNvPYzqXO0+pIeHpEtLExhJR2WpXj4wEU
S/qUcwwc5VD12vUnGOWBFxFR0s0VOpTaWl4MEvXdsbpGhKGbAbYfDnOyp/mcl0y/
8xmsLrx8zvXf4JF4zh4C35p37UjN6KkKMONyHyeNDh0H9nm2o4L1xzxtePlNLpOf
XLDKBEIOLe0AgoKpJV55KjmCOYfIAbdeHJpla8skLr03ZfOqzyr0n8jf+Siu9V/k
R/TVUFlyxLhqJxSDjSj+BR+EOYIU3AhCxyG/4wxv0Sfh/BgiboSUmTsH2XFiVeLU
+dOwXNrBqB8d9n4jYwGHI2BqJ8+xOEilbOjqVLp3rpvuZwkpfmE35D2437hrfkAn
HfwNPMlHYgwRenObR82dOZyXcGX2wu1l3aHTZ1gBMp0PjZL6XIM=
=GU8y
-----END PGP SIGNATURE-----

L
L
Ludovic Courtès wrote on 23 Jan 2023 11:18
(name . Andrew Tropin)(address . andrew@trop.in)
87ilgx4kqg.fsf@gnu.org
Hi,

Andrew Tropin <andrew@trop.in> skribis:

Toggle quote (26 lines)
> On 2023-01-17 10:02, Ludovic Courtès wrote:
>
>> Hi,
>>
>> Andrew Tropin <andrew@trop.in> skribis:
>>
>>>> What about accepting sexps (or gexps) instead of strings? As in:
>>>>
>>>> (init-file '((require 'whatever) (setq something t)))
>>>
>>> A quick minor note on this approach: it won't be possible to use
>>> #'elisp-function inside such configuration because it will be
>>> interpreted by guile reader, but actually rde lives without this
>>> functionality completely ok.
>>
>> Specifically:
>>
>> (write '#'x)
>> |= (syntax x)
>>
>> But we can use (guix read-print) and ensure that it prints #'.
>>
>
> Do you have any links to docs/sample implementations on the topic of
> extending guile reader, so we have an example to start with?

It’s not the reader but rather the writer that we’d want to tweak.

In (guix read-print), ‘pretty-print-with-comments’ already special cases
quasiquote etc. so that it prints ‘`’ (backtick) and not ‘quasiquote'.
We’d add clauses for ‘syntax’ and ‘quasisyntax’.

Toggle quote (3 lines)
> I think it will be cool to hook up a custom reader, ideally comment
> preserving, for emacs lisp inside scheme files.

(guix read-print) is what you want. :-)

Toggle quote (15 lines)
>>> Do we want something like this possible?
>>>
>>> (init-file `((require 'whatever)
>>> (setq something t)
>>> (load ,(local-file "old-init.el")))
>>
>> It’d be nice. In that case, we’ll want it to be a gexp though:
>>
>> #~((require 'whatever) (load #$(local-file …)))
>>
>
> gexps are nice, but do we really need/want them here? Do you have any
> thoughts on what are the benifits over quasiquotes in this case? Maybe
> some examples?

The benefit in the example above is that the gexp would actually work
whereas the sexp wouldn’t :-), unless there’s code somewhere to manually
traverse the sexp adn replace the <local-file> record with its store
item (which is what gexps are about).

I hope that makes sense!

Ludo’.
A
A
Andrew Tropin wrote on 26 Jan 2023 06:06
(name . Ludovic Courtès)(address . ludo@gnu.org)
87v8ktvq99.fsf@trop.in
On 2023-01-23 11:18, Ludovic Courtès wrote:

Toggle quote (32 lines)
> Hi,
>
> Andrew Tropin <andrew@trop.in> skribis:
>
>> On 2023-01-17 10:02, Ludovic Courtès wrote:
>>
>>> Hi,
>>>
>>> Andrew Tropin <andrew@trop.in> skribis:
>>>
>>>>> What about accepting sexps (or gexps) instead of strings? As in:
>>>>>
>>>>> (init-file '((require 'whatever) (setq something t)))
>>>>
>>>> A quick minor note on this approach: it won't be possible to use
>>>> #'elisp-function inside such configuration because it will be
>>>> interpreted by guile reader, but actually rde lives without this
>>>> functionality completely ok.
>>>
>>> Specifically:
>>>
>>> (write '#'x)
>>> |= (syntax x)
>>>
>>> But we can use (guix read-print) and ensure that it prints #'.
>>>
>>
>> Do you have any links to docs/sample implementations on the topic of
>> extending guile reader, so we have an example to start with?
>
> It’s not the reader but rather the writer that we’d want to tweak.

Right, it already can read #'x as (syntax x) and we can print it
properly later, but AFAIK comments are ignored by the default reader.
So I would expect to do something (very roughly) like this:

Toggle snippet (5 lines)
(parameterize (((@@ (guix gexp) read-procedure) read-with-comments))
#~(list 'hello ; Comment I would like to preserve during serialization
'guix))

Of course it doesn't work, but I hope demonstrates the idea.

Toggle quote (6 lines)
>
> In (guix read-print), ‘pretty-print-with-comments’ already special
> cases quasiquote etc. so that it prints ‘`’ (backtick) and not
> ‘quasiquote'. We’d add clauses for ‘syntax’ and ‘quasisyntax’.
>

It seems ice-9 pretty-print also preserves backticks, but I see that
pretty-print-with-comments also preserves gexps, which is cool. Adding
syntax will make it even cooler.

Toggle quote (6 lines)
>> I think it will be cool to hook up a custom reader, ideally comment
>> preserving, for emacs lisp inside scheme files.
>
> (guix read-print) is what you want. :-)
>

Can you give a hint on how to use it for preserving comments, please?

Toggle quote (22 lines)
>>>> Do we want something like this possible?
>>>>
>>>> (init-file `((require 'whatever)
>>>> (setq something t)
>>>> (load ,(local-file "old-init.el")))
>>>
>>> It’d be nice. In that case, we’ll want it to be a gexp though:
>>>
>>> #~((require 'whatever) (load #$(local-file …)))
>>>
>>
>> gexps are nice, but do we really need/want them here? Do you have any
>> thoughts on what are the benifits over quasiquotes in this case? Maybe
>> some examples?
>
> The benefit in the example above is that the gexp would actually work
> whereas the sexp wouldn’t :-), unless there’s code somewhere to manually
> traverse the sexp adn replace the <local-file> record with its store
> item (which is what gexps are about).
>
> I hope that makes sense!

With this simple serializer we already achieved quite good results:

For this input
Toggle snippet (10 lines)
`((load ,(local-file "./feature-lists.scm"))
,#~(format #f "hello") ; top level gexps are evaluated
(list ,#~(format #f "hello")) ; nested gexps are not
,#~";; hacky comment"
;; comment, which is not preserved
#'hi-fn ; incorrectly serialized, but fixable by alternative
; pretty-print
)

it provides quite satisfying results:
Toggle snippet (7 lines)
(load "/gnu/store/xb6ma0mcgg1zzq645s63arvy3qskmbiz-feature-lists.scm")
hello
(list (format #f "hello"))
;; hacky comment
(syntax hi-fn)

It's a little incosistent (top level gexp are evaluated, but nested are
not), comments are not preserved and #' serialized incorrectly, but
other than that it works very good.

WDYT about overall approach used here? or we can do it radically
better?

--
Best regards,
Andrew Tropin
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmPSClIACgkQIgjSCVjB
3rCylxAAkulwhScUyGj8PhTxx9lyrUS5tA8NWDgRop8L/+gwyn8GAtYUhT3kljXz
3txf97vp/cHzAB8DkjXao0omAVlqXd8q2DPMxBjXeUVBkQuaxE4qA/3T7MTS2rVx
WuBi/cI3Un8Y5m1WXOeoLxkjEgvOep7FDu887Ekzu+/JZ32DlDRFv6EP8N6ljbu4
DDlqVDlMGTzbIvRWKOloqpy/wIiaPA1ITVXQnyWhEyVSN8Yc9ajrWCSqugzFwiDS
FMGOF5Vzf/WKz9shwhNu7HGS5S3h4kyCIxow5OoiiV2JQ9s6NovQd8Pt4x96rhTn
tiCiFU4JO9TMEAn+Hgmx111cuuhzIQn+Acg3knoHxTbsCjTF4SsNhJskm6khJqBI
mXNRCK9N2VhbXcLUwQaEeB5WCYy+954nbp93jIBL4uib6Rfz71zspWLbjNPWk+fq
iI+ofk3NZAKybOYj2IuPksN0UHYZZ2pCUJE3DgA/IBvBEL8Ljkh3QI5dIEy/mQfQ
d2MdG09CsVXBU9/u83+PPfxyt8ED7op2OnhH8+FjKpWfzEZW+KZS0xaDiDTVn2nx
P2y3qDi1IfN7Ed9gAnf86AMHeKNKJ2SgCN4tegMaED+JqmkyehqNn5wj0b9OFi74
DU5M6X0Cyk+HzdHlfRyrCLdAjRmBw4CQ4H9OEkM7+Dbj5xHrghk=
=7FZo
-----END PGP SIGNATURE-----

R
R
Reily Siegel wrote on 26 Jan 2023 19:50
878rhpuo3e.fsf@reilysiegel.com
Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (7 lines)
> Specifically:
>
> (write '#'x)
> |= (syntax x)
>
> But we can use (guix read-print) and ensure that it prints #'.

The way I get around this in my config is adding

#+begin_source emacs-lisp
;; #' exports a scheme (syntax ...) form. Treat this as a
;; (function ...) form.
(defalias 'syntax 'function)
#+end_source

This is a very hacky solution, but if you wanted to not modify the
reader, you could add this to the beginning of init.el with the service.

--
Reily Siegel
L
L
Ludovic Courtès wrote on 31 Jan 2023 17:26
(name . Andrew Tropin)(address . andrew@trop.in)
87y1piu0u6.fsf@gnu.org
Hi Andrew,

Andrew Tropin <andrew@trop.in> skribis:

Toggle quote (8 lines)
>>> I think it will be cool to hook up a custom reader, ideally comment
>>> preserving, for emacs lisp inside scheme files.
>>
>> (guix read-print) is what you want. :-)
>>
>
> Can you give a hint on how to use it for preserving comments, please?

It can be used like this:

Toggle snippet (8 lines)
scheme@(guile-user)> ,use(guix read-print)
scheme@(guile-user)> (pretty-print-with-comments (current-output-port) `(list foo ,(comment ";ooh!\n" #t) bar))
(list foo ;ooh!
bar)$5 = 10
scheme@(guile-user)> (call-with-input-string "(list foo ;oh!\nbar)" read-with-comments)
$6 = (list foo #<<comment> str: ";oh!\n" margin?: #t> bar)

There’s a <comment> record type.

Now let’s see perhaps what we need to get ‘home-emacs-service-type’
merged, and what we can keep as future work. Thoughts?

Ludo’.
J
J
Jelle Licht wrote on 1 Feb 2023 13:59
87lelhils1.fsf@posteo.net
Andrew Tropin <andrew@trop.in> writes:

Toggle quote (117 lines)
> On 2023-01-23 11:18, Ludovic Courtès wrote:
>
>> Hi,
>>
>> Andrew Tropin <andrew@trop.in> skribis:
>>
>>> On 2023-01-17 10:02, Ludovic Courtès wrote:
>>>
>>>> Hi,
>>>>
>>>> Andrew Tropin <andrew@trop.in> skribis:
>>>>
>>>>>> What about accepting sexps (or gexps) instead of strings? As in:
>>>>>>
>>>>>> (init-file '((require 'whatever) (setq something t)))
>>>>>
>>>>> A quick minor note on this approach: it won't be possible to use
>>>>> #'elisp-function inside such configuration because it will be
>>>>> interpreted by guile reader, but actually rde lives without this
>>>>> functionality completely ok.
>>>>
>>>> Specifically:
>>>>
>>>> (write '#'x)
>>>> |= (syntax x)
>>>>
>>>> But we can use (guix read-print) and ensure that it prints #'.
>>>>
>>>
>>> Do you have any links to docs/sample implementations on the topic of
>>> extending guile reader, so we have an example to start with?
>>
>> It’s not the reader but rather the writer that we’d want to tweak.
>
> Right, it already can read #'x as (syntax x) and we can print it
> properly later, but AFAIK comments are ignored by the default reader.
> So I would expect to do something (very roughly) like this:
>
> --8<---------------cut here---------------start------------->8---
> (parameterize (((@@ (guix gexp) read-procedure) read-with-comments))
> #~(list 'hello ; Comment I would like to preserve during serialization
> 'guix))
> --8<---------------cut here---------------end--------------->8---
>
> Of course it doesn't work, but I hope demonstrates the idea.
>
>>
>> In (guix read-print), ‘pretty-print-with-comments’ already special
>> cases quasiquote etc. so that it prints ‘`’ (backtick) and not
>> ‘quasiquote'. We’d add clauses for ‘syntax’ and ‘quasisyntax’.
>>
>
> It seems ice-9 pretty-print also preserves backticks, but I see that
> pretty-print-with-comments also preserves gexps, which is cool. Adding
> syntax will make it even cooler.
>
>>> I think it will be cool to hook up a custom reader, ideally comment
>>> preserving, for emacs lisp inside scheme files.
>>
>> (guix read-print) is what you want. :-)
>>
>
> Can you give a hint on how to use it for preserving comments, please?
>
>>>>> Do we want something like this possible?
>>>>>
>>>>> (init-file `((require 'whatever)
>>>>> (setq something t)
>>>>> (load ,(local-file "old-init.el")))
>>>>
>>>> It’d be nice. In that case, we’ll want it to be a gexp though:
>>>>
>>>> #~((require 'whatever) (load #$(local-file …)))
>>>>
>>>
>>> gexps are nice, but do we really need/want them here? Do you have any
>>> thoughts on what are the benifits over quasiquotes in this case? Maybe
>>> some examples?
>>
>> The benefit in the example above is that the gexp would actually work
>> whereas the sexp wouldn’t :-), unless there’s code somewhere to manually
>> traverse the sexp adn replace the <local-file> record with its store
>> item (which is what gexps are about).
>>
>> I hope that makes sense!
>
> With this simple serializer we already achieved quite good results:
> https://git.sr.ht/~abcdw/rde/tree/388d3ad95e8607543df3dcdf26d058b610e77389/src/rde/serializers/lisp.scm#L35
>
> For this input
> --8<---------------cut here---------------start------------->8---
> `((load ,(local-file "./feature-lists.scm"))
> ,#~(format #f "hello") ; top level gexps are evaluated
> (list ,#~(format #f "hello")) ; nested gexps are not
> ,#~";; hacky comment"
> ;; comment, which is not preserved
> #'hi-fn ; incorrectly serialized, but fixable by alternative
> ; pretty-print
> )
> --8<---------------cut here---------------end--------------->8---
>
> it provides quite satisfying results:
> --8<---------------cut here---------------start------------->8---
> (load "/gnu/store/xb6ma0mcgg1zzq645s63arvy3qskmbiz-feature-lists.scm")
> hello
> (list (format #f "hello"))
> ;; hacky comment
> (syntax hi-fn)
> --8<---------------cut here---------------end--------------->8---
>
> It's a little incosistent (top level gexp are evaluated, but nested are
> not), comments are not preserved and #' serialized incorrectly, but
> other than that it works very good.
>
> WDYT about overall approach used here? or we can do it radically
> better?

Not saying it's better in any particular way, but I have had this locally
for all my elisp-read-by-guile-written-back-to-elisp needs:

Toggle snippet (49 lines)
(define-module (jlicht build elisp-write)
#:use-module (ice-9 match)
#:use-module (srfi srfi-1)
#:export (elisp-write))

(define (elisp-write in-list? exp port)
"Stack-blowing implementation that writes guile's internal elisp
representation to something that can be parsed by Emacs."
;; Definitions from (language elisp parser)'s quotation-symbols:
(define symbol-strings
'((#{`}# . "`")
(#{,}# . ",")
(#{,@}# . ",@")))
(define (elisp-symbol? sym)
(assq sym symbol-strings))
(define (write-elisp-symbol sym port)
(format port "~A" (assq-ref symbol-strings sym)))
(match exp
(((? elisp-symbol? sym) rest)
(write-elisp-symbol sym port)
(elisp-write in-list? rest port))
;; Vector expression
(#(vs ...)
(format port "[")
(elisp-write #t vs port)
(format port "]"))
;; Guile elisp implementation detail
('(%set-lexical-binding-mode #f) 'skip)
;; List walker
((e ...)
(when (not in-list?) (format port "("))
(unless (null? e)
(elisp-write #f (car e) port)
(for-each (lambda (v)
(format port " ")
(elisp-write #f v port)) (cdr e)))
(when (not in-list?) (format port ")")))
;; dotted pair
((and (? pair?) (? dotted-list? l))
(format port "(")
(elisp-write #t (drop-right l 0) port)
(format port " . ")
(elisp-write #t (take-right l 0) port)
(format port ")"))
;; Print simple primitives
(_ (write exp port))))

On the reader side I just use guile's elisp reader:

Toggle snippet (35 lines)
(define-module (jlicht test elisp)
#:use-module (language elisp parser)
#:use-module (jlicht build elisp-write)
#:use-module (srfi srfi-26)
#:use-module (srfi srfi-64))

(eval-when (expand load eval)
(read-hash-extend #\e (lambda (chr port) (read-elisp port))))

(set! test-log-to-file #f)

(define (roundtrip expr)
(let ((written (call-with-output-string (cut elisp-write #f expr <>))))
(call-with-input-string written read-elisp)))

(define-syntax test-roundtrip-equals
(syntax-rules ()
((_ expr)
(let ((e1 (roundtrip expr)))
(test-equal e1 (roundtrip e1))))))

(define runner (test-runner-simple))

(test-with-runner runner
(test-begin "roundtrip-elisp-fixed-point")
(test-roundtrip-equals 12)
(test-roundtrip-equals "hello")
(test-roundtrip-equals '#e#'my-fn)
(test-roundtrip-equals '#e[a b c])
(test-roundtrip-equals '#e`(+ 1 2 ,@(a b) ,c))
(test-end "roundtrip-elisp-fixed-point"))

(exit (test-runner-fail-count runner))

I've also hooked it up in combination with a sequence of calls to
`scheme-file' -> `computed-file' called `elisp-file', but that's a bit
more hacky and less relevant to the current discussion.

- Jelle
A
A
Andrew Tropin wrote on 1 Feb 2023 14:46
87wn51qyzw.fsf@trop.in
On 2023-02-01 12:59, Jelle Licht wrote:

Toggle quote (122 lines)
> Andrew Tropin <andrew@trop.in> writes:
>
>> On 2023-01-23 11:18, Ludovic Courtès wrote:
>>
>>> Hi,
>>>
>>> Andrew Tropin <andrew@trop.in> skribis:
>>>
>>>> On 2023-01-17 10:02, Ludovic Courtès wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> Andrew Tropin <andrew@trop.in> skribis:
>>>>>
>>>>>>> What about accepting sexps (or gexps) instead of strings? As in:
>>>>>>>
>>>>>>> (init-file '((require 'whatever) (setq something t)))
>>>>>>
>>>>>> A quick minor note on this approach: it won't be possible to use
>>>>>> #'elisp-function inside such configuration because it will be
>>>>>> interpreted by guile reader, but actually rde lives without this
>>>>>> functionality completely ok.
>>>>>
>>>>> Specifically:
>>>>>
>>>>> (write '#'x)
>>>>> |= (syntax x)
>>>>>
>>>>> But we can use (guix read-print) and ensure that it prints #'.
>>>>>
>>>>
>>>> Do you have any links to docs/sample implementations on the topic of
>>>> extending guile reader, so we have an example to start with?
>>>
>>> It’s not the reader but rather the writer that we’d want to tweak.
>>
>> Right, it already can read #'x as (syntax x) and we can print it
>> properly later, but AFAIK comments are ignored by the default reader.
>> So I would expect to do something (very roughly) like this:
>>
>> --8<---------------cut here---------------start------------->8---
>> (parameterize (((@@ (guix gexp) read-procedure) read-with-comments))
>> #~(list 'hello ; Comment I would like to preserve during serialization
>> 'guix))
>> --8<---------------cut here---------------end--------------->8---
>>
>> Of course it doesn't work, but I hope demonstrates the idea.
>>
>>>
>>> In (guix read-print), ‘pretty-print-with-comments’ already special
>>> cases quasiquote etc. so that it prints ‘`’ (backtick) and not
>>> ‘quasiquote'. We’d add clauses for ‘syntax’ and ‘quasisyntax’.
>>>
>>
>> It seems ice-9 pretty-print also preserves backticks, but I see that
>> pretty-print-with-comments also preserves gexps, which is cool. Adding
>> syntax will make it even cooler.
>>
>>>> I think it will be cool to hook up a custom reader, ideally comment
>>>> preserving, for emacs lisp inside scheme files.
>>>
>>> (guix read-print) is what you want. :-)
>>>
>>
>> Can you give a hint on how to use it for preserving comments, please?
>>
>>>>>> Do we want something like this possible?
>>>>>>
>>>>>> (init-file `((require 'whatever)
>>>>>> (setq something t)
>>>>>> (load ,(local-file "old-init.el")))
>>>>>
>>>>> It’d be nice. In that case, we’ll want it to be a gexp though:
>>>>>
>>>>> #~((require 'whatever) (load #$(local-file …)))
>>>>>
>>>>
>>>> gexps are nice, but do we really need/want them here? Do you have any
>>>> thoughts on what are the benifits over quasiquotes in this case? Maybe
>>>> some examples?
>>>
>>> The benefit in the example above is that the gexp would actually work
>>> whereas the sexp wouldn’t :-), unless there’s code somewhere to manually
>>> traverse the sexp adn replace the <local-file> record with its store
>>> item (which is what gexps are about).
>>>
>>> I hope that makes sense!
>>
>> With this simple serializer we already achieved quite good results:
>> https://git.sr.ht/~abcdw/rde/tree/388d3ad95e8607543df3dcdf26d058b610e77389/src/rde/serializers/lisp.scm#L35
>>
>> For this input
>> --8<---------------cut here---------------start------------->8---
>> `((load ,(local-file "./feature-lists.scm"))
>> ,#~(format #f "hello") ; top level gexps are evaluated
>> (list ,#~(format #f "hello")) ; nested gexps are not
>> ,#~";; hacky comment"
>> ;; comment, which is not preserved
>> #'hi-fn ; incorrectly serialized, but fixable by alternative
>> ; pretty-print
>> )
>> --8<---------------cut here---------------end--------------->8---
>>
>> it provides quite satisfying results:
>> --8<---------------cut here---------------start------------->8---
>> (load "/gnu/store/xb6ma0mcgg1zzq645s63arvy3qskmbiz-feature-lists.scm")
>> hello
>> (list (format #f "hello"))
>> ;; hacky comment
>> (syntax hi-fn)
>> --8<---------------cut here---------------end--------------->8---
>>
>> It's a little incosistent (top level gexp are evaluated, but nested are
>> not), comments are not preserved and #' serialized incorrectly, but
>> other than that it works very good.
>>
>> WDYT about overall approach used here? or we can do it radically
>> better?
>
> Not saying it's better in any particular way, but I have had this locally
> for all my elisp-read-by-guile-written-back-to-elisp needs:

I saw it in guix-home-manager and probably you've made the thread on
rde-devel too. I tried some parts of this code, but didn't succeed to
get a complete working out of it, now I have a little more knowledge and
hope will get better results :)

Toggle quote (63 lines)
>
> --8<---------------cut here---------------start------------->8---
> (define-module (jlicht build elisp-write)
> #:use-module (ice-9 match)
> #:use-module (srfi srfi-1)
> #:export (elisp-write))
>
> (define (elisp-write in-list? exp port)
> "Stack-blowing implementation that writes guile's internal elisp
> representation to something that can be parsed by Emacs."
> ;; Definitions from (language elisp parser)'s quotation-symbols:
> (define symbol-strings
> '((#{`}# . "`")
> (#{,}# . ",")
> (#{,@}# . ",@")))
> (define (elisp-symbol? sym)
> (assq sym symbol-strings))
> (define (write-elisp-symbol sym port)
> (format port "~A" (assq-ref symbol-strings sym)))
>
> (match exp
> (((? elisp-symbol? sym) rest)
> (write-elisp-symbol sym port)
> (elisp-write in-list? rest port))
> ;; Vector expression
> (#(vs ...)
> (format port "[")
> (elisp-write #t vs port)
> (format port "]"))
> ;; Guile elisp implementation detail
> ('(%set-lexical-binding-mode #f) 'skip)
> ;; List walker
> ((e ...)
> (when (not in-list?) (format port "("))
> (unless (null? e)
> (elisp-write #f (car e) port)
> (for-each (lambda (v)
> (format port " ")
> (elisp-write #f v port)) (cdr e)))
> (when (not in-list?) (format port ")")))
> ;; dotted pair
> ((and (? pair?) (? dotted-list? l))
> (format port "(")
> (elisp-write #t (drop-right l 0) port)
> (format port " . ")
> (elisp-write #t (take-right l 0) port)
> (format port ")"))
> ;; Print simple primitives
> (_ (write exp port))))
> --8<---------------cut here---------------end--------------->8---
>
> On the reader side I just use guile's elisp reader:
>
> --8<---------------cut here---------------start------------->8---
> (define-module (jlicht test elisp)
> #:use-module (language elisp parser)
> #:use-module (jlicht build elisp-write)
> #:use-module (srfi srfi-26)
> #:use-module (srfi srfi-64))
>
> (eval-when (expand load eval)
> (read-hash-extend #\e (lambda (chr port) (read-elisp port))))

That's what I was looking for. If you have any links related to the
topic of the reader extension, please let me know.

Toggle quote (23 lines)
>
> (set! test-log-to-file #f)
>
> (define (roundtrip expr)
> (let ((written (call-with-output-string (cut elisp-write #f expr <>))))
> (call-with-input-string written read-elisp)))
>
> (define-syntax test-roundtrip-equals
> (syntax-rules ()
> ((_ expr)
> (let ((e1 (roundtrip expr)))
> (test-equal e1 (roundtrip e1))))))
>
> (define runner (test-runner-simple))
>
> (test-with-runner runner
> (test-begin "roundtrip-elisp-fixed-point")
> (test-roundtrip-equals 12)
> (test-roundtrip-equals "hello")
> (test-roundtrip-equals '#e#'my-fn)
> (test-roundtrip-equals '#e[a b c])
> (test-roundtrip-equals '#e`(+ 1 2 ,@(a b) ,c))

It would be cool to make elisp-unquote for #e, but I think I can take a
look at ungexp to understand how to implement it.

Toggle quote (11 lines)
> (test-end "roundtrip-elisp-fixed-point"))
>
> (exit (test-runner-fail-count runner))
> --8<---------------cut here---------------end--------------->8---
>
> I've also hooked it up in combination with a sequence of calls to
> `scheme-file' -> `computed-file' called `elisp-file', but that's a bit
> more hacky and less relevant to the current discussion.
>
> - Jelle

Thank you very much!

--
Best regards,
Andrew Tropin
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmPabVMACgkQIgjSCVjB
3rCNKg/9HqXUnnKgo6sQGDDz8nkA0FkAsm0qCSS20Pa/vL3eZnD7umgSqADUXRyo
b0N8Y/hhP/dU59AK/Lp3h4x9V6r/WmvK/oO2Ai9JQ2VLeeaUPwKDIlAOp/yBplDP
zh/+xBcqy5lHfoTZI3TlgHDGTc0Ceb8L/PqGlc6kEwoOQP9VWg8XyoMpbvPp/m7u
7vQAHJZzK/WRN/NMxb4S6wTd22ZzP01Y5rRLdwiklGZM5U0osLcJCU2NaOiAJtWT
HdbsA5S5auWeGTkk6pV9c3X4Qi7RTEm+M7/0piJE6pwmyw7LulDqZ/RczsxFnJrE
z5hq7otbsBLMgsx3/7dcCwOTFTzgI0orw/tCHKq8Q1qqo7Rxizq5B9nuUKl/e1Ph
yez13UTtCuuS2A6djyLHjD5sNIGCc/AEzdozauXvMKHQnRX8mEE0eSGCsu4FVqm0
pAYXvRrAxVsMjRmmklkIWETkqbbHbU2WT7cGs1i2gSlFPeljPbcLcFVp2PlL7GUt
TvgpZ7hi3i2/n+UbeK0OlW+C+8KNuGBqitQwLeRzjDt8Np1FmT2ZahtRwwZ4ixs8
A5Lk7mvnMgDK06cjoOr8jDKgIkBDIKJHvoMINJ0ugAJV2MjTjv57YkGqIDR59+kS
flGC+2qR+w57hGTcWZ67XorwpiwHQLOXNZ5/BPalmeycFpPsJEU=
=JnjR
-----END PGP SIGNATURE-----

A
A
Andrew Tropin wrote on 1 Feb 2023 15:06
(name . Ludovic Courtès)(address . ludo@gnu.org)
87sffpqy2s.fsf@trop.in
On 2023-01-31 17:26, Ludovic Courtès wrote:

Toggle quote (25 lines)
> Hi Andrew,
>
> Andrew Tropin <andrew@trop.in> skribis:
>
>>>> I think it will be cool to hook up a custom reader, ideally comment
>>>> preserving, for emacs lisp inside scheme files.
>>>
>>> (guix read-print) is what you want. :-)
>>>
>>
>> Can you give a hint on how to use it for preserving comments, please?
>
> It can be used like this:
>
> --8<---------------cut here---------------start------------->8---
> scheme@(guile-user)> ,use(guix read-print)
> scheme@(guile-user)> (pretty-print-with-comments (current-output-port) `(list foo ,(comment ";ooh!\n" #t) bar))
> (list foo ;ooh!
> bar)$5 = 10
> scheme@(guile-user)> (call-with-input-string "(list foo ;oh!\nbar)" read-with-comments)
> $6 = (list foo #<<comment> str: ";oh!\n" margin?: #t> bar)
> --8<---------------cut here---------------end--------------->8---
>
> There’s a <comment> record type.

Yep, I already experimented with it, but it's not exactly what I'm
looking for, Jelle gave a few ideas and code snippets which looks closer
to what I searching. Pretty printer and read function are useful, but
not directly related to my question about reader.

Toggle quote (4 lines)
>
> Now let’s see perhaps what we need to get ‘home-emacs-service-type’
> merged, and what we can keep as future work. Thoughts?

We have not perfect, but working quite good implementation of lisp
serializer in rde, which we use in rde's home-emacs-service-type:

But I'm not completely satisfyied with it and don't want to upstream it
in current state, I plan to experiment with Jelle's code and get a
feeling of how his approach works, also want to dive into reader
extensions topic. If I get satisfying solution I will share it. It can
take quite a while, so don't expect it to happen anytime soon; it can,
but unlikely :) If anyone want to work in parallel and propose
alternative implementation, I would be glad to give a feedback on it.

--
Best regards,
Andrew Tropin
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmPacfsACgkQIgjSCVjB
3rDluhAAkfK/QMnJXcUra3mqobY+rtkI86mjyT6fgaY8kFDu0NFWcXLghwohRax1
4s8/sFf8LDJGwmgZgl9Cr7+WmL4ocnmoPCccWaBzUVfXJr7vce3XTgEVAP4exICS
BbVEVhkrJfZk2AKHDaGqGfVHMVsS5jIYEzLD4Ye5UfFMkrFJf1kqFeS1V/YWchO1
ppV9rM5V+IS9ViludZ1UY26c9RQprqkGHUGcZpxH+NNRQefNrfhEL89ZQrtBu5GQ
vXjugmojrEtDs8R78RTJdufzPORGr8fUcUEhcDbsRW1DVZ7lgP5VA56MIavIeTuO
iR8wARu8oZ//MwRCeWmp2mBA4efCveU78DiMk0lfo3jDwxO3L4PClAs5itEJacTf
Vz3Sr1++/5lUw5P1oVYGiBIEZqyjLKG8Vz+kRlV1/PEwaF2uhRDSRcHtDioM/3a+
Xa9S8KrfmIZvmyp/JgxXJGZUVZ5QgPXrAoHarnORijxgFcOIbbOtyBdNTwvgb4Y4
/4Jz3TymwMYY761Dx2xnbZGCxLJJvvnAAdQZIKe1j9Ix6K1MFwfXvkM8/KoqQ0LO
jiGzDIp1RIRaHiobboIa22bvHVl+Wa9Jr8TdrMVYnntDErlBv9fxyYoXVsM+SWm/
86BRhx4HDRyIYIu+XQI7OK5HqDE7R93/Vk+PEAz1v7/bjEXANeo=
=hT1d
-----END PGP SIGNATURE-----

D
D
David Wilson wrote on 10 Feb 2023 08:50
(name . Ludovic Courtès)(address . ludo@gnu.org)
875ycaq7lx.fsf@daviwil.com
Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (3 lines)
> Now let’s see perhaps what we need to get ‘home-emacs-service-type’
> merged, and what we can keep as future work. Thoughts?

Sorry for the long delay in getting back to this! To summarize what
we've discussed so far:

- It's possibly best to use g-expressions for the init.el file contents
because it gives ultimate flexibility on how one can describe their
Emacs configuration in Scheme while pulling in files from their local
configuration folder. Are we concerned whether this may be harder for
users to understand and adopt?

- We'll postpone any work to ensure that comments and #'function
references can be properly represented so that we can get the basic
`home-emacs-service' merged for now. Future patches will improve on
that situation.

Is that accurate? Either way, I'll spend some time today responding to
the feedback so that we can get this merged.

Thanks!

David
L
L
Ludovic Courtès wrote on 20 Feb 2023 12:10
(name . David Wilson)(address . david@daviwil.com)
87a618iods.fsf@gnu.org
Hi David,

David Wilson <david@daviwil.com> skribis:

Toggle quote (14 lines)
> Ludovic Courtès <ludo@gnu.org> writes:
>
>> Now let’s see perhaps what we need to get ‘home-emacs-service-type’
>> merged, and what we can keep as future work. Thoughts?
>
> Sorry for the long delay in getting back to this! To summarize what
> we've discussed so far:
>
> - It's possibly best to use g-expressions for the init.el file contents
> because it gives ultimate flexibility on how one can describe their
> Emacs configuration in Scheme while pulling in files from their local
> configuration folder. Are we concerned whether this may be harder for
> users to understand and adopt?

Ease of use should always be a concern IMO. I’d expect that writing
gexps will feel more convenient than in sexps-in-Scheme-strings for the
target Elisp audience.

Toggle quote (8 lines)
> - We'll postpone any work to ensure that comments and #'function
> references can be properly represented so that we can get the basic
> `home-emacs-service' merged for now. Future patches will improve on
> that situation.
>
> Is that accurate? Either way, I'll spend some time today responding to
> the feedback so that we can get this merged.

Sounds good to me!

Ludo’.
?