Skip to content

Commit

Permalink
Ratatouille example (wojtekmach#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
mhanberg authored Jul 25, 2022
1 parent b7e704a commit 3aa9fb8
Showing 1 changed file with 128 additions and 0 deletions.
128 changes: 128 additions & 0 deletions ratatouille.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
Mix.install([:ratatouille])

defmodule Main do
def main do
# there isn't a way to return output from the tui, so we use some global state
Agent.start_link(fn -> nil end, name: :capture_proc)

Ratatouille.run(RatatouilleSelector,
quit_events: [
{:key, Ratatouille.Constants.key(:ctrl_c)},
{:key, Ratatouille.Constants.key(:esc)}
]
)

selection = Agent.get(:capture_proc, & &1)

IO.puts(selection)
end
end

defmodule RatatouilleSelector do
@behaviour Ratatouille.App

import Ratatouille.View
import Ratatouille.Constants

@up [key(:ctrl_p), key(:arrow_up)]
@down [key(:ctrl_n), key(:arrow_down)]
@enter key(:enter)

def init(%{window: %{height: height}}) do
lines = ~w(foo bar baz)

%{
lines: lines,
selected_row: 0,
height: height - 1
}
end

def update(%{lines: lines} = model, msg) do
model
|> then(&on_arrow_pressed(msg, lines, &1))
|> then(&on_enter_pressed(msg, &1))
end

def render(%{lines: lines, selected_row: selected_row}) do
view do
viewport do
for {line, idx} <- Enum.with_index(lines) do
row do
column size: 12 do
label do
arrow(idx == selected_row)
gutter(idx == selected_row)

line(line, %{selected?: idx == selected_row})
end
end
end
end
end
end
end

defp line(l, %{selected?: true}) do
text(content: l, color: :black, background: :white)
end

defp line(l, %{selected?: false}) do
text(content: l, color: :default, background: :default)
end

defp gutter(true) do
text(content: " ", background: :white)
end

defp gutter(false) do
text(content: " ", background: :default)
end

defp arrow(true) do
text(content: ">", color: :red, background: :white)
end

defp arrow(false) do
text(content: " ", background: :white)
end

def on_arrow_pressed(msg, lines, model) do
case msg do
{:event, %{key: key}} when key in @up ->
%{model | selected_row: max(model.selected_row - 1, 0)}

{:event, %{key: key}} when key in @down ->
%{model | selected_row: min(model.selected_row + 1, length(lines) - 1)}

_ ->
model
end
end

def on_enter_pressed(msg, model) do
case msg do
{:event, %{key: @enter}} ->
word =
model.lines
|> Enum.with_index(fn f, i -> {i, f} end)
|> then(&Map.new(&1)[model.selected_row])

Agent.update(:capture_proc, fn _ -> word end)

quit()

model

_ ->
model
end
end

defp quit() do
# we fake a keystroke to quit the tui
send(self(), {:event, %{key: key(:esc)}})
end
end

Main.main()

0 comments on commit 3aa9fb8

Please sign in to comment.