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(,,,). 74 75:- multifile 76 el_setup/1, % +Input 77 prolog:complete_input/4.
88el_wrap_if_ok :- 89 \+ current_prolog_flag(readline, readline), 90 stream_property(user_input, tty(true)), 91 !, 92 el_wrap. 93el_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.119el_wrap :- 120 el_wrap([]). 121 122el_wrap(_) :- 123 el_wrapped(user_input), 124 !. 125el_wrap(Options) :- 126 stream_property(user_input, tty(true)), !, 127 findall(Opt, el_default(Opt), Defaults), 128 merge_options(Options, Defaults, Options1), 129 el_wrap(swipl, user_input, user_output, user_error, Options1), 130 add_prolog_commands(user_input), 131 ignore(el_set(user_input, wordchars("_"))), 132 forall(el_setup(user_input), true), 133 enable_bracketed_paste(user_input), 134 enable_word_motion(user_input), 135 enable_windows_eof(user_input). 136el_wrap(_). 137 138el_default(history(Size)) :- 139 current_prolog_flag(history, Value), 140 ( integer(Value), 141 Value >= 0 142 -> Size = Value 143 ; Value == false 144 -> Size = 0 145 ). 146:- if(current_predicate(prolog_alert_signal/2)). 147el_default(alert_signo(SigNo)) :- 148 prolog_alert_signal(SigName, SigName), 149 current_signal(SigName, SigNo, _Handler). 150:- endif. 151 152add_prolog_commands(Input) :- 153 el_addfn(Input, complete, 'Complete atoms and files', complete), 154 el_addfn(Input, show_completions, 'List completions', show_completions), 155 el_addfn(Input, electric, 'Indicate matching bracket', electric), 156 el_addfn(Input, isearch_history, 'Incremental search in history', 157 isearch_history), 158 el_addfn(Input, bracketed_paste, 'Handle bracketed paste', bracketed_paste), 159 el_bind(Input, ["^I", complete]), 160 el_bind(Input, ["^[?", show_completions]), 161 el_bind(Input, ["^R", isearch_history]), 162 bind_electric(Input), 163 add_paste_quoted(Input), 164 el_source(Input, _).
-v or -e.
175enable_bracketed_paste(Input) :-
176 ( el_get(Input, editor(vi))
177 -> el_bind(Input, ['-r', "\e[200~"]),
178 el_set(Input, bracketed_paste(false))
179 ; el_bind(Input, ["\e[200~", bracketed_paste]),
180 el_set(Input, bracketed_paste(true))
181 ).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.
196enable_word_motion(Input) :-
197 el_bind(Input, ["\e[1;5D", 'ed-prev-word']),
198 el_bind(Input, ["\e[1;5C", 'em-next-word']),
199 ( el_get(Input, editor(vi))
200 -> el_bind(Input, ['-a', "\e[1;5D", 'vi-prev-word']),
201 el_bind(Input, ['-a', "\e[1;5C", 'vi-next-word'])
202 ; true
203 ).^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.212enable_windows_eof(Input) :- 213 current_prolog_flag(windows, true), 214 !, 215 ( el_get(Input, editor(vi)) 216 -> el_bind(Input, ["^Z", 'vi-list-or-eof']) 217 ; el_bind(Input, ["^Z", 'em-delete-or-list']) 218 ). 219enable_windows_eof(_).
234el_wrap(ProgName, In, Out, Error) :-
235 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.434:- multifile 435 prolog:history/2. 436 437prologhistory(Input, enabled) :- 438 !, 439 el_wrapped(Input), 440 el_history(Input, getsize(Size)), 441 Size > 0. 442prologhistory(Input, add(Line)) :- 443 !, 444 el_add_history(Input, Line). 445prologhistory(Input, load(File)) :- 446 !, 447 compat_read_history(Input, File). 448prologhistory(Input, save(File)) :- 449 !, 450 el_write_history(Input, File). 451prologhistory(Input, events(Events)) :- 452 !, 453 el_history_events(Input, Events). 454prologhistory(Input, Command) :- 455 public_command(Command), 456 !, 457 el_history(Input, Command). 458 459public_command(first(_Num, _String)). 460public_command(curr(_Num, _String)). 461public_command(event(_Num, _String)). 462public_command(prev_str(_Search, _Num, _String)). 463public_command(clear).
swipl-win.exe before migrating to SDL.470compat_read_history(Input, File) :- 471 catch(el_read_history(Input, File), error(editline(_),_), fail), 472 !. 473compat_read_history(Input, File) :- 474 access_file(File, read), 475 setup_call_cleanup( 476 open(File, read, In, [encoding(utf8)]), 477 read_old_history(Input, In), 478 close(In)), 479 !. 480compat_read_history(_, _). 481 482read_old_history(Input, From) :- 483 catch('$raw_read'(From, Line), error(_,_), fail), 484 ( Line == end_of_file 485 -> true 486 ; string_concat(Line, '.', Event), 487 el_add_history(Input, Event), 488 read_old_history(Input, From) 489 ). 490 491 /******************************* 492 * ELECTRIC CARET * 493 *******************************/
499bind_electric(Input) :- 500 forall(bracket(_Open, Close), bind_code(Input, Close, electric)), 501 forall(quote(Close), bind_code(Input, Close, electric)). 502 503bind_code(Input, Code, Command) :- 504 string_codes(Key, [Code]), 505 el_bind(Input, [Key, Command]).
510electric(Input, Char, Continue) :- 511 string_codes(Str, [Char]), 512 el_insertstr(Input, Str), 513 el_line(Input, line(Before, _)), 514 ( string_codes(Before, Codes), 515 nesting(Codes, 0, Nesting), 516 reverse(Nesting, [Close|RevNesting]) 517 -> ( Close = open(_,_) % open quote 518 -> Continue = refresh 519 ; matching_open(RevNesting, Close, _, Index) 520 -> string_length(Before, Len), % Proper match 521 Move is Index-Len, 522 Continue = electric(Move, 500, refresh) 523 ; Continue = refresh_beep % Not properly nested 524 ) 525 ; Continue = refresh_beep 526 ). 527 528matching_open_index(String, Index) :- 529 string_codes(String, Codes), 530 nesting(Codes, 0, Nesting), 531 reverse(Nesting, [Close|RevNesting]), 532 matching_open(RevNesting, Close, _, Index). 533 534matching_open([Open|Rest], Close, Rest, Index) :- 535 Open = open(Index,_), 536 match(Open, Close), 537 !. 538matching_open([Close1|Rest1], Close, Rest, Index) :- 539 Close1 = close(_,_), 540 matching_open(Rest1, Close1, Rest2, _), 541 matching_open(Rest2, Close, Rest, Index). 542 543match(open(_,Open),close(_,Close)) :- 544 ( bracket(Open, Close) 545 -> true 546 ; Open == Close, 547 quote(Open) 548 ). 549 550bracket(0'(, 0')). 551bracket(0'[, 0']). 552bracket(0'{, 0'}). 553 554quote(0'\'). 555quote(0'\"). 556quote(0'\`). 557 558nesting([], _, []). 559nesting([H|T], I, Nesting) :- 560 ( bracket(H, _Close) 561 -> Nesting = [open(I,H)|Nest] 562 ; bracket(_Open, H) 563 -> Nesting = [close(I,H)|Nest] 564 ), 565 !, 566 I2 is I+1, 567 nesting(T, I2, Nest). 568nesting([0'0, 0'\'|T], I, Nesting) :- 569 !, 570 phrase(skip_code, T, T1), 571 difflist_length(T, T1, Len), 572 I2 is I+Len+2, 573 nesting(T1, I2, Nesting). 574nesting([H|T], I, Nesting) :- 575 quote(H), 576 !, 577 ( phrase(skip_quoted(H), T, T1) 578 -> difflist_length(T, T1, Len), 579 I2 is I+Len+1, 580 Nesting = [open(I,H),close(I2,H)|Nest], 581 nesting(T1, I2, Nest) 582 ; Nesting = [open(I,H)] % Open quote 583 ). 584nesting([_|T], I, Nesting) :- 585 I2 is I+1, 586 nesting(T, I2, Nesting). 587 588difflist_length(List, Tail, Len) :- 589 difflist_length(List, Tail, 0, Len). 590 591difflist_length(List, Tail, Len0, Len) :- 592 List == Tail, 593 !, 594 Len = Len0. 595difflist_length([_|List], Tail, Len0, Len) :- 596 Len1 is Len0+1, 597 difflist_length(List, Tail, Len1, Len). 598 599skip_quoted(H) --> 600 [H], 601 !. 602skip_quoted(H) --> 603 "\\", [H], 604 !, 605 skip_quoted(H). 606skip_quoted(H) --> 607 [_], 608 skip_quoted(H). 609 610skip_code --> 611 "\\", [_], 612 !. 613skip_code --> 614 [_]. 615 616 617 /******************************* 618 * COMPLETION * 619 *******************************/
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.630:- dynamic 631 last_complete/2. 632 633complete(Input, _Char, Continue) :- 634 el_line(Input, line(Before, After)), 635 ensure_input_completion, 636 prolog:complete_input(Before, After, Delete, Completions), 637 ( Completions = [One] 638 -> string_length(Delete, Len), 639 el_deletestr(Input, Len), 640 complete_text(One, Text), 641 el_insertstr(Input, Text), 642 Continue = refresh 643 ; Completions == [] 644 -> Continue = refresh_beep 645 ; get_time(Now), 646 retract(last_complete(TLast, Before)), 647 Now - TLast < 2 648 -> nl(user_error), 649 list_alternatives(Completions), 650 Continue = redisplay 651 ; retractall(last_complete(_,_)), 652 get_time(Now), 653 asserta(last_complete(Now, Before)), 654 common_competion(Completions, Extend), 655 ( Delete == Extend 656 -> Continue = refresh_beep 657 ; string_length(Delete, Len), 658 el_deletestr(Input, Len), 659 el_insertstr(Input, Extend), 660 Continue = refresh 661 ) 662 ). 663 664:- dynamic 665 input_completion_loaded/0. 666 667ensure_input_completion :- 668 input_completion_loaded, 669 !. 670ensure_input_completion :- 671 predicate_property(prolog:complete_input(_,_,_,_), 672 number_of_clauses(N)), 673 N > 0, 674 !. 675ensure_input_completion :- 676 exists_source(library(console_input)), 677 !, 678 use_module(library(console_input), []), 679 asserta(input_completion_loaded). 680ensure_input_completion.
687show_completions(Input, _Char, Continue) :- 688 el_line(Input, line(Before, After)), 689 prolog:complete_input(Before, After, _Delete, Completions), 690 nl(user_error), 691 list_alternatives(Completions), 692 Continue = redisplay. 693 694complete_text(Text-_Comment, Text) :- !. 695complete_text(Text, Text).
701common_competion(Alternatives, Common) :- 702 maplist(atomic, Alternatives), 703 !, 704 common_prefix(Alternatives, Common). 705common_competion(Alternatives, Common) :- 706 maplist(complete_text, Alternatives, AltText), 707 !, 708 common_prefix(AltText, Common).
714common_prefix([A1|T], Common) :- 715 common_prefix_(T, A1, Common). 716 717common_prefix_([], Common, Common). 718common_prefix_([H|T], Common0, Common) :- 719 common_prefix(H, Common0, Common1), 720 common_prefix_(T, Common1, Common).
726common_prefix(A1, A2, Prefix) :- 727 sub_atom(A1, 0, _, _, A2), 728 !, 729 Prefix = A2. 730common_prefix(A1, A2, Prefix) :- 731 sub_atom(A2, 0, _, _, A1), 732 !, 733 Prefix = A1. 734common_prefix(A1, A2, Prefix) :- 735 atom_codes(A1, C1), 736 atom_codes(A2, C2), 737 list_common_prefix(C1, C2, C), 738 string_codes(Prefix, C). 739 740list_common_prefix([H|T0], [H|T1], [H|T]) :- 741 !, 742 list_common_prefix(T0, T1, T). 743list_common_prefix(_, _, []).
753list_alternatives(Alternatives) :- 754 maplist(atomic, Alternatives), 755 !, 756 length(Alternatives, Count), 757 maplist(atom_length, Alternatives, Lengths), 758 max_list(Lengths, Max), 759 tty_size(_, Cols), 760 ColW is Max+2, 761 Columns is max(1, Cols // ColW), 762 RowCount is (Count+Columns-1)//Columns, 763 length(Rows, RowCount), 764 to_matrix(Alternatives, Rows, Rows), 765 ( RowCount > 11 766 -> length(First, 10), 767 Skipped is RowCount - 10, 768 append(First, _, Rows), 769 maplist(write_row(ColW), First), 770 format(user_error, '... skipped ~D rows~n', [Skipped]) 771 ; maplist(write_row(ColW), Rows) 772 ). 773list_alternatives(Alternatives) :- 774 maplist(complete_text, Alternatives, AltText), 775 list_alternatives(AltText). 776 777to_matrix([], _, Rows) :- 778 !, 779 maplist(close_list, Rows). 780to_matrix([H|T], [RH|RT], Rows) :- 781 !, 782 add_list(RH, H), 783 to_matrix(T, RT, Rows). 784to_matrix(List, [], Rows) :- 785 to_matrix(List, Rows, Rows). 786 787add_list(Var, Elem) :- 788 var(Var), !, 789 Var = [Elem|_]. 790add_list([_|T], Elem) :- 791 add_list(T, Elem). 792 793close_list(List) :- 794 append(List, [], _), 795 !. 796 797write_row(ColW, Row) :- 798 length(Row, Columns), 799 make_format(Columns, ColW, Format), 800 format(user_error, Format, Row). 801 802make_format(N, ColW, Format) :- 803 format(string(PerCol), '~~w~~t~~~d+', [ColW]), 804 Front is N - 1, 805 length(LF, Front), 806 maplist(=(PerCol), LF), 807 append(LF, ['~w~n'], Parts), 808 atomics_to_string(Parts, Format). 809 810 811 /******************************* 812 * SEARCH * 813 *******************************/
820isearch_history(Input, _Char, Continue) :- 821 el_line(Input, line(Before, After)), 822 string_concat(Before, After, Current), 823 string_length(Current, Len), 824 search_print('', "", Current), 825 search(Input, "", Current, 1, Line), 826 el_deletestr(Input, Len), 827 el_insertstr(Input, Line), 828 Continue = redisplay. 829 830search(Input, For, Current, Nth, Line) :- 831 el_getc(Input, Next), 832 Next \== -1, 833 !, 834 search(Next, Input, For, Current, Nth, Line). 835search(_Input, _For, _Current, _Nth, ""). 836 837search(7, _Input, _, Current, _, Current) :- % C-g: abort 838 !, 839 clear_line. 840search(18, Input, For, Current, Nth, Line) :- % C-r: search previous 841 !, 842 N2 is Nth+1, 843 search_(Input, For, Current, N2, Line). 844search(19, Input, For, Current, Nth, Line) :- % C-s: search next 845 !, 846 N2 is max(1,Nth-1), 847 search_(Input, For, Current, N2, Line). 848search(127, Input, For, Current, _Nth, Line) :- % DEL/BS: shorten search 849 sub_string(For, 0, _, 1, For1), 850 !, 851 search_(Input, For1, Current, 1, Line). 852search(Char, Input, For, Current, Nth, Line) :- 853 code_type(Char, cntrl), 854 !, 855 search_end(Input, For, Current, Nth, Line), 856 el_push(Input, Char). 857search(Char, Input, For, Current, _Nth, Line) :- 858 format(string(For1), '~w~c', [For,Char]), 859 search_(Input, For1, Current, 1, Line). 860 861search_(Input, For1, Current, Nth, Line) :- 862 ( find_in_history(Input, For1, Current, Nth, Candidate) 863 -> search_print('', For1, Candidate) 864 ; search_print('failed ', For1, Current) 865 ), 866 search(Input, For1, Current, Nth, Line). 867 868search_end(Input, For, Current, Nth, Line) :- 869 ( find_in_history(Input, For, Current, Nth, Line) 870 -> true 871 ; Line = Current 872 ), 873 clear_line. 874 875find_in_history(_, "", Current, _, Current) :- 876 !. 877find_in_history(Input, For, _, Nth, Line) :- 878 el_history_events(Input, History), 879 call_nth(( member(_N-Line, History), 880 sub_string(Line, _, _, _, For) 881 ), 882 Nth), 883 !. 884 885search_print(State, Search, Current) :- 886 format(user_error, '\r(~wreverse-i-search)`~w\': ~w\e[0K', 887 [State, Search, Current]). 888 889clear_line :- 890 format(user_error, '\r\e[0K', []). 891 892 893 /******************************* 894 * PASTE QUOTED * 895 *******************************/ 896 897:- meta_predicate 898 with_quote_flags(,,). 899 900add_paste_quoted(Input) :- 901 current_prolog_flag(gui, true), 902 !, 903 el_addfn(Input, paste_quoted, 'Paste as quoted atom', paste_quoted), 904 el_bind(Input, ["^Y", paste_quoted]). 905add_paste_quoted(_).
913paste_quoted(Input, _Char, Continue) :- 914 clipboard_content(String), 915 quote_text(Input, String, Quoted), 916 el_insertstr(Input, Quoted), 917 Continue = refresh. 918 919quote_text(Input, String, Value) :- 920 el_line(Input, line(Before, _After)), 921 ( sub_string(Before, _, 1, 0, Quote) 922 -> true 923 ; Quote = "'" 924 ), 925 quote_text(Input, Quote, String, Value). 926 927quote_text(Input, "'", Text, Quoted) => 928 format(string(Quoted), '~q', [Text]), 929 el_deletestr(Input, 1). 930quote_text(Input, "\"", Text, Quoted) => 931 atom_string(Text, String), 932 with_quote_flags( 933 string, codes, 934 format(string(Quoted), '~q', [String])), 935 el_deletestr(Input, 1). 936quote_text(Input, "`", Text, Quoted) => 937 atom_string(Text, String), 938 with_quote_flags( 939 codes, string, 940 format(string(Quoted), '~q', [String])), 941 el_deletestr(Input, 1). 942quote_text(_, _, Text, Quoted) => 943 format(string(Quoted), '~q', [Text]). 944 945with_quote_flags(Double, Back, Goal) :- 946 current_prolog_flag(double_quotes, ODouble), 947 current_prolog_flag(back_quotes, OBack), 948 setup_call_cleanup( 949 ( set_prolog_flag(double_quotes, Double), 950 set_prolog_flag(back_quotes, Back) ), 951 Goal, 952 ( set_prolog_flag(double_quotes, ODouble), 953 set_prolog_flag(back_quotes, OBack) )). 954 955clipboard_content(Text) :- 956 current_prolog_flag(gui, true), 957 !, 958 autoload_call(in_pce_thread_sync( 959 autoload_call( 960 get(@(display), paste, primary, string(Text))))). 961clipboard_content(""). 962 963 964 /******************************* 965 * BRACKETED PASTE * 966 *******************************/
The terminal is asked to enable bracketed paste mode (ESC[?2004h) from the C layer each time a prompt is issued.
977bracketed_paste(Input, _Char, Continue) :-
978 collect_paste(Input, [], RevCodes),
979 reverse(RevCodes, Codes),
980 string_codes(Text, Codes),
981 el_insertstr(Input, Text),
982 Continue = refresh.
991collect_paste(Input, RevCodes, Result) :-
992 el_getc(Input, Char),
993 ( Char == -1 % EOF / error
994 -> Result = RevCodes
995 ; paste_char(Char, Char1),
996 RevCodes1 = [Char1|RevCodes],
997 ( RevCodes1 = [0'~,0'1,0'0,0'2,0'[,0'\e|Rest] % ESC[201~ reversed
998 -> Result = Rest
999 ; collect_paste(Input, RevCodes1, Result)
1000 )
1001 ).1010paste_char(0'\r, 0'\n) :- !. % CR → LF (INLCR maps \n to \r in edit mode) 1011paste_char(C, C). 1012 1013 1014 /******************************* 1015 * MESSAGE * 1016 *******************************/ 1017 1018:- multifile prolog:error_message//1. 1019 1020prologerror_message(editline(Msg)) --> 1021 [ '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. */