fortrangoingonforty/fuss / 954f4a6

Browse files

better rename, enter doesn't work

Authored by espadonne
SHA
954f4a6271f529993f277b642c2cf6f30efbef2e
Parents
671e737
Tree
5427d4f

2 changed files

StatusFile+-
M src/display_module.f90 51 29
M src/fuss_main.f90 184 6
src/display_module.f90modified
@@ -129,12 +129,14 @@ contains
129
     end subroutine print_tree_node
129
     end subroutine print_tree_node
130
 
130
 
131
     subroutine draw_interactive_tree(tree_root, items, n_items, selected, &
131
     subroutine draw_interactive_tree(tree_root, items, n_items, selected, &
132
-                                     repo_name, branch_name, viewport_offset, visible_items, top_padding, mode)
132
+                                     repo_name, branch_name, viewport_offset, visible_items, top_padding, mode, &
133
+                                     in_rename_mode, rename_buffer, rename_cursor_pos)
133
         type(tree_node), pointer, intent(in) :: tree_root
134
         type(tree_node), pointer, intent(in) :: tree_root
134
         integer, intent(in) :: n_items, selected
135
         integer, intent(in) :: n_items, selected
135
         type(selectable_item), intent(in) :: items(:)
136
         type(selectable_item), intent(in) :: items(:)
136
-        character(len=*), intent(in) :: repo_name, branch_name, mode
137
+        character(len=*), intent(in) :: repo_name, branch_name, mode, rename_buffer
137
-        integer, intent(in) :: viewport_offset, visible_items, top_padding
138
+        integer, intent(in) :: viewport_offset, visible_items, top_padding, rename_cursor_pos
139
+        logical, intent(in) :: in_rename_mode
138
         integer :: item_idx, viewport_end, i
140
         integer :: item_idx, viewport_end, i
139
         character(len=512) :: status_line
141
         character(len=512) :: status_line
140
 
142
 
@@ -172,36 +174,39 @@ contains
172
         item_idx = 0
174
         item_idx = 0
173
         print '(A)', '.'
175
         print '(A)', '.'
174
         call print_interactive_node(tree_root, '', .true., .true., items, selected, &
176
         call print_interactive_node(tree_root, '', .true., .true., items, selected, &
175
-                                    item_idx, viewport_offset, viewport_end)
177
+                                    item_idx, viewport_offset, viewport_end, in_rename_mode, rename_buffer, rename_cursor_pos)
176
 
178
 
177
-        ! Print help (mode-dependent)
179
+        ! Print help (mode and rename state dependent)
178
         print '(A)', ''
180
         print '(A)', ''
179
-        if (mode == 'git') then
181
+        if (in_rename_mode) then
182
+            ! Rename mode help - show in cyan
183
+            print '(A)', achar(27) // '[36mRENAME MODE: Type new name | ←/→:move cursor | Backspace:delete | Enter/Tab:confirm | ESC:cancel' // achar(27) // '[0m'
184
+        else if (mode == 'git') then
180
             ! Git mode help - show in yellow tint
185
             ! Git mode help - show in yellow tint
181
             print '(A)', achar(27) // '[33mLegend: ' // achar(27) // '[32m↑' // achar(27) // '[0m=staged ' // &
186
             print '(A)', achar(27) // '[33mLegend: ' // achar(27) // '[32m↑' // achar(27) // '[0m=staged ' // &
182
                          achar(27) // '[31m✗' // achar(27) // '[0m=modified ' // &
187
                          achar(27) // '[31m✗' // achar(27) // '[0m=modified ' // &
183
                          achar(27) // '[90m✗' // achar(27) // '[0m=untracked ' // &
188
                          achar(27) // '[90m✗' // achar(27) // '[0m=untracked ' // &
184
                          achar(27) // '[34m↓' // achar(27) // '[0m=incoming' // achar(27) // '[0m'
189
                          achar(27) // '[34m↓' // achar(27) // '[0m=incoming' // achar(27) // '[0m'
