Hello,
I'm looking for guidance and help developing a patch. Here is the
NEWS entry describing the feature I'm trying to implement:
k. There is a new option: `enable-paste-delay'. This controls the
interpretation of newlines in pasted text when bracketed-paste mode
is on. The default is off, newlines are interpreted in pasted text
in the same manner as when typed at the keyboard. In this case
pasting does not enable the active region. Users can turn this
option on to allow editing and review of pasted text, in which case
the newline key on the keyboard must be pressed to submit the
pasted text to the running application.
The "plumbing", i.e. the configuration settings, documentation, etc.,
all seem to work. But the feature does not. (And, there may be an
existing readline bug when using `bind' in bash to adjust settings. Or
not. See below.) I may not be understanding how to use the variables
and functions of readline. And I'm definitely making other mistakes,
but am presenting what I have so far for review. It seemed time to
stop bumbling around and ask for help. I could also use some guidance
on the mechanics and conventions of texinfo. Details follow.
Attached: paste-delay_v1.patch
Apply to "devel" branch.
The attached patch is only to "source" files. Generated files are not
included. No changes were made to the CHANGELOG or CHANGES file but I
did add a NEWS entry.
Regarding the code in the patch:
The code that's failing is in _rl_bracketed_text() of kill.c. This is
clearly the wrong place to make changes because it's called and then
the input is "unwound" in multiple places. So anything that's done to
feed lines of pasted text to the application might be erroneously
redone multiple times. I'm thinking that _rl_bracketed_paste_begin()
might be the right place to make changes. Notwithstanding the poor
choice of function to patch, _rl_bracketed_paste_begin() calls
_rl_bracketed_text() so I expect to see the same sort of behavior if I
move my changes into _rl_bracketed_paste_begin(). But I see 3 (?)
problems when testing the existing patch, with enable-bracketed-paste
on and enable-paste-delay off (the defaults).
1) The pasted text is not echoed to the terminal.
2) Calling rl_newline() does not seem to be delivering what I have
inserted into rl_line_buffer to the application.
3) An extra newline seems to be appended to the pasted text.
(Testing with examples/rlcat.)
Maybe I should understand what the return value of
_rl_bracketed_paste_begin() means, given that I think my code is
making it return 1 instead of 0. Without the patch I'm just not
seeing how the return value is ever anything other than 0.
Or perhaps I'm fundamentally mis-understanding something.
Is _rl_bracketed_paste_begin() the place to work? It seems feasible
to have _rl_bracketed_paste_begin() (conditionally, on
_rl_enable_paste_delay) look through the result of
_rl_bracketed_text() for newlines, stick them in rl_line_buffer, and
call rl_newline() (?) to deliver each line to the application.
If the code is to look through the result of _rl_bracketed_text() for
newlines, the multibyte encodings supported by readline are
significant. What Unicode encodings are supported for multibyte
support? UTF-8 is easy to look through for newlines, but other
encodings not-so-much. I didn't find anything in the docs.
(Maybe the docs need improving?)
I don't really get the internal bracketed paste API and code paths.
(Sorry.) There's a lot in the comments about being able to call the
bracketed paste related functions instead of the "stock" functions,
but is that something that is done? Are code changes needed in more
than one bracketed paste function? (Like my commented out code at the
bottom of _rl_bracketed_read_key(), which does not seem to do anything
when un-commented. Although I don't know that my testing is adequate.)
Random questions and observations about the (devel branch) code:
Given the existing calls to _rl_bracketed_paste_begin(), it seems to
me that the condition in the last "if" in the function will always be
true. The "lenp" argument is always passed an address. (?)
I suspect (without testing) that there is a bug in that if, in
inputrc, enable-active-region is set before enable-bracketed-paste or
enable-paste-delay that the enable-active-region setting will be
ignored. It seems odd to be order-dependent like that. Similar
considerations would apply when adjusting settings with `bind' in bash.
But, if there is such a problem, then I believe it already existed
before this patch, as regards setting enable-bracketed-paste and
enable-active-region with `bind' in bash. (Not my problem! ;-)
I'm unclear on the active region. There's code that seems to imply
that it is used only in the case of bracketed-paste, but then it also
seems to be used in other situations (search & ??). So I don't know
how to think about fixing whatever problem there may be with the
ordering of inputrc lines and use of `bind'.
I am unclear on the interactions involving macro callbacks and
bracketed paste mode. My use of RL_STATE_MOREINPUT in kill.c may be
incorrect. This is probably irrelevant if I move the patched code out
of _rl_bracketed_text() so maybe I don't care.
It seems kind of wonky to include generated files (doc files and even
./configure) in the git repo. No need to comment or justify this, but
I am curious if anyone wants to respond.
It is also awkward that "necessary" files (./configure, doc/texi2dvi,
doc/texi2html) are not executable. Again, no need to comment or
justify this, but I am curious if anyone wants to respond.
FYI, on my Debian stable (Debian 11, bullseye) (cd doc; make) fails
with:
/texi2html -menu -monolithic -I . ./rlman.texi
Can't use 'defined(@array)' (Maybe you should just omit the defined()?) at
./texi2html line 4858.
make: *** [Makefile:157: readline.html] Error 2
Questions about texinfo:
I don't like the output in the info pages where I use @var{} on
configuration setting names. What is the right way to do this?
I'd like to include cross references between the various inputrc
settings in the documentation changes, but don't like embedding them
in sentences. They break the flow of the sentence. Any suggestions?
I'm happy enough to leave well enough alone.
All comments and help appreciated.
Apologies, but I may not have a lot of time to work on this right now
and may not respond in a timely matter.
Regards,
Karl <[email protected]>
Free Software: "You don't pay back, you pay forward."
-- Robert A. Heinlein
diff --git a/INSTALL b/INSTALL
index 73960ee..0006b03 100644
--- a/INSTALL
+++ b/INSTALL
@@ -188,6 +188,11 @@ The readline `configure' recognizes a single `--with-PACKAGE' option:
Enable bracketed paste by default, so the initial value of the
`enable-bracketed-paste' Readline variable is `on'. The default
is `yes'.
+
+`--enable-paste-delay-default'
+ Enable paste delay by default, so the initial value of the
+ `enable-paste-delay' Readine variable is `on'. The default is
+ `no'.
Shared Libraries
================
diff --git a/Makefile.in b/Makefile.in
index 2120daa..4a7f060 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -75,7 +75,7 @@ ETAGS = etags
CTAGS = ctags -w
CFLAGS = @CFLAGS@
-LOCAL_CFLAGS = @LOCAL_CFLAGS@ -DRL_LIBRARY_VERSION='"$(RL_LIBRARY_VERSION)"' @BRACKETED_PASTE@
+LOCAL_CFLAGS = @LOCAL_CFLAGS@ -DRL_LIBRARY_VERSION='"$(RL_LIBRARY_VERSION)"' @BRACKETED_PASTE@ @PASTE_DELAY@
CPPFLAGS = @CPPFLAGS@
DEFS = @DEFS@ @CROSS_COMPILE@
diff --git a/NEWS b/NEWS
index 1b289ae..1b0b3e7 100644
--- a/NEWS
+++ b/NEWS
@@ -40,6 +40,15 @@ j. Readline looks in $LS_COLORS for a custom filename extension
(*.readline-colored-completion-prefix) and uses that as the default color
for the common prefix displayed when `colored-completion-prefix' is set.
+k. There is a new option: `enable-paste-delay'. This controls the
+ interpretation of newlines in pasted text when bracketed-paste mode
+ is on. The default is off, newlines are interpreted in pasted text
+ in the same manner as when typed at the keyboard. In this case
+ pasting does not enable the active region. Users can turn this
+ option on to allow editing and review of pasted text, in which case
+ the newline key on the keyboard must be pressed to submit the
+ pasted text to the running application.
+
-------------------------------------------------------------------------------
This is a terse description of the new features added to readline-8.1 since
the release of readline-8.0.
diff --git a/bind.c b/bind.c
index 971116a..1f1256d 100644
--- a/bind.c
+++ b/bind.c
@@ -1902,6 +1902,7 @@ static const struct {
{ "enable-bracketed-paste", &_rl_enable_bracketed_paste, V_SPECIAL },
{ "enable-keypad", &_rl_enable_keypad, 0 },
{ "enable-meta-key", &_rl_enable_meta, 0 },
+ { "enable-paste-delay", &_rl_enable_paste_delay, V_SPECIAL },
{ "expand-tilde", &rl_complete_with_tilde_expansion, 0 },
{ "history-preserve-point", &_rl_history_preserve_point, 0 },
{ "horizontal-scroll-mode", &_rl_horizontal_scroll_mode, 0 },
@@ -1966,7 +1967,11 @@ hack_special_boolean_var (int i)
else if (_rl_stricmp (name, "show-mode-in-prompt") == 0)
_rl_reset_prompt ();
else if (_rl_stricmp (name, "enable-bracketed-paste") == 0)
- _rl_enable_active_region = _rl_enable_bracketed_paste;
+ _rl_enable_active_region = _rl_enable_bracketed_paste
+ && _rl_enable_paste_delay;
+ else if (_rl_stricmp (name, "enable-paste-delay") == 0)
+ _rl_enable_active_region = _rl_enable_bracketed_paste
+ && _rl_enable_paste_delay;
}
typedef int _rl_sv_func_t (const char *);
diff --git a/configure.ac b/configure.ac
index 720cd10..65d5210 100644
--- a/configure.ac
+++ b/configure.ac
@@ -53,6 +53,7 @@ opt_static_libs=yes
opt_shared_libs=yes
opt_install_examples=yes
opt_bracketed_paste_default=yes
+opt_paste_delay_default=no
AC_ARG_ENABLE(multibyte, AS_HELP_STRING([--enable-multibyte], [enable multibyte characters if OS supports them]), opt_multibyte=$enableval)
AC_ARG_ENABLE(shared, AS_HELP_STRING([--enable-shared], [build shared libraries [[default=YES]]]), opt_shared_libs=$enableval)
@@ -60,6 +61,7 @@ AC_ARG_ENABLE(static, AS_HELP_STRING([--enable-static], [build static libraries
AC_ARG_ENABLE(install-examples, AS_HELP_STRING([--disable-install-examples], [don't install examples [[default=install]]]), opt_install_examples=$enableval)
AC_ARG_ENABLE(bracketed-paste-default, AS_HELP_STRING([--disable-bracketed-paste-default], [disable bracketed paste by default [[default=enable]]]), opt_bracketed_paste_default=$enableval)
+AC_ARG_ENABLE(paste-delay-default, AS_HELP_STRING([--enable-paste-delay-default], [enable paste delay by default [[default=disable]]]), opt_paste_delay_default=$enableval)
if test $opt_multibyte = no; then
AC_DEFINE(NO_MULTIBYTE_SUPPORT)
@@ -67,10 +69,17 @@ fi
if test $opt_bracketed_paste_default = yes; then
BRACKETED_PASTE='-DBRACKETED_PASTE_DEFAULT=1'
+ if test $opt_paste_delay_default = yes; then
+ PASTE_DELAY='-DPASTE_DELAY_DEFAULT=1'
+ else
+ PASTE_DELAY='-DPASTE_DELAY_DEFAULT=0'
+ fi
else
BRACKETED_PASTE='-DBRACKETED_PASTE_DEFAULT=0'
+ PASTE_DELAY='-DPASTE_DELAY_DEFAULT=0'
fi
AC_SUBST(BRACKETED_PASTE)
+AC_SUBST(PASTE_DELAY)
dnl load up the cross-building cache file -- add more cases and cache
dnl files as necessary
diff --git a/doc/rluser.texi b/doc/rluser.texi
index deaff14..409acd2 100644
--- a/doc/rluser.texi
+++ b/doc/rluser.texi
@@ -582,7 +582,8 @@ When the region is active, Readline highlights the text in the region using
the value of the @code{active-region-start-color}, which defaults to the
string that enables
the terminal's standout mode.
-The active region shows the text inserted by bracketed-paste and any
+The active region shows the text inserted by bracketed-paste
+when @var{enable-paste-delay} is @samp{On}, and any
matching text found by incremental and non-incremental history searches.
The default is @samp{On}.
@@ -597,6 +598,9 @@ bound to key sequences appearing in the pasted text.
This will prevent pasted characters from being interpreted as editing commands.
The default is @samp{On}.
+The @var{enable-paste-delay} setting further customizes
+bracketed-paste mode, controlling the behavior of pasted newlines.
+
@item enable-keypad
@vindex enable-keypad
When set to @samp{on}, Readline will try to enable the application
@@ -609,6 +613,31 @@ key the terminal claims to support when it is called. On many terminals,
the meta key is used to send eight-bit characters.
The default is @samp{on}.
+@item enable-paste-delay
+@vindex enable-paste-delay
+When @var{enable-bracketed-paste} is @samp{On}, this variable controls
+how the end-of-line character (Newline or Return, depending on the OS)
+is acted upon when it appears in pasted text. Consequently,
+enable-paste-delay controls whether pasted text becomes an active
+region and is affected by the @var{enable-active-region} setting.
+
+When @var{enable-bracketed-paste} is @samp{Off} the value of this
+variable is ignored.
+
+When @var{enable-paste-delay} is @samp{On}, end-of-line characters
+appearing in pasted text are not immediately delivered to the
+application. Instead, the entire sequence of pasted characters,
+including any end-of-line characters, become the active region and are
+available for editing. Pressing the end-of-line key on the keyboard
+is necessary to deliver the pasted text to the application.
+
+When set to @samp{Off}, pasted characters are immediately delivered to
+the application and there is no active region. Pasting in
+bracketed-paste mode behaves as if no editing commands exist and every
+character in the clipboard is instead typed on the keyboard.
+
+The default is @samp{Off}.
+
@item expand-tilde
@vindex expand-tilde
If set to @samp{on}, tilde expansion is performed when Readline
diff --git a/kill.c b/kill.c
index 61b744c..4ff8170 100644
--- a/kill.c
+++ b/kill.c
@@ -692,8 +692,11 @@ rl_yank_last_arg (int count, int key)
}
/* Having read the special escape sequence denoting the beginning of a
- `bracketed paste' sequence, read the rest of the pasted input until the
- closing sequence and return the pasted text. */
+ `bracketed paste' sequence, read the rest of the pasted input until
+ the closing sequence. When paste-delay is enabled, return the
+ pasted text. Otherwise, accept each whole line of pasted text and
+ return the pasted text following the last EOL character in the
+ paste. */
char *
_rl_bracketed_text (size_t *lenp)
{
@@ -724,6 +727,18 @@ _rl_bracketed_text (size_t *lenp)
len -= BRACK_PASTE_SLEN;
break;
}
+
+ if (c == '\n' && ! _rl_enable_paste_delay)
+ {
+ buf[len] = '\0';
+ RL_UNSETSTATE (RL_STATE_MOREINPUT);
+ rl_insert_text (buf);
+ rl_newline (1, c);
+ RL_SETSTATE (RL_STATE_MOREINPUT);
+ len = 0;
+ buf[0] = '\0';
+ }
+
}
RL_UNSETSTATE (RL_STATE_MOREINPUT);
@@ -827,6 +842,12 @@ _rl_bracketed_read_key ()
xfree (pbuf);
}
+ /*
+ if (c == '\n' && ! _rl_enable_paste_delay)
+ {
+ rl_newline (1, c);
+ }
+ */
return c;
}
diff --git a/readline.c b/readline.c
index 888612c..72b20dd 100644
--- a/readline.c
+++ b/readline.c
@@ -321,7 +321,8 @@ int _rl_show_mode_in_prompt = 0;
where it will prefix pasted text with an escape sequence and send
another to mark the end of the paste. */
int _rl_enable_bracketed_paste = BRACKETED_PASTE_DEFAULT;
-int _rl_enable_active_region = BRACKETED_PASTE_DEFAULT;
+int _rl_enable_paste_delay = PASTE_DELAY_DEFAULT && BRACKETED_PASTE_DEFAULT;
+int _rl_enable_active_region = PASTE_DELAY_DEFAULT && BRACKETED_PASTE_DEFAULT;
/* **************************************************************** */
/* */
diff --git a/rlprivate.h b/rlprivate.h
index 70ff01c..2afd09f 100644
--- a/rlprivate.h
+++ b/rlprivate.h
@@ -322,6 +322,9 @@ extern int _rl_search_getchar (_rl_search_cxt *);
#ifndef BRACKETED_PASTE_DEFAULT
# define BRACKETED_PASTE_DEFAULT 1 /* XXX - for now */
#endif
+#ifndef PASTE_DELAY_DEFAULT
+# define PASTE_DELAY_DEFAULT 0
+#endif
#define BRACK_PASTE_PREF "\033[200~"
#define BRACK_PASTE_SUFF "\033[201~"
@@ -553,6 +556,7 @@ extern int _rl_revert_all_at_newline;
extern int _rl_echo_control_chars;
extern int _rl_show_mode_in_prompt;
extern int _rl_enable_bracketed_paste;
+extern int _rl_enable_paste_delay;
extern int _rl_enable_active_region;
extern char *_rl_active_region_start_color;
extern char *_rl_active_region_end_color;
diff --git a/shlib/Makefile.in b/shlib/Makefile.in
index d138524..9d37a53 100644
--- a/shlib/Makefile.in
+++ b/shlib/Makefile.in
@@ -64,7 +64,7 @@ localedir = @localedir@
DESTDIR =
CFLAGS = @CFLAGS@
-LOCAL_CFLAGS = @LOCAL_CFLAGS@ -DRL_LIBRARY_VERSION='"$(RL_LIBRARY_VERSION)"' @BRACKETED_PASTE@
+LOCAL_CFLAGS = @LOCAL_CFLAGS@ -DRL_LIBRARY_VERSION='"$(RL_LIBRARY_VERSION)"' @BRACKETED_PASTE@ @PASTE_DELAY@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@ @LOCAL_LDFLAGS@ @CFLAGS@
diff --git a/terminal.c b/terminal.c
index bddf1ed..f9d246c 100644
--- a/terminal.c
+++ b/terminal.c
@@ -568,6 +568,7 @@ _rl_init_terminal_io (const char *terminal_name)
/* Assume generic unknown terminal can't handle the enable/disable
escape sequences */
_rl_enable_bracketed_paste = 0;
+ _rl_enable_paste_delay = 0;
/* No terminal so/se capabilities. */
_rl_enable_active_region = 0;
@@ -628,7 +629,9 @@ _rl_init_terminal_io (const char *terminal_name)
/* There's no way to determine whether or not a given terminal supports
bracketed paste mode, so we assume a terminal named "dumb" does not. */
if (dumbterm)
- _rl_enable_bracketed_paste = _rl_enable_active_region = 0;
+ _rl_enable_bracketed_paste = _rl_enable_paste_delay
+ = _rl_enable_active_region
+ = 0;
if (reset_region_colors)
{