From: Yuan Fu <casouri@gmail.com>
To: Emacs developers <emacs-devel@gnu.org>
Subject: Propose to add setup-wizard.el to ELPA
Date: Sat, 1 Jan 2022 18:07:53 -0800 [thread overview]
Message-ID: <897ED591-43BC-4029-912A-917E5E9F6930@gmail.com> (raw)
[-- 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
next reply other threads:[~2022-01-02 2:07 UTC|newest]
Thread overview: 119+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-02 2:07 Yuan Fu [this message]
2022-01-02 2:37 ` Propose to add setup-wizard.el to ELPA 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
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=897ED591-43BC-4029-912A-917E5E9F6930@gmail.com \
--to=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).