185
-            print '(A)', achar(27) // '[33mKeys: j/k/↑/↓:nav | ←/→:nav tree | space:toggle | .:hide-dots | a:stage | u:unstage | S:stage-all | U:unstage-all | x:discard | z:stash | Z:unstash | b:switch | n:new-br | R:del-br | G:merge | O:reset | I:rebase | f:fetch | d:diff | c/alt-v:view | w:blame | h:history | L:reflog | y:cherry-pick | v:revert | r:delete | l:pull | m:commit | M:amend | p:push | t:tag | s/alt-s:status | q:exit-mode | ESC:exit-mode | ctrl-c:quit' // achar(27) // '[0m'
190
+            print '(A)', achar(27) // '[33mKeys: j/k/↑/↓:nav | ←/→:nav tree | space:toggle | .:hide-dots | alt-n:rename | a:stage | u:unstage | S:stage-all | U:unstage-all | x:discard | z:stash | Z:unstash | b:switch | n:new-br | R:del-br | G:merge | O:reset | I:rebase | f:fetch | d:diff | c/alt-v:view | w:blame | h:history | L:reflog | y:cherry-pick | v:revert | r:delete | l:pull | m:commit | M:amend | p:push | t:tag | s/alt-s:status | q:exit-mode | ESC:exit-mode | ctrl-c:quit' // achar(27) // '[0m'
186
         else
191
         else
187
             ! Normal mode help
192
             ! Normal mode help
188
             print '(A)', 'Legend: ' // achar(27) // '[32m↑' // achar(27) // '[0m=staged ' // &
193
             print '(A)', 'Legend: ' // achar(27) // '[32m↑' // achar(27) // '[0m=staged ' // &
189
                          achar(27) // '[31m✗' // achar(27) // '[0m=modified ' // &
194
                          achar(27) // '[31m✗' // achar(27) // '[0m=modified ' // &
190
                          achar(27) // '[90m✗' // achar(27) // '[0m=untracked ' // &
195
                          achar(27) // '[90m✗' // achar(27) // '[0m=untracked ' // &
191
                          achar(27) // '[34m↓' // achar(27) // '[0m=incoming'
196
                          achar(27) // '[34m↓' // achar(27) // '[0m=incoming'
192
-            print '(A)', 'Keys: j/k/↑/↓:nav | ←/→:nav tree | space:toggle | .:hide-dots | alt-v:view | alt-s:status | alt-g:git-mode | ctrl-c:quit'
197
+            print '(A)', 'Keys: j/k/↑/↓:nav | ←/→:nav tree | space:toggle | .:hide-dots | alt-n:rename | alt-v:view | alt-s:status | alt-g:git-mode | ctrl-c:quit'
193
         end if
198
         end if
194
 
199
 
195
         ! Don't free tree - it's owned by interactive_mode
200
         ! Don't free tree - it's owned by interactive_mode
196
     end subroutine draw_interactive_tree
201
     end subroutine draw_interactive_tree
197
 
202
 
198
     recursive subroutine print_interactive_node(node, prefix, is_last, is_root, items, selected, &
203
     recursive subroutine print_interactive_node(node, prefix, is_last, is_root, items, selected, &
199
-                                                item_idx, viewport_offset, viewport_end)
204
+                                                item_idx, viewport_offset, viewport_end, in_rename_mode, rename_buffer, rename_cursor_pos)
200
         type(tree_node), pointer, intent(in) :: node
205
         type(tree_node), pointer, intent(in) :: node
201
-        character(len=*), intent(in) :: prefix
206
+        character(len=*), intent(in) :: prefix, rename_buffer
202
-        logical, intent(in) :: is_last, is_root
207
+        logical, intent(in) :: is_last, is_root, in_rename_mode
203
         type(selectable_item), intent(in) :: items(:)
208
         type(selectable_item), intent(in) :: items(:)
204
-        integer, intent(in) :: selected, viewport_offset, viewport_end
209
+        integer, intent(in) :: selected, viewport_offset, viewport_end, rename_cursor_pos
205
         integer, intent(inout) :: item_idx
210
         integer, intent(inout) :: item_idx
206
 
211
 
207
         character(len=1024) :: line
212
         character(len=1024) :: line
@@ -262,24 +267,41 @@ contains
262
 
267
 
263
                 ! Add name with highlighting if selected
268
                 ! Add name with highlighting if selected
264
                 if (is_selected) then
269
                 if (is_selected) then
