From 69d051f715fc2f2f56543edba22bae50bdcb36dd Mon Sep 17 00:00:00 2001 From: Efraim Flashner Date: Mon, 5 Jun 2023 13:05:35 +0300 Subject: [PATCH] home: Add inputrc service. * gnu/home/services/shells.scm (home-inputrc-service-type, home-inputrc-configuration): New variables. (serialize-inputrc-key-bindings, serialize-inputrc-variables, serialize-inputrc-conditional-constructs, serialize-inputrc-extra-content): New procedures. * doc/guix.texi (Shells Home Services): Document it. --- doc/guix.texi | 129 +++++++++++++++++++++++++++++++++ gnu/home/services/shells.scm | 134 ++++++++++++++++++++++++++++++++++- 2 files changed, 262 insertions(+), 1 deletion(-) diff --git a/doc/guix.texi b/doc/guix.texi index 853396f776..4e7faf8aea 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -42991,6 +42991,135 @@ for example). @end deftp +@subsubheading Inputrc Profile Service +@cindex inputrc +@cindex readline + +The @uref{https://tiswww.cwru.edu/php/chet/readline/rltop.html, GNU +Readline package} includes Emacs and vi editing modes, with the ability +to customize the configuration with settings in the @file{~/.inputrc} +file. With the @code{gnu home services shells} module, you can setup +your readline configuration in a predictable manner, as shown below. +For more information about configuring an @file{~/.inputrc} file, +@pxref{Readline Init File,,, readline, GNU Readline}. + +@defvar home-inputrc-service-type + +This is the service to setup various @file{.inputrc} configurations. The +settings in @file{.inputrc} are read by all programs which are linked +with GNU Readline. + +Here is an example of a service and its configuration that you could add +to the @code{services} field of your @code{home-environment}: + +@lisp +(service home-inputrc-service-type + (home-inputrc-configuration + (key-bindings + `(("Control-l" . "clear-screen"))) + (variables + `(("bell-style" . "visible") + ("colored-completion-prefix" . #t) + ("editing-mode" . "vi") + ("show-mode-in-prompt" . #t))) + (conditional-constructs + `(("$if mode=vi" . + ,(home-inputrc-configuration + (variables + `(("colored-stats" . #t) + ("enable-bracketed-paste" . #t))))) + ("$else" . + ,(home-inputrc-configuration + (variables + `(("show-all-if-ambiguous" . #t))))) + ("endif" . #t) + ("$include" . "/etc/inputrc") + ("$include" . ,(file-append + (specification->package "readline") + "/etc/inputrc")))))) +@end lisp + +The example above starts with a combination of @code{key-bindings} and +@code{variables}. The @code{conditional-constructs} show how it is +possible to add conditionals and includes. In the example above +@code{colored-stats} is only enabled if the editing mode is @code{vi} +style, and it also reads any additional configuration located in +@file{/etc/inputrc} or in @file{/gnu/store/@dots{}-readline/etc/inputrc}. + +The value associated with a @code{home-inputrc-service-type} instance +must be a @code{home-inputrc-configuration} record, as described below. + +@end defvar + +@anchor{home-inputrc-configuration} +@deftp {Data Type} home-inputrc-configuration +Available @code{home-inputrc-configuration} fields are: + +@table @asis +@item @code{key-bindings} (default: @code{'()}) (type: alist) +Association list of readline key bindings to be added to the +@file{~/.inputrc} file. + +@lisp +'((\"Control-l\" . \"clear-screen\")) +@end lisp + +turns into + +@example +Control-l: clear-screen +@end example + +@item @code{variables} (default: @code{'()}) (type: alist) +Association list of readline variables to set. + +@lisp +'((\"bell-style\" . \"visible\") + (\"colored-completion-prefix\" . #t)) +@end lisp + +turns into + +@example +set bell-style visible +set colored-completion-prefix on +@end example + +@item @code{conditional-constructs} (default: @code{'()}) (type: alist) +Association list of conditionals to add to the initialization file. This +includes @command{$if}, @command{else}, @command{endif} and @command{include} +and they receive a value of another @command{home-inputrc-configuration}. + +@lisp +(conditional-constructs + `((\"$if mode=vi\" . + ,(home-inputrc-configuration + (variables + `((\"show-mode-in-prompt\" . #t))))) + (\"$else\" . + ,(home-inputrc-configuration + (key-bindings + `((\"Control-l\" . \"clear-screen\"))))) + (\"$endif\" . #t))) +@end lisp + +turns into + +@example +$if mode=vi +set show-mode-in-prompt on +$else +Control-l: clear-screen +$endif +@end example + +@item @code{extra-content} (default: @code{""}) (type: text-config) +Extra content appended as-is to the configuration file. Run @command{man +readline} for more information about all the configuration options. + +@end table +@end deftp + @node Mcron Home Service @subsection Scheduled User's Job Execution diff --git a/gnu/home/services/shells.scm b/gnu/home/services/shells.scm index f05f2221d6..415b5470c5 100644 --- a/gnu/home/services/shells.scm +++ b/gnu/home/services/shells.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2021 Andrew Tropin ;;; Copyright © 2021 Xinglu Chen +;;; Copyright © 2023 Efraim Flashner ;;; ;;; This file is part of GNU Guix. ;;; @@ -44,7 +45,10 @@ (define-module (gnu home services shells) home-fish-service-type home-fish-configuration - home-fish-extension)) + home-fish-extension + + home-inputrc-service-type + home-inputrc-configuration)) ;;; Commentary: ;;; @@ -626,6 +630,134 @@ (define home-fish-service-type (description "\ Install and configure Fish, the friendly interactive shell."))) + +;;; +;;; Readline. +;;; + +(define (serialize-inputrc-key-bindings field-name val) + #~(string-append + #$@(map + (match-lambda + ((key . value) + #~(string-append #$key ": " #$value "\n"))) + val))) + +(define (serialize-inputrc-variables field-name val) + #~(string-append + #$@(map + (match-lambda + ((key . #f) + #~(string-append "set " #$key " off\n")) + ((key . #t) + #~(string-append "set " #$key " on\n")) + ((key . value) + #~(string-append "set " #$key " " #$value "\n"))) + val))) + +(define (serialize-inputrc-conditional-constructs field-name val) + #~(string-append + #$@(map + (match-lambda + (("$endif" . _) + "$endif\n") + (("$include" . value) + #~(string-append "$include " #$value "\n")) + ;; TODO: key can only be "$if" or "$else". + ((key . value) + #~(string-append #$key "\n" + #$(serialize-configuration + value + home-inputrc-configuration-fields)))) + val))) + +(define (serialize-inputrc-extra-content field-name value) + #~(if (string=? #$value "") "" (string-append #$value "\n"))) + +(define-configuration home-inputrc-configuration + (key-bindings + (alist '()) + "Association list of readline key bindings to be added to the +@code{~/.inputrc} file. This is where code like this: + +@lisp +'((\"Control-l\" . \"clear-screen\")) +@end lisp + +turns into + +@example +Control-l: clear-screen +@end example" + (serializer serialize-inputrc-key-bindings)) + (variables + (alist '()) + "Association list of readline variables to set. This is where configuration +options like this: + +@lisp +'((\"bell-style\" . \"visible\") + (\"colored-completion-prefix\" . #t)) +@end lisp + +turns into + +@example +set bell-style visible +set colored-completion-prefix on +@end example" + (serializer serialize-inputrc-variables)) + (conditional-constructs + (alist '()) + "Association list of conditionals to add to the initialization file. This +includes @command{$if}, @command{else}, @command{endif} and @command{include} +and they receive a value of another @command{home-inputrc-configuration}. + +@lisp +(conditional-constructs + `((\"$if mode=vi\" . + ,(home-inputrc-configuration + (variables + `((\"show-mode-in-prompt\" . #t))))) + (\"$else\" . + ,(home-inputrc-configuration + (key-bindings + `((\"Control-l\" . \"clear-screen\"))))) + (\"$endif\" . #t))) +@end lisp + +turns into + +@example +$if mode=vi +set show-mode-in-prompt on +$else +Control-l: clear-screen +$endif +@end example" + (serializer serialize-inputrc-conditional-constructs)) + (extra-content + (string "") + "Extra content appended as-is to the configuration file. Run @command{man +readline} for more information about all the configuration options." + (serializer serialize-inputrc-extra-content))) + +(define (home-inputrc-files config) + (list + `(".inputrc" + ,(mixed-text-file "inputrc" + (serialize-configuration + config + home-inputrc-configuration-fields))))) + +(define home-inputrc-service-type + (service-type (name 'inputrc) + (extensions + (list (service-extension home-files-service-type + home-inputrc-files))) + (default-value (home-inputrc-configuration)) + (description "Configure readline in @code{.inputrc}."))) + (define (generate-home-shell-profile-documentation) (generate-documentation