Fortran · 13239 bytes Raw Blame History
1 module signature_tooltip_module
2 use iso_fortran_env, only: int32
3 use terminal_io_module, only: terminal_move_cursor, terminal_write
4 implicit none
5 private
6
7 public :: signature_tooltip_t
8 public :: init_signature_tooltip, cleanup_signature_tooltip
9 public :: show_signature_tooltip, hide_signature_tooltip
10 public :: is_signature_tooltip_visible, handle_signature_response
11 public :: set_active_parameter
12
13 ! Parameter information
14 type :: parameter_info_t
15 character(len=:), allocatable :: label
16 character(len=:), allocatable :: documentation
17 end type parameter_info_t
18
19 ! Signature information
20 type :: signature_info_t
21 character(len=:), allocatable :: label
22 character(len=:), allocatable :: documentation
23 type(parameter_info_t), allocatable :: parameters(:)
24 integer :: num_parameters = 0
25 end type signature_info_t
26
27 ! Signature tooltip
28 type :: signature_tooltip_t
29 logical :: visible = .false.
30 integer :: row = 1
31 integer :: col = 1
32
33 ! Signature data
34 type(signature_info_t), allocatable :: signatures(:)
35 integer :: num_signatures = 0
36 integer :: active_signature = 1
37 integer :: active_parameter = 0
38
39 ! Display settings
40 integer :: max_width = 80
41 end type signature_tooltip_t
42
43 contains
44
45 subroutine init_signature_tooltip(tooltip)
46 type(signature_tooltip_t), intent(out) :: tooltip
47
48 tooltip%visible = .false.
49 tooltip%num_signatures = 0
50 tooltip%active_signature = 1
51 tooltip%active_parameter = 0
52 tooltip%max_width = 80
53 end subroutine init_signature_tooltip
54
55 subroutine cleanup_signature_tooltip(tooltip)
56 type(signature_tooltip_t), intent(inout) :: tooltip
57 call clear_signatures(tooltip)
58 tooltip%visible = .false.
59 end subroutine cleanup_signature_tooltip
60
61 subroutine clear_signatures(tooltip)
62 type(signature_tooltip_t), intent(inout) :: tooltip
63 integer :: i, j
64
65 if (allocated(tooltip%signatures)) then
66 do i = 1, tooltip%num_signatures
67 if (allocated(tooltip%signatures(i)%label)) &
68 deallocate(tooltip%signatures(i)%label)
69 if (allocated(tooltip%signatures(i)%documentation)) &
70 deallocate(tooltip%signatures(i)%documentation)
71 if (allocated(tooltip%signatures(i)%parameters)) then
72 do j = 1, tooltip%signatures(i)%num_parameters
73 if (allocated(tooltip%signatures(i)%parameters(j)%label)) &
74 deallocate(tooltip%signatures(i)%parameters(j)%label)
75 if (allocated(tooltip%signatures(i)%parameters(j)%documentation)) &
76 deallocate(tooltip%signatures(i)%parameters(j)%documentation)
77 end do
78 deallocate(tooltip%signatures(i)%parameters)
79 end if
80 end do
81 deallocate(tooltip%signatures)
82 end if
83
84 tooltip%num_signatures = 0
85 tooltip%active_signature = 1
86 tooltip%active_parameter = 0
87 end subroutine clear_signatures
88
89 subroutine show_signature_tooltip(tooltip, row, col)
90 type(signature_tooltip_t), intent(inout) :: tooltip
91 integer, intent(in) :: row, col
92
93 tooltip%row = row
94 tooltip%col = col
95 tooltip%visible = .true.
96 end subroutine show_signature_tooltip
97
98 subroutine hide_signature_tooltip(tooltip)
99 type(signature_tooltip_t), intent(inout) :: tooltip
100 tooltip%visible = .false.
101 end subroutine hide_signature_tooltip
102
103 function is_signature_tooltip_visible(tooltip) result(visible)
104 type(signature_tooltip_t), intent(in) :: tooltip
105 logical :: visible
106 visible = tooltip%visible
107 end function is_signature_tooltip_visible
108
109 subroutine set_active_parameter(tooltip, param_index)
110 type(signature_tooltip_t), intent(inout) :: tooltip
111 integer, intent(in) :: param_index
112 tooltip%active_parameter = param_index
113 end subroutine set_active_parameter
114
115 ! UNUSED: Render signature tooltip with parameter highlighting
116 ! Kept for potential future use
117 ! subroutine render_signature_tooltip(tooltip)
118 ! type(signature_tooltip_t), intent(in) :: tooltip
119 ! integer :: display_row, sig_idx
120 ! character(len=512) :: line
121 ! character(len=256) :: label
122 ! integer :: param_start, param_end, i
123 !
124 ! if (.not. tooltip%visible .or. tooltip%num_signatures == 0) return
125 !
126 ! sig_idx = tooltip%active_signature
127 ! if (sig_idx < 1 .or. sig_idx > tooltip%num_signatures) return
128 !
129 ! display_row = tooltip%row
130 !
131 ! ! Draw background
132 ! call terminal_move_cursor(display_row, tooltip%col)
133 ! call terminal_write(char(27) // '[48;5;238m') ! Dark background
134 !
135 ! ! Build signature line with parameter highlighting
136 ! if (allocated(tooltip%signatures(sig_idx)%label)) then
137 ! label = tooltip%signatures(sig_idx)%label
138 !
139 ! ! If we have parameters, try to highlight the active one
140 ! if (tooltip%signatures(sig_idx)%num_parameters > 0 .and. &
141 ! tooltip%active_parameter > 0 .and. &
142 ! tooltip%active_parameter <= tooltip%signatures(sig_idx)%num_parameters) then
143 !
144 ! ! Get the parameter label to highlight
145 ! if (allocated(tooltip%signatures(sig_idx)%parameters(tooltip%active_parameter)%label)) then
146 ! block
147 ! character(len=:), allocatable :: param_label
148 ! param_label = tooltip%signatures(sig_idx)%parameters(tooltip%active_parameter)%label
149 !
150 ! ! Find parameter in signature
151 ! param_start = index(label, trim(param_label))
152 ! if (param_start > 0) then
153 ! param_end = param_start + len_trim(param_label) - 1
154 !
155 ! ! Build highlighted line
156 ! line = " "
157 ! if (param_start > 1) then
158 ! line = trim(line) // label(1:param_start-1)
159 ! end if
160 !
161 ! ! Highlight the active parameter
162 ! line = trim(line) // char(27) // '[1;33m' ! Bold yellow
163 ! line = trim(line) // label(param_start:param_end)
164 ! line = trim(line) // char(27) // '[0;48;5;238m' ! Reset to dark bg
165 !
166 ! if (param_end < len_trim(label)) then
167 ! line = trim(line) // label(param_end+1:len_trim(label))
168 ! end if
169 ! line = trim(line) // " "
170 ! else
171 ! ! Couldn't find parameter, show plain
172 ! line = " " // trim(label) // " "
173 ! end if
174 ! end block
175 ! else
176 ! line = " " // trim(label) // " "
177 ! end if
178 ! else
179 ! line = " " // trim(label) // " "
180 ! end if
181 ! else
182 ! line = " (no signature) "
183 ! end if
184 !
185 ! ! Truncate if too long
186 ! if (len_trim(line) > tooltip%max_width) then
187 ! line = line(1:tooltip%max_width-3) // "..."
188 ! end if
189 !
190 ! call terminal_write(trim(line))
191 !
192 ! ! Show which signature if multiple
193 ! if (tooltip%num_signatures > 1) then
194 ! block
195 ! character(len=20) :: sig_indicator
196 ! write(sig_indicator, '(A,I0,A,I0,A)') " (", sig_idx, "/", tooltip%num_signatures, ")"
197 ! call terminal_write(char(27) // '[90m') ! Gray
198 ! call terminal_write(trim(sig_indicator))
199 ! end block
200 ! end if
201 !
202 ! ! Reset colors
203 ! call terminal_write(char(27) // '[0m')
204 ! end subroutine render_signature_tooltip
205
206 subroutine handle_signature_response(tooltip, response)
207 use lsp_protocol_module, only: lsp_message_t
208 use json_module, only: json_value_t, json_get_array, json_get_object, &
209 json_get_string, json_get_number, json_array_size, &
210 json_get_array_element, json_has_key
211 type(signature_tooltip_t), intent(inout) :: tooltip
212 type(lsp_message_t), intent(in) :: response
213 type(json_value_t) :: result_obj, signatures_array, sig_obj
214 type(json_value_t) :: params_array, param_obj
215 integer :: num_signatures, num_params, i, j
216 character(len=:), allocatable :: label, doc
217 real(8) :: active_sig_real, active_param_real
218
219 ! Clear existing signatures
220 call clear_signatures(tooltip)
221
222 ! Get result object
223 result_obj = response%result
224
225 ! Get signatures array
226 if (.not. json_has_key(result_obj, 'signatures')) then
227 tooltip%visible = .false.
228 return
229 end if
230
231 signatures_array = json_get_array(result_obj, 'signatures')
232 num_signatures = json_array_size(signatures_array)
233
234 if (num_signatures == 0) then
235 tooltip%visible = .false.
236 return
237 end if
238
239 ! Allocate signatures
240 allocate(tooltip%signatures(num_signatures))
241 tooltip%num_signatures = num_signatures
242
243 ! Parse each signature
244 do i = 1, num_signatures
245 ! json_get_array_element expects 0-based index
246 sig_obj = json_get_array_element(signatures_array, i - 1)
247
248 ! Get label (required)
249 if (json_has_key(sig_obj, 'label')) then
250 label = json_get_string(sig_obj, 'label', '')
251 allocate(character(len=len(label)) :: tooltip%signatures(i)%label)
252 tooltip%signatures(i)%label = label
253 end if
254
255 ! Get documentation (optional)
256 if (json_has_key(sig_obj, 'documentation')) then
257 doc = json_get_string(sig_obj, 'documentation', '')
258 if (len(doc) > 0) then
259 allocate(character(len=len(doc)) :: tooltip%signatures(i)%documentation)
260 tooltip%signatures(i)%documentation = doc
261 end if
262 end if
263
264 ! Get parameters (optional)
265 if (json_has_key(sig_obj, 'parameters')) then
266 params_array = json_get_array(sig_obj, 'parameters')
267 num_params = json_array_size(params_array)
268
269 if (num_params > 0) then
270 allocate(tooltip%signatures(i)%parameters(num_params))
271 tooltip%signatures(i)%num_parameters = num_params
272
273 do j = 1, num_params
274 ! json_get_array_element expects 0-based index
275 param_obj = json_get_array_element(params_array, j - 1)
276
277 ! Get parameter label
278 if (json_has_key(param_obj, 'label')) then
279 ! Label can be string or [start, end] range
280 label = json_get_string(param_obj, 'label', '')
281 if (len(label) > 0) then
282 allocate(character(len=len(label)) :: &
283 tooltip%signatures(i)%parameters(j)%label)
284 tooltip%signatures(i)%parameters(j)%label = label
285 end if
286 end if
287
288 ! Get parameter documentation (optional)
289 if (json_has_key(param_obj, 'documentation')) then
290 doc = json_get_string(param_obj, 'documentation', '')
291 if (len(doc) > 0) then
292 allocate(character(len=len(doc)) :: &
293 tooltip%signatures(i)%parameters(j)%documentation)
294 tooltip%signatures(i)%parameters(j)%documentation = doc
295 end if
296 end if
297 end do
298 end if
299 end if
300 end do
301
302 ! Get active signature
303 if (json_has_key(result_obj, 'activeSignature')) then
304 active_sig_real = json_get_number(result_obj, 'activeSignature', 0.0d0)
305 tooltip%active_signature = int(active_sig_real) + 1 ! Convert 0-based to 1-based
306 else
307 tooltip%active_signature = 1
308 end if
309
310 ! Get active parameter
311 if (json_has_key(result_obj, 'activeParameter')) then
312 active_param_real = json_get_number(result_obj, 'activeParameter', 0.0d0)
313 tooltip%active_parameter = int(active_param_real) + 1 ! Convert 0-based to 1-based
314 else
315 tooltip%active_parameter = 1
316 end if
317
318 end subroutine handle_signature_response
319
320 end module signature_tooltip_module
321