265
-                    if (node%is_gitignored) then
270
+                    ! Special handling for rename mode
266
-                        line = trim(line) // highlight_on // ESC // '[90m' // trim(node%name) // ESC // '[0m'
271
+                    if (in_rename_mode) then
272
+                        ! Show editable name with cursor at correct position
273
+                        if (rename_cursor_pos == len_trim(rename_buffer)) then
274
+                            ! Cursor at end
275
+                            line = trim(line) // highlight_on // trim(rename_buffer) // '█' // highlight_off
276
+                        else if (rename_cursor_pos == 0) then
277
+                            ! Cursor at beginning
278
+                            line = trim(line) // highlight_on // '█' // trim(rename_buffer) // highlight_off
279
+                        else
280
+                            ! Cursor in middle
281
+                            line = trim(line) // highlight_on // rename_buffer(1:rename_cursor_pos) // '█' // &
282
+                                   rename_buffer(rename_cursor_pos+1:len_trim(rename_buffer)) // highlight_off
283
+                        end if
267
                     else
284
                     else
268
-                        line = trim(line) // highlight_on // trim(node%name)
285
+                        ! Normal selection highlighting
269
-                    end if
286
+                        if (node%is_gitignored) then
270
-                    if (node%is_staged) then
287
+                            line = trim(line) // highlight_on // ESC // '[90m' // trim(node%name) // ESC // '[0m'
271
-                        line = trim(line) // trim(mark_staged)
288
+                        else
272
-                    end if
289
+                            line = trim(line) // highlight_on // trim(node%name)
273
-                    if (node%is_unstaged) then
290
+                        end if
274
-                        line = trim(line) // trim(mark_unstaged)
291
+                        if (node%is_staged) then
275
-                    end if
292
+                            line = trim(line) // trim(mark_staged)
276
-                    if (node%is_untracked) then
293
+                        end if
277
-                        line = trim(line) // trim(mark_untracked)
294
+                        if (node%is_unstaged) then
278
-                    end if
295
+                            line = trim(line) // trim(mark_unstaged)
279
-                    if (node%has_incoming) then
296
+                        end if
280
-                        line = trim(line) // trim(mark_incoming)
297
+                        if (node%is_untracked) then
298
+                            line = trim(line) // trim(mark_untracked)
299
+                        end if
300
+                        if (node%has_incoming) then
301
+                            line = trim(line) // trim(mark_incoming)
302
+                        end if
303
+                        line = trim(line) // highlight_off
281
                     end if
304
                     end if
282
-                    line = trim(line) // highlight_off
283
                 else
305
                 else
284
                     if (node%is_gitignored) then
306
                     if (node%is_gitignored) then
285
                         line = trim(line) // ESC // '[90m' // trim(node%name) // ESC // '[0m'
307
                         line = trim(line) // ESC // '[90m' // trim(node%name) // ESC // '[0m'
@@ -322,7 +344,7 @@ contains
322
                 end if
344
                 end if
323
 
345
 
324
                 call print_interactive_node(child, new_prefix, i == n_children, .false., items, selected, &
346
                 call print_interactive_node(child, new_prefix, i == n_children, .false., items, selected, &
325
-                                        item_idx, viewport_offset, viewport_end)
347
+                                        item_idx, viewport_offset, viewport_end, in_rename_mode, rename_buffer, rename_cursor_pos)
326
                 child => child%next_sibling
348
                 child => child%next_sibling
327
             end do
349
             end do
328
         end if
350
         end if
src/fuss_main.f90modified
@@ -183,6 +183,11 @@ contains
183
         character(len=32) :: search_buffer
183
         character(len=32) :: search_buffer
184
         integer :: search_length
184
         integer :: search_length
185
         integer(8) :: last_search_tick, current_tick, clock_rate
185
         integer(8) :: last_search_tick, current_tick, clock_rate
186
+        ! Rename state for inline renaming
187
+        logical :: in_rename_mode
188
+        character(len=256) :: rename_buffer
189
+        character(len=256) :: rename_original_name
190
+        integer :: rename_cursor_pos
186
         type(tree_node), pointer :: tree_root
191
         type(tree_node), pointer :: tree_root
187
 
192
 
188
         ! Initialize tree pointer
193
         ! Initialize tree pointer
@@ -256,6 +261,12 @@ contains
256
         last_search_tick = 0
261
         last_search_tick = 0
257
         call system_clock(count_rate=clock_rate)
262
         call system_clock(count_rate=clock_rate)
258
 
263
 
