Fortran · 3925 bytes Raw Blame History
1 module text_prompt_module
2 use iso_fortran_env, only: int32
3 use terminal_io_module
4 implicit none
5 private
6
7 public :: show_text_prompt, show_yes_no_prompt
8
9 contains
10
11 subroutine show_text_prompt(prompt_text, input_text, cancelled, screen_rows)
12 character(len=*), intent(in) :: prompt_text
13 character(len=*), intent(out) :: input_text
14 logical, intent(out) :: cancelled
15 integer(int32), intent(in) :: screen_rows
16 character(len=512) :: input_buffer
17 integer :: input_pos, ch
18
19 ! Initialize
20 input_buffer = ''
21 input_pos = 0
22 cancelled = .false.
23
24 ! Display prompt at bottom of screen
25 call terminal_move_cursor(screen_rows, 1)
26 ! Use ANSI escape sequence to clear line (more reliable than spaces)
27 call terminal_write(achar(27) // '[2K') ! Clear entire line
28 call terminal_move_cursor(screen_rows, 1)
29 call terminal_write(trim(prompt_text))
30 call terminal_show_cursor()
31
32 ! Input loop
33 do
34 ch = terminal_read_char()
35
36 if (ch == -1) then
37 ! No input, continue
38 cycle
39 else if (ch == 27) then ! ESC
40 ! Cancel
41 cancelled = .true.
42 input_text = ''
43 exit
44 else if (ch == 10 .or. ch == 13) then ! Enter
45 ! Accept input
46 input_text = input_buffer(1:input_pos)
47 exit
48 else if (ch == 127 .or. ch == 8) then ! Backspace/Delete
49 if (input_pos > 0) then
50 input_pos = input_pos - 1
51 ! Redraw line
52 call terminal_move_cursor(screen_rows, 1)
53 call terminal_write(achar(27) // '[2K') ! Clear entire line
54 call terminal_move_cursor(screen_rows, 1)
55 call terminal_write(trim(prompt_text) // input_buffer(1:input_pos))
56 end if
57 else if (ch >= 32 .and. ch <= 126) then ! Printable characters
58 if (input_pos < len(input_buffer)) then
59 input_pos = input_pos + 1
60 input_buffer(input_pos:input_pos) = achar(ch)
61 ! Write character
62 call terminal_write(achar(ch))
63 end if
64 end if
65 end do
66
67 call terminal_hide_cursor()
68 end subroutine show_text_prompt
69
70 subroutine show_yes_no_prompt(prompt_text, answer, cancelled, screen_rows)
71 character(len=*), intent(in) :: prompt_text
72 logical, intent(out) :: answer
73 logical, intent(out) :: cancelled
74 integer(int32), intent(in) :: screen_rows
75 integer :: ch
76
77 ! Initialize
78 cancelled = .false.
79 answer = .false.
80
81 ! Display prompt at bottom of screen
82 call terminal_move_cursor(screen_rows, 1)
83 call terminal_write(achar(27) // '[2K') ! Clear entire line
84 call terminal_move_cursor(screen_rows, 1)
85 call terminal_write(trim(prompt_text))
86 call terminal_show_cursor()
87
88 ! Input loop - wait for single y/n/esc keypress
89 do
90 ch = terminal_read_char()
91
92 if (ch == -1) then
93 ! No input, continue
94 cycle
95 else if (ch == 27) then ! ESC
96 ! Cancel
97 cancelled = .true.
98 exit
99 else if (ch == 121 .or. ch == 89) then ! 'y' or 'Y'
100 ! Yes
101 answer = .true.
102 exit
103 else if (ch == 110 .or. ch == 78) then ! 'n' or 'N'
104 ! No
105 answer = .false.
106 exit
107 end if
108 ! Ignore other characters, keep waiting for y/n/esc
109 end do
110
111 call terminal_hide_cursor()
112 end subroutine show_yes_no_prompt
113
114 end module text_prompt_module
115