Something went wrong. Try again.
Measure the width of text in the terminal and build simple layouts!
Something went wrong. Try again.
2.8 kB · 91 lines
Erlang
at main
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192-module(tui_ffi).-export([tui_app/4]).
-behaviour(gen_event).-export([init/1, handle_event/2, handle_info/2, handle_call/2, terminate/2]).-export([run_read_loop/1]).
%% This implements tui_app using the new OTP 28 features.%% To try this out, build erlang from this branch (or what until the PR is merged):%% %% Branch: https://github.com/garazdawi/otp/blob/lukas/kernel/shell-improvements%% PR: https://github.com/erlang/otp/pull/8962%% %% Also, please heart the PR <3%% %% To be able to exit properly on CTRL+C, you have to invoke erlang with the +Bc flag:%% %% ERL_FLAGS="+Bc" gleam run -m human_rights%% %% Just `gleam run` also works, but will bring up the break handler menu on CTRL+C.%% If you abort, your terminal will still be somewhat broken; a `reset` fixes that.
tui_app(State, OnResize, OnData, View) -> io:setopts(standard_io, [binary, {encoding, utf8}]), ok = shell:start_interactive({noshell, raw}), io:put_chars(<<"\e[?1049h\e[?25l"/utf8>>), ok = gen_event:swap_sup_handler( erl_signal_server, {erl_signal_handler, []}, {tui_ffi, [self()]}), os:set_signal(sigwinch, handle), %% os:set_signal(sigterm, handle),
spawn_link(tui_ffi, run_read_loop, [self()]), loop(State, OnResize, OnData, View), io:put_chars(<<"\e[?25h\e[?1049l"/utf8>>), init:stop(), nil.
loop(State, OnResize, OnData, View) -> %% io:put_chars(<<"\e[0;0H"/utf8>>), io:put_chars(string:replace(View(State), <<"\n"/utf8>>, <<"\r\n"/utf8>>, all)), %% io:put_chars(unicode:characters_to_binary(integer_to_list(os:system_time()))), receive { data, Chars } -> case handle_input(Chars, State, OnData) of stop -> stop; NewState -> loop(NewState, OnResize, OnData, View) end;
{ signal, sigint } -> stop; { signal, sigterm } -> stop;
{ signal, sigwinch } -> {ok, Rows} = io:rows(), {ok, Cols} = io:columns(), NewState = OnResize(State, Rows, Cols), loop(NewState, OnResize, OnData, View) end.
handle_input(<<>>, State, _OnData) -> State;handle_input(<<3, _rest/bits>>, _State, _OnData) -> stop;handle_input(<<"q"/utf8, _rest/bits>>, _State, _OnData) -> stop;handle_input(Rest, State, OnData) -> OnData(State, Rest).
%% input handler
run_read_loop(Pid) -> Chars = io:get_chars("", 64), Pid ! { data, Chars }, run_read_loop(Pid).
%% signal handler
init({[Pid], _}) -> {ok, {Pid}}.
handle_event(Signal, {Pid} = State) -> Pid ! { signal, Signal }, {ok, State}.
handle_info(_, State) -> {ok, State}.
handle_call(_Request, State) -> {ok, ok, State}.
terminate(_Args, _State) -> ok.