From e7c7173e09b19811a3c40585fa8a23e0f8dd600a Mon Sep 17 00:00:00 2001 From: Frank Hunleth Date: Fri, 30 Jun 2023 08:02:48 -0400 Subject: [PATCH] erlang: bump to 26.0.2 --- .../0007-erlang-support-OTP-21-26.patch | 26 +- ...evert-multiline-editing-for-OTP-26.0.patch | 2204 ----------------- support/docker/nerves_system_br/Dockerfile | 2 +- 3 files changed, 14 insertions(+), 2218 deletions(-) delete mode 100644 patches/buildroot/0015-erlang-revert-multiline-editing-for-OTP-26.0.patch diff --git a/patches/buildroot/0007-erlang-support-OTP-21-26.patch b/patches/buildroot/0007-erlang-support-OTP-21-26.patch index 59e31b43..79ad6226 100644 --- a/patches/buildroot/0007-erlang-support-OTP-21-26.patch +++ b/patches/buildroot/0007-erlang-support-OTP-21-26.patch @@ -1,4 +1,4 @@ -From 861f29ed0021688f3dc9b90e56fe4c7f20f3c7f1 Mon Sep 17 00:00:00 2001 +From b1d06bbac0c512cee321dfa7c6d505c8fae0f3fb Mon Sep 17 00:00:00 2001 From: Frank Hunleth Date: Tue, 11 Sep 2018 12:28:41 -0400 Subject: [PATCH] erlang: support OTP 21 - 26 @@ -55,8 +55,8 @@ Signed-off-by: Frank Hunleth create mode 100644 package/erlang/24.3.2/0004-disksup-update-df-call-to-work-with-Busybox.patch create mode 100644 package/erlang/25.3.2/0001-erts-emulator-reorder-inclued-headers-paths.patch create mode 100644 package/erlang/25.3.2/0003-disksup-update-df-call-to-work-with-Busybox.patch - create mode 100644 package/erlang/26.0.1/0001-erts-emulator-reorder-inclued-headers-paths.patch - create mode 100644 package/erlang/26.0.1/0002-disksup-update-df-call-to-work-with-Busybox.patch + create mode 100644 package/erlang/26.0.2/0001-erts-emulator-reorder-inclued-headers-paths.patch + create mode 100644 package/erlang/26.0.2/0002-disksup-update-df-call-to-work-with-Busybox.patch diff --git a/package/erlang/0001-erts-ethread-instruct-libatomic_ops-we-do-require-CA.patch b/package/erlang/0001-erts-ethread-instruct-libatomic_ops-we-do-require-CA.patch deleted file mode 100644 @@ -1085,11 +1085,11 @@ index 0000000000..97f410b18c +-- +2.25.1 + -diff --git a/package/erlang/26.0.1/0001-erts-emulator-reorder-inclued-headers-paths.patch b/package/erlang/26.0.1/0001-erts-emulator-reorder-inclued-headers-paths.patch +diff --git a/package/erlang/26.0.2/0001-erts-emulator-reorder-inclued-headers-paths.patch b/package/erlang/26.0.2/0001-erts-emulator-reorder-inclued-headers-paths.patch new file mode 100644 index 0000000000..660af9d852 --- /dev/null -+++ b/package/erlang/26.0.1/0001-erts-emulator-reorder-inclued-headers-paths.patch ++++ b/package/erlang/26.0.2/0001-erts-emulator-reorder-inclued-headers-paths.patch @@ -0,0 +1,49 @@ +From c57e0592766507ac747badeee40fdb64d0d3a1e9 Mon Sep 17 00:00:00 2001 +From: Romain Naour @@ -1140,11 +1140,11 @@ index 0000000000..660af9d852 +-- +2.34.1 + -diff --git a/package/erlang/26.0.1/0002-disksup-update-df-call-to-work-with-Busybox.patch b/package/erlang/26.0.1/0002-disksup-update-df-call-to-work-with-Busybox.patch +diff --git a/package/erlang/26.0.2/0002-disksup-update-df-call-to-work-with-Busybox.patch b/package/erlang/26.0.2/0002-disksup-update-df-call-to-work-with-Busybox.patch new file mode 100644 index 0000000000..0173bf029b --- /dev/null -+++ b/package/erlang/26.0.1/0002-disksup-update-df-call-to-work-with-Busybox.patch ++++ b/package/erlang/26.0.2/0002-disksup-update-df-call-to-work-with-Busybox.patch @@ -0,0 +1,77 @@ +From da4aecc8a7bd2caae09576d6058bb26022ae297c Mon Sep 17 00:00:00 2001 +From: Frank Hunleth @@ -1277,14 +1277,14 @@ index 15931b5896..a5ee79ba42 100644 bool "install megaco application" help diff --git a/package/erlang/erlang.hash b/package/erlang/erlang.hash -index 338545a0ba..500899d86f 100644 +index 338545a0ba..69b82817a7 100644 --- a/package/erlang/erlang.hash +++ b/package/erlang/erlang.hash @@ -1,5 +1,15 @@ -# From https://github.com/erlang/otp/releases/download/OTP-22.3.4.22/SHA256.txt -sha256 e7f0793e62f8da4f7551dc9c1c0de76c40f19773ba516121fc56315c840f60cc otp_src_22.3.4.22.tar.gz -+# From https://github.com/erlang/otp/releases/download/OTP-26.0.1/SHA256.txt -+sha256 d0c8e17f73e7146294ba39f499de086d0640058ec038c24021722ea612207d92 otp_src_26.0.1.tar.gz ++# From https://github.com/erlang/otp/releases/download/OTP-26.0.2/SHA256.txt ++sha256 47853ea9230643a0a31004433f07a71c1b92d6e0094534f629e3b75dbc62f193 otp_src_26.0.2.tar.gz +# From https://github.com/erlang/otp/releases/download/OTP-25.3.2/SHA256.txt +sha256 aed4e4726cdc587ab820c8379d63e511e46a1b1cc0c59d6a720b51ae625b2510 otp_src_25.3.2.tar.gz +# From https://github.com/erlang/otp/releases/download/OTP-24.3.2/SHA256.txt @@ -1299,7 +1299,7 @@ index 338545a0ba..500899d86f 100644 # Hash for license file sha256 809fa1ed21450f59827d1e9aec720bbc4b687434fa22283c6cb5dd82a47ab9c0 LICENSE.txt diff --git a/package/erlang/erlang.mk b/package/erlang/erlang.mk -index a76bda4437..69a27e1755 100644 +index a76bda4437..5ebfe9dd8f 100644 --- a/package/erlang/erlang.mk +++ b/package/erlang/erlang.mk @@ -4,8 +4,36 @@ @@ -1330,8 +1330,8 @@ index a76bda4437..69a27e1755 100644 +ERLANG_VERSION = 25.3.2 +ERLANG_ERTS_VSN = 13.2.2 +else -+ERLANG_VERSION = 26.0.1 -+ERLANG_ERTS_VSN = 14.0.1 ++ERLANG_VERSION = 26.0.2 ++ERLANG_ERTS_VSN = 14.0.2 +endif +endif +endif diff --git a/patches/buildroot/0015-erlang-revert-multiline-editing-for-OTP-26.0.patch b/patches/buildroot/0015-erlang-revert-multiline-editing-for-OTP-26.0.patch deleted file mode 100644 index d2bb0a25..00000000 --- a/patches/buildroot/0015-erlang-revert-multiline-editing-for-OTP-26.0.patch +++ /dev/null @@ -1,2204 +0,0 @@ -From a1775b23b9ea59f5a99ae0c8a2baf0127c6adea6 Mon Sep 17 00:00:00 2001 -From: Frank Hunleth -Date: Mon, 5 Jun 2023 14:51:35 -0400 -Subject: [PATCH] erlang: revert multiline editing for OTP 26.0 - ---- - .../0003-Revert-multiline-editing.patch | 2185 +++++++++++++++++ - 1 file changed, 2185 insertions(+) - create mode 100644 package/erlang/26.0.1/0003-Revert-multiline-editing.patch - -diff --git a/package/erlang/26.0.1/0003-Revert-multiline-editing.patch b/package/erlang/26.0.1/0003-Revert-multiline-editing.patch -new file mode 100644 -index 0000000000..4fc0415fa6 ---- /dev/null -+++ b/package/erlang/26.0.1/0003-Revert-multiline-editing.patch -@@ -0,0 +1,2185 @@ -+From 19fe6e1ba9b679c0903fb6815800ffa9787050aa Mon Sep 17 00:00:00 2001 -+From: Frank Hunleth -+Date: Mon, 5 Jun 2023 08:57:03 -0400 -+Subject: [PATCH] Revert multiline editing -+ -+This reverts commit 16139b6a35944583b4f1ef05c7698bfe2f771c7a, reversing -+changes made to 8305dd5e2b962ada3403a6fc0c600367afdfec5e. -+--- -+ lib/kernel/src/group.erl | 348 +++++------ -+ lib/kernel/src/prim_tty.erl | 380 ++---------- -+ lib/kernel/src/user_drv.erl | 48 +- -+ lib/kernel/test/interactive_shell_SUITE.erl | 150 +---- -+ lib/stdlib/src/edlin.erl | 602 ++++++++------------ -+ 5 files changed, 487 insertions(+), 1041 deletions(-) -+ -+diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl -+index ca7251d7ec..311c2f3c5e 100644 -+--- a/lib/kernel/src/group.erl -++++ b/lib/kernel/src/group.erl -+@@ -483,56 +483,50 @@ get_chars_n(Prompt, M, F, Xa, Drv, Shell, Buf, Encoding) -> -+ Pbs = prompt_bytes(Prompt, Encoding), -+ case get(echo) of -+ true -> -+- get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf, start, [], Encoding); -++ get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf, start, Encoding); -+ false -> -+ get_chars_n_loop(Pbs, M, F, Xa, Drv, Shell, Buf, start, Encoding) -+ end. -+ -+ get_chars_line(Prompt, M, F, Xa, Drv, Shell, Buf, Encoding) -> -+ Pbs = prompt_bytes(Prompt, Encoding), -+- get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf, start, [], Encoding). -++ get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf, start, Encoding). -+ -+-get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf0, State, LineCont0, Encoding) -> -++get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf0, State, Encoding) -> -+ Result = case get(echo) of -+- true -> -+- get_line(Buf0, Pbs, LineCont0, Drv, Shell, Encoding); -+- false -> -+- %% get_line_echo_off only deals with lists -+- %% and does not need encoding... -+- get_line_echo_off(Buf0, Pbs, Drv, Shell) -+- end, -++ true -> -++ get_line(Buf0, Pbs, Drv, Shell, Encoding); -++ false -> -++ % get_line_echo_off only deals with lists -++ % and does not need encoding... -++ get_line_echo_off(Buf0, Pbs, Drv, Shell) -++ end, -+ case Result of -+- {done,LineCont1,Buf} -> -+- get_chars_apply(Pbs, M, F, Xa, Drv, Shell, Buf, State, LineCont1, Encoding); -+- -+- interrupted -> -+- {error,{error,interrupted},[]}; -+- terminated -> -+- {exit,terminated} -++ {done,Line,Buf} -> -++ get_chars_apply(Pbs, M, F, Xa, Drv, Shell, Buf, State, Line, Encoding); -++ interrupted -> -++ {error,{error,interrupted},[]}; -++ terminated -> -++ {exit,terminated} -+ end. -+ -+-get_chars_apply(Pbs, M, F, Xa, Drv, Shell, Buf, State0, LineCont, Encoding) -> -+- %% multi line support means that we should not keep the state -+- %% but we need to keep it for oldshell mode -+- {State, Line} = case get(echo) of -+- true -> {start, edlin:current_line(LineCont)}; -+- false -> {State0, LineCont} -+- end, -+- case catch M:F(State, cast(Line,get(read_mode), Encoding), Encoding, Xa) of -++get_chars_apply(Pbs, M, F, Xa, Drv, Shell, Buf, State0, Line, Encoding) -> -++ case catch M:F(State0, cast(Line,get(read_mode), Encoding), Encoding, Xa) of -+ {stop,Result,eof} -> -+ {ok,Result,eof}; -+ {stop,Result,Rest} -> -+- _ = case {M,F} of -+- {io_lib, get_until} -> -+- save_line_buffer(string:trim(Line, both)++"\n", get_lines(new_stack(get(line_buffer)))); -+- _ -> -+- skip -+- end, -+- {ok,Result,append(Rest, Buf, Encoding)}; -++ case {M,F} of -++ {io_lib, get_until} -> -++ save_line_buffer(Line, get_lines(new_stack(get(line_buffer)))), -++ {ok,Result,append(Rest, Buf, Encoding)}; -++ _ -> -++ {ok,Result,append(Rest, Buf, Encoding)} -++ end; -+ {'EXIT',_} -> -+ {error,{error,err_func(M, F, Xa)},[]}; -+ State1 -> -+- get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf, State1, LineCont, Encoding) -++ save_line_buffer(Line, get_lines(new_stack(get(line_buffer)))), -++ get_chars_loop(Pbs, M, F, Xa, Drv, Shell, Buf, State1, Encoding) -+ end. -+ -+ get_chars_n_loop(Pbs, M, F, Xa, Drv, Shell, Buf0, State, Encoding) -> -+@@ -564,73 +558,65 @@ err_func(_, F, _) -> -+ %% Get a line with eventual line editing. Handle other io requests -+ %% while getting line. -+ %% Returns: -+-%% {done,LineChars,RestChars} -+-%% interrupted -+-get_line(Chars, Pbs, Cont, Drv, Shell, Encoding) -> -+- {more_chars,Cont1,Rs} = case Cont of -+- [] -> edlin:start(Pbs); -+- _ -> edlin:start(Pbs, Cont) -+- end, -++%% {done,LineChars,RestChars} -++%% interrupted -++ -++get_line(Chars, Pbs, Drv, Shell, Encoding) -> -++ {more_chars,Cont,Rs} = edlin:start(Pbs), -+ send_drv_reqs(Drv, Rs), -+- get_line1(edlin:edit_line(Chars, Cont1), Drv, Shell, new_stack(get(line_buffer)), -+- Encoding). -++ get_line1(edlin:edit_line(Chars, Cont), Drv, Shell, new_stack(get(line_buffer)), -++ Encoding). -+ -+-get_line1({done, Cont, Rest, Rs}, Drv, _Shell, _Ls, _Encoding) -> -++get_line1({done,Line,Rest,Rs}, Drv, _Shell, _Ls, _Encoding) -> -+ send_drv_reqs(Drv, Rs), -+- {done, Cont, Rest}; -++ {done,Line,Rest}; -+ get_line1({undefined,{_A, Mode, Char}, _Cs, Cont, Rs}, Drv, Shell, Ls0, Encoding) -+- when Mode =:= none, Char =:= $\^O; -+- Mode =:= meta, Char =:= $o -> -++ when ((Mode =:= none) and (Char =:= $\^O)) -> -+ send_drv_reqs(Drv, Rs), -+- Buffer = edlin:current_line(Cont), -++ Buffer = edlin:current_chars(Cont), -+ send_drv(Drv, {open_editor, Buffer}), -+ receive -+ {Drv, {editor_data, Cs}} -> -+- send_drv_reqs(Drv, edlin:erase_line()), -++ send_drv_reqs(Drv, edlin:erase_line(Cont)), -+ {more_chars,NewCont,NewRs} = edlin:start(edlin:prompt(Cont)), -+ send_drv_reqs(Drv, NewRs), -+ get_line1(edlin:edit_line(Cs, NewCont), Drv, Shell, Ls0, Encoding) -+ end; -+-%% Move Up, Down in History: Ctrl+P, Ctrl+N -+ get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Shell, Ls0, Encoding) -+- when Mode =:= none, Char =:= $\^P; -+- Mode =:= meta_left_sq_bracket, Char =:= $A -> -++ when ((Mode =:= none) and (Char =:= $\^P)) -++ or ((Mode =:= meta_left_sq_bracket) and (Char =:= $A)) -> -+ send_drv_reqs(Drv, Rs), -+ case up_stack(save_line(Ls0, edlin:current_line(Cont))) of -+- {none,_Ls} -> -+- send_drv(Drv, beep), -+- get_line1(edlin:edit_line(Cs, Cont), Drv, Shell, Ls0, Encoding); -+- {Lcs,Ls} -> -+- send_drv_reqs(Drv, edlin:erase_line()), -+- {more_chars,Ncont,Nrs} = edlin:start(edlin:prompt(Cont)), -+- send_drv_reqs(Drv, Nrs), -+- get_line1(edlin:edit_line1(string:to_graphemes(lists:sublist(Lcs, -+- 1, -+- length(Lcs)-1)), -+- Ncont), -+- Drv, -+- Shell, -+- Ls, Encoding) -++ {none,_Ls} -> -++ send_drv(Drv, beep), -++ get_line1(edlin:edit_line(Cs, Cont), Drv, Shell, Ls0, Encoding); -++ {Lcs,Ls} -> -++ send_drv_reqs(Drv, edlin:erase_line(Cont)), -++ {more_chars,Ncont,Nrs} = edlin:start(edlin:prompt(Cont)), -++ send_drv_reqs(Drv, Nrs), -++ get_line1(edlin:edit_line1(lists:sublist(Lcs, 1, length(Lcs)-1), -++ Ncont), -++ Drv, -++ Shell, -++ Ls, Encoding) -+ end; -+ get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Shell, Ls0, Encoding) -+- when Mode =:= none, Char =:= $\^N; -+- Mode =:= meta_left_sq_bracket, Char =:= $B -> -++ when ((Mode =:= none) and (Char =:= $\^N)) -++ or ((Mode =:= meta_left_sq_bracket) and (Char =:= $B)) -> -+ send_drv_reqs(Drv, Rs), -+ case down_stack(save_line(Ls0, edlin:current_line(Cont))) of -+- {none,_Ls} -> -+- send_drv(Drv, beep), -+- get_line1(edlin:edit_line(Cs, Cont), Drv, Shell, Ls0, Encoding); -+- {Lcs,Ls} -> -+- send_drv_reqs(Drv, edlin:erase_line()), -+- {more_chars,Ncont,Nrs} = edlin:start(edlin:prompt(Cont)), -+- send_drv_reqs(Drv, Nrs), -+- get_line1(edlin:edit_line1(string:to_graphemes(lists:sublist(Lcs, -+- 1, -+- length(Lcs)-1)), -+- Ncont), -+- Drv, -+- Shell, -+- Ls, Encoding) -++ {none,_Ls} -> -++ send_drv(Drv, beep), -++ get_line1(edlin:edit_line(Cs, Cont), Drv, Shell, Ls0, Encoding); -++ {Lcs,Ls} -> -++ send_drv_reqs(Drv, edlin:erase_line(Cont)), -++ {more_chars,Ncont,Nrs} = edlin:start(edlin:prompt(Cont)), -++ send_drv_reqs(Drv, Nrs), -++ get_line1(edlin:edit_line1(lists:sublist(Lcs, 1, length(Lcs)-1), -++ Ncont), -++ Drv, -++ Shell, -++ Ls, Encoding) -+ end; -+ %% ^R = backward search, ^S = forward search. -+ %% Search is tricky to implement and does a lot of back-and-forth -+@@ -643,13 +629,15 @@ get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Shell, Ls0, Encoding) -+ %% the regular ones (none, meta_left_sq_bracket) and handle special -+ %% cases of history search. -+ get_line1({undefined,{_A,Mode,Char},Cs,Cont,Rs}, Drv, Shell, Ls, Encoding) -+- when Mode =:= none, Char =:= $\^R -> -++ when ((Mode =:= none) and (Char =:= $\^R)) -> -+ send_drv_reqs(Drv, Rs), -+ %% drop current line, move to search mode. We store the current -+ %% prompt ('N>') and substitute it with the search prompt. -+- put(search_quit_prompt, Cont), -+- Pbs = prompt_bytes("\033[;1;4msearch:\033[0m ", Encoding), -+- {more_chars,Ncont,_Nrs} = edlin:start(Pbs, search), -++ send_drv_reqs(Drv, edlin:erase_line(Cont)), -++ put(search_quit_prompt, edlin:prompt(Cont)), -++ Pbs = prompt_bytes("(search)`': ", Encoding), -++ {more_chars,Ncont,Nrs} = edlin:start(Pbs, search), -++ send_drv_reqs(Drv, Nrs), -+ get_line1(edlin:edit_line1(Cs, Ncont), Drv, Shell, Ls, Encoding); -+ get_line1({Expand, Before, Cs0, Cont,Rs}, Drv, Shell, Ls0, Encoding) -+ when Expand =:= expand; Expand =:= expand_full -> -+@@ -696,98 +684,66 @@ get_line1({Expand, Before, Cs0, Cont,Rs}, Drv, Shell, Ls0, Encoding) -+ _ -> -+ %% If there are more results than fit on -+ %% screen we expand above -+- send_drv_reqs(Drv, [{put_chars_keep_state, unicode, NlMatchStr},redraw_prompt]), -++ send_drv(Drv, {put_chars, unicode, NlMatchStr}), -+ [$\e, $l | Cs1] -+ end -+ end; -+ false -> -+- send_drv(Drv, {put_chars_keep_state, unicode, NlMatchStr}), -++ send_drv(Drv, {put_chars, unicode, NlMatchStr}), -+ [$\e, $l | Cs1] -+ end -+ end, -+ get_line1(edlin:edit_line(Cs, Cont), Drv, Shell, Ls0, Encoding); -+-get_line1({undefined, {_, search_quit, _}, _Cs, _Cont={line, P, Line, none}, Rs}, Drv, Shell, Ls, Encoding) -> -+- get_line1({more_chars, {line, P, Line, search_quit}, Rs}, Drv, Shell, Ls, Encoding); -+ get_line1({undefined,_Char,Cs,Cont,Rs}, Drv, Shell, Ls, Encoding) -> -+ send_drv_reqs(Drv, Rs), -+ send_drv(Drv, beep), -+ get_line1(edlin:edit_line(Cs, Cont), Drv, Shell, Ls, Encoding); -+ %% The search item was found and accepted (new line entered on the exact -+ %% result found) -+-get_line1({_What,{line,_,_Drv,search_found},Rs}, Drv, Shell, Ls0, Encoding) -> -+- SearchResult = get(search_result), -+- LineCont = case SearchResult of -+- [] -> {[],{[],[]},[]}; -+- _ -> [Last| LB] = lists:reverse(SearchResult), -+- {LB, {lists:reverse(Last),[]},[]} -+- end, -+- Prompt = edlin:prompt(get(search_quit_prompt)), -+- send_drv_reqs(Drv, Rs), -+- send_drv_reqs(Drv, edlin:erase_line()), -+- send_drv_reqs(Drv, edlin:redraw_line({line, Prompt, LineCont, none})), -+- put(search_result, []), -+- %% TODO, do even need to save it, won't it be saved by handling {done...}? -+- Ls = save_line(new_stack(get_lines(Ls0)), edlin:current_line({line, edlin:prompt(get(search_quit_prompt)), LineCont, none})), -+- get_line1({done, LineCont, "\n", Rs}, Drv, Shell, Ls, Encoding); -++get_line1({_What,Cont={line,_Prompt,_Chars,search_found},Rs}, Drv, Shell, Ls0, Encoding) -> -++ Line = edlin:current_line(Cont), -++ %% this may create duplicate entries. -++ Ls = save_line(new_stack(get_lines(Ls0)), Line), -++ get_line1({done, Line, "", Rs}, Drv, Shell, Ls, Encoding); -+ %% The search mode has been exited, but the user wants to remain in line -+ %% editing mode wherever that was, but editing the search result. -+-get_line1({What,{line,_,_,search_quit},Rs}, Drv, Shell, Ls, Encoding) -> -++get_line1({What,Cont={line,_Prompt,_Chars,search_quit},Rs}, Drv, Shell, Ls, Encoding) -> -++ Line = edlin:current_chars(Cont), -+ %% Load back the old prompt with the correct line number. -+- case edlin:prompt(get(search_quit_prompt)) of -+- Prompt -> % redraw the line and keep going with the same stack position -+- SearchResult = get(search_result), -+- L = case SearchResult of -+- [] -> {[],{[],[]},[]}; -+- _ -> [Last|LB] = lists:reverse(SearchResult), -+- {LB, {lists:reverse(Last), []}, []} -+- end, -+- NCont = {line,Prompt,L,none}, -+- put(search_result, []), -+- send_drv_reqs(Drv, [delete_line|Rs]), -+- send_drv_reqs(Drv, edlin:redraw_line(NCont)), -+- get_line1({What, NCont ,[]}, Drv, Shell, pad_stack(Ls), Encoding) -++ case get(search_quit_prompt) of -++ undefined -> % should not happen. Fallback. -++ LsFallback = save_line(new_stack(get_lines(Ls)), Line), -++ get_line1({done, "\n", Line, Rs}, Drv, Shell, LsFallback, Encoding); -++ Prompt -> % redraw the line and keep going with the same stack position -++ NCont = {line,Prompt,{lists:reverse(Line),[]},none}, -++ send_drv_reqs(Drv, Rs), -++ send_drv_reqs(Drv, edlin:erase_line(Cont)), -++ send_drv_reqs(Drv, edlin:redraw_line(NCont)), -++ get_line1({What, NCont ,[]}, Drv, Shell, pad_stack(Ls), Encoding) -+ end; -+-get_line1({What,_Cont={line,_,_,search_cancel},Rs}, Drv, Shell, Ls, Encoding) -> -+- NCont = get(search_quit_prompt), -+- put(search_result, []), -+- send_drv_reqs(Drv, [delete_line|Rs]), -+- send_drv_reqs(Drv, edlin:redraw_line(NCont)), -+- get_line1({What, NCont, []}, Drv, Shell, Ls, Encoding); -+ %% Search mode is entered. -+-get_line1({What,{line,Prompt,{_,{RevCmd0,_},_},search},_Rs}, -+- Drv, Shell, Ls0, Encoding) -> -++get_line1({What,{line,Prompt,{RevCmd0,_Aft},search},Rs}, -++ Drv, Shell, Ls0, Encoding) -> -++ send_drv_reqs(Drv, Rs), -+ %% Figure out search direction. ^S and ^R are returned through edlin -+ %% whenever we received a search while being already in search mode. -+ {Search, Ls1, RevCmd} = case RevCmd0 of -+- [$\^S|RevCmd1] -> -+- {fun search_down_stack/2, Ls0, RevCmd1}; -+- [$\^R|RevCmd1] -> -+- {fun search_up_stack/2, Ls0, RevCmd1}; -+- _ -> % new search, rewind stack for a proper search. -+- {fun search_up_stack/2, new_stack(get_lines(Ls0)), RevCmd0} -+- end, -++ [$\^S|RevCmd1] -> -++ {fun search_down_stack/2, Ls0, RevCmd1}; -++ [$\^R|RevCmd1] -> -++ {fun search_up_stack/2, Ls0, RevCmd1}; -++ _ -> % new search, rewind stack for a proper search. -++ {fun search_up_stack/2, new_stack(get_lines(Ls0)), RevCmd0} -++ end, -+ Cmd = lists:reverse(RevCmd), -+ {Ls, NewStack} = case Search(Ls1, Cmd) of -+- {none, Ls2} -> -+- send_drv(Drv, beep), -+- put(search_result, []), -+- send_drv(Drv, delete_line), -+- send_drv(Drv, {put_chars, unicode, unicode:characters_to_binary(Prompt++Cmd)}), -+- {Ls2, {[],{RevCmd, []},[]}}; -+- {Line, Ls2} -> % found. Complete the output edlin couldn't have done. -+- Lines = string:split(string:to_graphemes(Line), "\n", all), -+- Output = if length(Lines) > 5 -> -+- [A,B,C,D,E|_]=Lines, -+- (["\n " ++ Line1 || Line1 <- [A,B,C,D,E]] ++ -+- [io_lib:format("~n ... (~w lines omitted)",[length(Lines)-5])]); -+- true -> ["\n " ++ Line1 || Line1 <- Lines] -+- end, -+- put(search_result, Lines), -+- send_drv(Drv, delete_line), -+- send_drv(Drv, {put_chars, unicode, unicode:characters_to_binary(Prompt++Cmd)}), -+- send_drv(Drv, {put_expand_no_trim, unicode, unicode:characters_to_binary(Output)}), -+- {Ls2, {[],{RevCmd, []},[]}} -+- end, -++ {none, Ls2} -> -++ send_drv(Drv, beep), -++ {Ls2, {RevCmd, "': "}}; -++ {Line, Ls2} -> % found. Complete the output edlin couldn't have done. -++ send_drv_reqs(Drv, [{put_chars, Encoding, Line}]), -++ {Ls2, {RevCmd, "': "++Line}} -++ end, -+ Cont = {line,Prompt,NewStack,search}, -+ more_data(What, Cont, Drv, Shell, Ls, Encoding); -+ get_line1({What,Cont0,Rs}, Drv, Shell, Ls, Encoding) -> -+@@ -796,32 +752,29 @@ get_line1({What,Cont0,Rs}, Drv, Shell, Ls, Encoding) -> -+ -+ more_data(What, Cont0, Drv, Shell, Ls, Encoding) -> -+ receive -+- {Drv, activate} -> -+- send_drv_reqs(Drv, edlin:redraw_line(Cont0)), -+- more_data(What, Cont0, Drv, Shell, Ls, Encoding); -+- {Drv,{data,Cs}} -> -+- get_line1(edlin:edit_line(Cs, Cont0), Drv, Shell, Ls, Encoding); -+- {Drv,eof} -> -+- get_line1(edlin:edit_line(eof, Cont0), Drv, Shell, Ls, Encoding); -+- {io_request,From,ReplyAs,Req} when is_pid(From) -> -+- {more_chars,Cont,_More} = edlin:edit_line([], Cont0), -+- send_drv_reqs(Drv, edlin:erase_line()), -+- io_request(Req, From, ReplyAs, Drv, Shell, []), %WRONG!!! -+- send_drv_reqs(Drv, edlin:redraw_line(Cont)), -+- get_line1({more_chars,Cont,[]}, Drv, Shell, Ls, Encoding); -++ {Drv,{data,Cs}} -> -++ get_line1(edlin:edit_line(Cs, Cont0), Drv, Shell, Ls, Encoding); -++ {Drv,eof} -> -++ get_line1(edlin:edit_line(eof, Cont0), Drv, Shell, Ls, Encoding); -++ {io_request,From,ReplyAs,Req} when is_pid(From) -> -++ {more_chars,Cont,_More} = edlin:edit_line([], Cont0), -++ send_drv_reqs(Drv, edlin:erase_line(Cont)), -++ io_request(Req, From, ReplyAs, Drv, Shell, []), %WRONG!!! -++ send_drv_reqs(Drv, edlin:redraw_line(Cont)), -++ get_line1({more_chars,Cont,[]}, Drv, Shell, Ls, Encoding); -+ {reply,{From,ReplyAs},Reply} -> -+ %% We take care of replies from puts here as well -+ io_reply(From, ReplyAs, Reply), -+ more_data(What, Cont0, Drv, Shell, Ls, Encoding); -+- {'EXIT',Drv,interrupt} -> -+- interrupted; -+- {'EXIT',Drv,_} -> -+- terminated; -+- {'EXIT',Shell,R} -> -+- exit(R) -++ {'EXIT',Drv,interrupt} -> -++ interrupted; -++ {'EXIT',Drv,_} -> -++ terminated; -++ {'EXIT',Shell,R} -> -++ exit(R) -+ after -+- get_line_timeout(What)-> -+- get_line1(edlin:edit_line([], Cont0), Drv, Shell, Ls, Encoding) -++ get_line_timeout(What)-> -++ get_line1(edlin:edit_line([], Cont0), Drv, Shell, Ls, Encoding) -+ end. -+ -+ get_line_echo_off(Chars, Pbs, Drv, Shell) -> -+@@ -861,21 +814,21 @@ get_chars_echo_off1(Drv, Shell) -> -+ receive -+ {Drv, {data, Cs}} -> -+ Cs; -+- {Drv, eof} -> -++ {Drv, eof} -> -+ eof; -+- {io_request,From,ReplyAs,Req} when is_pid(From) -> -+- io_request(Req, From, ReplyAs, Drv, Shell, []), -+- get_chars_echo_off1(Drv, Shell); -++ {io_request,From,ReplyAs,Req} when is_pid(From) -> -++ io_request(Req, From, ReplyAs, Drv, Shell, []), -++ get_chars_echo_off1(Drv, Shell); -+ {reply,{From,ReplyAs},Reply} when From =/= undefined -> -+ %% We take care of replies from puts here as well -+ io_reply(From, ReplyAs, Reply), -+ get_chars_echo_off1(Drv, Shell); -+- {'EXIT',Drv,interrupt} -> -+- interrupted; -+- {'EXIT',Drv,_} -> -+- terminated; -+- {'EXIT',Shell,R} -> -+- exit(R) -++ {'EXIT',Drv,interrupt} -> -++ interrupted; -++ {'EXIT',Drv,_} -> -++ terminated; -++ {'EXIT',Shell,R} -> -++ exit(R) -+ end. -+ -+ %% We support line editing for the ICANON mode except the following -+@@ -956,8 +909,8 @@ get_all_lines({stack, U, {}, []}) -> -+ U; -+ get_all_lines({stack, U, {}, D}) -> -+ case lists:reverse(D, U) of -+- ["\n"|Lines] -> Lines; -+- Lines -> Lines -++ ["\n"|Lines] -> Lines; -++ Lines -> Lines -+ end; -+ get_all_lines({stack, U, L, D}) -> -+ get_all_lines({stack, U, {}, [L|D]}). -+@@ -981,22 +934,22 @@ save_line_buffer(Lines) -> -+ -+ search_up_stack(Stack, Substr) -> -+ case up_stack(Stack) of -+- {none,NewStack} -> {none,NewStack}; -+- {L, NewStack} -> -++ {none,NewStack} -> {none,NewStack}; -++ {L, NewStack} -> -+ case string:find(L, Substr) of -+ nomatch -> search_up_stack(NewStack, Substr); -+ _ -> {string:trim(L, trailing, "$\n"), NewStack} -+- end -++ end -+ end. -+ -+ search_down_stack(Stack, Substr) -> -+ case down_stack(Stack) of -+- {none,NewStack} -> {none,NewStack}; -+- {L, NewStack} -> -+- case string:find(L, Substr) of -+- nomatch -> search_down_stack(NewStack, Substr); -+- _ -> {string:trim(L, trailing, "$\n"), NewStack} -+- end -++ {none,NewStack} -> {none,NewStack}; -++ {L, NewStack} -> -++ case string:find(L, Substr) of -++ nomatch -> search_down_stack(NewStack, Substr); -++ _ -> {string:trim(L, trailing, "$\n"), NewStack} -++ end -+ end. -+ -+ -+@@ -1010,15 +963,16 @@ get_password1({Chars,[]}, Drv, Shell) -> -+ {Drv,{data,Cs}} -> -+ get_password1(edit_password(Cs,Chars),Drv,Shell); -+ {io_request,From,ReplyAs,Req} when is_pid(From) -> -++ %send_drv_reqs(Drv, [{delete_chars, -length(Pbs)}]), -+ io_request(Req, From, ReplyAs, Drv, Shell, []), %WRONG!!! -+ %% I guess the reason the above line is wrong is that Buf is -+ %% set to []. But do we expect anything but plain output? -+ -+- get_password1({Chars, []}, Drv, Shell); -++ get_password1({Chars, []}, Drv, Shell); -+ {reply,{From,ReplyAs},Reply} -> -+ %% We take care of replies from puts here as well -+ io_reply(From, ReplyAs, Reply), -+- get_password1({Chars, []}, Drv, Shell); -++ get_password1({Chars, []},Drv, Shell); -+ {'EXIT',Drv,interrupt} -> -+ interrupted; -+ {'EXIT',Drv,_} -> -+diff --git a/lib/kernel/src/prim_tty.erl b/lib/kernel/src/prim_tty.erl -+index a03e746cc9..4ef10c752d 100644 -+--- a/lib/kernel/src/prim_tty.erl -++++ b/lib/kernel/src/prim_tty.erl -+@@ -136,8 +136,6 @@ -+ writer, -+ options, -+ unicode, -+- lines_before = [], %% All lines before the current line in reverse order -+- lines_after = [], %% All lines after the current line. -+ buffer_before = [], %% Current line before cursor in reverse -+ buffer_after = [], %% Current line after cursor not in reverse -+ buffer_expand, %% Characters in expand buffer -+@@ -168,20 +166,10 @@ -+ -type request() :: -+ {putc_raw, binary()} | -+ {putc, unicode:unicode_binary()} | -+- {putc_keep_state, unicode:unicode_binary()} | -+ {expand, unicode:unicode_binary()} | -+- {expand_with_trim, unicode:unicode_binary()} | -+ {insert, unicode:unicode_binary()} | -+ {delete, integer()} | -+- delete_after_cursor | -+- delete_line | -+- redraw_prompt | -+- {redraw_prompt, string(), string(), tuple()} | -+- redraw_prompt_pre_deleted | -+- new_prompt | -+ {move, integer()} | -+- {move_line, integer()} | -+- {move_combo, integer(), integer(), integer()} | -+ clear | -+ beep. -+ -opaque state() :: #state{}. -+@@ -288,9 +276,9 @@ init(State, {unix,_}) -> -+ %% See https://www.gnu.org/software/termutils/manual/termcap-1.3/html_mono/termcap.html#SEC23 -+ %% for a list of all possible termcap capabilities -+ Clear = case tgetstr("clear") of -+- {ok, C} -> C; -+- false -> (#state{})#state.clear -+- end, -++ {ok, C} -> C; -++ false -> (#state{})#state.clear -++ end, -+ Cols = case tgetnum("co") of -+ {ok, Cs} -> Cs; -+ _ -> (#state{})#state.cols -+@@ -333,7 +321,7 @@ init(State, {unix,_}) -> -+ {ok, <<"\e[6n">> = U7} -> -+ %% User 7 should contain the codes for getting -+ %% cursor position. -+- %% User 6 should contain how to parse the reply -++ % User 6 should contain how to parse the reply -+ {ok, <<"\e[%i%d;%dR">>} = tgetstr("u6"), -+ <<"\e[6n">> = U7; -+ false -> (#state{})#state.position -+@@ -547,62 +535,26 @@ handle_request(State = #state{ options = #{ tty := false } }, Request) -> -+ _Ignore -> -+ {<<>>, State} -+ end; -+-handle_request(State, {redraw_prompt, Pbs, Pbs2, {LB, {Bef, Aft}, LA}}) -> -+- {ClearLine, Cleared} = handle_request(State, delete_line), -+- CL = lists:reverse(Bef,Aft), -+- Text = Pbs ++ lists:flatten(lists:join("\n"++Pbs2, lists:reverse(LB)++[CL|LA])), -+- Moves = if LA /= [] -> -+- [Last|_] = lists:reverse(LA), -+- {move_combo, -logical(Last), length(LA), logical(Bef)}; -+- true -> -+- {move, -logical(Aft)} -+- end, -+- {_, InsertedText} = handle_request(Cleared, {insert, unicode:characters_to_binary(Text)}), -+- {_, Moved} = handle_request(InsertedText, Moves), -+- {Redraw, NewState} = handle_request(Moved, redraw_prompt_pre_deleted), -+- {[ClearLine, Redraw], NewState}; -+-handle_request(State, redraw_prompt) -> -+- {ClearLine, _} = handle_request(State, delete_line), -+- {Redraw, NewState} = handle_request(State, redraw_prompt_pre_deleted), -+- {[ClearLine, Redraw], NewState}; -+-handle_request(State = #state{unicode = U, cols = W}, redraw_prompt_pre_deleted) -> -+- {Movement, TextInView} = in_view(State), -+- {_, NewPrompt} = handle_request(State, new_prompt), -+- {Redraw, RedrawState} = insert_buf(NewPrompt#state{xn = false}, unicode:characters_to_binary(TextInView)), -+- {Output, _} = case State#state.buffer_expand of -+- undefined -> -+- {[encode(Redraw, U), xnfix(RedrawState, RedrawState#state.buffer_before), Movement], RedrawState}; -+- BufferExpand -> -+- BBCols = cols(State#state.buffer_before, U), -+- End = BBCols + cols(State#state.buffer_after,U), -+- {ExpandBuffer, NewState} = insert_buf(RedrawState#state{ buffer_expand = [] }, iolist_to_binary(BufferExpand)), -+- BECols = cols(W, End, NewState#state.buffer_expand, U), -+- MoveToEnd = move_cursor(RedrawState, BECols, End), -+- {[encode(Redraw,U),encode(ExpandBuffer, U), MoveToEnd, Movement], RedrawState} -+- -+- end, -+- {Output, State}; -+ %% Clear the expand buffer after the cursor when we handle any request. -+-handle_request(State = #state{ buffer_expand = Expand, unicode = U}, Request) -++handle_request(State = #state{ buffer_expand = Expand, unicode = U }, Request) -+ when Expand =/= undefined -> -+- {Redraw, NoExpandState} = handle_request(State#state{ buffer_expand = undefined }, redraw_prompt), -+- {Output, NewState} = handle_request(NoExpandState#state{ buffer_expand = undefined }, Request), -+- {[encode(Redraw, U), encode(Output, U)], NewState}; -+-handle_request(State, new_prompt) -> -+- {"", State#state{buffer_before = [], -+- buffer_after = [], -+- lines_before = [], -+- lines_after = []}}; -++ BBCols = cols(State#state.buffer_before, U), -++ BACols = cols(State#state.buffer_after, U), -++ ClearExpand = [move_cursor(State, BBCols, BBCols + BACols), -++ State#state.delete_after_cursor, -++ move_cursor(State, BBCols + BACols, BBCols)], -++ {Output, NewState} = handle_request(State#state{ buffer_expand = undefined }, Request), -++ {[ClearExpand, encode(Output, U)], NewState}; -+ %% Print characters in the expandbuffer after the cursor -+-handle_request(State, {expand, Expand}) -> -+- handle_request(State#state{buffer_expand = Expand}, redraw_prompt); -+-handle_request(State, {expand_with_trim, Binary}) -> -+- handle_request(State, -+- {expand, iolist_to_binary(["\r\n",string:trim(Binary, both)])}); -+-%% putc_keep_state prints Binary and keeps the current prompt unchanged -+-handle_request(State = #state{ unicode = U }, {putc_keep_state, Binary}) -> -+- {PutBuffer, _NewState} = insert_buf(State, Binary), -+- {encode(PutBuffer, U), State}; -++handle_request(State = #state{ unicode = U }, {expand, Binary}) -> -++ BBCols = cols(State#state.buffer_before, U), -++ BACols = cols(State#state.buffer_after, U), -++ Expand = iolist_to_binary(["\r\n",string:trim(Binary, both)]), -++ MoveToEnd = move_cursor(State, BBCols, BBCols + BACols), -++ {ExpandBuffer, NewState} = insert_buf(State#state{ buffer_expand = [] }, Expand), -++ BECols = cols(NewState#state.cols, BBCols + BACols, NewState#state.buffer_expand, U), -++ MoveToOrig = move_cursor(State, BECols, BBCols), -++ {[MoveToEnd, encode(ExpandBuffer, U), MoveToOrig], NewState}; -+ %% putc prints Binary and overwrites any existing characters -+ handle_request(State = #state{ unicode = U }, {putc, Binary}) -> -+ %% Todo should handle invalid unicode? -+@@ -611,136 +563,36 @@ handle_request(State = #state{ unicode = U }, {putc, Binary}) -> -+ {encode(PutBuffer, U), NewState}; -+ true -> -+ %% Delete any overwritten characters after current the cursor -+- OldLength = logical(State#state.buffer_before) + lists:sum([logical(L) || L <- State#state.lines_before]), -+- NewLength = logical(NewState#state.buffer_before) + lists:sum([logical(L) || L <- NewState#state.lines_before]), -++ OldLength = logical(State#state.buffer_before), -++ NewLength = logical(NewState#state.buffer_before), -+ {_, _, _, NewBA} = split(NewLength - OldLength, NewState#state.buffer_after, U), -+ {encode(PutBuffer, U), NewState#state{ buffer_after = NewBA }} -+ end; -+ handle_request(State, {putc_raw, Binary}) -> -+ handle_request(State, {putc, unicode:characters_to_binary(Binary, latin1)}); -+-handle_request(State = #state{}, delete_after_cursor) -> -+- {[State#state.delete_after_cursor], -+- State#state{buffer_after = [], -+- lines_after = []}}; -+-handle_request(State = #state{unicode = U, cols = W, buffer_before = Bef, -+- lines_before = LinesBefore, -+- lines_after = _LinesAfter}, delete_line) -> -+- MoveToBeg = move_cursor(State, cols_multiline(Bef, LinesBefore, W, U), 0), -+- {[MoveToBeg, State#state.delete_after_cursor], -+- State#state{buffer_before = [], -+- buffer_after = [], -+- lines_before = [], -+- lines_after = []}}; -+-handle_request(State = #state{ unicode = U, cols = W }, {delete, N}) when N > 0 -> -++handle_request(State = #state{ unicode = U }, {delete, N}) when N > 0 -> -+ {_DelNum, DelCols, _, NewBA} = split(N, State#state.buffer_after, U), -+ BBCols = cols(State#state.buffer_before, U), -+- BACols = cols(State#state.buffer_after, U), -+ NewBACols = cols(NewBA, U), -+- Output = [encode(NewBA, U), -+- lists:duplicate(DelCols, $\s), -+- xnfix(State, BBCols + NewBACols + DelCols), -+- move_cursor(State, -+- BBCols + NewBACols + DelCols, -+- BBCols)], -+- NewState0 = State#state{ buffer_after = NewBA }, -+- if State#state.lines_after =/= [], (BBCols + BACols-N) rem W =:= 0 -> -+- {Delete, _} = handle_request(State, delete_line), -+- {Redraw, NewState1} = handle_request(NewState0, redraw_prompt_pre_deleted), -+- {[Delete, Redraw], NewState1}; -+- true -> -+- {Output, NewState0} -+- end; -+-handle_request(State = #state{ unicode = U, cols = W }, {delete, N}) when N < 0 -> -++ {[encode(NewBA, U), -++ lists:duplicate(DelCols, $\s), -++ xnfix(State, BBCols + NewBACols + DelCols), -++ move_cursor(State, -++ BBCols + NewBACols + DelCols, -++ BBCols)], -++ State#state{ buffer_after = NewBA }}; -++handle_request(State = #state{ unicode = U }, {delete, N}) when N < 0 -> -+ {_DelNum, DelCols, _, NewBB} = split(-N, State#state.buffer_before, U), -+- BBCols = cols(State#state.buffer_before, U), -+- BACols = cols(State#state.buffer_after, U), -+ NewBBCols = cols(NewBB, U), -+- Output = [move_cursor(State, NewBBCols + DelCols, NewBBCols), -+- encode(State#state.buffer_after,U), -+- lists:duplicate(DelCols, $\s), -+- xnfix(State, NewBBCols + BACols + DelCols), -+- move_cursor(State, NewBBCols + BACols + DelCols, NewBBCols)], -+- NewState0 = State#state{ buffer_before = NewBB }, -+- if State#state.lines_after =/= [], (BBCols+BACols+N) rem W =:= 0 -> -+- {Delete, _} = handle_request(State, delete_line), -+- {Redraw, NewState1} = handle_request(NewState0, redraw_prompt_pre_deleted), -+- {[Delete, Redraw], NewState1}; -+- true -> -+- {Output, NewState0} -+- end; -++ BACols = cols(State#state.buffer_after, U), -++ {[move_cursor(State, NewBBCols + DelCols, NewBBCols), -++ encode(State#state.buffer_after,U), -++ lists:duplicate(DelCols, $\s), -++ xnfix(State, NewBBCols + BACols + DelCols), -++ move_cursor(State, NewBBCols + BACols + DelCols, NewBBCols)], -++ State#state{ buffer_before = NewBB } }; -+ handle_request(State, {delete, 0}) -> -+ {"",State}; -+-%% {move_combo, before_line_movement, line_movement, after_line_movement} -+-%% Many of the move operations comes in threes, this is a helper to make -+-%% movement a little bit easier. We move to the beginning of -+-%% the line before switching line and then move to the right column on -+-%% the next line. -+-handle_request(State, {move_combo, V1, L, V2}) -> -+- {Moves1, NewState1} = handle_request(State, {move, V1}), -+- {Moves2, NewState2} = handle_request(NewState1, {move_line, L}), -+- {Moves3, NewState3} = handle_request(NewState2, {move, V2}), -+- {Moves1 ++ Moves2 ++ Moves3, NewState3}; -+-handle_request(State = #state{ cols = W, -+- rows = R, -+- unicode = U, -+- buffer_before = Bef, -+- buffer_after = Aft, -+- lines_before = LinesBefore, -+- lines_after = LinesAfter}, -+- {move_line, L}) when L < 0, length(LinesBefore) >= -L -> -+- {LinesJumped, [B|NewLinesBefore]} = lists:split(-L -1, LinesBefore), -+- PrevLinesCols = cols_multiline([B|LinesJumped], W, U), -+- N_Cols = min(cols(Bef, U), cols(B, U)), -+- {_, _, NewBB, NewBA} = split_cols(N_Cols, B, U), -+- Moves = move_cursor(State, PrevLinesCols, 0), -+- CL = lists:reverse(Bef,Aft), -+- NewLinesAfter = lists:reverse([CL|LinesJumped], LinesAfter), -+- NewState = State#state{buffer_before = NewBB, -+- buffer_after = NewBA, -+- lines_before = NewLinesBefore, -+- lines_after = NewLinesAfter}, -+- RowsInView = cols_multiline([B,CL|LinesBefore], W, U) div W, -+- Output = if -+- %% When we move up and the view is "full" -+- RowsInView >= R -> -+- {Movement, TextInView} = in_view(NewState), -+- {ClearLine, Cleared} = handle_request(State, delete_line), -+- {Redraw, _} = handle_request(Cleared, {insert, unicode:characters_to_binary(TextInView)}), -+- [ClearLine, Redraw, Movement]; -+- true -> Moves -+- end, -+- {Output, NewState}; -+-handle_request(State = #state{ cols = W, -+- rows = R, -+- unicode = U, -+- buffer_before = Bef, -+- buffer_after = Aft, -+- lines_before = LinesBefore, -+- lines_after = LinesAfter}, -+- {move_line, L}) when L > 0, length(LinesAfter) >= L -> -+- {LinesJumped, [A|NewLinesAfter]} = lists:split(L - 1, LinesAfter), -+- NextLinesCols = cols_multiline([(Bef++Aft)|LinesJumped], W, U), -+- N_Cols = min(cols(Bef, U), cols(A, U)), -+- {_, _, NewBB, NewBA} = split_cols(N_Cols, A, U), -+- Moves = move_cursor(State, 0, NextLinesCols), -+- CL = lists:reverse(Bef, Aft), -+- NewLinesBefore = lists:reverse([CL|LinesJumped],LinesBefore), -+- NewState = State#state{buffer_before = NewBB, -+- buffer_after = NewBA, -+- lines_before = NewLinesBefore, -+- lines_after = NewLinesAfter}, -+- RowsInView = cols_multiline([A|NewLinesBefore], W, U) div W, -+- Output = if -+- RowsInView >= R -> -+- {Movement, TextInView} = in_view(NewState), -+- {ClearLine, Cleared} = handle_request(State, delete_line), -+- {Redraw, _} = handle_request(Cleared, {insert, unicode:characters_to_binary(TextInView)}), -+- [ClearLine, Redraw, Movement]; -+- true -> Moves -+- end, -+- {Output, NewState}; -+-handle_request(State, {move_line, _}) -> -+- {"", State}; -+ handle_request(State = #state{ unicode = U }, {move, N}) when N < 0 -> -+ {_DelNum, DelCols, NewBA, NewBB} = split(-N, State#state.buffer_before, U), -+ NewBBCols = cols(NewBB, U), -+@@ -750,57 +602,29 @@ handle_request(State = #state{ unicode = U }, {move, N}) when N < 0 -> -+ handle_request(State = #state{ unicode = U }, {move, N}) when N > 0 -> -+ {_DelNum, DelCols, NewBB, NewBA} = split(N, State#state.buffer_after, U), -+ BBCols = cols(State#state.buffer_before, U), -+- Moves = move_cursor(State, BBCols, BBCols + DelCols), -+- {Moves, State#state{ buffer_after = NewBA, -+- buffer_before = NewBB ++ State#state.buffer_before} }; -++ {move_cursor(State, BBCols, BBCols + DelCols), -++ State#state{ buffer_after = NewBA, -++ buffer_before = NewBB ++ State#state.buffer_before} }; -+ handle_request(State, {move, 0}) -> -+ {"",State}; -+-handle_request(State = #state{cols = W, xn = OrigXn, unicode = U,lines_after = LinesAfter}, {insert, Chars}) -> -++handle_request(State = #state{ xn = OrigXn, unicode = U }, {insert, Chars}) -> -+ {InsertBuffer, NewState0} = insert_buf(State#state{ xn = false }, Chars), -+- NewState1 = NewState0#state{ xn = OrigXn }, -+- NewBBCols = cols(NewState1#state.buffer_before, U), -+- NewBACols = cols(NewState1#state.buffer_after, U), -+- Output = [ encode(InsertBuffer, U), -+- encode(NewState1#state.buffer_after, U), -+- xnfix(State, NewBBCols + NewBACols), -+- move_cursor(State, NewBBCols + NewBACols, NewBBCols) ], -+- if LinesAfter =:= []; (NewBBCols + NewBACols) rem W =:= 0 -> -+- {Output, NewState1}; -+- true -> -+- {Delete, _} = handle_request(State, delete_line), -+- {Redraw, NewState2} = handle_request(NewState1, redraw_prompt_pre_deleted), -+- {[Delete, Redraw,""], NewState2} -+- end; -++ NewState = NewState0#state{ xn = OrigXn }, -++ BBCols = cols(NewState#state.buffer_before, U), -++ BACols = cols(NewState#state.buffer_after, U), -++ {[ encode(InsertBuffer, U), -++ encode(NewState#state.buffer_after, U), -++ xnfix(State, BBCols + BACols), -++ move_cursor(State, BBCols + BACols, BBCols) ], -++ NewState}; -+ handle_request(State, beep) -> -+ {<<7>>, State}; -+ handle_request(State, clear) -> -+- {State#state.clear, State#state{buffer_before = [], -+- buffer_after = [], -+- lines_before = [], -+- lines_after = []}}; -++ {State#state.clear, State}; -+ handle_request(State, Req) -> -+ erlang:display({unhandled_request, Req}), -+ {"", State}. -+ -+-%% Split the buffer after N cols -+-%% Returns the number of characters deleted, and the column length (N) -+-%% of those characters. -+-split_cols(N_Cols, Buff, Unicode) -> -+- split_cols(N_Cols, Buff, [], 0, 0, Unicode). -+-split_cols(N, [SkipChars | T], Acc, Cnt, Cols, Unicode) when is_binary(SkipChars) -> -+- split_cols(N, T, [SkipChars | Acc], Cnt, Cols, Unicode); -+-split_cols(0, Buff, Acc, Chars, Cols, _Unicode) -> -+- {Chars, Cols, Acc, Buff}; -+-split_cols(N, _Buff, _Acc, _Chars, _Cols, _Unicode) when N < 0 -> -+- error; -+-split_cols(_N, [], Acc, Chars, Cols, _Unicode) -> -+- {Chars, Cols, Acc, []}; -+-split_cols(N, [Char | T], Acc, Cnt, Cols, Unicode) when is_integer(Char) -> -+- split_cols(N - npwcwidth(Char), T, [Char | Acc], Cnt + 1, Cols + npwcwidth(Char, Unicode), Unicode); -+-split_cols(N, [Chars | T], Acc, Cnt, Cols, Unicode) when is_list(Chars) -> -+- split_cols(N - length(Chars), T, [Chars | Acc], -+- Cnt + length(Chars), Cols + cols(Chars, Unicode), Unicode). -+- -+ %% Split the buffer after N logical characters returning -+ %% the number of real characters deleted and the column length -+ %% of those characters -+@@ -811,7 +635,7 @@ split(0, Buff, Acc, Chars, Cols, _Unicode) -> -+ ?dbg({?FUNCTION_NAME, {Chars, Cols, Acc, Buff}}), -+ {Chars, Cols, Acc, Buff}; -+ split(N, _Buff, _Acc, _Chars, _Cols, _Unicode) when N < 0 -> -+- error; -++ ok = N; -+ split(_N, [], Acc, Chars, Cols, _Unicode) -> -+ {Chars, Cols, Acc, []}; -+ split(N, [Char | T], Acc, Cnt, Cols, Unicode) when is_integer(Char) -> -+@@ -861,77 +685,6 @@ move(left, #state{ left = Left }, N) -> -+ move(right, #state{ right = Right }, N) -> -+ lists:duplicate(N, Right). -+ -+-in_view(#state{lines_after = LinesAfter, buffer_before = Bef, buffer_after = Aft, lines_before = LinesBefore, rows=R, cols=W, unicode=U, buffer_expand = BufferExpand} = State) -> -+- BufferExpandLines = case BufferExpand of -+- undefined -> []; -+- _ -> string:split(erlang:binary_to_list(BufferExpand), "\r\n", all) -+- end, -+- ExpandRows = (cols_multiline(BufferExpandLines, W, U) div W), -+- InputBeforeRows = (cols_multiline(LinesBefore, W, U) div W), -+- InputRows = (cols_multiline([Bef ++ Aft], W, U) div W), -+- InputAfterRows = (cols_multiline(LinesAfter, W, U) div W), -+- %% Dont print lines after if we have expansion rows -+- SumRows = InputBeforeRows+ InputRows + ExpandRows + InputAfterRows, -+- if SumRows > R -> -+- RowsLeftAfterInputRows = R - InputRows, -+- RowsLeftAfterExpandRows = RowsLeftAfterInputRows - ExpandRows, -+- RowsLeftAfterInputBeforeRows = RowsLeftAfterExpandRows - InputBeforeRows, -+- Cols1 = max(0,W*max(RowsLeftAfterInputBeforeRows, RowsLeftAfterExpandRows)), -+- {_, LBAfter, _, {_, LBAHalf}} = split_cols_multiline(Cols1, LinesBefore, U, W), -+- LBAfter0 = case LBAHalf of [] -> LBAfter; -+- _ -> [LBAHalf|LBAfter] -+- end, -+- -+- RowsLeftAfterInputAfterRows = RowsLeftAfterInputBeforeRows - InputAfterRows, -+- LAInViewLines = case BufferExpandLines of -+- [] -> -+- %% We must remove one line extra, since we may have an xnfix at the end which will -+- %% adds one extra line, so for consistency always remove one line -+- Cols2 = max(0,W*max(RowsLeftAfterInputAfterRows, RowsLeftAfterInputBeforeRows)-W), -+- {_, LABefore, _, {LABHalf, _}} = split_cols_multiline(Cols2, LinesAfter, U, W), -+- case LABHalf of [] -> LABefore; -+- _ -> [LABHalf|LABefore] -+- end; -+- _ -> -+- [] -+- end, -+- LAInView = lists:flatten(["\n"++LA||LA<-lists:reverse(LAInViewLines)]), -+- LBInView = lists:flatten([LB++"\n"||LB<-LBAfter0]), -+- Text = LBInView ++ lists:reverse(Bef,Aft) ++ LAInView, -+- Movement = move_cursor(State, -+- cols_after_cursor(State#state{lines_after = LAInViewLines++[lists:reverse(Bef, Aft)]}), -+- cols(Bef,U)), -+- {Movement, Text}; -+- -+- true -> -+- %% Everything fits in the current window, just output everything -+- Movement = move_cursor(State, cols_after_cursor(State#state{lines_after = lists:reverse(LinesAfter)++[lists:reverse(Bef, Aft)]}), cols(Bef,U)), -+- Text = lists:flatten([LB++"\n"||LB<-lists:reverse(LinesBefore)]) ++ -+- lists:reverse(Bef,Aft) ++ lists:flatten(["\n"++LA||LA<-LinesAfter]), -+- {Movement, Text} -+- end. -+-cols_after_cursor(#state{lines_after=[LAST|LinesAfter],cols=W, unicode=U}) -> -+- cols_multiline(LAST, LinesAfter, W, U). -+-split_cols_multiline(Cols, Lines, U, W) -> -+- split_cols_multiline(Cols, Lines, U, W, 0, []). -+-split_cols_multiline(0, Lines, _U, _W, ColsAcc, AccBefore) -> -+- {ColsAcc, AccBefore, Lines, {[],[]}}; -+-split_cols_multiline(_Cols, [], _U, _W, ColsAcc, AccBefore) -> -+- {ColsAcc, AccBefore, [], {[],[]}}; -+-split_cols_multiline(Cols, [L|Lines], U, W, ColsAcc, AccBefore) -> -+- case cols(L, U) > Cols of -+- true -> -+- {_, _, LB, LA} = split_cols(Cols, L, U), -+- {ColsAcc+Cols, AccBefore, Lines, {lists:reverse(LB), LA}}; -+- _ -> -+- Cols2 = (((cols(L,U)-1) div W)*W+W), -+- split_cols_multiline(Cols-Cols2, Lines, U, W, ColsAcc+Cols2, [L|AccBefore]) -+- end. -+-cols_multiline(Lines, W, U) -> -+- cols_multiline("", Lines, W, U). -+-cols_multiline(ExtraCols, Lines, W, U) -> -+- cols(ExtraCols, U) + lists:sum([((cols(LB,U)-1) div W)*W + W || LB <- Lines]). -+- -+ cols([],_Unicode) -> -+ 0; -+ cols([Char | T], Unicode) when is_integer(Char) -> -+@@ -975,7 +728,6 @@ npwcwidthstring(String) -> -+ _ -> -+ npwcwidth($\e) + npwcwidthstring(Rest) -+ end; -+- [H|Rest] when is_list(H)-> lists:sum([npwcwidth(A)||A<-H]) + npwcwidthstring(Rest); -+ [H|Rest] -> npwcwidth(H) + npwcwidthstring(Rest) -+ end. -+ -+@@ -1027,7 +779,7 @@ characters_to_output(Chars) -> -+ (Char) -> -+ Char -+ end, Chars) -+- ) -++ ) -+ end. -+ characters_to_buffer(Chars) -> -+ lists:flatmap( -+@@ -1063,12 +815,12 @@ insert_buf(State, Bin, LineAcc, Acc) -> -+ insert_buf(State, AnsiRest, [{ansi, Ansi} | LineAcc], Acc); -+ _ -> -+ insert_buf(State, Rest, [$\e | LineAcc], Acc) -+- end; -++ end; -+ {Ansi, AnsiRest} -> -+ %% We include the graphics ansi sequences in the -+ %% buffer that we step over -+ insert_buf(State, AnsiRest, [Ansi | LineAcc], Acc) -+- end; -++ end; -+ [NLCR | Rest] when NLCR =:= $\n; NLCR =:= $\r -> -+ Tail = -+ if NLCR =:= $\n -> -+@@ -1077,22 +829,10 @@ insert_buf(State, Bin, LineAcc, Acc) -> -+ <<$\r>> -+ end, -+ if State#state.buffer_expand =:= undefined -> -+- CurrentLine = lists:reverse(State#state.buffer_before), -+- LinesBefore = State#state.lines_before, -+- LinesBefore1 = -+- case {CurrentLine, LineAcc} of -+- {[], []} -> -+- LinesBefore; -+- {[],_} -> -+- [lists:reverse(LineAcc)|LinesBefore]; -+- {_,_} -> -+- [CurrentLine++lists:reverse(LineAcc)|LinesBefore] -+- end, -+- insert_buf(State#state{ buffer_before = [], -+- buffer_after = State#state.buffer_after, -+- lines_before=LinesBefore1}, -+- Rest, [], [Acc, [characters_to_output(lists:reverse(LineAcc)), Tail]]); -+- true -> insert_buf(State, Rest, [binary_to_list(Tail) | LineAcc], Acc) -++ insert_buf(State#state{ buffer_before = [], buffer_after = [] }, Rest, [], -++ [Acc, [characters_to_output(lists:reverse(LineAcc)), Tail]]); -++ true -> -++ insert_buf(State, Rest, [binary_to_list(Tail) | LineAcc], Acc) -+ end; -+ [Cluster | Rest] when is_list(Cluster) -> -+ insert_buf(State, Rest, [Cluster | LineAcc], Acc); -+diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl -+index 25ebcbdd68..fc1a4434fb 100644 -+--- a/lib/kernel/src/user_drv.erl -++++ b/lib/kernel/src/user_drv.erl -+@@ -52,25 +52,14 @@ -+ %% Same as put_chars/3, but sends Reply to From when the characters are -+ %% guaranteed to have been written to the terminal -+ {put_chars_sync, unicode, binary(), {From :: pid(), Reply :: term()}} | -+- %% Put text in expansion area -+- {put_expand} | -+- {put_expand_no_trim} | -+ %% Move the cursor X characters left or right (negative is left) -+ {move_rel, -32768..32767} | -+- %% Move the cursor Y rows up or down (negative is up) -+- {move_line, -32768..32767} | -+- %% Move combo, helper to simplify some move operations -+- {move_combo, -32768..32767, -32768..32767, -32768..32767} | -+ %% Insert characters at current cursor position moving any -+ %% characters after the cursor. -+ {insert_chars, unicode, binary()} | -+ %% Delete X chars before or after the cursor adjusting any test remaining -+ %% to the right of the cursor. -+ {delete_chars, -32768..32767} | -+- %% Deletes the current prompt and expression -+- delete_line | -+- %% Delete after the cursor -+- delete_after_cursor | -+ %% Trigger a terminal "bell" -+ beep | -+ %% Clears the screen -+@@ -78,12 +67,7 @@ -+ %% Execute multiple request() actions -+ {requests, [request()]} | -+ %% Open external editor -+- {open_editor, string()} | -+- %% Redraws the current prompt and expression -+- redraw_prompt | -+- {redraw_prompt, string(), string(), tuple()} | -+- %% Clears the state, not touching the characters -+- new_prompt. -++ {open_editor, string()}. -+ -+ -export_type([message/0]). -+ -export([start/0, start/1, start_shell/0, start_shell/1, whereis_group/0]). -+@@ -314,6 +298,7 @@ init_remote_shell(State, Node, {M, F, A}) -> -+ end. -+ -+ init_local_shell(State, InitialShell) -> -++ -+ Slogan = -+ case application:get_env( -+ stdlib, shell_slogan, -+@@ -610,9 +595,8 @@ switch_loop(internal, {line, Line}, State) -> -+ {ok, Groups} -> -+ Curr = gr_cur_pid(Groups), -+ put(current_group, Curr), -+- Curr ! {self(), activate}, -+ {next_state, server, -+- State#state{ current_group = Curr, groups = Groups }}; -++ State#state{ current_group = Curr, groups = Groups } }; -+ {retry, Requests} -> -+ {keep_state, State#state{ tty = io_requests(Requests, State#state.tty) }, -+ {next_event, internal, line}}; -+@@ -633,7 +617,7 @@ switch_loop(internal, {line, Line}, State) -> -+ end; -+ switch_loop(info,{ReadHandle,{data,Cs}}, {Cont, #state{ read = ReadHandle } = State}) -> -+ case edlin:edit_line(unicode:characters_to_list(Cs), Cont) of -+- {done,{[Line],_,_},_Rest, Rs} -> -++ {done,Line,_Rest, Rs} -> -+ {keep_state, State#state{ tty = io_requests(Rs, State#state.tty) }, -+ {next_event, internal, {line, Line}}}; -+ {undefined,_Char,MoreCs,NewCont,Rs} -> -+@@ -775,18 +759,6 @@ group_opts() -> -+ {term(), reference(), prim_tty:state()}. -+ io_request({requests,Rs}, TTY) -> -+ {noreply, io_requests(Rs, TTY)}; -+-io_request(redraw_prompt, TTY) -> -+- write(prim_tty:handle_request(TTY, redraw_prompt)); -+-io_request({redraw_prompt, Pbs, Pbs2, LineState}, TTY) -> -+- write(prim_tty:handle_request(TTY, {redraw_prompt, Pbs, Pbs2, LineState})); -+-io_request(new_prompt, TTY) -> -+- write(prim_tty:handle_request(TTY, new_prompt)); -+-io_request(delete_after_cursor, TTY) -> -+- write(prim_tty:handle_request(TTY, delete_after_cursor)); -+-io_request(delete_line, TTY) -> -+- write(prim_tty:handle_request(TTY, delete_line)); -+-io_request({put_chars_keep_state, unicode, Chars}, TTY) -> -+- write(prim_tty:handle_request(TTY, {putc_keep_state, unicode:characters_to_binary(Chars)})); -+ io_request({put_chars, unicode, Chars}, TTY) -> -+ write(prim_tty:handle_request(TTY, {putc, unicode:characters_to_binary(Chars)})); -+ io_request({put_chars_sync, unicode, Chars, Reply}, TTY) -> -+@@ -798,15 +770,9 @@ io_request({put_chars_sync, latin1, Chars, Reply}, TTY) -> -+ {ok, MonitorRef} = prim_tty:write(NewTTY, Output, self()), -+ {Reply, MonitorRef, NewTTY}; -+ io_request({put_expand, unicode, Chars}, TTY) -> -+- write(prim_tty:handle_request(TTY, {expand_with_trim, unicode:characters_to_binary(Chars)})); -+-io_request({put_expand_no_trim, unicode, Chars}, TTY) -> -+ write(prim_tty:handle_request(TTY, {expand, unicode:characters_to_binary(Chars)})); -+ io_request({move_rel, N}, TTY) -> -+ write(prim_tty:handle_request(TTY, {move, N})); -+-io_request({move_line, R}, TTY) -> -+- write(prim_tty:handle_request(TTY, {move_line, R})); -+-io_request({move_combo, V1, R, V2}, TTY) -> -+- write(prim_tty:handle_request(TTY, {move_combo, V1, R, V2})); -+ io_request({insert_chars, unicode, Chars}, TTY) -> -+ write(prim_tty:handle_request(TTY, {insert, unicode:characters_to_binary(Chars)})); -+ io_request({delete_chars, N}, TTY) -> -+@@ -824,12 +790,6 @@ io_requests([{insert_chars, unicode, C1},{insert_chars, unicode, C2}|Rs], TTY) - -+ io_requests([{insert_chars, unicode, [C1,C2]}|Rs], TTY); -+ io_requests([{put_chars, unicode, C1},{put_chars, unicode, C2}|Rs], TTY) -> -+ io_requests([{put_chars, unicode, [C1,C2]}|Rs], TTY); -+-io_requests([{move_rel, N}, {move_line, R}, {move_rel, M}|Rs], TTY) -> -+- io_requests([{move_combo, N, R, M}|Rs], TTY); -+-io_requests([{move_rel, N}, {move_line, R}|Rs], TTY) -> -+- io_requests([{move_combo, N, R, 0}|Rs], TTY); -+-io_requests([{move_line, R}, {move_rel, M}|Rs], TTY) -> -+- io_requests([{move_combo, 0, R, M}|Rs], TTY); -+ io_requests([R|Rs], TTY) -> -+ {noreply, NewTTY} = io_request(R, TTY), -+ io_requests(Rs, NewTTY); -+diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl -+index b413800661..04f4143ea9 100644 -+--- a/lib/kernel/test/interactive_shell_SUITE.erl -++++ b/lib/kernel/test/interactive_shell_SUITE.erl -+@@ -46,9 +46,9 @@ -+ shell_history_custom/1, shell_history_custom_errors/1, -+ job_control_remote_noshell/1,ctrl_keys/1, -+ get_columns_and_rows_escript/1, -+- shell_navigation/1, shell_multiline_navigation/1, shell_xnfix/1, shell_delete/1, -++ shell_navigation/1, shell_xnfix/1, shell_delete/1, -+ shell_transpose/1, shell_search/1, shell_insert/1, -+- shell_update_window/1, shell_small_window_multiline_navigation/1, shell_huge_input/1, -++ shell_update_window/1, shell_huge_input/1, -+ shell_invalid_unicode/1, shell_support_ansi_input/1, -+ shell_invalid_ansi/1, shell_suspend/1, shell_full_queue/1, -+ shell_unicode_wrap/1, shell_delete_unicode_wrap/1, -+@@ -66,7 +66,7 @@ -+ -export([load/0, add/1]). -+ %% For custom prompt testing -+ -export([prompt/1]). -+--record(tmux, {peer, node, name, orig_location }). -++ -+ suite() -> -+ [{ct_hooks,[ts_install_cth]}, -+ {timetrap,{minutes,3}}]. -+@@ -124,9 +124,9 @@ groups() -> -+ ]}, -+ {tty_latin1,[],[{group,tty_tests}]}, -+ {tty_tests, [parallel], -+- [shell_navigation, shell_multiline_navigation, shell_xnfix, shell_delete, -++ [shell_navigation, shell_xnfix, shell_delete, -+ shell_transpose, shell_search, shell_insert, -+- shell_update_window, shell_small_window_multiline_navigation, shell_huge_input, -++ shell_update_window, shell_huge_input, -+ shell_support_ansi_input, -+ shell_standard_error_nlcr, -+ shell_expand_location_above, -+@@ -404,68 +404,7 @@ shell_navigation(Config) -> -+ after -+ stop_tty(Term) -+ end. -+-shell_multiline_navigation(Config) -> -+- Term = start_tty(Config), -+ -+- try -+- [begin -+- check_location(Term, {0, 0}), -+- send_tty(Term,"{aaa,"), -+- check_location(Term, {0,width("{aaa,")}), -+- send_tty(Term,"\n'b"++U++"b',"), -+- check_location(Term, {0, width("'b"++U++"b',")}), -+- send_tty(Term,"\nccc}"), -+- check_location(Term, {-2, 0}), %% Check that cursor jump backward (blink) -+- timer:sleep(1000), %% Wait for cursor to jump back -+- check_location(Term, {0, width("ccc}")}), -+- send_tty(Term,"Home"), -+- check_location(Term, {0, 0}), -+- send_tty(Term,"End"), -+- check_location(Term, {0, width("ccc}")}), -+- send_tty(Term,"Left"), -+- check_location(Term, {0, width("ccc")}), -+- send_tty(Term,"C-Left"), -+- check_location(Term, {0, 0}), -+- send_tty(Term,"C-Left"), -+- check_location(Term, {-1, width("'b"++U++"b',")}), -+- send_tty(Term,"C-Left"), -+- check_location(Term, {-1, 0}), -+- %send_tty(Term,"C-Left"), -+- %check_location(Term, {-1, 0}), -+- %send_tty(Term,"C-Right"), -+- %check_location(Term, {-1, 1}), -+- send_tty(Term,"C-Right"), -+- check_location(Term, {-1, width("'b"++U++"b'")}), -+- send_tty(Term,"C-Up"), -+- check_location(Term, {-2, width("{aaa,")}), -+- send_tty(Term,"C-Down"), -+- send_tty(Term,"C-Down"), -+- check_location(Term, {0, width("ccc}")}), -+- send_tty(Term,"Left"), -+- send_tty(Term,"C-Up"), -+- check_location(Term, {-1, width("'b"++U)}), -+- send_tty(Term,"M-<"), -+- check_location(Term, {-2, 0}), -+- send_tty(Term,"M->"), -+- send_tty(Term,"Left"), -+- check_location(Term, {0,width("ccc")}), -+- send_tty(Term,"Enter"), -+- send_tty(Term,"Right"), -+- check_location(Term, {0,0}), -+- send_tty(Term,"C-h"), % Backspace -+- check_location(Term, {-1,width("ccc}")}), -+- send_tty(Term,"Left"), -+- send_tty(Term,"M-Enter"), -+- send_tty(Term,"Right"), -+- check_location(Term, {0,1}), -+- send_tty(Term,"M-c"), -+- check_location(Term, {-3,0}), -+- send_tty(Term,"{'"++U++"',\n\n\nworks}.\n") -+- end || U <- hard_unicode()], -+- ok -+- after -+- stop_tty(Term) -+- end. -+ shell_clear(Config) -> -+ -+ Term = start_tty(Config), -+@@ -788,7 +727,9 @@ shell_transpose(Config) -> -+ end. -+ -+ shell_search(C) -> -++ -+ Term = start_tty(C), -++ {_Row, Cols} = get_location(Term), -+ -+ try -+ send_tty(Term,"a"), -+@@ -802,22 +743,20 @@ shell_search(C) -> -+ send_tty(Term,"Enter"), -+ check_location(Term, {0, 0}), -+ send_tty(Term,"C-r"), -+- check_content(Term, "search:\\s*\n\\s*'a😀'."), -++ check_location(Term, {0, - Cols + width(C, "(search)`': 'a😀'.") }), -+ send_tty(Term,"C-a"), -+- check_location(Term, {-1, width(C, "'a😀'.")}), -++ check_location(Term, {0, width(C, "'a😀'.")}), -+ send_tty(Term,"Enter"), -+ send_tty(Term,"C-r"), -+- check_content(Term, "search:\\s*\n\\s*'a😀'."), -++ check_location(Term, {0, - Cols + width(C, "(search)`': 'a😀'.") }), -+ send_tty(Term,"a"), -+- check_content(Term, "search: a\\s*\n\\s*'a😀'."), -++ check_location(Term, {0, - Cols + width(C, "(search)`a': 'a😀'.") }), -+ send_tty(Term,"C-r"), -+- check_content(Term, "search: a\\s*\n\\s*a."), -++ check_location(Term, {0, - Cols + width(C, "(search)`a': a.") }), -+ send_tty(Term,"BSpace"), -+- check_content(Term, "search:\\s*\n\\s*'a😀'."), -++ check_location(Term, {0, - Cols + width(C, "(search)`': 'a😀'.") }), -+ send_tty(Term,"BSpace"), -+- check_content(Term, "search:\\s*\n\\s*'a😀'."), -+- send_tty(Term,"M-c"), -+- check_location(Term, {-1, 0}), -++ check_location(Term, {0, - Cols + width(C, "(search)`': 'a😀'.") }), -+ ok -+ after -+ stop_tty(Term), -+@@ -872,49 +811,7 @@ shell_update_window(Config) -> -+ after -+ stop_tty(Term) -+ end. -+-shell_small_window_multiline_navigation(Config) -> -+- Term0 = start_tty(Config), -+- tmux(["resize-window -t ",tty_name(Term0)," -x ",30, " -y ", 6]), -+- {Row, Col} = get_location(Term0), -+- Term = Term0#tmux{orig_location = {Row, Col}}, -+- Text = ("xbcdefghijklmabcdefghijklm\n"++ -+- "abcdefghijkl\n"++ -+- "abcdefghijklmabcdefghijklm\n"++ -+- "abcdefghijklmabcdefghijklx"), -+- try -+- send_tty(Term,Text), -+- check_location(Term, {0, -4}), -+- send_tty(Term,"Home"), -+- check_location(Term, {-1, 0}), -+- send_tty(Term, "C-Up"), -+- check_location(Term, {-2, 0}), -+- send_tty(Term, "C-Down"), -+- check_location(Term, {-1, 0}), -+- send_tty(Term, "Left"), -+- check_location(Term, {-1, -4}), -+- send_tty(Term, "Right"), -+- check_location(Term, {-1, 0}), -+- send_tty(Term, "\e[1;4A"), -+- check_location(Term, {-5, 0}), -+- check_content(Term,"xbc"), -+- send_tty(Term, "\e[1;4B"), -+- check_location(Term, {0, -4}), -+- check_content(Term,"klx"), -+- send_tty(Term, " sets:is_e\t"), -+- check_content(Term,"is_element"), -+- check_content(Term,"is_empty"), -+- check_location(Term, {-3, 6}), -+- send_tty(Term, "C-Up"), -+- send_tty(Term,"Home"), -+- check_location(Term, {-2, 0}), -+- send_tty(Term, "sets:is_e\t"), -+- check_content(Term,"is_element"), -+- check_content(Term,"is_empty"), -+- check_location(Term, {-4, 9}), -+- ok -+- after -+- stop_tty(Term) -+- end. -++ -+ shell_huge_input(Config) -> -+ Term = start_tty(Config), -+ -+@@ -1071,7 +968,7 @@ shell_expand_location_below(Config) -> -+ send_stdin(Term, "\t"), -+ %% The expansion does not fit on screen, verify that -+ %% expand above mode is used -+- check_content(fun() -> get_content(Term, "-S -7") end, -++ check_content(fun() -> get_content(Term, "-S -5") end, -+ "3> long_module:" ++ FunctionName ++ "\nfunctions"), -+ check_content(Term, "3> long_module:" ++ FunctionName ++ "$"), -+ -+@@ -1166,19 +1063,18 @@ external_editor(Config) -> -+ tmux(["resize-window -t ",tty_name(Term)," -x 80"]), -+ send_tty(Term,"os:putenv(\"EDITOR\",\"nano\").\n"), -+ send_tty(Term, "\"some text with\nnewline in it\""), -+- check_content(Term,"3> \"some text with\\s*\n.+\\s*newline in it\""), -++ check_content(Term,"3> \"some text with\\s*\n.+3>\\s*newline in it\""), -+ send_tty(Term, "C-O"), -+ check_content(Term,"GNU nano [\\d.]+"), -+- check_content(Term,"\"some text with\\s*\n\\s*newline in it\""), -+- send_tty(Term, "Right"), -++ check_content(Term,"newline in it\""), -+ send_tty(Term, "still"), -+ send_tty(Term, "Enter"), -+ send_tty(Term, "C-O"), %% save in nano -+ send_tty(Term, "Enter"), -+ send_tty(Term, "C-X"), %% quit in nano -+- check_content(Term,"3> \"still\\s*\n\\s*.+\\s*some text with\\s*\n.+\\s*newline in it\""), -++ check_content(Term,"still\n.+3> newline in it\""), -+ send_tty(Term,".\n"), -+- check_content(Term,"\\Q\"still\\nsome text with\\nnewline in it\"\\E"), -++ check_content(Term,"\\Q\"some text with\\nstill\\nnewline in it\"\\E"), -+ ok -+ after -+ stop_tty(Term), -+@@ -1484,6 +1380,8 @@ npwcwidth(CP) -> -+ end -+ end. -+ -++-record(tmux, {peer, node, name, orig_location }). -++ -+ tmux([Cmd|_] = Command) when is_list(Cmd) -> -+ tmux(lists:concat(Command)); -+ tmux(Command) -> -+@@ -2227,13 +2125,15 @@ test_remote_job_control(Node) -> -+ {expect, "Unknown job"}, -+ {expect, " --> $"}, -+ {putline, "c 1"}, -++ {expect, "\r\n"}, -++ {putline, ""}, -+ {expect, "\\Q("++RemNode++"@\\E[^)]*\\)[12]> $"}, -+ {putdata, "\^g"}, -+ {expect, " --> $"}, -+ {putline, "j"}, -+ {expect, "1[*] {shell,start,\\[init]}"}, -+ {putline, "c"}, -+- {expect, "\\Q("++RemNode++"@\\E[^)]*\\)[123]> $"}, -++ {expect, "\r\n"}, -+ {sleep, 100}, -+ {putline, "35."}, -+ {expect, "\\Q("++RemNode++"@\\E[^)]*\\)[123]> $"} -+diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl -+index 88283a54c9..b015479b9f 100644 -+--- a/lib/stdlib/src/edlin.erl -++++ b/lib/stdlib/src/edlin.erl -+@@ -23,9 +23,10 @@ -+ %% About Latin-1 characters: see the beginning of erl_scan.erl. -+ -+ -export([init/0,init/1,start/1,start/2,edit_line/2,prefix_arg/1]). -+--export([erase_line/0,erase_inp/1,redraw_line/1]). -++-export([erase_line/1,erase_inp/1,redraw_line/1]). -+ -export([length_before/1,length_after/1,prompt/1]). -+ -export([current_line/1, current_chars/1]). -++%%-export([expand/1]). -+ -+ -export([edit_line1/2]). -+ -+@@ -71,105 +72,80 @@ start(Pbs) -> -+ -+ %% Only two modes used: 'none' and 'search'. Other modes can be -+ %% handled inline through specific character handling. -+-start(Pbs, {_,{_,_},_}=Cont) -> -+- Rs1 = erase_line(), -+- Rs2 = redraw(Pbs, Cont, Rs1), -+- Rs3 = reverse(Rs2), -+- {more_chars,{line,Pbs,Cont,none},Rs3}; -+- -+ start(Pbs, Mode) -> -+- {more_chars,{line,Pbs,{[],{[],[]},[]},Mode},[new_prompt, {put_chars,unicode,Pbs}]}. -++ {more_chars,{line,Pbs,{[],[]},Mode},[{put_chars,unicode,Pbs}]}. -+ -+-edit_line(Cs, {line,P,L,{blink,N_Rs}}) -> -+- edit(Cs, P, L, none, N_Rs); -++edit_line(Cs, {line,P,L,{blink,N}}) -> -++ edit(Cs, P, L, none, [{move_rel,N}]); -+ edit_line(Cs, {line,P,L,M}) -> -+ edit(Cs, P, L, M, []). -+ -+-edit_line1(Cs, {line,P,L,{blink,N_Rs}}) -> -+- edit(Cs, P, L, none, N_Rs); -+-edit_line1(Cs, {line,P,{B,{[],[]},A},none}) -> -+- [CurrentLine|Lines] = [string:to_graphemes(Line) || Line <- reverse(string:split(Cs, "\n",all))], -+- Cont = {Lines ++ B,{reverse(CurrentLine),[]},A}, -+- Rs = reverse(redraw(P, Cont, [])), -+- %erlang:display({P, Cont, Cs, CurrentLine}), -+- {more_chars, {line,P,Cont,none},[delete_line|Rs]}; -++edit_line1(Cs, {line,P,L,{blink,N}}) -> -++ edit(Cs, P, L, none, [{move_rel,N}]); -++edit_line1(Cs, {line,P,{[],[]},none}) -> -++ {more_chars, {line,P,{string:reverse(Cs),[]},none},[{put_chars, unicode, Cs}]}; -+ edit_line1(Cs, {line,P,L,M}) -> -+ edit(Cs, P, L, M, []). -+ -+ edit([C|Cs], P, Line, {blink,_}, [_|Rs]) -> %Remove blink here -+ edit([C|Cs], P, Line, none, Rs); -+-edit([C|Cs], P, {LB, {Bef,Aft}, LA}=MultiLine, Prefix, Rs0) -> -++edit([C|Cs], P, {Bef,Aft}, Prefix, Rs0) -> -+ case key_map(C, Prefix) of -+ meta -> -+- edit(Cs, P, MultiLine, meta, Rs0); -++ edit(Cs, P, {Bef,Aft}, meta, Rs0); -+ meta_o -> -+- edit(Cs, P, MultiLine, meta_o, Rs0); -++ edit(Cs, P, {Bef,Aft}, meta_o, Rs0); -+ meta_csi -> -+- edit(Cs, P, MultiLine, meta_csi, Rs0); -++ edit(Cs, P, {Bef,Aft}, meta_csi, Rs0); -+ meta_meta -> -+- edit(Cs, P, MultiLine, meta_meta, Rs0); -++ edit(Cs, P, {Bef,Aft}, meta_meta, Rs0); -+ {csi, _} = Csi -> -+- edit(Cs, P, MultiLine, Csi, Rs0); -++ edit(Cs, P, {Bef,Aft}, Csi, Rs0); -+ meta_left_sq_bracket -> -+- edit(Cs, P, MultiLine, meta_left_sq_bracket, Rs0); -++ edit(Cs, P, {Bef,Aft}, meta_left_sq_bracket, Rs0); -+ search_meta -> -+- edit(Cs, P, MultiLine, search_meta, Rs0); -++ edit(Cs, P, {Bef,Aft}, search_meta, Rs0); -+ search_meta_left_sq_bracket -> -+- edit(Cs, P, MultiLine, search_meta_left_sq_bracket, Rs0); -++ edit(Cs, P, {Bef,Aft}, search_meta_left_sq_bracket, Rs0); -+ ctlx -> -+- edit(Cs, P, MultiLine, ctlx, Rs0); -++ edit(Cs, P, {Bef,Aft}, ctlx, Rs0); -+ new_line -> -+- case Bef of -+- [] -> edit(Cs, P, MultiLine, none, Rs0); -+- _ -> MultiLine1 = {[lists:reverse(Bef)|LB],{[],Aft},LA}, -+- edit(Cs, P, MultiLine1, none, redraw(P, MultiLine1, Rs0)) -+- end; -+- new_line_finish -> -+- [Last|LAR]=LA1 = lists:reverse([lists:reverse(Bef,Aft)|LA]), -+- MultiLine1 = {LA1 ++ LB,{[],[]},[]}, -+- % Move to end and redraw -+- Rs1 = redraw(P, {LAR ++ LB, {lists:reverse(Last), []},[]}, Rs0), -+- {done, MultiLine1, Cs, reverse(Rs1, [{insert_chars, unicode, "\n"}])}; -++ {done, get_line(Bef, Aft ++ "\n"), Cs, -++ reverse(Rs0, [{move_rel,cp_len(Aft)},{put_chars,unicode,"\n"}])}; -+ redraw_line -> -+- Rs1 = erase_line(Rs0), -+- Rs = redraw(P, MultiLine, Rs1), -+- edit(Cs, P, MultiLine, none, Rs); -++ Rs1 = erase(P, Bef, Aft, Rs0), -++ Rs = redraw(P, Bef, Aft, Rs1), -++ edit(Cs, P, {Bef,Aft}, none, Rs); -+ clear -> -+- Rs = redraw(P, MultiLine, [clear|Rs0]), -+- edit(Cs, P, MultiLine, none, Rs); -+- tab_expand -> -+- {expand, chars_before(MultiLine), Cs, -+- {line, P, MultiLine, tab_expand}, -+- reverse(Rs0)}; -++ Rs = redraw(P, Bef, Aft, [clear | Rs0]), -++ edit(Cs, P, {Bef,Aft}, none, Rs); -++ tab_expand -> -++ {expand, Bef, Cs, -++ {line, P, {Bef, Aft}, tab_expand}, -++ reverse(Rs0)}; -+ tab_expand_full -> -+- {expand_full, chars_before(MultiLine), Cs, -+- {line, P, MultiLine, tab_expand}, -+- reverse(Rs0)}; -++ {expand_full, Bef, Cs, -++ {line, P, {Bef, Aft}, tab_expand}, -++ reverse(Rs0)}; -+ {undefined,C} -> -+- {undefined,{none,Prefix,C},Cs,{line,P,MultiLine,none}, -++ {undefined,{none,Prefix,C},Cs,{line,P,{Bef,Aft},none}, -+ reverse(Rs0)}; -+ Op -> -+- case do_op(Op, MultiLine, Rs0) of -+- {blink,N,MultiLine1,Rs} -> -+- edit(Cs, P, MultiLine1, {blink,N}, Rs); -+- {redraw, MultiLine1, Rs} -> -+- edit(Cs, P, MultiLine1, none, redraw(P, MultiLine1, Rs)); -+- {MultiLine1, Rs, Mode} -> % allow custom modes from do_op -+- edit(Cs, P, MultiLine1, Mode, Rs); -+- {MultiLine1,Rs} -> -+- edit(Cs, P, MultiLine1, none, Rs) -++ case do_op(Op, Bef, Aft, Rs0) of -++ {blink,N,Line,Rs} -> -++ edit(Cs, P, Line, {blink,N}, Rs); -++ {Line, Rs, Mode} -> % allow custom modes from do_op -++ edit(Cs, P, Line, Mode, Rs); -++ {Line,Rs} -> -++ edit(Cs, P, Line, none, Rs) -+ end -+ end; -+ edit([], P, L, {blink,N}, Rs) -> -+- {blink,{line,P,L, {blink,N}},reverse(Rs)}; -++ {blink,{line,P,L,{blink,N}},reverse(Rs)}; -+ edit([], P, L, Prefix, Rs) -> -+ {more_chars,{line,P,L,Prefix},reverse(Rs)}; -+-edit(eof, _, {_,{Bef,Aft0},LA} = L, _, Rs) -> -+- Aft1 = case LA of -+- [Last|_] -> Last; -+- _ -> Aft0 -+- end, -+- {done,L,[],reverse(Rs, [{move_combo,-cp_len(Bef), length(LA), cp_len(Aft1)}])}. -++edit(eof, _, {Bef,Aft}, _, Rs) -> -++ {done,get_line(Bef, Aft),[],reverse(Rs, [{move_rel,cp_len(Aft)}])}. -+ -+ %% %% Assumes that arg is a string -+ %% %% Horizontal whitespace only. -+@@ -207,8 +183,8 @@ key_map($\t, tab_expand) -> tab_expand_full; -+ key_map(C, tab_expand) -> key_map(C, none); -+ key_map($\^K, none) -> kill_line; -+ key_map($\^L, none) -> clear; -+-key_map($\n, none) -> new_line_finish; -+-key_map($\r, none) -> new_line_finish; -++key_map($\n, none) -> new_line; -++key_map($\r, none) -> new_line; -+ key_map($\^T, none) -> transpose_char; -+ key_map($\^U, none) -> ctlu; -+ key_map($\^], none) -> auto_blink; -+@@ -232,16 +208,11 @@ key_map($L, meta) -> redraw_line; -+ key_map($T, meta) -> transpose_word; -+ key_map($Y, meta) -> yank_pop; -+ key_map($b, meta) -> backward_word; -+-key_map($c, meta) -> clear_line; -+ key_map($d, meta) -> kill_word; -+ key_map($f, meta) -> forward_word; -+ key_map($l, meta) -> redraw_line; -+ key_map($t, meta) -> transpose_word; -+ key_map($y, meta) -> yank_pop; -+-key_map($<, meta) -> beginning_of_expression; -+-key_map($>, meta) -> end_of_expression; -+-key_map($\n, meta) -> new_line; -+-key_map($\r, meta) -> new_line; -+ key_map($O, meta) -> meta_o; -+ key_map($H, meta_o) -> beginning_of_line; -+ key_map($F, meta_o) -> end_of_line; -+@@ -252,7 +223,7 @@ key_map($H, meta_left_sq_bracket) -> beginning_of_line; -+ key_map($F, meta_left_sq_bracket) -> end_of_line; -+ key_map($D, meta_left_sq_bracket) -> backward_char; -+ key_map($C, meta_left_sq_bracket) -> forward_char; -+-% support a few + combinations... -++% support a few + combinations... -+ % - forward: \e\e[C, \e[5C, \e[1;5C -+ % - backward: \e\e[D, \e[5D, \e[1;5D -+ key_map($\e, meta) -> meta_meta; -+@@ -261,31 +232,14 @@ key_map($C, meta_csi) -> forward_word; -+ key_map($D, meta_csi) -> backward_word; -+ key_map($1, meta_left_sq_bracket) -> {csi, "1"}; -+ key_map($3, meta_left_sq_bracket) -> {csi, "3"}; -+-key_map($C, {csi, "3"}) -> forward_word; -+-key_map($D, {csi, "3"}) -> backward_word; -+-key_map($~, {csi, "3"}) -> forward_delete_char; -+ key_map($5, meta_left_sq_bracket) -> {csi, "5"}; -+-key_map($C, {csi, "5"}) -> forward_word; -+-key_map($D, {csi, "5"}) -> backward_word; -+-key_map($;, {csi, "1"}) -> {csi, "1;"}; -+-key_map($3, {csi, "1;"}) -> {csi, "1;3"}; -+-key_map($C, {csi, "1;3"}) -> forward_word; -+-key_map($D, {csi, "1;3"}) -> backward_word; -+-key_map($A, {csi, "1;3"}) -> backward_line; -+-key_map($B, {csi, "1;3"}) -> forward_line; -+-key_map($4, {csi, "1;"}) -> {csi, "1;4"}; -+-key_map($A, {csi, "1;4"}) -> beginning_of_expression; -+-key_map($B, {csi, "1;4"}) -> end_of_expression; -+ key_map($5, {csi, "1;"}) -> {csi, "1;5"}; -++key_map($~, {csi, "3"}) -> forward_delete_char; -++key_map($C, {csi, "5"}) -> forward_word; -+ key_map($C, {csi, "1;5"}) -> forward_word; -++key_map($D, {csi, "5"}) -> backward_word; -+ key_map($D, {csi, "1;5"}) -> backward_word; -+-key_map($A, {csi, "1;5"}) -> backward_line; -+-key_map($B, {csi, "1;5"}) -> forward_line; -+- -+- -+- -+- -+- -++key_map($;, {csi, "1"}) -> {csi, "1;"}; -+ key_map(C, none) when C >= $\s -> -+ {insert,C}; -+ %% for search, we need smarter line handling and so -+@@ -310,8 +264,6 @@ key_map($\^], search) -> {search, search_quit}; -+ key_map($\^X, search) -> {search, search_quit}; -+ key_map($\^Y, search) -> {search, search_quit}; -+ key_map($\e, search) -> search_meta; -+-key_map($c, search_meta) -> {search, search_cancel}; -+-key_map($C, search_meta) -> {search, search_cancel}; -+ key_map($[, search_meta) -> search_meta_left_sq_bracket; -+ key_map(_, search_meta) -> {search, search_quit}; -+ key_map(_C, search_meta_left_sq_bracket) -> {search, search_quit}; -+@@ -320,19 +272,19 @@ key_map(C, _) -> {undefined,C}. -+ -+ %% do_op(Action, Before, After, Requests) -+ %% Before and After are of lists of type string:grapheme_cluster() -+-do_op({insert,C}, {LB,{[],[]},LA}, Rs) -> -+- {{LB,{[C],[]},LA},[{insert_chars, unicode,[C]}|Rs]}; -+-do_op({insert,C}, {LB,{[Bef|Bef0], []},LA}, Rs) -> -++do_op({insert,C}, [], [], Rs) -> -++ {{[C],[]},[{put_chars, unicode,[C]}|Rs]}; -++do_op({insert,C}, [Bef|Bef0], [], Rs) -> -+ case string:to_graphemes([Bef,C]) of -+- [GC] -> {{LB,{[GC|Bef0],[]},LA},[{insert_chars, unicode,[C]}|Rs]}; -+- _ -> {{LB,{[C,Bef|Bef0],[]},LA},[{insert_chars, unicode,[C]}|Rs]} -++ [GC] -> {{[GC|Bef0],[]},[{put_chars, unicode,[C]}|Rs]}; -++ _ -> {{[C,Bef|Bef0],[]},[{put_chars, unicode,[C]}|Rs]} -+ end; -+-do_op({insert,C}, {LB,{[], Aft},LA}, Rs) -> -+- {{LB,{[C],Aft},LA},[{insert_chars, unicode,[C]}|Rs]}; -+-do_op({insert,C}, {LB,{[Bef|Bef0], Aft},LA}, Rs) -> -++do_op({insert,C}, [], Aft, Rs) -> -++ {{[C],Aft},[{insert_chars, unicode,[C]}|Rs]}; -++do_op({insert,C}, [Bef|Bef0], Aft, Rs) -> -+ case string:to_graphemes([Bef,C]) of -+- [GC] -> {{LB,{[GC|Bef0],Aft},LA},[{insert_chars, unicode,[C]}|Rs]}; -+- _ -> {{LB,{[C,Bef|Bef0],Aft},LA},[{insert_chars, unicode,[C]}|Rs]} -++ [GC] -> {{[GC|Bef0],Aft},[{insert_chars, unicode,[C]}|Rs]}; -++ _ -> {{[C,Bef|Bef0],Aft},[{insert_chars, unicode,[C]}|Rs]} -+ end; -+ %% Search mode prompt always looks like (search)`$TERMS': $RESULT. -+ %% the {insert_search, _} handlings allow to share this implementation -+@@ -343,168 +295,127 @@ do_op({insert,C}, {LB,{[Bef|Bef0], Aft},LA}, Rs) -> -+ %% search mode), we can use the Bef and Aft variables to hold each -+ %% part of the line. Bef takes charge of "(search)`$TERMS" and Aft -+ %% takes charge of "': $RESULT". -+-%% -+-%% Since multiline support the search mode prompt always looks like: -+-%% search: $TERMS -+-%% $ResultLine1 -+-%% $ResultLine2 -+-do_op({insert_search, C}, {LB,{Bef, []},LA}, Rs) -> -+- {{LB, {[C|Bef],[]}, LA}, -+- [{insert_chars, unicode, [C]}, delete_after_cursor | Rs], search}; -+-do_op({insert_search, C}, {LB,{Bef, _Aft},LA}, Rs) -> -+- {{LB, {[C|Bef],[]}, LA}, -+- [{insert_chars, unicode, [C]}, delete_after_cursor | Rs], -++do_op({insert_search, C}, Bef, [], Rs) -> -++ Aft="': ", -++ {{[C|Bef],Aft}, -++ [{insert_chars, unicode, [C]++Aft}, {delete_chars,-3} | Rs], -++ search}; -++do_op({insert_search, C}, Bef, Aft, Rs) -> -++ Offset= cp_len(Aft), -++ NAft = "': ", -++ {{[C|Bef],NAft}, -++ [{insert_chars, unicode, [C]++NAft}, {delete_chars,-Offset} | Rs], -+ search}; -+-do_op({search, backward_delete_char}, {LB,{[_|Bef], Aft},LA}, Rs) -> -++do_op({search, backward_delete_char}, [_|Bef], Aft, Rs) -> -+ Offset= cp_len(Aft)+1, -+- {{LB, {Bef,Aft}, LA}, -+- [{insert_chars, unicode, Aft}, {delete_chars,-Offset}|Rs], -++ NAft = "': ", -++ {{Bef,NAft}, -++ [{insert_chars, unicode, NAft}, {delete_chars,-Offset}|Rs], -+ search}; -+-do_op({search, backward_delete_char}, {LB,{[], Aft},LA}, Rs) -> -+- {{LB, {[],Aft}, LA}, [{insert_chars, unicode, Aft}, {delete_chars,-cp_len(Aft)}|Rs], search}; -+-do_op({search, skip_up}, {_,{Bef, Aft},_}, Rs) -> -++do_op({search, backward_delete_char}, [], Aft, Rs) -> -++ NAft="': ", -++ {{[],NAft}, [{insert_chars, unicode, NAft}, {delete_chars,-cp_len(Aft)}|Rs], search}; -++do_op({search, skip_up}, Bef, Aft, Rs) -> -+ Offset= cp_len(Aft), -+- {{[],{[$\^R|Bef],Aft},[]}, % we insert ^R as a flag to whoever called us -+- [{insert_chars, unicode, Aft}, {delete_chars,-Offset}|Rs], -++ NAft = "': ", -++ {{[$\^R|Bef],NAft}, % we insert ^R as a flag to whoever called us -++ [{insert_chars, unicode, NAft}, {delete_chars,-Offset}|Rs], -+ search}; -+-do_op({search, skip_down}, {_,{Bef, Aft},_LA}, Rs) -> -++do_op({search, skip_down}, Bef, Aft, Rs) -> -+ Offset= cp_len(Aft), -+- {{[],{[$\^S|Bef],Aft},[]}, % we insert ^S as a flag to whoever called us -+- [{insert_chars, unicode, Aft}, {delete_chars,-Offset}|Rs], -++ NAft = "': ", -++ {{[$\^S|Bef],NAft}, % we insert ^S as a flag to whoever called us -++ [{insert_chars, unicode, NAft}, {delete_chars,-Offset}|Rs], -+ search}; -+-do_op({search, search_found}, {_,{_Bef, Aft},LA}, Rs) -> -+- {{[],{[],Aft},LA}, Rs, search_found}; -+-do_op({search, search_quit}, {_,{_Bef, Aft},LA}, Rs) -> -+- {{[],{[],Aft},LA}, Rs, search_quit}; -+-do_op({search, search_cancel}, _, Rs) -> -+- {{[],{[],[]},[]}, Rs, search_cancel}; -++do_op({search, search_found}, _Bef, Aft, Rs) -> -++ "': "++NAft = Aft, -++ {{[],NAft}, -++ [{put_chars, unicode, "\n"}, {move_rel,-cp_len(Aft)} | Rs], -++ search_found}; -++do_op({search, search_quit}, _Bef, Aft, Rs) -> -++ "': "++NAft = Aft, -++ {{[],NAft}, -++ [{put_chars, unicode, "\n"}, {move_rel,-cp_len(Aft)} | Rs], -++ search_quit}; -+ %% do blink after $$ -+-do_op({blink,C,M}, {_,{[$$,$$|_], _},_} = MultiLine, Rs) -> -+- blink(over_paren(chars_before(MultiLine), C, M), C, MultiLine, Rs); -++do_op({blink,C,M}, Bef=[$$,$$|_], Aft, Rs) -> -++ N = over_paren(Bef, C, M), -++ {blink,N+1,{[C|Bef],Aft},[{move_rel,-(N+1)},{insert_chars, unicode,[C]}|Rs]}; -+ %% don't blink after a $ -+-do_op({blink,C,_}, {_,{[$$|_], _},_} = MultiLine, Rs) -> -+- do_op({insert,C}, MultiLine, Rs); -+-do_op({blink,C,M}, MultiLine, Rs) -> -+- blink(over_paren(chars_before(MultiLine), C, M), C, MultiLine, Rs); -+-do_op(auto_blink, MultiLine, Rs) -> -+- blink(over_paren_auto(chars_before(MultiLine)), MultiLine, Rs); -+-do_op(forward_delete_char, {LB,{Bef, []},[NextLine|LA]}, Rs) -> -+- NewLine = {LB, {Bef, NextLine}, LA}, -+- {redraw, NewLine, Rs}; -+-do_op(forward_delete_char, {LB,{Bef, [GC|Aft]},LA}, Rs) -> -+- {{LB, {Bef,Aft}, LA},[{delete_chars,gc_len(GC)}|Rs]}; -+-do_op(backward_delete_char, {[PrevLine|LB],{[], Aft},LA}, Rs) -> -+- NewLine = {LB, {lists:reverse(PrevLine), Aft}, LA}, -+- {redraw, NewLine,Rs}; -+-do_op(backward_delete_char, {LB,{[GC|Bef], Aft},LA}, Rs) -> -+- {{LB, {Bef,Aft}, LA},[{delete_chars,-gc_len(GC)}|Rs]}; -+-do_op(transpose_char, {LB,{[C1,C2|Bef], []},LA}, Rs) -> -++do_op({blink,C,_}, Bef=[$$|_], Aft, Rs) -> -++ do_op({insert,C}, Bef, Aft, Rs); -++do_op({blink,C,M}, Bef, Aft, Rs) -> -++ case over_paren(Bef, C, M) of -++ beep -> -++ {{[C|Bef], Aft}, [beep,{insert_chars, unicode, [C]}|Rs]}; -++ N -> {blink,N+1,{[C|Bef],Aft}, -++ [{move_rel,-(N+1)},{insert_chars, unicode,[C]}|Rs]} -++ end; -++do_op(auto_blink, Bef, Aft, Rs) -> -++ case over_paren_auto(Bef) of -++ {N, Paren} -> -++ {blink,N+1, -++ {[Paren|Bef], Aft},[{move_rel,-(N+1)},{insert_chars, unicode,[Paren]}|Rs]}; -++ % N is likely 0 -++ N -> {blink,N+1,{Bef,Aft}, -++ [{move_rel,-(N+1)}|Rs]} -++ end; -++do_op(forward_delete_char, Bef, [GC|Aft], Rs) -> -++ {{Bef,Aft},[{delete_chars,gc_len(GC)}|Rs]}; -++do_op(backward_delete_char, [GC|Bef], Aft, Rs) -> -++ {{Bef,Aft},[{delete_chars,-gc_len(GC)}|Rs]}; -++do_op(transpose_char, [C1,C2|Bef], [], Rs) -> -+ Len = gc_len(C1)+gc_len(C2), -+- {{LB, {[C2,C1|Bef],[]}, LA},[{put_chars, unicode,[C1,C2]},{move_rel,-Len}|Rs]}; -+-do_op(transpose_char, {LB,{[C2|Bef], [C1|Aft]},LA}, Rs) -> -++ {{[C2,C1|Bef],[]},[{put_chars, unicode,[C1,C2]},{move_rel,-Len}|Rs]}; -++do_op(transpose_char, [C2|Bef], [C1|Aft], Rs) -> -+ Len = gc_len(C2), -+- {{LB, {[C2,C1|Bef],Aft}, LA},[{put_chars, unicode,[C1,C2]},{move_rel,-Len}|Rs]}; -+-do_op(kill_word, {LB,{Bef, Aft0},LA}, Rs) -> -++ {{[C2,C1|Bef],Aft},[{put_chars, unicode,[C1,C2]},{move_rel,-Len}|Rs]}; -++do_op(kill_word, Bef, Aft0, Rs) -> -+ {Aft1,Kill0,N0} = over_non_word(Aft0, [], 0), -+ {Aft,Kill,N} = over_word(Aft1, Kill0, N0), -+ put(kill_buffer, reverse(Kill)), -+- {{LB, {Bef,Aft}, LA},[{delete_chars,N}|Rs]}; -+-do_op(backward_kill_word, {LB,{Bef0, Aft},LA}, Rs) -> -++ {{Bef,Aft},[{delete_chars,N}|Rs]}; -++do_op(backward_kill_word, Bef0, Aft, Rs) -> -+ {Bef1,Kill0,N0} = over_non_word(Bef0, [], 0), -+ {Bef,Kill,N} = over_word(Bef1, Kill0, N0), -+ put(kill_buffer, Kill), -+- {{LB,{Bef,Aft},LA},[{delete_chars,-N}|Rs]}; -+-do_op(kill_line, {LB, {Bef, Aft}, LA}, Rs) -> -++ {{Bef,Aft},[{delete_chars,-N}|Rs]}; -++do_op(kill_line, Bef, Aft, Rs) -> -+ put(kill_buffer, Aft), -+- {{LB, {Bef,[]}, LA},[{delete_chars,cp_len(Aft)}|Rs]}; -+-do_op(clear_line, _, Rs) -> -+- {redraw, {[], {[],[]},[]}, Rs}; -+-do_op(yank, {LB,{Bef, []},LA}, Rs) -> -++ {{Bef,[]},[{delete_chars,cp_len(Aft)}|Rs]}; -++do_op(yank, Bef, [], Rs) -> -+ Kill = get(kill_buffer), -+- {{LB, {reverse(Kill, Bef),[]}, LA},[{put_chars, unicode,Kill}|Rs]}; -+-do_op(yank, {LB,{Bef, Aft},LA}, Rs) -> -++ {{reverse(Kill, Bef),[]},[{put_chars, unicode,Kill}|Rs]}; -++do_op(yank, Bef, Aft, Rs) -> -+ Kill = get(kill_buffer), -+- {{LB, {reverse(Kill, Bef),Aft}, LA},[{insert_chars, unicode,Kill}|Rs]}; -+-do_op(forward_line, {_,_,[]} = MultiLine, Rs) -> -+- {MultiLine, Rs}; -+-do_op(forward_line, {LB,{Bef, Aft},[AL|LA]}, Rs) -> -+- CL = lists:reverse(Bef, Aft), -+- CursorPos = min(length(Bef), length(AL)), -+- {Bef1, Aft1} = lists:split(CursorPos, AL), -+- {{[CL|LB], {lists:reverse(Bef1), Aft1}, LA}, [{move_combo, -cp_len(Bef), 1, cp_len(Bef1)}|Rs]}; -+-do_op(backward_line, {[], _, _} = MultiLine, Rs) -> -+- {MultiLine, Rs}; -+-do_op(backward_line, {[BL|LB],{Bef, Aft},LA}, Rs) -> -+- CL = lists:reverse(Bef, Aft), -+- CursorPos = min(length(Bef), length(BL)), -+- {Bef1, Aft1} = lists:split(CursorPos, BL), -+- {{LB, {lists:reverse(Bef1), Aft1}, [CL|LA]},[{move_combo, -cp_len(Bef), -1, cp_len(Bef1)}|Rs]}; -+-do_op(forward_char, {LB,{Bef, []}, [AL|LA]}, Rs) -> -+- {{[lists:reverse(Bef)|LB],{[], string:to_graphemes(AL)}, LA}, [{move_combo, -cp_len(Bef), 1, 0}|Rs]}; -+-do_op(forward_char, {LB,{Bef, [C|Aft]},LA}, Rs) -> -+- {{LB,{[C|Bef],Aft},LA},[{move_rel,gc_len(C)}|Rs]}; -+-do_op(backward_char, {[BL|LB],{[], Aft},LA}, Rs) -> -+- {{LB,{lists:reverse(string:to_graphemes(BL)), []}, [Aft|LA]}, [{move_combo, 0, -1, cp_len(BL)}|Rs]}; -+-do_op(backward_char, {LB,{[C|Bef], Aft},LA}, Rs) -> -+- {{LB, {Bef,[C|Aft]}, LA},[{move_rel,-gc_len(C)}|Rs]}; -+-do_op(forward_word, {LB,{Bef0, []},[NextLine|LA]}, Rs) -> -+- {{[reverse(Bef0)|LB], {[], NextLine}, LA},[{move_combo, -cp_len(Bef0), 1, 0}|Rs]}; -+-do_op(forward_word, {LB,{Bef0, Aft0},LA}, Rs) -> -++ {{reverse(Kill, Bef),Aft},[{insert_chars, unicode,Kill}|Rs]}; -++do_op(forward_char, Bef, [C|Aft], Rs) -> -++ {{[C|Bef],Aft},[{move_rel,gc_len(C)}|Rs]}; -++do_op(backward_char, [C|Bef], Aft, Rs) -> -++ {{Bef,[C|Aft]},[{move_rel,-gc_len(C)}|Rs]}; -++do_op(forward_word, Bef0, Aft0, Rs) -> -+ {Aft1,Bef1,N0} = over_non_word(Aft0, Bef0, 0), -+- {Aft, Bef, N} = over_word(Aft1, Bef1, N0), -+- {{LB, {Bef,Aft}, LA},[{move_rel,N}|Rs]}; -+-do_op(backward_word, {[PrevLine|LB],{[], Aft0},LA}, Rs) -> -+- {{LB, {reverse(PrevLine), []}, [Aft0|LA]},[{move_combo, 0, -1, cp_len(PrevLine)}|Rs]}; -+-do_op(backward_word, {LB,{Bef0, Aft0},LA}, Rs) -> -++ {Aft,Bef,N} = over_word(Aft1, Bef1, N0), -++ {{Bef,Aft},[{move_rel,N}|Rs]}; -++do_op(backward_word, Bef0, Aft0, Rs) -> -+ {Bef1,Aft1,N0} = over_non_word(Bef0, Aft0, 0), -+ {Bef,Aft,N} = over_word(Bef1, Aft1, N0), -+- {{LB, {Bef,Aft}, LA},[{move_rel,-N}|Rs]}; -+-do_op(beginning_of_expression, {[],{[], Aft},LA}, Rs) -> -+- {{[], {[],Aft}, LA},Rs}; -+-do_op(beginning_of_expression, {LB,{Bef, Aft},LA}, Rs) -> -+- [First|Rest] = lists:reverse(LB) ++ [lists:reverse(Bef, Aft)], -+- {{[], {[],First}, Rest ++ LA},[{move_combo, -cp_len(Bef), -length(LB), 0}|Rs]}; -+-do_op(end_of_expression, {LB,{Bef, []},[]}, Rs) -> -+- {{LB, {Bef,[]}, []},Rs}; -+-do_op(end_of_expression, {LB,{Bef, Aft},LA}, Rs) -> -+- [Last|Rest] = lists:reverse(LA) ++ [lists:reverse(Bef, Aft)], -+- {{LB ++ Rest, {lists:reverse(Last),[]}, []},[{move_combo, -cp_len(Bef), length(LA), cp_len(Last)}|Rs]}; -+-do_op(beginning_of_line, {LB,{[_|_]=Bef, Aft},LA}, Rs) -> -+- {{LB, {[],reverse(Bef, Aft)}, LA},[{move_rel,-(cp_len(Bef))}|Rs]}; -+-do_op(beginning_of_line, {LB,{[], Aft},LA}, Rs) -> -+- {{LB, {[],Aft}, LA},Rs}; -+-do_op(end_of_line, {LB,{Bef, [_|_]=Aft},LA}, Rs) -> -+- {{LB, {reverse(Aft, Bef),[]}, LA},[{move_rel,cp_len(Aft)}|Rs]}; -+-do_op(end_of_line, {LB,{Bef, []},LA}, Rs) -> -+- {{LB, {Bef,[]}, LA},Rs}; -+-do_op(ctlu, {LB,{Bef, Aft},LA}, Rs) -> -++ {{Bef,Aft},[{move_rel,-N}|Rs]}; -++do_op(beginning_of_line, [_|_]=Bef, Aft, Rs) -> -++ {{[],reverse(Bef, Aft)},[{move_rel,-(cp_len(Bef))}|Rs]}; -++do_op(beginning_of_line, [], Aft, Rs) -> -++ {{[],Aft},Rs}; -++do_op(end_of_line, Bef, [_|_]=Aft, Rs) -> -++ {{reverse(Aft, Bef),[]},[{move_rel,cp_len(Aft)}|Rs]}; -++do_op(end_of_line, Bef, [], Rs) -> -++ {{Bef,[]},Rs}; -++do_op(ctlu, Bef, Aft, Rs) -> -+ put(kill_buffer, reverse(Bef)), -+- {{LB, {[], Aft}, LA}, [{delete_chars, -cp_len(Bef)} | Rs]}; -+-do_op(beep, {LB,{Bef, Aft},LA}, Rs) -> -+- {{LB,{Bef,Aft},LA},[beep|Rs]}; -+-do_op(_, {LB,{Bef, Aft},LA}, Rs) -> -+- {{LB,{Bef,Aft},LA},[beep|Rs]}. -+- -+-blink(beep, C, {LB, {Bef, Aft}, LA}, Rs) -> -+- {{LB,{[C|Bef], Aft},LA}, [beep,{insert_chars, unicode, [C]}|Rs]}; -+-blink({N, R}, C, MultiLine, Rs) -> -+- blink({N, R, C}, MultiLine, Rs). -+-%% same line -+-blink(beep, {LB,{Bef, Aft},LA}, Rs) -> -+- {{LB,{Bef, Aft},LA}, [beep|Rs]}; -+-blink({N, 0, Paren}, {LB, {Bef, Aft}, LA}, Rs) -> -+- MoveBackToParen = {move_rel,-N-1}, -+- MoveForwardToParen = {move_rel, N+1}, -+- {blink,[MoveForwardToParen],{LB,{[Paren|Bef],Aft},LA}, -+- [MoveBackToParen,{insert_chars, unicode,[Paren]}|Rs]}; -+-%% multiline -+-blink({N, R, Paren}, {LB,{Bef, Aft},LA}, Rs) -> -+- LengthToClosingParen = cp_len([Paren|Bef]), -+- LengthOpeningParen = cp_len(lists:nth(R,LB)) - N - 1, -+- MoveToOpeningParen = {move_combo, -LengthToClosingParen, -R, LengthOpeningParen}, -+- MoveToClosingParen = {move_combo, -LengthOpeningParen, R, LengthToClosingParen+1}, -+- {blink,[MoveToClosingParen],{LB,{[Paren|Bef],Aft},LA}, -+- [MoveToOpeningParen,{insert_chars, unicode,[Paren]}|Rs]}. -++ {{[], Aft}, [{delete_chars, -cp_len(Bef)} | Rs]}; -++do_op(beep, Bef, Aft, Rs) -> -++ {{Bef,Aft},[beep|Rs]}; -++do_op(_, Bef, Aft, Rs) -> -++ {{Bef,Aft},[beep|Rs]}. -+ -+ %% over_word(Chars, InitialStack, InitialCount) -> -+ %% {RemainingChars,CharStack,Count} -+@@ -512,6 +423,8 @@ blink({N, R, Paren}, {LB,{Bef, Aft},LA}, Rs) -> -+ %% {RemainingChars,CharStack,Count} -+ %% Step over word/non-word characters pushing the stepped over ones on -+ %% the stack. -++ -++ -+ over_word(Cs, Stack, N) -> -+ L = length([1 || $\' <- Cs]), -+ case L rem 2 of -+@@ -572,84 +485,80 @@ word_char(_) -> false. -+ %% do proper parentheses matching check. Paren has NOT been added. -+ -+ over_paren(Chars, Paren, Match) -> -+- over_paren(Chars, Paren, Match, 1, 1, 0, []). -+- -+- -+-over_paren([C,$$,$$|Cs], Paren, Match, D, N, R, L) -> -+- over_paren([C|Cs], Paren, Match, D, N+2, R, L); -+-over_paren([GC,$$|Cs], Paren, Match, D, N, R, L) -> -+- over_paren(Cs, Paren, Match, D, N+1+gc_len(GC), R, L); -+-over_paren([$\n|Cs], Paren, Match, D, _N, R, L) -> -+- over_paren(Cs, Paren, Match, D, 0, R+1, L); -+-over_paren([Match|_], _Paren, Match, 1, N, R, _) -> -+- {N, R}; -+-over_paren([Match|Cs], Paren, Match, D, N, R, [Match|L]) -> -+- over_paren(Cs, Paren, Match, D-1, N+1, R, L); -+-over_paren([Paren|Cs], Paren, Match, D, N, R, L) -> -+- over_paren(Cs, Paren, Match, D+1, N+1, R, [Match|L]); -+- -+-over_paren([$)|Cs], Paren, Match, D, N, R, L) -> -+- over_paren(Cs, Paren, Match, D, N+1, R, [$(|L]); -+-over_paren([$]|Cs], Paren, Match, D, N, R, L) -> -+- over_paren(Cs, Paren, Match, D, N+1, R, [$[|L]); -+-over_paren([$}|Cs], Paren, Match, D, N, R, L) -> -+- over_paren(Cs, Paren, Match, D, N+1, R, [${|L]); -+- -+-over_paren([$(|Cs], Paren, Match, D, N, R, [$(|L]) -> -+- over_paren(Cs, Paren, Match, D, N+1, R, L); -+-over_paren([$[|Cs], Paren, Match, D, N, R, [$[|L]) -> -+- over_paren(Cs, Paren, Match, D, N+1, R, L); -+-over_paren([${|Cs], Paren, Match, D, N, R, [${|L]) -> -+- over_paren(Cs, Paren, Match, D, N+1, R, L); -+- -+-over_paren([$(|_], _, _, _, _, _, _) -> -++ over_paren(Chars, Paren, Match, 1, 1, []). -++ -++ -++over_paren([C,$$,$$|Cs], Paren, Match, D, N, L) -> -++ over_paren([C|Cs], Paren, Match, D, N+2, L); -++over_paren([GC,$$|Cs], Paren, Match, D, N, L) -> -++ over_paren(Cs, Paren, Match, D, N+1+gc_len(GC), L); -++over_paren([Match|_], _Paren, Match, 1, N, _) -> -++ N; -++over_paren([Match|Cs], Paren, Match, D, N, [Match|L]) -> -++ over_paren(Cs, Paren, Match, D-1, N+1, L); -++over_paren([Paren|Cs], Paren, Match, D, N, L) -> -++ over_paren(Cs, Paren, Match, D+1, N+1, [Match|L]); -++ -++over_paren([$)|Cs], Paren, Match, D, N, L) -> -++ over_paren(Cs, Paren, Match, D, N+1, [$(|L]); -++over_paren([$]|Cs], Paren, Match, D, N, L) -> -++ over_paren(Cs, Paren, Match, D, N+1, [$[|L]); -++over_paren([$}|Cs], Paren, Match, D, N, L) -> -++ over_paren(Cs, Paren, Match, D, N+1, [${|L]); -++ -++over_paren([$(|Cs], Paren, Match, D, N, [$(|L]) -> -++ over_paren(Cs, Paren, Match, D, N+1, L); -++over_paren([$[|Cs], Paren, Match, D, N, [$[|L]) -> -++ over_paren(Cs, Paren, Match, D, N+1, L); -++over_paren([${|Cs], Paren, Match, D, N, [${|L]) -> -++ over_paren(Cs, Paren, Match, D, N+1, L); -++ -++over_paren([$(|_], _, _, _, _, _) -> -+ beep; -+-over_paren([$[|_], _, _, _, _, _, _) -> -++over_paren([$[|_], _, _, _, _, _) -> -+ beep; -+-over_paren([${|_], _, _, _, _, _, _) -> -++over_paren([${|_], _, _, _, _, _) -> -+ beep; -+ -+-over_paren([GC|Cs], Paren, Match, D, N, R, L) -> -+- over_paren(Cs, Paren, Match, D, N+gc_len(GC), R, L); -+-over_paren([], _, _, _, _, _, _) -> -+- beep. -++over_paren([GC|Cs], Paren, Match, D, N, L) -> -++ over_paren(Cs, Paren, Match, D, N+gc_len(GC), L); -++over_paren([], _, _, _, _, _) -> -++ 0. -+ -+ over_paren_auto(Chars) -> -+- over_paren_auto(Chars, 1, 1, 0, []). -+- -+- -+-over_paren_auto([C,$$,$$|Cs], D, N, R, L) -> -+- over_paren_auto([C|Cs], D, N+2, R, L); -+-over_paren_auto([GC,$$|Cs], D, N, R, L) -> -+- over_paren_auto(Cs, D, N+1+gc_len(GC), R, L); -+-over_paren_auto([$\n|Cs], D, _N, R, L) -> -+- over_paren_auto(Cs, D, 0, R+1, L); -+- -+-over_paren_auto([$(|_], _, N, R, []) -> -+- {N, R, $)}; -+-over_paren_auto([$[|_], _, N, R, []) -> -+- {N, R, $]}; -+-over_paren_auto([${|_], _, N, R, []) -> -+- {N, R, $}}; -+- -+-over_paren_auto([$)|Cs], D, N, R, L) -> -+- over_paren_auto(Cs, D, N+1, R, [$(|L]); -+-over_paren_auto([$]|Cs], D, N, R, L) -> -+- over_paren_auto(Cs, D, N+1, R, [$[|L]); -+-over_paren_auto([$}|Cs], D, N, R, L) -> -+- over_paren_auto(Cs, D, N+1, R, [${|L]); -+- -+-over_paren_auto([$(|Cs], D, N, R, [$(|L]) -> -+- over_paren_auto(Cs, D, N+1, R, L); -+-over_paren_auto([$[|Cs], D, N, R, [$[|L]) -> -+- over_paren_auto(Cs, D, N+1, R, L); -+-over_paren_auto([${|Cs], D, N, R, [${|L]) -> -+- over_paren_auto(Cs, D, N+1, R, L); -+- -+-over_paren_auto([GC|Cs], D, N, R, L) -> -+- over_paren_auto(Cs, D, N+gc_len(GC), R, L); -+-over_paren_auto([], _, _, _, _) -> -+- beep. -++ over_paren_auto(Chars, 1, 1, []). -++ -++ -++over_paren_auto([C,$$,$$|Cs], D, N, L) -> -++ over_paren_auto([C|Cs], D, N+2, L); -++over_paren_auto([GC,$$|Cs], D, N, L) -> -++ over_paren_auto(Cs, D, N+1+gc_len(GC), L); -++ -++over_paren_auto([$(|_], _, N, []) -> -++ {N, $)}; -++over_paren_auto([$[|_], _, N, []) -> -++ {N, $]}; -++over_paren_auto([${|_], _, N, []) -> -++ {N, $}}; -++ -++over_paren_auto([$)|Cs], D, N, L) -> -++ over_paren_auto(Cs, D, N+1, [$(|L]); -++over_paren_auto([$]|Cs], D, N, L) -> -++ over_paren_auto(Cs, D, N+1, [$[|L]); -++over_paren_auto([$}|Cs], D, N, L) -> -++ over_paren_auto(Cs, D, N+1, [${|L]); -++ -++over_paren_auto([$(|Cs], D, N, [$(|L]) -> -++ over_paren_auto(Cs, D, N+1, L); -++over_paren_auto([$[|Cs], D, N, [$[|L]) -> -++ over_paren_auto(Cs, D, N+1, L); -++over_paren_auto([${|Cs], D, N, [${|L]) -> -++ over_paren_auto(Cs, D, N+1, L); -++ -++over_paren_auto([GC|Cs], D, N, L) -> -++ over_paren_auto(Cs, D, N+gc_len(GC), L); -++over_paren_auto([], _, _, _) -> -++ 0. -+ -+ %% erase_line(Line) -+ %% erase_inp(Line) -+@@ -658,57 +567,40 @@ over_paren_auto([], _, _, _, _) -> -+ %% length_after(Line) -+ %% prompt(Line) -+ %% current_line(Line) -+-%% current_chars(Line) -+ %% Various functions for accessing bits of a line. -+ -+-erase_line() -> -+- [delete_line]. -+- -+-erase_inp({line,_, L,_}) -> -+- reverse(erase([], L, [])). -++erase_line({line,Pbs,{Bef,Aft},_}) -> -++ reverse(erase(Pbs, Bef, Aft, [])). -+ -+-erase_line(Rs) -> -+- [delete_line|Rs]. -++erase_inp({line,_,{Bef,Aft},_}) -> -++ reverse(erase([], Bef, Aft, [])). -+ -+-erase(Pbs, {_,{Bef, Aft},_}, Rs) -> -++erase(Pbs, Bef, Aft, Rs) -> -+ [{delete_chars,-cp_len(Pbs)-cp_len(Bef)},{delete_chars,cp_len(Aft)}|Rs]. -+ -+-redraw_line({line, Pbs, L,_}) -> -+- redraw(Pbs, L, []). -+- -+-multi_line_prompt(Pbs) -> -+- lists:duplicate(max(0,prim_tty:npwcwidthstring(Pbs)-3), $ )++".. ". -++redraw_line({line,Pbs,{Bef,Aft},_}) -> -++ reverse(redraw(Pbs, Bef, Aft, [])). -+ -+-redraw(Pbs, {_,{_,_},_}=L, Rs) -> -+- [{redraw_prompt, Pbs, multi_line_prompt(Pbs), L} |Rs]. -++redraw(Pbs, Bef, Aft, Rs) -> -++ [{move_rel,-cp_len(Aft)},{put_chars, unicode,reverse(Bef, Aft)},{put_chars, unicode,Pbs}|Rs]. -+ -+-chars_before({[],{Bef,_},_}) -> -+- Bef; -+-chars_before({LB,{Bef,_},_}) -> -+- lists:flatten(lists:join($\n, [Bef| [reverse(Line)|| Line <- LB]])). -+- -+-length_before({line,Pbs,{_,{Bef,_Aft},_},_}) -> -++length_before({line,Pbs,{Bef,_Aft},_}) -> -+ cp_len(Pbs) + cp_len(Bef). -+ -+-length_after({line,_,{_,{_Bef,Aft},_},_}) -> -++length_after({line,_,{_Bef,Aft},_}) -> -+ cp_len(Aft). -+ -+ prompt({line,Pbs,_,_}) -> -+ Pbs. -+ -+-current_chars({line,_,MultiLine,_}) -> -+- current_line(MultiLine). -+-current_line({line,_,MultiLine,_}) -> -+- current_line(MultiLine) ++ "\n"; -+-%% Convert a multiline tuple into a string with new lines -+-current_line({LinesBefore, {Before, After}, LinesAfter}) -> -+- CurrentLine = lists:reverse(Before, After), -+- unicode:characters_to_list(lists:flatten( -+- lists:filter( -+- fun (X) -> -+- X /= [] -+- end, -+- lists:join($\n, lists:reverse(LinesBefore) ++ [CurrentLine] ++ LinesAfter)))). -++current_line({line,_,{Bef, Aft},_}) -> -++ get_line(Bef, Aft ++ "\n"). -++ -++current_chars({line,_,{Bef,Aft},_}) -> -++ get_line(Bef, Aft). -++ -++get_line(Bef, Aft) -> -++ unicode:characters_to_list(reverse(Bef, Aft)). -+ -+ %% Grapheme length in codepoints -+ gc_len(CP) when is_integer(CP) -> 1; -+-- -+2.34.1 -+ --- -2.34.1 - diff --git a/support/docker/nerves_system_br/Dockerfile b/support/docker/nerves_system_br/Dockerfile index de644d1c..1bb54e24 100644 --- a/support/docker/nerves_system_br/Dockerfile +++ b/support/docker/nerves_system_br/Dockerfile @@ -1,4 +1,4 @@ -FROM hexpm/erlang:26.0.1-ubuntu-jammy-20230126 +FROM hexpm/erlang:26.0.2-ubuntu-jammy-20230126 LABEL maintainer="Nerves Project developers " \ vendor="NervesProject" \ description="Container with everything needed to build Nerves Systems"