diff --git a/assets/macos/WezTerm.app/Contents/Info.plist b/assets/macos/WezTerm.app/Contents/Info.plist
index 36ff95b4cfb..11617cf2951 100644
--- a/assets/macos/WezTerm.app/Contents/Info.plist
+++ b/assets/macos/WezTerm.app/Contents/Info.plist
@@ -99,6 +99,16 @@
public.unix-executable
+
+ CFBundleTypeRole
+ Editor
+ LSItemContentTypes
+
+ public.directory
+ com.apple.bundle
+ com.apple.resolvable
+
+
diff --git a/wezterm-gui/src/frontend.rs b/wezterm-gui/src/frontend.rs
index 66c61e72acb..14e8df5986b 100644
--- a/wezterm-gui/src/frontend.rs
+++ b/wezterm-gui/src/frontend.rs
@@ -271,6 +271,47 @@ impl GuiFrontEnd {
})
.detach();
}
+ ApplicationEvent::OpenDirectory(path) => {
+ promise::spawn::spawn(async move {
+ use config::keyassignment::SpawnTabDomain;
+ use wezterm_term::TerminalSize;
+
+ // We send the script to execute to the shell on stdin, rather than ask the
+ // shell to execute it directly, so that we start the shell and read in the
+ // user's rc files before running the script. Without this, wezterm on macOS
+ // is launched with a default and very anemic path, and that is frustrating for
+ // users.
+
+ let mux = Mux::get();
+ let window_id = None;
+ let pane_id = None;
+ let cmd = None;
+ let cwd = Some(path.clone());
+ let workspace = mux.active_workspace();
+
+ match mux
+ .spawn_tab_or_window(
+ window_id,
+ SpawnTabDomain::DomainName("local".to_string()),
+ cmd,
+ cwd,
+ TerminalSize::default(),
+ pane_id,
+ workspace,
+ None, // optional position
+ )
+ .await
+ {
+ Ok((_tab, pane, _window_id)) => {
+ log::trace!("Spawned {path} as pane_id {}", pane.pane_id());
+ }
+ Err(err) => {
+ log::error!("Failed to spawn {path}: {err:#?}");
+ }
+ };
+ })
+ .detach();
+ }
ApplicationEvent::PerformKeyAssignment(action) => {
// We should only get here when there are no windows open
// and the user picks an action from the menubar.
diff --git a/window/src/connection.rs b/window/src/connection.rs
index 9564d4999b8..c0fcf498ed2 100644
--- a/window/src/connection.rs
+++ b/window/src/connection.rs
@@ -23,6 +23,7 @@ pub fn shutdown() {
pub enum ApplicationEvent {
/// The system wants to open a command in the terminal
OpenCommandScript(String),
+ OpenDirectory(String),
PerformKeyAssignment(KeyAssignment),
}
diff --git a/window/src/os/macos/app.rs b/window/src/os/macos/app.rs
index 800b6230b58..42b65a5a403 100644
--- a/window/src/os/macos/app.rs
+++ b/window/src/os/macos/app.rs
@@ -5,6 +5,7 @@ use crate::menu::{Menu, MenuItem};
use crate::{ApplicationEvent, Connection};
use cocoa::appkit::NSApplicationTerminateReply;
use cocoa::base::id;
+use cocoa::foundation::NSArray;
use cocoa::foundation::NSInteger;
use config::keyassignment::KeyAssignment;
use config::WindowCloseConfirmation;
@@ -68,27 +69,27 @@ extern "C" fn application_will_finish_launching(
log::debug!("application_will_finish_launching");
}
-extern "C" fn application_did_finish_launching(this: &mut Object, _sel: Sel, _notif: *mut Object) {
+extern "C" fn application_did_finish_launching(_self: &mut Object, _sel: Sel, _notif: *mut Object) {
log::debug!("application_did_finish_launching");
- unsafe {
- (*this).set_ivar("launched", YES);
- }
}
extern "C" fn application_open_untitled_file(
- this: &mut Object,
+ _self: &mut Object,
_sel: Sel,
- _app: *mut Object,
+ app: *mut Object,
) -> BOOL {
- let launched: BOOL = unsafe { *this.get_ivar("launched") };
- log::debug!("application_open_untitled_file launched={launched}");
- if let Some(conn) = Connection::get() {
- if launched == YES {
- conn.dispatch_app_event(ApplicationEvent::PerformKeyAssignment(
- KeyAssignment::SpawnWindow,
- ));
+ log::debug!("application_open_untitled_file");
+ unsafe {
+ let windows: id = msg_send![app, windows];
+ let windows_count = windows.count();
+ if windows_count == 0 {
+ if let Some(conn) = Connection::get() {
+ conn.dispatch_app_event(ApplicationEvent::PerformKeyAssignment(
+ KeyAssignment::SpawnWindow,
+ ));
+ return YES;
+ }
}
- return YES;
}
NO
}
@@ -113,19 +114,23 @@ extern "C" fn wezterm_perform_key_assignment(
}
extern "C" fn application_open_file(
- this: &mut Object,
+ _self: &mut Object,
_sel: Sel,
_app: *mut Object,
file_name: *mut Object,
-) {
- let launched: BOOL = unsafe { *this.get_ivar("launched") };
- if launched == YES {
- let file_name = unsafe { nsstring_to_str(file_name) }.to_string();
- if let Some(conn) = Connection::get() {
- log::debug!("application_open_file {file_name}");
+) -> BOOL {
+ let file_name = unsafe { nsstring_to_str(file_name) }.to_string();
+ let path = std::path::Path::new(&file_name);
+ if let Some(conn) = Connection::get() {
+ log::debug!("application_open_file {file_name}");
+ if path.is_dir() {
+ conn.dispatch_app_event(ApplicationEvent::OpenDirectory(file_name));
+ } else {
conn.dispatch_app_event(ApplicationEvent::OpenCommandScript(file_name));
}
+ return YES;
}
+ NO
}
extern "C" fn application_dock_menu(
@@ -147,8 +152,6 @@ fn get_class() -> &'static Class {
let mut cls = ClassDecl::new(CLS_NAME, class!(NSWindow))
.expect("Unable to register application class");
- cls.add_ivar::("launched");
-
unsafe {
cls.add_method(
sel!(applicationShouldTerminate:),
@@ -164,7 +167,7 @@ fn get_class() -> &'static Class {
);
cls.add_method(
sel!(application:openFile:),
- application_open_file as extern "C" fn(&mut Object, Sel, *mut Object, *mut Object),
+ application_open_file as extern "C" fn(&mut Object, Sel, *mut Object, *mut Object) -> BOOL,
);
cls.add_method(
sel!(applicationDockMenu:),
@@ -191,7 +194,6 @@ pub fn create_app_delegate() -> StrongPtr {
unsafe {
let delegate: *mut Object = msg_send![cls, alloc];
let delegate: *mut Object = msg_send![delegate, init];
- (*delegate).set_ivar("launched", NO);
StrongPtr::new(delegate)
}
}