264
+        ! Initialize rename state
265
+        in_rename_mode = .false.
266
+        rename_buffer = ''
267
+        rename_original_name = ''
268
+        rename_cursor_pos = 0
269
+
259
         ! Partial redraw optimization: initialize tracking state
270
         ! Partial redraw optimization: initialize tracking state
260
         prev_selected = 0  ! Force initial draw
271
         prev_selected = 0  ! Force initial draw
261
         prev_viewport = 0
272
         prev_viewport = 0
@@ -283,14 +294,16 @@ contains
283
                 ! Full redraw needed: viewport scrolled or forced refresh
294
                 ! Full redraw needed: viewport scrolled or forced refresh
284
                 call clear_screen()
295
                 call clear_screen()
285
                 call draw_interactive_tree(tree_root, items, n_items, selected, &
296
                 call draw_interactive_tree(tree_root, items, n_items, selected, &
286
-                                           repo_name, branch_name, viewport_offset, visible_items, top_padding, mode)
297
+                                           repo_name, branch_name, viewport_offset, visible_items, top_padding, mode, &
298
+                                           in_rename_mode, rename_buffer, rename_cursor_pos)
287
                 needs_full_redraw = .false.
299
                 needs_full_redraw = .false.
288
             else if (selected /= prev_selected) then
300
             else if (selected /= prev_selected) then
289
                 ! Only selection changed within same viewport - still need full redraw for now
301
                 ! Only selection changed within same viewport - still need full redraw for now
290
                 ! TODO: Could optimize this with partial line updates in the future
302
                 ! TODO: Could optimize this with partial line updates in the future
291
                 call clear_screen()
303
                 call clear_screen()
292
                 call draw_interactive_tree(tree_root, items, n_items, selected, &
304
                 call draw_interactive_tree(tree_root, items, n_items, selected, &
293
-                                           repo_name, branch_name, viewport_offset, visible_items, top_padding, mode)
305
+                                           repo_name, branch_name, viewport_offset, visible_items, top_padding, mode, &
306
+                                           in_rename_mode, rename_buffer, rename_cursor_pos)
294
             end if
307
             end if
295
 
308
 
296
             ! Update tracking state
309
             ! Update tracking state
@@ -340,7 +353,8 @@ contains
340
                 call execute_command_line('stty sane < /dev/tty')
353
                 call execute_command_line('stty sane < /dev/tty')
341
                 call clear_screen()
354
                 call clear_screen()
342
                 call draw_interactive_tree(tree_root, items, n_items, selected, &
355
                 call draw_interactive_tree(tree_root, items, n_items, selected, &
343
-                                           repo_name, branch_name, viewport_offset, visible_items, top_padding, mode)
356
+                                           repo_name, branch_name, viewport_offset, visible_items, top_padding, mode, &
357
+                                           in_rename_mode, rename_buffer, rename_cursor_pos)
344
                 ! Restore cbreak mode
358
                 ! Restore cbreak mode
345
                 call enable_raw_mode()
359
                 call enable_raw_mode()
346
                 cycle  ! Skip rest of key handling
360
                 cycle  ! Skip rest of key handling
@@ -364,15 +378,38 @@ contains
364
                 cycle
378
                 cycle
365
             end if
379
             end if
366
 
380
 
367
-            ! Handle ESC key - exit git mode or clear search
381
+            ! Check for alt-n to enter rename mode (available in both modes)
382
+            ! alt-n is encoded as achar(1 + ichar('n') - ichar('a')) = achar(14)
383
+            if (key == achar(14) .and. .not. in_rename_mode) then
384
+                ! Enter rename mode
385
+                if (associated(items(selected)%node)) then
386
+                    in_rename_mode = .true.
387
+                    rename_original_name = items(selected)%node%name
388
+                    rename_buffer = items(selected)%node%name
389
+                    rename_cursor_pos = len_trim(rename_buffer)
390
+                    needs_full_redraw = .true.
391
+                end if
392
+                cycle
393
+            end if
394
+
395
+            ! Handle ESC key - exit rename mode, git mode, or clear search
368
             if (key == achar(27)) then
396
             if (key == achar(27)) then
369
-                if (mode == 'git') then
397
+                if (in_rename_mode) then
398
+                    ! Cancel rename - restore original name
399
+                    in_rename_mode = .false.
400
+                    rename_buffer = ''
401
+                    rename_original_name = ''
402
+                    rename_cursor_pos = 0
403
+                    needs_full_redraw = .true.
404
+                    cycle
405
+                else if (mode == 'git') then
370
                     mode = 'normal'
