mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 22:28:24 +02:00
Work on code to run shells from a kitten with shell integration
This commit is contained in:
@@ -594,12 +594,13 @@ var RefMap = map[string]string{serialize_go_dict(ref_map['ref'])}
|
|||||||
var DocTitleMap = map[string]string{serialize_go_dict(ref_map['doc'])}
|
var DocTitleMap = map[string]string{serialize_go_dict(ref_map['doc'])}
|
||||||
var AllowedShellIntegrationValues = []string{{ {str(sorted(allowed_shell_integration_values))[1:-1].replace("'", '"')} }}
|
var AllowedShellIntegrationValues = []string{{ {str(sorted(allowed_shell_integration_values))[1:-1].replace("'", '"')} }}
|
||||||
var KittyConfigDefaults = struct {{
|
var KittyConfigDefaults = struct {{
|
||||||
Term, Shell_integration, Select_by_word_characters string
|
Term, Shell_integration, Select_by_word_characters, Shell string
|
||||||
Wheel_scroll_multiplier int
|
Wheel_scroll_multiplier int
|
||||||
Url_prefixes []string
|
Url_prefixes []string
|
||||||
}}{{
|
}}{{
|
||||||
Term: "{Options.term}", Shell_integration: "{' '.join(Options.shell_integration)}", Url_prefixes: []string{{ {url_prefixes} }},
|
Term: "{Options.term}", Shell_integration: "{' '.join(Options.shell_integration)}", Url_prefixes: []string{{ {url_prefixes} }},
|
||||||
Select_by_word_characters: `{Options.select_by_word_characters}`, Wheel_scroll_multiplier: {Options.wheel_scroll_multiplier},
|
Select_by_word_characters: `{Options.select_by_word_characters}`, Wheel_scroll_multiplier: {Options.wheel_scroll_multiplier},
|
||||||
|
Shell: "{Options.shell}",
|
||||||
}}
|
}}
|
||||||
''' # }}}
|
''' # }}}
|
||||||
|
|
||||||
@@ -812,7 +813,7 @@ def generate_ssh_kitten_data() -> None:
|
|||||||
for f in filenames:
|
for f in filenames:
|
||||||
path = os.path.join(dirpath, f)
|
path = os.path.join(dirpath, f)
|
||||||
files.add(path.replace(os.sep, '/'))
|
files.add(path.replace(os.sep, '/'))
|
||||||
dest = 'kittens/ssh/data_generated.bin'
|
dest = 'tools/tui/shell_integration/data_generated.bin'
|
||||||
|
|
||||||
def normalize(t: tarfile.TarInfo) -> tarfile.TarInfo:
|
def normalize(t: tarfile.TarInfo) -> tarfile.TarInfo:
|
||||||
t.uid = t.gid = 0
|
t.uid = t.gid = 0
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import (
|
|||||||
"kitty/tools/tty"
|
"kitty/tools/tty"
|
||||||
"kitty/tools/tui"
|
"kitty/tools/tui"
|
||||||
"kitty/tools/tui/loop"
|
"kitty/tools/tui/loop"
|
||||||
|
"kitty/tools/tui/shell_integration"
|
||||||
"kitty/tools/utils"
|
"kitty/tools/utils"
|
||||||
"kitty/tools/utils/secrets"
|
"kitty/tools/utils/secrets"
|
||||||
"kitty/tools/utils/shlex"
|
"kitty/tools/utils/shlex"
|
||||||
@@ -299,14 +300,14 @@ func make_tarfile(cd *connection_data, get_local_env func(string) (string, bool)
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
add_entries := func(prefix string, items ...Entry) error {
|
add_entries := func(prefix string, items ...shell_integration.Entry) error {
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
err := add(
|
err := add(
|
||||||
&tar.Header{
|
&tar.Header{
|
||||||
Typeflag: item.metadata.Typeflag, Name: path.Join(prefix, path.Base(item.metadata.Name)), Format: tar.FormatPAX,
|
Typeflag: item.Metadata.Typeflag, Name: path.Join(prefix, path.Base(item.Metadata.Name)), Format: tar.FormatPAX,
|
||||||
Size: int64(len(item.data)), Mode: item.metadata.Mode, ModTime: item.metadata.ModTime,
|
Size: int64(len(item.Data)), Mode: item.Metadata.Mode, ModTime: item.Metadata.ModTime,
|
||||||
AccessTime: item.metadata.AccessTime, ChangeTime: item.metadata.ChangeTime,
|
AccessTime: item.Metadata.AccessTime, ChangeTime: item.Metadata.ChangeTime,
|
||||||
}, item.data)
|
}, item.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -316,16 +317,16 @@ func make_tarfile(cd *connection_data, get_local_env func(string) (string, bool)
|
|||||||
}
|
}
|
||||||
add_data(fe{"data.sh", utils.UnsafeStringToBytes(env_script)})
|
add_data(fe{"data.sh", utils.UnsafeStringToBytes(env_script)})
|
||||||
if cd.script_type == "sh" {
|
if cd.script_type == "sh" {
|
||||||
add_data(fe{"bootstrap-utils.sh", Data()[path.Join("shell-integration/ssh/bootstrap-utils.sh")].data})
|
add_data(fe{"bootstrap-utils.sh", shell_integration.Data()[path.Join("shell-integration/ssh/bootstrap-utils.sh")].Data})
|
||||||
}
|
}
|
||||||
if ksi != "" {
|
if ksi != "" {
|
||||||
for _, fname := range Data().files_matching(
|
for _, fname := range shell_integration.Data().FilesMatching(
|
||||||
"shell-integration/",
|
"shell-integration/",
|
||||||
"shell-integration/ssh/.+", // bootstrap files are sent as command line args
|
"shell-integration/ssh/.+", // bootstrap files are sent as command line args
|
||||||
"shell-integration/zsh/kitty.zsh", // backward compat file not needed by ssh kitten
|
"shell-integration/zsh/kitty.zsh", // backward compat file not needed by ssh kitten
|
||||||
) {
|
) {
|
||||||
arcname := path.Join("home/", rd, "/", path.Dir(fname))
|
arcname := path.Join("home/", rd, "/", path.Dir(fname))
|
||||||
err = add_entries(arcname, Data()[fname])
|
err = add_entries(arcname, shell_integration.Data()[fname])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -338,15 +339,15 @@ func make_tarfile(cd *connection_data, get_local_env func(string) (string, bool)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, x := range []string{"kitty", "kitten"} {
|
for _, x := range []string{"kitty", "kitten"} {
|
||||||
err = add_entries(path.Join(arcname, "bin"), Data()[path.Join("shell-integration", "ssh", x)])
|
err = add_entries(path.Join(arcname, "bin"), shell_integration.Data()[path.Join("shell-integration", "ssh", x)])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = add_entries(path.Join("home", ".terminfo"), Data()["terminfo/kitty.terminfo"])
|
err = add_entries(path.Join("home", ".terminfo"), shell_integration.Data()["terminfo/kitty.terminfo"])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = add_entries(path.Join("home", ".terminfo", "x"), Data()["terminfo/x/xterm-kitty"])
|
err = add_entries(path.Join("home", ".terminfo", "x"), shell_integration.Data()["terminfo/x/xterm-kitty"])
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = tw.Close()
|
err = tw.Close()
|
||||||
@@ -470,7 +471,7 @@ func bootstrap_script(cd *connection_data) (err error) {
|
|||||||
}
|
}
|
||||||
maps.Copy(replacements, sensitive_data)
|
maps.Copy(replacements, sensitive_data)
|
||||||
cd.replacements = replacements
|
cd.replacements = replacements
|
||||||
cd.bootstrap_script = utils.UnsafeBytesToString(Data()["shell-integration/ssh/bootstrap."+cd.script_type].data)
|
cd.bootstrap_script = utils.UnsafeBytesToString(shell_integration.Data()["shell-integration/ssh/bootstrap."+cd.script_type].Data)
|
||||||
cd.bootstrap_script = prepare_script(cd.bootstrap_script, sd)
|
cd.bootstrap_script = prepare_script(cd.bootstrap_script, sd)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -584,7 +585,7 @@ func change_colors(color_scheme string) (ans string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func run_ssh(ssh_args, server_args, found_extra_args []string) (rc int, err error) {
|
func run_ssh(ssh_args, server_args, found_extra_args []string) (rc int, err error) {
|
||||||
go Data()
|
go shell_integration.Data()
|
||||||
go RelevantKittyOpts()
|
go RelevantKittyOpts()
|
||||||
defer func() {
|
defer func() {
|
||||||
if data_shm != nil {
|
if data_shm != nil {
|
||||||
|
|||||||
54
tools/cmd/run_shell/main.go
Normal file
54
tools/cmd/run_shell/main.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
package run_shell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"kitty/tools/cli"
|
||||||
|
"kitty/tools/tui"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = fmt.Print
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
Shell string
|
||||||
|
ShellIntegration string
|
||||||
|
}
|
||||||
|
|
||||||
|
func main(args []string, opts *Options) (rc int, err error) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
tui.RunCommandRestoringTerminalToSaneStateAfter(args)
|
||||||
|
}
|
||||||
|
err = tui.RunShell(tui.ResolveShell(opts.Shell), tui.ResolveShellIntegration(opts.ShellIntegration))
|
||||||
|
if err != nil {
|
||||||
|
rc = 1
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func EntryPoint(root *cli.Command) *cli.Command {
|
||||||
|
sc := root.AddSubCommand(&cli.Command{
|
||||||
|
Name: "run-shell",
|
||||||
|
Usage: "[options] [optional cmd to run before running the shell ...]",
|
||||||
|
ShortDescription: "Run the user's shell with shell integration enabled",
|
||||||
|
HelpText: "Run the users's configured shell. If the shell supports shell integration, enable it based on the user's configured shell_integration setting.",
|
||||||
|
Run: func(cmd *cli.Command, args []string) (ret int, err error) {
|
||||||
|
opts := &Options{}
|
||||||
|
err = cmd.GetOptionValues(opts)
|
||||||
|
if err != nil {
|
||||||
|
return 1, err
|
||||||
|
}
|
||||||
|
return main(args, opts)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
sc.Add(cli.OptionSpec{
|
||||||
|
Name: "--shell-integration",
|
||||||
|
Help: "Specify a value for the shell_integration option, overriding the one from kitty.conf.",
|
||||||
|
})
|
||||||
|
sc.Add(cli.OptionSpec{
|
||||||
|
Name: "--shell",
|
||||||
|
Help: "Specify the shell command to run. If not specified the value of the shell option from kitty.conf is used.",
|
||||||
|
})
|
||||||
|
return sc
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"kitty/tools/cmd/at"
|
"kitty/tools/cmd/at"
|
||||||
"kitty/tools/cmd/edit_in_kitty"
|
"kitty/tools/cmd/edit_in_kitty"
|
||||||
"kitty/tools/cmd/pytest"
|
"kitty/tools/cmd/pytest"
|
||||||
|
"kitty/tools/cmd/run_shell"
|
||||||
"kitty/tools/cmd/update_self"
|
"kitty/tools/cmd/update_self"
|
||||||
"kitty/tools/tui"
|
"kitty/tools/tui"
|
||||||
)
|
)
|
||||||
@@ -55,6 +56,8 @@ func KittyToolEntryPoints(root *cli.Command) {
|
|||||||
// themes
|
// themes
|
||||||
themes.EntryPoint(root)
|
themes.EntryPoint(root)
|
||||||
themes.ParseEntryPoint(root)
|
themes.ParseEntryPoint(root)
|
||||||
|
// run-shell
|
||||||
|
run_shell.EntryPoint(root)
|
||||||
// __pytest__
|
// __pytest__
|
||||||
pytest.EntryPoint(root)
|
pytest.EntryPoint(root)
|
||||||
// __hold_till_enter__
|
// __hold_till_enter__
|
||||||
|
|||||||
182
tools/tui/run.go
Normal file
182
tools/tui/run.go
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
package tui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"kitty"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
"kitty/tools/config"
|
||||||
|
"kitty/tools/tty"
|
||||||
|
"kitty/tools/tui/loop"
|
||||||
|
"kitty/tools/tui/shell_integration"
|
||||||
|
"kitty/tools/utils"
|
||||||
|
"kitty/tools/utils/shlex"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = fmt.Print
|
||||||
|
|
||||||
|
type KittyOpts struct {
|
||||||
|
Shell, Shell_integration string
|
||||||
|
}
|
||||||
|
|
||||||
|
func read_relevant_kitty_opts(path string) KittyOpts {
|
||||||
|
ans := KittyOpts{Shell: kitty.KittyConfigDefaults.Shell, Shell_integration: kitty.KittyConfigDefaults.Shell_integration}
|
||||||
|
handle_line := func(key, val string) error {
|
||||||
|
switch key {
|
||||||
|
case "shell":
|
||||||
|
ans.Shell = strings.TrimSpace(val)
|
||||||
|
case "shell_integration":
|
||||||
|
ans.Shell_integration = strings.TrimSpace(val)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cp := config.ConfigParser{LineHandler: handle_line}
|
||||||
|
cp.ParseFiles(path)
|
||||||
|
if ans.Shell == "" {
|
||||||
|
ans.Shell = kitty.KittyConfigDefaults.Shell
|
||||||
|
}
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
|
||||||
|
func get_effective_ksi_env_var(x string) string {
|
||||||
|
parts := strings.Split(strings.TrimSpace(strings.ToLower(x)), " ")
|
||||||
|
current := utils.NewSetWithItems(parts...)
|
||||||
|
if current.Has("disabled") {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
allowed := utils.NewSetWithItems(kitty.AllowedShellIntegrationValues...)
|
||||||
|
if !current.IsSubsetOf(allowed) {
|
||||||
|
return relevant_kitty_opts().Shell_integration
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
var relevant_kitty_opts = utils.Once(func() KittyOpts {
|
||||||
|
return read_relevant_kitty_opts(filepath.Join(utils.ConfigDir(), "kitty.conf"))
|
||||||
|
})
|
||||||
|
|
||||||
|
func ResolveShell(shell string) []string {
|
||||||
|
if shell == "" {
|
||||||
|
shell = relevant_kitty_opts().Shell
|
||||||
|
if shell == "." {
|
||||||
|
s, e := utils.LoginShellForCurrentUser()
|
||||||
|
if e != nil {
|
||||||
|
shell = "/bin/sh"
|
||||||
|
} else {
|
||||||
|
shell = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shell_cmd, err := shlex.Split(shell)
|
||||||
|
if err != nil {
|
||||||
|
shell_cmd = []string{shell}
|
||||||
|
}
|
||||||
|
exe := utils.FindExe(shell_cmd[0])
|
||||||
|
if unix.Access(exe, unix.X_OK) != nil {
|
||||||
|
shell_cmd = []string{"/bin/sh"}
|
||||||
|
}
|
||||||
|
return shell_cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResolveShellIntegration(shell_integration string) string {
|
||||||
|
if shell_integration == "" {
|
||||||
|
shell_integration = relevant_kitty_opts().Shell_integration
|
||||||
|
}
|
||||||
|
return get_effective_ksi_env_var(shell_integration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func get_shell_name(argv0 string) (ans string) {
|
||||||
|
ans = filepath.Base(argv0)
|
||||||
|
if strings.HasSuffix(strings.ToLower(ans), ".exe") {
|
||||||
|
ans = ans[:len(ans)-4]
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(ans, "-") {
|
||||||
|
ans = ans[1:]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func rc_modification_allowed(ksi string) bool {
|
||||||
|
for _, x := range strings.Split(ksi, " ") {
|
||||||
|
switch x {
|
||||||
|
case "disabled", "no-rc":
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ksi != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunShell(shell_cmd []string, shell_integration_env_var_val string) (err error) {
|
||||||
|
shell_name := get_shell_name(shell_cmd[0])
|
||||||
|
var shell_env map[string]string
|
||||||
|
if rc_modification_allowed(shell_integration_env_var_val) && shell_integration.IsSupportedShell(shell_name) {
|
||||||
|
oenv := os.Environ()
|
||||||
|
env := make(map[string]string, len(oenv))
|
||||||
|
for _, x := range oenv {
|
||||||
|
if k, v, found := strings.Cut(x, "="); found {
|
||||||
|
env[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argv, env, err := shell_integration.Setup(shell_name, shell_cmd, env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
shell_cmd = argv
|
||||||
|
shell_env = env
|
||||||
|
}
|
||||||
|
exe := shell_cmd[0]
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
// ensure shell runs in login mode
|
||||||
|
shell_cmd[0] = "-" + filepath.Base(shell_cmd[0])
|
||||||
|
}
|
||||||
|
var env []string
|
||||||
|
if shell_env != nil {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
return unix.Exec(utils.FindExe(exe), shell_cmd, env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunCommandRestoringTerminalToSaneStateAfter(cmd []string) {
|
||||||
|
exe := utils.FindExe(cmd[0])
|
||||||
|
c := exec.Command(exe, cmd[1:]...)
|
||||||
|
c.Stdout = os.Stdout
|
||||||
|
c.Stdin = os.Stdin
|
||||||
|
c.Stderr = os.Stderr
|
||||||
|
term, err := tty.OpenControllingTerm()
|
||||||
|
if err == nil {
|
||||||
|
var state_before unix.Termios
|
||||||
|
if term.Tcgetattr(&state_before) == nil {
|
||||||
|
term.WriteString(loop.SAVE_PRIVATE_MODE_VALUES)
|
||||||
|
defer func() {
|
||||||
|
term.WriteString(strings.Join([]string{
|
||||||
|
loop.RESTORE_PRIVATE_MODE_VALUES,
|
||||||
|
"\x1b[=u", // reset kitty keyboard protocol to legacy
|
||||||
|
"\x1b[1 q", // blinking block cursor
|
||||||
|
loop.DECTCEM.EscapeCodeToSet(), // cursor visible
|
||||||
|
"\x1b]112\a", // reset cursor color
|
||||||
|
}, ""))
|
||||||
|
term.Tcsetattr(tty.TCSANOW, &state_before)
|
||||||
|
term.Close()
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
defer term.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = c.Run()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, cmd[0], "failed with error:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
71
tools/tui/shell_integration/api.go
Normal file
71
tools/tui/shell_integration/api.go
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
package shell_integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = fmt.Print
|
||||||
|
|
||||||
|
type integration_setup_func = func(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()
|
||||||
|
for _, fname := range d.FilesMatching("shell-integration/" + shell_name + "/") {
|
||||||
|
entry := d[fname]
|
||||||
|
dest := filepath.Join(dest_dir, fname)
|
||||||
|
ddir := filepath.Dir(dest)
|
||||||
|
if err = os.MkdirAll(ddir, 0o755); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch entry.Metadata.Typeflag {
|
||||||
|
case tar.TypeDir:
|
||||||
|
if err = os.MkdirAll(dest, 0o755); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case tar.TypeSymlink:
|
||||||
|
if err = os.Symlink(entry.Metadata.Linkname, dest); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case tar.TypeReg:
|
||||||
|
if err = os.WriteFile(dest, entry.Data, 0o644); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func zsh_setup_func(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 bash_setup_func(argv []string, env map[string]string) (final_argv []string, final_env map[string]string, err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup_func_for_shell(shell_name string) integration_setup_func {
|
||||||
|
switch shell_name {
|
||||||
|
case "zsh":
|
||||||
|
return zsh_setup_func
|
||||||
|
case "fish":
|
||||||
|
return fish_setup_func
|
||||||
|
case "bash":
|
||||||
|
return bash_setup_func
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
package ssh
|
package shell_integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
@@ -19,8 +19,8 @@ var _ = fmt.Print
|
|||||||
var embedded_data string
|
var embedded_data string
|
||||||
|
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
metadata *tar.Header
|
Metadata *tar.Header
|
||||||
data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type Container map[string]Entry
|
type Container map[string]Entry
|
||||||
@@ -45,7 +45,7 @@ var Data = utils.Once(func() Container {
|
|||||||
return ans
|
return ans
|
||||||
})
|
})
|
||||||
|
|
||||||
func (self Container) files_matching(prefix string, exclude_patterns ...string) []string {
|
func (self Container) FilesMatching(prefix string, exclude_patterns ...string) []string {
|
||||||
ans := make([]string, 0, len(self))
|
ans := make([]string, 0, len(self))
|
||||||
patterns := make([]*regexp.Regexp, len(exclude_patterns))
|
patterns := make([]*regexp.Regexp, len(exclude_patterns))
|
||||||
for i, exp := range exclude_patterns {
|
for i, exp := range exclude_patterns {
|
||||||
Reference in New Issue
Block a user