mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-27 18:51:41 +02:00
kitten run-shell: Make kitty terminfo database available if needed before starting the shell
This commit is contained in:
@@ -54,6 +54,8 @@ Detailed list of changes
|
|||||||
|
|
||||||
- kitten icat: Fix image being displayed one cell to the right when using both ``--place`` and ``--unicode-placeholder`` (:iss:`6556`)
|
- kitten icat: Fix image being displayed one cell to the right when using both ``--place`` and ``--unicode-placeholder`` (:iss:`6556`)
|
||||||
|
|
||||||
|
- kitten run-shell: Make kitty terminfo database available if needed before starting the shell
|
||||||
|
|
||||||
- macOS: Fix keyboard shortcuts in the Apple global menubar not being changed when reloading the config
|
- macOS: Fix keyboard shortcuts in the Apple global menubar not being changed when reloading the config
|
||||||
|
|
||||||
- Fix a crash when resizing an OS Window that is displaying more than one image and the new size is smaller than the image needs (:iss:`6555`)
|
- Fix a crash when resizing an OS Window that is displaying more than one image and the new size is smaller than the image needs (:iss:`6555`)
|
||||||
|
|||||||
@@ -233,6 +233,8 @@ somewhere in the PATH, then you can log into the container with:
|
|||||||
|
|
||||||
docker exec -ti container-id kitten run-shell --shell=/path/to/your/shell/in/the/container
|
docker exec -ti container-id kitten run-shell --shell=/path/to/your/shell/in/the/container
|
||||||
|
|
||||||
|
The kitten will even take care of making the kitty terminfo database available
|
||||||
|
in the container automatically.
|
||||||
|
|
||||||
.. _clone_shell:
|
.. _clone_shell:
|
||||||
|
|
||||||
|
|||||||
@@ -562,7 +562,6 @@ def load_ref_map() -> Dict[str, Dict[str, str]]:
|
|||||||
def generate_constants() -> str:
|
def generate_constants() -> str:
|
||||||
from kittens.hints.main import DEFAULT_REGEX
|
from kittens.hints.main import DEFAULT_REGEX
|
||||||
from kitty.fast_data_types import FILE_TRANSFER_CODE
|
from kitty.fast_data_types import FILE_TRANSFER_CODE
|
||||||
from kitty.options.types import Options
|
|
||||||
from kitty.options.utils import allowed_shell_integration_values
|
from kitty.options.utils import allowed_shell_integration_values
|
||||||
del sys.modules['kittens.hints.main']
|
del sys.modules['kittens.hints.main']
|
||||||
ref_map = load_ref_map()
|
ref_map = load_ref_map()
|
||||||
@@ -589,6 +588,7 @@ const IsFrozenBuild bool = false
|
|||||||
const IsStandaloneBuild bool = false
|
const IsStandaloneBuild bool = false
|
||||||
const HandleTermiosSignals = {Mode.HANDLE_TERMIOS_SIGNALS.value[0]}
|
const HandleTermiosSignals = {Mode.HANDLE_TERMIOS_SIGNALS.value[0]}
|
||||||
const HintsDefaultRegex = `{DEFAULT_REGEX}`
|
const HintsDefaultRegex = `{DEFAULT_REGEX}`
|
||||||
|
const DefaultTermName = `{Options.term}`
|
||||||
var Version VersionType = VersionType{{Major: {kc.version.major}, Minor: {kc.version.minor}, Patch: {kc.version.patch},}}
|
var Version VersionType = VersionType{{Major: {kc.version.major}, Minor: {kc.version.minor}, Patch: {kc.version.patch},}}
|
||||||
var DefaultPager []string = []string{{ {dp} }}
|
var DefaultPager []string = []string{{ {dp} }}
|
||||||
var FunctionalKeyNameAliases = map[string]string{serialize_go_dict(functional_key_name_aliases)}
|
var FunctionalKeyNameAliases = map[string]string{serialize_go_dict(functional_key_name_aliases)}
|
||||||
@@ -811,7 +811,7 @@ def generate_unicode_names(src: TextIO, dest: BinaryIO) -> None:
|
|||||||
|
|
||||||
def generate_ssh_kitten_data() -> None:
|
def generate_ssh_kitten_data() -> None:
|
||||||
files = {
|
files = {
|
||||||
'terminfo/kitty.terminfo', 'terminfo/x/xterm-kitty',
|
'terminfo/kitty.terminfo', 'terminfo/x/' + Options.term,
|
||||||
}
|
}
|
||||||
for dirpath, dirnames, filenames in os.walk('shell-integration'):
|
for dirpath, dirnames, filenames in os.walk('shell-integration'):
|
||||||
for f in filenames:
|
for f in filenames:
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ func make_tarfile(cd *connection_data, get_local_env func(string) (string, bool)
|
|||||||
}
|
}
|
||||||
err = add_entries(path.Join("home", ".terminfo"), shell_integration.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"), shell_integration.Data()["terminfo/x/xterm-kitty"])
|
err = add_entries(path.Join("home", ".terminfo", "x"), shell_integration.Data()["terminfo/x/"+kitty.DefaultTermName])
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = tw.Close()
|
err = tw.Close()
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"kitty"
|
||||||
"kitty/tools/utils/shm"
|
"kitty/tools/utils/shm"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -133,7 +134,7 @@ func TestSSHTarfile(t *testing.T) {
|
|||||||
if !seen["data.sh"] {
|
if !seen["data.sh"] {
|
||||||
t.Fatalf("data.sh missing")
|
t.Fatalf("data.sh missing")
|
||||||
}
|
}
|
||||||
for _, x := range []string{".terminfo/kitty.terminfo", ".terminfo/x/xterm-kitty"} {
|
for _, x := range []string{".terminfo/kitty.terminfo", ".terminfo/x/" + kitty.DefaultTermName} {
|
||||||
if !seen["home/"+x] {
|
if !seen["home/"+x] {
|
||||||
t.Fatalf("%s missing", x)
|
t.Fatalf("%s missing", x)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,9 @@
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from typing import TYPE_CHECKING, Dict, Generator, Optional, cast
|
from typing import Dict, Generator, Optional, cast
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
from kitty.options.types import Options
|
||||||
from .options.types import Options
|
|
||||||
|
|
||||||
|
|
||||||
def modify_key_bytes(keybytes: bytes, amt: int) -> bytes:
|
def modify_key_bytes(keybytes: bytes, amt: int) -> bytes:
|
||||||
@@ -25,7 +24,7 @@ def encode_keystring(keybytes: bytes) -> str:
|
|||||||
return keybytes.decode('ascii').replace('\033', r'\E')
|
return keybytes.decode('ascii').replace('\033', r'\E')
|
||||||
|
|
||||||
|
|
||||||
names = 'xterm-kitty', 'KovIdTTY'
|
names = Options.term, 'KovIdTTY'
|
||||||
|
|
||||||
termcap_aliases = {
|
termcap_aliases = {
|
||||||
'TN': 'name'
|
'TN': 'name'
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ package run_shell
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"kitty"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"kitty/tools/cli"
|
"kitty/tools/cli"
|
||||||
"kitty/tools/tui"
|
"kitty/tools/tui"
|
||||||
|
"kitty/tools/tui/shell_integration"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = fmt.Print
|
var _ = fmt.Print
|
||||||
@@ -38,6 +40,19 @@ func main(args []string, opts *Options) (rc int, err error) {
|
|||||||
}
|
}
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
|
if os.Getenv("TERM") == "" {
|
||||||
|
os.Setenv("TERM", kitty.DefaultTermName)
|
||||||
|
}
|
||||||
|
if term := os.Getenv("TERM"); term == kitty.DefaultTermName && shell_integration.PathToTerminfoDb(term) == "" {
|
||||||
|
if terminfo_dir, err := shell_integration.EnsureTerminfoFiles(); err == nil {
|
||||||
|
os.Unsetenv("TERMINFO")
|
||||||
|
existing := os.Getenv("TERMINFO_DIRS")
|
||||||
|
if existing != "" {
|
||||||
|
existing = string(os.PathListSeparator) + existing
|
||||||
|
}
|
||||||
|
os.Setenv("TERMINFO_DIRS", terminfo_dir+existing)
|
||||||
|
}
|
||||||
|
}
|
||||||
err = tui.RunShell(tui.ResolveShell(opts.Shell), tui.ResolveShellIntegration(opts.ShellIntegration))
|
err = tui.RunShell(tui.ResolveShell(opts.Shell), tui.ResolveShellIntegration(opts.ShellIntegration))
|
||||||
if changed {
|
if changed {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"archive/tar"
|
"archive/tar"
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"kitty"
|
||||||
"kitty/tools/utils"
|
"kitty/tools/utils"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -55,6 +56,12 @@ func extract_shell_integration_for(shell_name string, dest_dir string) (err erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func extract_terminfo(dest_dir string) (err error) {
|
func extract_terminfo(dest_dir string) (err error) {
|
||||||
|
var s os.FileInfo
|
||||||
|
if s, err = os.Stat(filepath.Join(dest_dir, "terminfo", "x", kitty.DefaultTermName)); err == nil && s.Mode().IsRegular() {
|
||||||
|
if s, err = os.Stat(filepath.Join(dest_dir, "terminfo", "78", kitty.DefaultTermName)); err == nil && s.Mode().IsRegular() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
if err = extract_files("terminfo/", dest_dir); err == nil {
|
if err = extract_files("terminfo/", dest_dir); err == nil {
|
||||||
dest := filepath.Join(dest_dir, "terminfo", "78")
|
dest := filepath.Join(dest_dir, "terminfo", "78")
|
||||||
err = os.Symlink("x", dest)
|
err = os.Symlink("x", dest)
|
||||||
@@ -62,6 +69,76 @@ func extract_terminfo(dest_dir string) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PathToTerminfoDb(term string) (ans string) {
|
||||||
|
// see man terminfo for the algorithm ncurses uses for this
|
||||||
|
|
||||||
|
seen := utils.NewSet[string]()
|
||||||
|
check_dir := func(path string) string {
|
||||||
|
if seen.Has(path) {
|
||||||
|
return ``
|
||||||
|
}
|
||||||
|
seen.Add(path)
|
||||||
|
q := filepath.Join(path, term[:1], term)
|
||||||
|
if s, err := os.Stat(q); err == nil && s.Mode().IsRegular() {
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
if entries, err := os.ReadDir(filepath.Join(path)); err == nil {
|
||||||
|
for _, x := range entries {
|
||||||
|
q := filepath.Join(path, x.Name(), term)
|
||||||
|
if s, err := os.Stat(q); err == nil && s.Mode().IsRegular() {
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ``
|
||||||
|
}
|
||||||
|
|
||||||
|
if td := os.Getenv("TERMINFO"); td != "" {
|
||||||
|
if ans = check_dir(td); ans != "" {
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ans = check_dir(utils.Expanduser("~/.terminfo")); ans != "" {
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
if td := os.Getenv("TERMINFO_DIRS"); td != "" {
|
||||||
|
for _, q := range strings.Split(td, string(os.PathListSeparator)) {
|
||||||
|
if q == "" {
|
||||||
|
q = "/usr/share/terminfo"
|
||||||
|
}
|
||||||
|
if ans = check_dir(q); ans != "" {
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, q := range []string{"/usr/share/terminfo", "/usr/lib/terminfo", "/usr/share/lib/terminfo"} {
|
||||||
|
if ans = check_dir(q); ans != "" {
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func EnsureTerminfoFiles() (terminfo_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, "terminfo")
|
||||||
|
if s, e := os.Stat(q); e == nil && s.IsDir() {
|
||||||
|
return q, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
base := filepath.Join(utils.CacheDir(), "extracted-kti")
|
||||||
|
if err = os.MkdirAll(base, 0o755); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if err = extract_terminfo(base); err != nil {
|
||||||
|
return "", fmt.Errorf("Failed to extract terminfo files with error: %w", err)
|
||||||
|
}
|
||||||
|
return filepath.Join(base, "terminfo"), nil
|
||||||
|
}
|
||||||
|
|
||||||
func EnsureShellIntegrationFilesFor(shell_name string) (shell_integration_dir_for_shell string, err error) {
|
func EnsureShellIntegrationFilesFor(shell_name string) (shell_integration_dir_for_shell string, err error) {
|
||||||
if kid := os.Getenv("KITTY_INSTALLATION_DIR"); kid != "" {
|
if kid := os.Getenv("KITTY_INSTALLATION_DIR"); kid != "" {
|
||||||
if s, e := os.Stat(kid); e == nil && s.IsDir() {
|
if s, e := os.Stat(kid); e == nil && s.IsDir() {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package shell_integration
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"kitty"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -43,7 +44,7 @@ func TestExtractShellIntegration(t *testing.T) {
|
|||||||
if err = extract_terminfo(tdir); err != nil {
|
if err = extract_terminfo(tdir); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(filepath.Join(tdir, "terminfo", "78", "xterm-kitty")); err != nil {
|
if _, err := os.Stat(filepath.Join(tdir, "terminfo", "78", kitty.DefaultTermName)); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user