Skip to content

Commit 127d9ce

Browse files
committed
Initial bracketed-paste-mode, based on PR by timo++
1 parent a5c1a7f commit 127d9ce

4 files changed

Lines changed: 61 additions & 6 deletions

File tree

Changes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
Revision history for Terminal-LineEditor
22

33
{{$NEXT}}
4+
[Functionality]
5+
- Initial support for bracketed-paste-mode, inspired by timo++'s
6+
https://github.com/japhb/Terminal-LineEditor/pull/13
7+
48

59
0.0.21 2025-10-06T22:15:47-07:00
610
[Compatibility]

lib/Terminal/LineEditor/EditableBuffer.rakumod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,11 +476,16 @@ role Terminal::LineEditor::SingleLineTextInput {
476476
}
477477

478478

479-
### Insert/Yank/Swap
479+
### Insert/Paste/Yank/Swap
480480
method edit-insert-string(Str:D $string --> Bool) {
481481
$.buffer.insert($.insert-cursor.pos, $string)
482482
}
483483

484+
method edit-paste-buffer(@buffer --> Bool) {
485+
# Default paste behavior: join buffer into a string and insert that
486+
$.buffer.insert($.insert-cursor.pos, @buffer.join)
487+
}
488+
484489
method edit-yank(--> Bool) {
485490
$.buffer.yank($.insert-cursor.pos)
486491
}

lib/Terminal/LineEditor/RawTerminalInput.rakumod

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ enum MouseEventMode is export (
5959
MouseAnyEvents => 1003, # Press, release, any movement
6060
);
6161

62+
enum BracketedPasteMode is export <
63+
PasteNoBrackets
64+
PasteWithBrackets
65+
>;
66+
6267

6368
class ModifiedSpecialKey {
6469
has SpecialKey $.key;
@@ -221,6 +226,8 @@ role Terminal::LineEditor::KeyMappable {
221226
CursorUp => 'history-prev',
222227
CursorDown => 'history-next',
223228

229+
PasteStart => 'paste-start',
230+
224231
Alt-b => 'move-word-back',
225232
Alt-c => 'tclc-word', # Readline treats this as Capitalize
226233
Alt-d => 'delete-word-forward',
@@ -311,6 +318,7 @@ role Terminal::LineEditor::RawTerminalIO {
311318
has atomicint $!done = 0;
312319
has $!parse = make-ansi-parser(emit-item => { $!raw-supplier.emit($_) });
313320
has MouseEventMode:D $!previous-mouse-mode = MouseNoEvents;
321+
has BracketedPasteMode:D $.current-paste-mode = PasteNoBrackets;
314322
has $!saved-term-config;
315323
has $!saved-fd;
316324
has @!active-queries;
@@ -368,6 +376,12 @@ role Terminal::LineEditor::RawTerminalIO {
368376
$!previous-mouse-mode = $mode;
369377
}
370378

379+
#| Turn bracketed paste mode on or off
380+
method set-bracketed-paste-mode(BracketedPasteMode:D $mode) {
381+
$.output.print($mode ?? "\e[?2004h" !! "\e[?2004l");
382+
$.output.flush;
383+
$!current-paste-mode = $mode;
384+
}
371385

372386
#| Start reading input TTY and feeding the ANSI parser; parsed stream will
373387
#| appear at $!raw-supply, _in tokenized form_ (as codepoints and buffers
@@ -657,8 +671,11 @@ class Terminal::LineEditor::ScrollingSingleLineInput::ANSI
657671
#| Resolve an edit action and compute a new refresh string
658672
method do-edit($action, $insert?) {
659673
# Do edit and determine if contents actually changed
660-
my $edited = $insert.defined ?? self.edit-insert-string($insert)
661-
!! self."edit-$action"();
674+
my $edited = $insert.defined
675+
?? ($action eq 'insert-string'
676+
?? self.edit-insert-string($insert)
677+
!! self.edit-paste-buffer($insert))
678+
!! self."edit-$action"();
662679

663680
self.refresh-string($edited)
664681
}
@@ -685,7 +702,7 @@ class Terminal::LineEditor::CLIInput
685702
constant $special
686703
= set < abort-input abort-or-delete finish literal-next suspend
687704
history-start history-end history-next history-prev
688-
complete >;
705+
complete paste-start >;
689706
}
690707

691708
#| Fetch completions based on current buffer contents and cursor pos
@@ -827,6 +844,8 @@ class Terminal::LineEditor::CLIInput
827844

828845
# Read raw characters and dispatch either as actions or chars to insert
829846
my $literal-mode = False;
847+
my $paste-mode = False;
848+
my @paste-buffer;
830849
my $aborted = False;
831850
react whenever $.decoded {
832851
# note "Decoded as {.raku}"; $*ERR.flush;
@@ -840,6 +859,20 @@ class Terminal::LineEditor::CLIInput
840859
self.do-edit('insert-string', $string);
841860
$literal-mode = False;
842861
}
862+
elsif $paste-mode {
863+
my $key = self.decode-keyname($_);
864+
if !$key {
865+
@paste-buffer.push($_);
866+
}
867+
elsif $key eq 'PasteEnd' {
868+
self.do-edit('paste-buffer', @paste-buffer);
869+
@paste-buffer = Empty;
870+
$paste-mode = False;
871+
}
872+
else {
873+
# Intentionally ignore all other special keys
874+
}
875+
}
843876
else {
844877
my $key = self.decode-keyname($_);
845878
if !$key {
@@ -851,6 +884,7 @@ class Terminal::LineEditor::CLIInput
851884
reset-completions;
852885

853886
when 'literal-next' { $literal-mode = True }
887+
when 'paste-start' { $paste-mode = True if $.current-paste-mode }
854888
when 'history-start' { do-history-start }
855889
when 'history-prev' { do-history-prev }
856890
when 'history-next' { do-history-next }

t/03-single-line-text-input.rakutest

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use Terminal::LineEditor;
55
use Terminal::LineEditor::EditableBuffer;
66

77

8-
plan 243;
8+
plan 251;
99

1010

1111
# Compose role into a stub class
@@ -100,7 +100,19 @@ is $input.buffer.contents, 'foo';
100100
is $input.insert-cursor.pos, 3;
101101
ok $input.insert-cursor.at-end;
102102

103-
ok $input.edit-insert-string(' baz');
103+
ok $input.edit-insert-string(' b');
104+
is $input.buffer.contents, 'foo b';
105+
is $input.insert-cursor.pos, 5;
106+
ok $input.insert-cursor.at-end;
107+
108+
109+
# Pastes
110+
ok $input.edit-paste-buffer(< a z >);
111+
is $input.buffer.contents, 'foo baz';
112+
is $input.insert-cursor.pos, 7;
113+
ok $input.insert-cursor.at-end;
114+
115+
nok $input.edit-paste-buffer(Empty);
104116
is $input.buffer.contents, 'foo baz';
105117
is $input.insert-cursor.pos, 7;
106118
ok $input.insert-cursor.at-end;

0 commit comments

Comments
 (0)