fortrangoingonforty/facsimile / 5c5a6f9

Browse files

fix multiple rename issue

Authored by espadonne
SHA
5c5a6f9f332b266862a2c254437bca84d09758c5
Parents
b44a816
Tree
92fb770

11 changed files

StatusFile+-
M app/main.f90 0 50
M src/commands/command_handler_module.f90 107 9
M src/lsp/diagnostics_module.f90 1 19
M src/lsp/lsp_protocol_module.f90 1 11
M src/lsp/lsp_server_manager_module.f90 15 319
M src/terminal/input_handler_module.f90 59 91
M src/ui/help_display_module.f90 7 7
M src/ui/rename_prompt_module.f90 0 25
M src/workspace/workspace_module.f90 3 53
M tests/scratch_files/calculator.py 1 0
M tests/scratch_files/long_errors.py 1 1
app/main.f90modified
@@ -119,62 +119,42 @@ program facsimile
119119
         ! User selected a workspace from welcome menu (not browse)
120120
         ! This handles favorites, recents, and CURRENT DIRECTORY
121121
         if (allocated(selected_path) .and. .not. is_browse) then
122
-            write(0, '(A)') '[DEBUG WELCOME] selected_path allocated, value: ' // selected_path
123
-            write(0, '(A,L1)') '[DEBUG WELCOME] is_browse: ', is_browse
124
-
125122
             ! Check if user selected CURRENT DIRECTORY option
126123
             if (selected_path == "CWD") then
127
-                write(0, '(A)') '[DEBUG WELCOME] CWD selected, getting workspace path'
128124
                 ! Get actual current working directory
129125
                 call get_workspace_path(selected_path)
130
-                write(0, '(A)') '[DEBUG WELCOME] Workspace path: ' // selected_path
131126
                 arg = selected_path
132127
             else
133
-                write(0, '(A)') '[DEBUG WELCOME] Not CWD, using selected_path directly'
134128
                 arg = selected_path
135129
             end if
136130
 
137131
             ! Check if it's a directory
138
-            write(0, '(A)') '[DEBUG WELCOME] Testing if directory: ' // trim(arg)
139132
             call execute_command_line("test -d '" // trim(arg) // &
140133
                 "' && echo 'Directory' > /tmp/.fac_filetype || " // &
141134
                 "echo 'File' > /tmp/.fac_filetype", wait=.true.)
142135
             call read_file_type(status)
143
-            write(0, '(A,I0)') '[DEBUG WELCOME] read_file_type status: ', status
144136
             if (status == 0) then
145137
                 ! Directory - workspace mode
146
-                write(0, '(A)') '[DEBUG WELCOME] Setting is_workspace_mode = TRUE'
147138
                 is_workspace_mode = .true.
148139
                 call workspace_get_path(trim(arg), workspace_dir)
149
-                write(0, '(A)') '[DEBUG WELCOME] workspace_dir: ' // trim(workspace_dir)
150140
             else
151141
                 ! Invalid selection (favorites/recents should only have directories)
152142
                 write(error_unit, '(A)') 'Error: Selected path is not a directory'
153143
                 stop 1
154144
             end if
155
-        else
156
-            write(0, '(A,L1)') '[DEBUG WELCOME] selected_path allocated: ', allocated(selected_path)
157
-            if (allocated(selected_path)) then
158
-                write(0, '(A)') '[DEBUG WELCOME] selected_path value: ' // selected_path
159
-            end if
160
-            write(0, '(A,L1)') '[DEBUG WELCOME] is_browse: ', is_browse
161145
         end if
162146
     end if
163147
 
164148
     ! Handle workspace mode
165
-    write(0, '(A,L1)') '[DEBUG WORKSPACE] is_workspace_mode: ', is_workspace_mode
166149
     if (is_workspace_mode) then
167
-        write(0, '(A)') '[DEBUG WORKSPACE] In workspace mode, workspace_dir: ' // trim(workspace_dir)
168150
         ! Check if workspace exists, create if not
169151
         if (.not. workspace_exists(workspace_dir)) then
170
-            write(0, '(A)') '[DEBUG WORKSPACE] Workspace does not exist, creating'
171152
             call workspace_init(workspace_dir, workspace_success)
172153
             if (.not. workspace_success) then
173154
                 write(error_unit, '(A)') 'Error: Failed to create workspace'
174155
                 stop 1
175156
             end if
176157
         else
177
-            write(0, '(A)') '[DEBUG WORKSPACE] Workspace exists, loading'
178158
             ! Load existing workspace
179159
             call workspace_load(workspace_dir, workspace_success)
180160
             if (.not. workspace_success) then
@@ -182,8 +162,6 @@ program facsimile
182162
                 stop 1
183163
             end if
184164
         end if
185
-    else
186
-        write(0, '(A)') '[DEBUG WORKSPACE] NOT in workspace mode'
187165
     end if
188166
 
189167
     ! Initialize editor
@@ -204,46 +182,23 @@ program facsimile
204182
     call init_buffer(buffer)
205183
 
206184
     ! Set workspace path
207
-    write(0, '(A,L1)') '[DEBUG RESTORE CHECK] is_workspace_mode: ', is_workspace_mode
208185
     if (is_workspace_mode) then
209
-        write(0, '(A)') '[DEBUG RESTORE CHECK] workspace_dir: ' // trim(workspace_dir)
210186
         ! Use detected/created workspace directory
211187
         allocate(character(len=len_trim(workspace_dir)) :: editor%workspace_path)
212188
         editor%workspace_path = trim(workspace_dir)
213189
 
214
-        ! DEBUG: Print before restoration (unit 0 = stderr)
215
-        write(0, '(A)') '[DEBUG RESTORE] About to restore workspace from: ' // trim(editor%workspace_path)
216
-        write(0, '(A)') '[DEBUG RESTORE] Workspace JSON path: ' // trim(editor%workspace_path) // '/.fac/workspace.json'
217
-
218190
         ! Restore workspace state (tabs, cursor positions, etc.)
219191
         call workspace_restore_state(editor, editor%workspace_path, workspace_success)
220192
 
221
-        ! DEBUG: Print restoration results
222
-        write(0, '(A,L1)') '[DEBUG RESTORE] Workspace restore success: ', workspace_success
223
-        if (allocated(editor%tabs)) then
224
-            write(0, '(A,I0)') '[DEBUG RESTORE] Number of tabs restored: ', size(editor%tabs)
225
-        else
226
-            write(0, '(A)') '[DEBUG RESTORE] No tabs allocated after restore'
227
-        end if
228
-        write(0, '(A,I0)') '[DEBUG RESTORE] Active tab index: ', editor%active_tab_index
229
-
230193
         ! Sync restored active tab's buffer to main buffer
231194
         if (workspace_success .and. allocated(editor%tabs) .and. editor%active_tab_index > 0) then
232195
             if (editor%active_tab_index <= size(editor%tabs)) then
233196
                 if (allocated(editor%tabs(editor%active_tab_index)%panes) .and. &
234197
                     size(editor%tabs(editor%active_tab_index)%panes) > 0) then
235198
                     ! Copy active pane's buffer to main buffer (replaces the empty init)
236
-                    write(0, '(A)') '[DEBUG RESTORE] Copying restored tab buffer to main buffer'
237199
                     call copy_buffer(buffer, editor%tabs(editor%active_tab_index)%panes(1)%buffer)
238
-                else
239
-                    write(0, '(A)') '[DEBUG RESTORE] Active tab has no panes!'
240200
                 end if
241
-            else
242
-                write(0, '(A,I0,A,I0)') '[DEBUG RESTORE] Active tab index ', editor%active_tab_index, &
243
-                    ' exceeds tab count ', size(editor%tabs)
244201
             end if
245
-        else
246
-            write(0, '(A)') '[DEBUG RESTORE] Skipping buffer sync - conditions not met'
247202
         end if
248203
     else
249204
         ! Single-file mode - use current directory
@@ -515,11 +470,6 @@ contains
515470
         use terminal_io_module, only: terminal_write
516471
         type(lsp_message_t), intent(in) :: notification
517472
         integer, intent(in) :: server_index
