fortrangoingonforty/facsimile / 909f062

Browse files

don't perform eol behavior on cursor up on empty line

Authored by espadonne
SHA
909f06257f6b720323efb69086e0263a353c92cc
Parents
c4b4cfb
Tree
19dcf56

6 changed files

StatusFile+-
M app/main.f90 8 0
M src/commands/command_handler_module.f90 33 27
M src/editor_state_module.f90 10 0
M src/terminal/renderer_module.f90 20 0
M src/ui/command_palette_module.f90 28 12
M src/ui/unified_search_module.f90 3 4
app/main.f90modified
@@ -20,6 +20,8 @@ program facsimile
2020
                                          notify_file_closed, process_server_messages, &
2121
                                          set_diagnostics_handler, set_lsp_workspace_root
2222
     use lsp_protocol_module, only: lsp_message_t
23
+    use app_state_module, only: is_first_run, mark_first_run_complete
24
+    use lsp_server_installer_panel_module, only: show_lsp_server_installer_panel
2325
     implicit none
2426
 
2527
     type(editor_state_t) :: editor
@@ -352,6 +354,12 @@ program facsimile
352354
     ! Save initial file state for undo (position 0)
353355
     call save_initial_state_for_undo(buffer, editor)
354356
 
357
+    ! First-run experience: show LSP server installer panel
358
+    if (is_first_run()) then
359
+        call show_lsp_server_installer_panel(editor%lsp_installer_panel)
360
+        call mark_first_run_complete()
361
+    end if
362
+
355363
     ! Initial render
356364
     call render_screen(buffer, editor, allocated(search_pattern), match_case_sensitive)
357365
 
src/commands/command_handler_module.f90modified
@@ -65,6 +65,12 @@ module command_handler_module
6565
     use diagnostics_module, only: get_diagnostics_for_line, get_diagnostics_for_line_by_server, &
6666
                                   diagnostics_to_json, diagnostic_t
6767
     use json_module, only: json_value_t
68
+    use lsp_server_installer_panel_module, only: show_lsp_server_installer_panel, &
69
+                                                  hide_lsp_server_installer_panel, &
70
+                                                  is_lsp_server_installer_panel_visible, &
71
+                                                  lsp_server_installer_panel_handle_key, &
72
+                                                  render_lsp_server_installer_panel, &
73
+                                                  refresh_server_status
6874
     implicit none
6975
     private
7076
 
@@ -252,6 +258,15 @@ contains
252258
             end if
253259
         end if
254260
 
261
+        ! Route keys to LSP server installer panel when visible
262
+        if (is_lsp_server_installer_panel_visible(editor%lsp_installer_panel)) then
263
+            if (lsp_server_installer_panel_handle_key(editor%lsp_installer_panel, trim(key_str))) then
264
+                call render_lsp_server_installer_panel(editor%lsp_installer_panel, &
265
+                    editor%screen_rows, editor%screen_cols)
266
+                return
267
+            end if
268
+        end if
269
+
255270
         select case(trim(key_str))
256271
         ! File operations
257272
         case('ctrl-q')
@@ -1719,6 +1734,15 @@ contains
17191734
             ! Re-render screen to show/hide the panel
17201735
             call render_screen(buffer, editor)
17211736
 
1737
+        case('alt-m')
1738
+            ! Toggle LSP server installer panel (Alt+M for Manager)
1739
+            if (is_lsp_server_installer_panel_visible(editor%lsp_installer_panel)) then
1740
+                call hide_lsp_server_installer_panel(editor%lsp_installer_panel)
1741
+            else
1742
+                call show_lsp_server_installer_panel(editor%lsp_installer_panel)
1743
+            end if
1744
+            call render_screen(buffer, editor)
1745
+
17221746
         case('alt-c')
17231747
             ! Toggle case sensitivity for match mode (ctrl-d)
17241748
             ! Only has effect when in active match mode (search_pattern allocated)
@@ -1860,28 +1884,19 @@ contains
18601884
     subroutine move_cursor_up(cursor, buffer)
18611885
         type(cursor_t), intent(inout) :: cursor
