fortrangoingonforty/fit / 576fd05

Browse files

flags for non interactive mode

Authored by espadonne
SHA
576fd055b19b5c1636691ad4695e6e564cd52407
Parents
4ea4bb9
Tree
3d8baf6

3 changed files

StatusFile+-
M app/main.f90 58 6
M src/conflict_parser.f90 186 1
M src/tui_layout.f90 10 8
app/main.f90modified
@@ -7,10 +7,10 @@ program fit
77
     use pane_state
88
     implicit none
99
 
10
-    character(len=512) :: filename
10
+    character(len=512) :: filename, arg
1111
     type(conflict_t), allocatable :: conflicts(:)
12
-    integer :: n_conflicts, current_conflict, ios
13
-    logical :: success, running
12
+    integer :: n_conflicts, current_conflict, ios, i, auto_choice
13
+    logical :: success, running, interactive_mode
1414
     type(key_t) :: key
1515
     integer :: term_rows, term_cols
1616
     character(len=256) :: status_msg
@@ -18,12 +18,37 @@ program fit
1818
 
1919
     ! Parse command line arguments
2020
     if (command_argument_count() < 1) then
21
-        print '(A)', 'Usage: fit <file-with-conflicts>'
21
+        print '(A)', 'Usage: fit <file-with-conflicts> [--incoming|--local|--both]'
22
+        print '(A)', '  --incoming, -i  : Auto-resolve all conflicts with incoming changes'
23
+        print '(A)', '  --local, -l     : Auto-resolve all conflicts with local changes'
24
+        print '(A)', '  --both, -b      : Auto-resolve all conflicts with both changes'
2225
         stop 1
2326
     end if
2427
 
2528
     call get_command_argument(1, filename)
2629
 
30
+    ! Check for non-interactive mode flags
31
+    interactive_mode = .true.
32
+    auto_choice = 0  ! 0=none, 1=incoming, 2=local, 3=both
33
+
34
+    do i = 2, command_argument_count()
35
+        call get_command_argument(i, arg)
36
+        select case (trim(arg))
37
+        case ('--incoming', '-i')
38
+            interactive_mode = .false.
39
+            auto_choice = 1
40
+        case ('--local', '-l')
41
+            interactive_mode = .false.
42
+            auto_choice = 2
43
+        case ('--both', '-b')
44
+            interactive_mode = .false.
45
+            auto_choice = 3
46
+        case default
47
+            print '(A)', 'Error: Unknown argument: ' // trim(arg)
48
+            stop 1
49
+        end select
50
+    end do
51
+
2752
     ! Check if file exists
2853
     open(unit=99, file=trim(filename), status='old', iostat=ios)
2954
     if (ios /= 0) then
@@ -45,6 +70,33 @@ program fit
4570
         stop 0
4671
     end if
4772
 
73
+    ! Handle non-interactive mode
74
+    if (.not. interactive_mode) then
75
+        ! Apply auto_choice to all conflicts
76
+        do i = 1, n_conflicts
77
+            conflicts(i)%choice = auto_choice
78
+        end do
79
+
80
+        ! Write resolved file
81
+        call write_resolved_file(trim(filename), conflicts, n_conflicts, success)
82
+
83
+        if (success) then
84
+            select case (auto_choice)
85
+            case (1)
86
+                print '(A, I0, A)', 'Resolved ', n_conflicts, ' conflicts with INCOMING changes'
87
+            case (2)
88
+                print '(A, I0, A)', 'Resolved ', n_conflicts, ' conflicts with LOCAL changes'
89
+            case (3)
90
+                print '(A, I0, A)', 'Resolved ', n_conflicts, ' conflicts with BOTH changes'
91
+            end select
92
+            print '(A)', 'File saved: ' // trim(filename)
93
+            stop 0
94
+        else
95
+            print '(A)', 'Error: Failed to write resolved file'
96
+            stop 1
97
+        end if
98
+    end if
99
+
48100
     ! Initialize terminal
49101
     call term_get_size(term_rows, term_cols, success)
