mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-16 21:45:03 +02:00
macOS: fix args passed via open --args being ignored when macos-launch-services-cmdline is present (fixes #9910)
Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/2cdc7e8f-5b64-4c97-bd65-dec508155313 Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
cadaec5712
commit
7d3ff332b9
@@ -259,6 +259,8 @@ Detailed list of changes
|
|||||||
|
|
||||||
- Fix setting :opt:`momentum_scroll` to zero not *fully* disabling momentum scrolling (:iss:`9904`)
|
- Fix setting :opt:`momentum_scroll` to zero not *fully* disabling momentum scrolling (:iss:`9904`)
|
||||||
|
|
||||||
|
- macOS: Fix args passed via ``open --args`` being ignored when :file:`macos-launch-services-cmdline` is present (:iss:`9910`)
|
||||||
|
|
||||||
|
|
||||||
0.46.2 [2026-03-21]
|
0.46.2 [2026-03-21]
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|||||||
@@ -13,6 +13,24 @@
|
|||||||
#include <os/log.h>
|
#include <os/log.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool
|
||||||
|
append_arg_to_argv_array(argv_array *a, const char *arg) {
|
||||||
|
if (a->count + 2 > a->capacity) {
|
||||||
|
size_t cap = a->capacity * 2;
|
||||||
|
if (!cap) cap = 256;
|
||||||
|
void *m = realloc(a->argv, cap * sizeof(a->argv[0]));
|
||||||
|
if (!m) return false;
|
||||||
|
a->argv = m;
|
||||||
|
a->capacity = cap;
|
||||||
|
a->needs_free = true;
|
||||||
|
}
|
||||||
|
// arg points into the process's original argv which persists for the lifetime
|
||||||
|
// of the process and is never modified through this pointer.
|
||||||
|
a->argv[a->count++] = (char*)arg;
|
||||||
|
a->argv[a->count] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
free_argv_array(argv_array *a) {
|
free_argv_array(argv_array *a) {
|
||||||
if (a && a->needs_free) {
|
if (a && a->needs_free) {
|
||||||
|
|||||||
@@ -25,4 +25,5 @@ typedef struct argv_array {
|
|||||||
|
|
||||||
void single_instance_main(int argc, char *argv[], const CLIOptions *opts);
|
void single_instance_main(int argc, char *argv[], const CLIOptions *opts);
|
||||||
bool get_argv_from(const char *filename, const char* argv0, argv_array *ans);
|
bool get_argv_from(const char *filename, const char* argv0, argv_array *ans);
|
||||||
|
bool append_arg_to_argv_array(argv_array *a, const char *arg);
|
||||||
void free_argv_array(argv_array *a);
|
void free_argv_array(argv_array *a);
|
||||||
|
|||||||
@@ -539,7 +539,19 @@ main(int argc_, char *argv_[], char* envp[]) {
|
|||||||
if (launched_by_launch_services && config_dir[0]) {
|
if (launched_by_launch_services && config_dir[0]) {
|
||||||
char cbuf[PATH_MAX];
|
char cbuf[PATH_MAX];
|
||||||
safe_snprintf(cbuf, sizeof(cbuf), "%s/macos-launch-services-cmdline", config_dir);
|
safe_snprintf(cbuf, sizeof(cbuf), "%s/macos-launch-services-cmdline", config_dir);
|
||||||
|
int orig_argc = argc_; char **orig_argv = argv_;
|
||||||
if (!get_argv_from(cbuf, argva.argv[0], &argva)) exit(1);
|
if (!get_argv_from(cbuf, argva.argv[0], &argva)) exit(1);
|
||||||
|
// If the file was loaded (argva replaced), append any extra args passed via open --args
|
||||||
|
if (argva.needs_free) {
|
||||||
|
for (int i = 1; i < orig_argc; i++) {
|
||||||
|
// Skip Apple-internal process serial number args (-psn_*)
|
||||||
|
if (strncmp(orig_argv[i], "-psn_", sizeof("-psn_") - 1) == 0) continue;
|
||||||
|
if (!append_arg_to_argv_array(&argva, orig_argv[i])) {
|
||||||
|
fprintf(stderr, "Out of memory while processing launch services args\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -650,19 +650,26 @@ class TestDataTypes(BaseTest):
|
|||||||
shutil.rmtree(dot_config)
|
shutil.rmtree(dot_config)
|
||||||
with tempfile.TemporaryDirectory() as tdir:
|
with tempfile.TemporaryDirectory() as tdir:
|
||||||
with open(tdir + '/macos-launch-services-cmdline', 'w') as f:
|
with open(tdir + '/macos-launch-services-cmdline', 'w') as f:
|
||||||
print('kitty +runpy "import sys; print(sys.argv[-1])"', file=f)
|
print('kitty --title from-file', file=f)
|
||||||
print('next-line', file=f)
|
|
||||||
print()
|
|
||||||
if is_macos:
|
if is_macos:
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env['KITTY_CONFIG_DIRECTORY'] = tdir
|
env['KITTY_CONFIG_DIRECTORY'] = tdir
|
||||||
env['KITTY_LAUNCHED_BY_LAUNCH_SERVICES'] = '1'
|
env['KITTY_LAUNCHED_BY_LAUNCH_SERVICES'] = '1'
|
||||||
cp = subprocess.run([kitty_exe(), '+runpy', 'import json, sys; print(json.dumps(sys.argv))'], env=env, stdout=subprocess.PIPE)
|
# Test 1: file args are loaded when no extra user args are present
|
||||||
actual = cp.stdout.strip().decode()
|
cp = subprocess.run([kitty_exe(), '+testing-launcher-code'], env=env, stdout=subprocess.PIPE)
|
||||||
|
actual = cp.stdout.decode()
|
||||||
if cp.returncode != 0:
|
if cp.returncode != 0:
|
||||||
print(actual)
|
print(actual)
|
||||||
raise AssertionError(f'kitty +runpy failed with return code: {cp.returncode}')
|
raise AssertionError(f'kitty +testing-launcher-code failed with return code: {cp.returncode}')
|
||||||
self.ae('next-line', actual)
|
self.assertIn('from-file', actual)
|
||||||
|
# Test 2: extra args passed via open --args are appended after file args
|
||||||
|
cp = subprocess.run([kitty_exe(), '+testing-launcher-code', '--title', 'from-args'], env=env, stdout=subprocess.PIPE)
|
||||||
|
actual = cp.stdout.decode()
|
||||||
|
if cp.returncode != 0:
|
||||||
|
print(actual)
|
||||||
|
raise AssertionError(f'kitty +testing-launcher-code failed with return code: {cp.returncode}')
|
||||||
|
# from-args overrides from-file because user args are appended after file args
|
||||||
|
self.assertIn('from-args', actual)
|
||||||
os.makedirs(tdir + '/good/kitty')
|
os.makedirs(tdir + '/good/kitty')
|
||||||
open(tdir + '/good/kitty/kitty.conf', 'w').close()
|
open(tdir + '/good/kitty/kitty.conf', 'w').close()
|
||||||
data = os.urandom(32879)
|
data = os.urandom(32879)
|
||||||
|
|||||||
@@ -125,14 +125,18 @@ version
|
|||||||
|
|
||||||
|
|
||||||
def launcher(self):
|
def launcher(self):
|
||||||
|
import tempfile
|
||||||
|
from kitty.constants import is_macos
|
||||||
kexe = kitty_exe()
|
kexe = kitty_exe()
|
||||||
cfgdir = None
|
cfgdir = None
|
||||||
def get_report(cmdline: str, launch_services= False):
|
def get_report(cmdline: str, launch_services= False, config_dir: str = ''):
|
||||||
nonlocal cfgdir
|
nonlocal cfgdir
|
||||||
args = list(shlex_split(cmdline))
|
args = list(shlex_split(cmdline))
|
||||||
env = dict(os.environ)
|
env = dict(os.environ)
|
||||||
if launch_services:
|
if launch_services:
|
||||||
env['KITTY_LAUNCHED_BY_LAUNCH_SERVICES'] = '1'
|
env['KITTY_LAUNCHED_BY_LAUNCH_SERVICES'] = '1'
|
||||||
|
if config_dir:
|
||||||
|
env['KITTY_CONFIG_DIRECTORY'] = config_dir
|
||||||
cp = subprocess.run([kexe, "+testing-launcher-code"] + args, env=env, stdout=subprocess.PIPE)
|
cp = subprocess.run([kexe, "+testing-launcher-code"] + args, env=env, stdout=subprocess.PIPE)
|
||||||
self.assertEqual(cp.returncode, 0)
|
self.assertEqual(cp.returncode, 0)
|
||||||
ans = {}
|
ans = {}
|
||||||
@@ -200,6 +204,17 @@ def launcher(self):
|
|||||||
dt('--detach --session=moose --detached-log=xyz', detached_log='xyz', session='moose')
|
dt('--detach --session=moose --detached-log=xyz', detached_log='xyz', session='moose')
|
||||||
pn('+kitten panel -1 --edge=left', edge='left')
|
pn('+kitten panel -1 --edge=left', edge='left')
|
||||||
|
|
||||||
|
if is_macos:
|
||||||
|
with tempfile.TemporaryDirectory() as tdir:
|
||||||
|
with open(tdir + '/macos-launch-services-cmdline', 'w') as f:
|
||||||
|
f.write('kitty --title from-file\n')
|
||||||
|
# File args are used when launched by launch services
|
||||||
|
r, output = get_report('', launch_services=True, config_dir=tdir)
|
||||||
|
self.assertEqual(r.get('title'), 'from-file', f'Expected title=from-file in:\n{output}')
|
||||||
|
# User args passed via open --args are appended after file args (and override them)
|
||||||
|
r, output = get_report('--title from-args', launch_services=True, config_dir=tdir)
|
||||||
|
self.assertEqual(r.get('title'), 'from-args', f'Expected title=from-args to override from-file in:\n{output}')
|
||||||
|
|
||||||
|
|
||||||
def conf_parsing(self):
|
def conf_parsing(self):
|
||||||
from kitty.config import defaults, load_config
|
from kitty.config import defaults, load_config
|
||||||
|
|||||||
Reference in New Issue
Block a user