18621886
         type(buffer_t), intent(in) :: buffer
1863
-        character(len=:), allocatable :: current_line, target_line
1887
+        character(len=:), allocatable :: target_line
18641888
 
18651889
         cursor%has_selection = .false.  ! Clear selection
18661890
         if (cursor%line > 1) then
1867
-            current_line = buffer_get_line(buffer, cursor%line)
18681891
             cursor%line = cursor%line - 1
18691892
             target_line = buffer_get_line(buffer, cursor%line)
18701893
 
1871
-            ! If on empty line with no goal column established, go to end of target line
1872
-            ! Otherwise, use the goal column
1873
-            if (len(current_line) == 0 .and. cursor%desired_column == 1) then
1894
+            ! Always use goal column, clamped to line bounds (standard editor behavior)
1895
+            cursor%column = cursor%desired_column
1896
+            if (cursor%column > len(target_line) + 1) then
18741897
                 cursor%column = len(target_line) + 1
1875
-                cursor%desired_column = cursor%column
1876
-            else
1877
-                ! Use goal column, clamped to line bounds
1878
-                cursor%column = cursor%desired_column
1879
-                if (cursor%column > len(target_line) + 1) then
1880
-                    cursor%column = len(target_line) + 1
1881
-                end if
18821898
             end if
18831899
 
1884
-            if (allocated(current_line)) deallocate(current_line)
18851900
             if (allocated(target_line)) deallocate(target_line)
18861901
         end if
18871902
     end subroutine move_cursor_up
@@ -1890,28 +1905,19 @@ contains
18901905
         type(cursor_t), intent(inout) :: cursor
18911906
         type(buffer_t), intent(in) :: buffer
18921907
         integer, intent(in) :: line_count
1893
-        character(len=:), allocatable :: current_line, target_line
1908
+        character(len=:), allocatable :: target_line
18941909
 
18951910
         cursor%has_selection = .false.  ! Clear selection
18961911
         if (cursor%line < line_count) then
1897
-            current_line = buffer_get_line(buffer, cursor%line)
18981912
             cursor%line = cursor%line + 1
18991913
             target_line = buffer_get_line(buffer, cursor%line)
19001914
 
1901
-            ! If on empty line with no goal column established, go to col 1 of target line
1902
-            ! Otherwise, use the goal column
1903
-            if (len(current_line) == 0 .and. cursor%desired_column == 1) then
1904
-                cursor%column = 1
1905
-                ! desired_column stays 1
1906
-            else
1907
-                ! Use goal column, clamped to line bounds
1908
-                cursor%column = cursor%desired_column
1909
-                if (cursor%column > len(target_line) + 1) then
1910
-                    cursor%column = len(target_line) + 1
1911
-                end if
1915
+            ! Always use goal column, clamped to line bounds (standard editor behavior)
1916
+            cursor%column = cursor%desired_column
1917
+            if (cursor%column > len(target_line) + 1) then
1918
+                cursor%column = len(target_line) + 1
19121919
             end if
19131920
 
1914
-            if (allocated(current_line)) deallocate(current_line)
19151921
             if (allocated(target_line)) deallocate(target_line)
19161922
         end if
19171923
     end subroutine move_cursor_down
src/editor_state_module.f90modified
@@ -31,6 +31,9 @@ module editor_state_module
3131
                                     cleanup_document_sync
3232
     use jump_stack_module, only: jump_stack_t, init_jump_stack, &
3333
                                  cleanup_jump_stack
34
+    use lsp_server_installer_panel_module, only: lsp_server_installer_panel_t, &
35
+                                                  init_lsp_server_installer_panel, &
36
+                                                  cleanup_lsp_server_installer_panel
3437
     implicit none
3538
     private
3639
 
@@ -135,6 +138,7 @@ module editor_state_module
135138
         type(signature_tooltip_t) :: signature_tooltip
136139
         type(command_palette_t) :: command_palette
137140
         type(workspace_symbols_panel_t) :: workspace_symbols_panel
141
+        type(lsp_server_installer_panel_t) :: lsp_installer_panel
138142
 