50102
     if (.not. success) then
@@ -68,8 +120,8 @@ program fit
68120
     running = .true.
69121
 
70122
     do while (running)
71
-        ! Draw current conflict with scrolling
72
-        call draw_conflict_scrollable(conflicts(current_conflict), current_conflict, n_conflicts, pane)
123
+        ! Draw current conflict with scrolling (preview shows ALL conflicts resolved)
124
+        call draw_conflict_scrollable(conflicts, n_conflicts, current_conflict, pane)
73125
 
74126
         ! Update status message
75127
         write(status_msg, '(A, I0, A, I0, A)') &
src/conflict_parser.f90modified
@@ -2,7 +2,7 @@ module conflict_parser
22
     implicit none
33
     private
44
 
5
-    public :: conflict_t, parse_conflict_file, conflict_count, get_file_view
5
+    public :: conflict_t, parse_conflict_file, conflict_count, get_file_view, get_full_preview, get_side_view
66
 
77
     ! Type to hold a single conflict
88
     type :: conflict_t
@@ -281,4 +281,189 @@ contains
281281
 
282282
     end subroutine get_file_view
283283
 
284
+    ! Get a full preview with ALL conflicts resolved
285
+    subroutine get_full_preview(conflicts, n_conflicts, current_idx, file_view, n_lines, conflict_start, conflict_end)
286
+        type(conflict_t), intent(in) :: conflicts(:)
287
+        integer, intent(in) :: n_conflicts, current_idx
288
+        character(len=:), allocatable, dimension(:), intent(out) :: file_view
289
+        integer, intent(out) :: n_lines
290
+        integer, intent(out) :: conflict_start, conflict_end
291
+        integer :: i, j, view_idx, line_num, n_res_lines
292
+        character(len=:), allocatable, dimension(:) :: resolution_lines
293
+        logical :: in_conflict
294
+        integer :: conflict_idx
295
+
296
+        if (n_conflicts == 0 .or. .not. allocated(conflicts(1)%full_file)) return
297
+
298
+        ! Allocate output
299
+        allocate(character(len=1024) :: file_view(conflicts(1)%total_file_lines * 2))
300
+        view_idx = 0
301
+        conflict_start = 0
302
+        conflict_end = 0
303
+
304
+        ! Walk through the file line by line
305
+        line_num = 1
306
+        do while (line_num <= conflicts(1)%total_file_lines)
307
+            ! Check if this line starts a conflict
308
+            in_conflict = .false.
309
+            do i = 1, n_conflicts
310
+                if (line_num == conflicts(i)%start_line) then
311
+                    in_conflict = .true.
312
+                    conflict_idx = i
313
+
314
+                    ! Mark if this is the current conflict
315
+                    if (i == current_idx) then
316
+                        conflict_start = view_idx + 1
317
+                    end if
318
+
319
+                    ! Get resolution for this conflict
320
+                    select case (conflicts(i)%choice)
321
+                    case (1)  ! Incoming
322
+                        resolution_lines = conflicts(i)%incoming_lines
323
+                    case (2)  ! Local
324
+                        resolution_lines = conflicts(i)%local_lines
325
+                    case (3)  ! Both
326
+                        if (allocated(conflicts(i)%incoming_lines) .and. allocated(conflicts(i)%local_lines)) then
327
+                            n_res_lines = size(conflicts(i)%incoming_lines) + size(conflicts(i)%local_lines)
328
+                            allocate(character(len=1024) :: resolution_lines(n_res_lines))
329
+                            do j = 1, size(conflicts(i)%incoming_lines)
330
+                                resolution_lines(j) = conflicts(i)%incoming_lines(j)
331
+                            end do
332
+                            do j = 1, size(conflicts(i)%local_lines)
333
+                                resolution_lines(size(conflicts(i)%incoming_lines) + j) = conflicts(i)%local_lines(j)
334
+                            end do
335
+                        end if
336
+                    case default  ! No choice yet - show incoming
337
+                        resolution_lines = conflicts(i)%incoming_lines
338
+                    end select
339
+
340
+                    ! Add resolution lines
341
+                    if (allocated(resolution_lines)) then
342
+                        do j = 1, size(resolution_lines)
343
+                            view_idx = view_idx + 1
344
+                            file_view(view_idx) = resolution_lines(j)
345
+                        end do
346
+                        deallocate(resolution_lines)
347
+                    end if
348
+
349
+                    ! Mark end if this is the current conflict
350
+                    if (i == current_idx) then
351
+                        conflict_end = view_idx
352
+                    end if
353
+
354
+                    ! Skip to end of conflict
355
+                    line_num = conflicts(i)%end_line + 1
356
+                    exit
357
+                end if
358
+            end do
359
+
360
+            ! If not in conflict, copy the line
361
+            if (.not. in_conflict) then
362
+                view_idx = view_idx + 1
363
+                file_view(view_idx) = conflicts(1)%full_file(line_num)
364
+                line_num = line_num + 1
365
+            end if
366
+        end do
367
+
368
+        n_lines = view_idx
369
+
370
+    end subroutine get_full_preview
371
+
372
+    ! Get a view showing a specific side (incoming/local) for current conflict, all others resolved
373
+    subroutine get_side_view(conflicts, n_conflicts, current_idx, side, file_view, n_lines, conflict_start, conflict_end)
374
+        type(conflict_t), intent(in) :: conflicts(:)
375
+        integer, intent(in) :: n_conflicts, current_idx
376
+        integer, intent(in) :: side  ! 1=incoming, 2=local
377
+        character(len=:), allocatable, dimension(:), intent(out) :: file_view
378
+        integer, intent(out) :: n_lines
379
+        integer, intent(out) :: conflict_start, conflict_end
380
+        integer :: i, j, view_idx, line_num, n_res_lines
381
+        character(len=:), allocatable, dimension(:) :: resolution_lines
382
+        logical :: in_conflict
383
+
384
+        if (n_conflicts == 0 .or. .not. allocated(conflicts(1)%full_file)) return
385
+
386
+        ! Allocate output
387
+        allocate(character(len=1024) :: file_view(conflicts(1)%total_file_lines * 2))
388
+        view_idx = 0
389
+        conflict_start = 0
390
+        conflict_end = 0
391
+
392
+        ! Walk through the file line by line
393
+        line_num = 1
394
+        do while (line_num <= conflicts(1)%total_file_lines)
395
+            ! Check if this line starts a conflict
396
+            in_conflict = .false.
397
+            do i = 1, n_conflicts
398
+                if (line_num == conflicts(i)%start_line) then
399
+                    in_conflict = .true.
400
+
401
+                    ! Mark if this is the current conflict
402
+                    if (i == current_idx) then
403
+                        conflict_start = view_idx + 1
404
+                    end if
405
+
406
+                    ! Get resolution for this conflict
407
+                    if (i == current_idx) then
408
+                        ! For current conflict, use specified side
409
+                        if (side == 1) then
410
+                            resolution_lines = conflicts(i)%incoming_lines
411
+                        else
412
+                            resolution_lines = conflicts(i)%local_lines
413
+                        end if
414
+                    else
415
+                        ! For other conflicts, use their choice (or incoming if no choice)
416
+                        select case (conflicts(i)%choice)
417
+                        case (1)
418
+                            resolution_lines = conflicts(i)%incoming_lines
419
+                        case (2)
420
+                            resolution_lines = conflicts(i)%local_lines
421
+                        case (3)  ! Both
422
+                            if (allocated(conflicts(i)%incoming_lines) .and. allocated(conflicts(i)%local_lines)) then
423
+                                n_res_lines = size(conflicts(i)%incoming_lines) + size(conflicts(i)%local_lines)
424
+                                allocate(character(len=1024) :: resolution_lines(n_res_lines))
425
+                                do j = 1, size(conflicts(i)%incoming_lines)
426
+                                    resolution_lines(j) = conflicts(i)%incoming_lines(j)
427
+                                end do
428
+                                do j = 1, size(conflicts(i)%local_lines)
429
+                                    resolution_lines(size(conflicts(i)%incoming_lines) + j) = conflicts(i)%local_lines(j)
430
+                                end do
431
+                            end if
432
+                        case default  ! No choice yet - show incoming
433
+                            resolution_lines = conflicts(i)%incoming_lines
434
+                        end select
435
+                    end if
436
+
437
+                    ! Add resolution lines
438
+                    if (allocated(resolution_lines)) then
439
+                        do j = 1, size(resolution_lines)
440
+                            view_idx = view_idx + 1
441
+                            file_view(view_idx) = resolution_lines(j)
442
+                        end do
443
+                        deallocate(resolution_lines)
444
+                    end if
445
+
446
+                    ! Mark end if this is the current conflict
447
+                    if (i == current_idx) then
448
+                        conflict_end = view_idx
449
+                    end if
450
+
451
+                    ! Skip to end of conflict
452
+                    line_num = conflicts(i)%end_line + 1
453
+                    exit
454
+                end if
455
+            end do
456
+
457
+            ! If not in conflict, copy the line
458
+            if (.not. in_conflict) then
459
+                view_idx = view_idx + 1
460
+                file_view(view_idx) = conflicts(1)%full_file(line_num)
461
+                line_num = line_num + 1
462
+            end if
463
+        end do
464
+
465
+        n_lines = view_idx
466
+
467
+    end subroutine get_side_view
468
+
284469
 end module conflict_parser
