1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2017-2025, VU University Amsterdam 7 CWI Amsterdam 8 SWI-Prolog Solutions b.v. 9 All rights reserved. 10 11 Redistribution and use in source and binary forms, with or without 12 modification, are permitted provided that the following conditions 13 are met: 14 15 1. Redistributions of source code must retain the above copyright 16 notice, this list of conditions and the following disclaimer. 17 18 2. Redistributions in binary form must reproduce the above copyright 19 notice, this list of conditions and the following disclaimer in 20 the documentation and/or other materials provided with the 21 distribution. 22 23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 POSSIBILITY OF SUCH DAMAGE. 35*/ 36 37:- module(editline, 38 [ el_wrap/0, % wrap user_input, etc. 39 el_wrap/1, % +Options 40 el_wrap/4, % +Prog, +Input, +Output, +Error 41 el_wrap/5, % +Prog, +Input, +Output, +Error, +Options 42 el_wrapped/1, % +Input 43 el_unwrap/1, % +Input 44 45 el_source/2, % +Input, +File 46 el_bind/2, % +Input, +Args 47 el_set/2, % +Input, +Action 48 el_get/2, % +Input, ?Property 49 el_addfn/4, % +Input, +Name, +Help, :Goal 50 el_cursor/2, % +Input, +Move 51 el_line/2, % +Input, -Line 52 el_insertstr/2, % +Input, +Text 53 el_deletestr/2, % +Input, +Count 54 55 el_history/2, % +Input, ?Action 56 el_history_events/2, % +Input, -Events 57 el_add_history/2, % +Input, +Line 58 el_write_history/2, % +Input, +FileName 59 el_read_history/2, % +Input, +FileName 60 61 el_version/1 % -Version:integer 62 ]). 63:- autoload(library(apply),[maplist/2,maplist/3]). 64:- autoload(library(lists),[reverse/2,max_list/2,append/3,member/2]). 65:- autoload(library(solution_sequences),[call_nth/2]). 66:- autoload(library(option), [merge_options/3]). 67 68:- use_foreign_library(foreign(libedit4pl)). 69 70:- initialization el_wrap_if_ok. 71 72:- meta_predicate 73 el_addfn(+,+,+,3). 74 75:- multifile 76 el_setup/1, % +Input 77 el_wcwidth/2, % +Code, -Columns 78 prolog:complete_input/4.
89el_wrap_if_ok :- 90 \+ current_prolog_flag(readline, readline), 91 stream_property(user_input, tty(true)), 92 !, 93 el_wrap. 94el_wrap_if_ok.
user_input
is connected to a terminal. This is the high level predicate used
for most purposes. The remainder of the library interface deals with
low level predicates that allows for applying and programming
libedit in non-standard situations.
The library is registered with ProgName set to swipl (see
el_wrap/4).
Options processed:
history or 100 if this flag is not defined.120el_wrap :- 121 el_wrap([]). 122 123el_wrap(_) :- 124 el_wrapped(user_input), 125 !. 126el_wrap(Options) :- 127 stream_property(user_input, tty(true)), !, 128 findall(Opt, el_default(Opt), Defaults), 129 merge_options(Options, Defaults, Options1), 130 el_wrap(swipl, user_input, user_output, user_error, Options1), 131 add_prolog_commands(user_input), 132 ignore(el_set(user_input, wordchars("_"))), 133 forall(el_setup(user_input), true), 134 enable_bracketed_paste(user_input), 135 enable_word_motion(user_input), 136 enable_windows_eof(user_input). 137el_wrap(_). 138 139el_default(history(Size)) :- 140 current_prolog_flag(history, Value), 141 ( integer(Value), 142 Value >= 0 143 -> Size = Value 144 ; Value == false 145 -> Size = 0 146 ). 147:- if(current_predicate(prolog_alert_signal/2)). 148el_default(alert_signo(SigNo)) :- 149 prolog_alert_signal(SigName, SigName), 150 current_signal(SigName, SigNo, _Handler). 151:- endif. 152 153add_prolog_commands(Input) :- 154 el_addfn(Input, complete, 'Complete atoms and files', complete), 155 el_addfn(Input, show_completions, 'List completions', show_completions), 156 el_addfn(Input, electric, 'Indicate matching bracket', electric), 157 el_addfn(Input, isearch_history, 'Incremental search in history', 158 isearch_history), 159 el_addfn(Input, bracketed_paste, 'Handle bracketed paste', bracketed_paste), 160 el_bind(Input, ["^I", complete]), 161 el_bind(Input, ["^[?", show_completions]), 162 el_bind(Input, ["^R", isearch_history]), 163 bind_electric(Input), 164 add_paste_quoted(Input), 165 el_source(Input, _).
-v or -e.
176enable_bracketed_paste(Input) :-
177 ( el_get(Input, editor(vi))
178 -> el_bind(Input, ['-r', "\e[200~"]),
179 el_set(Input, bracketed_paste(false))
180 ; el_bind(Input, ["\e[200~", bracketed_paste]),
181 el_set(Input, bracketed_paste(true))
182 ).ESC[1;5D and ESC[1;5C
for these key combinations (see packages/xpce/src/txt/terminal.c);
most xterm-compatible terminals use the same sequences. In vi
mode the binding is installed in both the insert keymap and the
command (alternative) keymap. Called after the el_setup/1 hooks
since those may switch editor.
This complements the readline emulation, which already binds these sequences in its initialisation.
197enable_word_motion(Input) :-
198 el_bind(Input, ["\e[1;5D", 'ed-prev-word']),
199 el_bind(Input, ["\e[1;5C", 'em-next-word']),
200 ( el_get(Input, editor(vi))
201 -> el_bind(Input, ['-a', "\e[1;5D", 'vi-prev-word']),
202 el_bind(Input, ['-a', "\e[1;5C", 'vi-next-word'])
203 ; true
204 ).^Z to send end-of-file on Windows, matching the platform
convention (compare with ^D on Unix). Routed through libedit's
built-in em-delete-or-list (emacs) or vi-list-or-eof (vi), both
of which return EOF on an empty line.213enable_windows_eof(Input) :- 214 current_prolog_flag(windows, true), 215 !, 216 ( el_get(Input, editor(vi)) 217 -> el_bind(Input, ["^Z", 'vi-list-or-eof']) 218 ; el_bind(Input, ["^Z", 'em-delete-or-list']) 219 ). 220enable_windows_eof(_).
235el_wrap(ProgName, In, Out, Error) :-
236 el_wrap(ProgName, In, Out, Error, []).forall(el_setup(Input), true) after the
input stream has been wrapped, the default Prolog commands have been
added and the default user setup file has been sourced using
el_source/2. It can be used to define and bind additional commands.$HOME/.editrcbind command with the given arguments. The
example below lists the current key bindings.
?- el_bind(user_input, ['-a']).
The predicate el_bind/2 is typically used to bind commands defined using el_addfn/4. Note that the C proxy function has only the last character of the command as context to find the Prolog binding. This implies we cannot both bind e.g., "^[?" and "?" to a Prolog function.
bind -a (see el_bind/2) and Goal is called of the
associated key-binding is activated. Goal is called as
call(:Goal, +Input, +Char, -Continue)
where Input is the input stream providing access to the editor, Char
the activating character and Continue must be instantated with one
of the known continuation codes as defined by libedit: norm,
newline, eof, arghack, refresh, refresh_beep, cursor,
redisplay, error or fatal. In addition, the following Continue
code is provided.
The registered Goal typically used el_line/2 to fetch the input line and el_cursor/2, el_insertstr/2 and/or el_deletestr/2 to manipulate the input line.
Normally el_bind/2 is used to associate the defined command with a keyboard sequence.
el_set() and el_wset(). Currently provided values for
Action are:
el_wsey() EL_WORDCHARS, which is only provided
in some recent versions of libedit.ESC[200~ /
ESC[201~ before each prompt, which the default bindings
route through bracketed_paste/3. Disabling sends the matching
ESC[?2004l sequence immediately. enable_bracketed_paste/1
manages this based on the current editor; you normally do not
need to set it directly.This predicate fails silently of Action is not implemented. Illegal input raises in an exception.
el_get(). Currently supported Property terms:
emacs or vi, reflecting the current
keymap selected via el_bind/2 with -e / -v.
Any other Property raises a domain_error(editline_property, _).
line(Before,
After), where Before is a string holding the text before the
cursor and After is a string holding the text after the cursor.history() from libedit. Supported actions are:
el_history() using H_GETSIZE,
which returns the number of currently saved events. The number
of saved events may be computed from first and last or
using el_history_events/2.first is the most recent event and
last the oldest.history() API, retrieving a numbered event without changing
the current notion.Num-String, where
Num is the event number and String is the associated string
without terminating newline.LIBEDIT_MAJOR*10000 + LIBEDIT_MINOR*100.
The version is generated from the include file histedit.h,
which implies that the actual version of the shared library may be
different.435:- multifile 436 prolog:history/2. 437 438prologhistory(Input, enabled) :- 439 !, 440 el_wrapped(Input), 441 el_history(Input, getsize(Size)), 442 Size > 0. 443prologhistory(Input, add(Line)) :- 444 !, 445 el_add_history(Input, Line). 446prologhistory(Input, load(File)) :- 447 !, 448 compat_read_history(Input, File). 449prologhistory(Input, save(File)) :- 450 !, 451 el_write_history(Input, File). 452prologhistory(Input, events(Events)) :- 453 !, 454 el_history_events(Input, Events). 455prologhistory(Input, Command) :- 456 public_command(Command), 457 !, 458 el_history(Input, Command). 459 460public_command(first(_Num, _String)). 461public_command(curr(_Num, _String)). 462public_command(event(_Num, _String)). 463public_command(prev_str(_Search, _Num, _String)). 464public_command(clear).
swipl-win.exe before migrating to SDL.471compat_read_history(Input, File) :- 472 catch(el_read_history(Input, File), error(editline(_),_), fail), 473 !. 474compat_read_history(Input, File) :- 475 access_file(File, read), 476 setup_call_cleanup( 477 open(File, read, In, [encoding(utf8)]), 478 read_old_history(Input, In), 479 close(In)), 480 !. 481compat_read_history(_, _). 482 483read_old_history(Input, From) :- 484 catch('$raw_read'(From, Line), error(_,_), fail), 485 ( Line == end_of_file 486 -> true 487 ; string_concat(Line, '.', Event), 488 el_add_history(Input, Event), 489 read_old_history(Input, From) 490 ). 491 492 /******************************* 493 * ELECTRIC CARET * 494 *******************************/
500bind_electric(Input) :- 501 forall(bracket(_Open, Close), bind_code(Input, Close, electric)), 502 forall(quote(Close), bind_code(Input, Close, electric)). 503 504bind_code(Input, Code, Command) :- 505 string_codes(Key, [Code]), 506 el_bind(Input, [Key, Command]).
511electric(Input, Char, Continue) :- 512 string_codes(Str, [Char]), 513 el_insertstr(Input, Str), 514 el_line(Input, line(Before, _)), 515 ( string_codes(Before, Codes), 516 nesting(Codes, 0, Nesting), 517 reverse(Nesting, [Close|RevNesting]) 518 -> ( Close = open(_,_) % open quote 519 -> Continue = refresh 520 ; matching_open(RevNesting, Close, _, Index) 521 -> string_length(Before, Len), % Proper match 522 Move is Index-Len, 523 Continue = electric(Move, 500, refresh) 524 ; Continue = refresh_beep % Not properly nested 525 ) 526 ; Continue = refresh_beep 527 ). 528 529matching_open_index(String, Index) :- 530 string_codes(String, Codes), 531 nesting(Codes, 0, Nesting), 532 reverse(Nesting, [Close|RevNesting]), 533 matching_open(RevNesting, Close, _, Index). 534 535matching_open([Open|Rest], Close, Rest, Index) :- 536 Open = open(Index,_), 537 match(Open, Close), 538 !. 539matching_open([Close1|Rest1], Close, Rest, Index) :- 540 Close1 = close(_,_), 541 matching_open(Rest1, Close1, Rest2, _), 542 matching_open(Rest2, Close, Rest, Index). 543 544match(open(_,Open),close(_,Close)) :- 545 ( bracket(Open, Close) 546 -> true 547 ; Open == Close, 548 quote(Open) 549 ). 550 551bracket(0'(, 0')). 552bracket(0'[, 0']). 553bracket(0'{, 0'}). 554 555quote(0'\'). 556quote(0'\"). 557quote(0'\`). 558 559nesting([], _, []). 560nesting([H|T], I, Nesting) :- 561 ( bracket(H, _Close) 562 -> Nesting = [open(I,H)|Nest] 563 ; bracket(_Open, H) 564 -> Nesting = [close(I,H)|Nest] 565 ), 566 !, 567 I2 is I+1, 568 nesting(T, I2, Nest). 569nesting([0'0, 0'\'|T], I, Nesting) :- 570 !, 571 phrase(skip_code, T, T1), 572 difflist_length(T, T1, Len), 573 I2 is I+Len+2, 574 nesting(T1, I2, Nesting). 575nesting([H|T], I, Nesting) :- 576 quote(H), 577 !, 578 ( phrase(skip_quoted(H), T, T1) 579 -> difflist_length(T, T1, Len), 580 I2 is I+Len+1, 581 Nesting = [open(I,H),close(I2,H)|Nest], 582 nesting(T1, I2, Nest) 583 ; Nesting = [open(I,H)] % Open quote 584 ). 585nesting([_|T], I, Nesting) :- 586 I2 is I+1, 587 nesting(T, I2, Nesting). 588 589difflist_length(List, Tail, Len) :- 590 difflist_length(List, Tail, 0, Len). 591 592difflist_length(List, Tail, Len0, Len) :- 593 List == Tail, 594 !, 595 Len = Len0. 596difflist_length([_|List], Tail, Len0, Len) :- 597 Len1 is Len0+1, 598 difflist_length(List, Tail, Len1, Len). 599 600skip_quoted(H) --> 601 [H], 602 !. 603skip_quoted(H) --> 604 "\\", [H], 605 !, 606 skip_quoted(H). 607skip_quoted(H) --> 608 [_], 609 skip_quoted(H). 610 611skip_code --> 612 "\\", [_], 613 !. 614skip_code --> 615 [_]. 616 617 618 /******************************* 619 * COMPLETION * 620 *******************************/
complete editline function. The
predicate is called with three arguments, the first being the input
stream used to access the libedit functions and the second the
activating character. The last argument tells libedit what to do.
Consult el_set(3), EL_ADDFN for details.631:- dynamic 632 last_complete/2. 633 634complete(Input, _Char, Continue) :- 635 el_line(Input, line(Before, After)), 636 ensure_input_completion, 637 prolog:complete_input(Before, After, Delete, Completions), 638 ( Completions = [One] 639 -> string_length(Delete, Len), 640 el_deletestr(Input, Len), 641 complete_text(One, Text), 642 el_insertstr(Input, Text), 643 Continue = refresh 644 ; Completions == [] 645 -> Continue = refresh_beep 646 ; get_time(Now), 647 retract(last_complete(TLast, Before)), 648 Now - TLast < 2 649 -> nl(user_error), 650 list_alternatives(Completions), 651 Continue = redisplay 652 ; retractall(last_complete(_,_)), 653 get_time(Now), 654 asserta(last_complete(Now, Before)), 655 common_competion(Completions, Extend), 656 ( Delete == Extend 657 -> Continue = refresh_beep 658 ; string_length(Delete, Len), 659 el_deletestr(Input, Len), 660 el_insertstr(Input, Extend), 661 Continue = refresh 662 ) 663 ). 664 665:- dynamic 666 input_completion_loaded/0. 667 668ensure_input_completion :- 669 input_completion_loaded, 670 !. 671ensure_input_completion :- 672 predicate_property(prolog:complete_input(_,_,_,_), 673 number_of_clauses(N)), 674 N > 0, 675 !. 676ensure_input_completion :- 677 exists_source(library(console_input)), 678 !, 679 use_module(library(console_input), []), 680 asserta(input_completion_loaded). 681ensure_input_completion.
688show_completions(Input, _Char, Continue) :- 689 el_line(Input, line(Before, After)), 690 prolog:complete_input(Before, After, _Delete, Completions), 691 nl(user_error), 692 list_alternatives(Completions), 693 Continue = redisplay. 694 695complete_text(Text-_Comment, Text) :- !. 696complete_text(Text, Text).
702common_competion(Alternatives, Common) :- 703 maplist(atomic, Alternatives), 704 !, 705 common_prefix(Alternatives, Common). 706common_competion(Alternatives, Common) :- 707 maplist(complete_text, Alternatives, AltText), 708 !, 709 common_prefix(AltText, Common).
715common_prefix([A1|T], Common) :- 716 common_prefix_(T, A1, Common). 717 718common_prefix_([], Common, Common). 719common_prefix_([H|T], Common0, Common) :- 720 common_prefix(H, Common0, Common1), 721 common_prefix_(T, Common1, Common).
727common_prefix(A1, A2, Prefix) :- 728 sub_atom(A1, 0, _, _, A2), 729 !, 730 Prefix = A2. 731common_prefix(A1, A2, Prefix) :- 732 sub_atom(A2, 0, _, _, A1), 733 !, 734 Prefix = A1. 735common_prefix(A1, A2, Prefix) :- 736 atom_codes(A1, C1), 737 atom_codes(A2, C2), 738 list_common_prefix(C1, C2, C), 739 string_codes(Prefix, C). 740 741list_common_prefix([H|T0], [H|T1], [H|T]) :- 742 !, 743 list_common_prefix(T0, T1, T). 744list_common_prefix(_, _, []).
754list_alternatives(Alternatives) :- 755 maplist(atomic, Alternatives), 756 !, 757 length(Alternatives, Count), 758 maplist(atom_length, Alternatives, Lengths), 759 max_list(Lengths, Max), 760 tty_size(_, Cols), 761 ColW is Max+2, 762 Columns is max(1, Cols // ColW), 763 RowCount is (Count+Columns-1)//Columns, 764 length(Rows, RowCount), 765 to_matrix(Alternatives, Rows, Rows), 766 ( RowCount > 11 767 -> length(First, 10), 768 Skipped is RowCount - 10, 769 append(First, _, Rows), 770 maplist(write_row(ColW), First), 771 format(user_error, '... skipped ~D rows~n', [Skipped]) 772 ; maplist(write_row(ColW), Rows) 773 ). 774list_alternatives(Alternatives) :- 775 maplist(complete_text, Alternatives, AltText), 776 list_alternatives(AltText). 777 778to_matrix([], _, Rows) :- 779 !, 780 maplist(close_list, Rows). 781to_matrix([H|T], [RH|RT], Rows) :- 782 !, 783 add_list(RH, H), 784 to_matrix(T, RT, Rows). 785to_matrix(List, [], Rows) :- 786 to_matrix(List, Rows, Rows). 787 788add_list(Var, Elem) :- 789 var(Var), !, 790 Var = [Elem|_]. 791add_list([_|T], Elem) :- 792 add_list(T, Elem). 793 794close_list(List) :- 795 append(List, [], _), 796 !. 797 798write_row(ColW, Row) :- 799 length(Row, Columns), 800 make_format(Columns, ColW, Format), 801 format(user_error, Format, Row). 802 803make_format(N, ColW, Format) :- 804 format(string(PerCol), '~~w~~t~~~d+', [ColW]), 805 Front is N - 1, 806 length(LF, Front), 807 maplist(=(PerCol), LF), 808 append(LF, ['~w~n'], Parts), 809 atomics_to_string(Parts, Format). 810 811 812 /******************************* 813 * SEARCH * 814 *******************************/
821isearch_history(Input, _Char, Continue) :- 822 el_line(Input, line(Before, After)), 823 string_concat(Before, After, Current), 824 string_length(Current, Len), 825 search_print('', "", Current), 826 search(Input, "", Current, 1, Line), 827 el_deletestr(Input, Len), 828 el_insertstr(Input, Line), 829 Continue = redisplay. 830 831search(Input, For, Current, Nth, Line) :- 832 el_getc(Input, Next), 833 Next \== -1, 834 !, 835 search(Next, Input, For, Current, Nth, Line). 836search(_Input, _For, _Current, _Nth, ""). 837 838search(7, _Input, _, Current, _, Current) :- % C-g: abort 839 !, 840 clear_line. 841search(18, Input, For, Current, Nth, Line) :- % C-r: search previous 842 !, 843 N2 is Nth+1, 844 search_(Input, For, Current, N2, Line). 845search(19, Input, For, Current, Nth, Line) :- % C-s: search next 846 !, 847 N2 is max(1,Nth-1), 848 search_(Input, For, Current, N2, Line). 849search(127, Input, For, Current, _Nth, Line) :- % DEL/BS: shorten search 850 sub_string(For, 0, _, 1, For1), 851 !, 852 search_(Input, For1, Current, 1, Line). 853search(Char, Input, For, Current, Nth, Line) :- 854 code_type(Char, cntrl), 855 !, 856 search_end(Input, For, Current, Nth, Line), 857 el_push(Input, Char). 858search(Char, Input, For, Current, _Nth, Line) :- 859 format(string(For1), '~w~c', [For,Char]), 860 search_(Input, For1, Current, 1, Line). 861 862search_(Input, For1, Current, Nth, Line) :- 863 ( find_in_history(Input, For1, Current, Nth, Candidate) 864 -> search_print('', For1, Candidate) 865 ; search_print('failed ', For1, Current) 866 ), 867 search(Input, For1, Current, Nth, Line). 868 869search_end(Input, For, Current, Nth, Line) :- 870 ( find_in_history(Input, For, Current, Nth, Line) 871 -> true 872 ; Line = Current 873 ), 874 clear_line. 875 876find_in_history(_, "", Current, _, Current) :- 877 !. 878find_in_history(Input, For, _, Nth, Line) :- 879 el_history_events(Input, History), 880 call_nth(( member(_N-Line, History), 881 sub_string(Line, _, _, _, For) 882 ), 883 Nth), 884 !. 885 886search_print(State, Search, Current) :- 887 format(user_error, '\r(~wreverse-i-search)`~w\': ~w\e[0K', 888 [State, Search, Current]). 889 890clear_line :- 891 format(user_error, '\r\e[0K', []). 892 893 894 /******************************* 895 * PASTE QUOTED * 896 *******************************/ 897 898:- meta_predicate 899 with_quote_flags(+,+,0). 900 901add_paste_quoted(Input) :- 902 current_prolog_flag(gui, true), 903 !, 904 el_addfn(Input, paste_quoted, 'Paste as quoted atom', paste_quoted), 905 el_bind(Input, ["^Y", paste_quoted]). 906add_paste_quoted(_).
914paste_quoted(Input, _Char, Continue) :- 915 clipboard_content(String), 916 quote_text(Input, String, Quoted), 917 el_insertstr(Input, Quoted), 918 Continue = refresh. 919 920quote_text(Input, String, Value) :- 921 el_line(Input, line(Before, _After)), 922 ( sub_string(Before, _, 1, 0, Quote) 923 -> true 924 ; Quote = "'" 925 ), 926 quote_text(Input, Quote, String, Value). 927 928quote_text(Input, "'", Text, Quoted) => 929 format(string(Quoted), '~q', [Text]), 930 el_deletestr(Input, 1). 931quote_text(Input, "\"", Text, Quoted) => 932 atom_string(Text, String), 933 with_quote_flags( 934 string, codes, 935 format(string(Quoted), '~q', [String])), 936 el_deletestr(Input, 1). 937quote_text(Input, "`", Text, Quoted) => 938 atom_string(Text, String), 939 with_quote_flags( 940 codes, string, 941 format(string(Quoted), '~q', [String])), 942 el_deletestr(Input, 1). 943quote_text(_, _, Text, Quoted) => 944 format(string(Quoted), '~q', [Text]). 945 946with_quote_flags(Double, Back, Goal) :- 947 setup_call_cleanup( 948 ( push_prolog_flag(double_quotes, Double), 949 push_prolog_flag(back_quotes, Back) ), 950 Goal, 951 ( pop_prolog_flag(back_quotes), 952 pop_prolog_flag(double_quotes) )). 953 954clipboard_content(Text) :- 955 current_prolog_flag(gui, true), 956 !, 957 autoload_call(in_pce_thread_sync( 958 autoload_call( 959 get(@(display), paste, primary, string(Text))))). 960clipboard_content(""). 961 962 963 /******************************* 964 * BRACKETED PASTE * 965 *******************************/
The terminal is asked to enable bracketed paste mode (ESC[?2004h) from the C layer each time a prompt is issued.
976bracketed_paste(Input, _Char, Continue) :-
977 collect_paste(Input, [], RevCodes),
978 reverse(RevCodes, Codes),
979 string_codes(Text, Codes),
980 el_insertstr(Input, Text),
981 Continue = refresh.
990collect_paste(Input, RevCodes, Result) :-
991 el_getc(Input, Char),
992 ( Char == -1 % EOF / error
993 -> Result = RevCodes
994 ; paste_char(Char, Char1),
995 RevCodes1 = [Char1|RevCodes],
996 ( RevCodes1 = [0'~,0'1,0'0,0'2,0'[,0'\e|Rest] % ESC[201~ reversed
997 -> Result = Rest
998 ; collect_paste(Input, RevCodes1, Result)
999 )
1000 ).1009paste_char(0'\r, 0'\n) :- !. % CR → LF (INLCR maps \n to \r in edit mode) 1010paste_char(C, C). 1011 1012 1013 /******************************* 1014 * MESSAGE * 1015 *******************************/ 1016 1017:- multifile prolog:error_message//1. 1018 1019prologerror_message(editline(Msg)) --> 1020 [ 'editline: ~s'-[Msg] ]
BSD libedit based command line editing
This library wraps the BSD libedit command line editor. The binding provides a high level API to enable command line editing on the Prolog user streams and low level predicates to apply the library on other streams and program the library.