@@ -408,6 +408,26 @@ function M._apply_accepted_changes(diff_data, final_content)
408
408
409
409
require (" claudecode.logger" ).debug (" diff" , " Writing accepted changes to file:" , old_file_path )
410
410
411
+ -- Ensure parent directories exist for new files
412
+ if diff_data .is_new_file then
413
+ local parent_dir = vim .fn .fnamemodify (old_file_path , " :h" )
414
+ if parent_dir and parent_dir ~= " " and parent_dir ~= " ." then
415
+ require (" claudecode.logger" ).debug (" diff" , " Creating parent directories for new file:" , parent_dir )
416
+ local mkdir_success , mkdir_err = pcall (vim .fn .mkdir , parent_dir , " p" )
417
+ if not mkdir_success then
418
+ require (" claudecode.logger" ).error (
419
+ " diff" ,
420
+ " Failed to create parent directories:" ,
421
+ parent_dir ,
422
+ " error:" ,
423
+ mkdir_err
424
+ )
425
+ return
426
+ end
427
+ require (" claudecode.logger" ).debug (" diff" , " Successfully created parent directories:" , parent_dir )
428
+ end
429
+ end
430
+
411
431
-- Write the content to the actual file
412
432
local lines = vim .split (final_content , " \n " )
413
433
local success , err = pcall (vim .fn .writefile , lines , old_file_path )
581
601
-- @param old_file_path string Path to the original file
582
602
-- @param new_buffer number New file buffer ID
583
603
-- @param tab_name string The diff identifier
604
+ -- @param is_new_file boolean Whether this is a new file (doesn't exist yet)
584
605
-- @return table Info about the created diff layout
585
- function M ._create_diff_view_from_window (target_window , old_file_path , new_buffer , tab_name )
606
+ function M ._create_diff_view_from_window (target_window , old_file_path , new_buffer , tab_name , is_new_file )
586
607
require (" claudecode.logger" ).debug (" diff" , " Creating diff view from window" , target_window )
587
608
588
609
-- If no target window provided, create a new window in suitable location
@@ -608,16 +629,36 @@ function M._create_diff_view_from_window(target_window, old_file_path, new_buffe
608
629
vim .api .nvim_set_current_win (target_window )
609
630
end
610
631
611
- -- Make sure the window shows the file we want to diff
612
- -- This handles the case where the buffer exists but isn't in the current window
613
- vim .cmd (" edit " .. vim .fn .fnameescape (old_file_path ))
614
-
615
- -- Store the original buffer for later
616
- local original_buffer = vim .api .nvim_win_get_buf (target_window )
632
+ -- Handle the left side of the diff (original file or empty for new files)
633
+ local original_buffer
634
+ if is_new_file then
635
+ -- Create an empty buffer for new file comparison
636
+ require (" claudecode.logger" ).debug (" diff" , " Creating empty buffer for new file diff" )
637
+ local empty_buffer = vim .api .nvim_create_buf (false , true ) -- unlisted, scratch
638
+ vim .api .nvim_buf_set_name (empty_buffer , old_file_path .. " (NEW FILE)" )
639
+ vim .api .nvim_buf_set_lines (empty_buffer , 0 , - 1 , false , {}) -- Empty content
640
+ vim .api .nvim_buf_set_option (empty_buffer , " buftype" , " nofile" )
641
+ vim .api .nvim_buf_set_option (empty_buffer , " modifiable" , false )
642
+ vim .api .nvim_buf_set_option (empty_buffer , " readonly" , true )
643
+
644
+ -- Set the empty buffer in the target window
645
+ vim .api .nvim_win_set_buf (target_window , empty_buffer )
646
+ original_buffer = empty_buffer
647
+ else
648
+ -- Make sure the window shows the existing file we want to diff
649
+ vim .cmd (" edit " .. vim .fn .fnameescape (old_file_path ))
650
+ original_buffer = vim .api .nvim_win_get_buf (target_window )
651
+ end
617
652
618
- -- Enable diff mode on the original file
653
+ -- Enable diff mode on the original/empty file
619
654
vim .cmd (" diffthis" )
620
- require (" claudecode.logger" ).debug (" diff" , " Enabled diff mode on original file in window" , target_window )
655
+ require (" claudecode.logger" ).debug (
656
+ " diff" ,
657
+ " Enabled diff mode on" ,
658
+ is_new_file and " empty buffer" or " original file" ,
659
+ " in window" ,
660
+ target_window
661
+ )
621
662
622
663
-- Create vertical split for new buffer (proposed changes)
623
664
vim .cmd (" vsplit" )
@@ -647,6 +688,14 @@ function M._create_diff_view_from_window(target_window, old_file_path, new_buffe
647
688
-- Accept all changes
648
689
local new_content = vim .api .nvim_buf_get_lines (new_buffer , 0 , - 1 , false )
649
690
691
+ -- Ensure parent directories exist for new files
692
+ if is_new_file then
693
+ local parent_dir = vim .fn .fnamemodify (old_file_path , " :h" )
694
+ if parent_dir and parent_dir ~= " " and parent_dir ~= " ." then
695
+ vim .fn .mkdir (parent_dir , " p" )
696
+ end
697
+ end
698
+
650
699
-- Write to file
651
700
vim .fn .writefile (new_content , old_file_path )
652
701
@@ -747,41 +796,49 @@ function M._setup_blocking_diff(params, resolution_callback)
747
796
params .old_file_path
748
797
)
749
798
750
- -- Step 1: Check if the file exists
799
+ -- Step 1: Check if the file exists (allow new files)
751
800
local old_file_exists = vim .fn .filereadable (params .old_file_path ) == 1
752
- if not old_file_exists then
753
- error ({
754
- code = - 32000 ,
755
- message = " File access error" ,
756
- data = " Cannot open file: " .. params .old_file_path .. " (file does not exist)" ,
757
- })
758
- end
801
+ local is_new_file = not old_file_exists
759
802
760
- -- Step 2: Find if the file is already open in a buffer
803
+ require (" claudecode.logger" ).debug (
804
+ " diff" ,
805
+ " File existence check - old_file_exists:" ,
806
+ old_file_exists ,
807
+ " is_new_file:" ,
808
+ is_new_file ,
809
+ " path:" ,
810
+ params .old_file_path
811
+ )
812
+
813
+ -- Step 2: Find if the file is already open in a buffer (only for existing files)
761
814
local existing_buffer = nil
762
815
local target_window = nil
763
816
764
- -- Look for existing buffer with this file
765
- for _ , buf in ipairs (vim .api .nvim_list_bufs ()) do
766
- if vim .api .nvim_buf_is_valid (buf ) and vim .api .nvim_buf_is_loaded (buf ) then
767
- local buf_name = vim .api .nvim_buf_get_name (buf )
768
- if buf_name == params .old_file_path then
769
- existing_buffer = buf
770
- require (" claudecode.logger" ).debug (" diff" , " Found existing buffer" , buf , " for file" , params .old_file_path )
771
- break
817
+ if old_file_exists then
818
+ -- Look for existing buffer with this file
819
+ for _ , buf in ipairs (vim .api .nvim_list_bufs ()) do
820
+ if vim .api .nvim_buf_is_valid (buf ) and vim .api .nvim_buf_is_loaded (buf ) then
821
+ local buf_name = vim .api .nvim_buf_get_name (buf )
822
+ if buf_name == params .old_file_path then
823
+ existing_buffer = buf
824
+ require (" claudecode.logger" ).debug (" diff" , " Found existing buffer" , buf , " for file" , params .old_file_path )
825
+ break
826
+ end
772
827
end
773
828
end
774
- end
775
829
776
- -- Find window containing this buffer (if any)
777
- if existing_buffer then
778
- for _ , win in ipairs (vim .api .nvim_list_wins ()) do
779
- if vim .api .nvim_win_get_buf (win ) == existing_buffer then
780
- target_window = win
781
- require (" claudecode.logger" ).debug (" diff" , " Found window" , win , " containing buffer" , existing_buffer )
782
- break
830
+ -- Find window containing this buffer (if any)
831
+ if existing_buffer then
832
+ for _ , win in ipairs (vim .api .nvim_list_wins ()) do
833
+ if vim .api .nvim_win_get_buf (win ) == existing_buffer then
834
+ target_window = win
835
+ require (" claudecode.logger" ).debug (" diff" , " Found window" , win , " containing buffer" , existing_buffer )
836
+ break
837
+ end
783
838
end
784
839
end
840
+ else
841
+ require (" claudecode.logger" ).debug (" diff" , " Skipping buffer search for new file:" , params .old_file_path )
785
842
end
786
843
787
844
-- If no existing buffer/window, find a suitable main editor window
@@ -811,7 +868,7 @@ function M._setup_blocking_diff(params, resolution_callback)
811
868
})
812
869
end
813
870
814
- local new_unique_name = tab_name .. " (proposed)"
871
+ local new_unique_name = is_new_file and ( tab_name .. " (NEW FILE - proposed)" ) or ( tab_name .. " (proposed) " )
815
872
vim .api .nvim_buf_set_name (new_buffer , new_unique_name )
816
873
vim .api .nvim_buf_set_lines (new_buffer , 0 , - 1 , false , vim .split (params .new_file_contents , " \n " ))
817
874
@@ -820,8 +877,15 @@ function M._setup_blocking_diff(params, resolution_callback)
820
877
vim .api .nvim_buf_set_option (new_buffer , " modifiable" , true )
821
878
822
879
-- Step 4: Set up diff view using the target window
823
- require (" claudecode.logger" ).debug (" diff" , " Creating diff view from window" , target_window )
824
- local diff_info = M ._create_diff_view_from_window (target_window , params .old_file_path , new_buffer , tab_name )
880
+ require (" claudecode.logger" ).debug (
881
+ " diff" ,
882
+ " Creating diff view from window" ,
883
+ target_window ,
884
+ " is_new_file:" ,
885
+ is_new_file
886
+ )
887
+ local diff_info =
888
+ M ._create_diff_view_from_window (target_window , params .old_file_path , new_buffer , tab_name , is_new_file )
825
889
826
890
-- Step 5: Register autocmds for user interaction monitoring
827
891
require (" claudecode.logger" ).debug (" diff" , " Registering autocmds" )
@@ -842,6 +906,7 @@ function M._setup_blocking_diff(params, resolution_callback)
842
906
status = " pending" ,
843
907
resolution_callback = resolution_callback ,
844
908
result_content = nil ,
909
+ is_new_file = is_new_file ,
845
910
})
846
911
require (" claudecode.logger" ).debug (" diff" , " Setup completed successfully for" , tab_name )
847
912
end
0 commit comments