139143
         ! Navigation
140144
         type(jump_stack_t) :: jump_stack
@@ -199,6 +203,9 @@ contains
199203
 
200204
         ! Initialize jump stack
201205
         call init_jump_stack(editor%jump_stack)
206
+
207
+        ! Initialize LSP server installer panel
208
+        call init_lsp_server_installer_panel(editor%lsp_installer_panel)
202209
     end subroutine init_editor
203210
 
204211
     subroutine cleanup_editor(editor)
@@ -252,6 +259,9 @@ contains
252259
 
253260
         ! Cleanup jump stack
254261
         call cleanup_jump_stack(editor%jump_stack)
262
+
263
+        ! Cleanup LSP server installer panel
264
+        call cleanup_lsp_server_installer_panel(editor%lsp_installer_panel)
255265
     end subroutine cleanup_editor
256266
 
257267
     ! Helper to cleanup a single tab
src/terminal/renderer_module.f90modified
@@ -16,6 +16,8 @@ module renderer_module
1616
     use code_actions_panel_module, only: render_code_actions_panel
1717
     use symbols_panel_module, only: render_symbols_panel
1818
     use unified_search_module, only: get_matches_on_line, search_mode_active
19
+    use lsp_server_installer_panel_module, only: render_lsp_server_installer_panel, &
20
+                                                  is_lsp_server_installer_panel_visible
1921
     implicit none
2022
     private
2123
 
@@ -214,6 +216,12 @@ contains
214216
                 ! Render symbols panel if visible (for panes path)
215217
                 call render_symbols_panel(editor%symbols_panel, editor%screen_rows)
216218
 
219
+                ! Render LSP server installer panel if visible (for panes path)
220
+                if (is_lsp_server_installer_panel_visible(editor%lsp_installer_panel)) then
221
+                    call render_lsp_server_installer_panel(editor%lsp_installer_panel, &
222
+                        editor%screen_rows, editor%screen_cols)
223
+                end if
224
+
217225
                 ! Position cursor for panes
218226
                 call render_cursor_for_panes(editor)
219227
                 return  ! Exit after rendering panes
@@ -285,6 +293,12 @@ contains
285293
         ! Render symbols panel if visible
286294
         call render_symbols_panel(editor%symbols_panel, editor%screen_rows)
287295
 
296
+        ! Render LSP server installer panel if visible
297
+        if (is_lsp_server_installer_panel_visible(editor%lsp_installer_panel)) then
298
+            call render_lsp_server_installer_panel(editor%lsp_installer_panel, &
299
+                editor%screen_rows, editor%screen_cols)
300
+        end if
301
+
288302
         ! Position cursor for panes or regular view
289303
         if (size(editor%tabs) > 0 .and. editor%active_tab_index > 0 .and. &
290304
             editor%active_tab_index <= size(editor%tabs)) then
@@ -891,6 +905,12 @@ contains
891905
         ! Render symbols panel if visible
892906
         call render_symbols_panel(editor%symbols_panel, editor%screen_rows)
893907
 
908
+        ! Render LSP server installer panel if visible
909
+        if (is_lsp_server_installer_panel_visible(editor%lsp_installer_panel)) then
910
+            call render_lsp_server_installer_panel(editor%lsp_installer_panel, &
911
+                editor%screen_rows, editor%screen_cols)
912
+        end if
913
+
894914
         ! Position cursor in editor pane (use appropriate method based on pane count)
895915
         if (size(editor%tabs(editor%active_tab_index)%panes) > 1) then
896916
             ! Multiple panes: use pane-aware cursor rendering with tree offset
src/ui/command_palette_module.f90modified
@@ -323,17 +323,21 @@ contains
323323
         ! Draw header line with cyan title
324324
         row = start_row + 1
325325
         call terminal_move_cursor(row, start_col)
