@@ -158,12 +158,28 @@ def _backup_file(cls, file_path, io):
158158 @classmethod
159159 def _update_alacritty (cls , path , io , dry_run = False ):
160160 """Updates Alacritty TOML configuration with shift+enter binding."""
161- if os .environ .get ("TERM" ) != "alacritty" :
162- return False
161+ import tomlkit
162+
163+ # Create directory if it doesn't exist
164+ path .parent .mkdir (parents = True , exist_ok = True )
163165
164166 if not path .exists ():
165- io .tool_output (f"Skipping Alacritty: File not found at { path } " )
166- return False
167+ if dry_run :
168+ io .tool_output (f"DRY-RUN: Would create Alacritty config at { path } " )
169+ io .tool_output (
170+ 'DRY-RUN: Would add binding: {"key": "Return", "mods": "Shift", "chars": "\\ n"}'
171+ )
172+ return True
173+ else :
174+ io .tool_output (f"Creating Alacritty config at { path } " )
175+ # Create minimal Alacritty config with shift+enter binding
176+ data = {
177+ "keyboard" : {"bindings" : [{"key" : "Return" , "mods" : "Shift" , "chars" : "\n " }]}
178+ }
179+ with open (path , "w" , encoding = "utf-8" ) as f :
180+ tomlkit .dump (data , f )
181+ io .tool_output ("Created Alacritty config with shift+enter binding." )
182+ return True
167183
168184 # Define the binding to add
169185 new_binding = {"key" : "Return" , "mods" : "Shift" , "chars" : "\n " }
@@ -173,7 +189,7 @@ def _update_alacritty(cls, path, io, dry_run=False):
173189 io .tool_output (f"DRY-RUN: Would add binding: { new_binding } " )
174190 try :
175191 with open (path , "r" , encoding = "utf-8" ) as f :
176- data = toml .load (f )
192+ data = tomlkit .load (f )
177193
178194 # Check if binding already exists
179195 keyboard_section = data .get ("keyboard" , {})
@@ -195,7 +211,7 @@ def _update_alacritty(cls, path, io, dry_run=False):
195211 else :
196212 io .tool_output ("DRY-RUN: Would update Alacritty config." )
197213 return True
198- except toml .TomlDecodeError :
214+ except toml .TOMLDecodeError :
199215 io .tool_output ("DRY-RUN: Error: Could not parse Alacritty TOML file." )
200216 return False
201217 except Exception as e :
@@ -206,7 +222,7 @@ def _update_alacritty(cls, path, io, dry_run=False):
206222
207223 try :
208224 with open (path , "r" , encoding = "utf-8" ) as f :
209- data = toml .load (f )
225+ data = tomlkit .load (f )
210226
211227 # Ensure keyboard section exists
212228 if "keyboard" not in data :
@@ -237,12 +253,12 @@ def _update_alacritty(cls, path, io, dry_run=False):
237253
238254 # Write back to file
239255 with open (path , "w" , encoding = "utf-8" ) as f :
240- toml .dump (data , f )
256+ tomlkit .dump (data , f )
241257
242258 io .tool_output ("Updated Alacritty config." )
243259 return True
244260
245- except toml .TomlDecodeError :
261+ except toml .TOMLDecodeError :
246262 io .tool_output ("Error: Could not parse Alacritty TOML file. Is it valid TOML?" )
247263 return False
248264 except Exception as e :
@@ -252,9 +268,21 @@ def _update_alacritty(cls, path, io, dry_run=False):
252268 @classmethod
253269 def _update_kitty (cls , path , io , dry_run = False ):
254270 """Appends the Kitty mapping if not present."""
271+ # Create directory if it doesn't exist
272+ path .parent .mkdir (parents = True , exist_ok = True )
273+
255274 if not path .exists ():
256- io .tool_output (f"Skipping Kitty: File not found at { path } " )
257- return False
275+ if dry_run :
276+ io .tool_output (f"DRY-RUN: Would create Kitty config at { path } " )
277+ io .tool_output (f"DRY-RUN: Would add binding:\n { cls .KITTY_BINDING .strip ()} " )
278+ return True
279+ else :
280+ io .tool_output (f"Creating Kitty config at { path } " )
281+ # Create Kitty config with shift+enter binding
282+ with open (path , "w" , encoding = "utf-8" ) as f :
283+ f .write (cls .KITTY_BINDING )
284+ io .tool_output ("Created Kitty config with shift+enter binding." )
285+ return True
258286
259287 if dry_run :
260288 io .tool_output (f"DRY-RUN: Would check Kitty config at { path } " )
@@ -290,9 +318,6 @@ def _update_kitty(cls, path, io, dry_run=False):
290318 @classmethod
291319 def _update_konsole (cls , path , io , dry_run = False ):
292320 """Updates Konsole keytab configuration with shift+enter binding."""
293- if not os .environ .get ("KONSOLE_VERSION" ):
294- return False
295-
296321 default_keytab_path = Path (__file__ ).parent / "terminal_data" / "linux.keytab"
297322
298323 if not path .exists ():
@@ -354,10 +379,30 @@ def _update_konsole(cls, path, io, dry_run=False):
354379 @classmethod
355380 def _update_windows_terminal (cls , path , io , dry_run = False ):
356381 """Parses JSON, adds action to 'actions' list and keybinding to 'keybindings' list."""
357- if not path or not path . exists () :
358- io .tool_output ("Skipping Windows Terminal: File not found ." )
382+ if not path :
383+ io .tool_output ("Skipping Windows Terminal: No path available ." )
359384 return False
360385
386+ # Create directory if it doesn't exist
387+ path .parent .mkdir (parents = True , exist_ok = True )
388+
389+ if not path .exists ():
390+ if dry_run :
391+ io .tool_output (f"DRY-RUN: Would create Windows Terminal config at { path } " )
392+ io .tool_output (f"DRY-RUN: Would add action: { json .dumps (cls .WT_ACTION , indent = 2 )} " )
393+ io .tool_output (
394+ f"DRY-RUN: Would add keybinding: { json .dumps (cls .WT_KEYBINDING , indent = 2 )} "
395+ )
396+ return True
397+ else :
398+ io .tool_output (f"Creating Windows Terminal config at { path } " )
399+ # Create minimal Windows Terminal config with shift+enter binding
400+ data = {"actions" : [cls .WT_ACTION ], "keybindings" : [cls .WT_KEYBINDING ]}
401+ with open (path , "w" , encoding = "utf-8" ) as f :
402+ json .dump (data , f , indent = 4 )
403+ io .tool_output ("Created Windows Terminal config with shift+enter binding." )
404+ return True
405+
361406 if dry_run :
362407 io .tool_output (f"DRY-RUN: Would check Windows Terminal config at { path } " )
363408 io .tool_output (f"DRY-RUN: Would add action: { json .dumps (cls .WT_ACTION , indent = 2 )} " )
@@ -744,42 +789,118 @@ async def execute(cls, io, coder, args, **kwargs):
744789 paths = cls ._get_config_paths ()
745790
746791 # Check for dry-run mode
747- dry_run = args == "dry_run"
792+ dry_run = args == "dry_run" or ( hasattr ( args , "dry_run" ) and args . dry_run )
748793 if dry_run :
749794 io .tool_output ("DRY-RUN MODE: Showing what would be changed without modifying files\n " )
750795
796+ # Explicit yes required should always be true for terminal setup
797+ explicit_yes_required = True
798+
751799 updated = False
752800
753801 if "alacritty" in paths :
754- if cls ._update_alacritty (paths ["alacritty" ], io , dry_run = dry_run ):
755- updated = True
802+ path = paths ["alacritty" ]
803+ if path .exists ():
804+ question = f"Update Alacritty config at { path } to add shift+enter binding?"
805+ else :
806+ question = f"Create new Alacritty config at { path } with shift+enter binding?"
807+
808+ if dry_run or await coder .io .confirm_ask (
809+ question , default = "y" , explicit_yes_required = explicit_yes_required
810+ ):
811+ if cls ._update_alacritty (path , io , dry_run = dry_run ):
812+ updated = True
756813
757814 if "kitty" in paths :
758- if cls ._update_kitty (paths ["kitty" ], io , dry_run = dry_run ):
759- updated = True
815+ path = paths ["kitty" ]
816+ if path .exists ():
817+ question = f"Update Kitty config at { path } to add shift+enter binding?"
818+ else :
819+ question = f"Create new Kitty config at { path } with shift+enter binding?"
820+
821+ if dry_run or await coder .io .confirm_ask (
822+ question , default = "y" , explicit_yes_required = explicit_yes_required
823+ ):
824+ if cls ._update_kitty (path , io , dry_run = dry_run ):
825+ updated = True
760826
761827 if "konsole" in paths :
762- if cls ._update_konsole (paths ["konsole" ], io , dry_run = dry_run ):
763- updated = True
828+ path = paths ["konsole" ]
829+ if path .exists ():
830+ question = f"Update Konsole keytab at { path } to add shift+enter binding?"
831+ else :
832+ question = f"Create new Konsole keytab at { path } with shift+enter binding?"
833+
834+ if dry_run or await coder .io .confirm_ask (
835+ question , default = "y" , explicit_yes_required = explicit_yes_required
836+ ):
837+ if cls ._update_konsole (path , io , dry_run = dry_run ):
838+ updated = True
764839
765840 if "windows_terminal" in paths :
766- if cls ._update_windows_terminal (paths ["windows_terminal" ], io , dry_run = dry_run ):
767- updated = True
841+ path = paths ["windows_terminal" ]
842+ if path .exists ():
843+ question = f"Update Windows Terminal config at { path } to add shift+enter binding?"
844+ else :
845+ question = f"Create new Windows Terminal config at { path } with shift+enter binding?"
846+
847+ if dry_run or await coder .io .confirm_ask (
848+ question , default = "y" , explicit_yes_required = explicit_yes_required
849+ ):
850+ if cls ._update_windows_terminal (path , io , dry_run = dry_run ):
851+ updated = True
768852
769853 if "vscode" in paths :
770- if cls ._update_vscode (paths ["vscode" ], io , dry_run = dry_run ):
771- updated = True
772- # Also update VS Code settings.json for proper shift+enter support
773- if cls ._update_vscode_settings (paths ["vscode" ], io , dry_run = dry_run ):
774- updated = True
854+ path = paths ["vscode" ]
855+ if path .exists ():
856+ question = f"Update VS Code keybindings at { path } to add shift+enter binding?"
857+ else :
858+ question = f"Create new VS Code keybindings at { path } with shift+enter binding?"
859+
860+ if dry_run or await coder .io .confirm_ask (
861+ question , default = "y" , explicit_yes_required = explicit_yes_required
862+ ):
863+ if cls ._update_vscode (path , io , dry_run = dry_run ):
864+ updated = True
865+ # Also update VS Code settings.json for proper shift+enter support
866+ settings_question = (
867+ f"Update VS Code settings at { path .parent } /settings.json for proper shift+enter"
868+ " support?"
869+ )
870+ if dry_run or await coder .io .confirm_ask (
871+ settings_question , default = "y" , explicit_yes_required = explicit_yes_required
872+ ):
873+ if cls ._update_vscode_settings (path , io , dry_run = dry_run ):
874+ updated = True
775875
776876 if "vscode_windows" in paths :
877+ path = paths ["vscode_windows" ]
777878 io .tool_output ("Found Windows host VS Code configuration (running in WSL)" )
778- if cls ._update_vscode (paths ["vscode_windows" ], io , dry_run = dry_run ):
779- updated = True
780- # Also update Windows host VS Code settings.json
781- if cls ._update_vscode_settings (paths ["vscode_windows" ], io , dry_run = dry_run ):
782- updated = True
879+ if path .exists ():
880+ question = (
881+ f"Update Windows host VS Code keybindings at { path } to add shift+enter binding?"
882+ )
883+ else :
884+ question = (
885+ f"Create new Windows host VS Code keybindings at { path } with shift+enter"
886+ " binding?"
887+ )
888+
889+ if dry_run or await coder .io .confirm_ask (
890+ question , default = "y" , explicit_yes_required = explicit_yes_required
891+ ):
892+ if cls ._update_vscode (path , io , dry_run = dry_run ):
893+ updated = True
894+ # Also update Windows host VS Code settings.json
895+ settings_question = (
896+ f"Update Windows host VS Code settings at { path .parent } /settings.json for"
897+ " proper shift+enter support?"
898+ )
899+ if dry_run or await coder .io .confirm_ask (
900+ settings_question , default = "y" , explicit_yes_required = explicit_yes_required
901+ ):
902+ if cls ._update_vscode_settings (path , io , dry_run = dry_run ):
903+ updated = True
783904
784905 if dry_run :
785906 if updated :
0 commit comments