diff --git a/macos/Ghostty.xcodeproj/project.pbxproj b/macos/Ghostty.xcodeproj/project.pbxproj index 3a9c27f72..2b29f105b 100644 --- a/macos/Ghostty.xcodeproj/project.pbxproj +++ b/macos/Ghostty.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ A535B9DA299C569B0017E2E4 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A535B9D9299C569B0017E2E4 /* ErrorView.swift */; }; + A545D1A22A5772CE006E0AE4 /* shell-integration in Resources */ = {isa = PBXBuildFile; fileRef = A545D1A12A5772CE006E0AE4 /* shell-integration */; }; A55685E029A03A9F004303CE /* AppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55685DF29A03A9F004303CE /* AppError.swift */; }; A55B7BB629B6F47F0055DE60 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55B7BB529B6F47F0055DE60 /* AppState.swift */; }; A55B7BB829B6F53A0055DE60 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55B7BB729B6F53A0055DE60 /* Package.swift */; }; @@ -27,6 +28,7 @@ /* Begin PBXFileReference section */ A535B9D9299C569B0017E2E4 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = ""; }; + A545D1A12A5772CE006E0AE4 /* shell-integration */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "shell-integration"; path = "../zig-out/share/shell-integration"; sourceTree = ""; }; A55685DF29A03A9F004303CE /* AppError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppError.swift; sourceTree = ""; }; A55B7BB529B6F47F0055DE60 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = ""; }; A55B7BB729B6F53A0055DE60 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; @@ -90,6 +92,7 @@ A5A1F8862A489D7400D1E8BC /* Resources */ = { isa = PBXGroup; children = ( + A545D1A12A5772CE006E0AE4 /* shell-integration */, A5A1F8842A489D6800D1E8BC /* terminfo */, ); name = Resources; @@ -198,6 +201,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + A545D1A22A5772CE006E0AE4 /* shell-integration in Resources */, A5A1F8852A489D6800D1E8BC /* terminfo in Resources */, A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */, ); diff --git a/src/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish b/src/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish index 2d2d9da29..2200e03d6 100755 --- a/src/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish +++ b/src/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish @@ -1,3 +1,91 @@ #!/bin/fish +# +# This shell script aims to be written in a way where it can't really fail +# or all failure scenarios are handled, so that we never leave the shell in +# a weird state. If you find a way to break this, please report a bug! -echo GHOSTTY INTEGRATION LOADING +function ghostty_restore_xdg_data_dir -d "restore the original XDG_DATA_DIR value" + # If we don't have our own data dir then we don't need to do anything. + if not set -q GHOSTTY_FISH_XDG_DIR + return + end + + # If the data dir isn't set at all then we don't need to do anything. + if not set -q XDG_DATA_DIRS + return + end + + # We need to do this so that XDG_DATA_DIRS turns into an array. + set --function --path xdg_data_dirs "$XDG_DATA_DIRS" + + # If our data dir is in the list then remove it. + if set --function index (contains --index "$GHOSTTY_FISH_XDG_DIR" $xdg_data_dirs) + set --erase --function xdg_data_dirs[$index] + end + + # Re-export our data dir + if set -q xdg_data_dirs[1] + set --global --export --unpath XDG_DATA_DIRS "$xdg_data_dirs" + else + set --erase --global XDG_DATA_DIRS + end + + set --erase GHOSTTY_FISH_XDG_DIR +end + +function ghostty_exit -d "exit the shell integration setup" + functions -e ghostty_restore_xdg_data_dir + functions -e ghostty_exit + exit 0 +end + +# We always try to restore the XDG data dir +ghostty_restore_xdg_data_dir + +# If we aren't interactive or we've already run, don't run. +status --is-interactive || ghostty_exit + +# We do the full setup on the first prompt render. We do this so that other +# shell integrations that setup the prompt and modify things are able to run +# first. We want to run _last_. +function __ghostty_setup --on-event fish_prompt -d "Setup ghostty integration" + functions -e __ghostty_setup + + # Change the cursor to a beam on prompt. + function __ghostty_set_cursor_beam --on-event fish_prompt -d "Set cursor shape" + echo -en "\e[5 q" + end + function __ghostty_reset_cursor --on-event fish_preexec -d "Reset cursor shape" + echo -en "\e[0 q" + end + + # Setup prompt marking + function __ghostty_mark_prompt_start --on-event fish_prompt --on-event fish_cancel --on-event fish_posterror + # If we never got the output end event, then we need to send it now. + if test "$__ghostty_prompt_state" != prompt-start + echo -en "\e]133;D\a" + end + + set --global __ghostty_prompt_state prompt-start + echo -en "\e]133;A\a" + end + + function __ghostty_mark_output_start --on-event fish_preexec + set --global __ghostty_prompt_state pre-exec + echo -en "\e]133;C\a" + end + + function __ghostty_mark_output_end --on-event fish_postexec + set --global __ghostty_prompt_state post-exec + echo -en "\e]133;D;$status\a" + end + + # Enable fish to handle reflow because Ghostty clears the prompt on resize. + set --global fish_handle_reflow 1 + + # Initial calls for first prompt + __ghostty_set_cursor_beam + __ghostty_mark_prompt_start +end + +ghostty_exit diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index aa3e4df0a..a70967284 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -530,6 +530,9 @@ const Subprocess = struct { // Get our bundled resources directory, if it exists. We use this // for terminfo, shell-integration, etc. const resources_dir = try resourcesDir(alloc); + if (resources_dir) |dir| { + try env.put("GHOSTTY_RESOURCES_DIR", dir); + } // Set our TERM var. This is a bit complicated because we want to use // the ghostty TERM value but we want to only do that if we have diff --git a/src/termio/shell_integration.zig b/src/termio/shell_integration.zig index c941965b5..2aaf23870 100644 --- a/src/termio/shell_integration.zig +++ b/src/termio/shell_integration.zig @@ -46,7 +46,7 @@ fn setupFish( // Set an env var so we can remove this from XDG_DATA_DIRS later. // This happens in the shell integration config itself. We do this // so that our modifications don't interfere with other commands. - try env.put("GHOSTTY_FISH_DIR", integ_dir); + try env.put("GHOSTTY_FISH_XDG_DIR", integ_dir); if (env.get("XDG_DATA_DIRS")) |old| { // We have an old value, We need to prepend our value to it. @@ -62,6 +62,7 @@ fn setupFish( "{s}{c}{s}", .{ integ_dir, std.fs.path.delimiter, old }, ); + try env.put("XDG_DATA_DIRS", prepended); } else { // No XDG_DATA_DIRS set, we just set it our desired value.