518
-        character(len=256) :: debug_msg
519
-
520
-        ! Debug: Log when diagnostics are received
521
-        write(debug_msg, '(A,I0)') "[DEBUG] Received diagnostics from server ", server_index
522
-        call terminal_write(debug_msg)  ! Debug output enabled
523473
 
524474
         ! Parse and store diagnostics with server attribution (for multi-LSP)
525475
         ! This keeps diagnostics from different servers separate
src/commands/command_handler_module.f90modified
@@ -1386,15 +1386,15 @@ contains
13861386
 
13871387
                                             ! Check if rename response modified the buffer
13881388
                                             if (g_lsp_modified_buffer) then
1389
-                                                ! Sync buffer from tab (LSP modified tab buffer)
1390
-                                                call copy_buffer(buffer, editor%tabs(editor%active_tab_index)%buffer)
1391
-
1392
-                                                ! Also sync to active pane buffer if panes exist
1389
+                                                ! LSP now modifies pane buffer directly, sync FROM pane TO local buffer and tab
13931390
                                                 if (allocated(editor%tabs(editor%active_tab_index)%panes) .and. &
13941391
                                                     size(editor%tabs(editor%active_tab_index)%panes) > 0) then
13951392
                                                     pane_idx = editor%tabs(editor%active_tab_index)%active_pane_index
13961393
                                                     if (pane_idx > 0 .and. pane_idx <= size(editor%tabs(editor%active_tab_index)%panes)) then
1397
-                                                        call copy_buffer(editor%tabs(editor%active_tab_index)%panes(pane_idx)%buffer, buffer)
1394
+                                                        ! Copy FROM pane buffer TO local buffer (for rendering)
1395
+                                                        call copy_buffer(buffer, editor%tabs(editor%active_tab_index)%panes(pane_idx)%buffer)
1396
+                                                        ! Also sync to tab buffer (to keep them consistent)
1397
+                                                        call copy_buffer(editor%tabs(editor%active_tab_index)%buffer, buffer)
13981398
                                                     end if
13991399
                                                 end if
14001400
 
@@ -6313,14 +6313,16 @@ contains
63136313
     subroutine apply_file_edits_obj(editor, uri, edits_arr, changes_applied)
63146314
         use json_module, only: json_value_t, json_array_size, json_get_array_element, &
63156315
                                json_get_object, json_get_string, json_get_number, json_has_key
6316
+        use text_buffer_module, only: buffer_to_string
6317
+        use lsp_server_manager_module, only: notify_file_changed
63166318
         type(editor_state_t), intent(inout) :: editor
63176319
         character(len=*), intent(in) :: uri
63186320
         type(json_value_t), intent(in) :: edits_arr
63196321
         integer, intent(inout) :: changes_applied
63206322
 
63216323
         type(json_value_t) :: edit_obj, range_obj, start_obj, end_obj
6322
-        character(len=:), allocatable :: filename, new_text
6323
-        integer :: num_edits, i, j, tab_idx
6324
+        character(len=:), allocatable :: filename, new_text, buffer_content
6325
+        integer :: num_edits, i, j, tab_idx, server_idx, pane_idx
63246326
         integer :: start_line, start_char, end_line, end_char
63256327
 
63266328
         ! Convert URI to filename
@@ -6356,6 +6358,25 @@ contains
63566358
             return
63576359
         end if
63586360
 
6361
+        ! Get the active pane for this tab (panes contain the actual buffers)
6362
+        pane_idx = editor%tabs(tab_idx)%active_pane_index
6363
+        if (pane_idx < 1 .or. .not. allocated(editor%tabs(tab_idx)%panes)) then
6364
+            pane_idx = 1  ! Default to first pane
6365
+        end if
6366
+        if (pane_idx > size(editor%tabs(tab_idx)%panes)) then
6367
+            if (allocated(filename)) deallocate(filename)
6368
+            return
6369
+        end if
6370
+
6371
+        ! Debug: log tab_idx finding
6372
+        open(newunit=server_idx, file='/tmp/fac_tab_debug.log', status='unknown', &
6373
+             position='append', action='write')
6374
+        write(server_idx, '(A,I3,A,I3)') 'Found tab_idx=', tab_idx, ' pane_idx=', pane_idx
6375
+        write(server_idx, '(A,A)') 'Extracted filename: ', trim(filename)
6376
+        write(server_idx, '(A,A)') 'Tab filename: ', trim(editor%tabs(tab_idx)%filename)
6377
+        write(server_idx, '(A)') '---'
6378
+        close(server_idx)
6379
+
63596380
         ! Apply edits in reverse order (to preserve line numbers)
63606381
         num_edits = json_array_size(edits_arr)
63616382
 
@@ -6379,15 +6400,53 @@ contains
63796400
                 new_text = json_get_string(edit_obj, 'newText')
63806401
 
63816402
                 if (allocated(new_text)) then
