unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Propose to add setup-wizard.el to ELPA
@ 2022-01-02  2:07 Yuan Fu
  2022-01-02  2:37 ` Po Lu
                   ` (3 more replies)
  0 siblings, 4 replies; 119+ messages in thread
From: Yuan Fu @ 2022-01-02  2:07 UTC (permalink / raw)
  To: Emacs developers

[-- Attachment #1: Type: text/plain, Size: 794 bytes --]

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


[-- Attachment #2: setup-wizard.el --]
[-- Type: application/octet-stream, Size: 23716 bytes --]

;;; 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

^ permalink raw reply	[flat|nested] 119+ messages in thread
* Re: Propose to add setup-wizard.el to ELPA
@ 2022-01-02 15:46 Simon Pugnet
  0 siblings, 0 replies; 119+ messages in thread
From: Simon Pugnet @ 2022-01-02 15:46 UTC (permalink / raw)
  To: Philip Kaludercic; +Cc: Yuan Fu, Emacs developers

Philip Kaludercic <philipk@posteo.net> writes:

> 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?

I really like this idea!

If the wizard could provide a common interface (e.g. a "wizard-builder")
that's easy to use and is presented using the same interface as the main
wizard then I think that could be a very nice way of helping newcomers
to certain packages.

For example, as well as giving configuration instructions in the
package's README, the package author could include their own wizard and
say something like "For interactive configuration, just evaluate
(invoke-wizard 'some-package) after loading the package."

One could argue that this is pretty close to just launching
customize-group for the package and limiting the options to only the
most important. However Yuan's wizard provides a more newcomer-friendly
and interactive interface (e.g. changing the theme immediately once it
is selected) so I think it is worthwhile keeping the wizard UI and
customize UI separate in this case.

P.S., I also have an interest in the idea of an Emacs set-up wizard, and
I've written about this before:
https://blog.polaris64.net/post/could-emacs-have-a-set-up-wizard/





^ permalink raw reply	[flat|nested] 119+ messages in thread
* Re: Propose to add setup-wizard.el to ELPA
@ 2022-01-02 17:26 Simon Pugnet
  2022-01-02 18:49 ` Stefan Kangas
  0 siblings, 1 reply; 119+ messages in thread
From: Simon Pugnet @ 2022-01-02 17:26 UTC (permalink / raw)
  To: Emacs developers

Philip Kaludercic <philipk@posteo.net> writes:

> 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?

I really like this idea!

If the wizard could provide a common interface (e.g. a "wizard-builder")
that's easy to use and is presented using the same interface as the main
wizard then I think that could be a very nice way of helping newcomers
to certain packages.

For example, as well as giving configuration instructions in the
package's README, the package author could include their own wizard and
say something like "For interactive configuration, just evaluate
(invoke-wizard 'some-package) after loading the package."

One could argue that this is pretty close to just launching
customize-group for the package and limiting the options to only the
most important. However Yuan's wizard provides a more newcomer-friendly
and interactive interface (e.g. changing the theme immediately once it
is selected) so I think it is worthwhile keeping the wizard UI and
customize UI separate in this case.

P.S., I also have an interest in the idea of an Emacs set-up wizard, and
I've written about this before:
https://blog.polaris64.net/post/could-emacs-have-a-set-up-wizard/




^ permalink raw reply	[flat|nested] 119+ messages in thread

end of thread, other threads:[~2022-01-11  4:51 UTC | newest]

Thread overview: 119+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
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

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).