Created
June 17, 2025 18:43
-
-
Save frankdugan3/5efd044e2390bb13912ffadef42f74d9 to your computer and use it in GitHub Desktop.
OTP 28 - RawModeVim
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| defmodule RawModeVim do | |
| @moduledoc """ | |
| This is a quick experiment with OTP 28's raw mode. | |
| """ | |
| def run do | |
| :shell.start_interactive({:noshell, :raw}) | |
| cursor_start() | |
| mode = normal_mode() | |
| loop(nil, mode) | |
| end | |
| def loop("q", :normal) do | |
| IO.write([IO.ANSI.clear(), "\r", IO.ANSI.cursor(0, 0)]) | |
| System.halt(0) | |
| end | |
| def loop("\e", mode) when mode != :normal do | |
| mode = normal_mode() | |
| loop(IO.getn("", 1), mode) | |
| end | |
| def loop("\r", mode) when mode in [:insert, :replace, :overwrite] do | |
| IO.write(["\n\r"]) | |
| loop(IO.getn("", 1), mode) | |
| end | |
| def loop(last, :replace) do | |
| IO.write([last]) | |
| mode = normal_mode() | |
| loop(IO.getn("", 1), mode) | |
| end | |
| def loop(last, mode) when mode in [:insert, :overwrite] do | |
| IO.write([last]) | |
| loop(IO.getn("", 1), mode) | |
| end | |
| def loop("j", :normal) do | |
| IO.write([IO.ANSI.cursor_down(1)]) | |
| loop(IO.getn("", 1), :normal) | |
| end | |
| def loop("k", :normal) do | |
| IO.write([IO.ANSI.cursor_up(1)]) | |
| loop(IO.getn("", 1), :normal) | |
| end | |
| def loop("h", :normal) do | |
| IO.write([IO.ANSI.cursor_left(1)]) | |
| loop(IO.getn("", 1), :normal) | |
| end | |
| def loop("l", :normal) do | |
| IO.write([IO.ANSI.cursor_right(1)]) | |
| loop(IO.getn("", 1), :normal) | |
| end | |
| def loop("R", :normal) do | |
| mode = overwrite_mode() | |
| loop(IO.getn("", 1), mode) | |
| end | |
| def loop("r", :normal) do | |
| mode = replace_mode() | |
| loop(IO.getn("", 1), mode) | |
| end | |
| def loop("i", :normal) do | |
| mode = insert_mode() | |
| loop(IO.getn("", 1), mode) | |
| end | |
| def loop("o", :normal) do | |
| IO.write("\e[E\e[L") | |
| mode = insert_mode() | |
| loop(IO.getn("", 1), mode) | |
| end | |
| def loop("O", :normal) do | |
| IO.write("\e[L") | |
| mode = insert_mode() | |
| loop(IO.getn("", 1), mode) | |
| end | |
| def loop("d", :normal) do | |
| # We can easily append keysequences -- nice! | |
| loop("d" <> IO.getn("", 1), :normal) | |
| end | |
| def loop("dd", :normal) do | |
| delete_line() | |
| loop(IO.getn("", 1), :normal) | |
| end | |
| def loop(_last, :normal) do | |
| loop(IO.getn("", 1), :normal) | |
| end | |
| defp cursor_start() do | |
| IO.write([IO.ANSI.cursor(0, 0)]) | |
| end | |
| defp delete_line() do | |
| # This causes the modeline to move out of correct position, since there's no distinction between the screen and a "buffer" | |
| IO.write("\e[M") | |
| end | |
| defp set_modeline(terminal) do | |
| mode = terminal.mode |> Atom.to_string() |> String.upcase() | |
| {:ok, row} = :io.rows() | |
| {bg, fg} = | |
| case terminal.mode do | |
| :insert -> {IO.ANSI.green_background(), IO.ANSI.black()} | |
| :replace -> {IO.ANSI.yellow_background(), IO.ANSI.black()} | |
| :overwrite -> {IO.ANSI.red_background(), IO.ANSI.black()} | |
| _ -> {IO.ANSI.cyan_background(), IO.ANSI.black()} | |
| end | |
| write_preserving( | |
| [bg, fg, "\e[2K#{mode}", IO.ANSI.reset()], | |
| row, | |
| 0 | |
| ) | |
| end | |
| defp write_preserving(text, row, column) do | |
| IO.write("\e[s\e[#{row};#{column}H") | |
| IO.write(text) | |
| IO.write("\e[u") | |
| end | |
| defp insert_mode do | |
| set_modeline(%{mode: :insert}) | |
| IO.write(["\e[4h", "\e[5 q"]) | |
| :insert | |
| end | |
| defp overwrite_mode do | |
| set_modeline(%{mode: :overwrite}) | |
| IO.write(["\e[4l", "\e[1 q"]) | |
| :overwrite | |
| end | |
| defp replace_mode do | |
| set_modeline(%{mode: :replace}) | |
| IO.write(["\e[4l", "\e[1 q"]) | |
| :replace | |
| end | |
| defp normal_mode do | |
| set_modeline(%{mode: :normal}) | |
| IO.write(["\e[4l", "\e[2 q"]) | |
| :normal | |
| end | |
| end | |
| RawModeVim.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment