From: Thien-Thi Nguyen <ttn@gnuvola.org>
To: Stefan Monnier <monnier@iro.umontreal.ca>
Cc: emacs-devel@gnu.org
Subject: Re: vc-*-root finctions
Date: Wed, 20 Feb 2008 19:21:45 +0100 [thread overview]
Message-ID: <87mypvxzd2.fsf@ambire.localdomain> (raw)
In-Reply-To: <jwvir0jlf6i.fsf-monnier+emacs@gnu.org> (Stefan Monnier's message of "Wed, 20 Feb 2008 12:21:55 -0500")
[-- Attachment #1: Type: text/plain, Size: 1861 bytes --]
() Stefan Monnier <monnier@iro.umontreal.ca>
() Wed, 20 Feb 2008 12:21:55 -0500
This part I inferred, but of course it is necessary (weren't
you the guy complaining harshly about lack of comments in VC's
in-development code ;-)?
I said i find under-commenting obnoxious. Now i add: everyone is
free to be obnoxious -- makes life interesting. If these IMHOs
sound like harsh complaining, i must introduce you someday to my
two-year-old...
> I am using vc-BACKEND-root for (work-in-progress, see below)
> `vc-status-mode' munging.
I don't understand what for (in terms of user-level feature)?
Please see the `vc-status-mode' docstring in the updated code below.
This time i include a full patch for anyone interested in trying
it out. In terms of user experience, this means that doing:
M-x vc-status RET ~/build/MISC/ferm/examples RET
shows a buffer where the first line reads:
Directory: ~/build/MISC/ferm/examples/
and "ferm" (the project's "root" directory) is a button, which
means (for me) underlined and clickable, whose action is to do
`(vc-status "~/build/MISC/ferm")'.
If this explanation makes sense to you and the docstring doesn't,
could you suggest another wording?
thi
________________________________________________________________
one edit
* vc.el (vc-overview-p): New defsubst.
(vc-start-entry, vc-finish-logentry): Use it.
another edit
* vc.el (vc-status-headers): Delete func.
(vc-status, vc-status-mode, vc-status-refresh): Rewrite.
(vc-update-vc-status-buffer): Delete func.
* vc-svn.el (vc-svn-after-dir-status): Incorporate into...
(vc-svn-dir-status): ...here; update calling sequence.
* vc-hg.el (vc-hg-after-dir-status): Incorporate into...
(vc-hg-dir-status): ...here; update calling sequence.
* vc-git.el (vc-git-after-dir-status): Delete func.
(vc-git-dir-status): Rewrite.
full munging
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: two edits --]
[-- Type: text/x-diff, Size: 22638 bytes --]
Index: vc-git.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/vc-git.el,v
retrieving revision 1.38
diff -c -r1.38 vc-git.el
*** vc-git.el 18 Feb 2008 07:46:14 -0000 1.38
--- vc-git.el 20 Feb 2008 18:15:50 -0000
***************
*** 207,258 ****
;; fall back to the default VC representation
(vc-default-dired-state-info 'Git file))))
! ;;; vc-dir-status support (EXPERIMENTAL)
! ;;; If vc-directory (which is not half bad under Git, w/ some tweaking)
! ;;; is to go away, vc-dir-status must at least support the same operations.
! ;;; At the moment, vc-dir-status design is still fluid (a kind way to say
! ;;; half-baked, undocumented, and spottily-supported), so the following
! ;;; should be considered likewise ripe for sudden unannounced change.
! ;;; YHBW, HAND. --ttn
!
! (defun vc-git-after-dir-status (callback buffer)
! (sort-regexp-fields t "^. \\(.+\\)$" "\\1" (point-min) (point-max))
! (let ((map '((?H . cached)
! (?M . unmerged)
! (?R . removed)
! (?C . edited)
! (?K . removed) ; ??? "to be killed"
! (?? . unregistered)))
! status filename result)
! (goto-char (point-min))
! (while (> (point-max) (point))
! (setq status (string-to-char (buffer-substring (point) (1+ (point))))
! status (cdr (assq status map))
! filename (buffer-substring (+ 2 (point)) (line-end-position)))
! ;; TODO: Add dynamic selection of which status(es) to display, and
! ;; bubble that up to vc-dir-status. For now, we consider `cached'
! ;; to be uninteresting, to mimic vc-directory (somewhat).
! (unless (eq 'cached status)
(push (cons filename status) result))
! (forward-line 1))
! (funcall callback result buffer)))
!
! (defun vc-git-dir-status (dir update-function status-buffer)
! "Return a list of conses (file . state) for DIR."
! (with-current-buffer
! (get-buffer-create
! (expand-file-name " *VC-Git* tmp status" dir))
! (erase-buffer)
! (vc-git-command (current-buffer) 'async dir "ls-files" "-t"
! "-c" ; cached
! "-d" ; deleted
! "-k" ; killed
! "-m" ; modified
! "-o" ; others
! "--directory"
! "--exclude-per-directory=.gitignore")
! (vc-exec-after
! `(vc-git-after-dir-status (quote ,update-function) ,status-buffer))))
;;; STATE-CHANGING FUNCTIONS
--- 207,258 ----
;; fall back to the default VC representation
(vc-default-dired-state-info 'Git file))))
! (defun vc-git-dir-status (&optional kickp)
! "Return a list of conses (FILE . STATE) for the default directory."
! (if kickp
! ;; Don't do it asynchronously; git is fast and always local.
! ;; Avoid "-a" so as to be able to distinguish "in index".
! (call-process "git" nil t nil "status")
! (let* ((root (vc-git-root default-directory))
! (sub (file-relative-name default-directory root))
! ;; If we are not in the project's root dir, discard
! ;; lines that do not have the relative-dir prefix.
! (keep-rx (concat "^#\t\\([^:]+\\): +"
! (if (member sub '("." "./"))
! ""
! (file-name-as-directory sub))))
! (pair-rx (concat keep-rx "\\(.+\\)$"))
! status filename result)
! (goto-char (point-min))
! ;; Encode "in index" in the state; eg: `modified' vs `modified/in'.
! (when (search-forward "\n# Changes to be committed:\n" nil t)
! (search-forward "#\t")
! (forward-char -2)
! (while (looking-at "#\t[^:]+\\(:\\)")
! (replace-match "/in:" t t nil 1)
! (forward-line 1)))
! (when (search-forward "\n# Untracked files:\n" nil t)
! (while (re-search-forward "^#\t" nil t)
! (insert "untracked: ")))
! (keep-lines keep-rx (point-min) (point-max))
! ;; This sorting is purely cosmetic. We will probably remove it a
! ;; little further down the road, when VC Status learns to manage
! ;; total ordering and all that jazz. --ttn
! (sort-regexp-fields t pair-rx "\\2" (point-min) (point-max))
! (goto-char (point-min))
! (while (re-search-forward pair-rx nil t)
! (setq status (match-string 1)
! status (if (string-match "new file" status)
! (replace-match "new" t t status)
! status)
! status (intern status)
! filename (match-string 2))
! (when (memq status '(renamed renamed/in copied copied/in))
! ;; Discard first name: "ONE -> TWO" becomes "TWO".
! (setq filename (substring filename
! (+ 4 (string-match " -> " filename)))))
(push (cons filename status) result))
! result)))
;;; STATE-CHANGING FUNCTIONS
Index: vc-hg.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/vc-hg.el,v
retrieving revision 1.50
diff -c -r1.50 vc-hg.el
*** vc-hg.el 20 Feb 2008 15:21:55 -0000 1.50
--- vc-hg.el 20 Feb 2008 18:15:50 -0000
***************
*** 483,524 ****
(define-derived-mode vc-hg-incoming-mode vc-hg-log-view-mode "Hg-Incoming")
! ;; XXX Experimental function for the vc-dired replacement.
! (defun vc-hg-after-dir-status (update-function buff)
! (let ((status-char nil)
! (file nil)
! (translation '((?= . up-to-date)
! (?C . up-to-date)
! (?A . added)
! (?R . removed)
! (?M . edited)
! (?I . ignored)
! (?! . deleted)
! (?? . unregistered)))
! (translated nil)
! (result nil))
(goto-char (point-min))
(while (not (eobp))
! (setq status-char (char-after))
! (setq file
! (buffer-substring-no-properties (+ (point) 2)
! (line-end-position)))
! (setq translated (assoc status-char translation))
! (when (and translated (not (eq (cdr translated) 'up-to-date)))
! (push (cons file (cdr translated)) result))
! (forward-line))
! (funcall update-function result buff)))
!
! ;; XXX Experimental function for the vc-dired replacement.
! (defun vc-hg-dir-status (dir update-function status-buffer)
! "Return a list of conses (file . state) for DIR."
! (with-current-buffer
! (get-buffer-create
! (expand-file-name " *VC-hg* tmp status" dir))
! (erase-buffer)
! (vc-hg-command (current-buffer) 'async dir "status")
! (vc-exec-after
! `(vc-hg-after-dir-status (quote ,update-function) ,status-buffer))))
;; XXX this adds another top level menu, instead figure out how to
;; replace the Log-View menu.
--- 483,516 ----
(define-derived-mode vc-hg-incoming-mode vc-hg-log-view-mode "Hg-Incoming")
! (defun vc-hg-dir-status (&optional kickp)
! "Return a list of conses (FILE . STATE) for the default directory."
! (if kickp
! ;; TODO: Conditionally synchronous.
! (vc-hg-command (current-buffer) 'async default-directory "status")
! (let ((status-char nil)
! (file nil)
! (translation '((?= . up-to-date)
! (?C . up-to-date)
! (?A . added)
! (?R . removed)
! (?M . edited)
! (?I . ignored)
! (?! . deleted)
! (?? . unregistered)))
! (translated nil)
! (result nil))
(goto-char (point-min))
(while (not (eobp))
! (setq status-char (char-after))
! (setq file
! (buffer-substring-no-properties (+ (point) 2)
! (line-end-position)))
! (setq translated (assoc status-char translation))
! (when (and translated (not (eq (cdr translated) 'up-to-date)))
! (push (cons file (cdr translated)) result))
! (forward-line))
! result)))
;; XXX this adds another top level menu, instead figure out how to
;; replace the Log-View menu.
Index: vc-svn.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/vc-svn.el,v
retrieving revision 1.69
diff -c -r1.69 vc-svn.el
*** vc-svn.el 20 Feb 2008 10:40:46 -0000 1.69
--- vc-svn.el 20 Feb 2008 18:15:50 -0000
***************
*** 158,191 ****
(vc-svn-command t 0 nil "status" (if localp "-v" "-u"))
(vc-svn-parse-status))))
! (defun vc-svn-after-dir-status (callback buffer)
! (let ((state-map '((?A . added)
! (?C . edited)
! (?D . removed)
! (?I . ignored)
! (?M . edited)
! (?R . removed)
! (?? . unregistered)
! ;; This is what vc-svn-parse-status does.
! (?~ . edited)))
! result)
! (goto-char (point-min))
! (while (re-search-forward "^\\(.\\)..... \\(.*\\)$" nil t)
! (let ((state (cdr (assq (aref (match-string 1) 0) state-map)))
! (filename (match-string 2)))
! (when state
! (setq result (cons (cons filename state) result)))))
! (funcall callback result buffer)))
!
! (defun vc-svn-dir-status (dir callback buffer)
! "Run 'svn status' for DIR and update BUFFER via CALLBACK.
! CALLBACK is called as (CALLBACK RESULT BUFFER), where
! RESULT is a list of conses (FILE . STATE) for directory DIR."
! (with-current-buffer (get-buffer-create
! (generate-new-buffer-name " *vc svn status*"))
! (vc-svn-command (current-buffer) 'async nil "status")
! (vc-exec-after
! `(vc-svn-after-dir-status (quote ,callback) ,buffer))))
(defun vc-svn-working-revision (file)
"SVN-specific version of `vc-working-revision'."
--- 158,185 ----
(vc-svn-command t 0 nil "status" (if localp "-v" "-u"))
(vc-svn-parse-status))))
! (defun vc-svn-dir-status (&optional kickp)
! "Return a list of conses (FILE . STATE) for the default directory."
! (if kickp
! ;; TODO: Conditionally synchronous.
! (vc-svn-command (current-buffer) 'async nil "status")
! (let ((state-map '((?A . added)
! (?C . edited)
! (?D . removed)
! (?I . ignored)
! (?M . edited)
! (?R . removed)
! (?? . unregistered)
! ;; This is what vc-svn-parse-status does.
! (?~ . edited)))
! result)
! (goto-char (point-min))
! (while (re-search-forward "^\\(.\\)..... \\(.*\\)$" nil t)
! (let ((state (cdr (assq (aref (match-string 1) 0) state-map)))
! (filename (match-string 2)))
! (when state
! (setq result (cons (cons filename state) result)))))
! result)))
(defun vc-svn-working-revision (file)
"SVN-specific version of `vc-working-revision'."
Index: vc.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/vc.el,v
retrieving revision 1.537
diff -c -r1.537 vc.el
*** vc.el 20 Feb 2008 18:11:15 -0000 1.537
--- vc.el 20 Feb 2008 18:15:50 -0000
***************
*** 167,184 ****
;; in older versions this method was not required to recurse into
;; subdirectories.)
;;
! ;; - dir-status (dir update-function status-buffer)
;;
- ;; Produce RESULT: a list of conses of the form (file . vc-state)
- ;; for the files in DIR. If a command needs to be run to compute
- ;; this list, it should be run asynchronously. When RESULT is
- ;; computed, it should be passed back by doing:
- ;; (funcall UPDATE-FUNCTION RESULT STATUS-BUFFER)
;; This function is used by vc-status, a replacement for vc-dired.
;; vc-status is still under development, and is NOT feature
;; complete. As such, the requirements for this function might
! ;; change.
! ;; This is a replacement for dir-state.
;;
;; * working-revision (file)
;;
--- 167,186 ----
;; in older versions this method was not required to recurse into
;; subdirectories.)
;;
! ;; - dir-status (&optional kickp)
;;
;; This function is used by vc-status, a replacement for vc-dired.
;; vc-status is still under development, and is NOT feature
;; complete. As such, the requirements for this function might
! ;; change. This is a replacement for dir-state.
! ;;
! ;; Produce RESULT: a list of conses of the form (file . vc-state)
! ;; for the files in DIR. This function is called twice, the first
! ;; time with KICKP t, the second time, with KICKP nil. In both calls,
! ;; the current buffer is a scratch buffer with `default-directory'
! ;; set appropriately. If the backend workings are asynchronous, it
! ;; must use the current buffer as its process buffer. The return
! ;; value of the second call is RESULT.
;;
;; * working-revision (file)
;;
***************
*** 918,923 ****
--- 920,929 ----
(defvar vc-dired-mode nil)
(make-variable-buffer-local 'vc-dired-mode)
+ (defsubst vc-overview-p ()
+ "Return non-nil if current buffer is in VC Dired or VC Status mode."
+ (memq major-mode '(vc-dired-mode vc-status-mode)))
+
;; File property caching
(defun vc-clear-context ()
***************
*** 1794,1802 ****
\(current one if no file). AFTER-HOOK specifies the local value
for `vc-log-after-operation-hook'."
(let ((parent
! (if (eq major-mode 'vc-dired-mode)
! ;; If we are called from VC dired, the parent buffer is
! ;; the current buffer.
(current-buffer)
(if (and files (equal (length files) 1))
(get-file-buffer (car files))
--- 1800,1806 ----
\(current one if no file). AFTER-HOOK specifies the local value
for `vc-log-after-operation-hook'."
(let ((parent
! (if (vc-overview-p)
(current-buffer)
(if (and files (equal (length files) 1))
(get-file-buffer (car files))
***************
*** 1934,1940 ****
;; Sync parent buffer in case the user modified it while editing the comment.
;; But not if it is a vc-dired buffer.
(with-current-buffer vc-parent-buffer
! (or vc-dired-mode (vc-buffer-sync)))
(if (not vc-log-operation)
(error "No log operation is pending"))
;; save the parameters held in buffer-local variables
--- 1938,1944 ----
;; Sync parent buffer in case the user modified it while editing the comment.
;; But not if it is a vc-dired buffer.
(with-current-buffer vc-parent-buffer
! (unless (vc-overview-p) (vc-buffer-sync)))
(if (not vc-log-operation)
(error "No log operation is pending"))
;; save the parameters held in buffer-local variables
***************
*** 2642,2653 ****
(defvar vc-status nil)
- (defun vc-status-headers (backend dir)
- (concat
- (format "VC backend : %s\n" backend)
- "Repository : The repository goes here\n"
- (format "Working dir: %s\n" dir)))
-
(defun vc-status-printer (fileentry)
"Pretty print FILEENTRY."
;; If you change the layout here, change vc-status-move-to-goal-column.
--- 2646,2651 ----
***************
*** 2673,2684 ****
;;;###autoload
(defun vc-status (dir)
! "Show the VC status for DIR."
(interactive "DVC status for directory: ")
! (vc-setup-buffer "*vc-status*")
! (switch-to-buffer "*vc-status*")
! (cd dir)
! (vc-status-mode))
(defvar vc-status-mode-map
(let ((map (make-keymap)))
--- 2671,2697 ----
;;;###autoload
(defun vc-status (dir)
! "Show the VC status for DIR in its own buffer.
! Reuse an existing buffer if possible, otherwise create a new one
! and place it in `vc-status-mode'. Lastly, run `vc-status-refresh'."
(interactive "DVC status for directory: ")
! (setq dir (file-name-as-directory dir))
! (let ((ls (buffer-list))
! buf)
! (while (and ls (not buf))
! (with-current-buffer (car ls)
! (when (and vc-status (string= dir default-directory))
! (setq buf (car ls)))
! (setq ls (cdr ls))))
! (unless buf
! (set-buffer (setq buf (get-buffer-create
! (generate-new-buffer-name
! (file-name-nondirectory
! (directory-file-name dir))))))
! (setq default-directory dir)
! (vc-status-mode))
! (switch-to-buffer buf))
! (vc-status-refresh))
(defvar vc-status-mode-map
(let ((map (make-keymap)))
***************
*** 2777,2818 ****
(defun vc-status-mode ()
"Major mode for VC status.
\\{vc-status-mode-map}"
! (setq mode-name "*VC Status*")
! (setq major-mode 'vc-status-mode)
! (setq buffer-read-only t)
! (use-local-map vc-status-mode-map)
! (let ((buffer-read-only nil)
! (backend (vc-responsible-backend default-directory))
! entries)
! (erase-buffer)
(set (make-local-variable 'vc-status)
! (ewoc-create #'vc-status-printer
! (vc-status-headers backend default-directory)))
! (vc-status-refresh)))
(put 'vc-status-mode 'mode-class 'special)
- (defun vc-update-vc-status-buffer (entries buffer)
- (with-current-buffer buffer
- (dolist (entry entries)
- (ewoc-enter-last vc-status
- (vc-status-create-fileinfo (cdr entry) (car entry))))
- (ewoc-goto-node vc-status (ewoc-nth vc-status 0))))
-
(defun vc-status-refresh ()
! "Refresh the contents of the VC status buffer."
(interactive)
! ;; This is not very efficient; ewoc could use a new function here.
! (ewoc-filter vc-status (lambda (node) nil))
! (let ((backend (vc-responsible-backend default-directory)))
! ;; Call the dir-status backend function. dir-status is supposed to
! ;; be asynchronous. It should compute the results and call the
! ;; function passed as a an arg to update the vc-status buffer with
! ;; the results.
! (vc-call-backend
! backend 'dir-status default-directory
! #'vc-update-vc-status-buffer (current-buffer))))
(defun vc-status-next-line (arg)
"Go to the next line.
--- 2790,2887 ----
(defun vc-status-mode ()
"Major mode for VC status.
+ Prepare the buffer to begin with the lines:
+
+ Directory: DEFAULT-DIRECTORY
+ Updated: YYYY-MM-DD HH:MM:SS
+
+ If the `default-directory' is under the project's \"root\"
+ directory, make its root component a button whose action is
+ to run command `vc-status' there.
+
+ Keys do not self-insert; instead they do different things:
\\{vc-status-mode-map}"
! (buffer-disable-undo)
! (erase-buffer)
! (let* ((backend (vc-responsible-backend default-directory))
! (find-root (vc-find-backend-function backend 'root))
! (root (if find-root
! (funcall find-root default-directory)
! default-directory)))
! (setq major-mode 'vc-status-mode)
! (setq mode-name (format "VC-%s Status" backend))
! (insert "Directory: ")
! (if (or (not root) (string= root default-directory))
! (insert root)
! (let* ((root-fn (directory-file-name root))
! (parent (file-name-directory root-fn))
! (leaf (file-name-nondirectory root-fn)))
! (insert parent)
! ;; As of 2007-08-21, loadup.el includes button, so this
! ;; check is just future-proofing; not strictly necessary.
! (if (featurep 'button)
! (insert-text-button
! leaf
! 'root root
! 'action (lambda (button)
! (vc-status (button-get button 'root)))
! 'follow-link t)
! (insert leaf))
! (insert (substring default-directory (1- (length root))))))
! (insert "\n")
(set (make-local-variable 'vc-status)
! (ewoc-create #'vc-status-printer
! (format-time-string " Updated: %F %T\n")))
! (use-local-map vc-status-mode-map)
! (setq buffer-read-only t)))
(put 'vc-status-mode 'mode-class 'special)
(defun vc-status-refresh ()
! "Refresh the contents of the VC Status buffer."
(interactive)
! (unless vc-status
! (error "Not in a VC Status buffer"))
! (ewoc-filter vc-status 'ignore)
! (let* ((backend (vc-responsible-backend default-directory))
! (get-status (cond ((vc-find-backend-function backend 'dir-status))
! (t (kill-buffer nil)
! (error "No vc-status support for %s"
! backend))))
! (here (current-buffer))
! (scratch (get-buffer-create (format " vc status: %s"
! default-directory)))
! notice)
! ;; Call the backend function in two-phase style. First, kick...
! (with-current-buffer scratch
! (erase-buffer)
! (funcall get-status t))
! ;; Clue in the user if things are working asynchronously.
! (when (setq notice (buffer-local-value 'mode-line-process scratch))
! (setq mode-line-process notice)
! (ewoc-set-hf vc-status
! (format " Updated: %s -- %s working...\n"
! (format-time-string "%F %T")
! backend)
! ""))
! (with-current-buffer scratch
! (vc-exec-after
! ;; ... then collect.
! `(let ((entries (,get-status)))
! (when (buffer-live-p ,here)
! (with-current-buffer ,here
! (dolist (entry entries)
! (ewoc-enter-last vc-status (vc-status-create-fileinfo
! (cdr entry) (car entry))))
! (let ((first (ewoc-nth vc-status 0)))
! (when first
! (ewoc-goto-node vc-status first)
! (vc-status-move-to-goal-column))
! (ewoc-set-hf vc-status
! (format-time-string " Updated: %F %T\n")
! (if first "" "(no entries)"))
! (setq mode-line-process nil))))
! (kill-buffer nil))))))
(defun vc-status-next-line (arg)
"Go to the next line.
next prev parent reply other threads:[~2008-02-20 18:21 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-02-19 22:06 vc-*-root finctions Stefan Monnier
2008-02-20 11:12 ` Thien-Thi Nguyen
2008-02-20 17:21 ` Stefan Monnier
2008-02-20 18:21 ` Thien-Thi Nguyen [this message]
2008-02-20 18:50 ` Dan Nicolaescu
2008-02-21 15:33 ` Thien-Thi Nguyen
2008-02-21 18:35 ` Dan Nicolaescu
2008-02-21 19:03 ` Tom Tromey
2008-02-21 20:06 ` Dan Nicolaescu
2008-02-21 19:33 ` Stefan Monnier
2008-02-21 19:01 ` Tom Tromey
2008-02-21 20:01 ` Dan Nicolaescu
2008-02-21 19:50 ` Dan Nicolaescu
2008-02-22 14:41 ` Thien-Thi Nguyen
2008-02-22 15:42 ` Dan Nicolaescu
2008-02-22 17:34 ` Thien-Thi Nguyen
2008-02-22 19:02 ` Dan Nicolaescu
2008-02-22 2:42 ` Mike Mattie
2008-02-20 19:20 ` Stefan Monnier
2008-02-21 15:36 ` Thien-Thi Nguyen
2008-02-21 16:16 ` Stefan Monnier
2008-02-22 14:54 ` Thien-Thi Nguyen
2008-02-22 16:50 ` Stefan Monnier
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=87mypvxzd2.fsf@ambire.localdomain \
--to=ttn@gnuvola.org \
--cc=emacs-devel@gnu.org \
--cc=monnier@iro.umontreal.ca \
/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).