406
                     mode = 'normal'
371
                     ! Temporarily restore terminal to flush output properly
407
                     ! Temporarily restore terminal to flush output properly
372
                     call execute_command_line('stty sane < /dev/tty')
408
                     call execute_command_line('stty sane < /dev/tty')
373
                     call clear_screen()
409
                     call clear_screen()
374
                     call draw_interactive_tree(tree_root, items, n_items, selected, &
410
                     call draw_interactive_tree(tree_root, items, n_items, selected, &
375
-                                               repo_name, branch_name, viewport_offset, visible_items, top_padding, mode)
411
+                                               repo_name, branch_name, viewport_offset, visible_items, top_padding, mode, &
412
+                                               in_rename_mode, rename_buffer, rename_cursor_pos)
376
                     ! Restore cbreak mode
413
                     ! Restore cbreak mode
377
                     call enable_raw_mode()
414
                     call enable_raw_mode()
378
                     cycle
415
                     cycle
@@ -387,6 +424,87 @@ contains
387
                 cycle
424
                 cycle
388
             end if
425
             end if
389
 
426
 
427
+            ! Rename mode key handling - intercept all keys when in rename mode
428
+            if (in_rename_mode) then
429
+                ! DEBUG: Log all keys in rename mode
430
+                open(99, file='/tmp/fuss_debug.log', position='append')
431
+                write(99, '(A,I0,A,I0)') 'RENAME MODE: key code=', ichar(key), ' decimal=', ichar(key)
432
+                close(99)
433
+
434
+                ! Handle Enter (multiple possible codes) or Tab to confirm rename
435
+                ! achar(10) = LF, achar(13) = CR, achar(9) = Tab, achar(0) = null
436
+                if (key == achar(10) .or. key == achar(13) .or. key == achar(9) .or. &
437
+                    key == achar(0) .or. ichar(key) == 10 .or. ichar(key) == 13) then
438
+                    ! Enter or Tab - execute rename
439
+                    open(99, file='/tmp/fuss_debug.log', position='append')
440
+                    write(99, '(A)') 'RENAME MODE: ENTER/TAB detected - executing rename'
441
+                    close(99)
442
+                    call execute_rename(items(selected)%path, trim(rename_buffer))
443
+                    in_rename_mode = .false.
444
+                    rename_buffer = ''
445
+                    rename_original_name = ''
446
+                    rename_cursor_pos = 0
447
+                    ! Force refresh to show renamed file
448
+                    call refresh_and_rebuild(show_all, files, n_files, items, n_items, tree_root, &
449
+                                            hide_dotfiles, selected, running, force_refresh=.true.)
450
+                    needs_full_redraw = .true.
451
+                    cycle
452
+                else if (key == achar(127) .or. key == achar(8)) then
453
+                    ! Backspace - delete character before cursor
454
+                    if (rename_cursor_pos > 0) then
455
+                        ! Delete character before cursor
456
+                        if (rename_cursor_pos == len_trim(rename_buffer)) then
457
+                            ! Cursor at end - simple delete
458
+                            rename_buffer = rename_buffer(1:len_trim(rename_buffer)-1)
459
+                        else
460
+                            ! Cursor in middle - delete and shift left
461
+                            rename_buffer = rename_buffer(1:rename_cursor_pos-1) // &
462
+                                          rename_buffer(rename_cursor_pos+1:len_trim(rename_buffer))
463
+                        end if
464
+                        rename_cursor_pos = rename_cursor_pos - 1
465
+                        needs_full_redraw = .true.
466
+                    end if
467
+                    cycle
468
+                else if (key == 'C') then
469
+                    ! Right arrow - move cursor right
470
+                    if (rename_cursor_pos < len_trim(rename_buffer)) then
471
+                        rename_cursor_pos = rename_cursor_pos + 1
472
+                        needs_full_redraw = .true.
473
+                    end if
474
+                    cycle
475
+                else if (key == 'D') then
476
+                    ! Left arrow - move cursor left
477
+                    if (rename_cursor_pos > 0) then
478
+                        rename_cursor_pos = rename_cursor_pos - 1
479
+                        needs_full_redraw = .true.
480
+                    end if
481
+                    cycle
482
+                else if (key == 'A' .or. key == 'B') then
483
+                    ! Up/Down arrows - ignore in rename mode
484
+                    cycle
485
+                else if ((key >= 'a' .and. key <= 'z') .or. &
486
+                         (key >= 'A' .and. key <= 'Z') .or. &
487
+                         (key >= '0' .and. key <= '9') .or. &
488
+                         key == '_' .or. key == '-' .or. key == '.' .or. key == ' ') then
489
+                    ! Printable character - insert at cursor position
490
+                    if (len_trim(rename_buffer) < 255) then
491
+                        if (rename_cursor_pos == len_trim(rename_buffer)) then
492
+                            ! Cursor at end - simple append
493
+                            rename_buffer = trim(rename_buffer) // key
494
+                        else
495
+                            ! Cursor in middle - insert and shift right
496
+                            rename_buffer = rename_buffer(1:rename_cursor_pos) // key // &
497
+                                          rename_buffer(rename_cursor_pos+1:len_trim(rename_buffer))
498
+                        end if
499
+                        rename_cursor_pos = rename_cursor_pos + 1
500
+                        needs_full_redraw = .true.
501
+                    end if
502
+                    cycle
503
+                end if
504
+                ! Ignore all other keys in rename mode
505
+                cycle
506
+            end if
507
+
390
             ! Fuzzy search in normal mode - handle any printable character
