CLI help output make kitty.conf a clickable URL

This commit is contained in:
Kovid Goyal 2022-08-15 09:44:36 +05:30
parent aaf0dea8dc
commit 46840df1ad
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 132 additions and 6 deletions

View File

@ -1,8 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
import os
import re import re
import shlex import shlex
import socket
import sys import sys
from collections import deque from collections import deque
from typing import ( from typing import (
@ -13,7 +15,8 @@ from typing import (
from .cli_stub import CLIOptions from .cli_stub import CLIOptions
from .conf.utils import resolve_config from .conf.utils import resolve_config
from .constants import ( from .constants import (
appname, clear_handled_signals, defconf, is_macos, str_version, website_url appname, clear_handled_signals, config_dir, defconf, is_macos, str_version,
website_url
) )
from .fast_data_types import wcswidth from .fast_data_types import wcswidth
from .options.types import Options as KittyOpts from .options.types import Options as KittyOpts
@ -161,8 +164,17 @@ def hyperlink_for_url(url: str, text: str) -> str:
return text return text
def hyperlink_for_path(path: str, text: str) -> str:
path = os.path.abspath(path).replace(os.sep, "/")
if os.path.isdir(path):
path += path.rstrip("/") + "/"
return hyperlink_for_url(f'file://{socket.gethostname()}{path}', text)
@role @role
def file(x: str) -> str: def file(x: str) -> str:
if x == 'kitty.conf':
x = hyperlink_for_path(os.path.join(config_dir, x), x)
return italic(x) return italic(x)

View File

@ -3,6 +3,7 @@ package cli
import ( import (
"fmt" "fmt"
"os" "os"
"path/filepath"
"regexp" "regexp"
"strings" "strings"
"syscall" "syscall"
@ -15,6 +16,7 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"kitty" "kitty"
"kitty/tools/utils"
) )
var RootCmd *cobra.Command var RootCmd *cobra.Command
@ -180,11 +182,37 @@ func website_url(doc string) string {
var prettify_pat = regexp.MustCompile(":([a-z]+):`([^`]+)`") var prettify_pat = regexp.MustCompile(":([a-z]+):`([^`]+)`")
var ref_pat = regexp.MustCompile(`\s*<\S+?>`) var ref_pat = regexp.MustCompile(`\s*<\S+?>`)
func is_atty() bool {
return italic_fmt("") != ""
}
func hyperlink_for_path(path string, text string) string {
if !is_atty() {
return text
}
path = strings.ReplaceAll(utils.Abspath(path), string(os.PathSeparator), "/")
fi, err := os.Stat(path)
if err == nil && fi.IsDir() {
path = strings.TrimSuffix(path, "/") + "/"
}
host, err := os.Hostname()
if err != nil {
host = ""
}
return "\x1b]8;;file://" + host + path + "\x1b\\" + text + "\x1b]8;;\x1b\\"
}
func prettify(text string) string { func prettify(text string) string {
return ReplaceAllStringSubmatchFunc(prettify_pat, text, func(groups []string) string { return ReplaceAllStringSubmatchFunc(prettify_pat, text, func(groups []string) string {
val := groups[2] val := groups[2]
switch groups[1] { switch groups[1] {
case "file", "env", "envvar": case "file":
if val == "kitty.conf" && is_atty() {
path := filepath.Join(utils.ConfigDir(), val)
val = hyperlink_for_path(path, val)
}
return italic_fmt(val)
case "env", "envvar":
return italic_fmt(val) return italic_fmt(val)
case "doc": case "doc":
return website_url(val) return website_url(val)
@ -233,7 +261,7 @@ func show_usage(cmd *cobra.Command) error {
use := cmd.Use use := cmd.Use
idx := strings.Index(use, " ") idx := strings.Index(use, " ")
if idx > -1 { if idx > -1 {
use = use[idx + 1:] use = use[idx+1:]
} }
var parent_names []string var parent_names []string
cmd.VisitParents(func(p *cobra.Command) { cmd.VisitParents(func(p *cobra.Command) {
@ -274,7 +302,7 @@ func show_usage(cmd *cobra.Command) error {
defval := "" defval := ""
switch flag.Value.Type() { switch flag.Value.Type() {
default: default:
if (flag.DefValue != "") { if flag.DefValue != "" {
defval = fmt.Sprintf("[=%s]", italic_fmt(flag.DefValue)) defval = fmt.Sprintf("[=%s]", italic_fmt(flag.DefValue))
} }
case "bool": case "bool":

View File

@ -1,7 +1,6 @@
package at package at
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"kitty/tools/cli" "kitty/tools/cli"
@ -14,7 +13,7 @@ func EntryPoint(tool_root *cobra.Command) *cobra.Command {
var root = cli.CreateCommand(&cobra.Command{ var root = cli.CreateCommand(&cobra.Command{
Use: "@ [global options] command [command options] [command args]", Use: "@ [global options] command [command options] [command args]",
Short: "Control kitty remotely", Short: "Control kitty remotely",
Long: "Control kitty by sending it commands. Set the allow_remote_control option in kitty.conf or use a password, for this to work.", Long: "Control kitty by sending it commands. Set the allow_remote_control option in :file:`kitty.conf` or use a password, for this to work.",
}) })
root.Annotations["options_title"] = "Global options" root.Annotations["options_title"] = "Global options"

87
tools/utils/paths.go Normal file
View File

@ -0,0 +1,87 @@
package utils
import (
"os"
"os/user"
"path/filepath"
"runtime"
"strings"
)
func Expanduser(path string) string {
if !strings.HasPrefix(path, "~") {
return path
}
home, err := os.UserHomeDir()
if err != nil {
usr, err := user.Current()
if err == nil {
home = usr.HomeDir
}
}
if err != nil || home == "" {
return path
}
if path == "~" {
return home
}
path = strings.ReplaceAll(path, string(os.PathSeparator), "/")
parts := strings.Split(path, "/")
if parts[0] == "~" {
parts[0] = home
} else {
uname := parts[0][1:]
if uname != "" {
u, err := user.Lookup(uname)
if err == nil && u.HomeDir != "" {
parts[0] = u.HomeDir
}
}
}
return strings.Join(parts, string(os.PathSeparator))
}
func Abspath(path string) string {
q, err := filepath.Abs(path)
if err == nil {
return q
}
return path
}
var config_dir string
func ConfigDir() string {
if config_dir != "" {
return config_dir
}
if os.Getenv("KITTY_CONFIG_DIRECTORY") != "" {
config_dir = Abspath(Expanduser(os.Getenv("KITTY_CONFIG_DIRECTORY")))
} else {
var locations []string
if os.Getenv("XDG_CONFIG_HOME") != "" {
locations = append(locations, os.Getenv("XDG_CACHE_HOME"))
}
locations = append(locations, Expanduser("~/.config"))
if runtime.GOOS == "darwin" {
locations = append(locations, Expanduser("~/Library/Preferences"))
}
for _, loc := range locations {
if loc != "" {
q := filepath.Join(loc, "kitty")
if _, err := os.Stat(filepath.Join(q, "kitty.conf")); err == nil {
config_dir = q
break
}
}
}
for _, loc := range locations {
if loc != "" {
config_dir = filepath.Join(loc, "kitty")
break
}
}
}
return config_dir
}