From patchwork Mon Mar 3 02:09:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Nicolas Graves X-Patchwork-Id: 39629 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 EB95427BBEA; Mon, 3 Mar 2025 02:10:23 +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=-7.4 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_BLOCKED,RCVD_IN_MSPIKE_H2, RCVD_IN_VALIDITY_CERTIFIED,RCVD_IN_VALIDITY_RPBL,RCVD_IN_VALIDITY_SAFE, SPF_HELO_PASS,URIBL_BLOCKED autolearn=ham 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 7D3CF27BBE2 for ; Mon, 3 Mar 2025 02:10:21 +0000 (GMT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tovG4-00034S-8q; Sun, 02 Mar 2025 21:10:16 -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 1tovFr-0002z1-Mn for guix-patches@gnu.org; Sun, 02 Mar 2025 21:10:04 -0500 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tovFr-0000tM-9q for guix-patches@gnu.org; Sun, 02 Mar 2025 21:10:03 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:Date:From:To:In-Reply-To:References:Subject; bh=Pb8dOfTqssof1lM/EV2v+WfLfaW7KVwbhUwSIkvxrSg=; b=NDWLXg4FDLDWyE8sVfVEQWwbWFpGL5yR6AkH1HbrLe84/NdKLfKn8bF7YZffxSgR9j9SyBsc3YyqY/V+ioG7scVQjv4JVx6iQhKxiLGsa46zhXoPaqR3JR3PKnUdMFC5OO5wDxWtorNbIZKuaPagakjtZ5PULFPnedNzaqZQxEpN4cmkwVHGxCuFTceAG/Ssw/R1C1u9k5LX0QvNE/MxShEsZtR62mjfNCBaXP4VJ37CnavDO10cydmLS8JcnkPvktVJDR7MpV/fKkpuxNOGL7M+j+yIHPweGKBKs4h/ZCjTCUJEzNcZFuf+F6RiPxkQ7PbHQSm6tPcjQuJk+nJvsA==; Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1tovFr-0007eb-3B for guix-patches@gnu.org; Sun, 02 Mar 2025 21:10:03 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#76699] [PATCH 1/5] Switch to transient References: <20250303020636.3461-1-ngraves@ngraves.fr> In-Reply-To: <20250303020636.3461-1-ngraves@ngraves.fr> Resent-From: Nicolas Graves Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Mon, 03 Mar 2025 02:10:03 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 76699 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 76699@debbugs.gnu.org Cc: Nicolas Graves Received: via spool by 76699-submit@debbugs.gnu.org id=B76699.174096779229325 (code B ref 76699); Mon, 03 Mar 2025 02:10:03 +0000 Received: (at 76699) by debbugs.gnu.org; 3 Mar 2025 02:09:52 +0000 Received: from localhost ([127.0.0.1]:40747 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tovFc-0007cX-Np for submit@debbugs.gnu.org; Sun, 02 Mar 2025 21:09:52 -0500 Received: from 15.mo583.mail-out.ovh.net ([178.33.107.29]:51525) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1tovFS-0007aw-DG for 76699@debbugs.gnu.org; Sun, 02 Mar 2025 21:09:44 -0500 Received: from director8.ghost.mail-out.ovh.net (unknown [10.109.139.176]) by mo583.mail-out.ovh.net (Postfix) with ESMTP id 4Z5j1X4xGVz1SyY for <76699@debbugs.gnu.org>; Mon, 3 Mar 2025 02:09:36 +0000 (UTC) Received: from ghost-submission-5b5ff79f4f-klvlq (unknown [10.110.188.182]) by director8.ghost.mail-out.ovh.net (Postfix) with ESMTPS id 52F651FD42; Mon, 3 Mar 2025 02:09:36 +0000 (UTC) Received: from ngraves.fr ([37.59.142.101]) by ghost-submission-5b5ff79f4f-klvlq with ESMTPSA id bJD6AGAPxWdTfgIAxguJDg (envelope-from ); Mon, 03 Mar 2025 02:09:36 +0000 Authentication-Results: garm.ovh; auth=pass (GARM-101G004ee1ee68e-4a78-4fbb-b92e-b54a20d94d0d, 3FD0527DE2CE9D3C35B0E9483E243F320C79A24B) smtp.auth=ngraves@ngraves.fr X-OVh-ClientIp: 90.92.117.144 Date: Mon, 3 Mar 2025 03:09:16 +0100 Message-ID: <20250303020932.4194-1-ngraves@ngraves.fr> X-Mailer: git-send-email 2.48.1 MIME-Version: 1.0 X-Ovh-Tracer-Id: 1107885510514369250 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: 49 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdeljeekkecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecuogfuuhhsphgvtghtffhomhgrihhnucdlgeelmdenucfjughrpefhvfevufffkffogggtgfesthekredtredtjeenucfhrhhomheppfhitgholhgrshcuifhrrghvvghsuceonhhgrhgrvhgvshesnhhgrhgrvhgvshdrfhhrqeenucggtffrrghtthgvrhhnpeelgeeihfevledtffdvieefleelveehheejgedtkeekiedugeffudeuudehudduveenucffohhmrghinhepghhithhhuhgsrdgtohhmpdhmrghgihhtrdhvtgdpnhhonhhgnhhurdhorhhgpdhgnhhurdhorhhgpdhgihhtlhgrsgdrihhonecukfhppeduvdejrddtrddtrddupdeltddrledvrdduudejrddugeegpdefjedrheelrddugedvrddutddunecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehinhgvthepuddvjedrtddrtddruddpmhgrihhlfhhrohhmpehnghhrrghvvghssehnghhrrghvvghsrdhfrhdpnhgspghrtghpthhtohepuddprhgtphhtthhopeejieeileelseguvggssghughhsrdhgnhhurdhorhhgpdfovfetjfhoshhtpehmohehkeefmgdpmhhouggvpehsmhhtphhouhht DKIM-Signature: a=rsa-sha256; bh=Pb8dOfTqssof1lM/EV2v+WfLfaW7KVwbhUwSIkvxrSg=; c=relaxed/relaxed; d=ngraves.fr; h=From; s=ovhmo4487190-selector1; t=1740967776; v=1; b=0ILNUK9SRHElYDHiW7ao/+B9AZiUFtnFsiKV828U7LdQ1OIueQ3RE8zdS7lovakzC/KI1t3h zXPapjfRikwY98O4gcaU9Ka4bZP7dNB4C3nEqKZ0RlvVhi9kluMAqby1/o2CLWXacDqT45eV0MX lJhJZBNbj5eoPyRBBSygPfMhUKom8yElvJLkCUldcJRhyVpNkZnNUeCKyk0q9isOBCZ15+aR5eV MWCo0cHxAPWwa9rvNe3geXcFLWhJTXfrFDqMn0HbDyG4u7QZ0dT57yH7jzMW3HVmV4yY3iwZsQf 6L/7GSngKx+x9fFu7lkqiJxFIkMIyTxclLt31uD1eY96A== 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: , Reply-to: Nicolas Graves X-ACL-Warn: , Nicolas Graves via Guix-patches X-Patchwork-Original-From: Nicolas Graves via Guix-patches via From: Nicolas Graves 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 --- README | 2 +- configure.ac | 16 +-- doc/emacs-guix.texi | 55 +++++----- doc/htmlxref.cnf | 6 +- elisp/guix-command.el | 114 ++++++++++---------- elisp/guix-help.el | 2 +- elisp/guix-popup.el | 227 ---------------------------------------- elisp/guix-transient.el | 187 +++++++++++++++++++++++++++++++++ elisp/guix.el | 2 +- elisp/local.mk | 6 +- 10 files changed, 288 insertions(+), 329 deletions(-) delete mode 100644 elisp/guix-popup.el create mode 100644 elisp/guix-transient.el diff --git a/README b/README index 55a6956..6a63f97 100644 --- a/README +++ b/README @@ -34,7 +34,7 @@ In short, Emacs-Guix provides the following features: + [[/gnu/store]] items -- Magit-like popup interface for all Emacs-Guix and Guix shell commands +- Magit-like keyboard-driven menu for all Emacs-Guix and Guix shell commands (=M-x guix=). - Modes to view logs of package builds (=guix-build-log-mode= and diff --git a/configure.ac b/configure.ac index dd1de4b..3461bb3 100644 --- a/configure.ac +++ b/configure.ac @@ -130,18 +130,18 @@ AC_ARG_WITH([editindirect-lispdir], [editindirectlispdir="no"]) AC_SUBST([editindirectlispdir]) -AC_ARG_WITH([popup-lispdir], - [AS_HELP_STRING([--with-popup-lispdir], - [directory with magit-popup.el file])], - [popuplispdir="$withval"], - [popuplispdir="no"]) -AC_SUBST([popuplispdir]) +AC_ARG_WITH([transient-lispdir], +[AS_HELP_STRING([--with-transient-lispdir], + [directory with transient.el file])], + [transientlispdir="$withval"], + [transientlispdir="no"]) +AC_SUBST([transientlispdir]) AM_CONDITIONAL([GEISER_DIR], [test "x$geiserlispdir" != "xno"]) AM_CONDITIONAL([DASH_DIR], [test "x$dashlispdir" != "xno"]) AM_CONDITIONAL([BUI_DIR], [test "x$builispdir" != "xno"]) AM_CONDITIONAL([EDITINDIRECT_DIR], [test "x$editindirectlispdir" != "xno"]) -AM_CONDITIONAL([POPUP_DIR], [test "x$popuplispdir" != "xno"]) +AM_CONDITIONAL([TRANSIENT_DIR], [test "x$transientlispdir" != "xno"]) dnl If all elisp dependencies are specified, we can use "emacs -Q" for dnl byte-compilation. Otherwise, "emacs" will be used, and it will @@ -151,7 +151,7 @@ AM_CONDITIONAL([EMACS_Q], "x$dashlispdir" != "xno" -a \ "x$builispdir" != "xno" -a \ "x$editindirectlispdir" != "xno" -a \ - "x$popuplispdir" != "xno"]) + "x$transientlispdir" != "xno"]) dnl ---------------------------------------------------------------- diff --git a/doc/emacs-guix.texi b/doc/emacs-guix.texi index 3219354..6bb3810 100644 --- a/doc/emacs-guix.texi +++ b/doc/emacs-guix.texi @@ -53,7 +53,7 @@ A copy of the license is available at * System:: Interface for @code{operating-system} and services. * Store Items:: Interface for store items. * Package Licenses:: Interface for licenses of packages. -* Popup Interface:: Magit-like interface for Emacs-Guix commands. +* Keyboard-driven Menu:: Magit-like interface for Emacs-Guix commands. * Prettify Mode:: Abbreviating @file{/gnu/store/@dots{}} file names. * Prettify Variables:: Split and indent Shell variables. * Build Log Mode:: Highlighting Guix build logs. @@ -77,8 +77,8 @@ Indexes Emacs-Guix (also known as ``guix.el'') provides various interfaces and tools related to the GNU Guix package manager. -Call @kbd{M-x guix} if you prefer to dive in right away (@pxref{Popup -Interface}). +Call @kbd{M-x guix} if you prefer to dive in right away +(@pxref{Keyboard-driven Menu}). In short, Emacs-Guix provides the following features: @@ -99,8 +99,8 @@ Interfaces for: @end itemize @item -Magit-like popup interface for all Emacs-Guix @kbd{M-x} commands and -Guix shell commands (@pxref{Popup Interface}). +Keyboard-driven magit-like menu for all Emacs-Guix @kbd{M-x} and Guix +shell commands (@pxref{Keyboard-driven Menu}). @item Modes to view logs of package builds (@pxref{Build Log Mode}). @@ -185,10 +185,9 @@ features as without Guix. interfaces (to display packages, generations, licenses, etc.). @item -@uref{https://github.com/magit/magit-popup, magit-popup library}. You -already have this library if you use Magit 2.1.0 or later. This -library is required only for @kbd{M-x@tie{}guix} command (@pxref{Popup -Interface}). +@uref{https://github.com/magit/transient, transient library}. This +library is required only for @kbd{M-x@tie{}guix} command +(@pxref{Keyboard-driven Menu}). @item @uref{https://github.com/Fanael/edit-indirect, edit-indirect library}, @@ -204,7 +203,7 @@ list of packages (@pxref{Package Keys}). @end itemize To sum up, most likely, you'll need all the above dependencies except -maybe @code{magit-popup}, @code{edit-indirect} and @code{build-farm}. +maybe @code{transient}, @code{edit-indirect} and @code{build-farm}. @node Using from Git @section Using from Git @@ -1058,24 +1057,24 @@ Open @file{@dots{}/guix/licenses.scm} and move to the specified license. @end table @c ---------------------------------------------------------------- -@node Popup Interface -@chapter Popup Interface +@node Keybord-driven Menu +@chapter Keybord-driven Menu -If you ever used Magit, you know what ``popup interface'' is -(@pxref{Top,,, magit-popup, Magit-Popup User Manual}). Even if you are -not acquainted with Magit, there should be no worries as it is very -intuitive. +Transient is the library used to implement keybord-driven ``menus'' like +in Magit (@pxref{Top,,, transient, Transient User Manual}). Even if you +are not acquainted with Magit, this interface it is very intuitive. @findex guix -So, @kbd{M-x@tie{}guix} command provides a top-level popup interface -for almost all the available Emacs-Guix commands. It has 2 advantages -comparing with calling @kbd{M-x@tie{}guix-@dots{}} commands directly: +So, @kbd{M-x@tie{}guix} command provides a top-level keyboard-driven +menu for almost all the available Emacs-Guix commands. It has 2 +advantages comparing with calling @kbd{M-x@tie{}guix-@dots{}} commands +directly: @itemize @item There is no need to remember the names of Emacs-Guix commands, as you -can always find them in @kbd{M-x@tie{}guix} and its sub-popups. +can always find them in @kbd{M-x@tie{}guix} and its suffix transients. @item It is faster (well, if you know what you are going to call), as it may @@ -1092,17 +1091,17 @@ easy accessible key combination, for example, to @kbd{@key{super}-g}: (global-set-key (kbd "s-g") 'guix) @end example -@node Guix Popup Interface -@section Guix Popup Interface +@node Guix Keyboard-driven Menu +@section Guix Keyboard-driven Menu @findex guix-command -There is one rather special sub-popup in @kbd{M-x@tie{}guix}. It is -bind to @kbd{c} by default, and you can call it separately with -@kbd{M-x@tie{}guix-command}. It is a popup interface for -@code{guix@tie{}@dots{}} shell commands. It is probably not very +There is one rather special transient suffix in @kbd{M-x@tie{}guix}. It +is bind to @kbd{c} by default, and you can call it separately with +@kbd{M-x@tie{}guix-command}. It is a keyboard-driven, magit-like menu +for @code{guix@tie{}@dots{}} shell commands. It is probably not very useful, as it provides all the options and flags for all the shell -actions and subcommands, so it may be confusing to see them all at -once. Nevertheless, a description of this thing follows. +actions and subcommands, so it may be confusing to see them all at once. +Nevertheless, a description of this thing follows. When you select an option, you'll be prompted for a value in the minibuffer. Many values have completions, so don't hesitate to press diff --git a/doc/htmlxref.cnf b/doc/htmlxref.cnf index d547107..b42ac28 100644 --- a/doc/htmlxref.cnf +++ b/doc/htmlxref.cnf @@ -4,9 +4,9 @@ # manuals in the generated HTML pages (created by "make manual" # command). See (info "(texinfo) HTML Xref Configuration") for details. -MAGIT_POPUP = https://magit.vc/manual/magit-popup -magit-popup mono ${MAGIT_POPUP} -magit-popup node ${MAGIT_POPUP}/ +TRANSIENT = https://magit.vc/manual/transient +transient mono ${TRANSIENT} +transient node ${TRANSIENT}/ GEISER = http://www.nongnu.org/geiser geiser mono ${GEISER} diff --git a/elisp/guix-command.el b/elisp/guix-command.el index cbfc0fa..affda4e 100644 --- a/elisp/guix-command.el +++ b/elisp/guix-command.el @@ -1,4 +1,4 @@ -;;; guix-command.el --- Popup interface for guix shell commands -*- lexical-binding: t -*- +;;; guix-command.el --- Transient interface for guix shell commands -*- lexical-binding: t -*- ;; Copyright © 2015–2020 Alex Kost @@ -19,16 +19,16 @@ ;;; Commentary: -;; This file provides a magit-like popup interface for guix shell -;; commands. You can run a selected command in *shell* buffer, in Guix -;; REPL, or simply copy it into `kill-ring'. +;; This file provides a transient interface for guix shell commands. +;; You can run a selected command in *shell* buffer, in Guix REPL, or +;; simply copy it into `kill-ring'. ;; ;; The entry point is "M-x guix-command". When it is called the first ;; time, "guix --help" output is parsed and `guix-COMMAND-action' ;; functions are generated for each available guix COMMAND. Then a ;; window with these commands is popped up. When a particular COMMAND ;; is called, "guix COMMAND --help" output is parsed, and a user get a -;; new popup window with available options for this command and so on. +;; new transient window with available options for this command and so on. ;; To avoid hard-coding all guix options, actions, etc., as much data is ;; taken from "guix ... --help" outputs as possible. But this data is @@ -40,7 +40,7 @@ ;; structures. ;; Only "M-x guix-command" is available after this file is loaded. The -;; rest commands/actions/popups are generated on the fly only when they +;; rest commands/actions/transients are generated on the fly only when they ;; are needed (that's why there is a couple of `eval'-s in this file). ;; COMMANDS argument is used by many functions in this file. It means a @@ -48,7 +48,7 @@ ;; ("import" "gnu"). The empty list stands for the plain "guix" without ;; subcommands. -;; All actions in popup windows are divided into 2 groups: +;; All actions in transient windows are divided into 2 groups: ;; ;; - 'Popup' actions - used to pop up another window. For example, every ;; action in the 'guix' or 'guix import' window is a popup action. They @@ -56,13 +56,13 @@ ;; ;; - 'Execute' actions - used to do something with the command line (to ;; run a command in Guix REPL or to copy it into kill-ring) constructed -;; with the current popup. They are defined by +;; with the current transient. They are defined by ;; `guix-command-define-execute-action' macro. ;;; Code: (require 'cl-lib) -(require 'magit-popup) +(require 'transient) (require 'bui-utils) (require 'guix nil t) (require 'guix-utils) @@ -74,7 +74,7 @@ (require 'guix-external) (defgroup guix-commands nil - "Settings for guix popup windows." + "Settings for guix transient windows." :group 'guix) (defvar guix-command-complex-with-shared-arguments @@ -484,10 +484,10 @@ to be modified." argument)) (defun guix-command-improve-arguments (arguments commands) - "Return ARGUMENTS for 'guix COMMANDS ...' modified for popup interface." + "Return ARGUMENTS for 'guix COMMANDS ...' modified for transient interface." (let ((improvers (cons 'guix-command-improve-common-argument (bui-assoc-value guix-command-argument-improvers - commands)))) + commands)))) (mapcar (lambda (argument) (guix-command-improve-argument argument improvers)) arguments))) @@ -592,7 +592,7 @@ commands.") "Return additional arguments for COMMANDS." (let ((rest-arg (guix-command-rest-argument commands))) (append (bui-assoc-value guix-command-additional-arguments - commands) + commands) (and rest-arg (list rest-arg))))) ;; Ideally, only `guix-command-all-arguments' function should exist with @@ -611,7 +611,7 @@ commands.") (defun guix-command-all-arguments (&optional commands) ;; Note: `guix-command-arguments' name cannot be used because function - ;; with this name is generated by `magit-define-popup'. + ;; with this name is generated by `transient-define-prefix'. "Return list of arguments for 'guix COMMANDS ...'." (let ((command (car commands))) (if (member command @@ -634,28 +634,25 @@ commands.") (guix-command--all-arguments-memoize (list command)))) (guix-command--all-arguments commands)))) -(defun guix-command-switch->popup-switch (switch) - "Return popup switch from command SWITCH argument." - (list (guix-command-argument-char switch) +(defun guix-command-switch->transient-switch (switch) + "Return transient switch from command SWITCH argument." + (list (format "-%c" (guix-command-argument-char switch)) + (guix-command-argument-name switch) (or (guix-command-argument-doc switch) - "Unknown") - (guix-command-argument-name switch))) + "Unknown"))) -(defun guix-command-option->popup-option (option) - "Return popup option from command OPTION argument." - (list (guix-command-argument-char option) +(defun guix-command-option->transient-option (option) + "Return transient option from command OPTION argument." + (list (format "-%c" (guix-command-argument-char option)) + (guix-command-argument-name option) (or (guix-command-argument-doc option) "Unknown") - (let ((name (guix-command-argument-name option))) - (if (string-match-p " \\'" name) ; ends with space - name - (concat name "="))) (or (guix-command-argument-fun option) 'read-from-minibuffer))) -(defun guix-command-action->popup-action (action) - "Return popup action from command ACTION argument." - (list (guix-command-argument-char action) +(defun guix-command-action->transient-suffix (action) + "Return transient suffix from command ACTION argument." + (list (format "-%c" (guix-command-argument-char action)) (or (guix-command-argument-doc action) (guix-command-argument-name action) "Unknown") @@ -683,8 +680,8 @@ commands.") "Return actions from ARGUMENTS." (cl-remove-if-not #'guix-command-argument-action? arguments)) - -;;; Post processing popup arguments + +;;; Post processing transient arguments (defvar guix-command-post-processors '(("environment" @@ -698,7 +695,7 @@ commands.") ("system" guix-command-post-process-rest-single)) "Alist of guix commands and functions for post-processing -a list of arguments returned from popup interface. +a list of arguments returned from transient interface. Each function is called on the returned arguments in turn.") (defvar guix-command-rest-arg-regexp @@ -760,13 +757,13 @@ Leave '--' string as a separate argument." :split? t)) (defun guix-command-post-process-package-args (args) - "Adjust popup ARGS for 'guix package' command." + "Adjust transient ARGS for 'guix package' command." (guix-command-post-process-matching-args args (rx string-start (or "--install " "--remove ") (+ any)) :split? t)) (defun guix-command-post-process-environment-packages (args) - "Adjust popup ARGS for specified packages of 'guix environment' + "Adjust transient ARGS for specified packages of 'guix environment' command." (guix-command-post-process-matching-args args (rx string-start "++packages " (group (+ any))) @@ -774,14 +771,14 @@ command." :split? t)) (defun guix-command-post-process-environment-ad-hoc (args) - "Adjust popup ARGS for '--ad-hoc' argument of 'guix environment' + "Adjust transient ARGS for '--ad-hoc' argument of 'guix environment' command." (guix-command-post-process-matching-args args (rx string-start "--ad-hoc " (+ any)) :split? t)) (defun guix-command-post-process-args (commands args) - "Adjust popup ARGS for guix COMMANDS." + "Adjust transient ARGS for guix COMMANDS." (let* ((command (car commands)) (processors (append (bui-assoc-value guix-command-post-processors commands) @@ -931,32 +928,31 @@ open the log file(s)." ;;; Generating popups, actions, etc. (defmacro guix-command-define-popup-action (name &optional commands) - "Define NAME function to generate (if needed) and run popup for COMMANDS." + "Define NAME function to generate (if needed) and run transient for COMMANDS." (declare (indent 1) (debug t)) - (let* ((popup-fun (guix-command-symbol `(,@commands "popup"))) + (let* ((prefix-fun (guix-command-symbol `(,@commands "prefix"))) (doc (format "Call `%s' (generate it if needed)." - popup-fun))) + prefix-fun))) `(defun ,name (&optional arg) ,doc (interactive "P") - (unless (fboundp ',popup-fun) - (guix-command-generate-popup ',popup-fun ',commands)) - (,popup-fun arg)))) + (unless (fboundp ',prefix-fun) + (guix-command-generate-prefix ',prefix-fun ',commands)) + (,prefix-fun)))) (defmacro guix-command-define-execute-action (name executor &optional commands) "Define NAME function to execute the current action for guix COMMANDS. EXECUTOR function is called with the current command line arguments." (declare (indent 1) (debug t)) - (let* ((arguments-fun (guix-command-symbol `(,@commands "arguments"))) - (doc (format "Call `%s' with the current popup arguments." + (let* ((doc (format "Call `%s' with the current transient arguments." executor))) `(defun ,name (&rest args) ,doc - (interactive (,arguments-fun)) + (interactive) (,executor (append ',commands (guix-command-post-process-args - ',commands args)))))) + ',commands (transient-args (transient-current-command)))))))) (defun guix-command-generate-popup-actions (actions &optional commands) "Generate 'popup' commands from ACTIONS arguments for guix COMMANDS." @@ -977,11 +973,11 @@ EXECUTOR function is called with the current command line arguments." commands (guix-command-argument-name action)) ,commands)))))) -(defun guix-command-generate-popup (name &optional commands) - "Define NAME popup with 'guix COMMANDS ...' interface." +(defun guix-command-generate-prefix (name &optional commands) + "Define NAME prefix with 'guix COMMANDS ...' interface." (let* ((command (car commands)) (man-page (concat "guix" (and command (concat "-" command)))) - (doc (format "Popup window for '%s' command." + (doc (format "Transient for '%s' command." (guix-concat-strings (cons "guix" commands) " "))) (args (guix-command-all-arguments commands)) @@ -998,18 +994,22 @@ EXECUTOR function is called with the current command line arguments." (guix-command-generate-popup-actions popup-actions commands) (guix-command-generate-execute-actions execute-actions commands)) (eval - `(magit-define-popup ,name + `(transient-define-prefix ,name () ,doc - 'guix-commands :man-page ,man-page - :switches ',(mapcar #'guix-command-switch->popup-switch switches) - :options ',(mapcar #'guix-command-option->popup-option options) - :actions ',(mapcar #'guix-command-action->popup-action actions) - :max-action-columns 4)))) + ,@(and switches + `(["Switches" + ,@(mapcar #'guix-command-switch->transient-switch switches)])) + ,@(and options + `(["Options" + ,@(mapcar #'guix-command-option->transient-option options)])) + ,@(and actions + `(["Actions" + ,@(mapcar #'guix-command-action->transient-suffix actions)])))))) -(declare-function guix-command-popup "guix-command" t) +(declare-function guix-command-prefix "guix-command" t) -;;;###autoload (autoload 'guix-command "guix-command" "Popup window for 'guix' shell commands." t) +;;;###autoload (autoload 'guix-command "guix-command" "Transient for 'guix' shell commands." t) (guix-command-define-popup-action guix-command) (declare-function guix-find-package-definition "guix-package" t) diff --git a/elisp/guix-help.el b/elisp/guix-help.el index da69b09..d4aa472 100644 --- a/elisp/guix-help.el +++ b/elisp/guix-help.el @@ -68,7 +68,7 @@ If ARG is non-nil (interactively with prefix), show Guix info manual." :group 'guix-help-faces) (defvar guix-help-specifications - '("Popup interface for the rest commands" + '("Transient interface for the rest commands" guix "Show packages and their definitions" guix-all-packages diff --git a/elisp/guix-popup.el b/elisp/guix-popup.el deleted file mode 100644 index 77728f6..0000000 --- a/elisp/guix-popup.el +++ /dev/null @@ -1,227 +0,0 @@ -;;; guix-popup.el --- Popup interface for Emacs-Guix commands - -;; Copyright © 2018–2019, 2021 Alex Kost - -;; This file is part of Emacs-Guix. - -;; Emacs-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. -;; -;; Emacs-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 Emacs-Guix. If not, see . - -;;; Commentary: - -;; This file provides popup interface (using `magit-popup' library) for -;; Emacs-Guix commands. - -;;; Code: - -(require 'magit-popup) -(require 'guix-profiles) - -(defgroup guix-popup nil - "Popup interface for Emacs-Guix commands." - :group 'guix) - -;;;###autoload (autoload 'guix-popup "guix-popup" nil t) -(magit-define-popup guix-popup - "Show popup buffer for Emacs-Guix commands." - 'guix-popup - :actions '("Sub-popups" - (?p "packages" guix-package-popup) - (?P "profiles" guix-profile-popup) - (?s "services" guix-service-popup) - (?y "system commands" guix-system-popup) - (?l "package licenses" guix-license-popup) - (?S "store" guix-store-popup) - (?m "major/minor modes" guix-mode-popup) - (?c "guix shell commands" guix-command) - "Miscellaneous commands" - (?H "calculate file hash" guix-hash) - (?E "set Emacs environment" guix-set-emacs-environment) - "Auxiliary commands" - (?a "about" guix-about) - (?h "help (\"refcard\")" guix-help) - (?i "info manual" guix-info) - (?v "version" guix-version) - (?b "switch to buffer" guix-switch-to-buffer) - (?B "report guix bug" guix-report-bug)) - :max-action-columns #'guix-popup-max-columns) - -(defun guix-popup-max-columns (heading) - "Return the number of `:max-action-columns' for HEADING. -This function is used by command `guix-popup'." - (pcase heading - ("Sub-popups" 1) - ("Miscellaneous commands" 1) - (_ 2))) - -;;;###autoload -(defalias 'guix #'guix-popup - "Popup interface for Emacs-Guix commands.") - -(defun guix-popup-variable-value (var-name) - "Return string formatted for popup buffer. -String is made of variable VAR-NAME and its value." - (concat (propertize (symbol-name var-name) - 'face font-lock-variable-name-face) - " " - (propertize (prin1-to-string (symbol-value var-name)) - 'face 'magit-popup-option-value))) - -(defun guix-popup-format-profile () - "Return profile, formatted for '\\[guix-popup]'." - (guix-popup-variable-value 'guix-current-profile)) - -(defvar guix-popup-profile-variable - '(?p "profile" - guix-set-current-profile - guix-popup-format-profile) - "Popup structure for variable `guix-current-profile'.") - - -;;; Sub-popups - -(magit-define-popup guix-package-popup - "Show popup buffer for package commands." - 'guix-package-popup - :variables (list guix-popup-profile-variable) - :actions '("Show packages" - (?a "all" guix-all-packages) - (?i "installed" guix-installed-packages) - (?o "obsolete" guix-obsolete-packages) - (?s "superseded" guix-superseded-packages) - (?h "hidden" guix-hidden-packages) - "Search for packages" - (?n "by name" guix-packages-by-name) - (?N "by regexp (in name only)" guix-packages-by-name-regexp) - (?r "by regexp (in name, synopsis, description)" - guix-packages-by-regexp) - (?L "by location" guix-packages-by-location) - (?c "by license" guix-packages-by-license) - (?d "depending on other package(s)" guix-dependent-packages) - (?f "packages from file" guix-package-from-file) - (?y "packages from system config file" - guix-packages-from-system-config-file) - "Package locations" - (?l "show package locations" guix-package-locations) - (?e "\"edit\" package (find package definition)" - guix-find-package-definition) - (?F "find location file" guix-find-package-location-file) - "Other commands" - (?g "package graph" guix-package-graph) - (?z "package size" guix-package-size) - (?t "package lint" guix-package-lint) - (?C "lint checkers" guix-lint-checkers) - (?T "total number of packages" guix-number-of-packages)) - :max-action-columns #'guix-package-popup-max-columns) - -(defun guix-package-popup-max-columns (heading) - "Return the number of `:max-action-columns' for HEADING. -This function is used by command `guix-package-popup'." - (pcase heading - ("Show packages" 2) - ("Other commands" 2) - (_ 1))) - -(magit-define-popup guix-profile-popup - "Show popup buffer for profiles and generations commands." - 'guix-profile-popup - :variables (list guix-popup-profile-variable) - :actions '("Show profiles" - (?a "all" guix-profiles) - (?s "system" guix-system-profile) - (?h "home" guix-home-profile) - (?c "current" guix-current-profile) - "Show generations (of the current profile)" - (?g "all" guix-generations) - (?t "by time" guix-generations-by-time) - (?l "last" guix-last-generations) - "Other commands" - (?M "apply manifest to the current profile" - guix-apply-manifest)) - :max-action-columns 1) - -(magit-define-popup guix-service-popup - "Show popup buffer for service commands." - 'guix-service-popup - :actions '("Show services" - (?a "all system services" guix-all-services) - (?h "all Home services" guix-all-home-services) - (?d "default" guix-default-services) - (?n "by name" guix-services-by-name) - (?r "by regexp" guix-services-by-regexp) - (?L "by location" guix-services-by-location) - (?y "services from system config file" - guix-services-from-system-config-file) - "Service locations" - (?l "show service locations" guix-service-locations) - (?e "\"edit\" service (find service definition)" - guix-find-service-definition) - (?F "find location file" guix-find-service-location-file)) - :max-action-columns 1) - -(magit-define-popup guix-system-popup - "Show popup buffer for system commands." - 'guix-system-popup - :actions '("From system profile" - (?p "packages" guix-installed-system-packages) - (?P "profile" guix-system-profile) - (?g "all generations" guix-system-generations) - (?t "generations by time" guix-system-generations-by-time) - (?l "last generations" guix-last-system-generations) - "From system configuration file" - (?y "system" guix-system-from-file) - (?k "packages" guix-packages-from-system-config-file) - (?s "services" guix-services-from-system-config-file)) - :max-action-columns 1) - -(magit-define-popup guix-license-popup - "Show popup buffer for license commands." - 'guix-license-popup - :actions '((?a "show all package licenses" guix-licenses) - (?u "browse license URL" guix-browse-license-url) - (?e "\"edit\" license (find license definition)" - guix-find-license-definition) - (?F "find license location file" - guix-find-license-location-file)) - :max-action-columns 1) - -(magit-define-popup guix-store-popup - "Show popup buffer for store commands." - 'guix-store-popup - :actions '("Show store items" - (?l "live items" guix-store-live-items) - (?d "dead items" guix-store-dead-items) - (?e "failures" guix-store-failures) - (?i "single item" guix-store-item) - (?D "derivers" guix-store-item-derivers) - (?R "requisites" guix-store-item-requisites) - (?f "referrers" guix-store-item-referrers) - (?F "references" guix-store-item-references)) - :max-action-columns 2) - -(magit-define-popup guix-mode-popup - "Show popup buffer for Emacs-Guix major/minor modes." - 'guix-mode-popup - :actions '("Modes" - (?p "guix-prettify-mode" guix-prettify-mode) - (?P "global-guix-prettify-mode" global-guix-prettify-mode) - (?b "guix-build-log-minor-mode" guix-build-log-minor-mode) - (?B "guix-build-log-mode" guix-build-log-mode) - (?d "guix-devel-mode" guix-devel-mode) - (?D "guix-derivation-mode" guix-derivation-mode) - (?e "guix-env-var-mode" guix-env-var-mode)) - :max-action-columns 1) - -(provide 'guix-popup) - -;;; guix-popup.el ends here diff --git a/elisp/guix-transient.el b/elisp/guix-transient.el new file mode 100644 index 0000000..36a4733 --- /dev/null +++ b/elisp/guix-transient.el @@ -0,0 +1,187 @@ +;;; guix-transient.el --- Transient interface for Emacs-Guix commands + +;; Copyright © 2018–2019, 2021 Alex Kost +;; Copyright © 2025 Nicolas Graves + +;; This file is part of Emacs-Guix. + +;; Emacs-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. +;; +;; Emacs-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 Emacs-Guix. If not, see . + +;;; Commentary: + +;; This file provides transient interface (using `transient' library) for +;; Emacs-Guix commands. + +;;; Code: + +(require 'transient) +(require 'guix-profiles) + +(defgroup guix-transient nil + "Transient interface for Emacs-Guix commands." + :group 'guix) + +(defun guix-transient-format-profile () + "Return profile, formatted for `\\[guix-transient]'." + (interactive) + (concat (propertize "profile" + 'face 'transient-heading) + " " + (propertize (symbol-value 'guix-current-profile) + 'face 'transient-value))) + +(transient-define-infix guix-set-profile-infix () + :class 'transient-lisp-variable + :variable 'guix-current-profile + :reader 'guix-set-current-profile + :description "Set profile") + +;;;###autoload +(transient-define-prefix guix-transient () + "Show transient interface for Emacs-Guix commands." + [["Sub-menus" + ("p" "packages" guix-package-transient) + ("P" "profiles" guix-profile-transient) + ("s" "services" guix-service-transient) + ("y" "system commands" guix-system-transient) + ("l" "package licenses" guix-license-transient) + ("S" "store" guix-store-transient) + ("m" "major/minor modes" guix-mode-transient) + ("c" "guix shell commands" guix-command)] + ["Miscellaneous commands" + ("H" "calculate file hash" guix-hash) + ("E" "set Emacs environment" guix-set-emacs-environment)] + ["Auxiliary commands" + ("a" "about" guix-about) + ("h" "help (\"refcard\")" guix-help) + ("i" "info manual" guix-info) + ("v" "version" guix-version) + ("b" "switch to buffer" guix-switch-to-buffer) + ("B" "report guix bug" guix-report-bug)]]) + +;;;###autoload +(defalias 'guix #'guix-transient + "Transient interface for Emacs-Guix commands.") + +(transient-define-prefix guix-package-transient () + "Show transient interface for package commands." + ["Profile" + ("p" "Set profile" guix-set-profile-infix) + ("v" "Current profile" guix-transient-format-profile :transient nil :if (lambda () guix-current-profile))] + ["Show packages" + ("a" "all" guix-all-packages) + ("i" "installed" guix-installed-packages) + ("o" "obsolete" guix-obsolete-packages) + ("s" "superseded" guix-superseded-packages) + ("h" "hidden" guix-hidden-packages)] + ["Search for packages" + ("n" "by name" guix-packages-by-name) + ("N" "by regexp (in name only)" guix-packages-by-name-regexp) + ("r" "by regexp (in name, synopsis, description)" guix-packages-by-regexp) + ("L" "by location" guix-packages-by-location) + ("c" "by license" guix-packages-by-license) + ("d" "depending on other package(s)" guix-dependent-packages) + ("f" "packages from file" guix-package-from-file) + ("y" "packages from system config file" guix-packages-from-system-config-file)] + ["Package locations" + ("l" "show package locations" guix-package-locations) + ("e" "\"edit\" package (find package definition)" guix-find-package-definition) + ("F" "find location file" guix-find-package-location-file)] + ["Other commands" + ("g" "package graph" guix-package-graph) + ("z" "package size" guix-package-size) + ("t" "package lint" guix-package-lint) + ("C" "lint checkers" guix-lint-checkers) + ("T" "total number of packages" guix-number-of-packages)]) + +(transient-define-prefix guix-profile-transient () + "Show transient interface for profiles and generations commands." + ["Profile" + ("p" "Set profile" guix-set-profile-infix) + ("v" "Current profile" guix-transient-format-profile :transient nil :if (lambda () guix-current-profile))] + ["Show profiles" + ("a" "all" guix-profiles) + ("s" "system" guix-system-profile) + ("h" "home" guix-home-profile) + ("c" "current" guix-current-profile)] + ["Show generations (of the current profile)" + ("g" "all" guix-generations) + ("t" "by time" guix-generations-by-time) + ("l" "last" guix-last-generations)] + ["Other commands" + ("M" "apply manifest to the current profile" guix-apply-manifest)]) + +(transient-define-prefix guix-service-transient () + "Show transient interface for service commands." + [["Show services" + ("a" "all system services" guix-all-services) + ("h" "all Home services" guix-all-home-services) + ("d" "default" guix-default-services) + ("n" "by name" guix-services-by-name) + ("r" "by regexp" guix-services-by-regexp) + ("L" "by location" guix-services-by-location) + ("y" "services from system config file" guix-services-from-system-config-file)] + ["Service locations" + ("l" "show service locations" guix-service-locations) + ("e" "\"edit\" service (find service definition)" guix-find-service-definition) + ("F" "find location file" guix-find-service-location-file)]]) + +(transient-define-prefix guix-system-transient () + "Show transient interface for system commands." + [["From system profile" + ("p" "packages" guix-installed-system-packages) + ("P" "profile" guix-system-profile) + ("g" "all generations" guix-system-generations) + ("t" "generations by time" guix-system-generations-by-time) + ("l" "last generations" guix-last-system-generations)] + ["From system configuration file" + ("y" "system" guix-system-from-file) + ("k" "packages" guix-packages-from-system-config-file) + ("s" "services" guix-services-from-system-config-file)]]) + +(transient-define-prefix guix-license-transient () + "Show transient interface for license commands." + [["License commands" + ("a" "show all package licenses" guix-licenses) + ("u" "browse license URL" guix-browse-license-url) + ("e" "\"edit\" license (find license definition)" guix-find-license-definition) + ("F" "find license location file" guix-find-license-location-file)]]) + +(transient-define-prefix guix-store-transient () + "Show transient interface for store commands." + [["Show store items" + ("l" "live items" guix-store-live-items) + ("d" "dead items" guix-store-dead-items) + ("e" "failures" guix-store-failures) + ("i" "single item" guix-store-item)] + ["Show details" + ("D" "derivers" guix-store-item-derivers) + ("R" "requisites" guix-store-item-requisites) + ("f" "referrers" guix-store-item-referrers) + ("F" "references" guix-store-item-references)]]) + +(transient-define-prefix guix-mode-transient () + "Show transient interface for Emacs-Guix major/minor modes." + [["Modes" + ("p" "guix-prettify-mode" guix-prettify-mode) + ("P" "global-guix-prettify-mode" global-guix-prettify-mode) + ("b" "guix-build-log-minor-mode" guix-build-log-minor-mode) + ("B" "guix-build-log-mode" guix-build-log-mode) + ("d" "guix-devel-mode" guix-devel-mode) + ("D" "guix-derivation-mode" guix-derivation-mode) + ("e" "guix-env-var-mode" guix-env-var-mode)]]) + +(provide 'guix-transient) + +;;; guix-transient.el ends here diff --git a/elisp/guix.el b/elisp/guix.el index b4c170a..2686a24 100644 --- a/elisp/guix.el +++ b/elisp/guix.el @@ -6,7 +6,7 @@ ;; Version: 0.5.2 ;; URL: https://emacs-guix.gitlab.io/website/ ;; Keywords: tools -;; Package-Requires: ((emacs "24.3") (dash "2.11.0") (geiser "0.8") (bui "1.2.0") (magit-popup "2.1.0") (edit-indirect "0.1.4")) +;; Package-Requires: ((emacs "24.3") (dash "2.11.0") (geiser "0.8") (bui "1.2.0") (transient "0.8.4") (edit-indirect "0.1.4")) ;; This file is part of Emacs-Guix. diff --git a/elisp/local.mk b/elisp/local.mk index 3bc0a27..4efbae5 100644 --- a/elisp/local.mk +++ b/elisp/local.mk @@ -40,8 +40,8 @@ if EDITINDIRECT_DIR AM_ELCFLAGS += -L "$(editindirectlispdir)" endif -if POPUP_DIR - AM_ELCFLAGS += -L "$(popuplispdir)" +if TRANSIENT_DIR + AM_ELCFLAGS += -L "$(transientlispdir)" endif if EMACS_Q @@ -81,7 +81,7 @@ EL_FILES = \ %D%/guix-service.el \ %D%/guix-pcomplete.el \ %D%/guix-prettify.el \ - %D%/guix-popup.el \ + %D%/guix-transient.el \ %D%/guix-ui-messages.el \ %D%/guix-ui.el \ %D%/guix-ui-license.el \