508
             ! Fuzzy search in normal mode - handle any printable character
391
             ! Exclude A, B, C, D since those are arrow key codes after escape sequence processing
509
             ! Exclude A, B, C, D since those are arrow key codes after escape sequence processing
392
             if (mode == 'normal') then
510
             if (mode == 'normal') then
@@ -1736,4 +1854,64 @@ contains
1736
         end do
1854
         end do
1737
     end subroutine to_lowercase
1855
     end subroutine to_lowercase
1738
 
1856
 
1857
+    subroutine execute_rename(old_path, new_name)
1858
+        ! Execute file/directory rename
1859
+        character(len=*), intent(in) :: old_path, new_name
1860
+        character(len=1024) :: dirname, new_path, command
1861
+        integer :: status, last_slash
1862
+        logical :: file_exists
1863
+
1864
+        ! Validate new name
1865
+        if (len_trim(new_name) == 0) then
1866
+            call show_message_and_wait('Error: Filename cannot be empty!')
1867
+            return
1868
+        end if
1869
+
1870
+        ! Get directory name from old path
1871
+        last_slash = index(old_path, '/', back=.true.)
1872
+        if (last_slash > 0) then
1873
+            dirname = old_path(1:last_slash)
1874
+        else
1875
+            dirname = './'
1876
+        end if
1877
+
1878
+        ! Build new full path
1879
+        write(new_path, '(A,A)') trim(dirname), trim(new_name)
1880
+
1881
+        ! Check if new path already exists (and it's not the same file)
1882
+        if (trim(new_path) /= trim(old_path)) then
1883
+            inquire(file=trim(new_path), exist=file_exists)
1884
+            if (file_exists) then
1885
+                call show_message_and_wait('Error: A file with that name already exists!')
1886
+                return
1887
+            end if
1888
+        end if
1889
+
1890
+        ! If it's the same name, do nothing
1891
+        if (trim(new_path) == trim(old_path)) then
1892
+            return
1893
+        end if
1894
+
1895
+        ! Execute rename using mv command
1896
+        write(command, '(A,A,A,A,A)') 'mv "', trim(old_path), '" "', trim(new_path), '" 2>/dev/null'
1897
+        call execute_command_line(trim(command), exitstat=status)
1898
+
1899
+        if (status /= 0) then
1900
+            call show_message_and_wait('Error: Rename failed! Check permissions.')
1901
+            return
1902
+        end if
1903
+
1904
+    end subroutine execute_rename
1905
+
1906
+    subroutine show_message_and_wait(message)
1907
+        ! Show a message and wait for user to press a key
1908
+        character(len=*), intent(in) :: message
1909
+        character(len=1) :: key
1910
+
1911
+        print '(A)', ''
1912
+        print '(A)', trim(message)
1913
+        print '(A)', 'Press any key to continue...'
1914
+        call wait_for_key(key)
1915
+    end subroutine show_message_and_wait
1916
+
1739
 end program fuss
1917
 end program fuss