mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-02 12:44:01 +02:00
Port the fish setup function to Go
This commit is contained in:
@@ -125,7 +125,7 @@ func RunShell(shell_cmd []string, shell_integration_env_var_val string) (err err
|
||||
env[k] = v
|
||||
}
|
||||
}
|
||||
argv, env, err := shell_integration.Setup(shell_name, shell_cmd, env)
|
||||
argv, env, err := shell_integration.Setup(shell_name, shell_integration_env_var_val, shell_cmd, env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -134,18 +134,20 @@ func RunShell(shell_cmd []string, shell_integration_env_var_val string) (err err
|
||||
}
|
||||
exe := shell_cmd[0]
|
||||
if runtime.GOOS == "darwin" {
|
||||
// ensure shell runs in login mode
|
||||
// ensure shell runs in login mode. On macOS lots of people use ~/.bash_profile instead of ~/.bashrc
|
||||
// which means they expect the shell to run in login mode always. Le Sigh.
|
||||
shell_cmd[0] = "-" + filepath.Base(shell_cmd[0])
|
||||
}
|
||||
var env []string
|
||||
if shell_env != nil {
|
||||
env := make([]string, 0, len(shell_env))
|
||||
env = make([]string, 0, len(shell_env))
|
||||
for k, v := range shell_env {
|
||||
env = append(env, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
} else {
|
||||
env = os.Environ()
|
||||
}
|
||||
// fmt.Println(fmt.Sprintf("%s %v\n%#v", utils.FindExe(exe), shell_cmd, env))
|
||||
return unix.Exec(utils.FindExe(exe), shell_cmd, env)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,20 @@ package shell_integration
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"kitty/tools/utils"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
type integration_setup_func = func(argv []string, env map[string]string) ([]string, map[string]string, error)
|
||||
type integration_setup_func = func(shell_integration_dir string, argv []string, env map[string]string) ([]string, map[string]string, error)
|
||||
|
||||
func extract_shell_integration_for(shell_name string, dest_dir string) (err error) {
|
||||
d := Data()
|
||||
@@ -32,7 +38,10 @@ func extract_shell_integration_for(shell_name string, dest_dir string) (err erro
|
||||
return
|
||||
}
|
||||
case tar.TypeReg:
|
||||
if err = os.WriteFile(dest, entry.Data, 0o644); err != nil {
|
||||
if existing, rerr := os.ReadFile(dest); rerr == nil && bytes.Equal(existing, entry.Data) {
|
||||
continue
|
||||
}
|
||||
if err = utils.AtomicWriteFile(dest, entry.Data, 0o644); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -40,15 +49,44 @@ func extract_shell_integration_for(shell_name string, dest_dir string) (err erro
|
||||
return
|
||||
}
|
||||
|
||||
func zsh_setup_func(argv []string, env map[string]string) (final_argv []string, final_env map[string]string, err error) {
|
||||
func EnsureShellIntegrationFilesFor(shell_name string) (shell_integration_dir string, err error) {
|
||||
if kid := os.Getenv("KITTY_INSTALLATION_DIR"); kid != "" {
|
||||
if s, e := os.Stat(kid); e == nil && s.IsDir() {
|
||||
q := filepath.Join(kid, "shell-integration", shell_name)
|
||||
if s, e := os.Stat(q); e == nil && s.IsDir() {
|
||||
return q, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
base := filepath.Join(utils.CacheDir(), "extracted-ksi")
|
||||
if err = os.MkdirAll(base, 0o755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = extract_shell_integration_for(shell_name, base); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(base, "shell-integration"), nil
|
||||
}
|
||||
|
||||
func zsh_setup_func(shell_integration_dir string, argv []string, env map[string]string) (final_argv []string, final_env map[string]string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func fish_setup_func(argv []string, env map[string]string) (final_argv []string, final_env map[string]string, err error) {
|
||||
return
|
||||
func fish_setup_func(shell_integration_dir string, argv []string, env map[string]string) (final_argv []string, final_env map[string]string, err error) {
|
||||
shell_integration_dir = filepath.Dir(shell_integration_dir)
|
||||
val := env[`XDG_DATA_DIRS`]
|
||||
env[`KITTY_FISH_XDG_DATA_DIR`] = shell_integration_dir
|
||||
if val == "" {
|
||||
env[`XDG_DATA_DIRS`] = shell_integration_dir
|
||||
} else {
|
||||
dirs := utils.Filter(strings.Split(val, string(filepath.ListSeparator)), func(x string) bool { return x != "" })
|
||||
dirs = append([]string{shell_integration_dir}, dirs...)
|
||||
env[`XDG_DATA_DIRS`] = strings.Join(dirs, string(filepath.ListSeparator))
|
||||
}
|
||||
return argv, env, nil
|
||||
}
|
||||
|
||||
func bash_setup_func(argv []string, env map[string]string) (final_argv []string, final_env map[string]string, err error) {
|
||||
func bash_setup_func(shell_integration_dir string, argv []string, env map[string]string) (final_argv []string, final_env map[string]string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -66,6 +104,14 @@ func setup_func_for_shell(shell_name string) integration_setup_func {
|
||||
|
||||
func IsSupportedShell(shell_name string) bool { return setup_func_for_shell(shell_name) != nil }
|
||||
|
||||
func Setup(shell_name string, argv []string, env map[string]string) ([]string, map[string]string, error) {
|
||||
return setup_func_for_shell(shell_name)(argv, env)
|
||||
func Setup(shell_name string, ksi_var string, argv []string, env map[string]string) ([]string, map[string]string, error) {
|
||||
ksi_dir, err := EnsureShellIntegrationFilesFor(shell_name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
argv, env, err = setup_func_for_shell(shell_name)(ksi_dir, slices.Clone(argv), maps.Clone(env))
|
||||
if err == nil {
|
||||
env[`KITTY_SHELL_INTEGRATION`] = ksi_var
|
||||
}
|
||||
return argv, env, err
|
||||
}
|
||||
|
||||
42
tools/tui/shell_integration/api_test.go
Normal file
42
tools/tui/shell_integration/api_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
package shell_integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
func TestExtractShellIntegration(t *testing.T) {
|
||||
tdir := t.TempDir()
|
||||
if err := extract_shell_integration_for("zsh", tdir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
kzsh := filepath.Join(tdir, "shell-integration", "zsh", "kitty.zsh")
|
||||
if _, err := os.Stat(kzsh); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(tdir, "shell-integration", "zsh", "completions", "_kitty")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
orig, err := os.ReadFile(kzsh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
os.WriteFile(kzsh, []byte("changed"), 0o644)
|
||||
if err := extract_shell_integration_for("zsh", tdir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
changed, err := os.ReadFile(kzsh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(changed, orig) {
|
||||
t.Fatalf("Failed to update shell integration file")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user