unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Philip Kaludercic <philipk@posteo.net>
To: Yuan Fu <casouri@gmail.com>
Cc: Emacs developers <emacs-devel@gnu.org>
Subject: Re: Propose to add setup-wizard.el to ELPA
Date: Sun, 02 Jan 2022 12:02:11 +0000	[thread overview]
Message-ID: <87zgoeqrb0.fsf@posteo.net> (raw)
In-Reply-To: <897ED591-43BC-4029-912A-917E5E9F6930@gmail.com> (Yuan Fu's message of "Sat, 1 Jan 2022 18:07:53 -0800")


I am not sure if I brought this up last time, but how difficult do you
think it would be to generalise this into a "wizard.el" package, that
could be used by any package to define an interactive configuration
wizard?

Yuan Fu <casouri@gmail.com> writes:

> A while ago I wrote a package that helps a new user to configure
> Emacs: it takes a user through some interactive pages, where changes
> takes effect immediately; and in the end it generates some code that
> can be copied to init.el.
>
> Demo for the original package: https://youtu.be/0qMskTAR2aw
>
> I made some improvements to that package and renamed it
> setup-wizard. Do you think we could add it to ELPA? Maybe the name is
> too “official”, in that case I can rename it to yuan’s-setup-wizard or
> something.
>
> I don’t know how useful could it be, since nowadays every body
> (understandably) starts with some community distribution rather than
> vanilla Emacs, but surely it is better than not having a wizard.
>
> You can try it out with emacs -q -l setup-wizard.el -f setup-wizard
>
> Yuan
>
> ;;; setup-wizard.el --- Setup wizard  -*- lexical-binding: t; -*-
>
> ;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
>
> ;; Author: Yuan Fu <casouri@gmail.com>
> ;; Maintainer: Yuan Fu <casouri@gmail.com>
> ;; URL: https://github.com/casouri/setup-wizard
> ;; Version: 1.0.0
> ;; Keywords: convenience
> ;; Package-Requires: ((emacs "26.0"))
>
> ;; This file is part of GNU Emacs.
>
> ;; GNU Emacs 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 Emacs 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 Emacs.  If not, see <https://www.gnu.org/licenses/>.
>
> ;;; Commentary:
> ;;
> ;; This package provides a setup wizard that takes a user through an
> ;; interactive interface, in which he or she can configure key
> ;; bindings schemes, UI elements, Fonts, packages, etc.
>
> ;;; Code:
>
> (require 'widget)
> (require 'wid-edit)
> (require 'pcase)
> (require 'seq)
> (require 'cl-lib)
>
> ;;; Configs
>
> (defvar setup-wizard--config nil
>   "An alist (OPTION . (FORM COMMENT)) of configurations.
> We use FORM and COMMENT to produce the final config.")
>
> (defun setup-wizard--save-option-and-eval
>     (option form comment &optional additional)
>   "Save OPTION FORM and COMMENT, and evaluate FORM.
> If ADDITIONAL is non-nil, eval that too."
>   (when form
>     (setf (alist-get option setup-wizard--config)
>           (list form comment))
>     (eval form))
>   (when additional (eval additional)))
>
> ;;; Pages
>
> (defun setup-wizard--insert (&rest args)
>   "Insert ARGS and replace emojis if they can’t be displayed."
>   (widget-insert
>    (mapconcat (lambda (text)
>                 (if (and (char-displayable-p ?🧙)
>                          (char-displayable-p ?🧚))
>                     text
>                   (string-replace
>                    "🧚" "Fairy"
>                    (string-replace
>                     "🧙" "Wizard" text))))
>               args)))
>
> ;;;; Themes
>
> (defvar setup-wizard--c-demo
>   "    #include <stdlib.h>
>
>     struct point
>     {
>       x: int;
>       y: int;
>     };
>
>     int main(int arg, int* argv)
>     {
>       int x = -1;
>       int y = 2;
>       void *buf = malloc(sizeof(uin32_t));
>       return add(x, y) - 3;
>     }
> "
>   "Demo C code.")
>
> (defun setup-wizard--theme-page ()
>   "Theme configuration page."
>   (setup-wizard--insert
>    "🧚: Heya! You are here for help setting up your Emacs, right?
> Wizard will be here when you read to the next line.
>
> 🧙: Emacs comes with a couple of themes built-in, which are shown
> below. You can browse for more themes online or in the package
> manager.
>
> 🧚: Here are the built-in themes!
>
> Theme preview:\n\n")
>   ;; Insert a C demo.
>   (widget-insert
>    (with-temp-buffer
>      (insert setup-wizard--c-demo)
>      (c-mode)
>      (font-lock-fontify-region (point-min) (point-max))
>      (buffer-string)))
>   (widget-insert "\n")
>   ;; Insert theme selection menu.
>   (apply #'widget-create 'radio-button-choice
>          :follow-link t
>          :value "default"
>          ;; Enable the theme when the user selects it.
>          :notify (lambda (widget &rest _)
>                    (mapc #'disable-theme custom-enabled-themes)
>                    (let* ((theme (intern (widget-value widget)))
>                           (form (if (eq theme 'default)
>                                     nil
>                                   `(load-theme ',theme))))
>                      (setup-wizard--save-option-and-eval
>                       'theme form (format "Load %s theme" theme))))
>          (cons '(item "default")
>                (cl-loop for theme in (custom-available-themes)
>                         collect `(item ,(symbol-name theme)))))
>   (setup-wizard--insert "\n🧚: Want to ")
>   (widget-create
>    'push-button
>    :notify (lambda (&rest _)
>              (package-refresh-contents)
>              (list-packages t)
>              (goto-char (point-min))
>              (let ((inhibit-read-only t))
>                (keep-lines "-theme")))
>    :value "browse the package manager for themes")
>   (widget-insert "?\n"))
>
> ;;;; Keybinding
>
> (defun setup-wizard--keybinding-page ()
>   "Keybinding page."
>   (setup-wizard--insert "🧙: This is the notation for modifiers in Emacs:
>
>     C (control)   Ctrl
>     M (meta)      Alt/Option
>     s (super)     Windows/Command
>     S (shift)     Shift
>
> 🧚: Which binding scheme do you like?\n\n")
>   (widget-create 'radio-button-choice
>                  :follow-link t
>                  :value "default"
>                  :notify
>                  (lambda (widget &rest _)
>                    (setup-wizard--save-option-and-eval
>                     'keybinding
>                     (cond
>                      ((equal (widget-value widget)
>                              "Alternative")
>                       '(cua-mode))
>                      ((equal (widget-value widget)
>                              "Wizard’s choice")
>                       `(progn
>                          (global-set-key (kbd "s-c") #'kill-ring-save)
>                          (global-set-key (kbd "s-x") #'kill-region)
>                          (global-set-key (kbd "s-v") #'yank))))
>                     "Set bindings for copy/cut/paste."))
>                  '(item :value "Default"
>                         :format "%v\n\n%d\n"
>                         :doc "    M-w           Copy
>     C-w           Cut
>     C-y           Paste")
>                  '(item :value "Alternative"
>                         :format "%v\n\n%d\n"
>                         :doc "    C-c           Copy
>     C-x           Cut
>     C-v           Paste")
>                  '(item :value "Wizard’s choice"
>                         :format "%v\n\n%d\n"
>                         :doc "    s-c           Copy
>     s-x           Cut
>     s-v           Paste"))
>   (setup-wizard--insert
>    "\n🧙: In the alternative binding scheme, the binding for copy
> and cut only take effect when some text is selected. So when
> nothing is selected, they are still normal prefix keys.\n"))
>
> ;;;; UI features
>
> (defun setup-wizard--ui-features-page ()
>   "UI features page."
>   (setup-wizard--insert "🧚: What UI elements do you like?\n\n")
>   ;; Line numbers.
>   (widget-create 'checkbox
>                  :notify
>                  (lambda (widget &rest _)
>                    (let ((val (widget-value widget)))
>                      (setup-wizard--save-option-and-eval
>                       'line-number
>                       `(global-display-line-numbers-mode
>                         ,(if val 1 -1))
>                       (format "%s line number."
>                               (if val "Display" "Don’t display")))))
>                  :value nil)
>   (widget-insert " Line numbers.\n")
>   ;; Thin cursor.
>   (widget-create 'checkbox
>                  :notify
>                  (lambda (widget &rest _)
>                    (let ((val (widget-value widget)))
>                      (setup-wizard--save-option-and-eval
>                       'thin-cursor
>                       `(setq-default cursor-type
>                                      ',(if val 'bar t))
>                       (format "Use %s cursor"
>                               (if val "thin" "default")))))
>                  :value nil)
>   (widget-insert " Thin cursor bar.\n")
>   ;; Blink cursor.
>   (widget-create 'checkbox
>                  :notify
>                  (lambda (widget &rest _)
>                    (let ((val (widget-value widget)))
>                      (setup-wizard--save-option-and-eval
>                       'blink-cursor
>                       `(blink-cursor-mode ,(if val 1 -1))
>                       (format "%s cursor"
>                               (if val "Blink" "Do not blink")))))
>                  :value blink-cursor-mode)
>   (widget-insert " Blink cursor.\n")
>   ;; Tool bar.
>   (widget-create 'checkbox
>                  :notify
>                  (lambda (widget &rest _)
>                    (let ((val (widget-value widget)))
>                      (setup-wizard--save-option-and-eval
>                       'tool-bar
>                       `(tool-bar-mode ,(if val 1 -1))
>                       (format "%s tool bar."
>                               (if val "Enable" "Disable")))))
>                  :value tool-bar-mode)
>   (widget-insert " Tool bar.\n")
>   ;; Menu bar.
>   (widget-create 'checkbox
>                  :notify
>                  (lambda (widget &rest _)
>                    (let ((val (widget-value widget)))
>                      (setup-wizard--save-option-and-eval
>                       'menu-bar
>                       `(menu-bar-mode ,(if val 1 -1))
>                       (format "%s menu bar."
>                               (if val "Enable" "Disable")))))
>                  :value menu-bar-mode)
>   (widget-insert " Menu bar.\n")
>   ;; Scroll bar.
>   (widget-create 'checkbox
>                  :notify
>                  (lambda (widget &rest _)
>                    (let ((val (widget-value widget)))
>                      (setup-wizard--save-option-and-eval
>                       'scroll-bar
>                       `(scroll-bar-mode ,(if val 1 -1))
>                       (format "%s scroll bar"
>                               (if val "Enable" "Disable")))))
>                  :value scroll-bar-mode)
>   (widget-insert " Scroll bar.\n")
>   ;; Font.
>   (widget-insert "\n")
>   (let* (default-font-field
>          variable-font-field
>          cjk-font-field
>          size-field
>          action
>          (phrase "The quick brown fox jumps over the lazy dog.\n"))
>     (widget-insert "Font preview:\n\n")
>     (widget-insert "    " phrase)
>     (widget-insert "    " (propertize phrase 'face 'variable-pitch))
>     (widget-insert "    大漠孤烟直,长河落日圆。\n")
>     (widget-insert "    射は仁の道なり。射は正しきを己に求む。\n\n")
>     (setq default-font-field
>           (widget-create 'editable-field
>                          :size 20
>                          :value ""
>                          :format "Default font: %v \n"))
>     (setq variable-font-field
>           (widget-create 'editable-field
>                          :size 20
>                          :value ""
>                          :format "Variable-pitch font: %v \n"))
>     (setq cjk-font-field
>           (widget-create 'editable-field
>                          :size 20
>                          :value ""
>                          :format "CJK font: %v \n"))
>     (setq size-field
>           (widget-create 'editable-field
>                          :size 2
>                          :value ""
>                          :format "Font size: %v \n\n"))
>     (setq action
>           (lambda (&rest _)
>             (let* ((default-font
>                     (string-trim (widget-value default-font-field)))
>                    (variable-font
>                     (string-trim (widget-value variable-font-field)))
>                    (cjk-font
>                     (string-trim (widget-value cjk-font-field)))
>                    (size (string-to-number
>                           (string-trim
>                            (widget-value size-field)))))
>               (unless (equal default-font "")
>                 (setup-wizard--save-option-and-eval
>                  'font `(set-face-attribute
>                          'default nil :family ,default-font)
>                  "Set default font."))
>               (unless (equal variable-font "")
>                 (setup-wizard--save-option-and-eval
>                  'variable-font
>                  `(set-face-attribute
>                    'variable-pitch nil :family ,variable-font)
>                  "Set variable-pitch font."))
>               (unless (equal cjk-font "")
>                 (setup-wizard--save-option-and-eval
>                  'cjk-font
>                  `(dolist (charset '(kana han cjk-misc))
>                     (set-fontset-font
>                      t charset (font-spec :family ,cjk-font)))
>                  "Set CJK font."))
>               (unless (eq size 0)
>                 (setup-wizard--save-option-and-eval
>                  'font-size
>                  `(set-face-attribute 'default nil :height ,(* size 10))
>                  "Set font size.")))))
>     (widget-create 'push-button
>                    :value "Apply font settings"
>                    :notify action)
>     (widget-insert "\n")))
>
> (defun setup-wizard--undo-page ()
>   "Undo page."
>   (setup-wizard--insert
>    "🧙: Emacs has a powerful (but probably unintuitive) undo system,
> where undo operations themselves are recorded in the undo
> history, and redo is done by undoing an previous undo operation.
>
> 🧚: Which undo system do you like?\n\n")
>   (widget-create 'radio-button-choice
>                  :value "default"
>                  :follow-lint t
>                  :notify (lambda (widget &rest _)
>                            (when (equal (widget-value widget)
>                                         "Linear")
>                              (setup-wizard--save-option-and-eval
>                               'undo
>                               `(global-set-key [remap undo] #'undo-only)
>                               "Use linear undo style.")))
>                  '(item :value "Default"
>                         :format "%v\n\n%d\n"
>                         :doc "    One undo rules them all")
>                  '(item :value "Linear"
>                         :format "%v\n\n%d\n"
>                         :doc "    Undo and redo"))
>   (let (undo-key redo-key)
>     (widget-insert "\n")
>     (setq undo-key
>           (widget-create 'editable-field
>                          :size 5
>                          :value "C-/"
>                          :format "Bind undo to: %v "))
>     (widget-create 'push-button
>                    :value "Apply"
>                    :notify
>                    (lambda (&rest _)
>                      (let ((key (string-trim (widget-value undo-key))))
>                        (setup-wizard--save-option-and-eval
>                         'undo-key
>                         `(global-set-key (kbd ,key) #'undo)
>                         "Set binding for ‘undo’."))))
>     (widget-insert "\n")
>     (setq redo-key
>           (widget-create 'editable-field
>                          :size 5
>                          :value "C-?"
>                          :format "Bind redo to: %v "))
>     (widget-create 'push-button
>                    :value "Apply"
>                    :notify
>                    (lambda (&rest _)
>                      (let ((key (string-trim (widget-value redo-key))))
>                        (setup-wizard--save-option-and-eval
>                         'undo-key
>                         `(global-set-key (kbd ,key) #'undo-redo)
>                         "Set binding for ‘undo-redo’."))))
>     (setup-wizard--insert "\n\n🧙: I bind redo to C-.\n")))
>
> ;;;; Extra package
>
> (defun setup-wizard--package-activate (package mode)
>   "Return a form that activates PACKAGE and enable MODE."
>   `(progn
>      (require 'package)
>      (unless (package-installed-p ',package)
>        (package-install ',package))
>      (package-activate 'ivy)
>      (require ',package)
>      (,mode)))
>
> (defun setup-wizard--package-page ()
>   "Extra package page."
>   (setup-wizard--insert
>    "🧙: Here are some packages that I always install:\n\n")
>   ;; Ivy.
>   (widget-create 'checkbox
>                  :notify
>                  (lambda (widget &rest _)
>                    (let ((val (widget-value widget)))
>                      (setup-wizard--save-option-and-eval
>                       'ivy
>                       (when val
>                         `(progn
>                            ,(setup-wizard--package-activate
>                              'ivy 'ivy-mode)
>                            (setq enable-recursive-minibuffers t
>                                  ivy-use-selectable-prompt t
>                                  ivy-use-virtual-buffers t)
>                            ,(setup-wizard--package-activate
>                              'counsel 'counsel-mode)))
>                       "Install and enable ‘ivy-mode’ and ‘counsel-mode’."
>                       `(progn
>                          (ivy-mode ,(if val 1 -1))
>                          (counsel-mode ,(if val 1 -1))))))
>                  :value nil)
>   (widget-insert
>    " Ivy: A completion package that makes typing file names, buffer
> names, commands, etc so much easier.\n")
>   ;; Company
>   (widget-create 'checkbox
>                  :notify
>                  (lambda (widget &rest _)
>                    (let ((val (widget-value widget)))
>                      (setup-wizard--save-option-and-eval
>                       'company
>                       (setup-wizard--package-activate
>                        'company 'company-mode)
>                       "Install and enable ‘company-mode’."
>                       `(company-mode ,(if val 1 -1)))))
>                  :value nil)
>   (widget-insert
>    " Company: Popup completion menu when writing programs.\n")
>   (widget-create 'checkbox
>                  :notify
>                  (lambda (widget &rest _)
>                    (let ((val (widget-value widget)))
>                      (setup-wizard--save-option-and-eval
>                       'electric-pair-mode
>                       (when val
>                         `(electric-pair-mode))
>                       "Enable ‘electric-pair-mode’."
>                       `(electric-pair-mode ,(if val 1 -1)))))
>                  :value nil)
>   (widget-insert
>    " Electric-pair-mode (built-in): Automatically closes parenthesis\n")
>   (setup-wizard--insert "\n🧙: ...\n\n")
>   (setup-wizard--insert "🧙: I don’t use many packages.\n"))
>
> ;;; Guide
>
> (defun setup-wizard--with-boilerplate
>     (setup-fn &optional page-list finish-fn)
>   "Call page setup function SETUP-FN with widget boilerplate.
> PAGE-LIST is a list of setup function for pages to show in a
> series. FINISH-FN is called when user clicks the finish button.
> If PAGE-LIST or FINISH-FN are nil, don’t insert navigation
> buttons."
>   (kill-all-local-variables)
>   (let ((inhibit-read-only t))
>     (erase-buffer))
>   (remove-overlays)
>   (funcall setup-fn)
>   (widget-insert "\n")
>   (when (and page-list finish-fn)
>     (setup-wizard--insert-step-buttons setup-fn page-list finish-fn))
>   (use-local-map widget-keymap)
>   (widget-setup)
>   (goto-char (point-min))
>   (local-set-key (kbd "q") #'setup-wizard--quit))
>
> (defun setup-wizard--quit (&rest _)
>   "Quite the wizard."
>   (interactive)
>   (kill-buffer)
>   (message (with-temp-buffer
>              (setup-wizard--insert "🧚: See ya!")
>              (buffer-string))))
>
> (defun setup-wizard--insert-step-buttons (page page-list finish-fn)
>   "Insert buttons that go to previous and next page of PAGE.
> PAGE-LIST is a list of setup function for pages to show in a series.
> Insert a Button that calls FINISH-FN at the last page."
>   (let* ((idx (seq-position page-list page))
>          (previous-page (if (eq idx 0) nil
>                           (nth (1- idx) page-list)))
>          (next-page (nth (1+ idx) page-list)))
>     (setup-wizard--insert
>      (format "🧚: We are at step %s/%s, what’s next? "
>              (1+ idx) (length page-list)))
>     (when previous-page
>       (widget-create
>        'push-button
>        :notify (lambda (&rest _)
>                  (setup-wizard--with-boilerplate
>                   previous-page page-list finish-fn))
>        :value "Back"))
>     (widget-insert " ")
>     (if next-page
>         (widget-create
>          'push-button
>          :notify (lambda (&rest _)
>                    (setup-wizard--with-boilerplate
>                     next-page page-list finish-fn))
>          :value "Next")
>       (widget-create
>        'push-button
>        :notify (lambda (&rest _) (funcall finish-fn))
>        :value "Finish"))
>     (widget-insert " ")
>     (widget-create
>      'push-button
>      :value "Quit"
>      :notify #'setup-wizard--quit)
>     (widget-insert "\n")))
>
> (defun setup-wizard--insert-config ()
>   "Insert configuration in ‘setup-wizard--config’ line-by-line."
>   (dolist (config (reverse setup-wizard--config))
>     (insert ";; " (nth 2 config) "\n")
>     (dolist (conf (if (eq (car (nth 1 config)) 'progn)
>                       (cdr (nth 1 config))
>                     (list (nth 1 config))))
>       (insert (prin1-to-string conf) "\n"))))
>
> (defun setup-wizard--finish ()
>   "The default finish function.
> Constructs the config and display them."
>   (setup-wizard--with-boilerplate
>    (lambda ()
>      (setup-wizard--insert
>       "🧚: Here is your configuration! Do you want me to append it to
> init.el for you? ")
>      (widget-create 'push-button
>                     :notify
>                     (lambda (&rest _)
>                       (let ((init-file (locate-user-emacs-file
>                                         "init.el" ".emacs")))
>                         (find-file init-file)
>                         (goto-char (point-max))
>                         (insert "\n")
>                         (setup-wizard--insert-config)))
>                     :value "Append to init.el")
>      (widget-insert "\n\n")
>      (widget-insert
>       (with-temp-buffer
>         (setup-wizard--insert-config)
>         (emacs-lisp-mode)
>         (font-lock-fontify-region (point-min) (point-max))
>         (buffer-string))))))
>
> (defun setup-wizard ()
>   "Run the setup wizard."
>   (interactive)
>   (switch-to-buffer (get-buffer-create "*mage tower*"))
>   (setq setup-wizard--config nil)
>   (let ((page-list '(setup-wizard--theme-page
>                      setup-wizard--keybinding-page
>                      setup-wizard--ui-features-page
>                      setup-wizard--undo-page
>                      setup-wizard--package-page)))
>     (setup-wizard--with-boilerplate
>      (car page-list) page-list
>      #'setup-wizard--finish)))
>
> ;;; Backport
>
> (unless (fboundp 'undo--last-change-was-undo-p)
>   (defun undo--last-change-was-undo-p (undo-list)
>     (while (and (consp undo-list) (eq (car undo-list) nil))
>       (setq undo-list (cdr undo-list)))
>     (gethash undo-list undo-equiv-table)))
>
> (unless (fboundp 'undo-redo)
>   (defun undo-redo (&optional arg)
>     "Undo the last ARG undos."
>     (interactive "*p")
>     (cond
>      ((not (undo--last-change-was-undo-p buffer-undo-list))
>       (user-error "No undo to undo"))
>      (t
>       (let* ((ul buffer-undo-list)
>              (new-ul
>               (let ((undo-in-progress t))
>                 (while (and (consp ul) (eq (car ul) nil))
>                   (setq ul (cdr ul)))
>                 (primitive-undo arg ul)))
>              (new-pul (undo--last-change-was-undo-p new-ul)))
>         (message "Redo%s" (if undo-in-region " in region" ""))
>         (setq this-command 'undo)
>         (setq pending-undo-list new-pul)
>         (setq buffer-undo-list new-ul))))))
>
> (unless (fboundp 'undo-only)
>   (defun undo-only (&optional arg)
>     "Undo some previous changes.
> Repeat this command to undo more changes.
> A numeric ARG serves as a repeat count.
> Contrary to `undo', this will not redo a previous undo."
>     (interactive "*p")
>     (let ((undo-no-redo t)) (undo arg))))
>
> (provide 'setup-wizard)
>
> ;;; setup-wizard.el ends here
>

-- 
	Philip Kaludercic



  parent reply	other threads:[~2022-01-02 12:02 UTC|newest]

Thread overview: 119+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-02  2:07 Propose to add setup-wizard.el to ELPA Yuan Fu
2022-01-02  2:37 ` Po Lu
2022-01-02  3:02   ` Yuan Fu
2022-01-02  3:22     ` Po Lu
2022-01-02  5:51       ` Yuan Fu
2022-01-02  6:30         ` Po Lu
2022-01-02  7:58           ` Yuan Fu
2022-01-02  8:07             ` Po Lu
2022-01-02  9:07               ` Yuan Fu
2022-01-02  9:22                 ` xenodasein--- via Emacs development discussions.
2022-01-02  9:45                   ` Eduardo Ochs
2022-01-02  9:45                   ` Po Lu
2022-01-02 10:09                     ` Eduardo Ochs
2022-01-02 10:15                       ` Po Lu
2022-01-02 10:25                         ` Eduardo Ochs
2022-01-02 10:34                           ` xenodasein--- via Emacs development discussions.
2022-01-02 10:52                             ` Eli Zaretskii
2022-01-02 10:57                               ` xenodasein--- via Emacs development discussions.
2022-01-02 11:14                                 ` Eli Zaretskii
2022-01-02 11:30                                   ` xenodasein--- via Emacs development discussions.
2022-01-02 11:38                                     ` Eli Zaretskii
2022-01-02 12:01                                     ` Po Lu
2022-01-02 11:31                                   ` xenodasein--- via Emacs development discussions.
     [not found]                             ` <CADs++6jtFBah1hhsuN6T_-kFyjc_pNmmVKA+16vOWa8OctOZLw@mail.gmail.com>
2022-01-02 11:02                               ` xenodasein--- via Emacs development discussions.
2022-01-02 11:17                             ` Po Lu
2022-01-02 11:36                               ` xenodasein--- via Emacs development discussions.
2022-01-02 12:03                                 ` Po Lu
2022-01-02 15:27                                 ` Stefan Kangas
     [not found]                               ` <MsPZqa9--3-2@tutanota.de-MsP_1xO----2>
2022-01-02 11:57                                 ` xenodasein--- via Emacs development discussions.
2022-01-02 12:05                                   ` Po Lu
2022-01-02 15:27                                   ` Stefan Kangas
2022-01-02 15:37                                     ` Eli Zaretskii
2022-01-02 16:43                                       ` xenodasein--- via Emacs development discussions.
2022-01-02 17:32                                         ` Stefan Kangas
2022-01-02 18:51                                         ` FW: [External] : " Drew Adams
2022-01-02 19:07                                           ` xenodasein--- via Emacs development discussions.
2022-01-02 21:29                                             ` Drew Adams
2022-01-02 22:14                                               ` Stefan Kangas
2022-01-03  6:42                                                 ` Sean Whitton
2022-01-03  7:02                                                   ` Stefan Kangas
2022-01-03  8:19                                                     ` xenodasein--- via Emacs development discussions.
2022-01-03  9:27                                                       ` Po Lu
2022-01-03  9:55                                                         ` xenodasein--- via Emacs development discussions.
2022-01-03 10:10                                                           ` Po Lu
2022-01-03 10:21                                                             ` xenodasein--- via Emacs development discussions.
2022-01-03 10:53                                                               ` Po Lu
2022-01-03 11:07                                                                 ` xenodasein--- via Emacs development discussions.
2022-01-03 11:25                                                                   ` Po Lu
2022-01-03 11:32                                                                     ` xenodasein--- via Emacs development discussions.
2022-01-03 12:13                                                                       ` Po Lu
2022-01-03 12:20                                                                         ` xenodasein--- via Emacs development discussions.
2022-01-03 12:32                                                                           ` Po Lu
2022-01-03 12:44                                                                             ` xenodasein--- via Emacs development discussions.
2022-01-03 12:55                                                                               ` Po Lu
2022-01-03 13:24                                                                                 ` xenodasein--- via Emacs development discussions.
2022-01-03 15:15                                                                                 ` xenodasein--- via Emacs development discussions.
2022-01-03 16:04                                                       ` Drew Adams
2022-01-04 21:19                                                     ` Sean Whitton
2022-01-04 21:28                                                       ` Drew Adams
2022-01-04 22:38                                                         ` Sean Whitton
2022-01-04 22:51                                                           ` Drew Adams
2022-01-05  5:28                                                         ` tomas
2022-01-05  7:43                                                           ` Drew Adams
2022-01-05  8:13                                                             ` tomas
2022-01-07 10:34                                                     ` Jean Louis
2022-01-03 16:03                                                   ` Drew Adams
2022-01-03 16:05                                                   ` Stefan Monnier
2022-01-04  1:50                                                     ` Yuan Fu
2022-01-04  2:53                                                       ` Po Lu
2022-01-04  4:13                                                       ` Stefan Monnier
2022-01-04  4:30                                                         ` Yuan Fu
2022-01-04  6:10                                                           ` Stefan Monnier
2022-01-04 15:04                                                       ` Lars Ingebrigtsen
2022-01-04 21:25                                                         ` Sean Whitton
2022-01-05  0:58                                                           ` Po Lu
2022-01-05 15:35                                                           ` Lars Ingebrigtsen
2022-01-06  6:32                                                             ` Sean Whitton
2022-01-03  0:42                                         ` Po Lu
2022-01-02 18:47                                       ` [External] : " Drew Adams
2022-01-02 11:58                             ` Philip Kaludercic
2022-01-07 10:09                     ` Jean Louis
2022-01-02 18:47                   ` [External] : " Drew Adams
2022-01-02  9:41                 ` Po Lu
2022-01-02 17:18                   ` Yuan Fu
2022-01-02 18:47                     ` [External] : " Drew Adams
2022-01-07 10:02               ` Jean Louis
2022-01-07 10:50                 ` Po Lu
2022-01-07 12:11                 ` Eli Zaretskii
2022-01-09 22:54                   ` Yuan Fu
2022-01-10  4:15                   ` Jean Louis
2022-01-10 15:45                     ` [External] : " Drew Adams
2022-01-10 17:24                     ` Eli Zaretskii
2022-01-11  4:47                       ` Jean Louis
2022-01-11  4:51                     ` Richard Stallman
2022-01-02  7:55 ` Eli Zaretskii
2022-01-02  8:07   ` Yuan Fu
2022-01-02 15:42     ` Stefan Kangas
2022-01-02 17:26       ` Yuan Fu
2022-01-02 17:36         ` xenodasein--- via Emacs development discussions.
     [not found]         ` <MsQrOAf--J-2@tutanota.de-MsQrQR2----2>
2022-01-02 17:55           ` xenodasein--- via Emacs development discussions.
2022-01-02 18:50         ` Stefan Kangas
2022-01-02 21:14           ` Yuan Fu
2022-01-03  0:45             ` Po Lu
2022-01-03  0:59               ` Yuan Fu
2022-01-03  1:02             ` Stefan Kangas
2022-01-03  9:12             ` Joost Kremers
2022-01-03 12:49               ` Eli Zaretskii
2022-01-03 13:00                 ` Po Lu
2022-01-03 19:30                 ` Joost Kremers
2022-01-02  8:07   ` Po Lu
2022-01-02 15:23     ` nanjunjie
2022-01-03  8:28       ` Philip Kaludercic
2022-01-04 16:09         ` Nan JunJie
2022-01-04 19:45           ` Philip Kaludercic
2022-01-02 12:02 ` Philip Kaludercic [this message]
2022-01-07  9:58 ` Jean Louis
  -- strict thread matches above, loose matches on Subject: below --
2022-01-02 15:46 Simon Pugnet
2022-01-02 17:26 Simon Pugnet
2022-01-02 18:49 ` Stefan Kangas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87zgoeqrb0.fsf@posteo.net \
    --to=philipk@posteo.net \
    --cc=casouri@gmail.com \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).