Currently, there isn't any way to request quoting of completion matches
without getting also the attendant filename treatment.

In practice, authors of completion functions that need the matches to be
quoted often use `-o filenames', which works fine unless the matches
include slashes or happen to match existing directory names.

Alternatively, some authors opt to do their own quoting of matches but
doing so properly for partial word completion is tricky as it requires
accounting for the quoting style chosen by the user when they typed the
partial word.

The attached patch hopefully addresses these difficulties by allowing for
the decoupling of filename-specific match handling from match quoting.

It adds a new completion option `allquote' (I'm not quite happy with the
name) which controls the corresponding new readline variable
rl_all_quoting_desired.
From 8049e9f920fde4f84422fd651ba4a4beeafb7f10 Mon Sep 17 00:00:00 2001
From: Grisha Levit <grishale...@gmail.com>
Date: Fri, 14 Apr 2023 16:10:22 -0400
Subject: [PATCH] allow quoting completions w/o filename treatment

lib/readline/complete.c
    - rl_all_quoting_desired: new variable to tell readline to quote
      matches even if not doing filename completion
    - QUOTING_DESIRED: new macro for checking if quoting is enabled
    - change checks of filename comoletion && filename quoting to use
      QUOTING_DESIRED.
    - set_completion_defaults: set rl_all_quoting_desired to 0

lib/readline/readline.h
    - rl_all_quoting_desired: extern declaration

lib/readline/doc/rltech.texi
    - document rl_all_quoting_desired

pcomplete.h
    - COPT_ALLQUOTE: new value for compspec option, corresponds to
      rl_all_quoting_desired

pcomplete.c
    - pcomp_set_readline_variables: handle COPT_ALLQUOTE

builtins/complete.def
    - compopts: add allquote option for COPT_ALLQUOTE

lib/readline/doc/rluser.texi
    - document allquote compopt
---
 builtins/complete.def        |  1 +
 lib/readline/complete.c      | 26 +++++++++++++-------------
 lib/readline/doc/rltech.texi |  7 +++++++
 lib/readline/doc/rluser.texi |  3 +++
 lib/readline/readline.h      |  6 ++++++
 pcomplete.c                  |  2 ++
 pcomplete.h                  |  3 ++-
 7 files changed, 34 insertions(+), 14 deletions(-)

