-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 64fe6b0
Showing
17 changed files
with
410 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
_build |
Empty file.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Changes | ||
|
||
## 0.0.1 | ||
|
||
Initial release, including: | ||
|
||
* High-level `Terminal` module for controlling a terminal | ||
* Async-input with UTF-8 support in the `Stdin` module | ||
* Terminal `Profile`s for determining what color palettes are available | ||
* A `Color` module for parsing and working with RGB/ANSI/ANSI256 colors | ||
* A collection of 60 escape sequence functions in `Escape_seq` | ||
* a lot of room for improvement! | ||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
Copyright (c) 2023, Leandro Ostera | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# TTY | ||
|
||
TTY is a pure OCaml library for directly interacting with the | ||
terminal, including escape sequences, color profiles, colors, and | ||
consuming stdin. | ||
|
||
It is the main backend for [MintTea][minttea]. | ||
|
||
[minttea]: https://github.com/leostera/minttea | ||
|
||
## Getting Started | ||
|
||
``` | ||
$ opam install tty | ||
``` |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
(lang dune 3.11) | ||
|
||
(name tty) | ||
|
||
(generate_opam_files true) | ||
|
||
(source (github leostera/tty)) | ||
|
||
(authors "Leandro Ostera <[email protected]>") | ||
|
||
(maintainers "Leandro Ostera <[email protected]>") | ||
|
||
(license MIT) | ||
|
||
(package | ||
(name tty) | ||
(synopsis "A library for interacting with teletype and terminal emulators") | ||
(description "TTY is a library for directly interacting with teletypes and terminal emulators, including escape sequences, colors, and consuming stdin") | ||
(depends | ||
(ocaml (>= "5.1")) | ||
(dune (>= "3.11")) | ||
(uutf (>= "1.0.3"))) | ||
(tags (terminal ansi tty teletype utf8))) | ||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# This file is generated by dune, edit dune-project instead | ||
opam-version: "2.0" | ||
synopsis: "A library for interacting with teletype and terminal emulators" | ||
description: | ||
"TTY is a library for directly interacting with teletypes and terminal emulators, including escape sequences, colors, and consuming stdin" | ||
maintainer: ["Leandro Ostera <[email protected]>"] | ||
authors: ["Leandro Ostera <[email protected]>"] | ||
license: "MIT" | ||
tags: ["terminal" "ansi" "tty" "teletype" "utf8"] | ||
homepage: "https://github.com/leostera/tty" | ||
bug-reports: "https://github.com/leostera/tty/issues" | ||
depends: [ | ||
"ocaml" {>= "5.1"} | ||
"dune" {>= "3.11" & >= "3.11"} | ||
"uutf" {>= "1.0.3"} | ||
"odoc" {with-doc} | ||
] | ||
build: [ | ||
["dune" "subst"] {dev} | ||
[ | ||
"dune" | ||
"build" | ||
"-p" | ||
name | ||
"-j" | ||
jobs | ||
"@install" | ||
"@runtest" {with-test} | ||
"@doc" {with-doc} | ||
] | ||
] | ||
dev-repo: "git+https://github.com/leostera/tty.git" |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
type t = RGB of int * int * int | ANSI of int | ANSI256 of int | No_color | ||
|
||
exception Invalid_color of string | ||
exception Invalid_color_param of string | ||
exception Invalid_color_num of string * int | ||
|
||
let to_255 str = | ||
match int_of_string_opt ("0x" ^ str) with | ||
| None -> raise (Invalid_color_param str) | ||
| Some c -> c | ||
|
||
let rgb r g b = RGB (to_255 r, to_255 g, to_255 b) | ||
|
||
let rgb str = | ||
match String.to_seq str |> List.of_seq |> List.map (String.make 1) with | ||
| [ "#"; r1; r2; g1; g2; b1; b2 ] -> rgb (r1 ^ r2) (g1 ^ g2) (b1 ^ b2) | ||
| [ "#"; r1; g1; b1 ] -> rgb r1 g1 b1 | ||
| _ -> raise (Invalid_color str) | ||
|
||
let ansi i = ANSI i | ||
let ansi256 i = ANSI256 i | ||
let no_color = No_color | ||
|
||
let make str = | ||
if String.starts_with ~prefix:"#" str then rgb str | ||
else | ||
match int_of_string_opt str with | ||
| None -> raise (Invalid_color str) | ||
| Some i when i < 16 -> ansi i | ||
| Some i -> ansi256 i | ||
|
||
let to_escape_seq ~mode t = | ||
match t with | ||
| RGB (r, g, b) -> Format.sprintf "2;%d;%d;%d" r g b | ||
| ANSI c -> | ||
let bg_mod x = if mode = `bg then x + 10 else x in | ||
let c = if c < 8 then bg_mod c + 30 else bg_mod (c - 8) + 90 in | ||
Int.to_string c | ||
| ANSI256 c -> Format.sprintf "5;%d" c | ||
| No_color -> "" | ||
|
||
let is_no_color t = t = No_color | ||
let is_rgb t = match t with RGB _ -> true | _ -> false | ||
let is_ansi t = match t with ANSI _ -> true | _ -> false | ||
let is_ansi256 t = match t with ANSI256 _ -> true | _ -> false |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
type t = private | ||
| RGB of int * int * int | ||
| ANSI of int | ||
| ANSI256 of int | ||
| No_color | ||
|
||
val make : string -> t | ||
|
||
exception Invalid_color of string | ||
exception Invalid_color_param of string | ||
exception Invalid_color_num of string * int | ||
|
||
val no_color : t | ||
val is_no_color : t -> bool | ||
val is_rgb : t -> bool | ||
val is_ansi : t -> bool | ||
val is_ansi256 : t -> bool | ||
val to_escape_seq : mode:[> `bg | `fg ] -> t -> string |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
(library | ||
(public_name tty) | ||
(name tty) | ||
(libraries uutf unix)) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
let csi = "\x1b[" | ||
let reset_seq = "0" | ||
let bold_seq = "1" | ||
let faint_seq = "2" | ||
let italics_seq = "3" | ||
let underline_seq = "4" | ||
let blink_seq = "5" | ||
let reverse_seq = "7" | ||
let cross_out_seq = "9" | ||
let overline_seq = "53" | ||
let foreground_seq = "38" | ||
let background_seq = "48" | ||
let escape code () = Printf.printf "%s%s%!" csi code | ||
|
||
(* Cursor positioning. *) | ||
let cursor_up_seq x = escape (Printf.sprintf "%dA" x) | ||
let cursor_down_seq x = escape (Printf.sprintf "%dB" x) | ||
let cursor_forward_seq x = escape (Printf.sprintf "%dC" x) | ||
let cursor_back_seq x = escape (Printf.sprintf "%dD" x) | ||
let cursor_next_line_seq x = escape (Printf.sprintf "%dE" x) | ||
let cursor_previous_line_seq x = escape (Printf.sprintf "%dF" x) | ||
let cursor_horizontal_seq x = escape (Printf.sprintf "%dG" x) | ||
let cursor_position_seq x y = escape (Printf.sprintf "%d;%dH" x y) | ||
let erase_display_seq x = escape (Printf.sprintf "%dJ" x) | ||
let erase_line_seq x = escape (Printf.sprintf "%dK" x) | ||
let scroll_up_seq x = escape (Printf.sprintf "%dS" x) | ||
let scroll_down_seq x = escape (Printf.sprintf "%dT" x) | ||
let save_cursor_position_seq = escape "s" | ||
let restore_cursor_position_seq = escape "u" | ||
let change_scrolling_region_seq x y = escape (Printf.sprintf "%d;%dr" x y) | ||
let insert_line_seq x = escape (Printf.sprintf "%dL" x) | ||
let delete_line_seq x = escape (Printf.sprintf "%dM" x) | ||
|
||
(* Explicit values for EraseLineSeq. *) | ||
let erase_line_right_seq = escape "0K" | ||
let erase_line_left_seq = escape "1K" | ||
let erase_entire_line_seq = escape "2K" | ||
|
||
(* Mouse. *) | ||
let enable_mouse_press_seq = escape "?9h" | ||
let disable_mouse_press_seq = escape "?9l" | ||
let enable_mouse_seq = escape "?1000h" | ||
let disable_mouse_seq = escape "?1000l" | ||
let enable_mouse_hilite_seq = escape "?1001h" | ||
let disable_mouse_hilite_seq = escape "?1001l" | ||
let enable_mouse_cell_motion_seq = escape "?1002h" | ||
let disable_mouse_cell_motion_seq = escape "?1002l" | ||
let enable_mouse_all_motion_seq = escape "?1003h" | ||
let disable_mouse_all_motion_seq = escape "?1003l" | ||
let enable_mouse_extended_mode_seq = escape "?1006h" | ||
let disable_mouse_extended_mode_seq = escape "?1006l" | ||
let enable_mouse_pixels_mode_seq = escape "?1016h" | ||
let disable_mouse_pixels_mode_seq = escape "?1016l" | ||
|
||
(* Screen. *) | ||
let restore_screen_seq = escape "?47l" | ||
let save_screen_seq = escape "?47h" | ||
let alt_screen_seq = escape "?1049h" | ||
let exit_alt_screen_seq = escape "?1049l" | ||
|
||
(* Bracketed paste. *) | ||
let enable_bracketed_paste_seq = escape "?2004h" | ||
let disable_bracketed_paste_seq = escape "?2004l" | ||
let start_bracketed_paste_seq = escape "200~" | ||
let end_bracketed_paste_seq = escape "201~" | ||
|
||
(* Session. *) | ||
let set_window_title_seq s = escape (Printf.sprintf "2;%s" s) | ||
let set_foreground_color_seq s = escape (Printf.sprintf "10;%s" s) | ||
let set_background_color_seq s = escape (Printf.sprintf "11;%s" s) | ||
let set_cursor_color_seq s = escape (Printf.sprintf "12;%s" s) | ||
let show_cursor_seq = escape "?25h" | ||
let hide_cursor_seq = escape "?25l" |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
val csi : string | ||
val reset_seq : string | ||
val bold_seq : string | ||
val faint_seq : string | ||
val italics_seq : string | ||
val underline_seq : string | ||
val blink_seq : string | ||
val reverse_seq : string | ||
val cross_out_seq : string | ||
val overline_seq : string | ||
val foreground_seq : string | ||
val background_seq : string | ||
val alt_screen_seq : unit -> unit | ||
val change_scrolling_region_seq : int -> int -> unit -> unit | ||
val cursor_back_seq : int -> unit -> unit | ||
val cursor_down_seq : int -> unit -> unit | ||
val cursor_forward_seq : int -> unit -> unit | ||
val cursor_horizontal_seq : int -> unit -> unit | ||
val cursor_next_line_seq : int -> unit -> unit | ||
val cursor_position_seq : int -> int -> unit -> unit | ||
val cursor_previous_line_seq : int -> unit -> unit | ||
val cursor_up_seq : int -> unit -> unit | ||
val delete_line_seq : int -> unit -> unit | ||
val disable_bracketed_paste_seq : unit -> unit | ||
val disable_mouse_all_motion_seq : unit -> unit | ||
val disable_mouse_cell_motion_seq : unit -> unit | ||
val disable_mouse_extended_mode_seq : unit -> unit | ||
val disable_mouse_hilite_seq : unit -> unit | ||
val disable_mouse_pixels_mode_seq : unit -> unit | ||
val disable_mouse_press_seq : unit -> unit | ||
val disable_mouse_seq : unit -> unit | ||
val enable_bracketed_paste_seq : unit -> unit | ||
val enable_mouse_all_motion_seq : unit -> unit | ||
val enable_mouse_cell_motion_seq : unit -> unit | ||
val enable_mouse_extended_mode_seq : unit -> unit | ||
val enable_mouse_hilite_seq : unit -> unit | ||
val enable_mouse_pixels_mode_seq : unit -> unit | ||
val enable_mouse_press_seq : unit -> unit | ||
val enable_mouse_seq : unit -> unit | ||
val end_bracketed_paste_seq : unit -> unit | ||
val erase_display_seq : int -> unit -> unit | ||
val erase_entire_line_seq : unit -> unit | ||
val erase_line_left_seq : unit -> unit | ||
val erase_line_right_seq : unit -> unit | ||
val erase_line_seq : int -> unit -> unit | ||
val exit_alt_screen_seq : unit -> unit | ||
val hide_cursor_seq : unit -> unit | ||
val insert_line_seq : int -> unit -> unit | ||
val restore_cursor_position_seq : unit -> unit | ||
val restore_screen_seq : unit -> unit | ||
val save_cursor_position_seq : unit -> unit | ||
val save_screen_seq : unit -> unit | ||
val scroll_down_seq : int -> unit -> unit | ||
val scroll_up_seq : int -> unit -> unit | ||
val set_background_color_seq : string -> unit -> unit | ||
val set_cursor_color_seq : string -> unit -> unit | ||
val set_foreground_color_seq : string -> unit -> unit | ||
val set_window_title_seq : string -> unit -> unit | ||
val show_cursor_seq : unit -> unit | ||
val start_bracketed_paste_seq : unit -> unit |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
type t = No_color | ANSI | ANSI256 | True_color | ||
|
||
let from_env () = | ||
let term = Sys.getenv_opt "TERM" in | ||
let color_term = Sys.getenv_opt "COLORTERM" in | ||
let term_program = Sys.getenv_opt "TERM_PROGRAM" in | ||
|
||
let is_screen = | ||
match term with | ||
| Some term -> String.starts_with ~prefix:"screen" term | ||
| None -> false | ||
in | ||
|
||
let is_tmux = match term_program with Some "tmux" -> true | _ -> false in | ||
|
||
(* TODO(@leostera): String.contains "256color" "color" "ansi" *) | ||
let is_256color = false in | ||
let is_color = false in | ||
let is_ansi = false in | ||
|
||
match (term, color_term) with | ||
| _, Some "true" -> ANSI256 | ||
| _, Some "truecolor" when is_screen && not is_tmux -> ANSI256 | ||
| _, Some "truecolor" -> True_color | ||
| Some ("xterm-kitty" | "wezterm"), _ -> True_color | ||
| Some "linux", _ -> ANSI | ||
| Some _, _ when is_256color -> ANSI256 | ||
| Some _, _ when is_color || is_ansi -> ANSI | ||
| _ -> No_color | ||
|
||
let default = from_env () | ||
|
||
let convert profile color = | ||
match (color, profile) with | ||
| _, No_color -> Color.no_color | ||
| Color.No_color, _ -> Color.no_color | ||
| Color.ANSI _, _ -> color | ||
| Color.ANSI256 _, ANSI -> color | ||
| Color.ANSI256 _, _ -> color | ||
| Color.RGB _, ANSI -> color | ||
| Color.RGB _, ANSI256 -> color | ||
| Color.RGB _, True_color -> color |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
type t | ||
|
||
val from_env : unit -> t | ||
val default : t | ||
val convert : t -> Color.t -> Color.t |
Oops, something went wrong.