326
-        call terminal_write('│' // CYAN // ' Command Palette' // RESET)
327
-        display_width = 17  ! " Command Palette" length
328
-        call terminal_write(repeat(' ', content_width - display_width - 2) // '│')
326
+        call terminal_write('│')
327
+        call terminal_write(CYAN // ' Command Palette' // RESET)
328
+        display_width = 16  ! " Command Palette" visible length
329
+        call terminal_write(repeat(' ', max(0, content_width - 2 - display_width)))
330
+        call terminal_write('│')
329331
 
330332
         ! Draw search query line with yellow prompt
331333
         row = row + 1
332334
         call terminal_move_cursor(row, start_col)
333
-        call terminal_write('│' // YELLOW // ' > ' // RESET)
335
+        call terminal_write('│')
336
+        call terminal_write(YELLOW // ' > ' // RESET)
334337
         call terminal_write(trim(palette%search_query))
335
-        display_width = 3 + len_trim(palette%search_query)
336
-        call terminal_write(repeat(' ', content_width - display_width - 2) // '│')
338
+        display_width = 3 + len_trim(palette%search_query)  ! " > " + query length
339
+        call terminal_write(repeat(' ', max(0, content_width - 2 - display_width)))
340
+        call terminal_write('│')
337341
 
338342
         ! Draw separator
339343
         row = row + 1
@@ -352,7 +356,7 @@ contains
352356
             call terminal_move_cursor(row, start_col)
353357
             call terminal_write('│')
354358
 
355
-            ! Build line with category, name, and shortcut
359
+            ! Build line with category, name, and shortcut (for display_width calculation)
356360
             if (len_trim(cmd%category) > 0) then
357361
                 write(category_tag, '(A,A,A)') '[', trim(cmd%category), '] '
358362
             else
@@ -366,17 +370,29 @@ contains
366370
                 write(line, '(A,A,A)') trim(line), '  ', trim(cmd%shortcut)
367371
             end if
368372
 
369
-            ! Truncate if too long
370
-            display_width = min(len_trim(line), content_width - 3)
373
+            ! Calculate visible width (actual characters, no ANSI codes)
374
+            display_width = len_trim(line)
375
+
376
+            ! Ensure it fits
377
+            if (display_width > content_width - 2) then
378
+                display_width = content_width - 2
379
+            end if
380
+
381
+            ! Calculate padding
382
+            display_width = max(0, min(display_width, content_width - 2))
371383
 
372384
             if (i == palette%selected_index) then
373385
                 ! Highlight selected item with inverse colors
374
-                call terminal_write(INVERSE // line(1:display_width))
375
-                call terminal_write(repeat(' ', content_width - display_width - 2) // RESET // '│')
386
+                call terminal_write(INVERSE)
387
+                call terminal_write(line(1:display_width))
388
+                call terminal_write(repeat(' ', max(0, content_width - 2 - display_width)))
389
+                call terminal_write(RESET)
376390
             else
377391
                 call terminal_write(line(1:display_width))
378
-                call terminal_write(repeat(' ', content_width - display_width - 2) // '│')
392
+                call terminal_write(repeat(' ', max(0, content_width - 2 - display_width)))
379393
             end if
394
+
395
+            call terminal_write('│')
380396
         end do
381397
 
382398
         ! Fill remaining visible slots with empty rows
src/ui/unified_search_module.f90modified
@@ -4,7 +4,6 @@ module unified_search_module
44
     use editor_state_module, only: editor_state_t, cursor_t, sync_editor_to_pane
55
     use text_buffer_module
66
     use regex_module
7
-    use renderer_module, only: render_screen
87
     implicit none
98
     private
109
 
@@ -239,10 +238,10 @@ contains
239238
                         call search_forward(editor, buffer)
240239
                     end if
241240
 
242
-                    ! Re-render screen to show cursor at new match position
243
-                    call render_screen(buffer, editor)
241
+                    ! Note: Screen re-rendering happens in command_handler after search exits
242
+                    ! The match highlighting and cursor position will be visible after exiting search
244243
 
245
-                    ! Update prompt with match count (redraw prompt over rendered screen)
244
+                    ! Update prompt with match count
246245
                     call build_unified_prompt(prompt, find_buffer, find_pos, replace_buffer, replace_pos)
247246
                     call display_prompt(editor, prompt, find_pos, replace_pos)
248247
                 end if