@@ -408,6 +408,26 @@ function M._apply_accepted_changes(diff_data, final_content)
408408
409409 require (" claudecode.logger" ).debug (" diff" , " Writing accepted changes to file:" , old_file_path )
410410
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+
411431 -- Write the content to the actual file
412432 local lines = vim .split (final_content , " \n " )
413433 local success , err = pcall (vim .fn .writefile , lines , old_file_path )
581601-- @param old_file_path string Path to the original file
582602-- @param new_buffer number New file buffer ID
583603-- @param tab_name string The diff identifier
604+ -- @param is_new_file boolean Whether this is a new file (doesn't exist yet)
584605-- @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 )
586607 require (" claudecode.logger" ).debug (" diff" , " Creating diff view from window" , target_window )
587608
588609 -- 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
608629 vim .api .nvim_set_current_win (target_window )
609630 end
610631
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
617652
618- -- Enable diff mode on the original file
653+ -- Enable diff mode on the original/empty file
619654 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+ )
621662
622663 -- Create vertical split for new buffer (proposed changes)
623664 vim .cmd (" vsplit" )
@@ -647,6 +688,14 @@ function M._create_diff_view_from_window(target_window, old_file_path, new_buffe
647688 -- Accept all changes
648689 local new_content = vim .api .nvim_buf_get_lines (new_buffer , 0 , - 1 , false )
649690
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+
650699 -- Write to file
651700 vim .fn .writefile (new_content , old_file_path )
652701
@@ -747,41 +796,49 @@ function M._setup_blocking_diff(params, resolution_callback)
747796 params .old_file_path
748797 )
749798
750- -- Step 1: Check if the file exists
799+ -- Step 1: Check if the file exists (allow new files)
751800 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
759802
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)
761814 local existing_buffer = nil
762815 local target_window = nil
763816
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
772827 end
773828 end
774- end
775829
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
783838 end
784839 end
840+ else
841+ require (" claudecode.logger" ).debug (" diff" , " Skipping buffer search for new file:" , params .old_file_path )
785842 end
786843
787844 -- If no existing buffer/window, find a suitable main editor window
@@ -811,7 +868,7 @@ function M._setup_blocking_diff(params, resolution_callback)
811868 })
812869 end
813870
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) " )
815872 vim .api .nvim_buf_set_name (new_buffer , new_unique_name )
816873 vim .api .nvim_buf_set_lines (new_buffer , 0 , - 1 , false , vim .split (params .new_file_contents , " \n " ))
817874
@@ -820,8 +877,15 @@ function M._setup_blocking_diff(params, resolution_callback)
820877 vim .api .nvim_buf_set_option (new_buffer , " modifiable" , true )
821878
822879 -- 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 )
825889
826890 -- Step 5: Register autocmds for user interaction monitoring
827891 require (" claudecode.logger" ).debug (" diff" , " Registering autocmds" )
@@ -842,6 +906,7 @@ function M._setup_blocking_diff(params, resolution_callback)
842906 status = " pending" ,
843907 resolution_callback = resolution_callback ,
844908 result_content = nil ,
909+ is_new_file = is_new_file ,
845910 })
846911 require (" claudecode.logger" ).debug (" diff" , " Setup completed successfully for" , tab_name )
847912end
0 commit comments