diff --git a/builtins/complete.def b/builtins/complete.def
index 881c4711..89ce0726 100644
--- a/builtins/complete.def
+++ b/builtins/complete.def
@@ -141,6 +141,7 @@ static const struct _compopt {
   const char * const optname;
   unsigned long optflag;
 } compopts[] = {
+  { "allquote", COPT_ALLQUOTE },
   { "bashdefault", COPT_BASHDEFAULT },
   { "default",	COPT_DEFAULT },
   { "dirnames", COPT_DIRNAMES },
diff --git a/lib/readline/complete.c b/lib/readline/complete.c
index bf7cc856..3cf050fc 100644
--- a/lib/readline/complete.c
+++ b/lib/readline/complete.c
@@ -336,6 +336,14 @@ int rl_filename_completion_desired = 0;
    entry finder function. */
 int rl_filename_quoting_desired = 1;
 
+/* Non-zero means that we should apply filename quoting to the matches
+   even if we are not otherwise treating the matches as filenames. This
+   is ALWAYS zero on entry, and can only be changed within a completion
+   entry finder function. */
+int rl_all_quoting_desired = 0;
+
+#define QUOTING_DESIRED (rl_all_quoting_desired || (rl_filename_completion_desired && rl_filename_quoting_desired))
+
 /* This function, if defined, is called by the completer when real
    filename completion is done, after all the matching names have been
    generated. It is passed a (char**) known as matches in the code below.
@@ -510,7 +518,7 @@ static void
 set_completion_defaults (int what_to_do)
 {
   /* Only the completion entry function can change these. */
-  rl_filename_completion_desired = 0;
+  rl_filename_completion_desired = rl_all_quoting_desired = 0;
   rl_filename_quoting_desired = 1;
   rl_completion_type = what_to_do;
   rl_completion_suppress_append = rl_completion_suppress_quote = 0;
@@ -1408,10 +1416,7 @@ compute_lcd_of_matches (char **match_list, int matches, const char *text)
 		   check against the list of matches
 		FI */
 	  dtext = (char *)NULL;
-	  if (rl_filename_completion_desired &&
-	      rl_filename_dequoting_function &&
-	      rl_completion_found_quote &&
-	      rl_filename_quoting_desired)
+	  if (QUOTING_DESIRED && rl_completion_found_quote && rl_filename_dequoting_function)
 	    {
 	      dtext = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character);
 	      text = dtext;
@@ -1766,10 +1771,7 @@ make_quoted_replacement (char *match, int mtype, char *qc)
      matches don't require a quoted substring. */
   replacement = match;
 
-  should_quote = match && rl_completer_quote_characters &&
-			rl_filename_completion_desired &&
-			rl_filename_quoting_desired;
-
+  should_quote = match && rl_completer_quote_characters && QUOTING_DESIRED;
   if (should_quote)
     should_quote = should_quote && (!qc || !*qc ||
 		     (rl_completer_quote_characters && strchr (rl_completer_quote_characters, *qc)));
@@ -1980,8 +1982,7 @@ compare_match (char *text, const char *match)
   char *temp;
   int r;
 
-  if (rl_filename_completion_desired && rl_filename_quoting_desired && 
-      rl_completion_found_quote && rl_filename_dequoting_function)
+  if (QUOTING_DESIRED && rl_completion_found_quote && rl_filename_dequoting_function)
     {
       temp = (*rl_filename_dequoting_function) (text, rl_completion_quote_character);
       r = strcmp (temp, match);
@@ -2043,8 +2044,7 @@ rl_complete_internal (int what_to_do)
      strcmp directly. */
   /* nontrivial_lcd is set if the common prefix adds something to the word
      being completed. */
-  if (rl_filename_completion_desired && rl_filename_quoting_desired &&
-      rl_completion_found_quote && rl_filename_dequoting_function)
+  if (QUOTING_DESIRED && rl_completion_found_quote && rl_filename_dequoting_function)
     {
       char *t;
       t = (*rl_filename_dequoting_function) (text, rl_completion_quote_character);
diff --git a/lib/readline/doc/rltech.texi b/lib/readline/doc/rltech.texi
index db38a311..df76f6f9 100644
--- a/lib/readline/doc/rltech.texi
+++ b/lib/readline/doc/rltech.texi
@@ -2300,6 +2300,13 @@ The quoting is effected via a call to the function pointed to
 by @code{rl_filename_quoting_function}.
 @end deftypevar
 
+@deftypevar int rl_all_quoting_desired
+Non-zero means that we should apply filename quoting to the matches
+even if we are not otherwise treating the matches as filenames. This
+is @emph{always} zero on entry, and can only be changed within a completion
+entry finder function.
+@end deftypevar
+
 @deftypevar int rl_attempted_completion_over
 If an application-specific completion function assigned to
 @code{rl_attempted_completion_function} sets this variable to a non-zero
diff --git a/lib/readline/doc/rluser.texi b/lib/readline/doc/rluser.texi
index bb1a24f5..a9a702d5 100644
--- a/lib/readline/doc/rluser.texi
+++ b/lib/readline/doc/rluser.texi
@@ -2177,6 +2177,9 @@ beyond the simple generation of completions.
 
 @table @code
 
+@item allquote
+Tell readline to quote the completed words even if they are not filenames.
+
 @item bashdefault
 Perform the rest of the default Bash completions if the compspec
 generates no matches.
diff --git a/lib/readline/readline.h b/lib/readline/readline.h
index 48f1210a..4a0c3d1d 100644
--- a/lib/readline/readline.h
+++ b/lib/readline/readline.h
@@ -790,6 +790,12 @@ extern int rl_filename_completion_desired;
    entry finder function. */
 extern int rl_filename_quoting_desired;
 
+/* Non-zero means that we should apply filename quoting to the matches
+   even if we are not otherwise treating the matches as filenames. This
+   is ALWAYS zero on entry, and can only be changed within a completion
+   entry finder function. */
+extern int rl_all_quoting_desired;
+
 /* Set to a function to quote a filename in an application-specific fashion.
    Called with the text to quote, the type of match found (single or multiple)
    and a pointer to the quoting character to be used, which the function can
diff --git a/pcomplete.c b/pcomplete.c
index 553623d5..1d99c317 100644
--- a/pcomplete.c
+++ b/pcomplete.c
@@ -1486,6 +1486,8 @@ pcomp_set_readline_variables (int flags, int nval)
     rl_filename_quoting_desired = 1 - nval;
   if (flags & COPT_NOSORT)
     rl_sort_completion_matches = 1 - nval;
+  if (flags & COPT_ALLQUOTE)
+    rl_all_quoting_desired = nval;
 }
 
 /* Set or unset FLAGS in the options word of the current compspec.
diff --git a/pcomplete.h b/pcomplete.h
index f0821b19..076c2eb7 100644
--- a/pcomplete.h
+++ b/pcomplete.h
@@ -76,8 +76,9 @@ typedef struct compspec {
 #define COPT_BASHDEFAULT (1<<6)
 #define COPT_PLUSDIRS	(1<<7)
 #define COPT_NOSORT	(1<<8)
+#define COPT_ALLQUOTE	(1<<9)
 
-#define COPT_LASTUSER	COPT_NOSORT
+#define COPT_LASTUSER	COPT_ALLQUOTE
 
 #define PCOMP_RETRYFAIL (COPT_LASTUSER << 1)
 #define PCOMP_NOTFOUND	(COPT_LASTUSER << 2)
-- 
2.40.0

Reply via email to