From patchwork Thu Jan 12 17:27:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: David Wilson X-Patchwork-Id: 46073 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 3F68727BBEB; Thu, 12 Jan 2023 17:54:16 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-3.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_MSPIKE_H2,SPF_HELO_PASS, URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 1857227BBE9 for ; Thu, 12 Jan 2023 17:54:15 +0000 (GMT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pG1aZ-0000kt-I2; Thu, 12 Jan 2023 12:42:07 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pG1aV-0000jh-0r for guix-patches@gnu.org; Thu, 12 Jan 2023 12:42:04 -0500 Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pG1aU-0002sK-8I for guix-patches@gnu.org; Thu, 12 Jan 2023 12:42:02 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1pG1aT-0002dw-NC for guix-patches@gnu.org; Thu, 12 Jan 2023 12:42:01 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#60753] [PATCH] gnu: home: Add home-emacs-service-type. Resent-From: David Wilson Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Thu, 12 Jan 2023 17:42:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 60753 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: "(" Cc: 60753@debbugs.gnu.org Received: via spool by 60753-submit@debbugs.gnu.org id=B60753.167354530410136 (code B ref 60753); Thu, 12 Jan 2023 17:42:01 +0000 Received: (at 60753) by debbugs.gnu.org; 12 Jan 2023 17:41:44 +0000 Received: from localhost ([127.0.0.1]:48513 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pG1aB-0002dP-NT for submit@debbugs.gnu.org; Thu, 12 Jan 2023 12:41:44 -0500 Received: from wout1-smtp.messagingengine.com ([64.147.123.24]:36523) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pG1a8-0002dA-QA for 60753@debbugs.gnu.org; Thu, 12 Jan 2023 12:41:42 -0500 Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.west.internal (Postfix) with ESMTP id 7D5E43200921; Thu, 12 Jan 2023 12:41:33 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute1.internal (MEProxy); Thu, 12 Jan 2023 12:41:33 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=daviwil.com; h= cc:cc:content-transfer-encoding:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm1; t=1673545293; x= 1673631693; bh=maBoLn/A0riPhPFOMtuBS4MzdgYoUChc43sxx2G8g/I=; b=M Wa9xwBm/lPNKxnY0z3uWeQ+mDIGmqe2wb4s/7eXnzw1FEE1ewfhpcQ1W2nKjC0aP yAWzBJiYxXqqlr/T6JNjw9k+dT0TgtTG0fpo3sJVHOEaQaY860auxQYPcpDZV4Q5 /zmJmhIzGIUWFGMwJsHHn7EWg+RoQEnltrt5utVlqBFf0ZaVQwKm2PzEHsw4xn3A xamE2573CbLk6ywTxUFlvuQ5YcbPEK2uiGLvJIKwtSKBpHLOVZrxtSZB1jXmAtlh YoI4wdvyjThXfXX8B4ZIWSpjR1k7FqGKq/kfOkT/gjCUAHqsHdKiqgGmqMj0qLOq wOKgPl3An4vTy0LJ+CqFQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1673545293; x= 1673631693; bh=maBoLn/A0riPhPFOMtuBS4MzdgYoUChc43sxx2G8g/I=; b=s iskkSD8QS6qAw5/n9fsIqMWoOujyrGDOtUCQu/6tV4G7f96HuS6rqVb4/AcJEY5D USXggc02hewrx16bYeCibglQf04oR8I+G6jJun8f9oHAe3wQ7Im2mBGKwWTDRdjW K/6WuIdLBiANmPe/ko2mL5Pn76jzJ2pHTaGg1ogFf1b1jOp9fjK0v1r5p6jTbAoe JTkGuCfG+N+zAdo1wRn1brmNVVosMn7ymXeKC1LB7mFAfKl8sq5PaZhW7lyTN5ua Crr5s2V5lU+WeRO6YNJOmz+YDQBudz8AMVZsx6HQ9GpkY9DETC1o8DNsVQydN2ii LhRH6bJv+SknrXVjvKcgQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrleeigddutdegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpehffgfhvfevufffjgfkgggtgfesth hqredttderjeenucfhrhhomhepffgrvhhiugcuhghilhhsohhnuceouggrvhhiugesuggr vhhifihilhdrtghomheqnecuggftrfgrthhtvghrnhepteeigeeutdeigfekudevgfegie fgfeduveefffehfeehvdfhtedtfeevfeefudeknecuffhomhgrihhnpehgnhhurdhorhhg necuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepuggrvh hiugesuggrvhhifihilhdrtghomh X-ME-Proxy: Feedback-ID: iba684179:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 12 Jan 2023 12:41:32 -0500 (EST) References: <87edrzzw9w.fsf@daviwil.com> User-agent: mu4e 1.8.11; emacs 28.2 From: David Wilson Date: Thu, 12 Jan 2023 19:27:02 +0200 In-reply-to: Message-ID: <87v8lby7jq.fsf@daviwil.com> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org X-getmail-retrieved-from-mailbox: Patches Hey (! "(" writes: > 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: ( --- 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 -- 2.38.1 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 ( +;;; Copyright © 2023 David Wilson +;;; +;;; 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 . + +(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 + (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 \