mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-27 18:51:41 +02:00
choose files: Add a few more output formats
This commit is contained in:
@@ -777,6 +777,20 @@ func (h *Handler) set_state_from_config(conf *Config, opts *Options) (err error)
|
|||||||
var default_cwd string
|
var default_cwd string
|
||||||
var use_light_colors bool
|
var use_light_colors bool
|
||||||
|
|
||||||
|
func quote_if_needed(x string) string {
|
||||||
|
if s, err := shlex.Split(x); len(s) == 1 && err == nil && !strings.Contains(x, "$") {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
return utils.QuoteStringForSH(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func for_shell_relative(x string) string {
|
||||||
|
if rel, is_under, err := utils.RelativeIfUnder(default_cwd, x, false); err == nil && is_under {
|
||||||
|
x = rel
|
||||||
|
}
|
||||||
|
return quote_if_needed(x)
|
||||||
|
}
|
||||||
|
|
||||||
func main(_ *cli.Command, opts *Options, args []string) (rc int, err error) {
|
func main(_ *cli.Command, opts *Options, args []string) (rc int, err error) {
|
||||||
if opts.ClearCache {
|
if opts.ClearCache {
|
||||||
c, err := preview_cache()
|
c, err := preview_cache()
|
||||||
@@ -818,14 +832,21 @@ func main(_ *cli.Command, opts *Options, args []string) (rc int, err error) {
|
|||||||
if tui.RunningAsUI() {
|
if tui.RunningAsUI() {
|
||||||
fmt.Println(tui.KittenOutputSerializer()(payload))
|
fmt.Println(tui.KittenOutputSerializer()(payload))
|
||||||
} else {
|
} else {
|
||||||
m := strings.Join(selections, "\n")
|
var m string
|
||||||
if opts.OutputFormat == "json" {
|
switch opts.OutputFormat {
|
||||||
|
case "shell":
|
||||||
|
m = strings.Join(utils.Map(quote_if_needed, selections), " ")
|
||||||
|
case "shell-relative":
|
||||||
|
m = strings.Join(utils.Map(for_shell_relative, selections), " ")
|
||||||
|
case "text":
|
||||||
|
m = strings.Join(selections, "\n")
|
||||||
|
case "json":
|
||||||
b, _ := json.MarshalIndent(payload, "", " ")
|
b, _ := json.MarshalIndent(payload, "", " ")
|
||||||
m = string(b)
|
m = string(b)
|
||||||
}
|
}
|
||||||
fmt.Print(m)
|
os.Stdout.Write(utils.UnsafeStringToBytes(m))
|
||||||
if opts.WriteOutputTo != "" {
|
if opts.WriteOutputTo != "" {
|
||||||
os.WriteFile(opts.WriteOutputTo, []byte(m), 0600)
|
os.WriteFile(opts.WriteOutputTo, utils.UnsafeStringToBytes(m), 0600)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,6 +150,9 @@ def relative_path_if_possible(path: str, base: str) -> str:
|
|||||||
|
|
||||||
@result_handler(has_ready_notification=True)
|
@result_handler(has_ready_notification=True)
|
||||||
def handle_result(args: list[str], data: dict[str, Any], target_window_id: int, boss: BossType) -> None:
|
def handle_result(args: list[str], data: dict[str, Any], target_window_id: int, boss: BossType) -> None:
|
||||||
|
import shlex
|
||||||
|
|
||||||
|
from kitty.utils import shlex_split
|
||||||
paths: list[str] = data.get('paths', [])
|
paths: list[str] = data.get('paths', [])
|
||||||
if not paths:
|
if not paths:
|
||||||
boss.ring_bell_if_allowed()
|
boss.ring_bell_if_allowed()
|
||||||
@@ -160,6 +163,8 @@ def handle_result(args: list[str], data: dict[str, Any], target_window_id: int,
|
|||||||
cwd = w.cwd_of_child
|
cwd = w.cwd_of_child
|
||||||
if cwd:
|
if cwd:
|
||||||
path = relative_path_if_possible(path, cwd)
|
path = relative_path_if_possible(path, cwd)
|
||||||
|
if w.at_prompt and len(tuple(shlex_split(path))) > 1:
|
||||||
|
path = shlex.quote(path)
|
||||||
w.paste_text(path)
|
w.paste_text(path)
|
||||||
|
|
||||||
|
|
||||||
@@ -219,9 +224,13 @@ Path to a file to which the output is written in addition to STDOUT.
|
|||||||
|
|
||||||
|
|
||||||
--output-format
|
--output-format
|
||||||
choices=text,json
|
choices=text,json,shell,shell-relative
|
||||||
default=text
|
default=text
|
||||||
The format in which to write the output.
|
The format in which to write the output. The :code:`text` format is absolute paths separated by newlines.
|
||||||
|
The :code:`shell` format is quoted absolute paths separated by spaces, quoting is done only if needed. The
|
||||||
|
:code:shell-relative` format is the same as :code:`shell` except it returns paths relative to the starting
|
||||||
|
directory. Note that when invoked from a mapping, this option is ignored,
|
||||||
|
and either text or shell format is used automatically based on whether the cursor is at a shell prompt or not.
|
||||||
|
|
||||||
|
|
||||||
--write-pid-to
|
--write-pid-to
|
||||||
|
|||||||
@@ -330,3 +330,60 @@ func Commonpath(paths ...string) (longest_prefix string) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RelativeIfUnder returns the path to 'target' relative to 'base' if and only if
|
||||||
|
// target is inside base. It returns the relative path, a boolean indicating
|
||||||
|
// whether target is inside base, and an error.
|
||||||
|
//
|
||||||
|
// If resolveSymlinks is true, both base and target are run through filepath.EvalSymlinks
|
||||||
|
// before containment checks. If base == target the function returns "." and true.
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// - This uses filepath.Rel and then checks for leading ".." components to determine
|
||||||
|
// whether the returned relative path escapes the base directory.
|
||||||
|
// - On Windows behaviour is consistent with filepath semantics.
|
||||||
|
func RelativeIfUnder(base, target string, resolveSymlinks bool) (rel string, inside bool, err error) {
|
||||||
|
// Optionally resolve symlinks first
|
||||||
|
if resolveSymlinks {
|
||||||
|
if base, err = filepath.EvalSymlinks(base); err != nil {
|
||||||
|
return "", false, fmt.Errorf("resolving base symlinks: %w", err)
|
||||||
|
}
|
||||||
|
if target, err = filepath.EvalSymlinks(target); err != nil {
|
||||||
|
return "", false, fmt.Errorf("resolving target symlinks: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make absolute and clean
|
||||||
|
if base, err = filepath.Abs(base); err != nil {
|
||||||
|
return "", false, fmt.Errorf("abs base: %w", err)
|
||||||
|
}
|
||||||
|
if target, err = filepath.Abs(target); err != nil {
|
||||||
|
return "", false, fmt.Errorf("abs target: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Windows the volume (drive letter) must match. If they don't, the path is not inside.
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
if !strings.EqualFold(filepath.VolumeName(base), filepath.VolumeName(target)) {
|
||||||
|
return "", false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the relative path from base to target
|
||||||
|
rel, err = filepath.Rel(base, target)
|
||||||
|
if err != nil {
|
||||||
|
return "", false, fmt.Errorf("computing relative path: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If rel begins with ".." (or is ".."), then target is outside base.
|
||||||
|
// Use os.PathSeparator to be portable.
|
||||||
|
up := ".." + string(os.PathSeparator)
|
||||||
|
if rel == ".." || strings.HasPrefix(rel, up) {
|
||||||
|
return "", false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the returned rel is empty (shouldn't normally happen), normalize to "."
|
||||||
|
if rel == "" {
|
||||||
|
rel = "."
|
||||||
|
}
|
||||||
|
return rel, true, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user