Fortran · 6198 bytes Raw Blame History
1 module mock_terminal_module
2 use iso_fortran_env, only: output_unit
3 implicit none
4 private
5
6 public :: mock_init, mock_cleanup, mock_reset
7 public :: mock_queue_input, mock_queue_key_sequence
8 public :: mock_get_output, mock_get_cursor_position
9 public :: mock_read_char, mock_input_available
10 public :: mock_terminal_write
11
12 ! Mock terminal state
13 character(len=:), allocatable :: output_buffer
14 integer, allocatable :: input_queue(:)
15 integer :: input_pos = 0
16 integer :: input_size = 0
17 integer :: cursor_row = 1
18 integer :: cursor_col = 1
19 integer :: screen_rows = 24
20 integer :: screen_cols = 80
21 logical :: raw_mode = .false.
22
23 contains
24
25 subroutine mock_init(rows, cols)
26 integer, intent(in), optional :: rows, cols
27
28 if (present(rows)) screen_rows = rows
29 if (present(cols)) screen_cols = cols
30
31 call mock_reset()
32 end subroutine mock_init
33
34 subroutine mock_cleanup()
35 if (allocated(output_buffer)) deallocate(output_buffer)
36 if (allocated(input_queue)) deallocate(input_queue)
37 end subroutine mock_cleanup
38
39 subroutine mock_reset()
40 ! Reset all state
41 if (allocated(output_buffer)) deallocate(output_buffer)
42 if (allocated(input_queue)) deallocate(input_queue)
43
44 allocate(character(len=0) :: output_buffer)
45 allocate(input_queue(1000))
46 input_pos = 0
47 input_size = 0
48 cursor_row = 1
49 cursor_col = 1
50 end subroutine mock_reset
51
52 subroutine mock_queue_input(text)
53 character(len=*), intent(in) :: text
54 integer :: i
55
56 do i = 1, len(text)
57 if (input_size < size(input_queue)) then
58 input_size = input_size + 1
59 input_queue(input_size) = iachar(text(i:i))
60 end if
61 end do
62 end subroutine mock_queue_input
63
64 subroutine mock_queue_key_sequence(key_name)
65 character(len=*), intent(in) :: key_name
66
67 select case(key_name)
68 case('up')
69 call queue_escape_sequence([27, 91, 65])
70 case('down')
71 call queue_escape_sequence([27, 91, 66])
72 case('right')
73 call queue_escape_sequence([27, 91, 67])
74 case('left')
75 call queue_escape_sequence([27, 91, 68])
76 case('home')
77 call queue_escape_sequence([27, 91, 72])
78 case('end')
79 call queue_escape_sequence([27, 91, 70])
80 case('pageup')
81 call queue_escape_sequence([27, 91, 53, 126])
82 case('pagedown')
83 call queue_escape_sequence([27, 91, 54, 126])
84 case('enter')
85 input_size = input_size + 1
86 input_queue(input_size) = 10
87 case('tab')
88 input_size = input_size + 1
89 input_queue(input_size) = 9
90 case('backspace')
91 input_size = input_size + 1
92 input_queue(input_size) = 127
93 case('delete')
94 call queue_escape_sequence([27, 91, 51, 126])
95 case('ctrl-a')
96 input_size = input_size + 1
97 input_queue(input_size) = 1
98 case('ctrl-e')
99 input_size = input_size + 1
100 input_queue(input_size) = 5
101 case('ctrl-k')
102 input_size = input_size + 1
103 input_queue(input_size) = 11
104 case('ctrl-u')
105 input_size = input_size + 1
106 input_queue(input_size) = 21
107 case('ctrl-s')
108 input_size = input_size + 1
109 input_queue(input_size) = 19
110 case('ctrl-q')
111 input_size = input_size + 1
112 input_queue(input_size) = 17
113 case('ctrl-x')
114 input_size = input_size + 1
115 input_queue(input_size) = 24
116 case('ctrl-c')
117 input_size = input_size + 1
118 input_queue(input_size) = 3
119 case('ctrl-v')
120 input_size = input_size + 1
121 input_queue(input_size) = 22
122 case('ctrl-z')
123 input_size = input_size + 1
124 input_queue(input_size) = 26
125 case('ctrl-y')
126 input_size = input_size + 1
127 input_queue(input_size) = 25
128 case('ctrl-d')
129 input_size = input_size + 1
130 input_queue(input_size) = 4
131 case('ctrl-j')
132 input_size = input_size + 1
133 input_queue(input_size) = 10
134 case('ctrl-l')
135 input_size = input_size + 1
136 input_queue(input_size) = 12
137 case('ctrl-t')
138 input_size = input_size + 1
139 input_queue(input_size) = 20
140 case('esc')
141 input_size = input_size + 1
142 input_queue(input_size) = 27
143 end select
144 end subroutine mock_queue_key_sequence
145
146 subroutine queue_escape_sequence(seq)
147 integer, intent(in) :: seq(:)
148 integer :: i
149
150 do i = 1, size(seq)
151 if (input_size < size(input_queue)) then
152 input_size = input_size + 1
153 input_queue(input_size) = seq(i)
154 end if
155 end do
156 end subroutine queue_escape_sequence
157
158 function mock_input_available() result(available)
159 logical :: available
160 available = (input_pos < input_size)
161 end function mock_input_available
162
163 function mock_read_char() result(ch)
164 integer :: ch
165
166 if (input_pos < input_size) then
167 input_pos = input_pos + 1
168 ch = input_queue(input_pos)
169 else
170 ch = -1 ! No input available
171 end if
172 end function mock_read_char
173
174 subroutine mock_terminal_write(text)
175 character(len=*), intent(in) :: text
176 output_buffer = output_buffer // text
177 end subroutine mock_terminal_write
178
179 function mock_get_output() result(output)
180 character(len=:), allocatable :: output
181 if (allocated(output_buffer)) then
182 output = output_buffer
183 else
184 allocate(character(len=0) :: output)
185 end if
186 end function mock_get_output
187
188 subroutine mock_get_cursor_position(row, col)
189 integer, intent(out) :: row, col
190 row = cursor_row
191 col = cursor_col
192 end subroutine mock_get_cursor_position
193
194 end module mock_terminal_module