src/tui_layout.f90modified
@@ -112,9 +112,9 @@ contains
112112
     end subroutine draw_conflict
113113
 
114114
     ! Draw a conflict with scrollable panes
115
-    subroutine draw_conflict_scrollable(conflict, current, total, pane)
116
-        type(conflict_t), intent(inout) :: conflict
117
-        integer, intent(in) :: current, total
115
+    subroutine draw_conflict_scrollable(conflicts, n_conflicts, current, pane)
116
+        type(conflict_t), intent(inout) :: conflicts(:)
117
+        integer, intent(in) :: n_conflicts, current
118118
         type(pane_t), intent(inout) :: pane
119119
         integer :: mid_col, mid_row, max_lines, preview_max_lines
120120
         character(len=:), allocatable, dimension(:) :: incoming_view, local_view, preview_view
@@ -129,10 +129,12 @@ contains
129129
         ! Redraw layout with active pane highlighted
130130
         call draw_layout(term_rows, term_cols, pane%active_pane)
131131
 
132
-        ! Get full file views
133
-        call get_file_view(conflict, 1, incoming_view, n_incoming, conflict_start, conflict_end)
134
-        call get_file_view(conflict, 2, local_view, n_local, conflict_start, conflict_end)
135
-        call get_file_view(conflict, 3, preview_view, n_preview, conflict_start, conflict_end)
132
+        ! Get side views - show incoming/local for current conflict, all others resolved
133
+        call get_side_view(conflicts, n_conflicts, current, 1, incoming_view, n_incoming, conflict_start, conflict_end)
134
+        call get_side_view(conflicts, n_conflicts, current, 2, local_view, n_local, conflict_start, conflict_end)
135
+
136
+        ! Get full preview with ALL conflicts resolved
137
+        call get_full_preview(conflicts, n_conflicts, current, preview_view, n_preview, conflict_start, conflict_end)
136138
 
137139
         ! Update pane max lines
138140
         pane%max_lines_incoming = n_incoming
@@ -159,7 +161,7 @@ contains
159161
 
160162
         ! Draw conflict counter
161163
         call term_move_cursor(mid_row, term_cols - 15)
162
-        write(*, '(A, I0, A, I0, A)', advance='no') color_cyan // '[ ', current, ' / ', total, ' ]' // color_reset
164
+        write(*, '(A, I0, A, I0, A)', advance='no') color_cyan // '[ ', current, ' / ', n_conflicts, ' ]' // color_reset
163165
 
164166
         call flush(6)
165167
     end subroutine draw_conflict_scrollable