From: Jambunathan K <kjambunathan@gmail.com>
To: Stefan Monnier <monnier@iro.umontreal.ca>
Cc: 12638@debbugs.gnu.org
Subject: bug#12638: 24.2.50; FR: Some suggestions for icomplete-mode
Date: Fri, 02 Nov 2012 17:19:14 +0530 [thread overview]
Message-ID: <87sj8s8bt1.fsf@gmail.com> (raw)
In-Reply-To: <jwvk3ug3uoe.fsf-monnier+emacs@gnu.org> (Stefan Monnier's message of "Wed, 24 Oct 2012 09:09:11 -0400")
[-- Attachment #1: Type: text/plain, Size: 1852 bytes --]
I am attaching a second revision of the earlier patch.
It is not that patch is final. It is worthy of further discussion and
experimentation.
Changes are in minibuffer.el and icomplete.el.
1. `minibuffer-summarize-completions' is meant as a replacement for
`icomplete-exhibit'. As the name suggests, it is meant to go in to
minibuffer.el. It's presence in minibuffer.el proved problematic
(details in followup mail) and I had to move it to icomplete.el.
TODO: Handle key binding hints for sole command matches? Is it
really necessary. It seems so `old school'. May be it made sense
when Emacs /did not/ provide key binding hints.
2. There is a display overlay that is used in minibuffer (see
`minibuffer-message'). There is a counterpart in icomplete.el named
`icomplete-overlay'.
I am wondering whether `icomplete-overlay' could be thrown away and
have it use, yet to be introduced `minibuffer-overlay'. Should this
be buffer-local etc etc. I am not sure of.
I can exchange notes if there is some interest around this area.
3. Apropos `minibuffer-force-complete-and-exit' and `confirm' etc.
>> +(defun icomplete-this-match ()
>> + "Input first of the displayed matches to minibuffer prompt.
>> +See `icomplete-matches'."
>> + (interactive)
>> + (delete-region (minibuffer-prompt-end) (point))
>> + (when icomplete-matches
>> + (insert (car icomplete-matches)))
>> + (exit-minibuffer))
>
> I think it should still call test-completion and obey
> minibuffer-completion-confirm if that test fails.
Can `test-completion' fail if the prompt is filled from valid
candidates? Remember, `minibuffer-force-and-complete-and-exit' doesn't
rely on manual-typing at the prompt.
--8<---------------cut here---------------start------------->8---
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: bug12638-rev2-20121102.diff --]
[-- Type: text/x-diff, Size: 19936 bytes --]
=== modified file 'lisp/icomplete.el'
--- lisp/icomplete.el 2012-06-22 17:37:28 +0000
+++ lisp/icomplete.el 2012-11-02 11:12:09 +0000
@@ -71,6 +71,9 @@
(make-obsolete-variable
'icomplete-prospects-length 'icomplete-prospects-height "23.1")
+(defvar icomplete-separator " | "
+ "String used by icomplete to separate alternatives in the minibuffer.")
+
;;;_* User Customization variables
(defcustom icomplete-prospects-height
;; 20 is an estimated common size for the prompt + minibuffer content, to
@@ -102,7 +105,14 @@
:type 'boolean
:group 'icomplete)
-(defcustom icomplete-minibuffer-setup-hook nil
+(defcustom icomplete-minibuffer-setup-hook
+ '((lambda ()
+ (define-key icomplete-minibuffer-map
+ "\C-j" 'minibuffer-force-complete-and-exit)
+ (define-key icomplete-minibuffer-map
+ "\C-s" 'minibuffer-forward-sorted-completions)
+ (define-key icomplete-minibuffer-map
+ "\C-r" 'minibuffer-backward-sorted-completions)))
"Icomplete-specific customization of minibuffer setup.
This hook is run during minibuffer setup if icomplete is active.
@@ -118,6 +128,21 @@
will constrain Emacs to a maximum minibuffer height of 3 lines when
icompletion is occurring."
:type 'hook
+ :version "24.3"
+ :group 'icomplete)
+
+(defcustom icomplete-hide-common-prefix t
+ "When non-nil, hide common prefix (if any) from completion candidates.
+Default setting (typically) allows more candidates to be shown
+for given `icomplete-prospects-height'. When nil, show
+candidates in full."
+ :type 'boolean
+ :version "24.3"
+ :group 'icomplete)
+
+(defface icomplete-first-match '((t :weight bold))
+ "Face used by icomplete for highlighting first match."
+ :version "24.3"
:group 'icomplete)
@@ -169,6 +194,11 @@
Icomplete does not operate with any specialized completion tables
except those on this list.")
+(defvar icomplete-minibuffer-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [?\M-\t] 'minibuffer-force-complete)
+ map))
+
;;;_ > icomplete-mode (&optional prefix)
;;;###autoload
(define-minor-mode icomplete-mode
@@ -207,7 +237,9 @@
"Run in minibuffer on activation to establish incremental completion.
Usually run by inclusion in `minibuffer-setup-hook'."
(when (and icomplete-mode (icomplete-simple-completing-p))
- (set (make-local-variable 'completion-show-inline-help) nil)
+ ;; (set (make-local-variable 'completion-show-inline-help) nil)
+ (use-local-map (make-composed-keymap icomplete-minibuffer-map
+ (current-local-map)))
(add-hook 'pre-command-hook
(lambda () (let ((non-essential t))
(run-hooks 'icomplete-pre-command-hook)))
@@ -227,155 +259,192 @@
"Remove completions display \(if any) prior to new user input.
Should be run in on the minibuffer `pre-command-hook'. See `icomplete-mode'
and `minibuffer-setup-hook'."
- (delete-overlay icomplete-overlay))
+ (unless (memq this-command '(minibuffer-force-complete-and-exit minibuffer-forward-sorted-completions
+ minibuffer-backward-sorted-completions))
+ ;; Current command does not belong to icomplete-mode.
+ ;; Delete the overlay.
+ (delete-overlay icomplete-overlay)))
+
+(defun minibuffer-summarize-completions (&optional separator max-width
+ first-match-face
+ strip-common-substring)
+ "Summarize minibuffer completion and return it as a string.
+
+Return one of \"[No match]\", \"[Sole completion]\" or a string
+of the form:
+
+ \"\(TAB-COMPL\){CAND-1 SEPARATOR CAND-2 ... CAND-N SEPARATOR CONTD}\"
+
+CAND-1, CAND-2 etc are completion candidates.
+
+TAB-COMPL, when present, indicates the string to which next
+`minibuffer-complete' will complete to.
+
+CONTD (string \"...\"), when present, indicates that not all
+completions are shown. To disclose completions that are hidden,
+use `minibuffer-forward-sorted-completions' and
+`minibuffer-backward-sorted-completions'.
+
+SEPARATOR is a string to separate completions. If nil, use \" | \".
+
+MAX-WIDTH is width in characters, as a multiple of window width,
+to which summary string is capped. If MAX-WIDTH is not a
+multiple of `\(window-width\)', it is increased suitably. If it
+is nil (or in any case), it is forcibly increased to just
+accommodate minibuffer contents.
+
+FIRST-MATCH-FACE is a face to be applied to first of the matches,
+which can be input with `minibuffer-force-complete-and-exit'. If
+nil, use 'bold face.
+
+STRIP-COMMON-SUBSTRING, a boolean, controls whether how
+completion candidates are displayed. If nil, show completions in
+full. Otherwise, strip common prefix of all
+completions (obtained with `try-completion') from completions."
+
+ ;; Set defaults for optional params.
+ (setq separator (or separator " | "))
+ ;; Ensure max-width is big enough to hold current minibuffer
+ ;; content. Stretch max-width to a multiple of window width.
+ (let* ((content-width (string-width (buffer-string))))
+ (setq max-width (max content-width (or max-width 0)))
+ (setq max-width
+ (let* ((normalized-height (/ max-width (window-width)))
+ (normalized-width (* normalized-height (window-width))))
+ (if (< normalized-height max-width)
+ (+ normalized-width (window-width))
+ normalized-width))))
+ (setq first-match-face (or first-match-face 'bold))
+ (let* ((beg (field-beginning))
+ (end (field-end))
+ (string (buffer-substring beg end))
+ (md (completion--field-metadata beg))
+ (try-comp (completion-try-completion
+ string
+ minibuffer-completion-table
+ minibuffer-completion-predicate
+ (- (point) beg)
+ md)))
+ (cond
+ ;; No match.
+ ((null try-comp)
+ "[No match]")
+ ;; Sole completion. Exact and unique match.
+ ((eq t try-comp)
+ "[Sole completion]")
+ (t
+ ;; `completed' should be t if some completion was done, which doesn't
+ ;; include simply changing the case of the entered string. However,
+ ;; for appearance, the string is rewritten if the case changes.
+ (let* ((comp-pos (cdr try-comp))
+ (completion (car try-comp))
+ (compare (compare-strings completion nil nil
+ string nil nil
+ completion-ignore-case))
+ (completed (not (eq t compare)))
+ (exact (test-completion completion
+ minibuffer-completion-table
+ minibuffer-completion-predicate))
+ (comps (completion-all-sorted-completions))
+ ;; Compute common substring, if user wants it stripped from
+ ;; completion candidates.
+ (common-substring (when strip-common-substring
+ (let ((common (try-completion "" comps)))
+ (when (stringp common) common))))
+ (common-substring-len (when common-substring
+ (length common-substring)))
+ width)
+ ;; Trim completion, when possible.
+ (if (not completed)
+ (setq completion nil)
+ (setq compare (1- (abs compare)))
+ (setq completion (if (= compare (length string))
+ (substring completion compare)
+ (concat "..." completion))))
+
+ ;; Account for various filler characters.
+ (setq width (string-width (concat (buffer-string)
+ "(...)" "{" separator "..." "}")))
+ ;; Add completion.
+ (when completion
+ (setq width (+ width (string-width completion)))
+ (unless (< width max-width)
+ (setq completion nil)))
+
+ ;; Add completion candidates.
+ (let* ((last (last comps))
+ (base-size (cdr last))
+ first limit prospects)
+ ;; Remove the base-size tail to get a properly
+ ;; nil-terminated list that is amenable for easy iteration.
+ (when last (setcdr last nil))
+
+ ;; Decorate the first of completion with requested face.
+ (setq first (copy-sequence (pop comps)))
+ (put-text-property 0 (length first) 'face first-match-face first)
+ (setq first (if (not common-substring-len) first
+ (substring first common-substring-len)))
+ (setq width (+ width (string-width first)))
+ (when (< width max-width)
+ (setq prospects first))
+
+ ;; Rest of the completions.
+ (while (and comps (not limit))
+ (let* ((comp (pop comps)))
+ (setq comp (concat separator
+ (if (not common-substring-len) comp
+ (substring comp common-substring-len))))
+ (setq width (+ width (string-width comp)))
+ (if (< width max-width)
+ (setq prospects (concat prospects comp))
+ (setq prospects (concat prospects separator "..."))
+ (setq limit t))))
+
+ ;; Restore the base-size info, since
+ ;; `completion-all-sorted-completions' is cached.
+ (when last (setcdr last base-size))
+
+ ;; Return summary output.
+ (concat (and completion (concat "(" completion ")"))
+ (and prospects (concat "{" prospects "}")))))))))
;;;_ > icomplete-exhibit ()
(defun icomplete-exhibit ()
"Insert icomplete completions display.
Should be run via minibuffer `post-command-hook'. See `icomplete-mode'
and `minibuffer-setup-hook'."
- (when (and icomplete-mode (icomplete-simple-completing-p))
- (save-excursion
- (goto-char (point-max))
+ (if (and icomplete-mode (icomplete-simple-completing-p))
+ (save-excursion
+ (goto-char (point-max))
; Insert the match-status information:
- (if (and (> (point-max) (minibuffer-prompt-end))
- buffer-undo-list ; Wait for some user input.
- (or
- ;; Don't bother with delay after certain number of chars:
- (> (- (point) (field-beginning)) icomplete-max-delay-chars)
- ;; Don't delay if alternatives number is small enough:
- (and (sequencep minibuffer-completion-table)
- (< (length minibuffer-completion-table)
- icomplete-delay-completions-threshold))
- ;; Delay - give some grace time for next keystroke, before
- ;; embarking on computing completions:
- (sit-for icomplete-compute-delay)))
- (let ((text (while-no-input
- (icomplete-completions
- (field-string)
- minibuffer-completion-table
- minibuffer-completion-predicate
- (not minibuffer-completion-confirm))))
- (buffer-undo-list t)
- deactivate-mark)
- ;; Do nothing if while-no-input was aborted.
- (when (stringp text)
- (move-overlay icomplete-overlay (point) (point) (current-buffer))
- ;; The current C cursor code doesn't know to use the overlay's
- ;; marker's stickiness to figure out whether to place the cursor
- ;; before or after the string, so let's spoon-feed it the pos.
- (put-text-property 0 1 'cursor t text)
- (overlay-put icomplete-overlay 'after-string text)))))))
-
-;;;_ > icomplete-completions (name candidates predicate require-match)
-(defun icomplete-completions (name candidates predicate require-match)
- "Identify prospective candidates for minibuffer completion.
-
-The display is updated with each minibuffer keystroke during
-minibuffer completion.
-
-Prospective completion suffixes (if any) are displayed, bracketed by
-one of \(), \[], or \{} pairs. The choice of brackets is as follows:
-
- \(...) - a single prospect is identified and matching is enforced,
- \[...] - a single prospect is identified but matching is optional, or
- \{...} - multiple prospects, separated by commas, are indicated, and
- further input is required to distinguish a single one.
-
-The displays for unambiguous matches have ` [Matched]' appended
-\(whether complete or not), or ` \[No matches]', if no eligible
-matches exist. \(Keybindings for uniquely matched commands
-are exhibited within the square braces.)"
-
- (let* ((md (completion--field-metadata (field-beginning)))
- (comps (completion-all-sorted-completions))
- (last (if (consp comps) (last comps)))
- (base-size (cdr last))
- (open-bracket (if require-match "(" "["))
- (close-bracket (if require-match ")" "]")))
- ;; `concat'/`mapconcat' is the slow part.
- (if (not (consp comps))
- (format " %sNo matches%s" open-bracket close-bracket)
- (if last (setcdr last nil))
- (let* ((most-try
- (if (and base-size (> base-size 0))
- (completion-try-completion
- name candidates predicate (length name) md)
- ;; If the `comps' are 0-based, the result should be
- ;; the same with `comps'.
- (completion-try-completion
- name comps nil (length name) md)))
- (most (if (consp most-try) (car most-try)
- (if most-try (car comps) "")))
- ;; Compare name and most, so we can determine if name is
- ;; a prefix of most, or something else.
- (compare (compare-strings name nil nil
- most nil nil completion-ignore-case))
- (determ (unless (or (eq t compare) (eq t most-try)
- (= (setq compare (1- (abs compare)))
- (length most)))
- (concat open-bracket
- (cond
- ((= compare (length name))
- ;; Typical case: name is a prefix.
- (substring most compare))
- ((< compare 5) most)
- (t (concat "..." (substring most compare))))
- close-bracket)))
- ;;"-prospects" - more than one candidate
- (prospects-len (+ (length determ) 6 ;; take {,...} into account
- (string-width (buffer-string))))
- (prospects-max
- ;; Max total length to use, including the minibuffer content.
- (* (+ icomplete-prospects-height
- ;; If the minibuffer content already uses up more than
- ;; one line, increase the allowable space accordingly.
- (/ prospects-len (window-width)))
- (window-width)))
- (prefix-len
- ;; Find the common prefix among `comps'.
- ;; We can't use the optimization below because its assumptions
- ;; aren't always true, e.g. when completion-cycling (bug#10850):
- ;; (if (eq t (compare-strings (car comps) nil (length most)
- ;; most nil nil completion-ignore-case))
- ;; ;; Common case.
- ;; (length most)
- ;; Else, use try-completion.
- (let ((comps-prefix (try-completion "" comps)))
- (and (stringp comps-prefix)
- (length comps-prefix)))) ;;)
-
- prospects most-is-exact comp limit)
- (if (eq most-try t) ;; (or (null (cdr comps))
- (setq prospects nil)
- (while (and comps (not limit))
- (setq comp
- (if prefix-len (substring (car comps) prefix-len) (car comps))
- comps (cdr comps))
- (cond ((string-equal comp "") (setq most-is-exact t))
- ((member comp prospects))
- (t (setq prospects-len
- (+ (string-width comp) 1 prospects-len))
- (if (< prospects-len prospects-max)
- (push comp prospects)
- (setq limit t))))))
- ;; Restore the base-size info, since completion-all-sorted-completions
- ;; is cached.
- (if last (setcdr last base-size))
- (if prospects
- (concat determ
- "{"
- (and most-is-exact ",")
- (mapconcat 'identity (nreverse prospects) ",")
- (and limit ",...")
- "}")
- (concat determ
- " [Matched"
- (let ((keys (and icomplete-show-key-bindings
- (commandp (intern-soft most))
- (icomplete-get-keys most))))
- (if keys (concat "; " keys) ""))
- "]"))))))
+ (if (and (> (point-max) (minibuffer-prompt-end))
+ buffer-undo-list ; Wait for some user input.
+ (or
+ ;; Don't bother with delay after certain number of chars:
+ (> (- (point) (field-beginning)) icomplete-max-delay-chars)
+ ;; Don't delay if alternatives number is small enough:
+ (and (sequencep minibuffer-completion-table)
+ (< (length minibuffer-completion-table)
+ icomplete-delay-completions-threshold))
+ ;; Delay - give some grace time for next keystroke, before
+ ;; embarking on computing completions:
+ (sit-for icomplete-compute-delay)))
+ (let ((text (while-no-input
+ (minibuffer-summarize-completions
+ icomplete-separator
+ (* icomplete-prospects-height (window-width))
+ 'icomplete-first-match
+ icomplete-hide-common-prefix)))
+ (buffer-undo-list t)
+ deactivate-mark)
+ ;; Do nothing if while-no-input was aborted.
+ (when (stringp text)
+ (move-overlay icomplete-overlay (point) (point) (current-buffer))
+ ;; The current C cursor code doesn't know to use the overlay's
+ ;; marker's stickiness to figure out whether to place the cursor
+ ;; before or after the string, so let's spoon-feed it the pos.
+ (put-text-property 0 1 'cursor t text)
+ (overlay-put icomplete-overlay 'after-string text)))))))
;;_* Local emacs vars.
;;Local variables:
=== modified file 'lisp/minibuffer.el'
--- lisp/minibuffer.el 2012-10-28 19:07:52 +0000
+++ lisp/minibuffer.el 2012-11-02 07:57:15 +0000
@@ -1108,12 +1108,68 @@
(let ((hist (symbol-value minibuffer-history-variable)))
(setq all (sort all (lambda (c1 c2)
(> (length (member c1 hist))
- (length (member c2 hist))))))))
+ (length (member c2 hist)))))))
+ ;; Bring exact (but not unique) match to the front.
+ (when (member string all)
+ (push string all))
+
+ ;; Delete duplicates.
+ (delete-dups all))
;; Cache the result. This is not just for speed, but also so that
;; repeated calls to minibuffer-force-complete can cycle through
;; all possibilities.
(completion--cache-all-sorted-completions (nconc all base-size))))))
+(defun minibuffer-force-complete-and-exit ()
+ "Complete the minibuffer with first of the matches and exit."
+ (interactive)
+ ;; FIXME: Need to deal with the extra-size issue here as well.
+ ;; FIXME: ~/src/emacs/t<M-TAB>/lisp/minibuffer.el completes to
+ ;; ~/src/emacs/trunk/ and throws away lisp/minibuffer.el.
+ (let* ((start (copy-marker (field-beginning)))
+ (end (field-end))
+ ;; (md (completion--field-metadata start))
+ (all (completion-all-sorted-completions))
+ (base (+ start (or (cdr (last all)) 0))))
+ (cond
+ ((not (consp all))
+ (completion--message
+ (if all "No more completions" "No completions")))
+ ((not (consp (cdr all)))
+ (let ((done (equal (car all) (buffer-substring-no-properties base end))))
+ (unless done (completion--replace base end (car all)))
+ (completion--done (buffer-substring-no-properties start (point))
+ 'finished (when done "Sole completion"))
+ (exit-minibuffer)))
+ (t
+ (completion--replace base end (car all))
+ (completion--done (buffer-substring-no-properties start (point))
+ 'sole)
+ (exit-minibuffer)))))
+
+(defun minibuffer-forward-sorted-completions ()
+ "Step forward completions by one entry.
+Second entry becomes the first and can be selected with
+`minibuffer-force-complete-and-exit'."
+ (interactive)
+ (let* ((comps (completion-all-sorted-completions))
+ (last (last comps)))
+ (setcdr last (cons (car comps) (cdr last)))
+ (completion--cache-all-sorted-completions (cdr comps))))
+
+(defun minibuffer-backward-sorted-completions ()
+ "Step backward completions by one entry.
+Last entry becomes the first and can be selected with
+`minibuffer-force-complete-and-exit'."
+ (interactive)
+ (let* ((comps (completion-all-sorted-completions))
+ (last-but-one (last comps 2))
+ (last (cdr last-but-one)))
+ (when last
+ (setcdr last-but-one (cdr last))
+ (push (car last) comps)
+ (completion--cache-all-sorted-completions comps))))
+
(defun minibuffer-force-complete ()
"Complete the minibuffer to an exact match.
Repeated uses step through the possible completions."
[-- Attachment #3: Type: text/plain, Size: 67 bytes --]
--8<---------------cut here---------------end--------------->8---
next prev parent reply other threads:[~2012-11-02 11:49 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-10-13 17:33 bug#12638: 24.2.50; FR: Some suggestions for icomplete-mode Jambunathan K
2012-10-13 22:14 ` Stefan Monnier
2012-10-14 4:18 ` Drew Adams
2012-10-23 19:43 ` Stefan Monnier
2012-10-23 20:08 ` Jambunathan K
2012-10-23 20:17 ` Jambunathan K
2012-10-24 13:09 ` Stefan Monnier
2012-11-02 11:49 ` Jambunathan K [this message]
2012-11-02 12:12 ` Jambunathan K
2012-11-09 1:53 ` Stefan Monnier
2012-11-09 2:17 ` Stefan Monnier
2012-11-09 4:25 ` Jambunathan K
2012-11-09 14:12 ` Stefan Monnier
2012-11-29 21:34 ` Stefan Monnier
2012-11-30 6:18 ` Jambunathan K
2012-11-30 19:37 ` Stefan Monnier
2012-12-04 12:54 ` Jambunathan K
2012-12-04 15:02 ` Stefan Monnier
2012-12-04 15:30 ` Jambunathan K
2012-12-04 15:45 ` Stefan Monnier
2012-12-04 16:12 ` Jambunathan K
2012-12-04 17:14 ` Stefan Monnier
2012-12-04 17:32 ` Jambunathan K
2012-12-12 3:18 ` Stefan Monnier
2012-12-12 3:42 ` Drew Adams
2012-12-12 6:34 ` Kevin Rodgers
2012-12-12 16:15 ` Drew Adams
2012-12-04 15:51 ` Jambunathan K
2012-12-13 13:51 ` Jambunathan K
2012-12-17 16:28 ` Stefan Monnier
2012-12-17 19:22 ` Jambunathan K
2012-12-17 20:12 ` Stefan Monnier
2012-12-17 20:58 ` Jambunathan K
2012-12-18 1:26 ` Stefan Monnier
2012-12-18 3:09 ` Drew Adams
2012-12-18 14:40 ` Jambunathan K
2013-01-11 5:47 ` Jambunathan K
2013-01-11 14:17 ` Stefan Monnier
2013-02-13 13:56 ` Jambunathan K
2013-02-13 15:15 ` Stefan Monnier
2013-02-13 17:18 ` Jambunathan K
2013-11-15 4:42 ` Jambunathan K
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
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87sj8s8bt1.fsf@gmail.com \
--to=kjambunathan@gmail.com \
--cc=12638@debbugs.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 external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.