英文:
I want to deal with the screen flickering when I hold down the arrow keys
问题
我使用了OCaml并创建了一个命令行工具。
以下是我编写的代码。
主要函数是[list_question],它接受当前索引和字符串列表,并返回所选项。
我刚开始学习函数类型,如果有关如何更好地完成此任务的建议,将不胜感激。
我目前的目标是防止屏幕闪烁!
(* 语言列表 *)
let languages = ["Java"; "C#"; "C++"; "C"; "Python"; "Ruby"; "Perl";]
let get1char =
let termio = Unix.tcgetattr Unix.stdin in
let () =
termio.Unix.c_icanon <- false;
termio.Unix.c_vmin <- 1;
termio.Unix.c_vtime <- 0;
termio.Unix.c_echo <- false;
Unix.tcsetattr Unix.stdin Unix.TCSADRAIN termio
in
fun () -> input_char stdin
let is_enter c = Char.code c = 10 (* ASCII码表示的换行符 *)
let read_arrow_key () =
let esc = get1char() in
if is_enter esc then
Some "Enter"
else
if esc = '\027' then (* 转义字符 *)
let lb = get1char() in
if lb = '[' then (* 左方括号 *)
let c = get1char() in
match c with
| 'A' -> Some "Up"
| 'B' -> Some "Down"
| 'C' -> Some "Right"
| 'D' -> Some "Left"
| _ -> None
else
None
else
None
let clear_screen () =
print_endline "\027[2J \027[1;1H"
let prevIndex currentIndex listLength =
match currentIndex with
| 1 -> listLength
| _ -> currentIndex - 1
let nextIndex currentIndex listLength =
if currentIndex = listLength then
1
else
currentIndex + 1
let next_index current_index nextOrPrev list_length =
if nextOrPrev then
nextIndex current_index list_length
else
prevIndex current_index list_length
let rec list_question (num : int) (list : string list) =
let selected = ref num in
let rec print_list list index =
if index = !selected then
print_endline ("\027[32m❯\027[0m" ^ string_of_int index ^ ":" ^ List.nth list (index - 1))
else
print_endline (" " ^ string_of_int index ^ ":" ^ List.nth list (index - 1));
if index < List.length list then
print_list list (index + 1)
in
clear_screen ();
print_endline "Choose your favorite language:";
print_list languages 1;
let key = read_arrow_key () in
match key with
| Some "Up" | Some "Left" ->
selected := next_index !selected false (List.length languages);
print_int !selected;
print_list languages 1;
list_question !selected list
| Some "Down" | Some "Right" ->
selected := next_index !selected true (List.length languages);
print_list languages 1;
list_question !selected list
| Some "Enter" ->
List.nth languages (!selected - 1)
| _ ->
list_question !selected list
let sss = list_question 1 languages ;;
print_string sss;;
我已经尝试更改ANSI转义代码,但没有改进。我认为在重新绘制时有一些问题。
英文:
I use ocaml and have created a cli tool.
Below is the code I wrote.
The main function is [list_question], which takes the current index and list of strings and returns the selected item.
I am just starting to learn about function types, so any advice on how to do this better would be appreciated.
My current goal is to keep the screen from flickering!
(* language list *)
let languages = ["Java"; "C#"; "C++"; "C"; "Python"; "Ruby"; "Perl";]
let get1char =
let termio = Unix.tcgetattr Unix.stdin in
let () =
termio.Unix.c_icanon <- false;
termio.Unix.c_vmin <- 1;
termio.Unix.c_vtime <- 0;
termio.Unix.c_echo <- false;
Unix.tcsetattr Unix.stdin Unix.TCSADRAIN termio
in
fun () -> input_char stdin
let is_enter c = Char.code c = 10 (* ASCII code for '\n' *)
let read_arrow_key () =
let esc = get1char() in
if is_enter esc then
Some "Enter"
else
if esc = '\027' then (* escape character *)
let lb = get1char() in
if lb = '[' then (* left bracket *)
let c = get1char() in
match c with
| 'A' -> Some "Up"
| 'B' -> Some "Down"
| 'C' -> Some "Right"
| 'D' -> Some "Left"
| _ -> None
else
None
else
None
let clear_screen () =
print_endline "\027[2J \027[1;1H"
let prevIndex currentIndex listLength =
match currentIndex with
| 1 -> listLength
| _ -> currentIndex - 1
let nextIndex currentIndex listLength =
if currentIndex = listLength then
1
else
currentIndex + 1
let next_index current_index nextOrPrev list_length =
if nextOrPrev then
nextIndex current_index list_length
else
prevIndex current_index list_length
let rec list_question (num : int) (list : string list) =
let selected = ref num in
let rec print_list list index =
if index = !selected then
print_endline ("\027[32m❯\027[0m" ^ string_of_int index ^ ":" ^ List.nth list (index - 1))
else
print_endline (" " ^ string_of_int index ^ ":" ^ List.nth list (index - 1));
if index < List.length list then
print_list list (index + 1)
in
clear_screen ();
print_endline "Choose your favorite language:";
print_list languages 1;
let key = read_arrow_key () in
match key with
| Some "Up" | Some "Left" ->
selected := next_index !selected false (List.length languages);
print_int !selected;
print_list languages 1;
list_question !selected list
| Some "Down" | Some "Right" ->
selected := next_index !selected true (List.length languages);
print_list languages 1;
list_question !selected list
| Some "Enter" ->
List.nth languages (!selected - 1)
| _ ->
list_question !selected list
let sss = list_question 1 languages ;;
print_string sss;;
I have tried changing the code for ansi escape but no improvement. I think there is something wrong with the process when it is redrawn.
答案1
得分: 1
以下是翻译好的内容:
"The flickering was improved by grouping them into a single string before outputting them, instead of displaying them one line at a time."
"将它们分组成一个单独的字符串,而不是逐行显示,从而改善了闪烁。"
"The following is the improved code."
"以下是改进后的代码。"
(* language array... *)
let languages = ["Java"; "C#"; "C++"; "C"; "Python"; "Ruby"; "Perl";]
(* util: *)
let get_1_char =
let termio = Unix.tcgetattr Unix.stdin in
let () =
termio.Unix.c_icanon <- false;
termio.Unix.c_vmin <- 1;
termio.Unix.c_vtime <- 0;
termio.Unix.c_echo <- false;
Unix.tcsetattr Unix.stdin Unix.TCSADRAIN termio
in
fun () -> input_char stdin
let is_enter c = Char.code c = 10 (* ASCII code for '\n' *)
let read_arrow_key () =
let esc = get_1_char() in
if is_enter esc then
Some "Enter"
else
if esc = '\027' then (* escape character *)
let lb = get_1_char() in
if lb = '[' then (* left bracket *)
let c = get_1_char() in
match c with
| 'A' -> Some "Up"
| 'B' -> Some "Down"
| 'C' -> Some "Right"
| 'D' -> Some "Left"
| _ -> None
else
None
else
None
let clear_screen () =
print_endline "\027[1;1H\027[2J"
let prevIndex currentIndex listLength =
match currentIndex with
| 1 -> listLength
| _ -> currentIndex - 1
let next_index currentIndex listLength =
if currentIndex = listLength then
1
else
currentIndex + 1
let get_index current_index nextOrPrev list_length =
if nextOrPrev then
next_index current_index list_length
else
prevIndex current_index list_length
(*
print_list function
Takes a list and currentIndex.
Separates each line with \n and returns a single string.
*)
let list_to_string (list:string list) (currentIndex:int) =
let rec loop list currentIndex index result =
match list with
| [] -> result
| head :: tail ->
if index = currentIndex then
loop tail currentIndex (index + 1) (result ^ "\027[32m❯\027[0m" ^ string_of_int index ^ ":" ^ head ^ "\n")
else
loop tail currentIndex (index + 1) (result ^ " " ^ string_of_int index ^ ":" ^ head ^ "\n")
in
print_endline "Choose your favorite language:";
print_endline "Use arrow keys to navigate, Enter to select.";
print_endline (loop list currentIndex 1 "")
let rec list_question (num : int) (list : string list) =
let selected = ref num in
let key = read_arrow_key () in
match key with
| Some "Up" | Some "Left" ->
clear_screen ();
selected := get_index !selected false (List.length list);
list_to_string list !selected;
list_question !selected list
| Some "Down" | Some "Right" ->
clear_screen ();
selected := get_index !selected true (List.length list);
list_to_string list !selected;
list_question !selected list
| Some "Enter" ->
List.nth list (!selected - 1)
| _ ->
list_question !selected list;;
clear_screen();;
list_to_string languages 1;;
let result_string = list_question 1 languages ;;
print_string result_string;;
英文:
The flickering was improved by grouping them into a single string before outputting them, instead of displaying them one line at a time.
The following is the improved code.
(* language array... *)
let languages = ["Java"; "C#"; "C++"; "C"; "Python"; "Ruby"; "Perl";]
(* util: *)
let get_1_char =
let termio = Unix.tcgetattr Unix.stdin in
let () =
termio.Unix.c_icanon <- false;
termio.Unix.c_vmin <- 1;
termio.Unix.c_vtime <- 0;
termio.Unix.c_echo <- false;
Unix.tcsetattr Unix.stdin Unix.TCSADRAIN termio
in
fun () -> input_char stdin
let is_enter c = Char.code c = 10 (* ASCII code for '\n' *)
let read_arrow_key () =
let esc = get_1_char() in
if is_enter esc then
Some "Enter"
else
if esc = '\027' then (* escape character *)
let lb = get_1_char() in
if lb = '[' then (* left bracket *)
let c = get_1_char() in
match c with
| 'A' -> Some "Up"
| 'B' -> Some "Down"
| 'C' -> Some "Right"
| 'D' -> Some "Left"
| _ -> None
else
None
else
None
let clear_screen () =
print_endline "\027[1;1H\027[2J"
let prevIndex currentIndex listLength =
match currentIndex with
| 1 -> listLength
| _ -> currentIndex - 1
let next_index currentIndex listLength =
if currentIndex = listLength then
1
else
currentIndex + 1
let get_index current_index nextOrPrev list_length =
if nextOrPrev then
next_index current_index list_length
else
prevIndex current_index list_length
(*
print_list関数
listとcurrentIndexを受け取る。
1行ずつ\nで改行し、ひとつの文字列を返す。
*)
let list_to_string (list:string list) (currentIndex:int) =
let rec loop list currentIndex index result =
match list with
| [] -> result
| head :: tail ->
if index = currentIndex then
loop tail currentIndex (index + 1) (result ^ "\027[32m❯\027[0m" ^ string_of_int index ^ ":" ^ head ^ "\n")
else
loop tail currentIndex (index + 1) (result ^ " " ^ string_of_int index ^ ":" ^ head ^ "\n")
in
print_endline "Choose your favorite language:";
print_endline "Use arrow keys to navigate, Enter to select.";
print_endline (loop list currentIndex 1 "")
let rec list_question (num : int) (list : string list) =
let selected = ref num in
let key = read_arrow_key () in
match key with
| Some "Up" | Some "Left" ->
clear_screen ();
selected := get_index !selected false (List.length list);
list_to_string list !selected;
list_question !selected list
| Some "Down" | Some "Right" ->
clear_screen ();
selected := get_index !selected true (List.length list);
list_to_string list !selected;
list_question !selected list
| Some "Enter" ->
List.nth list (!selected - 1)
| _ ->
list_question !selected list;;
clear_screen();;
list_to_string languages 1;;
let result_string = list_question 1 languages ;;
print_string result_string;;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论