6382
-                    ! Apply the edit to the buffer
6383
-                    call apply_single_edit(editor%tabs(tab_idx)%buffer, &
6403
+                    ! Apply the edit to the pane buffer (not tab buffer!)
6404
+                    call apply_single_edit(editor%tabs(tab_idx)%panes(pane_idx)%buffer, &
63846405
                         start_line, start_char, end_line, end_char, new_text)
63856406
                     changes_applied = changes_applied + 1
6407
+
6408
+                    ! Debug: check buffer size after edit
6409
+                    block
6410
+                        character(len=:), allocatable :: check_content
6411
+                        integer :: check_unit
6412
+                        check_content = buffer_to_string(editor%tabs(tab_idx)%panes(pane_idx)%buffer)
6413
+                        open(newunit=check_unit, file='/tmp/fac_after_edit.log', status='unknown', &
6414
+                             position='append', action='write')
6415
+                        write(check_unit, '(A,I8)') 'After edit, buffer len: ', len(check_content)
6416
+                        close(check_unit)
6417
+                        if (allocated(check_content)) deallocate(check_content)
6418
+                    end block
6419
+
63866420
                     deallocate(new_text)
63876421
                 end if
63886422
             end if
63896423
         end do
63906424
 
6425
+        ! Sync the changed document back to all LSP servers
6426
+        if (changes_applied > 0) then
6427
+            buffer_content = buffer_to_string(editor%tabs(tab_idx)%panes(pane_idx)%buffer)
6428
+            if (allocated(buffer_content)) then
6429
+                ! Debug: log what we're about to sync
6430
+                open(newunit=server_idx, file='/tmp/fac_sync_debug.log', status='unknown', &
6431
+                     position='append', action='write')
6432
+                write(server_idx, '(A,I4)') 'Sync after changes_applied=', changes_applied
6433
+                write(server_idx, '(A,I8)') 'Buffer content length: ', len(buffer_content)
6434
+                write(server_idx, '(A,A)') 'First 100 chars: ', buffer_content(1:min(100,len(buffer_content)))
6435
+                write(server_idx, '(A)') '---'
6436
+                close(server_idx)
6437
+
6438
+                ! Notify all active LSP servers about the document change
6439
+                ! Use the absolute path from the URI (filename variable) not the tab's relative path
6440
+                do server_idx = 1, editor%lsp_manager%num_servers
6441
+                    if (editor%lsp_manager%servers(server_idx)%initialized) then
6442
+                        call notify_file_changed(editor%lsp_manager, server_idx, &
6443
+                            'file://' // filename, buffer_content)
6444
+                    end if
6445
+                end do
6446
+                deallocate(buffer_content)
6447
+            end if
6448
+        end if
6449
+
63916450
         if (allocated(filename)) deallocate(filename)
63926451
     end subroutine apply_file_edits_obj
63936452
 
@@ -6398,23 +6457,62 @@ contains
63986457
         character(len=*), intent(in) :: new_text
63996458
 
64006459
         integer :: start_pos, end_pos, delete_count
6460
+        integer :: debug_unit
6461
+        character(len=256) :: debug_msg
64016462
 
64026463
         ! Calculate buffer positions
64036464
         start_pos = get_buffer_position(buffer, start_line, start_char)
64046465
         end_pos = get_buffer_position(buffer, end_line, end_char)
64056466
 
6467
+        ! Debug logging
6468
+        open(newunit=debug_unit, file='/tmp/fac_edit_debug.log', status='unknown', &
6469
+             position='append', action='write')
6470
+        write(debug_msg, '(A,I4,A,I4,A,I4,A,I4)') 'Edit range: line ', start_line, &
6471
+              ' char ', start_char, ' to line ', end_line, ' char ', end_char
6472
+        write(debug_unit, '(A)') trim(debug_msg)
6473
+        write(debug_msg, '(A,I6,A,I6,A,I4)') 'Buffer pos: start=', start_pos, &
6474
+              ' end=', end_pos, ' delete_count=', end_pos - start_pos
6475
+        write(debug_unit, '(A)') trim(debug_msg)
6476
+        write(debug_msg, '(A,I4,A,A,A)') 'New text len=', len(new_text), ' text="', new_text, '"'
6477
+        write(debug_unit, '(A)') trim(debug_msg)
6478
+        write(debug_unit, '(A)') '---'
6479
+        close(debug_unit)
6480
+
64066481
         if (start_pos <= 0 .or. end_pos <= 0) return
64076482
 
64086483
         ! Delete the old text
64096484
         delete_count = end_pos - start_pos
6485
+
6486
+        ! Debug: log gap buffer state before operations
6487
+        open(newunit=debug_unit, file='/tmp/fac_gap_debug.log', status='unknown', &
6488
+             position='append', action='write')
6489
+        write(debug_unit, '(A,I6,A,I6,A,I6)') 'BEFORE: gap_start=', buffer%gap_start, &
6490
+              ' gap_end=', buffer%gap_end, ' size=', buffer%size
6491
+        close(debug_unit)
6492
+
64106493
         if (delete_count > 0) then
64116494
             call buffer_delete(buffer, start_pos, delete_count)
64126495
         end if
64136496
 
6497
+        ! Debug: log gap buffer state after delete
6498
+        open(newunit=debug_unit, file='/tmp/fac_gap_debug.log', status='unknown', &
6499
+             position='append', action='write')
6500
+        write(debug_unit, '(A,I6,A,I6,A,I6)') 'AFTER DELETE: gap_start=', buffer%gap_start, &
6501
+              ' gap_end=', buffer%gap_end, ' size=', buffer%size
6502
+        close(debug_unit)
6503
+
64146504
         ! Insert the new text
64156505
         if (len(new_text) > 0) then
64166506
             call buffer_insert(buffer, start_pos, new_text)
64176507
         end if
6508
+
6509
+        ! Debug: log gap buffer state after insert
6510
+        open(newunit=debug_unit, file='/tmp/fac_gap_debug.log', status='unknown', &
6511
+             position='append', action='write')
6512
+        write(debug_unit, '(A,I6,A,I6,A,I6)') 'AFTER INSERT: gap_start=', buffer%gap_start, &
6513
+              ' gap_end=', buffer%gap_end, ' size=', buffer%size
6514
+        write(debug_unit, '(A)') '---'
6515
+        close(debug_unit)
64186516
     end subroutine apply_single_edit
64196517
 
64206518
     ! Execute a command from the command palette
src/lsp/diagnostics_module.f90modified
@@ -108,16 +108,11 @@ contains
108108
         character(len=:), allocatable :: uri
109109
         integer :: i, n_diagnostics, file_idx
110110
         type(diagnostic_t) :: diag
111
-        character(len=512) :: debug_msg
112111
 
113112
         ! Get URI
114113
         if (.not. json_has_key(params, "uri")) return
115114
         uri = json_get_string(params, "uri")
116115
 
117
-        ! Debug: Log URI
118
-        write(debug_msg, '(A,A)') "[DIAG] Parsing diagnostics for URI: ", trim(uri)
119
-        call terminal_write(debug_msg)
120
-
121116
         ! Find or create file entry
122117
         file_idx = find_or_create_file(store, uri)
123118
 
@@ -132,10 +127,6 @@ contains
132127
             diagnostics_array = json_get_array(params, "diagnostics")
133128
             n_diagnostics = json_array_size(diagnostics_array)
134129
 
135
-            ! Debug: Log number of diagnostics
136
-            write(debug_msg, '(A,I0,A)') "[DIAG] Found ", n_diagnostics, " diagnostics"
137
-            call terminal_write(debug_msg)
138
-
139130
             if (n_diagnostics > 0) then
140131
                 allocate(store%files(file_idx)%items(n_diagnostics))
141132
                 store%files(file_idx)%count = n_diagnostics
@@ -208,17 +199,12 @@ contains
208199
         character(len=:), allocatable :: uri
209200
         integer :: i, n_diagnostics, file_idx, old_count, new_count, j
210201
         type(diagnostic_t) :: diag
211
-        type(diagnostic_t), allocatable :: old_items(:), new_items(:)
212
-        character(len=512) :: debug_msg
202
+        type(diagnostic_t), allocatable :: old_items(:)
213203
 
214204
         ! Get URI
215205
         if (.not. json_has_key(params, "uri")) return
216206
         uri = json_get_string(params, "uri")
217207
 
218
-        ! Debug: Log URI
219
-        write(debug_msg, '(A,A,A,I0)') "[DIAG] Parsing diagnostics for URI: ", trim(uri), " from server ", server_index
220
-        call terminal_write(debug_msg)
221
-
222208
         ! Find or create file entry
223209
         file_idx = find_or_create_file(store, uri)
224210
 
@@ -255,10 +241,6 @@ contains
255241
             n_diagnostics = json_array_size(diagnostics_array)
256242
         end if
257243
 
258
-        ! Debug: Log number of diagnostics
259
-        write(debug_msg, '(A,I0,A,I0,A)') "[DIAG] Found ", n_diagnostics, " new + ", old_count, " existing diagnostics"
260
-        call terminal_write(debug_msg)
261
-
262244
         ! Allocate combined array
263245
         new_count = old_count + n_diagnostics
264246
         if (new_count > 0) then
src/lsp/lsp_protocol_module.f90modified
@@ -106,16 +106,6 @@ contains
106106
         ! Convert root_path to absolute path
107107
         abs_root_path = make_absolute_path(root_path)
108108
 
109
-        block
110
-            integer :: debug_unit
111
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
112
-            write(debug_unit, '(A)') '>>> create_initialize_request <<<'
113
-            write(debug_unit, '(A)') 'root_path (input): ' // trim(root_path)
114
-            write(debug_unit, '(A)') 'abs_root_path: ' // abs_root_path
115
-            write(debug_unit, '(A)') 'rootUri: file://' // abs_root_path
116
-            close(debug_unit)
117
-        end block
118
-
119109
         params = json_create_object()
120110
         call json_add_number(params, "processId", real(process_id, real64))
121111
         call json_add_string(params, "rootPath", abs_root_path)
@@ -238,7 +228,7 @@ contains
238228
         changes = json_create_array()
239229
         change = json_create_object()
240230
         call json_add_string(change, "text", text)
241
-        ! TODO: Add change to array
231
+        call json_array_add_element(changes, change)
242232
         call json_add_array(params, "contentChanges", changes)
243233
 
244234
         msg%params = params
src/lsp/lsp_server_manager_module.f90modified
@@ -375,16 +375,6 @@ contains
375375
             return
376376
         end if
377377
 
378
-        block
379
-            integer :: debug_unit
380
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
381
-            write(debug_unit, '(A)') '>>> STARTING LSP SERVER <<<'
382
-            write(debug_unit, '(A)') 'Language: ' // trim(language)
383
-            write(debug_unit, '(A)') 'Command: ' // trim(command)
384
-            write(debug_unit, '(A)') 'Root path: ' // trim(root_path)
385
-            close(debug_unit)
386
-        end block
387
-
388378
         ! Expand server array
389379
         allocate(new_servers(manager%num_servers + 1))
390380
         if (manager%num_servers > 0) then
@@ -467,98 +457,20 @@ contains
467457
         procedure(response_callback), optional :: callback
468458
         character(len=:), allocatable :: json_msg
469459
 
470
-        block
471
-            integer :: debug_unit
472
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
473
-            write(debug_unit, '(A)') '>>> send_request: START <<<'
474
-            write(debug_unit, '(A,I0)') 'server_index = ', server_index
475
-            write(debug_unit, '(A,I0)') 'num_servers = ', manager%num_servers
476
-            close(debug_unit)
477
-        end block
478
-
479
-        if (server_index < 1 .or. server_index > manager%num_servers) then
480
-            block
481
-                integer :: debug_unit
482
-                open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
483
-                write(debug_unit, '(A)') '>>> send_request: EARLY RETURN - invalid server_index <<<'
484
-                close(debug_unit)
485
-            end block
486
-            return
487
-        end if
460
+        if (server_index < 1 .or. server_index > manager%num_servers) return
488461
 
489462
         if (.not. manager%servers(server_index)%initialized .and. &
490
-            .not. manager%servers(server_index)%initializing) then
491
-            block
492
-                integer :: debug_unit
493
-                open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
494
-                write(debug_unit, '(A)') '>>> send_request: EARLY RETURN - server not initialized <<<'
495
-                write(debug_unit, '(A,L1)') 'initialized = ', manager%servers(server_index)%initialized
496
-                write(debug_unit, '(A,L1)') 'initializing = ', manager%servers(server_index)%initializing
497
-                close(debug_unit)
498
-            end block
499
-            return
500
-        end if
501
-
502
-        block
503
-            integer :: debug_unit
504
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
505
-            write(debug_unit, '(A)') '>>> send_request: Formatting JSON <<<'
506
-            close(debug_unit)
507
-        end block
463
+            .not. manager%servers(server_index)%initializing) return
508464
 
509465
         json_msg = format_json_rpc(msg)
510
-
511
-        block
512
-            integer :: debug_unit
513
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
514
-            write(debug_unit, '(A)') '>>> send_request: Sending message <<<'
515
-            write(debug_unit, '(A)') 'JSON (first 500 chars): ' // json_msg(1:min(500,len(json_msg)))
516
-            close(debug_unit)
517
-        end block
518
-
519466
         call send_raw_message(manager%servers(server_index), json_msg)
520467
 
521
-        block
522
-            integer :: debug_unit
523
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
524
-            write(debug_unit, '(A)') '>>> send_request: Tracking request <<<'
525
-            close(debug_unit)
526
-        end block
527
-
528468
         ! Track request and register callback
529469
         call track_request(manager%servers(server_index), msg%id)
530470
 
531
-        block
532
-            integer :: debug_unit
533
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
534
-            write(debug_unit, '(A,L1)') '>>> send_request: callback present = ', present(callback)
535
-            close(debug_unit)
536
-        end block
537
-
538471
         if (present(callback)) then
539
-            block
540
-                integer :: debug_unit
541
-                open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
542
-                write(debug_unit, '(A)') '>>> send_request: Calling register_callback <<<'
543
-                close(debug_unit)
544
-            end block
545
-
546472
             call register_callback(manager, msg%id, callback)
547
-
548
-            block
549
-                integer :: debug_unit
550
-                open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
551
-                write(debug_unit, '(A)') '>>> send_request: register_callback DONE <<<'
552
-                close(debug_unit)
553
-            end block
554473
         end if
555
-
556
-        block
557
-            integer :: debug_unit
558
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
559
-            write(debug_unit, '(A)') '>>> send_request: DONE <<<'
560
-            close(debug_unit)
561
-        end block
562474
     end subroutine send_request
563475
 
564476
     subroutine send_notification(server, msg)
@@ -569,52 +481,15 @@ contains
569481
         if (.not. server%initialized .and. .not. server%initializing) return
570482
 
571483
         json_msg = format_json_rpc(msg)
572
-
573
-        ! Debug log for didOpen notifications
574
-        if (index(msg%method, 'didOpen') > 0) then
575
-            block
576
-                integer :: debug_unit
577
-                open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
578
-                write(debug_unit, '(A)') '>>> Sending didOpen notification <<<'
579
-                write(debug_unit, '(A)') 'JSON (first 800 chars): ' // json_msg(1:min(800,len(json_msg)))
580
-                close(debug_unit)
581
-            end block
582
-        end if
583
-
584484
         call send_raw_message(server, json_msg)
585485
     end subroutine send_notification
586486
 
587487
     subroutine send_raw_message(server, message)
588488
         type(lsp_server_t), intent(inout) :: server
589489
         character(len=*), intent(in) :: message
590
-        integer :: result, debug_unit
591
-
592
-        ! Check if handle is valid
593
-        block
594
-            integer :: debug_unit2
595
-            open(newunit=debug_unit2, file='/tmp/fac_keys.log', position='append', action='write')
596
-            write(debug_unit2, '(A)') '>>> send_raw_message: START <<<'
597
-            write(debug_unit2, '(A,L1)') 'c_associated(server%handle) = ', c_associated(server%handle)
598
-            close(debug_unit2)
599
-        end block
600
-
601
-        if (.not. c_associated(server%handle)) then
602
-            block
603
-                integer :: debug_unit2
604
-                open(newunit=debug_unit2, file='/tmp/fac_keys.log', position='append', action='write')
605
-                write(debug_unit2, '(A)') '>>> send_raw_message: EARLY RETURN - handle is NULL <<<'
606
-                close(debug_unit2)
607
-            end block
608
-            return
609
-        end if
490
+        integer :: result
610491
 
611
-        ! Log outgoing messages for debugging
612
-        open(newunit=debug_unit, file='/tmp/fac_lsp_out.log', position='append', action='write')
613
-        write(debug_unit, '(A)') '>>> OUTGOING MESSAGE >>>'
614
-        write(debug_unit, '(A)') trim(message)
615
-        write(debug_unit, '(A)') '<<< END MESSAGE <<<'
616
-        write(debug_unit, '(A)') ''
617
-        close(debug_unit)
492
+        if (.not. c_associated(server%handle)) return
618493
 
619494
         result = lsp_send_message_f(server%handle, message//c_null_char, len(message))
620495
 
@@ -675,18 +550,6 @@ contains
675550
 
676551
             ! Extract and parse message
677552
             message = server%read_buffer(1:message_end)
678
-
679
-            ! Log incoming message
680
-            block
681
-                integer :: debug_unit
682
-                open(newunit=debug_unit, file='/tmp/fac_lsp_in.log', position='append', action='write')
683
-                write(debug_unit, '(A)') '>>> INCOMING MESSAGE >>>'
684
-                write(debug_unit, '(A)') trim(message)
685
-                write(debug_unit, '(A)') '<<< END MESSAGE <<<'
686
-                write(debug_unit, '(A)') ''
687
-                close(debug_unit)
688
-            end block
689
-
690553
             msg = parse_lsp_message(message)
691554
 
692555
             ! Handle the message
@@ -818,19 +681,13 @@ contains
818681
         server%initialized = .true.
819682
         server%initializing = .false.
820683
 
821
-        write(error_unit, '(a,a)') "LSP server initialized: ", server%language
822
-
823684
         ! Send all queued didOpen notifications
824685
         if (allocated(server%pending_didopens) .and. server%num_pending_didopens > 0) then
825686
             block
826
-                integer :: i, debug_unit
687
+                integer :: i
827688
                 type(lsp_message_t) :: didopen_msg
828689
                 character(len=:), allocatable :: lang, file_uri
829690
 
830
-                open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
831
-                write(debug_unit, '(A,I0,A)') '>>> Flushing ', server%num_pending_didopens, ' queued didOpen notifications <<<'
832
-                close(debug_unit)
833
-
834691
                 do i = 1, server%num_pending_didopens
835692
                     if (allocated(server%pending_didopens(i)%filename) .and. &
836693
                         allocated(server%pending_didopens(i)%content)) then
@@ -840,14 +697,6 @@ contains
840697
                         didopen_msg = create_did_open_notification( &
841698
                             file_uri, lang, 1, &
842699
                             server%pending_didopens(i)%content)
843
-
844
-                        open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
845
-                        write(debug_unit, '(A,A)') '  - Sent didOpen for: ', trim(server%pending_didopens(i)%filename)
846
-                        write(debug_unit, '(A,A)') '  - URI: ', trim(file_uri)
847
-                        write(debug_unit, '(A,I0)') '  - Content length: ', len(server%pending_didopens(i)%content)
848
-                        write(debug_unit, '(A,A)') '  - Language: ', trim(lang)
849
-                        close(debug_unit)
850
-
851700
                         call send_notification(server, didopen_msg)
852701
                     end if
853702
                 end do
@@ -865,9 +714,6 @@ contains
865714
         type(lsp_message_t), intent(in) :: msg
866715
         integer :: srv_idx, i
867716
 
868
-        ! Debug: log all notifications
869
-        write(error_unit, '(A,A)') "[LSP DEBUG] Received notification: ", msg%method
870
-
871717
         ! Find the server index for this server
872718
         srv_idx = 0
873719
         do i = 1, manager%num_servers
@@ -882,12 +728,9 @@ contains
882728
 
883729
         select case(msg%method)
884730
         case("textDocument/publishDiagnostics")
885
-            write(error_unit, '(A,I0)') "[LSP DEBUG] Processing publishDiagnostics from server ", srv_idx
886731
             ! Forward to diagnostics handler if set (with server index)
887732
             if (associated(manager%diagnostics_handler)) then
888733
                 call manager%diagnostics_handler(msg, srv_idx)
889
-            else
890
-                write(error_unit, '(A)') "[LSP DEBUG] No diagnostics handler set!"
891734
             end if
892735
         case("window/showMessage")
893736
             ! TODO: Show message to user
@@ -940,87 +783,19 @@ contains
940783
         procedure(response_callback) :: callback
941784
         type(callback_entry_t), allocatable :: new_callbacks(:)
942785
 
943
-        block
944
-            integer :: debug_unit
945
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
946
-            write(debug_unit, '(A)') '>>> register_callback: START <<<'
947
-            write(debug_unit, '(A,I0)') 'request_id = ', request_id
948
-            write(debug_unit, '(A,I0)') 'num_callbacks = ', manager%num_callbacks
949
-            close(debug_unit)
950
-        end block
951
-
952
-        block
953
-            integer :: debug_unit
954
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
955
-            write(debug_unit, '(A)') '>>> register_callback: Allocating new_callbacks <<<'
956
-            close(debug_unit)
957
-        end block
958
-
959786
         allocate(new_callbacks(manager%num_callbacks + 1))
960787
 
961
-        block
962
-            integer :: debug_unit
963
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
964
-            write(debug_unit, '(A)') '>>> register_callback: Copying old callbacks <<<'
965
-            close(debug_unit)
966
-        end block
967
-
968788
         if (manager%num_callbacks > 0) then
969789
             new_callbacks(1:manager%num_callbacks) = manager%callbacks
970790
         end if
971791
 
972
-        block
973
-            integer :: debug_unit
974
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
975
-            write(debug_unit, '(A)') '>>> register_callback: Setting new callback <<<'
976
-            close(debug_unit)
977
-        end block
978
-
979792
         new_callbacks(manager%num_callbacks + 1)%request_id = request_id
980793
         new_callbacks(manager%num_callbacks + 1)%callback => callback
981794
 
982
-        block
983
-            integer :: debug_unit
984
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
985
-            write(debug_unit, '(A)') '>>> register_callback: Deallocating old callbacks <<<'
986
-            close(debug_unit)
987
-        end block
988
-
989795
         if (allocated(manager%callbacks)) deallocate(manager%callbacks)
990
-
991
-        block
992
-            integer :: debug_unit
993
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
994
-            write(debug_unit, '(A)') '>>> register_callback: Reallocating manager%callbacks <<<'
995
-            close(debug_unit)
996
-        end block
997
-
998796
         allocate(manager%callbacks(size(new_callbacks)))
999
-
1000
-        block
1001
-            integer :: debug_unit
1002
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
1003
-            write(debug_unit, '(A)') '>>> register_callback: Copying new_callbacks <<<'
1004
-            close(debug_unit)
1005
-        end block
1006
-
1007797
         manager%callbacks = new_callbacks
1008
-
1009
-        block
1010
-            integer :: debug_unit
1011
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
1012
-            write(debug_unit, '(A)') '>>> register_callback: Incrementing num_callbacks <<<'
1013
-            close(debug_unit)
1014
-        end block
1015
-
1016798
         manager%num_callbacks = manager%num_callbacks + 1
1017
-
1018
-        block
1019
-            integer :: debug_unit
1020
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
1021
-            write(debug_unit, '(A)') '>>> register_callback: DONE <<<'
1022
-            close(debug_unit)
1023
-        end block
1024799
     end subroutine register_callback
1025800
 
1026801
     subroutine remove_callback(manager, index)
@@ -1191,17 +966,6 @@ contains
1191966
 
1192967
         command = manager%configs(config_index)%command
1193968
 
1194
-        block
1195
-            integer :: debug_unit
1196
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
1197
-            write(debug_unit, '(A)') '>>> STARTING LSP SERVER (from config) <<<'
1198
-            write(debug_unit, '(A)') 'Name: ' // trim(manager%configs(config_index)%name)
1199
-            write(debug_unit, '(A)') 'Language: ' // trim(manager%configs(config_index)%language)
1200
-            write(debug_unit, '(A)') 'Command: ' // trim(command)
1201
-            write(debug_unit, '(A)') 'Root path: ' // trim(root_path)
1202
-            close(debug_unit)
1203
-        end block
1204
-
1205969
         ! Expand server array
1206970
         allocate(new_servers(manager%num_servers + 1))
1207971
         if (manager%num_servers > 0) then
@@ -1280,14 +1044,6 @@ contains
12801044
 
12811045
         ! If server not initialized yet, queue the notification
12821046
         if (.not. manager%servers(server_index)%initialized) then
1283
-            block
1284
-                integer :: debug_unit
1285
-                open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
1286
-                write(debug_unit, '(A)') '>>> notify_file_opened: Queuing (server not ready) <<<'
1287
-                write(debug_unit, '(A)') 'File: ' // trim(filename)
1288
-                close(debug_unit)
1289
-            end block
1290
-
12911047
             ! Add to pending queue
12921048
             if (allocated(manager%servers(server_index)%pending_didopens)) then
12931049
                 ! Grow array
@@ -1322,14 +1078,6 @@ contains
13221078
             return
13231079
         end if
13241080
 
1325
-        block
1326
-            integer :: debug_unit
1327
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
1328
-            write(debug_unit, '(A)') '>>> notify_file_opened: Sending immediately <<<'
1329
-            write(debug_unit, '(A)') 'File: ' // trim(filename)
1330
-            close(debug_unit)
1331
-        end block
1332
-
13331081
         ! Server is ready, send immediately
13341082
         language = get_language_for_file(filename)
13351083
         block
@@ -1338,14 +1086,6 @@ contains
13381086
             msg = create_did_open_notification(file_uri, language, 1, content)
13391087
         end block
13401088
 
1341
-        block
1342
-            integer :: debug_unit
1343
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
1344
-            write(debug_unit, '(A)') '>>> didOpen content length: ' // trim(adjustl(char(len(content))))
1345
-            write(debug_unit, '(A)') '>>> didOpen language: ' // trim(language)
1346
-            close(debug_unit)
1347
-        end block
1348
-
13491089
         call send_notification(manager%servers(server_index), msg)
13501090
     end subroutine notify_file_opened
13511091
 
@@ -1359,6 +1099,16 @@ contains
13591099
         integer, intent(in), optional :: version
13601100
         type(lsp_message_t) :: msg
13611101
         integer :: doc_version
1102
+        integer :: debug_unit
1103
+
1104
+        ! Debug logging
1105
+        open(newunit=debug_unit, file='/tmp/fac_didchange_debug.log', status='unknown', &
1106
+             position='append', action='write')
1107
+        write(debug_unit, '(A,I2,A)') 'notify_file_changed called for server ', server_index, ':'
1108
+        write(debug_unit, '(A,A)') '  URI: ', trim(filename)
1109
+        write(debug_unit, '(A,I8)') '  Content length: ', len(content)
1110
+        write(debug_unit, '(A)') '---'
1111
+        close(debug_unit)
13621112
 
13631113
         if (server_index < 1 .or. server_index > manager%num_servers) return
13641114
         if (.not. manager%servers(server_index)%initialized) return
@@ -1395,9 +1145,6 @@ contains
13951145
         end if
13961146
 
13971147
         call send_notification(manager%servers(server_index), msg)
1398
-
1399
-        ! Debug output
1400
-        write(error_unit, '(A,A)') "[LSP DEBUG] Sent didSave for: ", trim(filename)
14011148
     end subroutine notify_file_saved
14021149
 
14031150
     ! Send textDocument/didClose notification
@@ -1477,55 +1224,14 @@ contains
14771224
         type(lsp_message_t) :: msg
14781225
         character(len=:), allocatable :: uri
14791226
 
1480
-        block
1481
-            integer :: debug_unit
1482
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
1483
-            write(debug_unit, '(A)') '>>> request_definition: START <<<'
1484
-            close(debug_unit)
1485
-        end block
1486
-
14871227
         request_id = -1
14881228
         if (server_index < 1 .or. server_index > manager%num_servers) return
14891229
         if (.not. manager%servers(server_index)%initialized) return
14901230
 
1491
-        block
1492
-            integer :: debug_unit
1493
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
1494
-            write(debug_unit, '(A)') '>>> request_definition: Creating URI <<<'
1495
-            write(debug_unit, '(A)') 'Filename: ' // trim(filename)
1496
-            close(debug_unit)
1497
-        end block
1498
-
1499
-        ! Convert filename to URI (simple file:// for now)
15001231
         uri = filename_to_uri(filename)
1501
-
1502
-        block
1503
-            integer :: debug_unit
1504
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
1505
-            write(debug_unit, '(A)') '>>> request_definition: Creating request <<<'
1506
-            write(debug_unit, '(A)') 'URI: ' // trim(uri)
1507
-            write(debug_unit, '(A,I0,A,I0)') 'Position: line=', line, ' char=', character
1508
-            close(debug_unit)
1509
-        end block
1510
-
15111232
         msg = create_definition_request(uri, line, character)
15121233
         request_id = msg%id
1513
-
1514
-        block
1515
-            integer :: debug_unit
1516
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
1517
-            write(debug_unit, '(A)') '>>> request_definition: Calling send_request <<<'
1518
-            close(debug_unit)
1519
-        end block
1520
-
15211234
         call send_request(manager, server_index, msg, callback)
1522
-
1523
-        block
1524
-            integer :: debug_unit
1525
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
1526
-            write(debug_unit, '(A)') '>>> request_definition: DONE <<<'
1527
-            close(debug_unit)
1528
-        end block
15291235
     end function request_definition
15301236
 
15311237
     ! Request references at cursor position
@@ -1568,19 +1274,9 @@ contains
15681274
         integer :: request_id
15691275
         type(lsp_message_t) :: msg
15701276
         character(len=:), allocatable :: uri
1571
-        integer :: dbg
15721277
 
15731278
         request_id = -1
15741279
 
1575
-        ! Debug logging
1576
-        open(newunit=dbg, file='/tmp/fac_code_actions.log', position='append', action='write')
1577
-        write(dbg, '(A,I0)') 'request_code_actions: server_index = ', server_index
1578
-        write(dbg, '(A,I0)') 'request_code_actions: num_servers = ', manager%num_servers
1579
-        if (server_index >= 1 .and. server_index <= manager%num_servers) then
1580
-            write(dbg, '(A,L1)') 'request_code_actions: initialized = ', manager%servers(server_index)%initialized
1581
-        end if
1582
-        close(dbg)
1583
-
15841280
         if (server_index < 1 .or. server_index > manager%num_servers) return
15851281
         if (.not. manager%servers(server_index)%initialized) return
15861282
 
src/terminal/input_handler_module.f90modified
@@ -105,14 +105,6 @@ contains
105105
             end if
106106
             ch2 = achar(char_code)
107107
 
108
-            block
109
-                integer :: debug_unit, ch2_code
110
-                ch2_code = ichar(ch2)
111
-                open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
112
-                write(debug_unit, '(A,I0,A)') '>>> ESC[ RECEIVED, ch2=', ch2_code, ' (' // ch2 // ')'
113
-                close(debug_unit)
114
-            end block
115
-
116108
             select case(ch2)
117109
             case('A')
118110
                 key_str = 'up'
@@ -187,22 +179,10 @@ contains
187179
                 end if
188180
             case('1')
189181
                 ! Could be function key (F1-F9) or modified arrow/home/end
190
-                block
191
-                    integer :: debug_unit
192
-                    open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
193
-                    write(debug_unit, '(A)') '>>> ESC[1 SEQUENCE DETECTED <<<'
194
-                    close(debug_unit)
195
-                end block
196182
                 ! Check next character
197183
                 char_code = terminal_read_char()
198184
                 if (char_code >= 0) then
199185
                     ch3 = achar(char_code)
200
-                    block
201
-                        integer :: debug_unit
202
-                        open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
203
-                        write(debug_unit, '(A)') 'ch3 = ' // ch3
204
-                        close(debug_unit)
205
-                    end block
206186
                     if (ch3 == '~') then
207187
                         ! F1: ESC [ 1 1 ~ (alternate format)
208188
                         key_str = 'f1'
@@ -250,21 +230,9 @@ contains
250230
                 end if
251231
             case('2')
252232
                 ! Could be F9-F12 or alternate modified keys
253
-                block
254
-                    integer :: debug_unit
255
-                    open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
256
-                    write(debug_unit, '(A)') '>>> ESC[2 SEQUENCE DETECTED <<<'
257
-                    close(debug_unit)
258
-                end block
259233
                 char_code = terminal_read_char()
260234
                 if (char_code >= 0) then
261235
                     ch3 = achar(char_code)
262
-                    block
263
-                        integer :: debug_unit
264
-                        open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
265
-                        write(debug_unit, '(A)') 'ch3 = ' // ch3
266
-                        close(debug_unit)
267
-                    end block
268236
                     if (ch3 == '0' .or. ch3 == '1' .or. ch3 == '3' .or. ch3 == '4') then
269237
                         ! Function keys F9-F12: ESC [ 2 X ~ or ESC [ 2 X ; modifier ~
270238
                         char_code = terminal_read_char()
@@ -281,13 +249,6 @@ contains
281249
                                     key_str = 'f11'
282250
                                 case('4')
283251
                                     key_str = 'f12'
284
-                                    block
285
-                                        integer :: debug_unit
286
-                                        open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
287
-                                        write(debug_unit, '(A)') '>>> F12 KEY DETECTED IN INPUT HANDLER <<<'
288
-                                        write(debug_unit, '(A)') 'key_str set to: ' // trim(key_str)
289
-                                        close(debug_unit)
290
-                                    end block
291252
                                 end select
292253
                             else if (ch == ';') then
293254
                                 ! Modified F9-F12: ESC [ 2 X ; modifier ~
@@ -465,64 +426,71 @@ contains
465426
         if (terminator == '') return
466427
 
467428
         ! Parse modifier
468
-        if (len_trim(modifier_seq) > 1 .and. modifier_seq(1:1) == ';') then
469
-            ! Standard format: ";2" where 2 is the modifier
429
+        if (len_trim(modifier_seq) >= 1 .and. modifier_seq(1:1) == ';') then
430
+            ! Standard format with leading ';': ";2" where 2 is the modifier
470431
             if (len_trim(modifier_seq) >= 2) then
471432
                 read(modifier_seq(2:len_trim(modifier_seq)), '(i10)', iostat=ios) modifier
472433
             else
473434
                 ios = -1
474435
             end if
475
-            if (ios == 0) then
476
-                select case(modifier)
477
-                case(2)  ! Shift
478
-                    key_str = 'shift-'
479
-                case(3)  ! Alt
480
-                    key_str = 'alt-'
481
-                case(4)  ! Alt+Shift
482
-                    key_str = 'alt-shift-'
483
-                case(5)  ! Ctrl
484
-                    key_str = 'ctrl-'
485
-                case(6)  ! Ctrl+Shift
486
-                    key_str = 'ctrl-shift-'
487
-                case(7)  ! Alt+Ctrl
488
-                    key_str = 'alt-ctrl-'
489
-                case(8)  ! Alt+Shift (or Option+Shift)
490
-                    key_str = 'alt-shift-'
491
-                case(9)  ! Alt+Cmd (or Option+Cmd on macOS)
492
-                    key_str = 'opt-meta-'
493
-                case default
494
-                    key_str = ''
495
-                end select
436
+        else if (len_trim(modifier_seq) >= 1 .and. &
437
+                 modifier_seq(1:1) >= '1' .and. modifier_seq(1:1) <= '9') then
438
+            ! Format without leading ';' (already consumed by caller): "2" or "3" etc
439
+            read(modifier_seq(1:len_trim(modifier_seq)), '(i10)', iostat=ios) modifier
440
+        else
441
+            ios = -1
442
+        end if
496443
 
497
-                ! Append the key type using the terminator character
498
-                select case(terminator)
499
-                case('A')
500
-                    key_str = trim(key_str) // 'up'
501
-                case('B')
502
-                    key_str = trim(key_str) // 'down'
503
-                case('C')
504
-                    key_str = trim(key_str) // 'right'
505
-                case('D')
506
-                    key_str = trim(key_str) // 'left'
507
-                case('H')
508
-                    key_str = trim(key_str) // 'home'
509
-                case('F')
510
-                    key_str = trim(key_str) // 'end'
511
-                case('Z')
512
-                    ! Shift+Z could be ctrl-shift-z for redo
513
-                    if (index(key_str, 'ctrl-shift') == 1) then
514
-                        key_str = 'ctrl-shift-z'
515
-                    else
516
-                        key_str = trim(key_str) // 'Z'
517
-                    end if
518
-                case('~')
519
-                    ! Check what special key it is based on the beginning of modifier_seq
520
-                    if (index(modifier_seq, ';') == 1 .and. len_trim(modifier_seq) > 1) then
521
-                        ! Already read the ;2 or ;5 etc, the key type should be before
522
-                        key_str = trim(key_str) // 'unknown'
523
-                    end if
524
-                end select
525
-            end if
444
+        if (ios == 0) then
445
+            select case(modifier)
446
+            case(2)  ! Shift
447
+                key_str = 'shift-'
448
+            case(3)  ! Alt
449
+                key_str = 'alt-'
450
+            case(4)  ! Alt+Shift
451
+                key_str = 'alt-shift-'
452
+            case(5)  ! Ctrl
453
+                key_str = 'ctrl-'
454
+            case(6)  ! Ctrl+Shift
455
+                key_str = 'ctrl-shift-'
456
+            case(7)  ! Alt+Ctrl
457
+                key_str = 'alt-ctrl-'
458
+            case(8)  ! Alt+Shift (or Option+Shift)
459
+                key_str = 'alt-shift-'
460
+            case(9)  ! Alt+Cmd (or Option+Cmd on macOS)
461
+                key_str = 'opt-meta-'
462
+            case default
463
+                key_str = ''
464
+            end select
465
+
466
+            ! Append the key type using the terminator character
467
+            select case(terminator)
468
+            case('A')
469
+                key_str = trim(key_str) // 'up'
470
+            case('B')
471
+                key_str = trim(key_str) // 'down'
472
+            case('C')
473
+                key_str = trim(key_str) // 'right'
474
+            case('D')
475
+                key_str = trim(key_str) // 'left'
476
+            case('H')
477
+                key_str = trim(key_str) // 'home'
478
+            case('F')
479
+                key_str = trim(key_str) // 'end'
480
+            case('Z')
481
+                ! Shift+Z could be ctrl-shift-z for redo
482
+                if (index(key_str, 'ctrl-shift') == 1) then
483
+                    key_str = 'ctrl-shift-z'
484
+                else
485
+                    key_str = trim(key_str) // 'Z'
486
+                end if
487
+            case('~')
488
+                ! Check what special key it is based on the beginning of modifier_seq
489
+                if (index(modifier_seq, ';') == 1 .and. len_trim(modifier_seq) > 1) then
490
+                    ! Already read the ;2 or ;5 etc, the key type should be before
491
+                    key_str = trim(key_str) // 'unknown'
492
+                end if
493
+            end select
526494
         end if
527495
     end subroutine handle_modified_key
528496
 
src/ui/help_display_module.f90modified
@@ -114,7 +114,7 @@ contains
114114
         n_lines = n_lines + 7 + 2   ! PANES
115115
         n_lines = n_lines + 10 + 2  ! GIT
116116
         n_lines = n_lines + 5 + 2   ! FILE
117
-        n_lines = n_lines + 6 + 2   ! LSP
117
+        n_lines = n_lines + 7 + 2   ! LSP (added code actions)
118118
 
119119
         allocate(lines(n_lines))
120120
         i = 1
@@ -244,14 +244,14 @@ contains
244244
         ! LSP (Language Server Protocol)
245245
         lines(i) = "LSP (Language Server Protocol)"; i = i + 1
246246
         lines(i) = "  ctrl-space          code completion"; i = i + 1
247
-        lines(i) = "  ctrl-h              hover information"; i = i + 1
248
-        lines(i) = "  F12                 go to definition"; i = i + 1
249
-        lines(i) = "  shift-F12           find all references"; i = i + 1
247
+        lines(i) = "  F12/alt-g           go to definition"; i = i + 1
248
+        lines(i) = "  shift-F12/alt-r     find all references"; i = i + 1
250249
         lines(i) = "  alt-, (alt-comma)   jump back (navigation history)"; i = i + 1
251250
         lines(i) = "  F2                  rename symbol"; i = i + 1
252
-        lines(i) = "  F4                  document symbols (outline)"; i = i + 1
253
-        lines(i) = "  F6                  workspace symbols (search project)"; i = i + 1
254
-        lines(i) = "  F8                  toggle diagnostics panel (errors)"; i = i + 1
251
+        lines(i) = "  F10/alt-.           code actions (quick fixes)"; i = i + 1
252
+        lines(i) = "  F4/alt-o            document symbols (outline)"; i = i + 1
253
+        lines(i) = "  F6/alt-p            workspace symbols (search project)"; i = i + 1
254
+        lines(i) = "  F8/alt-e            toggle diagnostics panel (errors)"; i = i + 1
255255
         lines(i) = "  ctrl-p              command palette"; i = i + 1
256256
         lines(i) = ""; i = i + 1
257257
 
src/ui/rename_prompt_module.f90modified
@@ -23,18 +23,6 @@ contains
2323
         ! Show the text prompt
2424
         call show_text_prompt(trim(prompt_text), input_text, cancelled, screen_rows)
2525
 
26
-        ! Debug logging
27
-        block
28
-            integer :: debug_unit
29
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
30
-            write(debug_unit, '(A)') '>>> RENAME PROMPT RETURNED <<<'
31
-            write(debug_unit, '(A,L1)') 'Cancelled: ', cancelled
32
-            write(debug_unit, '(A)') 'Input text: "' // trim(input_text) // '"'
33
-            write(debug_unit, '(A)') 'Old name: "' // trim(old_name) // '"'
34
-            write(debug_unit, '(A,I0)') 'Input length: ', len_trim(input_text)
35
-            close(debug_unit)
36
-        end block
37
-
3826
         if (.not. cancelled) then
3927
             if (len_trim(input_text) > 0 .and. trim(input_text) /= trim(old_name)) then
4028
                 allocate(character(len=len_trim(input_text)) :: new_name)
@@ -43,19 +31,6 @@ contains
4331
                 cancelled = .true.
4432
             end if
4533
         end if
46
-
47
-        ! Debug logging after check
48
-        block
49
-            integer :: debug_unit
50
-            open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write')
51
-            write(debug_unit, '(A,L1)') 'Final cancelled: ', cancelled
52
-            if (allocated(new_name)) then
53
-                write(debug_unit, '(A)') 'New name allocated: "' // trim(new_name) // '"'
54
-            else
55
-                write(debug_unit, '(A)') 'New name NOT allocated'
56
-            end if
57
-            close(debug_unit)
58
-        end block
5934
     end subroutine show_rename_prompt
6035
 
6136
 end module rename_prompt_module
src/workspace/workspace_module.f90modified
@@ -231,25 +231,9 @@ contains
231231
         success = .false.
232232
         workspace_file = trim(dir_path) // "/.fac/workspace.json"
233233
 
234
-        ! DEBUG: Write to stderr (unit 0) so it doesn't interfere
235
-        write(0, '(A)') '[DEBUG SAVE] workspace_save_state called'
236
-        write(0, '(A)') '[DEBUG SAVE] Workspace file: ' // trim(workspace_file)
237
-        if (allocated(editor%tabs)) then
238
-            write(0, '(A,I0)') '[DEBUG SAVE] Tabs allocated, size: ', size(editor%tabs)
239
-            if (size(editor%tabs) > 0) then
240
-                write(0, '(A)') '[DEBUG SAVE] First tab filename: ' // trim(editor%tabs(1)%filename)
241
-            end if
242
-        else
243
-            write(0, '(A)') '[DEBUG SAVE] ERROR: Tabs not allocated!'
244
-        end if
245
-        write(0, '(A,I0)') '[DEBUG SAVE] Active tab index: ', editor%active_tab_index
246
-
247234
         ! Open file for writing
248235
         open(newunit=unit, file=workspace_file, status='replace', iostat=ios)
249
-        if (ios /= 0) then
250
-            write(0, '(A,I0)') '[DEBUG SAVE] ERROR: Failed to open file, ios=', ios
251
-            return
252
-        end if
236
+        if (ios /= 0) return
253237
 
254238
         ! Get current timestamp (simplified)
255239
         call date_and_time(timestamp)
@@ -263,7 +247,6 @@ contains
263247
 
264248
         ! Write tabs
265249
         if (allocated(editor%tabs)) then
266
-            write(0, '(A,I0)') '[DEBUG SAVE] Writing ', size(editor%tabs), ' tabs'
267250
             ws_len = len_trim(dir_path)
268251
             do i = 1, size(editor%tabs)
269252
                 ! Write tab start - must be on its own line for parser
@@ -426,33 +409,18 @@ contains
426409
         logical :: file_exists
427410
         integer :: load_status, tab_idx, pane_count, file_unit
428411
         character(len=20) :: value_str
429
-        character(len=512) :: warning_msg
430
-
431
-        ! DEBUG: Start of restoration
432
-        write(0, '(A)') '[DEBUG RESTORE WS] workspace_restore_state called'
433
-        write(0, '(A)') '[DEBUG RESTORE WS] Dir path: ' // trim(dir_path)
434412
 
435413
         success = .false.
436414
         workspace_file = trim(dir_path) // "/.fac/workspace.json"
437415
 
438
-        write(0, '(A)') '[DEBUG RESTORE WS] Workspace file: ' // trim(workspace_file)
439
-
440416
         ! Open workspace file
441417
         open(newunit=unit, file=workspace_file, status='old', iostat=ios)
442418
         if (ios /= 0) then
443
-            ! Workspace file doesn't exist or can't be read (Phase 7: error handling)
444
-            write(0, '(A,I0)') '[DEBUG RESTORE WS] ERROR: Failed to open workspace.json, ios=', ios
445
-            warning_msg = "Warning: Could not open workspace.json - using empty workspace"
446
-            call terminal_write(trim(warning_msg))
447
-            ! Brief pause so user can see the warning
448
-            call execute_command_line("sleep 1.0", wait=.true.)
449
-            ! Initialize a new workspace instead
419
+            ! Workspace file doesn't exist or can't be read - initialize new workspace
450420
             call workspace_init(dir_path, success)
451421
             return
452422
         end if
453423
 
454
-        write(0, '(A)') '[DEBUG RESTORE WS] Workspace file opened successfully'
455
-
456424
         ! Parse JSON line by line (simple parser for our specific format)
457425
         in_tabs_array = .false.
458426
         reading_tab = .false.
@@ -601,28 +569,19 @@ contains
601569
                         end if
602570
 
603571
                         if (.not. file_exists) then
604
-                            ! File doesn't exist - show warning and skip this tab
605
-                            warning_msg = "Warning: File not found (skipping): " // trim(full_path)
606
-                            call terminal_write(trim(warning_msg))
607
-                            ! Brief pause so user can see the warning
608
-                            call execute_command_line("sleep 0.8", wait=.true.)
609
-                            ! Continue to next tab without creating this one
572
+                            ! File doesn't exist - skip this tab silently
610573
                             reading_pane = .false.
611574
                             cycle
612575
                         end if
613576
 
614577
                         ! Create tab
615
-                        write(0, '(A)') '[DEBUG RESTORE WS] Creating tab for file: ' // trim(full_path)
616578
                         call create_tab(editor, trim(full_path))
617579
                         tab_idx = editor%active_tab_index
618580
 
619581
                         ! Set orphan flag and load file
620582
                         if (allocated(editor%tabs) .and. tab_idx > 0) then
621
-                            write(0, '(A,I0)') '[DEBUG RESTORE WS] Tab created successfully, index: ', tab_idx
622583
                             editor%tabs(tab_idx)%is_orphan = is_orphan
623
-
624584
                             call buffer_load_file(editor%tabs(tab_idx)%buffer, trim(full_path), load_status)
625
-                            write(0, '(A,I0)') '[DEBUG RESTORE WS] Buffer loaded, status: ', load_status
626585
 
627586
                             ! Send LSP didOpen notification for restored tabs
628587
                             if (load_status == 0 .and. editor%tabs(tab_idx)%num_lsp_servers > 0) then
@@ -799,11 +758,8 @@ contains
799758
 
800759
         close(unit)
801760
 
802
-        write(0, '(A)') '[DEBUG RESTORE WS] Finished parsing JSON'
803
-
804761
         ! Clamp active_tab_index to valid range
805762
         if (allocated(editor%tabs)) then
806
-            write(0, '(A,I0)') '[DEBUG RESTORE WS] Tabs allocated, count: ', size(editor%tabs)
807763
             if (size(editor%tabs) > 0) then
808764
                 if (editor%active_tab_index > size(editor%tabs)) then
809765
                     editor%active_tab_index = size(editor%tabs)
@@ -812,16 +768,12 @@ contains
812768
                     editor%active_tab_index = 1
813769
                 end if
814770
             else
815
-                write(0, '(A)') '[DEBUG RESTORE WS] No tabs in array!'
816771
                 editor%active_tab_index = 0  ! No tabs
817772
             end if
818773
         else
819
-            write(0, '(A)') '[DEBUG RESTORE WS] Tabs NOT allocated!'
820774
             editor%active_tab_index = 0  ! No tabs
821775
         end if
822776
 
823
-        write(0, '(A,I0)') '[DEBUG RESTORE WS] Final active_tab_index: ', editor%active_tab_index
824
-
825777
         ! Sync the active pane to editor state so status bar shows correct filename
826778
         if (allocated(editor%tabs) .and. editor%active_tab_index > 0) then
827779
             if (editor%active_tab_index <= size(editor%tabs)) then
@@ -829,7 +781,6 @@ contains
829781
                     if (editor%tabs(editor%active_tab_index)%active_pane_index > 0 .and. &
830782
                         editor%tabs(editor%active_tab_index)%active_pane_index <= &
831783
                         size(editor%tabs(editor%active_tab_index)%panes)) then
832
-                        write(0, '(A)') '[DEBUG RESTORE WS] Syncing active pane to editor'
833784
                         call sync_pane_to_editor(editor, editor%active_tab_index, &
834785
                                                 editor%tabs(editor%active_tab_index)%active_pane_index)
835786
                     end if
@@ -838,7 +789,6 @@ contains
838789
         end if
839790
 
840791
         success = .true.
841
-        write(0, '(A)') '[DEBUG RESTORE WS] workspace_restore_state completed successfully'
842792
     end subroutine workspace_restore_state
843793
 
844794
     !> Track workspace in recents (helper function)
tests/scratch_files/calculator.pymodified
@@ -11,6 +11,7 @@ Test these features:
1111
 - Formatting: Shift+Alt+F to format
1212
 """
1313
 
14
+
1415
 def add(x, y):
1516
     """Add two numbers together."""
1617
     return x + y
tests/scratch_files/long_errors.pymodified
@@ -1,6 +1,6 @@
11
 # Test file with errors that generate long diagnostic messages
22
 
3
-from typing import Dict, List, Optional, Union, Callable
3
+from typing import Callable, Dict, List, Optional, Union
44
 
55
 # Type mismatch with long type names
66
 def process_data(