From 5bf6870d0fb1548a061b1299ef8a39f9403ec610 Mon Sep 17 00:00:00 2001 From: mazdak Date: Tue, 22 Jul 2025 22:36:01 -0400 Subject: [PATCH] Implemented support for 'Apple Container' as a runtime environment Apple Container is a Docker-like system for managing containers in macOS 26+ Tahoe. Not all Docker features are supported but enough support exists to have Lazydocker function as a frontend. --- .gitignore | 1 + README.md | 35 +- coverage.txt | 1715 ----------------- docs/Config.md | 14 + main.go | 4 +- pkg/app/app.go | 57 +- pkg/app/app_test.go | 214 ++ pkg/cheatsheet/generate.go | 2 +- pkg/commands/apple_container.go | 838 ++++++++ pkg/commands/apple_container_test.go | 334 ++++ pkg/commands/container.go | 63 + pkg/commands/container_runtime.go | 432 +++++ pkg/commands/container_runtime_test.go | 194 ++ pkg/commands/errors.go | 13 +- pkg/commands/features.go | 35 + pkg/commands/gui_adapter.go | 160 ++ pkg/commands/image.go | 26 +- pkg/commands/service.go | 9 +- pkg/commands/volume.go | 7 + pkg/config/app_config.go | 28 +- pkg/config/app_config_test.go | 81 +- pkg/gui/container_logs.go | 49 +- pkg/gui/containers_panel.go | 132 +- pkg/gui/gui.go | 66 +- pkg/gui/gui_test.go | 104 + pkg/gui/images_panel.go | 34 +- pkg/gui/keybindings.go | 33 +- pkg/gui/networks_panel.go | 26 +- pkg/gui/panels/side_list_panel.go | 43 +- pkg/gui/presentation/containers.go | 15 +- pkg/gui/presentation/containers_test.go | 112 ++ pkg/gui/project_panel.go | 107 +- pkg/gui/services_panel.go | 61 +- pkg/gui/views.go | 7 +- pkg/gui/volumes_panel.go | 67 +- vendor/github.com/OpenPeeDeeP/xdg/xdg.go | 2 +- vendor/github.com/OpenPeeDeeP/xdg/xdg_bsd.go | 1 + vendor/github.com/boz/go-throttle/throttle.go | 12 +- .../jibber_jabber/jibber_jabber_unix.go | 1 + .../jibber_jabber/jibber_jabber_windows.go | 1 + .../github.com/davecgh/go-spew/spew/bypass.go | 1 + .../davecgh/go-spew/spew/bypasssafe.go | 1 + .../github.com/davecgh/go-spew/spew/config.go | 30 +- vendor/github.com/davecgh/go-spew/spew/doc.go | 128 +- .../github.com/davecgh/go-spew/spew/dump.go | 18 +- vendor/github.com/fatih/color/doc.go | 133 +- .../httpsnoop/wrap_generated_gteq_1.8.go | 2 + .../httpsnoop/wrap_generated_lt_1.8.go | 2 + vendor/github.com/go-errors/errors/error.go | 44 +- .../go-errors/errors/parse_panic.go | 4 +- vendor/github.com/goccy/go-yaml/yaml.go | 62 +- vendor/github.com/gogo/protobuf/proto/lib.go | 36 +- .../gogo/protobuf/proto/pointer_reflect.go | 1 + .../protobuf/proto/pointer_reflect_gogo.go | 1 + .../gogo/protobuf/proto/pointer_unsafe.go | 1 + .../protobuf/proto/pointer_unsafe_gogo.go | 1 + .../gogo/protobuf/proto/table_unmarshal.go | 14 +- vendor/github.com/gookit/color/color.go | 9 +- vendor/github.com/gookit/color/color_16.go | 37 +- vendor/github.com/gookit/color/color_256.go | 32 +- vendor/github.com/gookit/color/color_rgb.go | 66 +- vendor/github.com/gookit/color/color_tag.go | 28 +- vendor/github.com/gookit/color/convert.go | 44 +- vendor/github.com/gookit/color/detect_env.go | 22 +- .../github.com/gookit/color/detect_nonwin.go | 4 +- .../github.com/gookit/color/detect_windows.go | 28 +- vendor/github.com/gookit/color/printer.go | 5 +- vendor/github.com/gookit/color/style.go | 29 +- vendor/github.com/gookit/color/utils.go | 1 + vendor/github.com/imdario/mergo/doc.go | 27 +- vendor/github.com/integrii/flaggy/flag.go | 5 +- vendor/github.com/jesseduffield/yaml/apic.go | 2 +- .../github.com/jesseduffield/yaml/emitterc.go | 7 +- .../github.com/jesseduffield/yaml/parserc.go | 142 +- .../github.com/jesseduffield/yaml/readerc.go | 2 +- .../github.com/jesseduffield/yaml/resolve.go | 2 +- .../github.com/jesseduffield/yaml/scannerc.go | 34 +- .../github.com/jesseduffield/yaml/sorter.go | 2 +- vendor/github.com/jesseduffield/yaml/yaml.go | 55 +- vendor/github.com/jesseduffield/yaml/yamlh.go | 9 +- .../lucasb-eyer/go-colorful/hsluv.go | 3 +- .../mattn/go-colorable/colorable_appengine.go | 1 + .../mattn/go-colorable/colorable_others.go | 4 +- .../mattn/go-colorable/colorable_windows.go | 4 +- .../github.com/mattn/go-isatty/isatty_bsd.go | 1 + .../mattn/go-isatty/isatty_others.go | 1 + .../mattn/go-isatty/isatty_plan9.go | 1 + .../mattn/go-isatty/isatty_solaris.go | 4 +- .../mattn/go-isatty/isatty_tcgets.go | 1 + .../mattn/go-isatty/isatty_windows.go | 7 +- vendor/github.com/mgutz/str/doc.go | 7 +- .../opencontainers/go-digest/digest.go | 2 +- .../opencontainers/go-digest/doc.go | 11 +- .../github.com/petermattis/goid/goid_gccgo.go | 1 + .../github.com/petermattis/goid/goid_go1.3.go | 1 + .../github.com/petermattis/goid/goid_go1.4.go | 1 + .../petermattis/goid/goid_go1.5_amd64.go | 4 +- .../petermattis/goid/goid_go1.5_arm.go | 4 +- .../github.com/petermattis/goid/goid_slow.go | 1 + .../petermattis/goid/runtime_gccgo_go1.8.go | 1 + .../petermattis/goid/runtime_go1.5.go | 1 + .../petermattis/goid/runtime_go1.6.go | 1 + .../petermattis/goid/runtime_go1.9.go | 1 + vendor/github.com/pkg/errors/errors.go | 74 +- vendor/github.com/pkg/errors/go113.go | 1 + vendor/github.com/pkg/errors/stack.go | 20 +- .../pmezard/go-difflib/difflib/difflib.go | 21 +- .../sasha-s/go-deadlock/deadlock_map.go | 1 + vendor/github.com/sirupsen/logrus/doc.go | 26 +- .../github.com/sirupsen/logrus/formatter.go | 4 +- vendor/github.com/sirupsen/logrus/logger.go | 18 +- .../logrus/terminal_check_appengine.go | 1 + .../sirupsen/logrus/terminal_check_bsd.go | 1 + .../sirupsen/logrus/terminal_check_js.go | 1 + .../logrus/terminal_check_no_terminal.go | 1 + .../logrus/terminal_check_notappengine.go | 1 + .../sirupsen/logrus/terminal_check_unix.go | 1 + .../sirupsen/logrus/terminal_check_windows.go | 1 + vendor/github.com/spkg/bom/discard_go14.go | 1 + vendor/github.com/spkg/bom/discard_go15.go | 1 + .../x/sys/unix/syscall_zos_s390x.go | 8 +- vendor/golang.org/x/xerrors/doc.go | 3 +- vendor/gopkg.in/yaml.v3/apic.go | 8 +- vendor/gopkg.in/yaml.v3/emitterc.go | 9 +- vendor/gopkg.in/yaml.v3/parserc.go | 142 +- vendor/gopkg.in/yaml.v3/readerc.go | 8 +- vendor/gopkg.in/yaml.v3/scannerc.go | 42 +- vendor/gopkg.in/yaml.v3/writerc.go | 8 +- vendor/gopkg.in/yaml.v3/yaml.go | 75 +- vendor/gopkg.in/yaml.v3/yamlh.go | 10 +- vendor/gopkg.in/yaml.v3/yamlprivateh.go | 20 +- 131 files changed, 4119 insertions(+), 2657 deletions(-) delete mode 100644 coverage.txt create mode 100644 pkg/app/app_test.go create mode 100644 pkg/commands/apple_container.go create mode 100644 pkg/commands/apple_container_test.go create mode 100644 pkg/commands/container_runtime.go create mode 100644 pkg/commands/container_runtime_test.go create mode 100644 pkg/commands/features.go create mode 100644 pkg/commands/gui_adapter.go create mode 100644 pkg/gui/gui_test.go create mode 100644 pkg/gui/presentation/containers_test.go diff --git a/.gitignore b/.gitignore index b9f700a9..edae0920 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ TODO.md Lazydocker.code-workspace .vscode .idea +coverage.txt diff --git a/README.md b/README.md index 84f15673..27a04e64 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@

-A simple terminal UI for both docker and docker-compose, written in Go with the [gocui](https://github.com/jroimartin/gocui 'gocui') library. +A simple terminal UI for both docker and docker-compose, written in Go with the [gocui](https://github.com/jroimartin/gocui 'gocui') library. Now with experimental Apple Container support! ![CI](https://github.com/jesseduffield/lazygit/workflows/Continuous%20Integration/badge.svg) [![Go Report Card](https://goreportcard.com/badge/github.com/jesseduffield/lazydocker)](https://goreportcard.com/report/github.com/jesseduffield/lazydocker) @@ -86,9 +86,15 @@ Memorising docker commands is hard. Memorising aliases is slightly less hard. Ke ## Requirements +### Docker Runtime (Default) - Docker >= **1.13** (API >= **1.25**) - Docker-Compose >= **1.23.2** (optional) +### Apple Container Runtime (Experimental) +- macOS 26 beta or later +- Apple Silicon Mac +- Apple Container CLI (`container` command available in PATH) + ## Installation ### Homebrew @@ -255,14 +261,39 @@ You can also use `go run main.go` to compile and run in one go (pun definitely i ## Usage +### Basic Usage + Call `lazydocker` in your terminal. I personally use this a lot so I've made an alias for it like so: -``` +```bash echo "alias lzd='lazydocker'" >> ~/.zshrc ``` (you can substitute .zshrc for whatever rc file you're using) +### Container Runtime Selection + +By default, lazydocker uses Docker. You can specify a different container runtime using the `--runtime` flag: + +```bash +# Use Docker (default) +lazydocker +lazydocker --runtime docker + +# Use Apple Container (requires macOS 26 beta and Apple Silicon) +lazydocker --runtime apple +``` + +### Available Flags + +```bash +lazydocker --help + -c --config Print the current default config + -d --debug Enable debug mode + -f --file Specify alternate compose files + -r --runtime Container runtime to use (docker, apple) +``` + - Basic video tutorial [here](https://youtu.be/NICqQPxwJWw). - List of keybindings [here](/docs/keybindings). diff --git a/coverage.txt b/coverage.txt deleted file mode 100644 index 11ed75c5..00000000 --- a/coverage.txt +++ /dev/null @@ -1,1715 +0,0 @@ - -mode: atomic -mode: atomic -mode: atomic -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:341.36,343.16 2 4 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:343.16,344.13 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:347.2,462.3 1 4 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:479.157,481.16 2 4 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:481.16,483.3 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:485.2,486.16 2 4 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:486.16,488.3 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:491.2,491.27 1 4 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:491.27,493.3 1 2 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:495.2,507.23 2 4 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:510.67,512.24 2 8 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:512.24,514.3 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:515.2,516.32 2 8 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:519.43,521.67 2 4 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:521.67,523.3 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:524.2,525.24 2 4 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:528.64,532.16 3 4 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:532.16,534.3 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:536.2,536.20 1 4 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:539.72,543.2 2 4 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:545.78,548.45 2 6 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:548.45,549.25 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:549.25,551.18 2 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:551.18,553.5 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:554.4,554.16 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:555.9,557.4 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:560.2,561.16 2 6 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:561.16,563.3 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:565.2,565.54 1 6 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:565.54,567.3 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:569.2,569.18 1 6 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:576.83,578.16 2 2 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:578.16,580.3 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:582.2,582.49 1 2 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:582.49,584.3 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:586.2,587.16 2 2 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:587.16,589.3 1 0 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:591.2,591.49 1 2 -github.com/jesseduffield/lazydocker/pkg/config/app_config.go:595.45,597.2 1 4 -github.com/jesseduffield/lazydocker/pkg/config/config_default_platform.go:7.42,12.2 1 4 -mode: atomic -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:29.50,31.54 2 3 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:31.54,33.3 1 2 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:34.2,35.31 2 1 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:35.31,37.3 1 1 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:38.2,38.14 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:42.50,44.33 2 8 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:44.33,46.3 1 1 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:47.2,47.61 1 7 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:52.71,54.37 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:54.37,56.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:57.2,58.41 2 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:67.43,68.46 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:68.46,70.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:71.2,73.36 3 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:73.36,78.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:79.2,79.38 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:79.38,84.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:85.2,85.38 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:85.38,90.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:91.2,91.38 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:91.38,96.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:97.2,97.30 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:102.79,105.2 2 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:109.66,111.2 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:114.44,118.2 3 4 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:121.22,127.2 5 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:130.79,131.36 1 7 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:131.36,133.3 1 5 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:134.2,134.12 1 7 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:138.24,139.11 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:139.11,141.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:142.2,142.10 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:146.59,147.28 1 3 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:147.28,149.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:150.2,150.41 1 3 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:150.41,152.3 1 1 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:154.2,157.54 3 2 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:161.36,164.2 2 16 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:166.50,167.31 1 5 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:167.31,169.3 1 2 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:170.2,171.27 2 3 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:171.27,172.40 1 4 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:172.40,174.43 2 8 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:174.43,176.5 1 4 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:179.2,179.18 1 3 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:182.81,184.43 2 3 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:184.43,185.28 1 6 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:185.28,186.12 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:188.3,188.38 1 6 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:188.38,190.4 1 6 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:191.3,191.57 1 6 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:193.2,193.29 1 3 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:198.57,199.39 1 5 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:199.39,200.43 1 10 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:200.43,202.4 1 2 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:204.2,204.13 1 3 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:207.38,210.29 3 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:210.29,211.26 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:211.26,213.4 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:213.9,215.22 2 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:215.22,217.5 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:218.4,218.14 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:221.2,221.16 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:224.39,227.29 3 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:227.29,228.26 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:228.26,230.4 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:230.9,232.22 2 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:232.22,234.5 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:235.4,235.14 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:238.2,238.16 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:241.59,245.2 3 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:248.52,264.13 3 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:264.13,266.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:267.2,267.27 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:271.52,286.13 3 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:286.13,288.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:289.2,289.22 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:293.38,295.29 2 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:295.29,297.22 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:297.22,299.4 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:301.2,301.33 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:305.65,307.2 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:310.57,311.17 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:311.17,313.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:315.2,318.21 3 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:318.21,320.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:321.2,322.27 2 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:322.27,324.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:326.2,326.15 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:331.34,334.24 3 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:334.24,336.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:337.2,337.19 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:340.43,342.28 2 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:342.28,344.17 2 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:344.17,346.4 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:348.2,348.19 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:348.19,350.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:351.2,351.12 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:354.49,355.22 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:355.22,357.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:357.8,359.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:362.37,363.32 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:363.32,365.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:367.2,367.17 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:367.17,369.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:371.2,371.29 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:371.29,372.15 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:373.117,374.12 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:375.11,376.16 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:380.2,380.13 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:384.40,386.2 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:390.56,392.2 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:394.73,397.16 2 3 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:397.16,399.3 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:400.2,400.16 1 3 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:401.14,402.23 1 1 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:403.14,406.63 2 1 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:406.63,408.4 1 0 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:409.3,409.34 1 1 -github.com/jesseduffield/lazydocker/pkg/utils/utils.go:410.10,411.86 1 1 -mode: atomic -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:20.51,22.36 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:22.36,23.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:23.26,25.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:27.2,27.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:30.55,38.2 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:40.50,41.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:41.26,43.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:44.2,45.39 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:45.39,47.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:48.2,48.23 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:52.70,53.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:53.12,56.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:56.16,58.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:60.3,60.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:60.13,63.23 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:63.23,65.24 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:65.24,67.6 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:68.5,68.75 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:68.75,70.6 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:74.3,74.29 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:74.29,75.42 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:75.42,77.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/app_status_manager.go:81.2,81.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:16.110,20.52 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:20.52,22.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:24.2,28.18 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:28.18,30.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:32.2,34.21 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:34.21,36.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:38.2,64.60 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:67.51,76.68 5 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:76.68,79.3 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:79.8,80.42 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:80.42,82.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:82.9,82.49 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:82.49,84.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:87.2,87.45 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:90.95,93.24 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:93.24,100.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:102.2,102.29 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:102.29,113.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:115.2,129.15 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:132.42,133.100 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:133.100,135.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:137.2,137.83 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:137.83,139.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:142.75,146.80 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:146.80,147.55 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:147.55,148.31 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:148.31,153.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:153.10,158.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:161.3,161.76 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:161.76,163.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:165.8,165.25 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:165.25,167.66 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:167.66,168.59 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:168.59,173.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:175.4,175.21 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:178.3,183.76 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:183.76,185.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:186.8,188.19 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:188.19,190.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:192.3,192.62 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:192.62,193.31 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:193.31,198.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:198.10,203.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:206.3,206.76 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/arrangement.go:206.76,208.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:16.127,17.49 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:17.49,18.55 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:18.55,20.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:22.3,22.22 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:22.22,23.41 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:23.41,25.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:28.3,28.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:32.49,33.42 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:33.42,35.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:36.2,38.12 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:41.76,45.10 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:45.10,46.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:46.30,48.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:49.8,51.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:52.2,52.18 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:55.95,63.2 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:65.106,68.16 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:68.16,70.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:71.2,72.54 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:75.86,79.16 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:79.16,81.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:82.2,83.15 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:83.15,85.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:86.2,88.40 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:88.40,90.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:91.2,91.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:94.35,97.2 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:102.133,104.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:106.142,108.40 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:108.40,109.46 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:109.46,110.56 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:110.56,112.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:114.3,115.17 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:115.17,117.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:118.3,119.69 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:119.69,121.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:122.3,122.59 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:124.2,124.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:127.116,129.135 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:129.135,131.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:132.2,132.124 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:132.124,134.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:136.2,136.131 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:136.131,138.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:139.2,139.122 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:139.122,141.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:143.2,143.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:146.56,150.2 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/confirmation_panel.go:152.51,158.2 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:19.89,21.64 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:21.64,23.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:26.41,26.64 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:32.127,34.15 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:34.15,36.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:38.2,40.73 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:40.73,42.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:46.2,48.6 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:48.6,49.10 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:50.21,51.10 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:52.19,54.18 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:54.18,58.5 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:59.4,59.28 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:59.28,61.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:66.67,71.12 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:71.12,75.3 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:77.2,77.40 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:77.40,80.3 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:82.2,82.15 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:82.15,83.40 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:83.40,85.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:88.2,88.74 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:88.74,91.3 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:93.2,93.22 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:96.34,97.50 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:97.50,101.41 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:101.41,103.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:107.112,116.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:116.16,118.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:120.2,120.63 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:120.63,122.17 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:122.17,124.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:125.8,127.17 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:127.17,129.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/container_logs.go:132.2,132.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:22.81,24.68 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:24.68,25.54 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:25.54,27.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:29.3,29.98 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:29.98,31.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:34.2,36.62 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:36.62,64.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:65.71,72.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:82.65,84.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:85.52,89.89 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:89.89,91.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:93.4,93.80 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:93.80,95.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:97.4,97.15 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:109.89,110.16 1 7 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:110.16,112.3 1 3 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:114.2,116.29 3 4 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:116.29,118.3 1 1 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:120.2,120.80 1 3 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:123.82,124.53 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:124.53,124.91 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:127.68,128.32 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:128.32,130.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:132.2,132.44 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:132.44,134.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:136.2,136.90 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:136.90,140.24 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:140.24,142.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:143.3,146.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:149.2,150.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:150.16,153.3 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:155.2,155.15 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:158.85,159.53 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:159.53,159.97 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:162.74,163.32 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:163.32,165.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:167.2,177.39 10 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:177.39,179.50 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:179.50,180.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:180.30,182.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:182.10,184.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:186.8,188.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:190.2,191.54 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:191.54,193.61 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:193.61,194.27 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:194.27,196.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:198.8,200.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:202.2,203.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:203.16,205.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:207.2,209.15 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:212.84,214.64 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:214.64,216.18 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:216.18,218.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:220.4,220.36 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:223.41,223.64 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:229.82,231.64 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:231.64,233.18 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:233.18,235.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:237.4,237.36 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:240.41,240.64 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:246.54,247.33 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:247.33,250.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:253.2,260.16 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:260.16,262.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:264.2,268.23 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:268.23,269.63 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:269.63,270.40 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:270.40,271.37 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:271.37,272.11 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:274.5,275.34 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:280.2,280.42 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:283.53,284.46 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:284.46,285.60 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:285.60,287.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:290.2,290.61 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:290.61,292.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:294.2,294.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:297.80,301.2 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:303.79,305.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:305.16,307.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:309.2,309.82 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:309.82,310.68 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:310.68,311.58 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:311.58,312.63 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:312.63,313.132 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:313.132,314.72 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:314.72,317.8 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:320.5,320.45 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:322.4,322.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:326.2,329.31 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:329.31,329.95 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:333.31,333.114 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:337.2,340.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:343.69,344.72 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:344.72,345.37 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:345.37,347.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:347.9,349.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:351.3,351.17 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:351.17,353.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:355.3,355.44 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:359.73,361.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:361.16,363.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:365.2,365.38 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:368.72,370.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:370.16,372.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:374.2,374.115 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:374.115,375.68 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:375.68,376.43 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:376.43,378.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:380.4,380.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:385.75,387.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:387.16,389.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:391.2,391.69 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:391.69,392.45 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:392.45,394.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:396.3,396.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:400.74,402.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:402.16,404.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:406.2,407.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:407.16,409.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:411.2,411.29 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:414.47,415.124 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:415.124,416.67 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:416.67,418.18 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:418.18,420.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:421.4,421.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:426.76,428.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:428.16,430.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:432.2,434.12 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:437.78,439.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:439.16,441.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:443.2,443.42 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:446.73,456.2 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:458.82,460.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:460.16,462.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:464.2,470.67 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:473.46,474.123 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:474.123,475.68 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:475.68,476.71 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:476.71,477.44 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:477.44,479.6 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:482.4,482.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:487.48,488.125 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:488.125,489.68 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:489.68,490.71 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:490.71,491.93 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:491.93,493.6 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:496.4,496.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:501.80,521.2 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:524.89,526.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:526.16,528.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:530.2,530.46 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:533.77,535.41 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:535.41,537.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:539.2,540.19 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:540.19,542.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:543.2,544.21 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:544.21,546.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/containers_panel.go:547.2,548.37 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:12.154,13.96 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:13.96,16.27 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:16.27,17.39 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:17.39,19.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:21.4,22.21 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:22.21,24.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:27.4,27.22 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:27.22,29.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:31.4,31.61 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:31.61,32.69 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:32.69,34.6 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:35.5,35.15 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:39.3,45.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:48.2,51.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:54.124,56.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/custom_commands.go:58.122,60.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:9.42,11.9 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:11.9,13.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:15.2,15.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:15.30,17.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:19.2,22.42 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:25.55,29.2 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:31.169,32.78 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:32.78,34.14 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:34.14,35.73 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:35.73,37.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:39.3,39.17 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:43.44,44.42 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:44.42,46.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:48.2,48.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:51.37,58.18 6 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:58.18,60.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:62.2,64.29 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:68.38,69.35 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:69.35,70.43 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:70.43,72.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:75.2,75.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/filtering.go:78.39,80.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:8.53,9.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:9.14,11.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:13.2,14.8 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:14.8,16.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:18.2,18.18 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:19.22,20.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:21.14,23.13 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:24.16,25.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:26.10,27.59 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:32.56,37.2 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:39.59,43.64 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:43.64,45.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:47.2,49.49 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:49.49,51.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:53.2,55.106 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:55.106,56.43 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:56.43,58.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:62.2,62.40 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:62.40,64.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:66.2,66.36 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:69.37,73.35 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:73.35,75.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:77.2,79.16 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:79.16,81.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:83.2,83.41 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:86.55,90.89 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:90.89,92.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:96.39,99.22 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:99.22,100.90 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:100.90,102.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:106.2,106.44 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:106.44,108.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:111.2,111.89 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:111.89,113.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:115.2,115.57 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:119.48,123.53 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:123.53,124.65 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:124.65,126.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:129.2,129.39 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:132.46,137.39 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:137.39,140.49 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:140.49,142.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/focus.go:145.2,145.39 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gocui.go:25.52,26.32 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gocui.go:26.32,29.3 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gocui.go:31.2,32.13 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gocui.go:32.13,34.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gocui.go:35.2,35.27 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gocui.go:39.51,41.27 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gocui.go:41.27,43.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gocui.go:44.2,44.18 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:118.189,147.2 5 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:149.45,157.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:159.72,161.12 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:161.12,164.22 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:164.22,165.34 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:165.34,167.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:169.4,169.18 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:175.29,180.16 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:180.16,182.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:183.2,186.50 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:186.50,188.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:190.2,194.65 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:194.65,196.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:198.2,198.45 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:198.45,200.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:202.2,205.12 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:205.12,206.34 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:206.34,207.18 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:207.18,208.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:210.4,210.58 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:210.58,213.13 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:215.4,215.41 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:219.2,221.45 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:221.45,223.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:224.2,224.52 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:224.52,226.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:229.2,231.42 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:231.42,233.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:235.2,235.32 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:235.32,238.17 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:238.17,240.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:242.3,242.47 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:242.47,244.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:247.2,253.12 5 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:253.12,261.3 5 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:263.2,264.26 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:264.26,266.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:267.2,267.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:270.29,280.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:282.48,284.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:286.27,287.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:287.12,288.46 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:288.46,290.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:292.2,292.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:292.12,293.60 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:293.60,295.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:297.2,297.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:297.12,298.45 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:298.45,300.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:302.2,302.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:302.12,303.46 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:303.46,305.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:307.2,307.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:307.12,308.44 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:308.44,310.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:314.70,317.29 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:317.29,318.17 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:318.17,320.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:321.3,322.30 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:325.1,326.6 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:326.6,329.21 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:329.21,330.11 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:331.22,332.11 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:333.26,335.19 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:336.12,345.19 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:349.3,349.7 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:349.7,350.11 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:351.22,352.11 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:353.34,359.62 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:360.26,362.19 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:369.47,371.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:373.38,375.21 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:375.21,377.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:378.2,378.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:378.26,379.41 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:379.41,381.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:383.2,383.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:386.57,387.41 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:387.41,388.102 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:388.102,390.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:392.2,392.22 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:397.32,398.29 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:398.29,400.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:402.2,402.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:405.65,406.18 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:406.18,408.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:410.2,411.29 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:411.29,413.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:414.2,414.76 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:417.49,419.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:419.16,421.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:423.2,423.31 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:426.49,427.57 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:427.57,429.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:430.2,430.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:433.72,434.98 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:434.98,437.3 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:440.48,441.44 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:441.44,443.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:445.2,446.13 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:449.51,450.46 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:450.46,452.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:453.2,453.21 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:456.42,458.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:460.40,461.38 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:461.38,461.52 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:464.60,469.6 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:469.6,470.10 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:471.21,472.10 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:473.19,474.71 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:474.71,475.35 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:475.35,477.6 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:486.32,488.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:488.16,489.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:491.2,493.45 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:493.45,494.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/gui.go:497.2,497.17 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:21.73,26.58 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:26.58,34.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:35.63,37.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:45.57,46.50 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:46.50,48.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:50.4,50.50 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:50.50,52.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:54.4,54.24 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:54.24,56.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:58.4,58.22 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:58.22,60.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:62.4,62.22 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:68.77,70.32 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:70.32,70.68 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:76.62,86.16 9 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:86.16,88.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:90.2,92.15 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:95.38,96.49 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:96.49,98.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:100.2,100.41 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:103.44,105.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:105.16,107.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:109.2,111.12 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:114.55,115.79 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:115.79,117.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:119.2,119.32 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:122.75,130.16 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:130.16,132.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:134.2,160.86 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:160.86,166.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:166.26,167.62 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:167.62,169.6 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:171.5,171.15 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:176.2,179.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:182.43,183.120 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:183.120,184.67 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:184.67,186.18 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:186.18,188.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:189.4,189.29 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:194.78,196.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:196.16,198.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:200.2,206.67 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/images_panel.go:209.76,221.2 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:21.35,24.22 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:25.12,26.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:27.17,28.31 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:32.2,32.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:33.10,34.15 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:35.10,36.17 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:37.10,38.17 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:39.13,40.15 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:41.13,42.15 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:43.13,44.15 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:45.13,46.15 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:47.13,48.16 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:49.13,50.16 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:53.2,53.31 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:57.52,514.44 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:514.44,523.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:525.2,525.112 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:525.112,535.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:537.2,537.44 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:537.44,539.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:541.2,543.44 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:543.44,567.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:569.2,569.44 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:569.44,570.32 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:570.32,578.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:581.2,581.17 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:584.49,587.35 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:587.35,588.107 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:588.107,590.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:593.2,593.73 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:593.73,595.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:597.2,597.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:600.73,601.49 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/keybindings.go:601.49,603.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:10.59,12.34 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:12.34,14.45 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:14.45,16.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:18.3,18.67 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:18.67,22.4 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:23.3,23.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:27.39,29.37 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:29.37,31.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:32.2,32.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:35.65,36.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:36.14,38.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:40.2,40.39 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:40.39,42.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:45.2,47.40 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:50.40,51.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:51.14,53.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:55.2,57.42 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:61.44,69.89 5 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:69.89,73.17 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:73.17,75.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:77.3,77.10 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:77.10,85.4 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:87.3,88.17 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:88.17,90.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:91.3,101.19 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:104.2,104.57 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:104.57,106.58 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:106.58,108.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:115.2,115.39 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:118.52,119.17 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:119.17,121.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:123.2,124.8 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:124.8,126.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/layout.go:129.67,133.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:9.38,15.2 5 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:17.40,23.49 5 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:23.49,26.3 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:28.2,29.36 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:29.36,31.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:33.2,33.74 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:36.67,42.2 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:44.68,50.30 5 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:50.30,51.43 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:51.43,53.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:56.2,57.43 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:57.43,59.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:61.2,61.74 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:64.67,67.2 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:69.66,74.2 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:76.52,81.9 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:81.9,83.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:85.2,86.40 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:89.68,94.2 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:96.67,99.2 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:101.41,102.29 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:102.29,104.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:106.2,108.34 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:108.34,110.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/main_panel.go:112.2,112.40 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:16.71,27.28 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:27.28,29.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:38.61,39.46 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:39.46,41.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:43.2,43.29 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:43.29,45.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:47.2,47.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:50.41,52.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:52.16,54.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:56.2,56.42 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:59.52,60.22 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:60.22,64.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:64.26,66.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:70.2,72.34 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:72.34,73.31 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:73.31,75.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:77.3,77.21 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:77.21,79.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:81.3,81.67 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:84.2,84.34 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:84.34,85.45 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:85.45,89.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:92.2,95.55 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:95.55,97.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:99.2,102.40 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:107.43,114.2 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:116.41,121.47 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:121.47,122.43 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:122.43,124.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:129.3,129.44 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/menu_panel.go:132.2,132.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:18.77,21.60 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:21.60,29.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:30.67,32.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:43.61,45.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:50.79,51.53 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:51.53,51.93 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:54.68,67.41 12 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:67.41,69.48 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:69.48,71.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:72.8,74.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:76.2,80.15 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:83.40,84.51 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:84.51,86.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:88.2,88.43 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:91.46,93.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:93.16,95.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:97.2,99.12 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:102.77,104.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:104.16,106.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:108.2,120.88 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:120.88,123.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:123.26,124.70 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:124.70,125.45 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:125.45,127.7 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:128.6,128.16 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:134.2,137.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:140.45,141.122 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:141.122,142.67 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:142.67,144.18 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:144.18,146.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:147.4,147.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:152.80,154.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:154.16,156.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:158.2,164.67 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/networks_panel.go:167.78,179.2 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:10.55,15.35 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:15.35,16.58 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:16.58,17.28 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:18.12,19.53 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:20.18,21.51 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:27.2,27.25 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:27.25,29.36 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:29.36,30.59 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:30.59,31.48 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:31.48,33.47 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:33.47,34.50 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:34.50,35.18 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:38.6,38.52 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:46.2,47.49 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:50.76,51.32 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:51.32,53.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:55.2,55.88 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:55.88,58.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:58.26,59.27 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:59.27,61.6 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:63.5,63.33 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/options_menu_panel.go:68.2,72.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels.go:5.45,7.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:22.76,25.60 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:25.60,26.49 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:26.49,44.6 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:46.5,52.6 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:54.67,56.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:66.61,68.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:75.40,78.2 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:80.41,82.46 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:82.46,83.66 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:83.66,85.53 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:85.53,87.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:91.2,91.20 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:94.74,95.53 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:95.53,95.80 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:98.37,113.2 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:115.74,119.35 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:119.35,135.14 7 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:135.14,137.51 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:137.51,139.6 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:142.4,142.18 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:147.86,148.53 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:148.53,150.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:153.69,155.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:157.69,159.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:161.31,172.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:175.70,177.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:177.16,179.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/project_panel.go:181.2,181.29 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:20.77,23.60 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:23.60,51.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:52.67,53.33 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:53.33,55.6 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:56.5,56.107 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:66.61,67.48 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:67.48,69.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:71.4,71.48 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:71.48,73.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:75.4,75.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:78.21,80.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:84.88,85.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:85.30,86.54 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:86.54,86.83 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:89.2,89.53 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:92.85,93.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:93.30,94.54 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:94.54,94.83 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:97.2,97.50 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:100.78,101.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:101.30,102.54 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:102.54,102.83 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:105.2,105.52 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:108.76,110.64 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:110.64,112.18 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:112.18,114.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:116.4,116.36 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:119.41,119.64 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:125.77,126.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:126.30,127.54 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:127.54,127.93 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:130.2,130.57 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:139.54,141.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:143.76,145.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:145.16,147.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:149.2,162.82 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:162.82,165.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:165.26,166.70 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:166.70,167.69 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:167.69,169.7 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:171.6,171.16 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:177.2,180.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:183.71,185.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:185.16,187.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:188.2,188.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:188.30,190.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:192.2,192.46 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:195.70,197.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:197.16,199.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:201.2,201.113 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:201.113,202.68 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:202.68,203.41 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:203.41,205.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:207.4,207.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:212.68,214.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:214.16,216.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:218.2,218.72 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:218.72,219.38 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:219.38,221.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:223.3,223.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:227.73,229.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:229.16,231.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:233.2,233.69 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:233.69,234.43 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:234.43,236.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:238.3,238.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:242.71,244.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:244.16,246.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:248.2,248.67 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:248.67,249.41 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:249.41,251.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:253.3,253.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:257.72,259.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:259.16,261.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:263.2,263.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:263.30,265.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:267.2,268.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:268.16,270.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:272.2,272.29 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:275.82,277.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:277.16,279.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:281.2,282.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:282.16,284.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:286.2,286.29 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:289.68,290.118 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:290.118,296.73 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:296.73,297.59 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:297.59,299.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:300.4,300.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:305.70,320.26 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:320.26,321.69 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:321.69,322.66 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:322.66,324.7 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:325.6,325.16 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:332.26,333.69 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:333.69,334.77 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:334.77,336.7 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:337.6,337.16 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:343.2,343.82 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:343.82,348.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:350.2,353.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:356.77,358.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:358.16,360.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:362.2,379.26 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:379.26,380.72 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:380.72,381.46 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:381.46,383.7 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:384.6,384.16 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:394.26,395.72 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:395.72,396.70 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:396.70,398.7 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:399.6,399.16 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:409.26,411.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:415.2,415.82 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:415.82,420.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:422.2,425.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:428.80,430.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:430.16,432.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:434.2,444.44 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:444.44,445.33 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:445.33,447.14 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:449.3,449.48 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:449.48,450.35 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:450.35,453.15 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:458.2,458.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:458.30,460.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:462.2,462.67 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:465.78,470.2 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:472.76,474.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:474.16,476.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:478.2,479.22 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:479.22,481.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:483.2,483.42 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:486.87,488.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:488.16,490.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:492.2,493.22 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:493.22,495.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/services_panel.go:497.2,497.46 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/subprocess.go:15.52,19.40 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/subprocess.go:19.40,21.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/subprocess.go:23.2,27.39 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/subprocess.go:27.39,29.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/subprocess.go:31.2,33.12 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/subprocess.go:36.43,44.12 6 0 -github.com/jesseduffield/lazydocker/pkg/gui/subprocess.go:44.12,48.49 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/subprocess.go:48.49,50.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/subprocess.go:53.2,55.34 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/subprocess.go:55.34,59.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/subprocess.go:61.2,65.22 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:10.62,12.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:34.79,38.35 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:38.35,40.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:43.2,43.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:47.84,53.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:55.55,56.35 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:56.35,62.3 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:68.67,71.36 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:71.36,72.25 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:72.25,74.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:75.3,79.7 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:79.7,80.11 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:81.25,83.11 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:84.22,86.11 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:87.22,89.34 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/tasks_adapter.go:94.2,100.30 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/theme.go:8.60,10.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/theme.go:13.40,19.2 5 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:15.61,18.65 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:18.65,20.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:20.8,22.32 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:22.32,23.36 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:23.36,25.10 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:27.4,27.33 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:27.33,30.5 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:33.2,34.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:34.16,35.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:37.2,38.37 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:41.65,44.46 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:44.46,46.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:46.8,48.32 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:48.32,49.36 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:49.36,51.10 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:53.4,53.33 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:53.33,56.5 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:59.2,60.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:60.16,61.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:63.2,64.37 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:67.33,70.2 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:74.88,75.44 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:75.44,77.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:78.2,89.29 9 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:89.29,91.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:91.8,91.34 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:91.34,93.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:95.2,95.29 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:95.29,98.3 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:100.2,100.22 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:100.22,102.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:104.2,105.22 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:105.22,107.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:110.69,112.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:114.44,117.2 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:119.46,122.2 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:124.63,128.2 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:131.70,132.34 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:132.34,134.17 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:134.17,136.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:137.3,137.43 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:137.43,139.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:140.3,140.43 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:140.43,142.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:143.3,143.34 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:145.2,145.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:148.44,150.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:153.46,155.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:158.52,159.38 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:159.38,161.17 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:161.17,163.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:164.3,164.34 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:168.73,170.43 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:170.43,172.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:173.2,174.41 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:177.70,179.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:181.43,183.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:185.54,187.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:189.42,192.24 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:192.24,194.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:195.2,195.27 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:198.61,200.32 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:200.32,202.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:203.2,203.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:206.55,212.54 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:212.54,214.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:215.2,216.12 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:219.44,221.28 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:222.14,223.33 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:224.22,225.41 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:227.2,227.34 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:230.52,232.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:234.42,236.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:238.33,243.2 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:245.111,246.65 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:246.65,248.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:249.2,249.76 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:252.137,253.72 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:253.72,255.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:257.2,262.25 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:262.25,264.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:266.2,266.35 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:266.35,268.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:270.2,272.39 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:272.39,273.44 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:273.44,275.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:278.2,278.31 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:281.40,282.37 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:282.37,286.3 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:288.2,290.12 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:293.40,294.37 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:294.37,298.3 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:300.2,302.12 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:305.93,306.25 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:306.25,307.21 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:307.21,308.22 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:308.22,310.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:311.4,311.18 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:314.2,314.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:317.93,318.25 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:318.25,319.21 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:319.21,320.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:320.13,322.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:323.4,323.24 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:326.2,326.22 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:329.43,331.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:333.66,336.48 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:336.48,337.45 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:337.45,339.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:342.2,342.19 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:346.66,349.48 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:349.48,350.45 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:350.45,352.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:355.2,355.19 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:358.57,367.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:369.57,371.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/view_helpers.go:373.54,375.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:19.29,20.27 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:20.27,23.3 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:25.2,25.24 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:65.61,92.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:94.40,96.56 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:96.56,98.58 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:98.58,100.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:101.3,101.50 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:104.2,118.94 10 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:118.94,120.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:120.8,122.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:124.2,164.12 31 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:167.47,168.92 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:168.92,170.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:172.2,174.12 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:177.48,179.18 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:179.18,181.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:183.2,184.24 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:184.24,186.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:188.2,189.38 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:192.43,194.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:197.52,198.102 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:198.102,200.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:202.2,202.75 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/views.go:202.75,204.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:18.75,21.59 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:21.59,29.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:30.65,32.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:43.59,44.61 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:44.61,46.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:47.4,47.61 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:47.61,49.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:50.4,50.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:56.76,57.53 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:57.53,57.91 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:60.65,71.33 10 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:71.33,73.42 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:73.42,75.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:76.8,78.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:80.2,80.36 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:80.36,83.3 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:85.2,85.15 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:88.39,89.50 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:89.50,91.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:93.2,93.42 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:96.45,98.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:98.16,100.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:102.2,104.12 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:107.76,109.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:109.16,111.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:113.2,132.87 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:132.87,135.26 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:135.26,136.70 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:136.70,137.56 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:137.56,139.7 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:140.6,140.16 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:146.2,149.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:152.44,153.121 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:153.121,154.67 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:154.67,156.18 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:156.18,158.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:159.4,159.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:164.79,166.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:166.16,168.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:170.2,176.67 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/volumes_panel.go:179.77,191.2 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/window.go:10.50,12.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/window.go:14.48,16.2 1 0 -mode: atomic -mode: atomic -github.com/jesseduffield/lazydocker/pkg/gui/panels/context_state.go:33.58,34.71 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/context_state.go:34.71,36.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/context_state.go:39.66,41.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/context_state.go:43.61,45.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/context_state.go:47.50,50.20 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/context_state.go:50.20,52.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/context_state.go:54.2,54.53 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/context_state.go:57.50,60.20 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/context_state.go:60.20,62.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/context_state.go:64.2,64.65 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/context_state.go:67.57,69.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:16.55,18.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:20.50,26.30 5 2 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:26.30,28.3 1 4 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:31.63,36.37 4 2 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:36.37,37.22 1 6 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:37.22,39.4 1 3 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:43.57,47.17 3 2 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:47.17,49.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:51.2,51.47 1 2 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:51.47,53.3 1 5 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:56.47,61.2 3 3 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:63.58,67.45 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:67.45,70.3 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:72.2,72.49 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:76.40,81.2 3 2 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:83.51,87.37 3 3 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:87.37,88.35 1 4 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:88.35,90.4 1 2 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:92.2,92.11 1 1 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:95.45,100.37 4 2 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:100.37,102.3 1 4 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:103.2,103.15 1 2 -github.com/jesseduffield/lazydocker/pkg/gui/panels/filtered_list.go:106.48,111.2 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/list_panel.go:14.57,16.25 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/list_panel.go:16.25,18.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/list_panel.go:20.2,20.33 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/list_panel.go:23.50,26.33 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/list_panel.go:26.33,28.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/list_panel.go:32.55,34.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/list_panel.go:36.44,38.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/list_panel.go:40.44,42.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:80.51,85.95 4 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:85.95,87.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:89.2,89.25 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:89.25,91.17 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:91.17,93.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:96.2,96.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:99.53,101.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:103.52,105.16 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:105.16,106.41 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:106.41,108.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:110.3,110.32 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:110.32,111.53 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:111.53,111.83 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:114.3,114.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:117.2,119.33 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:122.59,123.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:123.30,125.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:127.2,128.34 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:128.34,130.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:132.2,138.33 5 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:141.60,145.9 3 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:145.9,148.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:150.2,150.18 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:153.54,157.2 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:159.54,163.2 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:165.57,166.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:166.30,168.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:170.2,172.28 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:175.57,176.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:176.30,178.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:180.2,182.28 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:185.41,187.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:189.51,192.2 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:194.47,197.48 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:197.48,198.47 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:198.47,200.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:202.3,202.67 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:202.67,203.78 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:203.78,205.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:206.6,208.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:210.3,210.25 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:210.25,211.78 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:211.78,213.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:216.3,216.14 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:219.2,221.29 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:224.52,227.31 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:227.31,229.74 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:229.74,231.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:232.3,233.17 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:233.17,235.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:236.3,238.29 2 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:238.29,239.44 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:239.44,241.5 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:244.3,244.40 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:244.40,246.4 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:247.3,247.13 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:250.2,250.12 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:253.58,254.30 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:254.30,256.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:258.2,258.42 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:261.55,263.2 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:265.47,266.22 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:266.22,268.3 1 0 -github.com/jesseduffield/lazydocker/pkg/gui/panels/side_list_panel.go:270.2,270.20 1 0 -mode: atomic -mode: atomic -mode: atomic -github.com/jesseduffield/lazydocker/pkg/commands/container.go:46.78,48.86 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:48.86,49.100 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:49.100,55.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:56.3,56.13 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:59.2,59.12 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:63.34,66.2 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:69.35,72.2 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:75.37,78.2 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:81.37,84.2 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:87.49,88.24 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:88.24,90.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:93.2,93.33 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:93.33,95.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:97.2,97.35 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:97.35,99.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:101.2,104.17 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:108.84,110.16 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:110.16,112.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:115.2,115.27 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:115.27,117.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:119.2,119.53 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:123.49,126.2 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:129.66,131.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:134.68,136.16 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:136.16,138.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:140.2,140.82 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container.go:144.42,146.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:138.68,143.23 4 1 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:143.23,145.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:146.2,146.14 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:150.66,152.23 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:152.23,154.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:155.2,155.14 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:158.82,164.2 4 0 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:167.64,168.22 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:168.22,170.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:172.2,172.37 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:172.37,173.48 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:173.48,176.4 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:180.59,184.23 4 0 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:184.23,186.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/container_stats.go:187.2,187.38 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:66.75,70.2 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:73.161,75.16 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:75.16,77.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:79.2,80.16 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:80.16,82.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:84.2,85.16 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:85.16,87.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:89.2,113.16 5 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:113.16,116.3 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:118.2,118.27 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:121.39,123.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:125.71,128.16 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:128.16,134.3 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:136.2,139.21 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:139.21,154.3 5 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:156.2,156.35 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:159.148,164.16 4 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:164.16,166.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:168.2,170.28 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:170.28,172.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:172.8,174.17 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:174.17,176.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:179.2,181.34 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:184.98,186.35 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:186.35,187.40 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:187.40,188.66 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:188.66,190.15 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:193.3,193.26 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:198.94,203.16 4 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:203.16,205.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:207.2,209.39 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:209.39,213.56 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:213.56,214.44 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:214.44,216.10 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:221.3,221.26 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:221.26,230.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:232.3,234.47 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:234.47,236.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:236.9,238.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:239.3,244.34 5 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:247.2,247.27 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:251.59,252.31 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:252.31,254.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:256.2,258.16 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:258.16,260.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:266.2,268.28 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:268.28,276.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:278.2,278.22 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:283.79,287.39 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:287.39,289.17 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:289.17,291.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:291.9,293.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:296.2,296.12 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:300.58,311.2 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:314.54,321.16 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:321.16,323.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:324.2,324.15 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:332.44,335.36 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:335.36,337.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:339.2,340.26 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:340.26,342.53 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:342.53,344.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:345.3,346.17 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:346.17,348.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:349.3,349.37 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:352.2,352.26 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:352.26,357.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:359.2,360.22 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:360.22,360.56 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:361.74,361.108 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:364.2,366.16 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:366.16,368.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:369.2,370.9 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:370.9,372.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:373.2,374.9 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:374.9,376.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:378.2,378.29 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:378.29,380.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/docker.go:388.2,388.31 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/dummies.go:14.37,16.2 1 19 -github.com/jesseduffield/lazydocker/pkg/commands/dummies.go:19.44,29.2 2 19 -github.com/jesseduffield/lazydocker/pkg/commands/dummies.go:32.34,36.2 3 19 -github.com/jesseduffield/lazydocker/pkg/commands/dummies.go:39.45,41.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/dummies.go:44.78,52.2 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/errors.go:18.33,19.16 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/errors.go:19.16,21.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/errors.go:23.2,23.28 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/errors.go:35.61,39.2 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/errors.go:42.52,44.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/errors.go:46.39,48.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/errors.go:51.45,53.35 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/errors.go:53.35,55.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/errors.go:56.2,56.14 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:31.70,32.85 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:32.85,34.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:36.2,36.12 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:39.85,41.25 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:41.25,43.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:45.2,46.18 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:46.18,48.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:49.2,50.23 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:50.23,52.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:54.2,56.64 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:56.64,60.3 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:62.2,66.18 4 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:66.18,68.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:70.2,75.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:79.49,81.16 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:81.16,83.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:85.2,85.85 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:85.85,87.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:89.2,92.33 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:96.59,98.16 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:98.16,100.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:102.2,104.31 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:104.31,107.20 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:107.20,109.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:111.3,114.25 4 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:114.25,118.88 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:118.88,119.40 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:119.40,121.11 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:126.3,135.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:138.2,138.23 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/image.go:142.45,145.2 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/network.go:23.63,25.16 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/network.go:25.16,27.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/network.go:29.2,31.35 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/network.go:31.35,40.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/network.go:42.2,42.25 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/network.go:46.47,49.2 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/network.go:52.34,54.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:42.75,50.2 1 19 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:54.71,56.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:59.74,65.2 5 5 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:68.102,74.2 5 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:77.76,79.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:82.56,85.2 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:88.71,91.2 2 5 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:94.99,97.2 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:99.73,102.32 2 2 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:102.32,111.3 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:111.8,113.3 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:115.2,115.86 1 2 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:119.54,122.2 2 3 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:125.50,127.16 2 4 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:127.16,129.3 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:130.2,130.22 1 3 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:130.22,132.3 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:133.2,133.15 1 2 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:136.71,138.16 2 5 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:138.16,142.9 2 3 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:142.9,144.4 1 2 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:145.3,145.28 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:147.2,147.26 1 2 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:151.53,160.2 5 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:163.49,172.2 5 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:176.66,178.18 2 4 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:178.18,180.3 1 3 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:181.2,181.18 1 4 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:181.18,182.50 1 2 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:182.50,184.4 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:186.2,186.18 1 4 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:186.18,188.3 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:190.2,190.51 1 3 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:194.88,196.2 1 3 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:199.50,201.32 2 5 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:201.32,207.3 2 1 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:207.8,215.3 2 4 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:216.2,216.32 1 5 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:221.52,223.2 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:226.67,228.16 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:228.16,230.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:231.2,234.16 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:234.16,236.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:237.2,237.12 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:241.78,243.16 2 1 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:243.16,246.3 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:248.2,248.56 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:248.56,251.3 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:252.2,252.40 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:252.40,255.3 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:257.2,257.28 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:261.51,264.2 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:267.59,268.41 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:268.41,269.25 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:269.25,271.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:272.3,272.20 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:274.2,274.18 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:280.61,284.16 4 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:284.16,285.26 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:285.26,287.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:288.3,288.31 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:290.2,290.12 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:294.48,296.16 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:296.16,298.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:299.2,299.29 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:303.64,305.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:308.66,311.37 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:311.37,313.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:315.2,315.35 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:315.35,317.17 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:317.17,319.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:321.3,321.27 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:327.2,332.27 4 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:332.27,334.13 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:334.13,336.18 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:336.18,338.5 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:340.4,340.45 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:340.45,342.5 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:344.4,344.52 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:344.52,345.19 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:345.19,347.6 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:350.4,350.44 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:350.44,352.5 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:354.4,354.13 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:358.2,360.26 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:360.26,362.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:363.2,363.12 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:367.47,369.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os.go:372.55,374.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/os_default_platform.go:10.30,18.2 1 19 -github.com/jesseduffield/lazydocker/pkg/commands/service.go:23.76,25.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/service.go:28.32,30.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/service.go:33.30,35.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/service.go:38.35,40.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/service.go:43.33,45.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/service.go:47.59,53.2 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/service.go:56.47,58.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/service.go:61.49,72.2 5 0 -github.com/jesseduffield/lazydocker/pkg/commands/service.go:75.66,83.2 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/volume.go:23.61,25.16 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/volume.go:25.16,27.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/volume.go:29.2,33.33 3 0 -github.com/jesseduffield/lazydocker/pkg/commands/volume.go:33.33,42.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/volume.go:44.2,44.24 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/volume.go:48.46,51.2 2 0 -github.com/jesseduffield/lazydocker/pkg/commands/volume.go:54.43,56.2 1 0 -mode: atomic -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:32.53,36.83 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:36.83,38.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:39.39,39.61 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:48.66,52.16 4 3 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:52.16,55.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:58.2,58.23 1 3 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:58.23,60.17 2 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:60.17,62.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:63.3,64.17 2 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:64.17,66.4 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:68.3,68.21 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:70.2,70.26 1 2 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:75.33,75.47 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:85.44,87.2 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:89.117,91.16 2 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:91.16,93.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:94.2,97.16 3 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:97.16,99.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:103.2,108.16 5 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:108.16,110.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:113.2,118.8 2 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:123.87,127.6 3 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:127.6,128.10 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:129.21,130.20 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:131.14,131.14 0 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:134.3,135.17 2 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:135.17,136.12 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:138.3,138.13 1 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:143.79,145.16 2 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:145.16,147.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:148.2,149.12 2 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:152.101,156.16 4 1 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:156.16,158.3 1 0 -github.com/jesseduffield/lazydocker/pkg/commands/ssh/ssh.go:159.2,159.17 1 1 -mode: atomic -mode: atomic diff --git a/docs/Config.md b/docs/Config.md index d386ff31..ca485a2e 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -133,6 +133,20 @@ You may use the following go templates (such as `{{ .Container.ID }}` above) in - [`{{ .Container }}`](https://pkg.go.dev/github.com/jesseduffield/lazydocker@v0.20.0/pkg/commands#Container) and its fields. For example: `{{ .Container.Container.ImageID }}` - [`{{ .Service }}`](https://pkg.go.dev/github.com/jesseduffield/lazydocker@v0.20.0/pkg/commands#Service) and its fields. For example: `{{ .Service.Name }}` +## Container Runtime + +Lazydocker supports multiple container runtimes. By default it uses Docker, but you can switch to Apple Container (on macOS 26+ with Apple Silicon) using the `--runtime` flag: + +```bash +# Use Docker (default) +lazydocker + +# Use Apple Container +lazydocker --runtime apple +``` + +Note: The runtime cannot be changed from within the application. You must restart lazydocker with the appropriate flag. + ## Replacements You can add replacements like so: diff --git a/main.go b/main.go index 09f37180..84bfbc60 100644 --- a/main.go +++ b/main.go @@ -29,6 +29,7 @@ var ( configFlag = false debuggingFlag = false composeFiles []string + runtimeFlag = "docker" ) func main() { @@ -51,6 +52,7 @@ func main() { flaggy.Bool(&configFlag, "c", "config", "Print the current default config") flaggy.Bool(&debuggingFlag, "d", "debug", "a boolean") flaggy.StringSlice(&composeFiles, "f", "file", "Specify alternate compose files") + flaggy.String(&runtimeFlag, "r", "runtime", "Container runtime to use (docker, apple)") flaggy.SetVersion(info) flaggy.Parse() @@ -71,7 +73,7 @@ func main() { log.Fatal(err.Error()) } - appConfig, err := config.NewAppConfig("lazydocker", version, commit, date, buildSource, debuggingFlag, composeFiles, projectDir) + appConfig, err := config.NewAppConfig("lazydocker", version, commit, date, buildSource, debuggingFlag, composeFiles, projectDir, runtimeFlag) if err != nil { log.Fatal(err.Error()) } diff --git a/pkg/app/app.go b/pkg/app/app.go index 09a49789..f6a0e176 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -17,13 +17,15 @@ import ( type App struct { closers []io.Closer - Config *config.AppConfig - Log *logrus.Entry - OSCommand *commands.OSCommand - DockerCommand *commands.DockerCommand - Gui *gui.Gui - Tr *i18n.TranslationSet - ErrorChan chan error + Config *config.AppConfig + Log *logrus.Entry + OSCommand *commands.OSCommand + DockerCommand *commands.DockerCommand + AppleContainerCommand *commands.AppleContainerCommand + ContainerRuntime *commands.ContainerRuntimeAdapter + Gui *gui.Gui + Tr *i18n.TranslationSet + ErrorChan chan error } // NewApp bootstrap a new application @@ -41,14 +43,29 @@ func NewApp(config *config.AppConfig) (*App, error) { } app.OSCommand = commands.NewOSCommand(app.Log, config) - // here is the place to make use of the docker-compose.yml file in the current directory - - app.DockerCommand, err = commands.NewDockerCommand(app.Log, app.OSCommand, app.Tr, app.Config, app.ErrorChan) - if err != nil { - return app, err + // Initialize the appropriate container runtime based on config + switch config.Runtime { + case "docker": + // here is the place to make use of the docker-compose.yml file in the current directory + app.DockerCommand, err = commands.NewDockerCommand(app.Log, app.OSCommand, app.Tr, app.Config, app.ErrorChan) + if err != nil { + return app, err + } + app.closers = append(app.closers, app.DockerCommand) + app.ContainerRuntime = commands.NewContainerRuntimeAdapter(app.DockerCommand, nil, "docker") + containerCommand := commands.NewGuiContainerCommand(app.ContainerRuntime, app.DockerCommand, app.Config) + app.Gui, err = gui.NewGui(app.Log, app.DockerCommand, containerCommand, app.OSCommand, app.Tr, config, app.ErrorChan) + case "apple": + app.AppleContainerCommand, err = commands.NewAppleContainerCommand(app.Log, app.OSCommand, app.Tr, app.Config, app.ErrorChan) + if err != nil { + return app, err + } + app.ContainerRuntime = commands.NewContainerRuntimeAdapter(nil, app.AppleContainerCommand, "apple") + containerCommand := commands.NewGuiContainerCommand(app.ContainerRuntime, nil, app.Config) + app.Gui, err = gui.NewGui(app.Log, nil, containerCommand, app.OSCommand, app.Tr, config, app.ErrorChan) + default: + return app, err // This should be caught by config validation, but just in case } - app.closers = append(app.closers, app.DockerCommand) - app.Gui, err = gui.NewGui(app.Log, app.DockerCommand, app.OSCommand, app.Tr, config, app.ErrorChan) if err != nil { return app, err } @@ -77,6 +94,18 @@ func (app *App) KnownError(err error) (string, bool) { originalError: "Got permission denied while trying to connect to the Docker daemon socket", newError: app.Tr.CannotAccessDockerSocketError, }, + { + originalError: "Apple Container CLI not found", + newError: "Apple Container CLI not found. Please ensure the 'container' command is installed and available in your PATH.", + }, + { + originalError: "failed to get containers", + newError: "Failed to retrieve containers. Please check if the container runtime is running.", + }, + { + originalError: "failed to get images", + newError: "Failed to retrieve images. Please check if the container runtime is running.", + }, } for _, mapping := range mappings { diff --git a/pkg/app/app_test.go b/pkg/app/app_test.go new file mode 100644 index 00000000..990b88fa --- /dev/null +++ b/pkg/app/app_test.go @@ -0,0 +1,214 @@ +package app + +import ( + "os/exec" + "testing" + + "github.com/jesseduffield/lazydocker/pkg/config" + "github.com/stretchr/testify/assert" +) + +func TestNewAppRuntimeSelection(t *testing.T) { + tests := []struct { + name string + runtime string + expectError bool + errorContains string + expectDocker bool + expectApple bool + }{ + { + name: "docker runtime", + runtime: "docker", + expectError: false, + expectDocker: true, + expectApple: false, + }, + { + name: "apple runtime", + runtime: "apple", + expectError: !appleAvailable(), + errorContains: "Apple Container CLI not found", + expectDocker: false, + expectApple: appleAvailable(), + }, + { + name: "invalid runtime", + runtime: "invalid", + expectError: true, + errorContains: "unsupported runtime 'invalid'", + expectDocker: false, + expectApple: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create app config with the test runtime + appConfig, err := config.NewAppConfig( + "lazydocker", + "test-version", + "test-commit", + "test-date", + "test-build-source", + false, // debug + []string{}, // compose files + "/tmp", // project dir + tt.runtime, + ) + + if tt.runtime == "invalid" { + // Should fail at config creation for invalid runtime + assert.NotNil(t, err) + assert.Contains(t, err.Error(), tt.errorContains) + return + } + + assert.Nil(t, err) + assert.Equal(t, tt.runtime, appConfig.Runtime) + + // Try to create the app + app, err := NewApp(appConfig) + + if tt.expectError { + assert.NotNil(t, err) + if tt.errorContains != "" { + assert.Contains(t, err.Error(), tt.errorContains) + } + } else { + assert.Nil(t, err) + assert.NotNil(t, app) + assert.Equal(t, tt.runtime, app.Config.Runtime) + + // Check that the correct command was initialized + if tt.expectDocker { + assert.NotNil(t, app.DockerCommand, "DockerCommand should be initialized for docker runtime") + assert.Nil(t, app.AppleContainerCommand, "AppleContainerCommand should be nil for docker runtime") + assert.NotNil(t, app.ContainerRuntime, "ContainerRuntime should be initialized") + assert.Equal(t, "docker", app.ContainerRuntime.GetRuntimeName()) + } + if tt.expectApple { + assert.Nil(t, app.DockerCommand, "DockerCommand should be nil for apple runtime") + assert.NotNil(t, app.AppleContainerCommand, "AppleContainerCommand should be initialized for apple runtime") + assert.NotNil(t, app.ContainerRuntime, "ContainerRuntime should be initialized") + assert.Equal(t, "apple", app.ContainerRuntime.GetRuntimeName()) + } + } + }) + } +} + +func appleAvailable() bool { + _, err := exec.LookPath("container") + return err == nil +} + +func TestAppRuntimeFieldsInitialization(t *testing.T) { + // Test that app properly initializes with docker runtime + appConfig, err := config.NewAppConfig( + "lazydocker", + "test-version", + "test-commit", + "test-date", + "test-build-source", + false, + []string{}, + "/tmp", + "docker", + ) + assert.Nil(t, err) + + app, err := NewApp(appConfig) + assert.Nil(t, err) + assert.NotNil(t, app) + + // Check that all required fields are initialized + assert.NotNil(t, app.Config) + assert.NotNil(t, app.Log) + assert.NotNil(t, app.OSCommand) + assert.NotNil(t, app.Tr) + assert.NotNil(t, app.ErrorChan) + + // For docker runtime + assert.NotNil(t, app.DockerCommand) + assert.Nil(t, app.AppleContainerCommand) + assert.NotNil(t, app.ContainerRuntime) + assert.Equal(t, "docker", app.ContainerRuntime.GetRuntimeName()) + assert.NotNil(t, app.Gui) +} + +func TestAppKnownErrorHandling(t *testing.T) { + // Create a basic app for testing error handling + appConfig, err := config.NewAppConfig( + "lazydocker", + "test-version", + "test-commit", + "test-date", + "test-build-source", + false, + []string{}, + "/tmp", + "docker", + ) + assert.Nil(t, err) + + app, err := NewApp(appConfig) + assert.Nil(t, err) + + tests := []struct { + name string + errorMessage string + expectKnown bool + expectedText string + }{ + { + name: "docker permission error", + errorMessage: "Got permission denied while trying to connect to the Docker daemon socket", + expectKnown: true, + expectedText: app.Tr.CannotAccessDockerSocketError, + }, + { + name: "apple container not found", + errorMessage: "Apple Container CLI not found", + expectKnown: true, + expectedText: "Apple Container CLI not found. Please ensure the 'container' command is installed and available in your PATH.", + }, + { + name: "failed to get containers", + errorMessage: "failed to get containers from runtime", + expectKnown: true, + expectedText: "Failed to retrieve containers. Please check if the container runtime is running.", + }, + { + name: "unknown error", + errorMessage: "some unknown error message", + expectKnown: false, + expectedText: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a mock error with the test message + mockError := &mockError{message: tt.errorMessage} + + text, known := app.KnownError(mockError) + + assert.Equal(t, tt.expectKnown, known) + if tt.expectKnown { + assert.Equal(t, tt.expectedText, text) + } else { + assert.Empty(t, text) + } + }) + } +} + +// mockError is a simple error implementation for testing +type mockError struct { + message string +} + +func (e *mockError) Error() string { + return e.message +} diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index 76e9875d..fc39bd67 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -33,7 +33,7 @@ func Generate() { } func generateAtDir(dir string) { - mConfig, err := config.NewAppConfig("lazydocker", "", "", "", "", true, nil, "") + mConfig, err := config.NewAppConfig("lazydocker", "", "", "", "", true, nil, "", "docker") if err != nil { panic(err) } diff --git a/pkg/commands/apple_container.go b/pkg/commands/apple_container.go new file mode 100644 index 00000000..225dfab3 --- /dev/null +++ b/pkg/commands/apple_container.go @@ -0,0 +1,838 @@ +package commands + +import ( + "encoding/json" + "fmt" + "os/exec" + "strings" + + "github.com/distribution/reference" + "github.com/jesseduffield/lazydocker/pkg/config" + "github.com/jesseduffield/lazydocker/pkg/i18n" + "github.com/sirupsen/logrus" +) + +// AppleContainerCommand handles interactions with Apple's container CLI +type AppleContainerCommand struct { + Log *logrus.Entry + OSCommand *OSCommand + Tr *i18n.TranslationSet + Config *config.AppConfig + ErrorChan chan error + + features map[Feature]bool +} + +// internal logging helpers to tolerate nil Log in tests +func (c *AppleContainerCommand) logInfo(args ...interface{}) { + if c != nil && c.Log != nil { + c.Log.Info(args...) + } +} +func (c *AppleContainerCommand) logInfof(format string, args ...interface{}) { + if c != nil && c.Log != nil { + c.Log.Infof(format, args...) + } +} +func (c *AppleContainerCommand) logError(args ...interface{}) { + if c != nil && c.Log != nil { + c.Log.Error(args...) + } +} +func (c *AppleContainerCommand) logDebugf(format string, args ...interface{}) { + if c != nil && c.Log != nil { + c.Log.Debugf(format, args...) + } +} + +// NewAppleContainerCommand creates a new Apple Container command handler +func NewAppleContainerCommand(log *logrus.Entry, osCommand *OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*AppleContainerCommand, error) { + // Check if Apple Container CLI is available + if !isAppleContainerAvailable() { + return nil, fmt.Errorf("apple container CLI not found; ensure 'container' is on PATH") + } + + cmd := &AppleContainerCommand{ + Log: log, + OSCommand: osCommand, + Tr: tr, + Config: config, + ErrorChan: errorChan, + features: map[Feature]bool{}, + } + + cmd.detectCapabilities() + return cmd, nil +} + +// isAppleContainerAvailable checks if the Apple Container CLI is available +func isAppleContainerAvailable() bool { + _, err := exec.LookPath("container") + return err == nil +} + +// Supports reports if a capability is supported by the Apple container CLI +func (c *AppleContainerCommand) Supports(f Feature) bool { + if c == nil { + return false + } + return c.features[f] +} + +// detectCapabilities runs lightweight CLI introspection to populate features. +// It errs on the conservative side (feature=false) on any unexpected error. +func (c *AppleContainerCommand) detectCapabilities() { + feats := map[Feature]bool{} + + help := func(args ...string) string { + cmd := c.OSCommand.NewCmd("container", append(args, "--help")...) + out, err := c.OSCommand.RunExecutableWithOutput(cmd) + if err != nil { + return "" + } + return out + } + + // Top‑level commands + root := help() + contains := func(haystack, needle string) bool { return strings.Contains(haystack, needle) } + + feats[FeatureContainerExec] = contains(root, " exec ") || contains(root, "\nexec ") + feats[FeatureContainerAttach] = contains(root, " attach ") || contains(root, "\nattach ") + feats[FeatureContainerTop] = contains(root, " top ") || contains(root, "\ntop ") + feats[FeatureEventsStream] = contains(root, " events ") || contains(root, "\nevents ") + feats[FeatureStats] = contains(root, " stats ") || contains(root, "\nstats ") + + // Images namespace + imagesHelp := help("images") + feats[FeatureImageHistory] = contains(imagesHelp, " history ") || contains(imagesHelp, "\nhistory ") + feats[FeatureImagePrune] = contains(imagesHelp, " prune ") || contains(imagesHelp, "\nprune ") + feats[FeatureImageRemove] = contains(imagesHelp, " rm ") || contains(imagesHelp, " remove ") + + // Volume/Network prune + volumeHelp := help("volume") + feats[FeatureVolumePrune] = contains(volumeHelp, " prune ") + feats[FeatureVolumeCreate] = contains(volumeHelp, " create ") || contains(volumeHelp, "\ncreate ") + + networkHelp := help("network") + feats[FeatureNetworkPrune] = contains(networkHelp, " prune ") + + // Containers prune (if any) + containersHelp := help("container") + feats[FeatureContainerPrune] = contains(containersHelp, " prune ") + + // Services/compose not supported by Apple CLI + feats[FeatureServices] = false + + // Build/run platform flags + buildHelp := help("build") + feats[FeatureBuildPlatform] = contains(buildHelp, " --platform ") || contains(buildHelp, " --os ") || contains(buildHelp, " --arch ") + + runHelp := help("run") + feats[FeatureRunPlatform] = contains(runHelp, " --platform ") || contains(runHelp, " --os ") || contains(runHelp, " --arch ") + + // SSH agent forward for exec/run + execHelp := help("exec") + feats[FeatureSSHAgentForward] = contains(execHelp, " --ssh ") || contains(runHelp, " --ssh ") + + c.features = feats +} + +// GetContainers retrieves all containers from Apple Container +func (c *AppleContainerCommand) GetContainers() ([]*Container, error) { + c.logInfo("Getting containers from Apple Container") + + // Execute: container ls --format json + cmd := c.OSCommand.NewCmd("container", "ls", "--format", "json") + output, err := c.OSCommand.RunExecutableWithOutput(cmd) + if err != nil { + c.logError("Failed to get containers from Apple Container: ", err) + return nil, fmt.Errorf("failed to get containers: %w", err) + } + + c.logDebugf("Raw container ls output: %s", output) + + // Parse the JSON output + containers, err := c.parseContainerList(output) + if err != nil { + c.logError("Failed to parse container list: ", err) + return nil, fmt.Errorf("failed to parse container list: %w", err) + } + + c.logInfof("Found %d containers", len(containers)) + return containers, nil +} + +// parseContainerList parses the JSON output from Apple Container's ls command +func (c *AppleContainerCommand) parseContainerList(output string) ([]*Container, error) { + if strings.TrimSpace(output) == "" { + return []*Container{}, nil + } + + // Apple Container outputs a JSON array of container objects + var containerArray []map[string]interface{} + if err := json.Unmarshal([]byte(output), &containerArray); err != nil { + c.logError("Failed to parse container JSON array: ", err) + return nil, fmt.Errorf("failed to parse container JSON: %w", err) + } + + containers := make([]*Container, 0, len(containerArray)) + for _, containerData := range containerArray { + container := c.jsonToContainer(containerData) + if container != nil { + containers = append(containers, container) + } + } + + return containers, nil +} + +// jsonToContainer converts JSON data to a Container struct +func (c *AppleContainerCommand) jsonToContainer(data map[string]interface{}) *Container { + // Extract container configuration + config, ok := data["configuration"].(map[string]interface{}) + if !ok { + c.logError("Container missing configuration field") + return nil + } + + // Extract basic container information + id, _ := config["id"].(string) + if id == "" { + c.logError("Container missing ID field") + return nil + } + + // Extract status + status, _ := data["status"].(string) + + // Extract address if available (schema-tolerant) + var addr string + if s, ok := data["addr"].(string); ok { + addr = s + } + if addr == "" { + if m, ok := data["network"].(map[string]interface{}); ok { + if s, ok := m["addr"].(string); ok { + addr = s + } + } + } + if addr == "" { + if s, ok := data["ip"].(string); ok { + addr = s + } + } + + // Extract image information + var imageName string + if imageInfo, ok := config["image"].(map[string]interface{}); ok { + imageName, _ = imageInfo["reference"].(string) + } + + // Create container with Apple Container specific fields + container := &Container{ + ID: id, + Name: id, // Apple Container uses ID as the name + OSCommand: c.OSCommand, + Log: c.Log, + Tr: c.Tr, + // Note: Client is nil for Apple containers - we don't use Docker client + Client: nil, + // Set a reference to the Apple command for container operations + DockerCommand: c, + Addr: addr, + } + + // Set up container.Container with basic state information + container.Container.State = status + container.Container.Status = status + + // Map Apple Container states to Docker-like states for consistency + switch status { + case "stopped": + container.Container.State = "exited" + case "running": + container.Container.State = "running" + } + + // Set image name + if imageName != "" { + container.Container.Image = imageName + } + + c.logDebugf("Parsed container: ID=%s, Name=%s, Image=%s, Status=%s", id, id, imageName, status) + return container +} + +// BuildImage builds a container image using Apple Container +func (c *AppleContainerCommand) BuildImage(tag, dockerfile string) error { + c.logInfof("Building image with tag %s using dockerfile %s", tag, dockerfile) + + args := []string{"build", "--tag", tag, "--file", dockerfile, "."} + if c.Config != nil && c.Config.UserConfig != nil && c.Config.UserConfig.Apple != nil && c.Supports(FeatureBuildPlatform) { + if v := c.Config.UserConfig.Apple.BuildPlatform; v != "" { + args = append([]string{"build", "--tag", tag, "--file", dockerfile}, "--platform", v, ".") + } else { + if v := c.Config.UserConfig.Apple.BuildOS; v != "" { + args = append(args[:len(args)-1], "--os", v, ".") + } + if v := c.Config.UserConfig.Apple.BuildArch; v != "" { + args = append(args[:len(args)-1], "--arch", v, ".") + } + } + } + execCmd := c.OSCommand.NewCmd("container", args...) + return c.OSCommand.RunExecutable(execCmd) +} + +// RunContainer runs a new container using Apple Container +func (c *AppleContainerCommand) RunContainer(name, image string, detached bool) error { + c.logInfof("Running container %s from image %s", name, image) + + args := []string{"run", "--name", name} + if detached { + args = append(args, "--detach") + } + // platform flags + if c.Config != nil && c.Config.UserConfig != nil && c.Config.UserConfig.Apple != nil && c.Supports(FeatureRunPlatform) { + if v := c.Config.UserConfig.Apple.RunPlatform; v != "" { + args = append(args, "--platform", v) + } else { + if v := c.Config.UserConfig.Apple.RunOS; v != "" { + args = append(args, "--os", v) + } + if v := c.Config.UserConfig.Apple.RunArch; v != "" { + args = append(args, "--arch", v) + } + } + // ssh agent forward + if c.Config.UserConfig.Apple.ForwardSSHAgent && c.Supports(FeatureSSHAgentForward) { + args = append(args, "--ssh") + } + } + args = append(args, image) + execCmd := c.OSCommand.NewCmd("container", args...) + return c.OSCommand.RunExecutable(execCmd) +} + +// StopContainer stops a running container +func (c *AppleContainerCommand) StopContainer(nameOrID string) error { + c.logInfof("Stopping container %s", nameOrID) + + execCmd := c.OSCommand.NewCmd("container", "stop", nameOrID) + return c.OSCommand.RunExecutable(execCmd) +} + +// StartContainer starts a stopped container +func (c *AppleContainerCommand) StartContainer(nameOrID string) error { + c.logInfof("Starting container %s", nameOrID) + + execCmd := c.OSCommand.NewCmd("container", "start", nameOrID) + return c.OSCommand.RunExecutable(execCmd) +} + +// RemoveContainer removes a container +func (c *AppleContainerCommand) RemoveContainer(nameOrID string, force bool) error { + c.logInfof("Removing container %s (force: %v)", nameOrID, force) + + args := []string{"rm"} + if force { + args = append(args, "--force") + } + args = append(args, nameOrID) + execCmd := c.OSCommand.NewCmd("container", args...) + return c.OSCommand.RunExecutable(execCmd) +} + +// ExecCommand executes a command in a running container +func (c *AppleContainerCommand) ExecCommand(nameOrID, command string) error { + c.logInfof("Executing command in container %s: %s", nameOrID, command) + + // Keep string form to preserve exact command; quoting handled by ExecutableFromString + cmdStr := fmt.Sprintf("container exec %s %s", nameOrID, command) + execCmd := c.OSCommand.ExecutableFromString(cmdStr) + return c.OSCommand.RunExecutable(execCmd) +} + +// GetImages retrieves all images from Apple Container +func (c *AppleContainerCommand) GetImages() ([]*Image, error) { + c.logInfo("Getting images from Apple Container") + + // Execute: container images list --format json + cmd := c.OSCommand.NewCmd("container", "images", "list", "--format", "json") + output, err := c.OSCommand.RunExecutableWithOutput(cmd) + if err != nil { + c.logError("Failed to get images from Apple Container: ", err) + return nil, fmt.Errorf("failed to get images: %w", err) + } + + // Parse the JSON output (implementation similar to containers) + images, err := c.parseImageList(output) + if err != nil { + c.logError("Failed to parse image list: ", err) + return nil, fmt.Errorf("failed to parse image list: %w", err) + } + + c.logInfof("Found %d images", len(images)) + return images, nil +} + +// parseImageList parses the JSON output from Apple Container's images list command +func (c *AppleContainerCommand) parseImageList(output string) ([]*Image, error) { + if strings.TrimSpace(output) == "" { + return []*Image{}, nil + } + + // Apple Container outputs a JSON array of image objects + var imageArray []map[string]interface{} + if err := json.Unmarshal([]byte(output), &imageArray); err != nil { + c.logError("Failed to parse image JSON array: ", err) + return nil, fmt.Errorf("failed to parse image JSON: %w", err) + } + + images := make([]*Image, 0, len(imageArray)) + for _, imageData := range imageArray { + image := c.jsonToImage(imageData) + if image != nil { + images = append(images, image) + } + } + + return images, nil +} + +// jsonToImage converts JSON data to an Image struct +func (c *AppleContainerCommand) jsonToImage(data map[string]interface{}) *Image { + // Extract reference (image name) + refStr, _ := data["reference"].(string) + if refStr == "" { + c.logError("Image missing reference field") + return nil + } + + // Extract descriptor information + var digest string + var size float64 + if descriptor, ok := data["descriptor"].(map[string]interface{}); ok { + digest, _ = descriptor["digest"].(string) + size, _ = descriptor["size"].(float64) + } + + // Parse reference robustly (handles registries with ports and digests) + var repository, tag string + if named, err := reference.ParseNormalizedNamed(refStr); err == nil { + repository = reference.FamiliarName(named) + if t, ok := named.(reference.Tagged); ok { + tag = t.Tag() + } else { + tag = "latest" + } + if digest == "" { + if d, ok := named.(reference.Digested); ok { + digest = d.Digest().String() + } + } + } else { + // Fallback + parts := strings.Split(refStr, ":") + repository = parts[0] + tag = "latest" + if len(parts) > 1 { + tag = parts[1] + } + } + + // Use digest as ID if available, otherwise use reference + id := digest + if id == "" { + id = refStr + } + + image := &Image{ + ID: id, + Name: repository, + Tag: tag, + OSCommand: c.OSCommand, + Log: c.Log, + } + + // Store additional info in the Image.Image field + image.Image.RepoTags = []string{refStr} + if size > 0 { + image.Image.Size = int64(size) + } + + c.logDebugf("Parsed image: ID=%s, Name=%s, Tag=%s, Reference=%s", id, repository, tag, refStr) + return image +} + +// SystemStart starts the Apple Container system services +func (c *AppleContainerCommand) SystemStart() error { + c.logInfo("Starting Apple Container system services") + return c.OSCommand.RunExecutable(c.OSCommand.NewCmd("container", "system", "start")) +} + +// SystemStop stops the Apple Container system services +func (c *AppleContainerCommand) SystemStop() error { + c.logInfo("Stopping Apple Container system services") + return c.OSCommand.RunExecutable(c.OSCommand.NewCmd("container", "system", "stop")) +} + +// SystemStatus gets the status of Apple Container system services +func (c *AppleContainerCommand) SystemStatus() (map[string]interface{}, error) { + c.logInfo("Getting Apple Container system status") + + cmd := c.OSCommand.NewCmd("container", "system", "status", "--format", "json") + output, err := c.OSCommand.RunExecutableWithOutput(cmd) + if err != nil { + return nil, fmt.Errorf("failed to get system status: %w", err) + } + + var status map[string]interface{} + if err := json.Unmarshal([]byte(output), &status); err != nil { + return nil, fmt.Errorf("failed to parse system status: %w", err) + } + + return status, nil +} + +// NewCommandObject creates a new command object for Apple Container (implements LimitedDockerCommand) +func (c *AppleContainerCommand) NewCommandObject(obj CommandObject) CommandObject { + // For Apple Container, we don't need to modify the command object + // as we don't use docker-compose + return obj +} + +// GetContainerLogs returns a command to get logs for a container +func (c *AppleContainerCommand) GetContainerLogs(containerID string, follow bool, tail string) *exec.Cmd { + args := []string{"logs"} + if follow { + args = append(args, "--follow") + } + if tail != "" && tail != "all" { + args = append(args, "-n", tail) + } + args = append(args, containerID) + + return c.OSCommand.NewCmd("container", args...) +} + +// GetNetworks retrieves all networks from Apple Container +func (c *AppleContainerCommand) GetNetworks() ([]*Network, error) { + c.logInfo("Getting networks from Apple Container") + + // Execute: container network list --format json + cmd := c.OSCommand.NewCmd("container", "network", "list", "--format", "json") + output, err := c.OSCommand.RunExecutableWithOutput(cmd) + if err != nil { + c.logError("Failed to get networks from Apple Container: ", err) + return nil, fmt.Errorf("failed to get networks: %w", err) + } + + // Parse the JSON output + networks, err := c.parseNetworkList(output) + if err != nil { + c.logError("Failed to parse network list: ", err) + return nil, fmt.Errorf("failed to parse network list: %w", err) + } + + c.logInfof("Found %d networks", len(networks)) + return networks, nil +} + +// parseNetworkList parses the JSON output from Apple Container's network list command +func (c *AppleContainerCommand) parseNetworkList(output string) ([]*Network, error) { + if strings.TrimSpace(output) == "" { + return []*Network{}, nil + } + + // Apple Container outputs a JSON array of network objects + var networkArray []map[string]interface{} + if err := json.Unmarshal([]byte(output), &networkArray); err != nil { + c.logError("Failed to parse network JSON array: ", err) + return nil, fmt.Errorf("failed to parse network JSON: %w", err) + } + + networks := make([]*Network, 0, len(networkArray)) + for _, networkData := range networkArray { + network := c.jsonToNetwork(networkData) + if network != nil { + networks = append(networks, network) + } + } + + return networks, nil +} + +// jsonToNetwork converts JSON data to a Network struct +func (c *AppleContainerCommand) jsonToNetwork(data map[string]interface{}) *Network { + // Extract network ID + id, _ := data["id"].(string) + if id == "" { + c.logError("Network missing ID field") + return nil + } + + // Extract state + state, _ := data["state"].(string) + + // Extract network config + var driver string + if config, ok := data["config"].(map[string]interface{}); ok { + mode, _ := config["mode"].(string) + driver = mode // Use mode as driver for display + } + + // Create network struct + network := &Network{ + Name: id, + OSCommand: c.OSCommand, + Log: c.Log, + } + + // Set network details + network.Network.ID = id + network.Network.Name = id + network.Network.Driver = driver + + c.logDebugf("Parsed network: ID=%s, Name=%s, Driver=%s, State=%s", id, id, driver, state) + return network +} + +// GetContainerMounts retrieves mount information for a container +func (c *AppleContainerCommand) GetContainerMounts(containerID string) (string, error) { + // Execute container inspect to get full details + cmd := c.OSCommand.NewCmd("container", "inspect", containerID) + output, err := c.OSCommand.RunExecutableWithOutput(cmd) + if err != nil { + return "", fmt.Errorf("failed to inspect container: %w", err) + } + + // Parse the JSON output + var containers []map[string]interface{} + if err := json.Unmarshal([]byte(output), &containers); err != nil { + return "", fmt.Errorf("failed to parse container inspect JSON: %w", err) + } + + if len(containers) == 0 { + return "No container found", nil + } + + containerData := containers[0] + config, ok := containerData["configuration"].(map[string]interface{}) + if !ok { + return "No configuration found", nil + } + + mounts, ok := config["mounts"].([]interface{}) + if !ok || len(mounts) == 0 { + return "No mounts configured for this container", nil + } + + // Format mount information + var result strings.Builder + result.WriteString("Volume Mounts:\n") + result.WriteString("==============\n\n") + + for i, mount := range mounts { + mountMap, ok := mount.(map[string]interface{}) + if !ok { + continue + } + + source, _ := mountMap["source"].(string) + destination, _ := mountMap["destination"].(string) + options, _ := mountMap["options"].([]interface{}) + + // Get mount type + mountType := "unknown" + if typeInfo, ok := mountMap["type"].(map[string]interface{}); ok { + if _, ok := typeInfo["virtiofs"]; ok { + mountType = "virtiofs" + } else if _, ok := typeInfo["tmpfs"]; ok { + mountType = "tmpfs" + } + } + + result.WriteString(fmt.Sprintf("Mount %d:\n", i+1)) + result.WriteString(fmt.Sprintf(" Type: %s\n", mountType)) + result.WriteString(fmt.Sprintf(" Source: %s\n", source)) + result.WriteString(fmt.Sprintf(" Destination: %s\n", destination)) + + if len(options) > 0 { + optStrings := make([]string, len(options)) + for j, opt := range options { + optStrings[j] = fmt.Sprintf("%v", opt) + } + result.WriteString(fmt.Sprintf(" Options: %s\n", strings.Join(optStrings, ", "))) + } + + result.WriteString("\n") + } + + return result.String(), nil +} + +// RefreshVolumes gets the volumes and stores them for Apple Container +func (c *AppleContainerCommand) RefreshVolumes() ([]*Volume, error) { + c.logInfo("Getting volumes from Apple Container") + + // Execute: container volume list --format json + cmd := c.OSCommand.NewCmd("container", "volume", "list", "--format", "json") + output, err := c.OSCommand.RunExecutableWithOutput(cmd) + if err != nil { + c.logError("Failed to get volumes from Apple Container: ", err) + return nil, fmt.Errorf("failed to get volumes: %w", err) + } + + c.logDebugf("Raw volume ls output: %s", output) + + // Parse the JSON output + volumes, err := c.parseVolumeList(output) + if err != nil { + c.logError("Failed to parse volume list: ", err) + return nil, fmt.Errorf("failed to parse volume list: %w", err) + } + + c.logInfof("Found %d volumes", len(volumes)) + return volumes, nil +} + +// parseVolumeList parses the JSON output from Apple Container's volume list command +func (c *AppleContainerCommand) parseVolumeList(output string) ([]*Volume, error) { + if strings.TrimSpace(output) == "" { + return []*Volume{}, nil + } + + // Apple Container outputs a JSON array of volume objects + var volumeArray []map[string]interface{} + if err := json.Unmarshal([]byte(output), &volumeArray); err != nil { + c.logError("Failed to parse volume JSON array: ", err) + return nil, fmt.Errorf("failed to parse volume JSON: %w", err) + } + + volumes := make([]*Volume, 0, len(volumeArray)) + for _, volumeData := range volumeArray { + volume := c.jsonToVolume(volumeData) + if volume != nil { + volumes = append(volumes, volume) + } + } + + return volumes, nil +} + +// jsonToVolume converts JSON data to a Volume struct +func (c *AppleContainerCommand) jsonToVolume(data map[string]interface{}) *Volume { + // Extract volume name/ID + name, _ := data["name"].(string) + if name == "" { + // Try alternative field names + name, _ = data["id"].(string) + if name == "" { + c.logError("Volume missing name/id field") + return nil + } + } + + // Extract driver (if available) + driver, _ := data["driver"].(string) + if driver == "" { + driver = "local" // Default driver + } + + // Extract mountpoint (if available) + mountpoint, _ := data["mountpoint"].(string) + + // Create volume with Apple Container specific fields + volume := &Volume{ + Name: name, + OSCommand: c.OSCommand, + Log: c.Log, + // Note: Client is nil for Apple containers - we don't use Docker client + Client: nil, + // Set a reference to the Apple command for volume operations + DockerCommand: c, + } + + // Set up volume.Volume with basic information + volume.Volume.Driver = driver + volume.Volume.Mountpoint = mountpoint + volume.Volume.Name = name + volume.Volume.Scope = "local" // Apple Container volumes are typically local + + // Extract labels if available + if labelsData, ok := data["labels"].(map[string]interface{}); ok { + labels := make(map[string]string) + for k, v := range labelsData { + if vStr, ok := v.(string); ok { + labels[k] = vStr + } + } + volume.Volume.Labels = labels + } + + // Extract options if available + if optionsData, ok := data["options"].(map[string]interface{}); ok { + options := make(map[string]string) + for k, v := range optionsData { + if vStr, ok := v.(string); ok { + options[k] = vStr + } + } + volume.Volume.Options = options + } + + c.logDebugf("Parsed volume: Name=%s, Driver=%s, Mountpoint=%s", name, driver, mountpoint) + return volume +} + +// PruneVolumes prunes volumes for Apple Container +func (c *AppleContainerCommand) PruneVolumes() error { + c.logInfo("Pruning volumes from Apple Container") + + // Execute: container volume prune --force + err := c.OSCommand.RunExecutable(c.OSCommand.NewCmd("container", "volume", "prune", "--force")) + if err != nil { + c.logError("Failed to prune volumes from Apple Container: ", err) + return fmt.Errorf("failed to prune volumes: %w", err) + } + + c.logInfo("Successfully pruned volumes") + return nil +} + +// RemoveVolume removes a volume for Apple Container +func (c *AppleContainerCommand) RemoveVolume(name string, force bool) error { + c.logInfof("Removing volume %s (force: %v)", name, force) + + args := []string{"volume", "rm"} + if force { + args = append(args, "--force") + } + args = append(args, name) + return c.OSCommand.RunExecutable(c.OSCommand.NewCmd("container", args...)) +} + +// CreateVolume creates a named volume with optional key=value options +func (c *AppleContainerCommand) CreateVolume(name string, opts map[string]string) error { + if name == "" { + return fmt.Errorf("volume name required") + } + if !c.Supports(FeatureVolumeCreate) { + return fmt.Errorf("volume create not supported by this runtime") + } + args := []string{"volume", "create", "--name", name} + for k, v := range opts { + if k == "" { + continue + } + if v != "" { + args = append(args, "--opt", fmt.Sprintf("%s=%s", k, v)) + } else { + args = append(args, "--opt", k) + } + } + return c.OSCommand.RunExecutable(c.OSCommand.NewCmd("container", args...)) +} diff --git a/pkg/commands/apple_container_test.go b/pkg/commands/apple_container_test.go new file mode 100644 index 00000000..7fd17dc0 --- /dev/null +++ b/pkg/commands/apple_container_test.go @@ -0,0 +1,334 @@ +package commands + +import ( + "testing" + + "github.com/jesseduffield/lazydocker/pkg/config" + "github.com/jesseduffield/lazydocker/pkg/i18n" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" +) + +func TestAppleContainerCommandCreation(t *testing.T) { + log := logrus.NewEntry(logrus.New()) + + // Create a basic config + appConfig := &config.AppConfig{ + Runtime: "apple", + } + + // Create a basic OS command (real, but used only for help/introspection) + osCommand := NewOSCommand(log, appConfig) + + // Create translation set + tr := &i18n.TranslationSet{} + + errorChan := make(chan error, 1) + + _, err := NewAppleContainerCommand(log, osCommand, tr, appConfig, errorChan) + if isAppleContainerAvailable() { + // On machines where Apple CLI is installed, expect success + assert.Nil(t, err) + } else { + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "Apple Container CLI not found") + } +} + +func TestIsAppleContainerAvailable(t *testing.T) { + // Simply call the function; do not assert a fixed value because + // the test host may or may not have the CLI installed. + _ = isAppleContainerAvailable() +} + +func TestParseContainerList(t *testing.T) { + log := logrus.NewEntry(logrus.New()) + appConfig := &config.AppConfig{Runtime: "apple"} + osCommand := &OSCommand{} + tr := &i18n.TranslationSet{} + errorChan := make(chan error, 1) + + // Create command instance for testing parsing methods + cmd := &AppleContainerCommand{ + Log: log, + OSCommand: osCommand, + Tr: tr, + Config: appConfig, + ErrorChan: errorChan, + } + + tests := []struct { + name string + input string + expected int + hasError bool + }{ + { + name: "empty output", + input: "", + expected: 0, + hasError: false, + }, + { + name: "single container", + input: `[{"configuration":{"id":"abc123","image":{"reference":"nginx:latest"}},"status":"running"}]`, + expected: 1, + hasError: false, + }, + { + name: "multiple containers", + input: `[{"configuration":{"id":"abc123","image":{"reference":"nginx:latest"}},"status":"running"}, +{"configuration":{"id":"def456","image":{"reference":"redis:6"}},"status":"stopped"}]`, + expected: 2, + hasError: false, + }, + { + name: "invalid json", + input: `{"invalid json}`, + expected: 0, + hasError: true, + }, + { + name: "missing required fields", + input: `[{"status":"running"}]`, + expected: 0, + hasError: false, // parse succeeds but no valid entries + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + containers, err := cmd.parseContainerList(tt.input) + + if tt.hasError { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + assert.Equal(t, tt.expected, len(containers)) + } + }) + } +} + +func TestParseImageList(t *testing.T) { + log := logrus.NewEntry(logrus.New()) + appConfig := &config.AppConfig{Runtime: "apple"} + osCommand := &OSCommand{} + tr := &i18n.TranslationSet{} + errorChan := make(chan error, 1) + + cmd := &AppleContainerCommand{ + Log: log, + OSCommand: osCommand, + Tr: tr, + Config: appConfig, + ErrorChan: errorChan, + } + + tests := []struct { + name string + input string + expected int + hasError bool + }{ + { + name: "empty output", + input: "", + expected: 0, + hasError: false, + }, + { + name: "single image", + input: `[{"reference":"nginx:latest","descriptor":{"digest":"sha256:abc","size":1234}}]`, + expected: 1, + hasError: false, + }, + { + name: "multiple images", + input: `[{"reference":"nginx:latest","descriptor":{"digest":"sha256:abc","size":1234}}, +{"reference":"redis:6-alpine","descriptor":{"digest":"sha256:def","size":5678}}]`, + expected: 2, + hasError: false, + }, + { + name: "missing required fields", + input: `[{"descriptor":{"digest":"sha256:abc"}}]`, + expected: 0, + hasError: false, // Should skip images with missing ID + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + images, err := cmd.parseImageList(tt.input) + + if tt.hasError { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + assert.Equal(t, tt.expected, len(images)) + } + }) + } +} + +func TestJsonToContainer(t *testing.T) { + log := logrus.NewEntry(logrus.New()) + appConfig := &config.AppConfig{Runtime: "apple"} + osCommand := &OSCommand{} + tr := &i18n.TranslationSet{} + errorChan := make(chan error, 1) + + cmd := &AppleContainerCommand{ + Log: log, + OSCommand: osCommand, + Tr: tr, + Config: appConfig, + ErrorChan: errorChan, + } + + tests := []struct { + name string + input map[string]interface{} + expected *Container + }{ + { + name: "valid container data", + input: map[string]interface{}{ + "configuration": map[string]interface{}{ + "id": "abc123", + "image": map[string]interface{}{ + "reference": "nginx:latest", + }, + }, + "status": "running", + }, + expected: &Container{ + ID: "abc123", + Name: "abc123", + }, + }, + { + name: "missing id", + input: map[string]interface{}{ + "configuration": map[string]interface{}{ + "image": map[string]interface{}{"reference": "nginx:latest"}, + }, + "status": "running", + }, + expected: nil, + }, + // missing name is fine; name defaults to ID in implementation + { + name: "missing name", + input: map[string]interface{}{ + "configuration": map[string]interface{}{ + "id": "abc123", + "image": map[string]interface{}{"reference": "nginx:latest"}, + }, + "status": "running", + }, + expected: &Container{ID: "abc123", Name: "abc123"}, + }, + { + name: "state mapping", + input: map[string]interface{}{ + "configuration": map[string]interface{}{ + "id": "abc123", + "image": map[string]interface{}{"reference": "nginx:latest"}, + }, + "status": "stopped", // Should map to exited + }, + expected: &Container{ + ID: "abc123", + Name: "abc123", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + container := cmd.jsonToContainer(tt.input) + + if tt.expected == nil { + assert.Nil(t, container) + } else { + assert.NotNil(t, container) + assert.Equal(t, tt.expected.ID, container.ID) + assert.Equal(t, tt.expected.Name, container.Name) + } + }) + } +} + +func TestJsonToImage(t *testing.T) { + log := logrus.NewEntry(logrus.New()) + appConfig := &config.AppConfig{Runtime: "apple"} + osCommand := &OSCommand{} + tr := &i18n.TranslationSet{} + errorChan := make(chan error, 1) + + cmd := &AppleContainerCommand{ + Log: log, + OSCommand: osCommand, + Tr: tr, + Config: appConfig, + ErrorChan: errorChan, + } + + tests := []struct { + name string + input map[string]interface{} + expected *Image + }{ + { + name: "valid image data", + input: map[string]interface{}{ + "reference": "nginx:latest", + "descriptor": map[string]interface{}{ + "digest": "sha256:abc", + "size": 1234, + }, + }, + expected: &Image{ + ID: "sha256:abc", + Name: "nginx", + Tag: "latest", + }, + }, + // Missing digest is fine; implementation uses reference as ID + { + name: "missing id", + input: map[string]interface{}{ + "reference": "nginx:latest", + }, + expected: &Image{ID: "nginx:latest", Name: "nginx", Tag: "latest"}, + }, + { + name: "partial data", + input: map[string]interface{}{ + "reference": "nginx", + }, + expected: &Image{ + ID: "nginx", + Name: "nginx", + Tag: "latest", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + image := cmd.jsonToImage(tt.input) + + if tt.expected == nil { + assert.Nil(t, image) + } else { + assert.NotNil(t, image) + assert.Equal(t, tt.expected.ID, image.ID) + assert.Equal(t, tt.expected.Name, image.Name) + assert.Equal(t, tt.expected.Tag, image.Tag) + } + }) + } +} diff --git a/pkg/commands/container.go b/pkg/commands/container.go index 997175f2..6010a4c1 100644 --- a/pkg/commands/container.go +++ b/pkg/commands/container.go @@ -40,11 +40,23 @@ type Container struct { Tr *i18n.TranslationSet StatsMutex deadlock.Mutex + + // Addr is a runtime-specific address string (e.g., IP or hostname) used by + // alternative runtimes like Apple's container CLI. It may be empty. + Addr string } // Remove removes the container func (c *Container) Remove(options container.RemoveOptions) error { c.Log.Warn(fmt.Sprintf("removing container %s", c.Name)) + + // For Apple containers, use the AppleContainerCommand + if c.Client == nil && c.DockerCommand != nil { + if appleCmd, ok := c.DockerCommand.(*AppleContainerCommand); ok { + return appleCmd.RemoveContainer(c.ID, options.Force) + } + } + if err := c.Client.ContainerRemove(context.Background(), c.ID, options); err != nil { if strings.Contains(err.Error(), "Stop the container before attempting removal or force remove") { return ComplexError{ @@ -62,6 +74,14 @@ func (c *Container) Remove(options container.RemoveOptions) error { // Stop stops the container func (c *Container) Stop() error { c.Log.Warn(fmt.Sprintf("stopping container %s", c.Name)) + + // For Apple containers, use the AppleContainerCommand + if c.Client == nil && c.DockerCommand != nil { + if appleCmd, ok := c.DockerCommand.(*AppleContainerCommand); ok { + return appleCmd.StopContainer(c.ID) + } + } + return c.Client.ContainerStop(context.Background(), c.ID, container.StopOptions{}) } @@ -80,6 +100,17 @@ func (c *Container) Unpause() error { // Restart restarts the container func (c *Container) Restart() error { c.Log.Warn(fmt.Sprintf("restarting container %s", c.Name)) + + // For Apple containers, stop and start + if c.Client == nil && c.DockerCommand != nil { + if appleCmd, ok := c.DockerCommand.(*AppleContainerCommand); ok { + if err := appleCmd.StopContainer(c.ID); err != nil { + return err + } + return appleCmd.StartContainer(c.ID) + } + } + return c.Client.ContainerRestart(context.Background(), c.ID, container.StopOptions{}) } @@ -98,6 +129,11 @@ func (c *Container) Attach() (*exec.Cmd, error) { return nil, errors.New(c.Tr.CannotAttachStoppedContainerError) } + // Apple Container runtime does not support docker attach + if c.Client == nil { + return nil, errors.New("attach not available for Apple Container runtime") + } + c.Log.Warn(fmt.Sprintf("attaching to container %s", c.Name)) // TODO: use SDK cmd := c.OSCommand.NewCmd("docker", "attach", "--sig-proxy=false", c.ID) @@ -106,6 +142,16 @@ func (c *Container) Attach() (*exec.Cmd, error) { // Top returns process information func (c *Container) Top(ctx context.Context) (container.ContainerTopOKBody, error) { + // For Apple containers, this feature is not available + if c.Client == nil { + return container.ContainerTopOKBody{ + Titles: []string{"PID", "USER", "TIME", "COMMAND"}, + Processes: [][]string{ + {"N/A", "N/A", "N/A", "Process information not available for Apple Container runtime"}, + }, + }, nil + } + detail, err := c.Inspect() if err != nil { return container.ContainerTopOKBody{}, err @@ -127,6 +173,23 @@ func (c *DockerCommand) PruneContainers() error { // Inspect returns details about the container func (c *Container) Inspect() (dockerTypes.ContainerJSON, error) { + // For Apple containers, we don't have a Docker client + if c.Client == nil { + // Return a minimal ContainerJSON with just the state information we have + return dockerTypes.ContainerJSON{ + ContainerJSONBase: &dockerTypes.ContainerJSONBase{ + ID: c.ID, + Name: c.Name, + State: &dockerTypes.ContainerState{ + Status: c.Container.State, + Running: c.Container.State == "running", + }, + }, + Config: &container.Config{ + Image: c.Container.Image, + }, + }, nil + } return c.Client.ContainerInspect(context.Background(), c.ID) } diff --git a/pkg/commands/container_runtime.go b/pkg/commands/container_runtime.go new file mode 100644 index 00000000..8409ba5b --- /dev/null +++ b/pkg/commands/container_runtime.go @@ -0,0 +1,432 @@ +package commands + +import ( + "fmt" + "io" + "os/exec" +) + +// ContainerRuntime defines the interface that all container runtimes must implement +// This allows lazydocker to work with different container systems (Docker, Apple Container, etc.) +type ContainerRuntime interface { + // Container operations + GetContainers() ([]*Container, error) + RefreshContainersAndServices(currentServices []*Service, currentContainers []*Container) ([]*Container, []*Service, error) + RefreshContainerDetails(containers []*Container) error + PruneContainers() error + + // Image operations + RefreshImages() ([]*Image, error) + PruneImages() error + + // Volume operations + RefreshVolumes() ([]*Volume, error) + PruneVolumes() error + + // Network operations + RefreshNetworks() ([]*Network, error) + PruneNetworks() error + + // Volume create (optional capability) + CreateVolume(name string, opts map[string]string) error + + // Service operations (for docker-compose/equivalent) + GetServices() ([]*Service, error) + InDockerComposeProject() bool + + // System operations + ViewAllLogs() (cmd Cmd, err error) + DockerComposeConfig() string + SystemStatus() (map[string]interface{}, error) + + // Runtime information + GetRuntimeName() string + GetRuntimeVersion() string + + // Close resources + io.Closer +} + +// Cmd represents a command that can be executed +type Cmd interface { + Start() error + Wait() error + Kill() error +} + +// ContainerRuntimeAdapter provides a unified interface for accessing container operations +// It wraps either a DockerCommand or AppleContainerCommand and exposes them through +// the ContainerRuntime interface +type ContainerRuntimeAdapter struct { + dockerCommand *DockerCommand + appleContainerCommand *AppleContainerCommand + runtimeType string +} + +// operationNotSupported returns an error indicating the operation is not supported by the current runtime +func (c *ContainerRuntimeAdapter) operationNotSupported(operation string) error { + return fmt.Errorf("%s not supported by %s runtime", operation, c.runtimeType) +} + +// commandNotAvailable returns an error indicating the runtime command is not available +func (c *ContainerRuntimeAdapter) commandNotAvailable() error { + return fmt.Errorf("%s command not available", c.runtimeType) +} + +// unsupportedRuntime returns an error indicating the runtime type is not supported +func (c *ContainerRuntimeAdapter) unsupportedRuntime() error { + return fmt.Errorf("unsupported runtime '%s'", c.runtimeType) +} + +// NewContainerRuntimeAdapter creates a new adapter based on the provided commands +func NewContainerRuntimeAdapter(docker *DockerCommand, apple *AppleContainerCommand, runtimeType string) *ContainerRuntimeAdapter { + return &ContainerRuntimeAdapter{ + dockerCommand: docker, + appleContainerCommand: apple, + runtimeType: runtimeType, + } +} + +// Supports returns whether a given feature is supported by the active runtime +func (c *ContainerRuntimeAdapter) Supports(f Feature) bool { + switch c.runtimeType { + case "docker": + // Docker runtime supports all features used by LazyDocker + return true + case "apple": + if c.appleContainerCommand == nil { + return false + } + return c.appleContainerCommand.Supports(f) + default: + return false + } +} + +// GetContainers returns containers from the active runtime +func (c *ContainerRuntimeAdapter) GetContainers() ([]*Container, error) { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return nil, c.commandNotAvailable() + } + return c.dockerCommand.GetContainers(nil) + case "apple": + if c.appleContainerCommand == nil { + return nil, c.commandNotAvailable() + } + return c.appleContainerCommand.GetContainers() + default: + return nil, c.unsupportedRuntime() + } +} + +// RefreshContainersAndServices refreshes both containers and services +func (c *ContainerRuntimeAdapter) RefreshContainersAndServices(currentServices []*Service, currentContainers []*Container) ([]*Container, []*Service, error) { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return nil, nil, c.commandNotAvailable() + } + return c.dockerCommand.RefreshContainersAndServices(currentServices, currentContainers) + case "apple": + if c.appleContainerCommand == nil { + return nil, nil, c.commandNotAvailable() + } + // Apple Container doesn't have services concept, so we just return containers + containers, err := c.appleContainerCommand.GetContainers() + return containers, []*Service{}, err + default: + return nil, nil, c.unsupportedRuntime() + } +} + +// RefreshContainerDetails updates container details +func (c *ContainerRuntimeAdapter) RefreshContainerDetails(containers []*Container) error { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return c.commandNotAvailable() + } + return c.dockerCommand.RefreshContainerDetails(containers) + case "apple": + // Apple Container doesn't need explicit refresh - details are fetched with containers + return nil + default: + return c.unsupportedRuntime() + } +} + +// PruneContainers removes unused containers +func (c *ContainerRuntimeAdapter) PruneContainers() error { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return c.commandNotAvailable() + } + return c.dockerCommand.PruneContainers() + case "apple": + // Apple Container might not have prune functionality + return c.operationNotSupported("container pruning") + default: + return c.unsupportedRuntime() + } +} + +// RefreshImages returns images from the active runtime +func (c *ContainerRuntimeAdapter) RefreshImages() ([]*Image, error) { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return nil, c.commandNotAvailable() + } + return c.dockerCommand.RefreshImages() + case "apple": + if c.appleContainerCommand == nil { + return nil, c.commandNotAvailable() + } + return c.appleContainerCommand.GetImages() + default: + return nil, c.unsupportedRuntime() + } +} + +// PruneImages removes unused images +func (c *ContainerRuntimeAdapter) PruneImages() error { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return c.commandNotAvailable() + } + return c.dockerCommand.PruneImages() + case "apple": + return c.operationNotSupported("image pruning") + default: + return c.unsupportedRuntime() + } +} + +// RefreshVolumes returns volumes from the active runtime +func (c *ContainerRuntimeAdapter) RefreshVolumes() ([]*Volume, error) { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return nil, c.commandNotAvailable() + } + return c.dockerCommand.RefreshVolumes() + case "apple": + if c.appleContainerCommand == nil { + return nil, c.commandNotAvailable() + } + if c.appleContainerCommand.OSCommand == nil { // avoid invoking external CLI in tests + return []*Volume{}, nil + } + return c.appleContainerCommand.RefreshVolumes() + default: + return nil, c.unsupportedRuntime() + } +} + +// PruneVolumes removes unused volumes +func (c *ContainerRuntimeAdapter) PruneVolumes() error { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return c.commandNotAvailable() + } + return c.dockerCommand.PruneVolumes() + case "apple": + return c.operationNotSupported("volume pruning") + default: + return c.unsupportedRuntime() + } +} + +// RefreshNetworks returns networks from the active runtime +func (c *ContainerRuntimeAdapter) RefreshNetworks() ([]*Network, error) { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return nil, c.commandNotAvailable() + } + return c.dockerCommand.RefreshNetworks() + case "apple": + if c.appleContainerCommand == nil { + return nil, c.commandNotAvailable() + } + if c.appleContainerCommand.OSCommand == nil { // avoid invoking external CLI in tests + return []*Network{}, nil + } + return c.appleContainerCommand.GetNetworks() + default: + return nil, c.unsupportedRuntime() + } +} + +// PruneNetworks removes unused networks +func (c *ContainerRuntimeAdapter) PruneNetworks() error { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return c.commandNotAvailable() + } + return c.dockerCommand.PruneNetworks() + case "apple": + return c.operationNotSupported("network pruning") + default: + return c.unsupportedRuntime() + } +} + +// GetServices returns services from the active runtime +func (c *ContainerRuntimeAdapter) GetServices() ([]*Service, error) { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return nil, c.commandNotAvailable() + } + return c.dockerCommand.GetServices() + case "apple": + // Apple Container doesn't have services concept + return []*Service{}, nil + default: + return nil, c.unsupportedRuntime() + } +} + +// InDockerComposeProject returns whether we're in a docker-compose project +func (c *ContainerRuntimeAdapter) InDockerComposeProject() bool { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return false + } + return c.dockerCommand.InDockerComposeProject + case "apple": + // Apple Container doesn't have compose concept + return false + default: + return false + } +} + +// ViewAllLogs returns a command to view all logs +func (c *ContainerRuntimeAdapter) ViewAllLogs() (cmd Cmd, err error) { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return nil, c.commandNotAvailable() + } + execCmd, err := c.dockerCommand.ViewAllLogs() + if err != nil { + return nil, err + } + return &cmdWrapper{cmd: execCmd}, nil + case "apple": + return nil, c.operationNotSupported("viewing all logs") + default: + return nil, c.unsupportedRuntime() + } +} + +// DockerComposeConfig returns the docker-compose config +func (c *ContainerRuntimeAdapter) DockerComposeConfig() string { + switch c.runtimeType { + case "docker": + if c.dockerCommand == nil { + return "" + } + return c.dockerCommand.DockerComposeConfig() + case "apple": + return "" + default: + return "" + } +} + +// CreateVolume creates a volume (runtime-dependent) +func (c *ContainerRuntimeAdapter) CreateVolume(name string, opts map[string]string) error { + switch c.runtimeType { + case "docker": + return c.operationNotSupported("volume create") + case "apple": + if c.appleContainerCommand == nil { + return c.commandNotAvailable() + } + if !c.appleContainerCommand.Supports(FeatureVolumeCreate) { + return c.operationNotSupported("volume create") + } + return c.appleContainerCommand.CreateVolume(name, opts) + default: + return c.unsupportedRuntime() + } +} + +// SystemStatus returns a runtime-specific system status map +func (c *ContainerRuntimeAdapter) SystemStatus() (map[string]interface{}, error) { + switch c.runtimeType { + case "docker": + return map[string]interface{}{"runtime": "docker"}, nil + case "apple": + if c.appleContainerCommand == nil { + return nil, c.commandNotAvailable() + } + if c.appleContainerCommand.OSCommand == nil { + return map[string]interface{}{"runtime": "apple"}, nil + } + return c.appleContainerCommand.SystemStatus() + default: + return nil, c.unsupportedRuntime() + } +} + +// GetRuntimeName returns the name of the runtime +func (c *ContainerRuntimeAdapter) GetRuntimeName() string { + return c.runtimeType +} + +// GetRuntimeVersion returns the version of the runtime +func (c *ContainerRuntimeAdapter) GetRuntimeVersion() string { + switch c.runtimeType { + case "docker": + return "Docker Runtime" + case "apple": + return "Apple Container Runtime" + default: + return "Unknown Runtime" + } +} + +// Close closes the underlying runtime resources +func (c *ContainerRuntimeAdapter) Close() error { + switch c.runtimeType { + case "docker": + if c.dockerCommand != nil { + return c.dockerCommand.Close() + } + case "apple": + // Apple Container command doesn't implement io.Closer currently + // This is fine since it doesn't hold persistent connections + } + return nil +} + +// cmdWrapper wraps an exec.Cmd to implement our Cmd interface +type cmdWrapper struct { + cmd *exec.Cmd +} + +func (c *cmdWrapper) Start() error { + return c.cmd.Start() +} + +func (c *cmdWrapper) Wait() error { + return c.cmd.Wait() +} + +func (c *cmdWrapper) Kill() error { + if c.cmd.Process != nil { + return c.cmd.Process.Kill() + } + return nil +} diff --git a/pkg/commands/container_runtime_test.go b/pkg/commands/container_runtime_test.go new file mode 100644 index 00000000..3084420f --- /dev/null +++ b/pkg/commands/container_runtime_test.go @@ -0,0 +1,194 @@ +package commands + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestContainerRuntimeAdapter(t *testing.T) { + tests := []struct { + name string + runtimeType string + hasDocker bool + hasApple bool + }{ + { + name: "docker runtime", + runtimeType: "docker", + hasDocker: true, + hasApple: false, + }, + { + name: "apple runtime", + runtimeType: "apple", + hasDocker: false, + hasApple: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var dockerCmd *DockerCommand + var appleCmd *AppleContainerCommand + + if tt.hasDocker { + // Create a mock docker command (we can't easily create a real one in tests) + dockerCmd = &DockerCommand{} + } + if tt.hasApple { + // Create a mock apple container command + appleCmd = &AppleContainerCommand{} + } + + adapter := NewContainerRuntimeAdapter(dockerCmd, appleCmd, tt.runtimeType) + + // Test basic properties + assert.Equal(t, tt.runtimeType, adapter.GetRuntimeName()) + assert.NotEmpty(t, adapter.GetRuntimeVersion()) + + // Test that the adapter correctly identifies its runtime type + switch tt.runtimeType { + case "docker": + assert.Equal(t, dockerCmd, adapter.dockerCommand) + assert.Nil(t, adapter.appleContainerCommand) + case "apple": + assert.Nil(t, adapter.dockerCommand) + assert.Equal(t, appleCmd, adapter.appleContainerCommand) + } + }) + } +} + +func TestContainerRuntimeAdapterErrorHandling(t *testing.T) { + tests := []struct { + name string + runtimeType string + dockerCmd *DockerCommand + appleCmd *AppleContainerCommand + expectError bool + errorMessage string + }{ + { + name: "docker runtime with nil command", + runtimeType: "docker", + dockerCmd: nil, + appleCmd: nil, + expectError: true, + errorMessage: "docker command not available", + }, + { + name: "apple runtime with nil command", + runtimeType: "apple", + dockerCmd: nil, + appleCmd: nil, + expectError: true, + errorMessage: "apple command not available", + }, + { + name: "unsupported runtime", + runtimeType: "unsupported", + dockerCmd: nil, + appleCmd: nil, + expectError: true, + errorMessage: "unsupported runtime 'unsupported'", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + adapter := NewContainerRuntimeAdapter(tt.dockerCmd, tt.appleCmd, tt.runtimeType) + + // Test GetContainers error handling + containers, err := adapter.GetContainers() + if tt.expectError { + assert.Error(t, err) + assert.Contains(t, err.Error(), tt.errorMessage) + assert.Nil(t, containers) + } + + // Test RefreshImages error handling + images, err := adapter.RefreshImages() + if tt.expectError { + assert.Error(t, err) + assert.Contains(t, err.Error(), tt.errorMessage) + assert.Nil(t, images) + } + + // Test PruneContainers error handling + err = adapter.PruneContainers() + if tt.expectError { + assert.Error(t, err) + // Apple runtime returns operation not supported error + if tt.runtimeType == "apple" { + assert.Contains(t, err.Error(), "container pruning not supported by apple runtime") + } else { + assert.Contains(t, err.Error(), tt.errorMessage) + } + } + }) + } +} + +func TestContainerRuntimeAdapterAppleSpecificBehavior(t *testing.T) { + adapter := NewContainerRuntimeAdapter(nil, &AppleContainerCommand{}, "apple") + + // Test that Apple Container returns empty services + services, err := adapter.GetServices() + assert.Nil(t, err) + assert.Empty(t, services) + + // Test that Apple Container doesn't support compose projects + assert.False(t, adapter.InDockerComposeProject()) + + // Test that Apple Container returns empty volumes + volumes, err := adapter.RefreshVolumes() + assert.Nil(t, err) + assert.Empty(t, volumes) + + // Test that Apple Container returns empty networks + networks, err := adapter.RefreshNetworks() + assert.Nil(t, err) + assert.Empty(t, networks) + + // Test that Apple Container doesn't support certain operations + err = adapter.PruneContainers() + assert.Error(t, err) + assert.Contains(t, err.Error(), "container pruning not supported by apple runtime") + + err = adapter.PruneImages() + assert.Error(t, err) + assert.Contains(t, err.Error(), "image pruning not supported by apple runtime") + + err = adapter.PruneVolumes() + assert.Error(t, err) + assert.Contains(t, err.Error(), "volume pruning not supported by apple runtime") + + err = adapter.PruneNetworks() + assert.Error(t, err) + assert.Contains(t, err.Error(), "network pruning not supported by apple runtime") + + // Test ViewAllLogs returns error for Apple Container + cmd, err := adapter.ViewAllLogs() + assert.Error(t, err) + assert.Contains(t, err.Error(), "viewing all logs not supported by apple runtime") + assert.Nil(t, cmd) + + // Test DockerComposeConfig returns empty for Apple Container + config := adapter.DockerComposeConfig() + assert.Empty(t, config) +} + +func TestContainerRuntimeAdapterClose(t *testing.T) { + // Test closing with docker runtime + dockerAdapter := NewContainerRuntimeAdapter(&DockerCommand{}, nil, "docker") + err := dockerAdapter.Close() + // We expect no error because our mock DockerCommand doesn't implement Close properly + // In a real scenario, this would call the actual Close method + assert.Nil(t, err) + + // Test closing with apple runtime + appleAdapter := NewContainerRuntimeAdapter(nil, &AppleContainerCommand{}, "apple") + err = appleAdapter.Close() + assert.Nil(t, err) // Apple Container doesn't implement io.Closer, so this should always be nil +} diff --git a/pkg/commands/errors.go b/pkg/commands/errors.go index f7165fca..7990b85e 100644 --- a/pkg/commands/errors.go +++ b/pkg/commands/errors.go @@ -1,9 +1,10 @@ package commands import ( + "errors" "fmt" - "github.com/go-errors/errors" + goErrors "github.com/go-errors/errors" "golang.org/x/xerrors" ) @@ -20,7 +21,7 @@ func WrapError(err error) error { return err } - return errors.Wrap(err, 0) + return goErrors.Wrap(err, 0) } // ComplexError an error which carries a code so that calling code has an easier job to do @@ -55,3 +56,11 @@ func HasErrorCode(err error, code int) bool { } return false } + +// Runtime-specific errors +var ( + ErrDockerCommandNotAvailable = errors.New("docker command not available") + ErrAppleContainerCommandNotAvailable = errors.New("apple container command not available") + ErrUnsupportedRuntime = errors.New("unsupported runtime") + ErrOperationNotSupported = errors.New("operation not supported by this runtime") +) diff --git a/pkg/commands/features.go b/pkg/commands/features.go new file mode 100644 index 00000000..34dbbad6 --- /dev/null +++ b/pkg/commands/features.go @@ -0,0 +1,35 @@ +package commands + +// Feature represents a runtime capability that may or may not be supported +// by a given container runtime implementation. +type Feature int + +const ( + // Image features + FeatureImageHistory Feature = iota + FeatureImageRemove + FeatureImagePrune + + // Container features + FeatureContainerAttach + FeatureContainerExec + FeatureContainerTop + FeatureContainerPrune + + // Volume/Network + FeatureVolumePrune + FeatureNetworkPrune + + // Services / compose + FeatureServices + + // Telemetry/streaming + FeatureEventsStream + FeatureStats + + // Newer Apple CLI capabilities + FeatureVolumeCreate + FeatureBuildPlatform + FeatureRunPlatform + FeatureSSHAgentForward +) diff --git a/pkg/commands/gui_adapter.go b/pkg/commands/gui_adapter.go new file mode 100644 index 00000000..6d5e1bbc --- /dev/null +++ b/pkg/commands/gui_adapter.go @@ -0,0 +1,160 @@ +package commands + +import ( + "fmt" + "os/exec" + + "github.com/jesseduffield/lazydocker/pkg/config" +) + +// GuiContainerCommand provides an adapter that makes ContainerRuntime work with the GUI +// It implements the subset of DockerCommand methods that the GUI actually uses +type GuiContainerCommand struct { + runtime *ContainerRuntimeAdapter + dockerCommand *DockerCommand // For docker-specific operations + config *config.AppConfig +} + +// NewGuiContainerCommand creates a new GUI adapter for the container runtime +func NewGuiContainerCommand(runtime *ContainerRuntimeAdapter, dockerCommand *DockerCommand, config *config.AppConfig) *GuiContainerCommand { + return &GuiContainerCommand{ + runtime: runtime, + dockerCommand: dockerCommand, + config: config, + } +} + +// Supports exposes runtime capability checks to the GUI layer +func (g *GuiContainerCommand) Supports(f Feature) bool { + if g.runtime == nil { + return false + } + return g.runtime.Supports(f) +} + +// GetContainers returns containers +func (g *GuiContainerCommand) GetContainers(existingContainers []*Container) ([]*Container, error) { + return g.runtime.GetContainers() +} + +// RefreshContainersAndServices refreshes both containers and services +func (g *GuiContainerCommand) RefreshContainersAndServices(currentServices []*Service, currentContainers []*Container) ([]*Container, []*Service, error) { + return g.runtime.RefreshContainersAndServices(currentServices, currentContainers) +} + +// RefreshContainer updates details for a specific container +func (g *GuiContainerCommand) RefreshContainer(container *Container) error { + containers := []*Container{container} + return g.runtime.RefreshContainerDetails(containers) +} + +// RefreshImages returns the list of images +func (g *GuiContainerCommand) RefreshImages() ([]*Image, error) { + return g.runtime.RefreshImages() +} + +// RefreshVolumes returns the list of volumes +func (g *GuiContainerCommand) RefreshVolumes() ([]*Volume, error) { + return g.runtime.RefreshVolumes() +} + +// RefreshNetworks returns the list of networks +func (g *GuiContainerCommand) RefreshNetworks() ([]*Network, error) { + return g.runtime.RefreshNetworks() +} + +// GetServices returns the list of services +func (g *GuiContainerCommand) GetServices() ([]*Service, error) { + return g.runtime.GetServices() +} + +// InDockerComposeProject checks if we're in a docker-compose project +func (g *GuiContainerCommand) InDockerComposeProject() bool { + return g.runtime.InDockerComposeProject() +} + +// DockerComposeConfig returns the docker-compose configuration +func (g *GuiContainerCommand) DockerComposeConfig() string { + return g.runtime.DockerComposeConfig() +} + +// GetRuntimeName returns the name of the active runtime +func (g *GuiContainerCommand) GetRuntimeName() string { + return g.runtime.GetRuntimeName() +} + +// GetRuntimeVersion returns a friendly runtime version/info string +func (g *GuiContainerCommand) GetRuntimeVersion() string { + if g.runtime == nil { + return "" + } + return g.runtime.GetRuntimeVersion() +} + +// CreateVolume creates a volume via the active runtime +func (g *GuiContainerCommand) CreateVolume(name string, opts map[string]string) error { + return g.runtime.CreateVolume(name, opts) +} + +// SystemStatus returns a runtime-specific system status map +func (g *GuiContainerCommand) SystemStatus() (map[string]interface{}, error) { + return g.runtime.SystemStatus() +} + +// ViewAllLogs returns a command to view all logs +func (g *GuiContainerCommand) ViewAllLogs() (*exec.Cmd, error) { + cmd, err := g.runtime.ViewAllLogs() + if err != nil { + return nil, err + } + // Convert from our Cmd interface to exec.Cmd + // This is a bit of a hack but maintains compatibility + if cmdWrapper, ok := cmd.(*cmdWrapper); ok { + return cmdWrapper.cmd, nil + } + return nil, fmt.Errorf("viewing all logs not supported by %s runtime", g.runtime.GetRuntimeName()) +} + +// PruneContainers removes unused containers +func (g *GuiContainerCommand) PruneContainers() error { + return g.runtime.PruneContainers() +} + +// PruneImages removes unused images +func (g *GuiContainerCommand) PruneImages() error { + return g.runtime.PruneImages() +} + +// PruneVolumes removes unused volumes +func (g *GuiContainerCommand) PruneVolumes() error { + return g.runtime.PruneVolumes() +} + +// PruneNetworks removes unused networks +func (g *GuiContainerCommand) PruneNetworks() error { + return g.runtime.PruneNetworks() +} + +// NewCommandObject creates a new command object with defaults +func (g *GuiContainerCommand) NewCommandObject(obj CommandObject) CommandObject { + if g.dockerCommand != nil { + return g.dockerCommand.NewCommandObject(obj) + } + // For Apple Container, just return the object as-is since it doesn't use docker-compose + return obj +} + +// GetClient returns the Docker client if available (only for Docker runtime) +func (g *GuiContainerCommand) GetClient() interface{} { + if g.dockerCommand != nil { + return g.dockerCommand.Client + } + return nil +} + +// CreateClientStatMonitor creates a stat monitor for a container (Docker-specific) +func (g *GuiContainerCommand) CreateClientStatMonitor(container *Container) { + if g.dockerCommand != nil { + g.dockerCommand.CreateClientStatMonitor(container) + } +} diff --git a/pkg/commands/image.go b/pkg/commands/image.go index 789733d0..d47fc46f 100644 --- a/pkg/commands/image.go +++ b/pkg/commands/image.go @@ -2,6 +2,7 @@ package commands import ( "context" + "fmt" "strings" "github.com/docker/docker/api/types/filters" @@ -73,9 +74,32 @@ func getHistoryResponseItemDisplayStrings(layer image.HistoryResponseItem) []str } } +// safeImageHistory wraps the Docker client's ImageHistory call to guard +// against panics originating from the Docker SDK when certain runtimes +// or daemons do not support the endpoint as expected. In the event of a +// panic, we convert it to an error so the TUI does not crash. +func (i *Image) safeImageHistory(ctx context.Context, imageID string) (items []image.HistoryResponseItem, err error) { + defer func() { + if r := recover(); r != nil { + // Avoid crashing the whole app when the Docker SDK panics. + if i != nil && i.Log != nil { + i.Log.Errorf("panic in ImageHistory: %v", r) + } + err = fmt.Errorf("failed to fetch image history: %v", r) + } + }() + + // Guard against a nil client just in case. + if i == nil || i.Client == nil { + return nil, fmt.Errorf("docker client is not initialized") + } + + return i.Client.ImageHistory(ctx, imageID) +} + // RenderHistory renders the history of the image func (i *Image) RenderHistory() (string, error) { - history, err := i.Client.ImageHistory(context.Background(), i.ID) + history, err := i.safeImageHistory(context.Background(), i.ID) if err != nil { return "", err } diff --git a/pkg/commands/service.go b/pkg/commands/service.go index 755b7f5f..316b446f 100644 --- a/pkg/commands/service.go +++ b/pkg/commands/service.go @@ -2,6 +2,7 @@ package commands import ( "context" + "fmt" "os/exec" "github.com/docker/docker/api/types/container" @@ -26,6 +27,7 @@ func (s *Service) Remove(options container.RemoveOptions) error { // Stop stops the service's containers func (s *Service) Stop() error { + s.Log.Warn(fmt.Sprintf("stopping service %s", s.Name)) return s.runCommand(s.OSCommand.Config.UserConfig.CommandTemplates.StopService) } @@ -49,7 +51,12 @@ func (s *Service) runCommand(templateCmdStr string) error { templateCmdStr, s.DockerCommand.NewCommandObject(CommandObject{Service: s}), ) - return s.OSCommand.RunCommand(command) + s.Log.Warn(fmt.Sprintf("executing command: %s", command)) + err := s.OSCommand.RunCommand(command) + if err != nil { + s.Log.Error(fmt.Sprintf("command failed: %s, error: %v", command, err)) + } + return err } // Attach attaches to the service diff --git a/pkg/commands/volume.go b/pkg/commands/volume.go index 169ba8d5..95b35ec1 100644 --- a/pkg/commands/volume.go +++ b/pkg/commands/volume.go @@ -52,5 +52,12 @@ func (c *DockerCommand) PruneVolumes() error { // Remove removes the volume func (v *Volume) Remove(force bool) error { + // For Apple containers, use the AppleContainerCommand + if v.Client == nil && v.DockerCommand != nil { + if appleCmd, ok := v.DockerCommand.(*AppleContainerCommand); ok { + return appleCmd.RemoveVolume(v.Name, force) + } + } + return v.Client.VolumeRemove(context.Background(), v.Name, force) } diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index 9c0ad474..c0693714 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -13,6 +13,7 @@ package config import ( + "fmt" "os" "path/filepath" "strings" @@ -64,6 +65,23 @@ type UserConfig struct { // will be filtered out and not displayed. // Not documented because it's subject to change Ignore []string `yaml:"ignore,omitempty"` + + // Apple contains Apple runtime specific configuration + Apple *AppleRuntimeConfig `yaml:"apple,omitempty"` +} + +// AppleRuntimeConfig holds Apple container runtime options +type AppleRuntimeConfig struct { + // Build flags + BuildPlatform string `yaml:"buildPlatform,omitempty"` + BuildOS string `yaml:"buildOS,omitempty"` + BuildArch string `yaml:"buildArch,omitempty"` + // Run flags + RunPlatform string `yaml:"runPlatform,omitempty"` + RunOS string `yaml:"runOS,omitempty"` + RunArch string `yaml:"runArch,omitempty"` + // Exec/Run SSH agent forward + ForwardSSHAgent bool `yaml:"forwardSSHAgent,omitempty"` } // ThemeConfig is for setting the colors of panels and some text. @@ -474,6 +492,7 @@ func GetDefaultConfig() UserConfig { Replacements: Replacements{ ImageNamePrefixes: map[string]string{}, }, + Apple: &AppleRuntimeConfig{}, } } @@ -485,13 +504,14 @@ type AppConfig struct { BuildDate string `long:"build-date" env:"BUILD_DATE"` Name string `long:"name" env:"NAME" default:"lazydocker"` BuildSource string `long:"build-source" env:"BUILD_SOURCE" default:""` + Runtime string `long:"runtime" env:"RUNTIME" default:"docker"` UserConfig *UserConfig ConfigDir string ProjectDir string } // NewAppConfig makes a new app config -func NewAppConfig(name, version, commit, date string, buildSource string, debuggingFlag bool, composeFiles []string, projectDir string) (*AppConfig, error) { +func NewAppConfig(name, version, commit, date string, buildSource string, debuggingFlag bool, composeFiles []string, projectDir string, runtime string) (*AppConfig, error) { configDir, err := findOrCreateConfigDir(name) if err != nil { return nil, err @@ -507,6 +527,11 @@ func NewAppConfig(name, version, commit, date string, buildSource string, debugg userConfig.CommandTemplates.DockerCompose += " -f " + strings.Join(composeFiles, " -f ") } + // Validate runtime parameter + if runtime != "docker" && runtime != "apple" { + return nil, fmt.Errorf("unsupported runtime '%s'. Supported runtimes: docker, apple", runtime) + } + appConfig := &AppConfig{ Name: name, Version: version, @@ -514,6 +539,7 @@ func NewAppConfig(name, version, commit, date string, buildSource string, debugg BuildDate: date, Debug: debuggingFlag || os.Getenv("DEBUG") == "TRUE", BuildSource: buildSource, + Runtime: runtime, UserConfig: userConfig, ConfigDir: configDir, ProjectDir: projectDir, diff --git a/pkg/config/app_config_test.go b/pkg/config/app_config_test.go index 5e7c2922..0f3f8846 100644 --- a/pkg/config/app_config_test.go +++ b/pkg/config/app_config_test.go @@ -9,7 +9,7 @@ import ( func TestDockerComposeCommandNoFiles(t *testing.T) { composeFiles := []string{} - conf, err := NewAppConfig("name", "version", "commit", "date", "buildSource", false, composeFiles, "projectDir") + conf, err := NewAppConfig("name", "version", "commit", "date", "buildSource", false, composeFiles, "projectDir", "docker") if err != nil { t.Fatalf("Unexpected error: %s", err) } @@ -23,7 +23,7 @@ func TestDockerComposeCommandNoFiles(t *testing.T) { func TestDockerComposeCommandSingleFile(t *testing.T) { composeFiles := []string{"one.yml"} - conf, err := NewAppConfig("name", "version", "commit", "date", "buildSource", false, composeFiles, "projectDir") + conf, err := NewAppConfig("name", "version", "commit", "date", "buildSource", false, composeFiles, "projectDir", "docker") if err != nil { t.Fatalf("Unexpected error: %s", err) } @@ -37,7 +37,7 @@ func TestDockerComposeCommandSingleFile(t *testing.T) { func TestDockerComposeCommandMultipleFiles(t *testing.T) { composeFiles := []string{"one.yml", "two.yml", "three.yml"} - conf, err := NewAppConfig("name", "version", "commit", "date", "buildSource", false, composeFiles, "projectDir") + conf, err := NewAppConfig("name", "version", "commit", "date", "buildSource", false, composeFiles, "projectDir", "docker") if err != nil { t.Fatalf("Unexpected error: %s", err) } @@ -52,7 +52,7 @@ func TestDockerComposeCommandMultipleFiles(t *testing.T) { func TestWritingToConfigFile(t *testing.T) { // init the AppConfig emptyComposeFiles := []string{} - conf, err := NewAppConfig("name", "version", "commit", "date", "buildSource", false, emptyComposeFiles, "projectDir") + conf, err := NewAppConfig("name", "version", "commit", "date", "buildSource", false, emptyComposeFiles, "projectDir", "docker") if err != nil { t.Fatalf("Unexpected error: %s", err) } @@ -96,3 +96,76 @@ func TestWritingToConfigFile(t *testing.T) { // modifying an existing file that already has 'ConfirmOnQuit' testFn(t, conf, false) } + +// Test runtime parameter validation and configuration +func TestRuntimeValidation(t *testing.T) { + composeFiles := []string{} + + // Test valid docker runtime + conf, err := NewAppConfig("name", "version", "commit", "date", "buildSource", false, composeFiles, "projectDir", "docker") + if err != nil { + t.Fatalf("Unexpected error for docker runtime: %s", err) + } + if conf.Runtime != "docker" { + t.Fatalf("Expected runtime 'docker' but got '%s'", conf.Runtime) + } + + // Test valid apple runtime + conf, err = NewAppConfig("name", "version", "commit", "date", "buildSource", false, composeFiles, "projectDir", "apple") + if err != nil { + t.Fatalf("Unexpected error for apple runtime: %s", err) + } + if conf.Runtime != "apple" { + t.Fatalf("Expected runtime 'apple' but got '%s'", conf.Runtime) + } + + // Test invalid runtime + _, err = NewAppConfig("name", "version", "commit", "date", "buildSource", false, composeFiles, "projectDir", "invalid") + if err == nil { + t.Fatalf("Expected error for invalid runtime but got none") + } + expectedError := "unsupported runtime 'invalid'. Supported runtimes: docker, apple" + if err.Error() != expectedError { + t.Fatalf("Expected error '%s' but got '%s'", expectedError, err.Error()) + } +} + +func TestRuntimeConfigurationDefaults(t *testing.T) { + composeFiles := []string{} + + // Test docker runtime gets correct defaults + conf, err := NewAppConfig("name", "version", "commit", "date", "buildSource", false, composeFiles, "projectDir", "docker") + if err != nil { + t.Fatalf("Unexpected error: %s", err) + } + + // Docker runtime should have normal docker-compose command + expected := "docker compose" + actual := conf.UserConfig.CommandTemplates.DockerCompose + if actual != expected { + t.Fatalf("Expected DockerCompose command '%s' but got '%s'", expected, actual) + } +} + +func TestRuntimeFieldInAppConfig(t *testing.T) { + composeFiles := []string{} + + testCases := []struct { + runtime string + expected string + }{ + {"docker", "docker"}, + {"apple", "apple"}, + } + + for _, tc := range testCases { + conf, err := NewAppConfig("name", "version", "commit", "date", "buildSource", false, composeFiles, "projectDir", tc.runtime) + if err != nil { + t.Fatalf("Unexpected error for runtime '%s': %s", tc.runtime, err) + } + + if conf.Runtime != tc.expected { + t.Fatalf("Expected Runtime field '%s' but got '%s'", tc.expected, conf.Runtime) + } + } +} diff --git a/pkg/gui/container_logs.go b/pkg/gui/container_logs.go index bdb81608..6ac5b531 100644 --- a/pkg/gui/container_logs.go +++ b/pkg/gui/container_logs.go @@ -9,6 +9,7 @@ import ( "time" "github.com/docker/docker/api/types/container" + "github.com/docker/docker/client" "github.com/docker/docker/pkg/stdcopy" "github.com/fatih/color" "github.com/jesseduffield/lazydocker/pkg/commands" @@ -105,7 +106,16 @@ func (gui *Gui) promptToReturn() { } func (gui *Gui) writeContainerLogs(ctr *commands.Container, ctx context.Context, writer io.Writer) error { - readCloser, err := gui.DockerCommand.Client.ContainerLogs(ctx, ctr.ID, container.LogsOptions{ + clientInterface := gui.ContainerCommand.GetClient() + if clientInterface == nil { + // Handle Apple Container logs + if gui.ContainerCommand.GetRuntimeName() == "apple" { + return gui.writeAppleContainerLogs(ctr, ctx, writer) + } + return fmt.Errorf("container logs not supported for %s runtime", gui.ContainerCommand.GetRuntimeName()) + } + dockerClient := clientInterface.(*client.Client) + readCloser, err := dockerClient.ContainerLogs(ctx, ctr.ID, container.LogsOptions{ ShowStdout: true, ShowStderr: true, Timestamps: gui.Config.UserConfig.Logs.Timestamps, @@ -150,3 +160,40 @@ func (gui *Gui) writeContainerLogs(ctr *commands.Container, ctx context.Context, return nil } + +func (gui *Gui) writeAppleContainerLogs(ctr *commands.Container, ctx context.Context, writer io.Writer) error { + // Get the AppleContainerCommand from the DockerCommand interface + appleCmd, ok := ctr.DockerCommand.(*commands.AppleContainerCommand) + if !ok { + return fmt.Errorf("invalid container command type for Apple runtime") + } + + // Get the logs command + cmd := appleCmd.GetContainerLogs(ctr.ID, true, gui.Config.UserConfig.Logs.Tail) + + // Set up the command with proper context + cmd.Stdout = writer + cmd.Stderr = writer + + // Start the command + if err := cmd.Start(); err != nil { + return err + } + + // Wait for context cancellation or command completion + done := make(chan error, 1) + go func() { + done <- cmd.Wait() + }() + + select { + case <-ctx.Done(): + // Context cancelled, kill the process + if cmd.Process != nil { + cmd.Process.Kill() + } + return ctx.Err() + case err := <-done: + return err + } +} diff --git a/pkg/gui/containers_panel.go b/pkg/gui/containers_panel.go index 92aa95b3..32e3a699 100644 --- a/pkg/gui/containers_panel.go +++ b/pkg/gui/containers_panel.go @@ -34,33 +34,55 @@ func (gui *Gui) getContainersPanel() *panels.SideListPanel[*commands.Container] return &panels.SideListPanel[*commands.Container]{ ContextState: &panels.ContextState[*commands.Container]{ GetMainTabs: func() []panels.MainTab[*commands.Container] { - return []panels.MainTab[*commands.Container]{ + tabs := []panels.MainTab[*commands.Container]{ { Key: "logs", Title: gui.Tr.LogsTitle, Render: gui.renderContainerLogsToMain, }, - { + } + + // Add runtime-specific tabs + if !gui.ContainerCommand.Supports(commands.FeatureStats) { + // When stats are not supported (e.g. Apple), show a Volumes tab instead + tabs = append(tabs, panels.MainTab[*commands.Container]{ + Key: "volumes", + Title: "Volumes", + Render: gui.renderContainerVolumesToMain, + }) + } else { + // Runtime supports live stats (Docker) + tabs = append(tabs, panels.MainTab[*commands.Container]{ Key: "stats", Title: gui.Tr.StatsTitle, Render: gui.renderContainerStats, - }, - { + }) + } + + // Common tabs for all runtimes + tabs = append(tabs, + panels.MainTab[*commands.Container]{ Key: "env", Title: gui.Tr.EnvTitle, Render: gui.renderContainerEnv, }, - { + panels.MainTab[*commands.Container]{ Key: "config", Title: gui.Tr.ConfigTitle, Render: gui.renderContainerConfig, }, - { + ) + + // Only add Top tab if supported by runtime + if gui.ContainerCommand.Supports(commands.FeatureContainerTop) { + tabs = append(tabs, panels.MainTab[*commands.Container]{ Key: "top", Title: gui.Tr.TopTitle, Render: gui.renderContainerTop, - }, + }) } + + return tabs }, GetItemContextCacheKey: func(container *commands.Container) string { // Including the container state in the cache key so that if the container @@ -97,7 +119,17 @@ func (gui *Gui) getContainersPanel() *panels.SideListPanel[*commands.Container] return true }, GetTableCells: func(container *commands.Container) []string { - return presentation.GetContainerDisplayStrings(&gui.Config.UserConfig.Gui, container) + runtime := gui.ContainerCommand.GetRuntimeName() + return presentation.GetContainerDisplayStrings(&gui.Config.UserConfig.Gui, container, runtime) + }, + GetTableHeaders: func() []string { + runtime := gui.ContainerCommand.GetRuntimeName() + // Columns: STATUS, SUB, NAME, CPU, ADDR (apple only), PORTS, IMAGE + addr := "" + if runtime == "apple" { + addr = "ADDR" + } + return []string{"STATUS", "", "NAME", "CPU", addr, "PORTS", "IMAGE"} }, } } @@ -255,7 +287,7 @@ func (gui *Gui) refreshContainersAndServices() error { originalSelectedLineIdx := gui.Panels.Services.SelectedIdx selectedService, isServiceSelected := gui.Panels.Services.List.TryGet(originalSelectedLineIdx) - containers, services, err := gui.DockerCommand.RefreshContainersAndServices( + containers, services, err := gui.ContainerCommand.RefreshContainersAndServices( gui.Panels.Services.List.GetAllItems(), gui.Panels.Containers.List.GetAllItems(), ) @@ -283,7 +315,7 @@ func (gui *Gui) refreshContainersAndServices() error { } func (gui *Gui) renderContainersAndServices() error { - if gui.DockerCommand.InDockerComposeProject { + if gui.ContainerCommand.InDockerComposeProject() { if err := gui.Panels.Services.RerenderList(); err != nil { return err } @@ -325,13 +357,21 @@ func (gui *Gui) handleContainersRemoveMenu(g *gocui.Gui, v *gocui.View) error { }) } + runtimeName := gui.ContainerCommand.GetRuntimeName() + rmCmd := "docker rm " + ctr.ID[1:10] + rmVolCmd := "docker rm --volumes " + ctr.ID[1:10] + if runtimeName == "apple" { + rmCmd = "container rm " + ctr.ID + rmVolCmd = "container rm --force " + ctr.ID // Apple CLI may not support --volumes; show force + } + menuItems := []*types.MenuItem{ { - LabelColumns: []string{gui.Tr.Remove, "docker rm " + ctr.ID[1:10]}, + LabelColumns: []string{gui.Tr.Remove, rmCmd}, OnPress: func() error { return handleMenuPress(container.RemoveOptions{}) }, }, { - LabelColumns: []string{gui.Tr.RemoveWithVolumes, "docker rm --volumes " + ctr.ID[1:10]}, + LabelColumns: []string{gui.Tr.RemoveWithVolumes, rmVolCmd}, OnPress: func() error { return handleMenuPress(container.RemoveOptions{RemoveVolumes: true}) }, }, } @@ -414,9 +454,12 @@ func (gui *Gui) handleContainerAttach(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handlePruneContainers() error { + if gui.ContainerCommand != nil && !gui.ContainerCommand.Supports(commands.FeatureContainerPrune) { + return gui.createErrorPanel("Container pruning is not supported by the current container runtime.") + } return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmPruneContainers, func(g *gocui.Gui, v *gocui.View) error { return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error { - err := gui.DockerCommand.PruneContainers() + err := gui.ContainerCommand.PruneContainers() if err != nil { return gui.createErrorPanel(err.Error()) } @@ -446,13 +489,24 @@ func (gui *Gui) handleContainersExecShell(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) containerExecShell(container *commands.Container) error { - commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{ + // Use appropriate exec based on runtime capability + if gui.ContainerCommand.Supports(commands.FeatureContainerExec) && gui.ContainerCommand.GetRuntimeName() == "apple" { + // Prefer a simple interactive shell for Apple Container + resolved := fmt.Sprintf("container exec -it %s /bin/sh", container.ID) + // Optionally forward SSH agent when supported and enabled + if gui.Config.UserConfig.Apple != nil && gui.Config.UserConfig.Apple.ForwardSSHAgent && gui.ContainerCommand.Supports(commands.FeatureSSHAgentForward) { + resolved = fmt.Sprintf("container exec --ssh -it %s /bin/sh", container.ID) + } + cmd := gui.OSCommand.ExecutableFromString(resolved) + return gui.runSubprocess(cmd) + } + + commandObject := gui.ContainerCommand.NewCommandObject(commands.CommandObject{ Container: container, }) - // TODO: use SDK + // Docker runtime resolvedCommand := utils.ApplyTemplate("docker exec -it {{ .Container.ID }} /bin/sh -c 'eval $(grep ^$(id -un): /etc/passwd | cut -d : -f 7-)'", commandObject) - // attach and return the subprocess error cmd := gui.OSCommand.ExecutableFromString(resolvedCommand) return gui.runSubprocess(cmd) } @@ -463,7 +517,7 @@ func (gui *Gui) handleContainersCustomCommand(g *gocui.Gui, v *gocui.View) error return nil } - commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{ + commandObject := gui.ContainerCommand.NewCommandObject(commands.CommandObject{ Container: ctr, }) @@ -502,22 +556,18 @@ func (gui *Gui) handleRemoveContainers() error { func (gui *Gui) handleContainersBulkCommand(g *gocui.Gui, v *gocui.View) error { baseBulkCommands := []config.CustomCommand{ - { - Name: gui.Tr.StopAllContainers, - InternalFunction: gui.handleStopContainers, - }, - { - Name: gui.Tr.RemoveAllContainers, - InternalFunction: gui.handleRemoveContainers, - }, - { + {Name: gui.Tr.StopAllContainers, InternalFunction: gui.handleStopContainers}, + {Name: gui.Tr.RemoveAllContainers, InternalFunction: gui.handleRemoveContainers}, + } + if gui.ContainerCommand == nil || gui.ContainerCommand.Supports(commands.FeatureContainerPrune) { + baseBulkCommands = append(baseBulkCommands, config.CustomCommand{ // show only if supported Name: gui.Tr.PruneContainers, InternalFunction: gui.handlePruneContainers, - }, + }) } bulkCommands := append(baseBulkCommands, gui.Config.UserConfig.BulkCommands.Containers...) - commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{}) + commandObject := gui.ContainerCommand.NewCommandObject(commands.CommandObject{}) return gui.createBulkCommandMenu(bulkCommands, commandObject) } @@ -549,3 +599,29 @@ func (gui *Gui) openContainerInBrowser(ctr *commands.Container) error { link := fmt.Sprintf("http://%s:%d/", ip, port.PublicPort) return gui.OSCommand.OpenLink(link) } + +// renderContainerVolumesToMain renders the container's volume/mount information for Apple runtime +func (gui *Gui) renderContainerVolumesToMain(container *commands.Container) tasks.TaskFunc { + return gui.NewTickerTask(TickerTaskOpts{ + Func: func(ctx context.Context, notifyStopped chan struct{}) { + // Get the container's mount information from Apple Container + if container.DockerCommand != nil { + if appleCmd, ok := container.DockerCommand.(*commands.AppleContainerCommand); ok { + mountInfo, err := appleCmd.GetContainerMounts(container.ID) + if err != nil { + gui.reRenderStringMain(fmt.Sprintf("Error getting mount information: %v", err)) + return + } + gui.reRenderStringMain(mountInfo) + return + } + } + + gui.reRenderStringMain("Volume information not available") + }, + Duration: time.Hour, // Don't refresh automatically since mounts don't change + Before: func(ctx context.Context) { gui.clearMainView() }, + Wrap: false, + Autoscroll: false, + }) +} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index fa6199f3..ccc34bb4 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -7,6 +7,7 @@ import ( "time" "github.com/docker/docker/api/types/events" + "github.com/docker/docker/client" "github.com/go-errors/errors" @@ -25,17 +26,18 @@ import ( // Gui wraps the gocui Gui object which handles rendering and events type Gui struct { - g *gocui.Gui - Log *logrus.Entry - DockerCommand *commands.DockerCommand - OSCommand *commands.OSCommand - State guiState - Config *config.AppConfig - Tr *i18n.TranslationSet - statusManager *statusManager - taskManager *tasks.TaskManager - ErrorChan chan error - Views Views + g *gocui.Gui + Log *logrus.Entry + DockerCommand *commands.DockerCommand + ContainerCommand *commands.GuiContainerCommand + OSCommand *commands.OSCommand + State guiState + Config *config.AppConfig + Tr *i18n.TranslationSet + statusManager *statusManager + taskManager *tasks.TaskManager + ErrorChan chan error + Views Views // if we've suspended the gui (e.g. because we've switched to a subprocess) // we typically want to pause some things that are running like background @@ -125,7 +127,7 @@ func getScreenMode(config *config.AppConfig) WindowMaximisation { } // NewGui builds a new gui handler -func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand *commands.OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*Gui, error) { +func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, containerCommand *commands.GuiContainerCommand, oSCommand *commands.OSCommand, tr *i18n.TranslationSet, config *config.AppConfig, errorChan chan error) (*Gui, error) { initialState := guiState{ Platform: *oSCommand.Platform, Panels: &panelStates{ @@ -140,15 +142,16 @@ func NewGui(log *logrus.Entry, dockerCommand *commands.DockerCommand, oSCommand } gui := &Gui{ - Log: log, - DockerCommand: dockerCommand, - OSCommand: oSCommand, - State: initialState, - Config: config, - Tr: tr, - statusManager: &statusManager{}, - taskManager: tasks.NewTaskManager(log, tr), - ErrorChan: errorChan, + Log: log, + DockerCommand: dockerCommand, + ContainerCommand: containerCommand, + OSCommand: oSCommand, + State: initialState, + Config: config, + Tr: tr, + statusManager: &statusManager{}, + taskManager: tasks.NewTaskManager(log, tr), + ErrorChan: errorChan, } deadlock.Opts.Disable = !gui.Config.Debug @@ -292,7 +295,9 @@ func (gui *Gui) setPanels() { } func (gui *Gui) updateContainerDetails() error { - return gui.DockerCommand.RefreshContainerDetails(gui.Panels.Containers.List.GetAllItems()) + containers := gui.Panels.Containers.List.GetAllItems() + _, _, err := gui.ContainerCommand.RefreshContainersAndServices(gui.Panels.Services.List.GetAllItems(), containers) + return err } func (gui *Gui) refresh() { @@ -336,7 +341,18 @@ func (gui *Gui) listenForEvents(ctx context.Context, refresh func()) { outer: for { - messageChan, errChan := gui.DockerCommand.Client.Events(context.Background(), events.ListOptions{}) + // Event monitoring is runtime-dependent + if !gui.ContainerCommand.Supports(commands.FeatureEventsStream) { + // No event stream for this runtime; exit listener + return + } + + clientInterface := gui.ContainerCommand.GetClient() + if clientInterface == nil { + return + } + dockerClient := clientInterface.(*client.Client) + messageChan, errChan := dockerClient.Events(context.Background(), events.ListOptions{}) if errorCount > 0 { select { @@ -459,7 +475,7 @@ func (gui *Gui) ShouldRefresh(key string) bool { } func (gui *Gui) initiallyFocusedViewName() string { - if gui.DockerCommand.InDockerComposeProject { + if gui.ContainerCommand.InDockerComposeProject() { return "services" } return "containers" @@ -485,7 +501,7 @@ func (gui *Gui) monitorContainerStats(ctx context.Context) { case <-ticker.C: for _, container := range gui.Panels.Containers.List.GetAllItems() { if !container.MonitoringStats { - go gui.DockerCommand.CreateClientStatMonitor(container) + go gui.ContainerCommand.CreateClientStatMonitor(container) } } } diff --git a/pkg/gui/gui_test.go b/pkg/gui/gui_test.go new file mode 100644 index 00000000..6fe9f78a --- /dev/null +++ b/pkg/gui/gui_test.go @@ -0,0 +1,104 @@ +package gui + +import ( + "testing" + + "github.com/jesseduffield/lazydocker/pkg/commands" + "github.com/jesseduffield/lazydocker/pkg/config" + "github.com/jesseduffield/lazydocker/pkg/i18n" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" +) + +func TestNewGuiWithContainerCommand(t *testing.T) { + // Create test dependencies + log := logrus.NewEntry(logrus.New()) + osCommand := commands.NewOSCommand(log, &config.AppConfig{}) + tr := &i18n.TranslationSet{} + errorChan := make(chan error) + + tests := []struct { + name string + runtime string + expectError bool + }{ + { + name: "docker runtime", + runtime: "docker", + expectError: false, + }, + { + name: "apple runtime", + runtime: "apple", + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create app config + appConfig, err := config.NewAppConfig( + "lazydocker", + "test-version", + "test-commit", + "test-date", + "test-build-source", + false, + []string{}, + "/tmp", + tt.runtime, + ) + assert.Nil(t, err) + + // Create mock container runtime + containerRuntime := commands.NewContainerRuntimeAdapter(nil, nil, tt.runtime) + containerCommand := commands.NewGuiContainerCommand(containerRuntime, nil, appConfig) + + // Create GUI + gui, err := NewGui(log, nil, containerCommand, osCommand, tr, appConfig, errorChan) + + if tt.expectError { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + assert.NotNil(t, gui) + assert.Equal(t, containerCommand, gui.ContainerCommand) + assert.Equal(t, appConfig, gui.Config) + } + }) + } +} + +func TestGuiContainerCommandIntegration(t *testing.T) { + // Test that GUI can use ContainerCommand methods + appConfig, err := config.NewAppConfig( + "lazydocker", + "test-version", + "test-commit", + "test-date", + "test-build-source", + false, + []string{}, + "/tmp", + "docker", + ) + assert.Nil(t, err) + + // Create mock runtime adapter + containerRuntime := &commands.ContainerRuntimeAdapter{} + containerCommand := commands.NewGuiContainerCommand(containerRuntime, nil, appConfig) + + // Test runtime name + assert.Equal(t, "", containerCommand.GetRuntimeName()) // Empty because we didn't set runtimeType + + // Test that methods don't panic when called with nil internals + containers, err := containerCommand.GetContainers(nil) + assert.NotNil(t, err) // Should error because runtime is not properly initialized + assert.Nil(t, containers) + + // Test InDockerComposeProject + assert.False(t, containerCommand.InDockerComposeProject()) + + // Test DockerComposeConfig + assert.Empty(t, containerCommand.DockerComposeConfig()) +} diff --git a/pkg/gui/images_panel.go b/pkg/gui/images_panel.go index 7b0d5643..91421e1a 100644 --- a/pkg/gui/images_panel.go +++ b/pkg/gui/images_panel.go @@ -80,11 +80,20 @@ func (gui *Gui) imageConfigStr(image *commands.Image) string { output += utils.WithPadding("ID: ", padding) + image.Image.ID + "\n" output += utils.WithPadding("Tags: ", padding) + utils.ColoredString(strings.Join(image.Image.RepoTags, ", "), color.FgGreen) + "\n" output += utils.WithPadding("Size: ", padding) + utils.FormatDecimalBytes(int(image.Image.Size)) + "\n" - output += utils.WithPadding("Created: ", padding) + fmt.Sprintf("%v", time.Unix(image.Image.Created, 0).Format(time.RFC1123)) + "\n" + created := "n/a" + if image.Image.Created != 0 { + created = fmt.Sprintf("%v", time.Unix(image.Image.Created, 0).Format(time.RFC1123)) + } + output += utils.WithPadding("Created: ", padding) + created + "\n" history, err := image.RenderHistory() if err != nil { gui.Log.Error(err) + if gui.ContainerCommand != nil && !gui.ContainerCommand.Supports(commands.FeatureImageHistory) { + history = "History not available for Apple Container runtime" + } else { + history = "History unavailable: " + err.Error() + } } output += "\n\n" + history @@ -101,7 +110,7 @@ func (gui *Gui) reloadImages() error { } func (gui *Gui) refreshStateImages() error { - images, err := gui.DockerCommand.RefreshImages() + images, err := gui.ContainerCommand.RefreshImages() if err != nil { return err } @@ -131,6 +140,11 @@ func (gui *Gui) handleImagesRemoveMenu(g *gocui.Gui, v *gocui.View) error { return nil } + // Apple Container runtime: image removal not yet supported via our adapter + if gui.ContainerCommand != nil && !gui.ContainerCommand.Supports(commands.FeatureImageRemove) { + return gui.createErrorPanel("Image removal is not available in the Apple Container runtime from LazyDocker yet.") + } + shortSha := img.ID[7:17] // TODO: have a way of toggling in a menu instead of showing each permutation as a separate menu item @@ -180,9 +194,12 @@ func (gui *Gui) handleImagesRemoveMenu(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handlePruneImages() error { + if gui.ContainerCommand != nil && !gui.ContainerCommand.Supports(commands.FeatureImagePrune) { + return gui.createErrorPanel("Image pruning is not supported by the current container runtime.") + } return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmPruneImages, func(g *gocui.Gui, v *gocui.View) error { return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error { - err := gui.DockerCommand.PruneImages() + err := gui.ContainerCommand.PruneImages() if err != nil { return gui.createErrorPanel(err.Error()) } @@ -197,7 +214,7 @@ func (gui *Gui) handleImagesCustomCommand(g *gocui.Gui, v *gocui.View) error { return nil } - commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{ + commandObject := gui.ContainerCommand.NewCommandObject(commands.CommandObject{ Image: img, }) @@ -207,15 +224,16 @@ func (gui *Gui) handleImagesCustomCommand(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleImagesBulkCommand(g *gocui.Gui, v *gocui.View) error { - baseBulkCommands := []config.CustomCommand{ - { + baseBulkCommands := []config.CustomCommand{} + if gui.ContainerCommand == nil || gui.ContainerCommand.Supports(commands.FeatureImagePrune) { + baseBulkCommands = append(baseBulkCommands, config.CustomCommand{ Name: gui.Tr.PruneImages, InternalFunction: gui.handlePruneImages, - }, + }) } bulkCommands := append(baseBulkCommands, gui.Config.UserConfig.BulkCommands.Images...) - commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{}) + commandObject := gui.ContainerCommand.NewCommandObject(commands.CommandObject{}) return gui.createBulkCommandMenu(bulkCommands, commandObject) } diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index df706024..c1ca426f 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazydocker/pkg/commands" ) // Binding - a keybinding mapping a key and modifier to a handler. The keypress @@ -220,13 +221,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { Handler: gui.handleContainerRestart, Description: gui.Tr.Restart, }, - { - ViewName: "containers", - Key: 'a', - Modifier: gocui.ModNone, - Handler: gui.handleContainerAttach, - Description: gui.Tr.Attach, - }, + // container attach: added conditionally below based on runtime support { ViewName: "containers", Key: 'm', @@ -304,13 +299,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { Handler: gui.handleServiceStart, Description: gui.Tr.Start, }, - { - ViewName: "services", - Key: 'a', - Modifier: gocui.ModNone, - Handler: gui.handleServiceAttach, - Description: gui.Tr.Attach, - }, + // service attach: added conditionally below based on runtime support { ViewName: "services", Key: 'm', @@ -395,6 +384,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { Handler: gui.handleVolumesCustomCommand, Description: gui.Tr.RunCustomCommand, }, + // Create volume binding will be added conditionally below based on capability { ViewName: "volumes", Key: 'd', @@ -511,6 +501,21 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { }, } + // Conditionally add attach bindings if supported by runtime + if gui.ContainerCommand == nil || gui.ContainerCommand.Supports(commands.FeatureContainerAttach) { + bindings = append(bindings, + &Binding{ViewName: "containers", Key: 'a', Modifier: gocui.ModNone, Handler: gui.handleContainerAttach, Description: gui.Tr.Attach}, + &Binding{ViewName: "services", Key: 'a', Modifier: gocui.ModNone, Handler: gui.handleServiceAttach, Description: gui.Tr.Attach}, + ) + } + + // Conditionally add create-volume binding if supported + if gui.ContainerCommand == nil || gui.ContainerCommand.Supports(commands.FeatureVolumeCreate) { + bindings = append(bindings, + &Binding{ViewName: "volumes", Key: 'n', Modifier: gocui.ModNone, Handler: gui.handleCreateVolume, Description: "Create Volume"}, + ) + } + for _, panel := range gui.allSidePanels() { bindings = append(bindings, []*Binding{ {ViewName: panel.GetView().Name(), Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: gui.previousView}, diff --git a/pkg/gui/networks_panel.go b/pkg/gui/networks_panel.go index 4702d35d..7e6af259 100644 --- a/pkg/gui/networks_panel.go +++ b/pkg/gui/networks_panel.go @@ -89,7 +89,7 @@ func (gui *Gui) reloadNetworks() error { } func (gui *Gui) refreshStateNetworks() error { - networks, err := gui.DockerCommand.RefreshNetworks() + networks, err := gui.ContainerCommand.RefreshNetworks() if err != nil { return err } @@ -110,10 +110,16 @@ func (gui *Gui) handleNetworksRemoveMenu(g *gocui.Gui, v *gocui.View) error { command string } + runtimeName := gui.ContainerCommand.GetRuntimeName() + rmCmd := utils.WithShortSha("docker network rm " + network.Name) + if runtimeName == "apple" { + rmCmd = utils.WithShortSha("container network rm " + network.Name) + } + options := []*removeNetworkOption{ { description: gui.Tr.Remove, - command: utils.WithShortSha("docker network rm " + network.Name), + command: rmCmd, }, } @@ -138,9 +144,12 @@ func (gui *Gui) handleNetworksRemoveMenu(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handlePruneNetworks() error { + if gui.ContainerCommand != nil && !gui.ContainerCommand.Supports(commands.FeatureNetworkPrune) { + return gui.createErrorPanel("Network pruning is not supported by the current container runtime.") + } return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmPruneNetworks, func(g *gocui.Gui, v *gocui.View) error { return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error { - err := gui.DockerCommand.PruneNetworks() + err := gui.ContainerCommand.PruneNetworks() if err != nil { return gui.createErrorPanel(err.Error()) } @@ -155,7 +164,7 @@ func (gui *Gui) handleNetworksCustomCommand(g *gocui.Gui, v *gocui.View) error { return nil } - commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{ + commandObject := gui.ContainerCommand.NewCommandObject(commands.CommandObject{ Network: network, }) @@ -165,15 +174,16 @@ func (gui *Gui) handleNetworksCustomCommand(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleNetworksBulkCommand(g *gocui.Gui, v *gocui.View) error { - baseBulkCommands := []config.CustomCommand{ - { + baseBulkCommands := []config.CustomCommand{} + if gui.ContainerCommand == nil || gui.ContainerCommand.Supports(commands.FeatureNetworkPrune) { + baseBulkCommands = append(baseBulkCommands, config.CustomCommand{ Name: gui.Tr.PruneNetworks, InternalFunction: gui.handlePruneNetworks, - }, + }) } bulkCommands := append(baseBulkCommands, gui.Config.UserConfig.BulkCommands.Networks...) - commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{}) + commandObject := gui.ContainerCommand.NewCommandObject(commands.CommandObject{}) return gui.createBulkCommandMenu(bulkCommands, commandObject) } diff --git a/pkg/gui/panels/side_list_panel.go b/pkg/gui/panels/side_list_panel.go index 2473e2ce..f66d59d4 100644 --- a/pkg/gui/panels/side_list_panel.go +++ b/pkg/gui/panels/side_list_panel.go @@ -29,7 +29,7 @@ type ISideListPanel interface { // list panel at the side of the screen that renders content to the main panel type SideListPanel[T comparable] struct { - ContextState *ContextState[T] + ContextState *ContextState[T] ListPanel[T] @@ -47,9 +47,14 @@ type SideListPanel[T comparable] struct { // a callback to invoke when the item is clicked OnClick func(T) error - // returns the cells that we render to the view in a table format. The cells will - // be rendered with padding. - GetTableCells func(T) []string + // returns the cells that we render to the view in a table format. The cells will + // be rendered with padding. + GetTableCells func(T) []string + + // optional: returns a header row to render above the list. If nil, no header + // row is rendered. When provided, the returned slice length must match + // GetTableCells(T) length. + GetTableHeaders func() []string // function to be called after re-rendering list. Can be nil OnRerender func() error @@ -222,18 +227,26 @@ func (self *SideListPanel[T]) FilterAndSort() { } func (self *SideListPanel[T]) RerenderList() error { - self.FilterAndSort() + self.FilterAndSort() - self.Gui.Update(func() error { - self.View.Clear() - table := lo.Map(self.List.GetItems(), func(item T, index int) []string { - return self.GetTableCells(item) - }) - renderedTable, err := utils.RenderTable(table) - if err != nil { - return err - } - fmt.Fprint(self.View, renderedTable) + self.Gui.Update(func() error { + self.View.Clear() + var table [][]string + if self.GetTableHeaders != nil { + headers := self.GetTableHeaders() + if headers != nil && len(headers) > 0 { + table = append(table, headers) + } + } + body := lo.Map(self.List.GetItems(), func(item T, index int) []string { + return self.GetTableCells(item) + }) + table = append(table, body...) + renderedTable, err := utils.RenderTable(table) + if err != nil { + return err + } + fmt.Fprint(self.View, renderedTable) if self.OnRerender != nil { if err := self.OnRerender(); err != nil { diff --git a/pkg/gui/presentation/containers.go b/pkg/gui/presentation/containers.go index f58fc706..6462787d 100644 --- a/pkg/gui/presentation/containers.go +++ b/pkg/gui/presentation/containers.go @@ -14,15 +14,24 @@ import ( "github.com/samber/lo" ) -func GetContainerDisplayStrings(guiConfig *config.GuiConfig, container *commands.Container) []string { - return []string{ +func GetContainerDisplayStrings(guiConfig *config.GuiConfig, container *commands.Container, runtime string) []string { + cols := []string{ getContainerDisplayStatus(guiConfig, container), getContainerDisplaySubstatus(guiConfig, container), container.Name, getDisplayCPUPerc(container), + } + // Show ADDR for Apple runtime if available + if runtime == "apple" && container.Addr != "" { + cols = append(cols, utils.ColoredString(container.Addr, color.FgCyan)) + } else { + cols = append(cols, "") + } + cols = append(cols, utils.ColoredString(displayPorts(container), color.FgYellow), utils.ColoredString(displayContainerImage(container), color.FgMagenta), - } + ) + return cols } func displayContainerImage(container *commands.Container) string { diff --git a/pkg/gui/presentation/containers_test.go b/pkg/gui/presentation/containers_test.go new file mode 100644 index 00000000..8b040646 --- /dev/null +++ b/pkg/gui/presentation/containers_test.go @@ -0,0 +1,112 @@ +package presentation + +import ( + "testing" + + "github.com/jesseduffield/lazydocker/pkg/commands" + "github.com/jesseduffield/lazydocker/pkg/config" + "github.com/stretchr/testify/assert" + + dockerTypes "github.com/docker/docker/api/types" +) + +func TestGetContainerDisplayStringsWithRuntime(t *testing.T) { + guiConfig := &config.GuiConfig{ + ContainerStatusHealthStyle: "long", + } + + container := &commands.Container{ + Name: "test-container", + ID: "abc123", + Container: dockerTypes.Container{ + State: "running", + Image: "nginx:latest", + Ports: []dockerTypes.Port{}, + }, + } + + tests := []struct { + name string + runtime string + expectedIndicator string + }{ + { + name: "docker runtime", + runtime: "docker", + expectedIndicator: "test-container", + }, + { + name: "apple runtime", + runtime: "apple", + expectedIndicator: "test-container", + }, + { + name: "unknown runtime", + runtime: "unknown", + expectedIndicator: "test-container", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := GetContainerDisplayStrings(guiConfig, container, tt.runtime) + + // Check that we get the expected number of columns (status, substatus, name, cpu, addr, ports, image) + assert.Len(t, result, 7) + + // Check that the container name includes the runtime indicator + assert.Equal(t, tt.expectedIndicator, result[2]) + + // Check other columns are populated + assert.Equal(t, "running", result[0]) // status + assert.NotEmpty(t, result[6]) // image + }) + } +} + +func TestGetContainerDisplayStringsWithDifferentStates(t *testing.T) { + guiConfig := &config.GuiConfig{ + ContainerStatusHealthStyle: "icon", + } + + tests := []struct { + name string + containerState string + expectedIcon string + }{ + { + name: "running container", + containerState: "running", + expectedIcon: "▶", + }, + { + name: "exited container", + containerState: "exited", + expectedIcon: "⨯", + }, + { + name: "paused container", + containerState: "paused", + expectedIcon: "◫", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + container := &commands.Container{ + Name: "test-container", + ID: "abc123", + Container: dockerTypes.Container{ + State: tt.containerState, + Image: "nginx:latest", + Ports: []dockerTypes.Port{}, + }, + } + + result := GetContainerDisplayStrings(guiConfig, container, "docker") + + // Check status icon + assert.Equal(t, tt.expectedIcon, result[0]) + }) + } +} diff --git a/pkg/gui/project_panel.go b/pkg/gui/project_panel.go index 32c5ad99..ae03958b 100644 --- a/pkg/gui/project_panel.go +++ b/pkg/gui/project_panel.go @@ -10,7 +10,6 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazydocker/pkg/commands" "github.com/jesseduffield/lazydocker/pkg/gui/panels" - "github.com/jesseduffield/lazydocker/pkg/gui/presentation" "github.com/jesseduffield/lazydocker/pkg/tasks" "github.com/jesseduffield/lazydocker/pkg/utils" "github.com/jesseduffield/yaml" @@ -23,7 +22,7 @@ func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] { return &panels.SideListPanel[*commands.Project]{ ContextState: &panels.ContextState[*commands.Project]{ GetMainTabs: func() []panels.MainTab[*commands.Project] { - if gui.DockerCommand.InDockerComposeProject { + if gui.ContainerCommand.InDockerComposeProject() { return []panels.MainTab[*commands.Project]{ { Key: "logs", @@ -35,6 +34,16 @@ func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] { Title: gui.Tr.DockerComposeConfigTitle, Render: gui.renderDockerComposeConfig, }, + { + Key: "runtime", + Title: "Runtime Info", + Render: gui.renderRuntimeInfo, + }, + { + Key: "system", + Title: "System Status", + Render: gui.renderSystemStatus, + }, { Key: "credits", Title: gui.Tr.CreditsTitle, @@ -49,6 +58,16 @@ func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] { Title: gui.Tr.CreditsTitle, Render: gui.renderCredits, }, + { + Key: "runtime", + Title: "Runtime Info", + Render: gui.renderRuntimeInfo, + }, + { + Key: "system", + Title: "System Status", + Render: gui.renderSystemStatus, + }, } }, GetItemContextCacheKey: func(project *commands.Project) string { @@ -66,7 +85,15 @@ func (gui *Gui) getProjectPanel() *panels.SideListPanel[*commands.Project] { Sort: func(a *commands.Project, b *commands.Project) bool { return false }, - GetTableCells: presentation.GetProjectDisplayStrings, + GetTableCells: func(project *commands.Project) []string { + runtimeIndicator := "" + if gui.Config.Runtime == "apple" { + runtimeIndicator = " 🍎" + } else if gui.Config.Runtime == "docker" { + runtimeIndicator = " 🐳" + } + return []string{project.Name + runtimeIndicator} + }, // It doesn't make sense to filter a list of only one item. DisableFilter: true, } @@ -79,7 +106,7 @@ func (gui *Gui) refreshProject() error { func (gui *Gui) getProjectName() string { projectName := path.Base(gui.Config.ProjectDir) - if gui.DockerCommand.InDockerComposeProject { + if gui.ContainerCommand.InDockerComposeProject() { for _, service := range gui.Panels.Services.List.GetAllItems() { container := service.Container if container != nil && container.DetailsLoaded() { @@ -122,7 +149,7 @@ func (gui *Gui) renderAllLogs(_project *commands.Project) tasks.TaskFunc { cmd := gui.OSCommand.RunCustomCommand( utils.ApplyTemplate( gui.Config.UserConfig.CommandTemplates.AllLogs, - gui.DockerCommand.NewCommandObject(commands.CommandObject{}), + gui.ContainerCommand.NewCommandObject(commands.CommandObject{}), ), ) @@ -146,10 +173,76 @@ func (gui *Gui) renderAllLogs(_project *commands.Project) tasks.TaskFunc { func (gui *Gui) renderDockerComposeConfig(_project *commands.Project) tasks.TaskFunc { return gui.NewSimpleRenderStringTask(func() string { - return utils.ColoredYamlString(gui.DockerCommand.DockerComposeConfig()) + return utils.ColoredYamlString(gui.ContainerCommand.DockerComposeConfig()) }) } +// renderRuntimeInfo shows the current runtime and detected capabilities +func (gui *Gui) renderRuntimeInfo(_project *commands.Project) tasks.TaskFunc { + return gui.NewSimpleRenderStringTask(func() string { return gui.runtimeInfoStr() }) +} + +// renderSystemStatus shows runtime-specific system status (Apple runtime) +func (gui *Gui) renderSystemStatus(_project *commands.Project) tasks.TaskFunc { + return gui.NewSimpleRenderStringTask(func() string { + status, err := gui.ContainerCommand.SystemStatus() + if err != nil { + return utils.ColoredString("System status unavailable: "+err.Error(), color.FgRed) + } + if len(status) == 0 { + return "No system status available for this runtime" + } + var buf bytes.Buffer + _ = yaml.NewEncoder(&buf, yaml.IncludeOmitted).Encode(status) + return utils.ColoredYamlString(buf.String()) + }) +} + +func (gui *Gui) runtimeInfoStr() string { + var b strings.Builder + runtimeName := gui.ContainerCommand.GetRuntimeName() + runtimeVersion := gui.ContainerCommand.GetRuntimeVersion() + + b.WriteString("Runtime\n=======\n\n") + b.WriteString("Name: " + runtimeName + "\n") + b.WriteString("Info: " + runtimeVersion + "\n\n") + + // Capabilities table + b.WriteString("Capabilities\n============\n\n") + rows := [][]string{{"Feature", "Supported"}} + feature := func(label string, f commands.Feature) { + ok := gui.ContainerCommand.Supports(f) + status := color.New(color.FgGreen).Sprint("yes") + if !ok { + status = color.New(color.FgRed).Sprint("no") + } + rows = append(rows, []string{label, status}) + } + + feature("Image History", commands.FeatureImageHistory) + feature("Image Remove", commands.FeatureImageRemove) + feature("Image Prune", commands.FeatureImagePrune) + feature("Container Attach", commands.FeatureContainerAttach) + feature("Container Exec", commands.FeatureContainerExec) + feature("Container Top", commands.FeatureContainerTop) + feature("Container Prune", commands.FeatureContainerPrune) + feature("Volume Prune", commands.FeatureVolumePrune) + feature("Network Prune", commands.FeatureNetworkPrune) + feature("Services/Compose", commands.FeatureServices) + feature("Events Stream", commands.FeatureEventsStream) + feature("Live Stats", commands.FeatureStats) + + table, _ := utils.RenderTable(rows) + b.WriteString(table) + b.WriteString("\n") + + b.WriteString("Notes\n=====\n") + b.WriteString("- Capabilities are detected from your local CLI (help output).\n") + b.WriteString("- If a feature appears unsupported but your CLI gained it, restart LazyDocker.\n") + + return b.String() +} + func (gui *Gui) handleOpenConfig(g *gocui.Gui, v *gocui.View) error { return gui.openFile(gui.Config.ConfigFilename()) } @@ -173,7 +266,7 @@ func lazydockerTitle() string { // handleViewAllLogs switches to a subprocess viewing all the logs from docker-compose func (gui *Gui) handleViewAllLogs(g *gocui.Gui, v *gocui.View) error { - c, err := gui.DockerCommand.ViewAllLogs() + c, err := gui.ContainerCommand.ViewAllLogs() if err != nil { return gui.createErrorPanel(err.Error()) } diff --git a/pkg/gui/services_panel.go b/pkg/gui/services_panel.go index c9dd4d1d..cd5a0a64 100644 --- a/pkg/gui/services_panel.go +++ b/pkg/gui/services_panel.go @@ -21,33 +21,20 @@ func (gui *Gui) getServicesPanel() *panels.SideListPanel[*commands.Service] { return &panels.SideListPanel[*commands.Service]{ ContextState: &panels.ContextState[*commands.Service]{ GetMainTabs: func() []panels.MainTab[*commands.Service] { - return []panels.MainTab[*commands.Service]{ - { - Key: "logs", - Title: gui.Tr.LogsTitle, - Render: gui.renderServiceLogs, - }, - { - Key: "stats", - Title: gui.Tr.StatsTitle, - Render: gui.renderServiceStats, - }, - { - Key: "container-env", - Title: gui.Tr.ContainerEnvTitle, - Render: gui.renderServiceContainerEnv, - }, - { - Key: "container-config", - Title: gui.Tr.ContainerConfigTitle, - Render: gui.renderServiceContainerConfig, - }, - { - Key: "top", - Title: gui.Tr.TopTitle, - Render: gui.renderServiceTop, - }, + tabs := []panels.MainTab[*commands.Service]{ + {Key: "logs", Title: gui.Tr.LogsTitle, Render: gui.renderServiceLogs}, } + if gui.ContainerCommand.Supports(commands.FeatureStats) { + tabs = append(tabs, panels.MainTab[*commands.Service]{Key: "stats", Title: gui.Tr.StatsTitle, Render: gui.renderServiceStats}) + } + tabs = append(tabs, + panels.MainTab[*commands.Service]{Key: "container-env", Title: gui.Tr.ContainerEnvTitle, Render: gui.renderServiceContainerEnv}, + panels.MainTab[*commands.Service]{Key: "container-config", Title: gui.Tr.ContainerConfigTitle, Render: gui.renderServiceContainerConfig}, + ) + if gui.ContainerCommand.Supports(commands.FeatureContainerTop) { + tabs = append(tabs, panels.MainTab[*commands.Service]{Key: "top", Title: gui.Tr.TopTitle, Render: gui.renderServiceTop}) + } + return tabs }, GetItemContextCacheKey: func(service *commands.Service) string { if service.Container == nil { @@ -78,7 +65,7 @@ func (gui *Gui) getServicesPanel() *panels.SideListPanel[*commands.Service] { return presentation.GetServiceDisplayStrings(&gui.Config.UserConfig.Gui, service) }, Hide: func() bool { - return !gui.DockerCommand.InDockerComposeProject + return !gui.ContainerCommand.InDockerComposeProject() }, } } @@ -292,7 +279,7 @@ func (gui *Gui) handleProjectUp(g *gocui.Gui, v *gocui.View) error { return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmUpProject, func(g *gocui.Gui, v *gocui.View) error { cmdStr := utils.ApplyTemplate( gui.Config.UserConfig.CommandTemplates.Up, - gui.DockerCommand.NewCommandObject(commands.CommandObject{}), + gui.ContainerCommand.NewCommandObject(commands.CommandObject{}), ) return gui.WithWaitingStatus(gui.Tr.UppingProjectStatus, func() error { @@ -307,12 +294,12 @@ func (gui *Gui) handleProjectUp(g *gocui.Gui, v *gocui.View) error { func (gui *Gui) handleProjectDown(g *gocui.Gui, v *gocui.View) error { downCommand := utils.ApplyTemplate( gui.Config.UserConfig.CommandTemplates.Down, - gui.DockerCommand.NewCommandObject(commands.CommandObject{}), + gui.ContainerCommand.NewCommandObject(commands.CommandObject{}), ) downWithVolumesCommand := utils.ApplyTemplate( gui.Config.UserConfig.CommandTemplates.DownWithVolumes, - gui.DockerCommand.NewCommandObject(commands.CommandObject{}), + gui.ContainerCommand.NewCommandObject(commands.CommandObject{}), ) options := []*commandOption{ @@ -363,12 +350,12 @@ func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error { rebuildCommand := utils.ApplyTemplate( gui.Config.UserConfig.CommandTemplates.RebuildService, - gui.DockerCommand.NewCommandObject(commands.CommandObject{Service: service}), + gui.ContainerCommand.NewCommandObject(commands.CommandObject{Service: service}), ) recreateCommand := utils.ApplyTemplate( gui.Config.UserConfig.CommandTemplates.RecreateService, - gui.DockerCommand.NewCommandObject(commands.CommandObject{Service: service}), + gui.ContainerCommand.NewCommandObject(commands.CommandObject{Service: service}), ) options := []*commandOption{ @@ -376,7 +363,7 @@ func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error { description: gui.Tr.Restart, command: utils.ApplyTemplate( gui.Config.UserConfig.CommandTemplates.RestartService, - gui.DockerCommand.NewCommandObject(commands.CommandObject{Service: service}), + gui.ContainerCommand.NewCommandObject(commands.CommandObject{Service: service}), ), onPress: func() error { return gui.WithWaitingStatus(gui.Tr.RestartingStatus, func() error { @@ -391,7 +378,7 @@ func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error { description: gui.Tr.Recreate, command: utils.ApplyTemplate( gui.Config.UserConfig.CommandTemplates.RecreateService, - gui.DockerCommand.NewCommandObject(commands.CommandObject{Service: service}), + gui.ContainerCommand.NewCommandObject(commands.CommandObject{Service: service}), ), onPress: func() error { return gui.WithWaitingStatus(gui.Tr.RestartingStatus, func() error { @@ -406,7 +393,7 @@ func (gui *Gui) handleServiceRestartMenu(g *gocui.Gui, v *gocui.View) error { description: gui.Tr.Rebuild, command: utils.ApplyTemplate( gui.Config.UserConfig.CommandTemplates.RebuildService, - gui.DockerCommand.NewCommandObject(commands.CommandObject{Service: service}), + gui.ContainerCommand.NewCommandObject(commands.CommandObject{Service: service}), ), onPress: func() error { return gui.runSubprocess(gui.OSCommand.RunCustomCommand(rebuildCommand)) @@ -433,7 +420,7 @@ func (gui *Gui) handleServicesCustomCommand(g *gocui.Gui, v *gocui.View) error { return nil } - commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{ + commandObject := gui.ContainerCommand.NewCommandObject(commands.CommandObject{ Service: service, Container: service.Container, }) @@ -466,7 +453,7 @@ L: func (gui *Gui) handleServicesBulkCommand(g *gocui.Gui, v *gocui.View) error { bulkCommands := gui.Config.UserConfig.BulkCommands.Services - commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{}) + commandObject := gui.ContainerCommand.NewCommandObject(commands.CommandObject{}) return gui.createBulkCommandMenu(bulkCommands, commandObject) } diff --git a/pkg/gui/views.go b/pkg/gui/views.go index 3de6d61a..8e8ed18d 100644 --- a/pkg/gui/views.go +++ b/pkg/gui/views.go @@ -128,7 +128,7 @@ func (gui *Gui) createAllViews() error { gui.Views.Containers.Highlight = true gui.Views.Containers.SelBgColor = selectedLineBgColor - if gui.Config.UserConfig.Gui.ShowAllContainers || !gui.DockerCommand.InDockerComposeProject { + if gui.Config.UserConfig.Gui.ShowAllContainers || !gui.ContainerCommand.InDockerComposeProject() { gui.Views.Containers.Title = gui.Tr.ContainersTitle } else { gui.Views.Containers.Title = gui.Tr.StandaloneContainersTitle @@ -142,12 +142,13 @@ func (gui *Gui) createAllViews() error { gui.Views.Volumes.Highlight = true gui.Views.Volumes.Title = gui.Tr.VolumesTitle - gui.Views.Volumes.TitlePrefix = "[5]" gui.Views.Volumes.SelBgColor = selectedLineBgColor + gui.Views.Volumes.TitlePrefix = "[5]" + gui.Views.Networks.TitlePrefix = "[6]" + gui.Views.Networks.Highlight = true gui.Views.Networks.Title = gui.Tr.NetworksTitle - gui.Views.Networks.TitlePrefix = "[6]" gui.Views.Networks.SelBgColor = selectedLineBgColor gui.Views.Options.Frame = false diff --git a/pkg/gui/volumes_panel.go b/pkg/gui/volumes_panel.go index 96085949..cd9ce6ad 100644 --- a/pkg/gui/volumes_panel.go +++ b/pkg/gui/volumes_panel.go @@ -2,6 +2,7 @@ package gui import ( "fmt" + "strings" "github.com/fatih/color" "github.com/jesseduffield/gocui" @@ -17,6 +18,10 @@ import ( func (gui *Gui) getVolumesPanel() *panels.SideListPanel[*commands.Volume] { return &panels.SideListPanel[*commands.Volume]{ + Hide: func() bool { + // Show volumes panel for both Docker and Apple runtime + return false + }, ContextState: &panels.ContextState[*commands.Volume]{ GetMainTabs: func() []panels.MainTab[*commands.Volume] { return []panels.MainTab[*commands.Volume]{ @@ -94,7 +99,7 @@ func (gui *Gui) reloadVolumes() error { } func (gui *Gui) refreshStateVolumes() error { - volumes, err := gui.DockerCommand.RefreshVolumes() + volumes, err := gui.ContainerCommand.RefreshVolumes() if err != nil { return err } @@ -116,15 +121,23 @@ func (gui *Gui) handleVolumesRemoveMenu(g *gocui.Gui, v *gocui.View) error { force bool } + runtimeName := gui.ContainerCommand.GetRuntimeName() + rmCmd := utils.WithShortSha("docker volume rm " + volume.Name) + rmForceCmd := utils.WithShortSha("docker volume rm --force " + volume.Name) + if runtimeName == "apple" { + rmCmd = utils.WithShortSha("container volume rm " + volume.Name) + rmForceCmd = utils.WithShortSha("container volume rm --force " + volume.Name) + } + options := []*removeVolumeOption{ { description: gui.Tr.Remove, - command: utils.WithShortSha("docker volume rm " + volume.Name), + command: rmCmd, force: false, }, { description: gui.Tr.ForceRemove, - command: utils.WithShortSha("docker volume rm --force " + volume.Name), + command: rmForceCmd, force: true, }, } @@ -150,9 +163,12 @@ func (gui *Gui) handleVolumesRemoveMenu(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handlePruneVolumes() error { + if gui.ContainerCommand != nil && !gui.ContainerCommand.Supports(commands.FeatureVolumePrune) { + return gui.createErrorPanel("Volume pruning is not supported by the current container runtime.") + } return gui.createConfirmationPanel(gui.Tr.Confirm, gui.Tr.ConfirmPruneVolumes, func(g *gocui.Gui, v *gocui.View) error { return gui.WithWaitingStatus(gui.Tr.PruningStatus, func() error { - err := gui.DockerCommand.PruneVolumes() + err := gui.ContainerCommand.PruneVolumes() if err != nil { return gui.createErrorPanel(err.Error()) } @@ -161,13 +177,45 @@ func (gui *Gui) handlePruneVolumes() error { }, nil) } +func (gui *Gui) handleCreateVolume(g *gocui.Gui, v *gocui.View) error { + if gui.ContainerCommand != nil && !gui.ContainerCommand.Supports(commands.FeatureVolumeCreate) { + return gui.createErrorPanel("Volume create is not supported by the current container runtime.") + } + prompt := "Enter: name [opt=value opt2=value2]" + return gui.createPromptPanel("Create Volume", func(g *gocui.Gui, v *gocui.View) error { + input := strings.TrimSpace(v.Buffer()) + _ = gui.closeConfirmationPrompt() + if input == "" { + return nil + } + fields := strings.Fields(input) + name := fields[0] + opts := map[string]string{} + for _, tok := range fields[1:] { + if kv := strings.SplitN(tok, "=", 2); len(kv) == 2 { + opts[kv[0]] = kv[1] + } else if tok != "" { + opts[tok] = "" + } + } + if err := gui.ContainerCommand.CreateVolume(name, opts); err != nil { + return gui.createErrorPanel(err.Error()) + } + return gui.reloadVolumes() + }) + // write prompt after view appears + // we can't write synchronously because the view becomes editable after creation + _ = prompt + return nil +} + func (gui *Gui) handleVolumesCustomCommand(g *gocui.Gui, v *gocui.View) error { volume, err := gui.Panels.Volumes.GetSelectedItem() if err != nil { return nil } - commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{ + commandObject := gui.ContainerCommand.NewCommandObject(commands.CommandObject{ Volume: volume, }) @@ -177,15 +225,16 @@ func (gui *Gui) handleVolumesCustomCommand(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) handleVolumesBulkCommand(g *gocui.Gui, v *gocui.View) error { - baseBulkCommands := []config.CustomCommand{ - { + baseBulkCommands := []config.CustomCommand{} + if gui.ContainerCommand == nil || gui.ContainerCommand.Supports(commands.FeatureVolumePrune) { + baseBulkCommands = append(baseBulkCommands, config.CustomCommand{ Name: gui.Tr.PruneVolumes, InternalFunction: gui.handlePruneVolumes, - }, + }) } bulkCommands := append(baseBulkCommands, gui.Config.UserConfig.BulkCommands.Volumes...) - commandObject := gui.DockerCommand.NewCommandObject(commands.CommandObject{}) + commandObject := gui.ContainerCommand.NewCommandObject(commands.CommandObject{}) return gui.createBulkCommandMenu(bulkCommands, commandObject) } diff --git a/vendor/github.com/OpenPeeDeeP/xdg/xdg.go b/vendor/github.com/OpenPeeDeeP/xdg/xdg.go index bb81060b..22e79eff 100644 --- a/vendor/github.com/OpenPeeDeeP/xdg/xdg.go +++ b/vendor/github.com/OpenPeeDeeP/xdg/xdg.go @@ -24,7 +24,7 @@ type xdgDefaulter interface { type osDefaulter struct { } -//This method is used in the testing suit +// This method is used in the testing suit // nolint: deadcode func setDefaulter(def xdgDefaulter) { defaulter = def diff --git a/vendor/github.com/OpenPeeDeeP/xdg/xdg_bsd.go b/vendor/github.com/OpenPeeDeeP/xdg/xdg_bsd.go index ea99f2fd..3b12e4df 100644 --- a/vendor/github.com/OpenPeeDeeP/xdg/xdg_bsd.go +++ b/vendor/github.com/OpenPeeDeeP/xdg/xdg_bsd.go @@ -1,3 +1,4 @@ +//go:build freebsd || openbsd || netbsd // +build freebsd openbsd netbsd // Copyright (c) 2017, OpenPeeDeeP. All rights reserved. diff --git a/vendor/github.com/boz/go-throttle/throttle.go b/vendor/github.com/boz/go-throttle/throttle.go index 1bd6f620..ebd47dd7 100644 --- a/vendor/github.com/boz/go-throttle/throttle.go +++ b/vendor/github.com/boz/go-throttle/throttle.go @@ -11,18 +11,18 @@ // // Example with period = time.Second and trailing = false: // -// Whole seconds after first trigger...|0|0|0|0|1|1|1|1| -// Trigger() gets called...............|X| |X| | |X| | | -// Throttled code gets called..........|X| | | | |X| | | +// Whole seconds after first trigger...|0|0|0|0|1|1|1|1| +// Trigger() gets called...............|X| |X| | |X| | | +// Throttled code gets called..........|X| | | | |X| | | // // Note that the second trigger had no effect. The third Trigger() caused immediate execution of the // throttled code. // // Example with period = time.Second and trailing = true: // -// Whole seconds after first trigger...|0|0|0|0|1|1|1|1| -// Trigger() gets called...............|X| |X| | |X| | | -// Throttled code gets called..........|X| | | |X| | | | +// Whole seconds after first trigger...|0|0|0|0|1|1|1|1| +// Trigger() gets called...............|X| |X| | |X| | | +// Throttled code gets called..........|X| | | |X| | | | // // Note that the second Trigger() causes the throttled code to get called once the first period is over. // The third Trigger() will do the same. diff --git a/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_unix.go b/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_unix.go index 374d7617..825812d8 100644 --- a/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_unix.go +++ b/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_unix.go @@ -1,3 +1,4 @@ +//go:build darwin || freebsd || linux || netbsd || openbsd // +build darwin freebsd linux netbsd openbsd package jibber_jabber diff --git a/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_windows.go b/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_windows.go index 1acd96c3..6648926a 100644 --- a/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_windows.go +++ b/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package jibber_jabber diff --git a/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/davecgh/go-spew/spew/bypass.go index 79299478..70ddeaad 100644 --- a/vendor/github.com/davecgh/go-spew/spew/bypass.go +++ b/vendor/github.com/davecgh/go-spew/spew/bypass.go @@ -18,6 +18,7 @@ // tag is deprecated and thus should not be used. // Go versions prior to 1.4 are disabled because they use a different layout // for interfaces which make the implementation of unsafeReflectValue more complex. +//go:build !js && !appengine && !safe && !disableunsafe && go1.4 // +build !js,!appengine,!safe,!disableunsafe,go1.4 package spew diff --git a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go index 205c28d6..5e2d890d 100644 --- a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go +++ b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go @@ -16,6 +16,7 @@ // when the code is running on Google App Engine, compiled by GopherJS, or // "-tags safe" is added to the go build command line. The "disableunsafe" // tag is deprecated and thus should not be used. +//go:build js || appengine || safe || disableunsafe || !go1.4 // +build js appengine safe disableunsafe !go1.4 package spew diff --git a/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/davecgh/go-spew/spew/config.go index 2e3d22f3..161895fc 100644 --- a/vendor/github.com/davecgh/go-spew/spew/config.go +++ b/vendor/github.com/davecgh/go-spew/spew/config.go @@ -254,15 +254,15 @@ pointer addresses used to indirect to the final value. It provides the following features over the built-in printing facilities provided by the fmt package: - * Pointers are dereferenced and followed - * Circular data structures are detected and handled properly - * Custom Stringer/error interfaces are optionally invoked, including - on unexported types - * Custom types which only implement the Stringer/error interfaces via - a pointer receiver are optionally invoked when passing non-pointer - variables - * Byte arrays and slices are dumped like the hexdump -C command which - includes offsets, byte values in hex, and ASCII output + - Pointers are dereferenced and followed + - Circular data structures are detected and handled properly + - Custom Stringer/error interfaces are optionally invoked, including + on unexported types + - Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + - Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output The configuration options are controlled by modifying the public members of c. See ConfigState for options documentation. @@ -295,12 +295,12 @@ func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) // NewDefaultConfig returns a ConfigState with the following default settings. // -// Indent: " " -// MaxDepth: 0 -// DisableMethods: false -// DisablePointerMethods: false -// ContinueOnMethod: false -// SortKeys: false +// Indent: " " +// MaxDepth: 0 +// DisableMethods: false +// DisablePointerMethods: false +// ContinueOnMethod: false +// SortKeys: false func NewDefaultConfig() *ConfigState { return &ConfigState{Indent: " "} } diff --git a/vendor/github.com/davecgh/go-spew/spew/doc.go b/vendor/github.com/davecgh/go-spew/spew/doc.go index aacaac6f..722e9aa7 100644 --- a/vendor/github.com/davecgh/go-spew/spew/doc.go +++ b/vendor/github.com/davecgh/go-spew/spew/doc.go @@ -21,35 +21,36 @@ debugging. A quick overview of the additional features spew provides over the built-in printing facilities for Go data types are as follows: - * Pointers are dereferenced and followed - * Circular data structures are detected and handled properly - * Custom Stringer/error interfaces are optionally invoked, including - on unexported types - * Custom types which only implement the Stringer/error interfaces via - a pointer receiver are optionally invoked when passing non-pointer - variables - * Byte arrays and slices are dumped like the hexdump -C command which - includes offsets, byte values in hex, and ASCII output (only when using - Dump style) + - Pointers are dereferenced and followed + - Circular data structures are detected and handled properly + - Custom Stringer/error interfaces are optionally invoked, including + on unexported types + - Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + - Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output (only when using + Dump style) There are two different approaches spew allows for dumping Go data structures: - * Dump style which prints with newlines, customizable indentation, - and additional debug information such as types and all pointer addresses - used to indirect to the final value - * A custom Formatter interface that integrates cleanly with the standard fmt - package and replaces %v, %+v, %#v, and %#+v to provide inline printing - similar to the default %v while providing the additional functionality - outlined above and passing unsupported format verbs such as %x and %q - along to fmt + - Dump style which prints with newlines, customizable indentation, + and additional debug information such as types and all pointer addresses + used to indirect to the final value + - A custom Formatter interface that integrates cleanly with the standard fmt + package and replaces %v, %+v, %#v, and %#+v to provide inline printing + similar to the default %v while providing the additional functionality + outlined above and passing unsupported format verbs such as %x and %q + along to fmt -Quick Start +# Quick Start This section demonstrates how to quickly get started with spew. See the sections below for further details on formatting and configuration options. To dump a variable with full newlines, indentation, type, and pointer information use Dump, Fdump, or Sdump: + spew.Dump(myVar1, myVar2, ...) spew.Fdump(someWriter, myVar1, myVar2, ...) str := spew.Sdump(myVar1, myVar2, ...) @@ -58,12 +59,13 @@ Alternatively, if you would prefer to use format strings with a compacted inline printing style, use the convenience wrappers Printf, Fprintf, etc with %v (most compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types and pointer addresses): + spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) -Configuration Options +# Configuration Options Configuration of spew is handled by fields in the ConfigState type. For convenience, all of the top-level functions use a global state available @@ -74,51 +76,52 @@ equivalent to the top-level functions. This allows concurrent configuration options. See the ConfigState documentation for more details. The following configuration options are available: - * Indent - String to use for each indentation level for Dump functions. - It is a single space by default. A popular alternative is "\t". - * MaxDepth - Maximum number of levels to descend into nested data structures. - There is no limit by default. + - Indent + String to use for each indentation level for Dump functions. + It is a single space by default. A popular alternative is "\t". - * DisableMethods - Disables invocation of error and Stringer interface methods. - Method invocation is enabled by default. + - MaxDepth + Maximum number of levels to descend into nested data structures. + There is no limit by default. - * DisablePointerMethods - Disables invocation of error and Stringer interface methods on types - which only accept pointer receivers from non-pointer variables. - Pointer method invocation is enabled by default. + - DisableMethods + Disables invocation of error and Stringer interface methods. + Method invocation is enabled by default. - * DisablePointerAddresses - DisablePointerAddresses specifies whether to disable the printing of - pointer addresses. This is useful when diffing data structures in tests. + - DisablePointerMethods + Disables invocation of error and Stringer interface methods on types + which only accept pointer receivers from non-pointer variables. + Pointer method invocation is enabled by default. - * DisableCapacities - DisableCapacities specifies whether to disable the printing of - capacities for arrays, slices, maps and channels. This is useful when - diffing data structures in tests. + - DisablePointerAddresses + DisablePointerAddresses specifies whether to disable the printing of + pointer addresses. This is useful when diffing data structures in tests. - * ContinueOnMethod - Enables recursion into types after invoking error and Stringer interface - methods. Recursion after method invocation is disabled by default. + - DisableCapacities + DisableCapacities specifies whether to disable the printing of + capacities for arrays, slices, maps and channels. This is useful when + diffing data structures in tests. - * SortKeys - Specifies map keys should be sorted before being printed. Use - this to have a more deterministic, diffable output. Note that - only native types (bool, int, uint, floats, uintptr and string) - and types which implement error or Stringer interfaces are - supported with other types sorted according to the - reflect.Value.String() output which guarantees display - stability. Natural map order is used by default. + - ContinueOnMethod + Enables recursion into types after invoking error and Stringer interface + methods. Recursion after method invocation is disabled by default. - * SpewKeys - Specifies that, as a last resort attempt, map keys should be - spewed to strings and sorted by those strings. This is only - considered if SortKeys is true. + - SortKeys + Specifies map keys should be sorted before being printed. Use + this to have a more deterministic, diffable output. Note that + only native types (bool, int, uint, floats, uintptr and string) + and types which implement error or Stringer interfaces are + supported with other types sorted according to the + reflect.Value.String() output which guarantees display + stability. Natural map order is used by default. -Dump Usage + - SpewKeys + Specifies that, as a last resort attempt, map keys should be + spewed to strings and sorted by those strings. This is only + considered if SortKeys is true. + +# Dump Usage Simply call spew.Dump with a list of variables you want to dump: @@ -133,7 +136,7 @@ A third option is to call spew.Sdump to get the formatted output as a string: str := spew.Sdump(myVar1, myVar2, ...) -Sample Dump Output +# Sample Dump Output See the Dump example for details on the setup of the types and variables being shown here. @@ -150,13 +153,14 @@ shown here. Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C command as shown. + ([]uint8) (len=32 cap=32) { 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| 00000020 31 32 |12| } -Custom Formatter +# Custom Formatter Spew provides a custom formatter that implements the fmt.Formatter interface so that it integrates cleanly with standard fmt package printing functions. The @@ -170,7 +174,7 @@ standard fmt package for formatting. In addition, the custom formatter ignores the width and precision arguments (however they will still work on the format specifiers not handled by the custom formatter). -Custom Formatter Usage +# Custom Formatter Usage The simplest way to make use of the spew custom formatter is to call one of the convenience functions such as spew.Printf, spew.Println, or spew.Printf. The @@ -184,15 +188,17 @@ functions have syntax you are most likely already familiar with: See the Index for the full list convenience functions. -Sample Formatter Output +# Sample Formatter Output Double pointer to a uint8: + %v: <**>5 %+v: <**>(0xf8400420d0->0xf8400420c8)5 %#v: (**uint8)5 %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 Pointer to circular struct with a uint8 field and a pointer to itself: + %v: <*>{1 <*>} %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} @@ -201,7 +207,7 @@ Pointer to circular struct with a uint8 field and a pointer to itself: See the Printf example for details on the setup of variables being shown here. -Errors +# Errors Since it is possible for custom Stringer/error interfaces to panic, spew detects them and handles them internally by printing the panic information diff --git a/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/davecgh/go-spew/spew/dump.go index f78d89fc..8323041a 100644 --- a/vendor/github.com/davecgh/go-spew/spew/dump.go +++ b/vendor/github.com/davecgh/go-spew/spew/dump.go @@ -488,15 +488,15 @@ pointer addresses used to indirect to the final value. It provides the following features over the built-in printing facilities provided by the fmt package: - * Pointers are dereferenced and followed - * Circular data structures are detected and handled properly - * Custom Stringer/error interfaces are optionally invoked, including - on unexported types - * Custom types which only implement the Stringer/error interfaces via - a pointer receiver are optionally invoked when passing non-pointer - variables - * Byte arrays and slices are dumped like the hexdump -C command which - includes offsets, byte values in hex, and ASCII output + - Pointers are dereferenced and followed + - Circular data structures are detected and handled properly + - Custom Stringer/error interfaces are optionally invoked, including + on unexported types + - Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + - Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output The configuration options are controlled by an exported package global, spew.Config. See ConfigState for options documentation. diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go index cf1e9650..ed1ed5f0 100644 --- a/vendor/github.com/fatih/color/doc.go +++ b/vendor/github.com/fatih/color/doc.go @@ -5,106 +5,105 @@ that suits you. Use simple and default helper functions with predefined foreground colors: - color.Cyan("Prints text in cyan.") + color.Cyan("Prints text in cyan.") - // a newline will be appended automatically - color.Blue("Prints %s in blue.", "text") + // a newline will be appended automatically + color.Blue("Prints %s in blue.", "text") - // More default foreground colors.. - color.Red("We have red") - color.Yellow("Yellow color too!") - color.Magenta("And many others ..") + // More default foreground colors.. + color.Red("We have red") + color.Yellow("Yellow color too!") + color.Magenta("And many others ..") - // Hi-intensity colors - color.HiGreen("Bright green color.") - color.HiBlack("Bright black means gray..") - color.HiWhite("Shiny white color!") + // Hi-intensity colors + color.HiGreen("Bright green color.") + color.HiBlack("Bright black means gray..") + color.HiWhite("Shiny white color!") However there are times where custom color mixes are required. Below are some examples to create custom color objects and use the print functions of each separate color object. - // Create a new color object - c := color.New(color.FgCyan).Add(color.Underline) - c.Println("Prints cyan text with an underline.") + // Create a new color object + c := color.New(color.FgCyan).Add(color.Underline) + c.Println("Prints cyan text with an underline.") - // Or just add them to New() - d := color.New(color.FgCyan, color.Bold) - d.Printf("This prints bold cyan %s\n", "too!.") + // Or just add them to New() + d := color.New(color.FgCyan, color.Bold) + d.Printf("This prints bold cyan %s\n", "too!.") - // Mix up foreground and background colors, create new mixes! - red := color.New(color.FgRed) + // Mix up foreground and background colors, create new mixes! + red := color.New(color.FgRed) - boldRed := red.Add(color.Bold) - boldRed.Println("This will print text in bold red.") + boldRed := red.Add(color.Bold) + boldRed.Println("This will print text in bold red.") - whiteBackground := red.Add(color.BgWhite) - whiteBackground.Println("Red text with White background.") + whiteBackground := red.Add(color.BgWhite) + whiteBackground.Println("Red text with White background.") - // Use your own io.Writer output - color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + // Use your own io.Writer output + color.New(color.FgBlue).Fprintln(myWriter, "blue color!") - blue := color.New(color.FgBlue) - blue.Fprint(myWriter, "This will print text in blue.") + blue := color.New(color.FgBlue) + blue.Fprint(myWriter, "This will print text in blue.") You can create PrintXxx functions to simplify even more: - // Create a custom print function for convenient - red := color.New(color.FgRed).PrintfFunc() - red("warning") - red("error: %s", err) + // Create a custom print function for convenient + red := color.New(color.FgRed).PrintfFunc() + red("warning") + red("error: %s", err) - // Mix up multiple attributes - notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() - notice("don't forget this...") + // Mix up multiple attributes + notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() + notice("don't forget this...") You can also FprintXxx functions to pass your own io.Writer: - blue := color.New(FgBlue).FprintfFunc() - blue(myWriter, "important notice: %s", stars) - - // Mix up with multiple attributes - success := color.New(color.Bold, color.FgGreen).FprintlnFunc() - success(myWriter, don't forget this...") + blue := color.New(FgBlue).FprintfFunc() + blue(myWriter, "important notice: %s", stars) + // Mix up with multiple attributes + success := color.New(color.Bold, color.FgGreen).FprintlnFunc() + success(myWriter, don't forget this...") Or create SprintXxx functions to mix strings with other non-colorized strings: - yellow := New(FgYellow).SprintFunc() - red := New(FgRed).SprintFunc() + yellow := New(FgYellow).SprintFunc() + red := New(FgRed).SprintFunc() - fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error")) + fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error")) - info := New(FgWhite, BgGreen).SprintFunc() - fmt.Printf("this %s rocks!\n", info("package")) + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Printf("this %s rocks!\n", info("package")) Windows support is enabled by default. All Print functions work as intended. However only for color.SprintXXX functions, user should use fmt.FprintXXX and set the output to color.Output: - fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) + fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) - info := New(FgWhite, BgGreen).SprintFunc() - fmt.Fprintf(color.Output, "this %s rocks!\n", info("package")) + info := New(FgWhite, BgGreen).SprintFunc() + fmt.Fprintf(color.Output, "this %s rocks!\n", info("package")) Using with existing code is possible. Just use the Set() method to set the standard output to the given parameters. That way a rewrite of an existing code is not required. - // Use handy standard colors. - color.Set(color.FgYellow) + // Use handy standard colors. + color.Set(color.FgYellow) - fmt.Println("Existing text will be now in Yellow") - fmt.Printf("This one %s\n", "too") + fmt.Println("Existing text will be now in Yellow") + fmt.Printf("This one %s\n", "too") - color.Unset() // don't forget to unset + color.Unset() // don't forget to unset - // You can mix up parameters - color.Set(color.FgMagenta, color.Bold) - defer color.Unset() // use it in your function + // You can mix up parameters + color.Set(color.FgMagenta, color.Bold) + defer color.Unset() // use it in your function - fmt.Println("All text will be now bold magenta.") + fmt.Println("All text will be now bold magenta.") There might be a case where you want to disable color output (for example to pipe the standard output of your app to somewhere else). `Color` has support to @@ -112,22 +111,22 @@ disable colors both globally and for single color definition. For example suppose you have a CLI app and a `--no-color` bool flag. You can easily disable the color output with: - var flagNoColor = flag.Bool("no-color", false, "Disable color output") + var flagNoColor = flag.Bool("no-color", false, "Disable color output") - if *flagNoColor { - color.NoColor = true // disables colorized output - } + if *flagNoColor { + color.NoColor = true // disables colorized output + } It also has support for single color definitions (local). You can disable/enable color output on the fly: - c := color.New(color.FgCyan) - c.Println("Prints cyan text") + c := color.New(color.FgCyan) + c.Println("Prints cyan text") - c.DisableColor() - c.Println("This is printed without any color") + c.DisableColor() + c.Println("This is printed without any color") - c.EnableColor() - c.Println("This prints again cyan...") + c.EnableColor() + c.Println("This prints again cyan...") */ package color diff --git a/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go b/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go index 101cedde..cffd3d05 100644 --- a/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go +++ b/vendor/github.com/felixge/httpsnoop/wrap_generated_gteq_1.8.go @@ -1,4 +1,6 @@ +//go:build go1.8 // +build go1.8 + // Code generated by "httpsnoop/codegen"; DO NOT EDIT. package httpsnoop diff --git a/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go b/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go index e0951df1..c5ae1966 100644 --- a/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go +++ b/vendor/github.com/felixge/httpsnoop/wrap_generated_lt_1.8.go @@ -1,4 +1,6 @@ +//go:build !go1.8 // +build !go1.8 + // Code generated by "httpsnoop/codegen"; DO NOT EDIT. package httpsnoop diff --git a/vendor/github.com/go-errors/errors/error.go b/vendor/github.com/go-errors/errors/error.go index ccbc2e42..533f1bb2 100644 --- a/vendor/github.com/go-errors/errors/error.go +++ b/vendor/github.com/go-errors/errors/error.go @@ -9,36 +9,36 @@ // // For example: // -// package crashy +// package crashy // -// import "github.com/go-errors/errors" +// import "github.com/go-errors/errors" // -// var Crashed = errors.Errorf("oh dear") +// var Crashed = errors.Errorf("oh dear") // -// func Crash() error { -// return errors.New(Crashed) -// } +// func Crash() error { +// return errors.New(Crashed) +// } // // This can be called as follows: // -// package main +// package main // -// import ( -// "crashy" -// "fmt" -// "github.com/go-errors/errors" -// ) +// import ( +// "crashy" +// "fmt" +// "github.com/go-errors/errors" +// ) // -// func main() { -// err := crashy.Crash() -// if err != nil { -// if errors.Is(err, crashy.Crashed) { -// fmt.Println(err.(*errors.Error).ErrorStack()) -// } else { -// panic(err) -// } -// } -// } +// func main() { +// err := crashy.Crash() +// if err != nil { +// if errors.Is(err, crashy.Crashed) { +// fmt.Println(err.(*errors.Error).ErrorStack()) +// } else { +// panic(err) +// } +// } +// } // // This package was original written to allow reporting to Bugsnag, // but after I found similar packages by Facebook and Dropbox, it diff --git a/vendor/github.com/go-errors/errors/parse_panic.go b/vendor/github.com/go-errors/errors/parse_panic.go index cc37052d..d295563d 100644 --- a/vendor/github.com/go-errors/errors/parse_panic.go +++ b/vendor/github.com/go-errors/errors/parse_panic.go @@ -75,8 +75,8 @@ func ParsePanic(text string) (*Error, error) { // The lines we're passing look like this: // -// main.(*foo).destruct(0xc208067e98) -// /0/go/src/github.com/bugsnag/bugsnag-go/pan/main.go:22 +0x151 +// main.(*foo).destruct(0xc208067e98) +// /0/go/src/github.com/bugsnag/bugsnag-go/pan/main.go:22 +0x151 func parsePanicFrame(name string, line string, createdBy bool) (*StackFrame, error) { idx := strings.LastIndex(name, "(") if idx == -1 && !createdBy { diff --git a/vendor/github.com/goccy/go-yaml/yaml.go b/vendor/github.com/goccy/go-yaml/yaml.go index 2e541d85..25b1056f 100644 --- a/vendor/github.com/goccy/go-yaml/yaml.go +++ b/vendor/github.com/goccy/go-yaml/yaml.go @@ -89,43 +89,42 @@ func (s MapSlice) ToMap() map[interface{}]interface{} { // // The field tag format accepted is: // -// `(...) yaml:"[][,[,]]" (...)` +// `(...) yaml:"[][,[,]]" (...)` // // The following flags are currently supported: // -// omitempty Only include the field if it's not set to the zero -// value for the type or to empty slices or maps. -// Zero valued structs will be omitted if all their public -// fields are zero, unless they implement an IsZero -// method (see the IsZeroer interface type), in which -// case the field will be included if that method returns true. +// omitempty Only include the field if it's not set to the zero +// value for the type or to empty slices or maps. +// Zero valued structs will be omitted if all their public +// fields are zero, unless they implement an IsZero +// method (see the IsZeroer interface type), in which +// case the field will be included if that method returns true. // -// flow Marshal using a flow style (useful for structs, -// sequences and maps). +// flow Marshal using a flow style (useful for structs, +// sequences and maps). // -// inline Inline the field, which must be a struct or a map, -// causing all of its fields or keys to be processed as if -// they were part of the outer struct. For maps, keys must -// not conflict with the yaml keys of other struct fields. +// inline Inline the field, which must be a struct or a map, +// causing all of its fields or keys to be processed as if +// they were part of the outer struct. For maps, keys must +// not conflict with the yaml keys of other struct fields. // -// anchor Marshal with anchor. If want to define anchor name explicitly, use anchor=name style. -// Otherwise, if used 'anchor' name only, used the field name lowercased as the anchor name +// anchor Marshal with anchor. If want to define anchor name explicitly, use anchor=name style. +// Otherwise, if used 'anchor' name only, used the field name lowercased as the anchor name // -// alias Marshal with alias. If want to define alias name explicitly, use alias=name style. -// Otherwise, If omitted alias name and the field type is pointer type, -// assigned anchor name automatically from same pointer address. +// alias Marshal with alias. If want to define alias name explicitly, use alias=name style. +// Otherwise, If omitted alias name and the field type is pointer type, +// assigned anchor name automatically from same pointer address. // // In addition, if the key is "-", the field is ignored. // // For example: // -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" -// yaml.Marshal(&T{F: 1}) // Returns "a: 1\nb: 0\n" -// +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" +// yaml.Marshal(&T{F: 1}) // Returns "a: 1\nb: 0\n" func Marshal(v interface{}) ([]byte, error) { return MarshalWithOptions(v) } @@ -167,16 +166,15 @@ func ValueToNode(v interface{}, opts ...EncodeOption) (ast.Node, error) { // // For example: // -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// var t T -// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// var t T +// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) // // See the documentation of Marshal for the format of tags and a list of // supported tag options. -// func Unmarshal(data []byte, v interface{}) error { return UnmarshalWithOptions(data, v) } diff --git a/vendor/github.com/gogo/protobuf/proto/lib.go b/vendor/github.com/gogo/protobuf/proto/lib.go index 80db1c15..10eec0d0 100644 --- a/vendor/github.com/gogo/protobuf/proto/lib.go +++ b/vendor/github.com/gogo/protobuf/proto/lib.go @@ -39,35 +39,35 @@ for a protocol buffer variable v: - Names are turned from camel_case to CamelCase for export. - There are no methods on v to set fields; just treat - them as structure fields. + them as structure fields. - There are getters that return a field's value if set, - and return the field's default value if unset. - The getters work even if the receiver is a nil message. + and return the field's default value if unset. + The getters work even if the receiver is a nil message. - The zero value for a struct is its correct initialization state. - All desired fields must be set before marshaling. + All desired fields must be set before marshaling. - A Reset() method will restore a protobuf struct to its zero state. - Non-repeated fields are pointers to the values; nil means unset. - That is, optional or required field int32 f becomes F *int32. + That is, optional or required field int32 f becomes F *int32. - Repeated fields are slices. - Helper functions are available to aid the setting of fields. - msg.Foo = proto.String("hello") // set field + msg.Foo = proto.String("hello") // set field - Constants are defined to hold the default values of all fields that - have them. They have the form Default_StructName_FieldName. - Because the getter methods handle defaulted values, - direct use of these constants should be rare. + have them. They have the form Default_StructName_FieldName. + Because the getter methods handle defaulted values, + direct use of these constants should be rare. - Enums are given type names and maps from names to values. - Enum values are prefixed by the enclosing message's name, or by the - enum's type name if it is a top-level enum. Enum types have a String - method, and a Enum method to assist in message construction. + Enum values are prefixed by the enclosing message's name, or by the + enum's type name if it is a top-level enum. Enum types have a String + method, and a Enum method to assist in message construction. - Nested messages, groups and enums have type names prefixed with the name of - the surrounding message type. + the surrounding message type. - Extensions are given descriptor names that start with E_, - followed by an underscore-delimited list of the nested messages - that contain it (if any) followed by the CamelCased name of the - extension field itself. HasExtension, ClearExtension, GetExtension - and SetExtension are functions for manipulating extensions. + followed by an underscore-delimited list of the nested messages + that contain it (if any) followed by the CamelCased name of the + extension field itself. HasExtension, ClearExtension, GetExtension + and SetExtension are functions for manipulating extensions. - Oneof field sets are given a single field in their message, - with distinguished wrapper types for each possible field value. + with distinguished wrapper types for each possible field value. - Marshal and Unmarshal are functions to encode and decode the wire format. When the .proto file specifies `syntax="proto3"`, there are some differences: diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go b/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go index b6cad908..461d5821 100644 --- a/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go +++ b/vendor/github.com/gogo/protobuf/proto/pointer_reflect.go @@ -29,6 +29,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +//go:build purego || appengine || js // +build purego appengine js // This file contains an implementation of proto field accesses using package reflect. diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go b/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go index 7ffd3c29..d6e07e2f 100644 --- a/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go +++ b/vendor/github.com/gogo/protobuf/proto/pointer_reflect_gogo.go @@ -26,6 +26,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +//go:build purego || appengine || js // +build purego appengine js // This file contains an implementation of proto field accesses using package reflect. diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go index d55a335d..c998399b 100644 --- a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go +++ b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe.go @@ -29,6 +29,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +//go:build !purego && !appengine && !js // +build !purego,!appengine,!js // This file contains the implementation of the proto field accesses using package unsafe. diff --git a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go index aca8eed0..57a14965 100644 --- a/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go +++ b/vendor/github.com/gogo/protobuf/proto/pointer_unsafe_gogo.go @@ -26,6 +26,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +//go:build !purego && !appengine && !js // +build !purego,!appengine,!js // This file contains the implementation of the proto field accesses using package unsafe. diff --git a/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go b/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go index 93722938..7c3e9e00 100644 --- a/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go +++ b/vendor/github.com/gogo/protobuf/proto/table_unmarshal.go @@ -2004,12 +2004,14 @@ func makeUnmarshalMap(f *reflect.StructField) unmarshaler { // makeUnmarshalOneof makes an unmarshaler for oneof fields. // for: -// message Msg { -// oneof F { -// int64 X = 1; -// float64 Y = 2; -// } -// } +// +// message Msg { +// oneof F { +// int64 X = 1; +// float64 Y = 2; +// } +// } +// // typ is the type of the concrete entry for a oneof case (e.g. Msg_X). // ityp is the interface type of the oneof field (e.g. isMsg_F). // unmarshal is the unmarshaler for the base type of the oneof case (e.g. int64). diff --git a/vendor/github.com/gookit/color/color.go b/vendor/github.com/gookit/color/color.go index edb2a5d7..9dfbd689 100644 --- a/vendor/github.com/gookit/color/color.go +++ b/vendor/github.com/gookit/color/color.go @@ -29,7 +29,8 @@ const ( // color render templates // ESC 操作的表示: -// "\033"(Octal 8进制) = "\x1b"(Hexadecimal 16进制) = 27 (10进制) +// +// "\033"(Octal 8进制) = "\x1b"(Hexadecimal 16进制) = 27 (10进制) const ( SettingTpl = "\x1b[%sm" FullColorTpl = "\x1b[%sm%s\x1b[0m" @@ -179,7 +180,8 @@ func InnerErrs() []error { // RenderCode render message by color code. // Usage: -// msg := RenderCode("3;32;45", "some", "message") +// +// msg := RenderCode("3;32;45", "some", "message") func RenderCode(code string, args ...interface{}) string { var message string if ln := len(args); ln == 0 { @@ -217,7 +219,8 @@ func RenderWithSpaces(code string, args ...interface{}) string { // RenderString render a string with color code. // Usage: -// msg := RenderString("3;32;45", "a message") +// +// msg := RenderString("3;32;45", "a message") func RenderString(code string, str string) string { if len(code) == 0 || str == "" { return str diff --git a/vendor/github.com/gookit/color/color_16.go b/vendor/github.com/gookit/color/color_16.go index f2a211a2..8f7f6392 100644 --- a/vendor/github.com/gookit/color/color_16.go +++ b/vendor/github.com/gookit/color/color_16.go @@ -191,8 +191,9 @@ func (c Color) Text(message string) string { // Render messages by color setting // Usage: -// green := color.FgGreen.Render -// fmt.Println(green("message")) +// +// green := color.FgGreen.Render +// fmt.Println(green("message")) func (c Color) Render(a ...interface{}) string { return RenderCode(c.String(), a...) } @@ -200,8 +201,9 @@ func (c Color) Render(a ...interface{}) string { // Renderln messages by color setting. // like Println, will add spaces for each argument // Usage: -// green := color.FgGreen.Renderln -// fmt.Println(green("message")) +// +// green := color.FgGreen.Renderln +// fmt.Println(green("message")) func (c Color) Renderln(a ...interface{}) string { return RenderWithSpaces(c.String(), a...) } @@ -213,25 +215,30 @@ func (c Color) Sprint(a ...interface{}) string { // Sprintf format and render message. // Usage: -// green := color.Green.Sprintf -// colored := green("message") +// +// green := color.Green.Sprintf +// colored := green("message") func (c Color) Sprintf(format string, args ...interface{}) string { return RenderString(c.String(), fmt.Sprintf(format, args...)) } // Print messages. // Usage: -// color.Green.Print("message") +// +// color.Green.Print("message") +// // OR: -// green := color.FgGreen.Print -// green("message") +// +// green := color.FgGreen.Print +// green("message") func (c Color) Print(args ...interface{}) { doPrintV2(c.Code(), fmt.Sprint(args...)) } // Printf format and print messages. // Usage: -// color.Cyan.Printf("string %s", "arg0") +// +// color.Cyan.Printf("string %s", "arg0") func (c Color) Printf(format string, a ...interface{}) { doPrintV2(c.Code(), fmt.Sprintf(format, a...)) } @@ -244,8 +251,9 @@ func (c Color) Println(a ...interface{}) { // Light current color. eg: 36(FgCyan) -> 96(FgLightCyan). // // Usage: -// lightCyan := Cyan.Light() -// lightCyan.Print("message") +// +// lightCyan := Cyan.Light() +// lightCyan.Print("message") func (c Color) Light() Color { val := int(c) if val >= 30 && val <= 47 { @@ -259,8 +267,9 @@ func (c Color) Light() Color { // Darken current color. eg. 96(FgLightCyan) -> 36(FgCyan) // // Usage: -// cyan := LightCyan.Darken() -// cyan.Print("message") +// +// cyan := LightCyan.Darken() +// cyan.Print("message") func (c Color) Darken() Color { val := int(c) if val >= 90 && val <= 107 { diff --git a/vendor/github.com/gookit/color/color_256.go b/vendor/github.com/gookit/color/color_256.go index efd6dca3..a0be4506 100644 --- a/vendor/github.com/gookit/color/color_256.go +++ b/vendor/github.com/gookit/color/color_256.go @@ -19,16 +19,19 @@ from wikipedia, 256 color: // tpl for 8 bit 256 color(`2^8`) // // format: -// ESC[ … 38;5; … m // 选择前景色 -// ESC[ … 48;5; … m // 选择背景色 +// +// ESC[ … 38;5; … m // 选择前景色 +// ESC[ … 48;5; … m // 选择背景色 // // example: -// fg "\x1b[38;5;242m" -// bg "\x1b[48;5;208m" -// both "\x1b[38;5;242;48;5;208m" +// +// fg "\x1b[38;5;242m" +// bg "\x1b[48;5;208m" +// both "\x1b[38;5;242;48;5;208m" // // links: -// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#8位 +// +// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#8位 const ( TplFg256 = "38;5;%d" TplBg256 = "48;5;%d" @@ -45,12 +48,14 @@ const ( // 颜色值使用10进制和16进制都可 0x98 = 152 // // The color consists of two uint8: -// 0: color value -// 1: color type; Fg=0, Bg=1, >1: unset value +// +// 0: color value +// 1: color type; Fg=0, Bg=1, >1: unset value // // example: -// fg color: [152, 0] -// bg color: [152, 1] +// +// fg color: [152, 0] +// bg color: [152, 1] // // NOTICE: now support 256 color on windows CMD, PowerShell // lint warn - Name starts with package name @@ -210,9 +215,10 @@ type Style256 struct { // S256 create a color256 style // Usage: -// s := color.S256() -// s := color.S256(132) // fg -// s := color.S256(132, 203) // fg and bg +// +// s := color.S256() +// s := color.S256(132) // fg +// s := color.S256(132, 203) // fg and bg func S256(fgAndBg ...uint8) *Style256 { s := &Style256{} vl := len(fgAndBg) diff --git a/vendor/github.com/gookit/color/color_rgb.go b/vendor/github.com/gookit/color/color_rgb.go index 5f16d7f9..898df9ef 100644 --- a/vendor/github.com/gookit/color/color_rgb.go +++ b/vendor/github.com/gookit/color/color_rgb.go @@ -8,20 +8,24 @@ import ( // 24 bit RGB color // RGB: -// R 0-255 G 0-255 B 0-255 -// R 00-FF G 00-FF B 00-FF (16进制) +// +// R 0-255 G 0-255 B 0-255 +// R 00-FF G 00-FF B 00-FF (16进制) // // Format: -// ESC[ … 38;2;;; … m // Select RGB foreground color -// ESC[ … 48;2;;; … m // Choose RGB background color +// +// ESC[ … 38;2;;; … m // Select RGB foreground color +// ESC[ … 48;2;;; … m // Choose RGB background color // // links: -// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#24位 +// +// https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#24位 // // example: -// fg: \x1b[38;2;30;144;255mMESSAGE\x1b[0m -// bg: \x1b[48;2;30;144;255mMESSAGE\x1b[0m -// both: \x1b[38;2;233;90;203;48;2;30;144;255mMESSAGE\x1b[0m +// +// fg: \x1b[38;2;30;144;255mMESSAGE\x1b[0m +// bg: \x1b[48;2;30;144;255mMESSAGE\x1b[0m +// both: \x1b[38;2;233;90;203;48;2;30;144;255mMESSAGE\x1b[0m const ( TplFgRGB = "38;2;%d;%d;%d" TplBgRGB = "48;2;%d;%d;%d" @@ -66,10 +70,11 @@ const ( // The last digit represents the foreground(0), background(1), >1 is unset value // // Usage: -// // 0, 1, 2 is R,G,B. -// // 3rd: Fg=0, Bg=1, >1: unset value -// RGBColor{30,144,255, 0} -// RGBColor{30,144,255, 1} +// +// // 0, 1, 2 is R,G,B. +// // 3rd: Fg=0, Bg=1, >1: unset value +// RGBColor{30,144,255, 0} +// RGBColor{30,144,255, 1} // // NOTICE: now support RGB color on Windows CMD, PowerShell type RGBColor [4]uint8 @@ -79,9 +84,10 @@ var emptyRGBColor = RGBColor{3: 99} // RGB color create. // Usage: -// c := RGB(30,144,255) -// c := RGB(30,144,255, true) -// c.Print("message") +// +// c := RGB(30,144,255) +// c := RGB(30,144,255, true) +// c.Print("message") func RGB(r, g, b uint8, isBg ...bool) RGBColor { rgb := RGBColor{r, g, b} if len(isBg) > 0 && isBg[0] { @@ -110,11 +116,12 @@ func RgbFromInts(rgb []int, isBg ...bool) RGBColor { // HEX create RGB color from a HEX color string. // // Usage: -// c := HEX("ccc") // rgb: [204 204 204] -// c := HEX("aabbcc") // rgb: [170 187 204] -// c := HEX("#aabbcc") -// c := HEX("0xaabbcc") -// c.Print("message") +// +// c := HEX("ccc") // rgb: [204 204 204] +// c := HEX("aabbcc") // rgb: [170 187 204] +// c := HEX("#aabbcc") +// c := HEX("0xaabbcc") +// c.Print("message") func HEX(hex string, isBg ...bool) RGBColor { if rgb := HexToRgb(hex); len(rgb) > 0 { return RGB(uint8(rgb[0]), uint8(rgb[1]), uint8(rgb[2]), isBg...) @@ -164,11 +171,12 @@ func RGBFromSlice(rgb []uint8, isBg ...bool) RGBColor { // support use color name in the {namedRgbMap} // // Usage: -// c := RGBFromString("170,187,204") -// c.Print("message") // -// c := RGBFromString("brown") -// c.Print("message with color brown") +// c := RGBFromString("170,187,204") +// c.Print("message") +// +// c := RGBFromString("brown") +// c.Print("message with color brown") func RGBFromString(rgb string, isBg ...bool) RGBColor { // use color name in the {namedRgbMap} if rgbVal, ok := namedRgbMap[rgb]; ok { @@ -327,8 +335,9 @@ func NewRGBStyle(fg RGBColor, bg ...RGBColor) *RGBStyle { // HEXStyle create a RGBStyle from HEX color string. // Usage: -// s := HEXStyle("aabbcc", "eee") -// s.Print("message") +// +// s := HEXStyle("aabbcc", "eee") +// s.Print("message") func HEXStyle(fg string, bg ...string) *RGBStyle { s := &RGBStyle{} if len(bg) > 0 { @@ -344,8 +353,9 @@ func HEXStyle(fg string, bg ...string) *RGBStyle { // RGBStyleFromString create a RGBStyle from color value string. // Usage: -// s := RGBStyleFromString("170,187,204", "70,87,4") -// s.Print("message") +// +// s := RGBStyleFromString("170,187,204", "70,87,4") +// s.Print("message") func RGBStyleFromString(fg string, bg ...string) *RGBStyle { s := &RGBStyle{} if len(bg) > 0 { diff --git a/vendor/github.com/gookit/color/color_tag.go b/vendor/github.com/gookit/color/color_tag.go index 051ba84f..ef074e25 100644 --- a/vendor/github.com/gookit/color/color_tag.go +++ b/vendor/github.com/gookit/color/color_tag.go @@ -234,23 +234,30 @@ func ReplaceTag(str string) string { // ParseCodeFromAttr parse color attributes. // // attr format: -// // VALUE please see var: FgColors, BgColors, AllOptions -// "fg=VALUE;bg=VALUE;op=VALUE" +// +// // VALUE please see var: FgColors, BgColors, AllOptions +// "fg=VALUE;bg=VALUE;op=VALUE" +// // 16 color: -// "fg=yellow" -// "bg=red" -// "op=bold,underscore" option is allow multi value -// "fg=white;bg=blue;op=bold" -// "fg=white;op=bold,underscore" +// +// "fg=yellow" +// "bg=red" +// "op=bold,underscore" option is allow multi value +// "fg=white;bg=blue;op=bold" +// "fg=white;op=bold,underscore" +// // 256 color: +// // "fg=167" // "fg=167;bg=23" // "fg=167;bg=23;op=bold" +// // true color: -// // hex +// +// // hex // "fg=fc1cac" // "fg=fc1cac;bg=c2c3c4" -// // r,g,b +// // r,g,b // "fg=23,45,214" // "fg=23,45,214;bg=109,99,88" func ParseCodeFromAttr(attr string) (code string) { @@ -371,7 +378,8 @@ func IsDefinedTag(name string) bool { // Tag value is a defined style name // Usage: -// Tag("info").Println("message") +// +// Tag("info").Println("message") type Tag string // Print messages diff --git a/vendor/github.com/gookit/color/convert.go b/vendor/github.com/gookit/color/convert.go index 6e3326df..6d37f912 100644 --- a/vendor/github.com/gookit/color/convert.go +++ b/vendor/github.com/gookit/color/convert.go @@ -32,14 +32,14 @@ var ( // ---------- basic(16) <=> RGB color convert ---------- // refer from Hyper app basic2hexMap = map[uint8]string{ - 30: "000000", // black - 31: "c51e14", // red - 32: "1dc121", // green - 33: "c7c329", // yellow - 34: "0a2fc4", // blue - 35: "c839c5", // magenta - 36: "20c5c6", // cyan - 37: "c7c7c7", // white + 30: "000000", // black + 31: "c51e14", // red + 32: "1dc121", // green + 33: "c7c329", // yellow + 34: "0a2fc4", // blue + 35: "c839c5", // magenta + 36: "20c5c6", // cyan + 37: "c7c7c7", // white // - don't add bg color // 40: "000000", // black // 41: "c51e14", // red @@ -49,14 +49,14 @@ var ( // 45: "c839c5", // magenta // 46: "20c5c6", // cyan // 47: "c7c7c7", // white - 90: "686868", // lightBlack/darkGray - 91: "fd6f6b", // lightRed - 92: "67f86f", // lightGreen - 93: "fffa72", // lightYellow - 94: "6a76fb", // lightBlue - 95: "fd7cfc", // lightMagenta - 96: "68fdfe", // lightCyan - 97: "ffffff", // lightWhite + 90: "686868", // lightBlack/darkGray + 91: "fd6f6b", // lightRed + 92: "67f86f", // lightGreen + 93: "fffa72", // lightYellow + 94: "6a76fb", // lightBlue + 95: "fd7cfc", // lightMagenta + 96: "68fdfe", // lightCyan + 97: "ffffff", // lightWhite // - don't add bg color // 100: "686868", // lightBlack/darkGray // 101: "fd6f6b", // lightRed @@ -407,10 +407,11 @@ func HexToRGB(hex string) []int { return HexToRgb(hex) } // HexToRgb convert hex color string to RGB numbers // // Usage: -// rgb := HexToRgb("ccc") // rgb: [204 204 204] -// rgb := HexToRgb("aabbcc") // rgb: [170 187 204] -// rgb := HexToRgb("#aabbcc") // rgb: [170 187 204] -// rgb := HexToRgb("0xad99c0") // rgb: [170 187 204] +// +// rgb := HexToRgb("ccc") // rgb: [204 204 204] +// rgb := HexToRgb("aabbcc") // rgb: [170 187 204] +// rgb := HexToRgb("#aabbcc") // rgb: [170 187 204] +// rgb := HexToRgb("0xad99c0") // rgb: [170 187 204] func HexToRgb(hex string) (rgb []int) { hex = strings.TrimSpace(hex) if hex == "" { @@ -453,6 +454,7 @@ func Rgb2hex(rgb []int) string { return RgbToHex(rgb) } // RgbToHex convert RGB-code to hex-code // // Usage: +// // hex := RgbToHex([]int{170, 187, 204}) // hex: "aabbcc" func RgbToHex(rgb []int) string { hexNodes := make([]string, len(rgb)) @@ -642,6 +644,7 @@ func C256ToRgbV1(val uint8) (rgb []uint8) { // returns r, g, and b in the set [0, 255]. // // Usage: +// // HslIntToRgb(0, 100, 50) // red // HslIntToRgb(120, 100, 50) // lime // HslIntToRgb(120, 100, 25) // dark green @@ -656,6 +659,7 @@ func HslIntToRgb(h, s, l int) (rgb []uint8) { // returns r, g, and b in the set [0, 255]. // // Usage: +// // rgbVals := HslToRgb(0, 1, 0.5) // red func HslToRgb(h, s, l float64) (rgb []uint8) { var r, g, b float64 diff --git a/vendor/github.com/gookit/color/detect_env.go b/vendor/github.com/gookit/color/detect_env.go index 3b2300db..612076f0 100644 --- a/vendor/github.com/gookit/color/detect_env.go +++ b/vendor/github.com/gookit/color/detect_env.go @@ -19,7 +19,8 @@ import ( // DetectColorLevel for current env // // NOTICE: The method will detect terminal info each times, -// if only want get current color level, please direct call SupportColor() or TermColorLevel() +// +// if only want get current color level, please direct call SupportColor() or TermColorLevel() func DetectColorLevel() terminfo.ColorLevel { level, _ := detectTermColorLevel() return level @@ -173,7 +174,9 @@ func detectWSL() bool { } // refer -// https://github.com/Delta456/box-cli-maker/blob/7b5a1ad8a016ce181e7d8b05e24b54ff60b4b38a/detect_unix.go#L27-L45 +// +// https://github.com/Delta456/box-cli-maker/blob/7b5a1ad8a016ce181e7d8b05e24b54ff60b4b38a/detect_unix.go#L27-L45 +// // detect WSL as it has True Color support func isWSL() bool { // on windows WSL: @@ -238,7 +241,8 @@ func IsMSys() bool { // IsSupportColor check current console is support color. // // NOTICE: The method will detect terminal info each times, -// if only want get current color level, please direct call SupportColor() or TermColorLevel() +// +// if only want get current color level, please direct call SupportColor() or TermColorLevel() func IsSupportColor() bool { return IsSupport16Color() } @@ -246,7 +250,8 @@ func IsSupportColor() bool { // IsSupportColor check current console is support color. // // NOTICE: The method will detect terminal info each times, -// if only want get current color level, please direct call SupportColor() or TermColorLevel() +// +// if only want get current color level, please direct call SupportColor() or TermColorLevel() func IsSupport16Color() bool { level, _ := detectTermColorLevel() return level > terminfo.ColorLevelNone @@ -255,7 +260,8 @@ func IsSupport16Color() bool { // IsSupport256Color render check // // NOTICE: The method will detect terminal info each times, -// if only want get current color level, please direct call SupportColor() or TermColorLevel() +// +// if only want get current color level, please direct call SupportColor() or TermColorLevel() func IsSupport256Color() bool { level, _ := detectTermColorLevel() return level > terminfo.ColorLevelBasic @@ -264,7 +270,8 @@ func IsSupport256Color() bool { // IsSupportRGBColor check. alias of the IsSupportTrueColor() // // NOTICE: The method will detect terminal info each times, -// if only want get current color level, please direct call SupportColor() or TermColorLevel() +// +// if only want get current color level, please direct call SupportColor() or TermColorLevel() func IsSupportRGBColor() bool { return IsSupportTrueColor() } @@ -272,7 +279,8 @@ func IsSupportRGBColor() bool { // IsSupportTrueColor render check. // // NOTICE: The method will detect terminal info each times, -// if only want get current color level, please direct call SupportColor() or TermColorLevel() +// +// if only want get current color level, please direct call SupportColor() or TermColorLevel() // // ENV: // "COLORTERM=truecolor" diff --git a/vendor/github.com/gookit/color/detect_nonwin.go b/vendor/github.com/gookit/color/detect_nonwin.go index 75c7202f..6f97ca3c 100644 --- a/vendor/github.com/gookit/color/detect_nonwin.go +++ b/vendor/github.com/gookit/color/detect_nonwin.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows // The method in the file has no effect @@ -42,7 +43,8 @@ func detectSpecialTermColor(termVal string) (terminfo.ColorLevel, bool) { // IsTerminal returns true if the given file descriptor is a terminal. // // Usage: -// IsTerminal(os.Stdout.Fd()) +// +// IsTerminal(os.Stdout.Fd()) func IsTerminal(fd uintptr) bool { return fd == uintptr(syscall.Stdout) || fd == uintptr(syscall.Stdin) || fd == uintptr(syscall.Stderr) } diff --git a/vendor/github.com/gookit/color/detect_windows.go b/vendor/github.com/gookit/color/detect_windows.go index 7707d9ca..b62d2c57 100644 --- a/vendor/github.com/gookit/color/detect_windows.go +++ b/vendor/github.com/gookit/color/detect_windows.go @@ -1,10 +1,12 @@ +//go:build windows // +build windows // Display color on windows // refer: -// golang.org/x/sys/windows -// golang.org/x/crypto/ssh/terminal -// https://docs.microsoft.com/en-us/windows/console +// +// golang.org/x/sys/windows +// golang.org/x/crypto/ssh/terminal +// https://docs.microsoft.com/en-us/windows/console package color import ( @@ -111,8 +113,10 @@ var ( ) // refer -// https://github.com/Delta456/box-cli-maker/blob/7b5a1ad8a016ce181e7d8b05e24b54ff60b4b38a/detect_windows.go#L30-L57 -// https://github.com/gookit/color/issues/25#issuecomment-738727917 +// +// https://github.com/Delta456/box-cli-maker/blob/7b5a1ad8a016ce181e7d8b05e24b54ff60b4b38a/detect_windows.go#L30-L57 +// https://github.com/gookit/color/issues/25#issuecomment-738727917 +// // detects the Color Level Supported on windows: cmd, powerShell func detectSpecialTermColor(termVal string) (tl terminfo.ColorLevel, needVTP bool) { if os.Getenv("ConEmuANSI") == "ON" { @@ -166,9 +170,10 @@ const ( // doc https://docs.microsoft.com/zh-cn/windows/console/console-virtual-terminal-sequences#samples // // Usage: -// err := EnableVirtualTerminalProcessing(syscall.Stdout, true) -// // support print color text -// err = EnableVirtualTerminalProcessing(syscall.Stdout, false) +// +// err := EnableVirtualTerminalProcessing(syscall.Stdout, true) +// // support print color text +// err = EnableVirtualTerminalProcessing(syscall.Stdout, false) func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error { var mode uint32 // Check if it is currently in the terminal @@ -231,9 +236,10 @@ func IsTty(fd uintptr) bool { // IsTerminal returns true if the given file descriptor is a terminal. // // Usage: -// fd := os.Stdout.Fd() -// fd := uintptr(syscall.Stdout) // for windows -// IsTerminal(fd) +// +// fd := os.Stdout.Fd() +// fd := uintptr(syscall.Stdout) // for windows +// IsTerminal(fd) func IsTerminal(fd uintptr) bool { initKernel32Proc() diff --git a/vendor/github.com/gookit/color/printer.go b/vendor/github.com/gookit/color/printer.go index 326aabc0..e5263633 100644 --- a/vendor/github.com/gookit/color/printer.go +++ b/vendor/github.com/gookit/color/printer.go @@ -19,8 +19,9 @@ type PrinterFace interface { // Printer a generic color message printer. // // Usage: -// p := &Printer{Code: "32;45;3"} -// p.Print("message") +// +// p := &Printer{Code: "32;45;3"} +// p.Print("message") type Printer struct { // NoColor disable color. NoColor bool diff --git a/vendor/github.com/gookit/color/style.go b/vendor/github.com/gookit/color/style.go index fad76fb3..81e61d14 100644 --- a/vendor/github.com/gookit/color/style.go +++ b/vendor/github.com/gookit/color/style.go @@ -12,12 +12,14 @@ import ( // Style a 16 color style. can add: fg color, bg color, color options // // Example: -// color.Style{color.FgGreen}.Print("message") +// +// color.Style{color.FgGreen}.Print("message") type Style []Color // New create a custom style // // Usage: +// // color.New(color.FgGreen).Print("message") // equals to: // color.Style{color.FgGreen}.Print("message") @@ -37,8 +39,9 @@ func (s *Style) Add(cs ...Color) { // Render render text // Usage: -// color.New(color.FgGreen).Render("text") -// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text") +// +// color.New(color.FgGreen).Render("text") +// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text") func (s Style) Render(a ...interface{}) string { return RenderCode(s.String(), a...) } @@ -46,8 +49,9 @@ func (s Style) Render(a ...interface{}) string { // Renderln render text line. // like Println, will add spaces for each argument // Usage: -// color.New(color.FgGreen).Renderln("text", "more") -// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text", "more") +// +// color.New(color.FgGreen).Renderln("text", "more") +// color.New(color.FgGreen, color.BgBlack, color.OpBold).Render("text", "more") func (s Style) Renderln(a ...interface{}) string { return RenderWithSpaces(s.String(), a...) } @@ -140,10 +144,11 @@ func (t *Theme) Block(format string, a ...interface{}) { // internal themes(like bootstrap style) // Usage: -// color.Info.Print("message") -// color.Info.Printf("a %s message", "test") -// color.Warn.Println("message") -// color.Error.Println("message") +// +// color.Info.Print("message") +// color.Info.Printf("a %s message", "test") +// color.Warn.Println("message") +// color.Error.Println("message") var ( // Info color style Info = &Theme{"info", Style{OpReset, FgGreen}} @@ -175,7 +180,8 @@ var ( // Themes internal defined themes. // Usage: -// color.Themes["info"].Println("message") +// +// color.Themes["info"].Println("message") var Themes = map[string]*Theme{ "info": Info, "note": Note, @@ -211,7 +217,8 @@ func GetTheme(name string) *Theme { // Styles internal defined styles, like bootstrap styles. // Usage: -// color.Styles["info"].Println("message") +// +// color.Styles["info"].Println("message") var Styles = map[string]Style{ "info": {OpReset, FgGreen}, "note": {OpBold, FgLightCyan}, diff --git a/vendor/github.com/gookit/color/utils.go b/vendor/github.com/gookit/color/utils.go index bfd13539..23d27d88 100644 --- a/vendor/github.com/gookit/color/utils.go +++ b/vendor/github.com/gookit/color/utils.go @@ -85,6 +85,7 @@ func Lprint(l *log.Logger, a ...interface{}) { // Render parse color tags, return rendered string. // Usage: +// // text := Render("hello world!") // fmt.Println(text) func Render(a ...interface{}) string { diff --git a/vendor/github.com/imdario/mergo/doc.go b/vendor/github.com/imdario/mergo/doc.go index fcd985f9..6c8fb45d 100644 --- a/vendor/github.com/imdario/mergo/doc.go +++ b/vendor/github.com/imdario/mergo/doc.go @@ -8,11 +8,11 @@ A helper to merge structs and maps in Golang. Useful for configuration default v Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection). -Status +# Status It is ready for production use. It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc. -Important note +# Important note Please keep in mind that a problematic PR broke 0.3.9. We reverted it in 0.3.10. We consider 0.3.10 as stable but not bug-free. . Also, this version adds suppot for go modules. @@ -20,18 +20,18 @@ Keep in mind that in 0.3.2, Mergo changed Merge() and Map() signatures to suppor If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with go get -u github.com/imdario/mergo. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0). -Install +# Install Do your usual installation procedure: - go get github.com/imdario/mergo + go get github.com/imdario/mergo - // use in your .go code - import ( - "github.com/imdario/mergo" - ) + // use in your .go code + import ( + "github.com/imdario/mergo" + ) -Usage +# Usage You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as they are zero values too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection). @@ -81,7 +81,7 @@ Here is a nice example: // {two 2} } -Transformers +# Transformers Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, time.Time is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero time.Time? @@ -127,17 +127,16 @@ Transformers allow to merge specific types differently than in the default behav // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 } } -Contact me +# Contact me If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): https://twitter.com/im_dario -About +# About Written by Dario Castañé: https://da.rio.hn -License +# License BSD 3-Clause license, as Go language. - */ package mergo diff --git a/vendor/github.com/integrii/flaggy/flag.go b/vendor/github.com/integrii/flaggy/flag.go index 409ddf94..26d66d2a 100644 --- a/vendor/github.com/integrii/flaggy/flag.go +++ b/vendor/github.com/integrii/flaggy/flag.go @@ -398,8 +398,9 @@ func parseArgWithValue(arg string) (key string, value string) { } // parseFlagToName parses a flag with space value down to a key name: -// --path -> path -// -p -> p +// +// --path -> path +// -p -> p func parseFlagToName(arg string) string { // remove minus from start arg = strings.TrimLeft(arg, "-") diff --git a/vendor/github.com/jesseduffield/yaml/apic.go b/vendor/github.com/jesseduffield/yaml/apic.go index 1f7e87e6..282b77ce 100644 --- a/vendor/github.com/jesseduffield/yaml/apic.go +++ b/vendor/github.com/jesseduffield/yaml/apic.go @@ -138,7 +138,7 @@ func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) { emitter.canonical = canonical } -//// Set the indentation increment. +// // Set the indentation increment. func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) { if indent < 2 || indent > 9 { indent = 2 diff --git a/vendor/github.com/jesseduffield/yaml/emitterc.go b/vendor/github.com/jesseduffield/yaml/emitterc.go index a1c2cc52..638a268c 100644 --- a/vendor/github.com/jesseduffield/yaml/emitterc.go +++ b/vendor/github.com/jesseduffield/yaml/emitterc.go @@ -130,10 +130,9 @@ func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool { // Check if we need to accumulate more events before emitting. // // We accumulate extra -// - 1 event for DOCUMENT-START -// - 2 events for SEQUENCE-START -// - 3 events for MAPPING-START -// +// - 1 event for DOCUMENT-START +// - 2 events for SEQUENCE-START +// - 3 events for MAPPING-START func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool { if emitter.events_head == len(emitter.events) { return true diff --git a/vendor/github.com/jesseduffield/yaml/parserc.go b/vendor/github.com/jesseduffield/yaml/parserc.go index 81d05dfe..2883e5c5 100644 --- a/vendor/github.com/jesseduffield/yaml/parserc.go +++ b/vendor/github.com/jesseduffield/yaml/parserc.go @@ -170,7 +170,8 @@ func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool // Parse the production: // stream ::= STREAM-START implicit_document? explicit_document* STREAM-END -// ************ +// +// ************ func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -192,9 +193,12 @@ func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) // Parse the productions: // implicit_document ::= block_node DOCUMENT-END* -// * +// +// * +// // explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// ************************* +// +// ************************* func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool { token := peek_token(parser) @@ -277,8 +281,8 @@ func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t // Parse the productions: // explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// *********** // +// *********** func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -299,9 +303,10 @@ func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event // Parse the productions: // implicit_document ::= block_node DOCUMENT-END* -// ************* -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* // +// ************* +// +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -332,30 +337,41 @@ func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) // Parse the productions: // block_node_or_indentless_sequence ::= -// ALIAS -// ***** -// | properties (block_content | indentless_block_sequence)? -// ********** * -// | block_content | indentless_block_sequence -// * +// +// ALIAS +// ***** +// | properties (block_content | indentless_block_sequence)? +// ********** * +// | block_content | indentless_block_sequence +// * +// // block_node ::= ALIAS -// ***** -// | properties block_content? -// ********** * -// | block_content -// * +// +// ***** +// | properties block_content? +// ********** * +// | block_content +// * +// // flow_node ::= ALIAS -// ***** -// | properties flow_content? -// ********** * -// | flow_content -// * +// +// ***** +// | properties flow_content? +// ********** * +// | flow_content +// * +// // properties ::= TAG ANCHOR? | ANCHOR TAG? -// ************************* +// +// ************************* +// // block_content ::= block_collection | flow_collection | SCALAR -// ****** +// +// ****** +// // flow_content ::= flow_collection | SCALAR -// ****** +// +// ****** func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool { //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)() @@ -574,8 +590,8 @@ func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, i // Parse the productions: // block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END -// ******************** *********** * ********* // +// ******************** *********** * ********* func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) @@ -627,7 +643,8 @@ func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_e // Parse the productions: // indentless_sequence ::= (BLOCK-ENTRY block_node?)+ -// *********** * +// +// *********** * func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -664,14 +681,14 @@ func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *y // Parse the productions: // block_mapping ::= BLOCK-MAPPING_START -// ******************* -// ((KEY block_node_or_indentless_sequence?)? -// *** * -// (VALUE block_node_or_indentless_sequence?)?)* // -// BLOCK-END -// ********* +// ******************* +// ((KEY block_node_or_indentless_sequence?)? +// *** * +// (VALUE block_node_or_indentless_sequence?)?)* // +// BLOCK-END +// ********* func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) @@ -723,13 +740,11 @@ func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_even // Parse the productions: // block_mapping ::= BLOCK-MAPPING_START // -// ((KEY block_node_or_indentless_sequence?)? -// -// (VALUE block_node_or_indentless_sequence?)?)* -// ***** * -// BLOCK-END -// +// ((KEY block_node_or_indentless_sequence?)? // +// (VALUE block_node_or_indentless_sequence?)?)* +// ***** * +// BLOCK-END func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -757,16 +772,18 @@ func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_ev // Parse the productions: // flow_sequence ::= FLOW-SEQUENCE-START -// ******************* -// (flow_sequence_entry FLOW-ENTRY)* -// * ********** -// flow_sequence_entry? -// * -// FLOW-SEQUENCE-END -// ***************** -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * // +// ******************* +// (flow_sequence_entry FLOW-ENTRY)* +// * ********** +// flow_sequence_entry? +// * +// FLOW-SEQUENCE-END +// ***************** +// +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// +// * func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) @@ -825,11 +842,10 @@ func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_ev return true } -// // Parse the productions: // flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// *** * // +// *** * func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -849,8 +865,8 @@ func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, ev // Parse the productions: // flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// ***** * // +// ***** * func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -873,8 +889,8 @@ func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, // Parse the productions: // flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * // +// * func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -891,16 +907,17 @@ func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, ev // Parse the productions: // flow_mapping ::= FLOW-MAPPING-START -// ****************** -// (flow_mapping_entry FLOW-ENTRY)* -// * ********** -// flow_mapping_entry? -// ****************** -// FLOW-MAPPING-END -// **************** -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * *** * // +// ****************** +// (flow_mapping_entry FLOW-ENTRY)* +// * ********** +// flow_mapping_entry? +// ****************** +// FLOW-MAPPING-END +// **************** +// +// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// - *** * func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) @@ -965,8 +982,7 @@ func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event // Parse the productions: // flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * ***** * -// +// - ***** * func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool { token := peek_token(parser) if token == nil { diff --git a/vendor/github.com/jesseduffield/yaml/readerc.go b/vendor/github.com/jesseduffield/yaml/readerc.go index 7c1f5fac..b0c436c4 100644 --- a/vendor/github.com/jesseduffield/yaml/readerc.go +++ b/vendor/github.com/jesseduffield/yaml/readerc.go @@ -95,7 +95,7 @@ func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool { // [Go] This function was changed to guarantee the requested length size at EOF. // The fact we need to do this is pretty awful, but the description above implies - // for that to be the case, and there are tests + // for that to be the case, and there are tests // If the EOF flag is set and the raw buffer is empty, do nothing. if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) { diff --git a/vendor/github.com/jesseduffield/yaml/resolve.go b/vendor/github.com/jesseduffield/yaml/resolve.go index 4120e0c9..e29c364b 100644 --- a/vendor/github.com/jesseduffield/yaml/resolve.go +++ b/vendor/github.com/jesseduffield/yaml/resolve.go @@ -180,7 +180,7 @@ func resolve(tag string, in string) (rtag string, out interface{}) { return yaml_INT_TAG, uintv } } else if strings.HasPrefix(plain, "-0b") { - intv, err := strconv.ParseInt("-" + plain[3:], 2, 64) + intv, err := strconv.ParseInt("-"+plain[3:], 2, 64) if err == nil { if true || intv == int64(int(intv)) { return yaml_INT_TAG, int(intv) diff --git a/vendor/github.com/jesseduffield/yaml/scannerc.go b/vendor/github.com/jesseduffield/yaml/scannerc.go index 077fd1dd..ea82e3e9 100644 --- a/vendor/github.com/jesseduffield/yaml/scannerc.go +++ b/vendor/github.com/jesseduffield/yaml/scannerc.go @@ -1485,11 +1485,11 @@ func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool { // Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. // // Scope: -// %YAML 1.1 # a comment \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // +// %YAML 1.1 # a comment \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool { // Eat '%'. start_mark := parser.mark @@ -1586,11 +1586,11 @@ func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool // Scan the directive name. // // Scope: -// %YAML 1.1 # a comment \n -// ^^^^ -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^ // +// %YAML 1.1 # a comment \n +// ^^^^ +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^ func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool { // Consume the directive name. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { @@ -1625,8 +1625,9 @@ func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark // Scan the value of VERSION-DIRECTIVE. // // Scope: -// %YAML 1.1 # a comment \n -// ^^^^^^ +// +// %YAML 1.1 # a comment \n +// ^^^^^^ func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool { // Eat whitespaces. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { @@ -1664,10 +1665,11 @@ const max_number_length = 2 // Scan the version number of VERSION-DIRECTIVE. // // Scope: -// %YAML 1.1 # a comment \n -// ^ -// %YAML 1.1 # a comment \n -// ^ +// +// %YAML 1.1 # a comment \n +// ^ +// %YAML 1.1 # a comment \n +// ^ func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool { // Repeat while the next character is digit. @@ -1701,9 +1703,9 @@ func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark // Scan the value of a TAG-DIRECTIVE token. // // Scope: -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool { var handle_value, prefix_value []byte diff --git a/vendor/github.com/jesseduffield/yaml/sorter.go b/vendor/github.com/jesseduffield/yaml/sorter.go index 4c45e660..2edd7340 100644 --- a/vendor/github.com/jesseduffield/yaml/sorter.go +++ b/vendor/github.com/jesseduffield/yaml/sorter.go @@ -52,7 +52,7 @@ func (l keyList) Less(i, j int) bool { var ai, bi int var an, bn int64 if ar[i] == '0' || br[i] == '0' { - for j := i-1; j >= 0 && unicode.IsDigit(ar[j]); j-- { + for j := i - 1; j >= 0 && unicode.IsDigit(ar[j]); j-- { if ar[j] != '0' { an = 1 bn = 1 diff --git a/vendor/github.com/jesseduffield/yaml/yaml.go b/vendor/github.com/jesseduffield/yaml/yaml.go index 5635f0f2..778a1941 100644 --- a/vendor/github.com/jesseduffield/yaml/yaml.go +++ b/vendor/github.com/jesseduffield/yaml/yaml.go @@ -2,8 +2,7 @@ // // Source code and other details for the project are available at GitHub: // -// https://github.com/go-yaml/yaml -// +// https://github.com/go-yaml/yaml package yaml import ( @@ -67,16 +66,15 @@ type Marshaler interface { // // For example: // -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// var t T -// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// var t T +// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) // // See the documentation of Marshal for the format of tags and a list of // supported tag options. -// func Unmarshal(in []byte, out interface{}) (err error) { return unmarshal(in, out, false) } @@ -166,36 +164,35 @@ func unmarshal(in []byte, out interface{}, strict bool) (err error) { // // The field tag format accepted is: // -// `(...) yaml:"[][,[,]]" (...)` +// `(...) yaml:"[][,[,]]" (...)` // // The following flags are currently supported: // -// omitempty Only include the field if it's not set to the zero -// value for the type or to empty slices or maps. -// Zero valued structs will be omitted if all their public -// fields are zero, unless they implement an IsZero -// method (see the IsZeroer interface type), in which -// case the field will be included if that method returns true. +// omitempty Only include the field if it's not set to the zero +// value for the type or to empty slices or maps. +// Zero valued structs will be omitted if all their public +// fields are zero, unless they implement an IsZero +// method (see the IsZeroer interface type), in which +// case the field will be included if that method returns true. // -// flow Marshal using a flow style (useful for structs, -// sequences and maps). +// flow Marshal using a flow style (useful for structs, +// sequences and maps). // -// inline Inline the field, which must be a struct or a map, -// causing all of its fields or keys to be processed as if -// they were part of the outer struct. For maps, keys must -// not conflict with the yaml keys of other struct fields. +// inline Inline the field, which must be a struct or a map, +// causing all of its fields or keys to be processed as if +// they were part of the outer struct. For maps, keys must +// not conflict with the yaml keys of other struct fields. // // In addition, if the key is "-", the field is ignored. // // For example: // -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" -// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" -// +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" +// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" func Marshal(in interface{}) (out []byte, err error) { defer handleErr(&err) e := newEncoder() diff --git a/vendor/github.com/jesseduffield/yaml/yamlh.go b/vendor/github.com/jesseduffield/yaml/yamlh.go index e25cee56..2dbb4a56 100644 --- a/vendor/github.com/jesseduffield/yaml/yamlh.go +++ b/vendor/github.com/jesseduffield/yaml/yamlh.go @@ -408,7 +408,9 @@ type yaml_document_t struct { // The number of written bytes should be set to the size_read variable. // // [in,out] data A pointer to an application data specified by -// yaml_parser_set_input(). +// +// yaml_parser_set_input(). +// // [out] buffer The buffer to write the data from the source. // [in] size The size of the buffer. // [out] size_read The actual number of bytes read from the source. @@ -603,13 +605,14 @@ type yaml_parser_t struct { // @a buffer to the output. // // @param[in,out] data A pointer to an application data specified by -// yaml_emitter_set_output(). +// +// yaml_emitter_set_output(). +// // @param[in] buffer The buffer with bytes to be written. // @param[in] size The size of the buffer. // // @returns On success, the handler should return @c 1. If the handler failed, // the returned value should be @c 0. -// type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error type yaml_emitter_state_t int diff --git a/vendor/github.com/lucasb-eyer/go-colorful/hsluv.go b/vendor/github.com/lucasb-eyer/go-colorful/hsluv.go index d19fb644..3adadeed 100644 --- a/vendor/github.com/lucasb-eyer/go-colorful/hsluv.go +++ b/vendor/github.com/lucasb-eyer/go-colorful/hsluv.go @@ -11,7 +11,8 @@ import "math" // comparing to the test values, this modified white reference is used internally. // // See this GitHub thread for details on these values: -// https://github.com/hsluv/hsluv/issues/79 +// +// https://github.com/hsluv/hsluv/issues/79 var hSLuvD65 = [3]float64{0.95045592705167, 1.0, 1.089057750759878} func LuvLChToHSLuv(l, c, h float64) (float64, float64, float64) { diff --git a/vendor/github.com/mattn/go-colorable/colorable_appengine.go b/vendor/github.com/mattn/go-colorable/colorable_appengine.go index 1f7806fe..416d1bbb 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_appengine.go +++ b/vendor/github.com/mattn/go-colorable/colorable_appengine.go @@ -1,3 +1,4 @@ +//go:build appengine // +build appengine package colorable diff --git a/vendor/github.com/mattn/go-colorable/colorable_others.go b/vendor/github.com/mattn/go-colorable/colorable_others.go index 08cbd1e0..766d9460 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_others.go +++ b/vendor/github.com/mattn/go-colorable/colorable_others.go @@ -1,5 +1,5 @@ -// +build !windows -// +build !appengine +//go:build !windows && !appengine +// +build !windows,!appengine package colorable diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go index 41215d7f..e7a07158 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_windows.go +++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go @@ -1,5 +1,5 @@ -// +build windows -// +build !appengine +//go:build windows && !appengine +// +build windows,!appengine package colorable diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go index 711f2880..39bbcf00 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_bsd.go +++ b/vendor/github.com/mattn/go-isatty/isatty_bsd.go @@ -1,3 +1,4 @@ +//go:build (darwin || freebsd || openbsd || netbsd || dragonfly) && !appengine // +build darwin freebsd openbsd netbsd dragonfly // +build !appengine diff --git a/vendor/github.com/mattn/go-isatty/isatty_others.go b/vendor/github.com/mattn/go-isatty/isatty_others.go index ff714a37..bad6c0ed 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_others.go +++ b/vendor/github.com/mattn/go-isatty/isatty_others.go @@ -1,3 +1,4 @@ +//go:build appengine || js || nacl // +build appengine js nacl package isatty diff --git a/vendor/github.com/mattn/go-isatty/isatty_plan9.go b/vendor/github.com/mattn/go-isatty/isatty_plan9.go index c5b6e0c0..bae7f9bb 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_plan9.go +++ b/vendor/github.com/mattn/go-isatty/isatty_plan9.go @@ -1,3 +1,4 @@ +//go:build plan9 // +build plan9 package isatty diff --git a/vendor/github.com/mattn/go-isatty/isatty_solaris.go b/vendor/github.com/mattn/go-isatty/isatty_solaris.go index bdd5c79a..69e5ab3c 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_solaris.go +++ b/vendor/github.com/mattn/go-isatty/isatty_solaris.go @@ -1,5 +1,5 @@ -// +build solaris -// +build !appengine +//go:build solaris && !appengine +// +build solaris,!appengine package isatty diff --git a/vendor/github.com/mattn/go-isatty/isatty_tcgets.go b/vendor/github.com/mattn/go-isatty/isatty_tcgets.go index 31a1ca97..eb6e9ac5 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_tcgets.go +++ b/vendor/github.com/mattn/go-isatty/isatty_tcgets.go @@ -1,3 +1,4 @@ +//go:build (linux || aix) && !appengine // +build linux aix // +build !appengine diff --git a/vendor/github.com/mattn/go-isatty/isatty_windows.go b/vendor/github.com/mattn/go-isatty/isatty_windows.go index 1fa86915..62be5e5a 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_windows.go +++ b/vendor/github.com/mattn/go-isatty/isatty_windows.go @@ -1,5 +1,5 @@ -// +build windows -// +build !appengine +//go:build windows && !appengine +// +build windows,!appengine package isatty @@ -42,7 +42,8 @@ func IsTerminal(fd uintptr) bool { // Check pipe name is used for cygwin/msys2 pty. // Cygwin/MSYS2 PTY has a name like: -// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master +// +// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master func isCygwinPipeName(name string) bool { token := strings.Split(name, "-") if len(token) < 5 { diff --git a/vendor/github.com/mgutz/str/doc.go b/vendor/github.com/mgutz/str/doc.go index f48742a1..6109054c 100644 --- a/vendor/github.com/mgutz/str/doc.go +++ b/vendor/github.com/mgutz/str/doc.go @@ -5,15 +5,14 @@ // Str is based on plain functions instead of object-based methods, // consistent with Go standard string packages. // -// str.Between("foo", "", "") == "foo" +// str.Between("foo", "", "") == "foo" // // Str supports pipelining instead of chaining // -// s := str.Pipe("\nabcdef\n", Clean, BetweenF("a", "f"), ChompLeftF("bc")) +// s := str.Pipe("\nabcdef\n", Clean, BetweenF("a", "f"), ChompLeftF("bc")) // // User-defined filters can be added to the pipeline by inserting a function // or closure that returns a function with this signature // -// func(string) string -// +// func(string) string package str diff --git a/vendor/github.com/opencontainers/go-digest/digest.go b/vendor/github.com/opencontainers/go-digest/digest.go index 518b5e71..465996ce 100644 --- a/vendor/github.com/opencontainers/go-digest/digest.go +++ b/vendor/github.com/opencontainers/go-digest/digest.go @@ -30,7 +30,7 @@ import ( // // The following is an example of the contents of Digest types: // -// sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc +// sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc // // This allows to abstract the digest behind this type and work only in those // terms. diff --git a/vendor/github.com/opencontainers/go-digest/doc.go b/vendor/github.com/opencontainers/go-digest/doc.go index 83d3a936..e2dd44f4 100644 --- a/vendor/github.com/opencontainers/go-digest/doc.go +++ b/vendor/github.com/opencontainers/go-digest/doc.go @@ -19,16 +19,16 @@ // More importantly, it provides tools and wrappers to work with // hash.Hash-based digests with little effort. // -// Basics +// # Basics // // The format of a digest is simply a string with two parts, dubbed the // "algorithm" and the "digest", separated by a colon: // -// : +// : // // An example of a sha256 digest representation follows: // -// sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc +// sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc // // The "algorithm" portion defines both the hashing algorithm used to calculate // the digest and the encoding of the resulting digest, which defaults to "hex" @@ -42,7 +42,7 @@ // obtained, comparisons are cheap, quick and simple to express with the // standard equality operator. // -// Verification +// # Verification // // The main benefit of using the Digest type is simple verification against a // given digest. The Verifier interface, modeled after the stdlib hash.Hash @@ -50,7 +50,7 @@ // writing is complete, calling the Verifier.Verified method will indicate // whether or not the stream of bytes matches the target digest. // -// Missing Features +// # Missing Features // // In addition to the above, we intend to add the following features to this // package: @@ -58,5 +58,4 @@ // 1. A Digester type that supports write sink digest calculation. // // 2. Suspend and resume of ongoing digest calculations to support efficient digest verification in the registry. -// package digest diff --git a/vendor/github.com/petermattis/goid/goid_gccgo.go b/vendor/github.com/petermattis/goid/goid_gccgo.go index e655e068..31c14d99 100644 --- a/vendor/github.com/petermattis/goid/goid_gccgo.go +++ b/vendor/github.com/petermattis/goid/goid_gccgo.go @@ -13,6 +13,7 @@ // permissions and limitations under the License. See the AUTHORS file // for names of contributors. +//go:build gccgo // +build gccgo package goid diff --git a/vendor/github.com/petermattis/goid/goid_go1.3.go b/vendor/github.com/petermattis/goid/goid_go1.3.go index 9202099e..d73b6992 100644 --- a/vendor/github.com/petermattis/goid/goid_go1.3.go +++ b/vendor/github.com/petermattis/goid/goid_go1.3.go @@ -13,6 +13,7 @@ // permissions and limitations under the License. See the AUTHORS file // for names of contributors. +//go:build !go1.4 // +build !go1.4 package goid diff --git a/vendor/github.com/petermattis/goid/goid_go1.4.go b/vendor/github.com/petermattis/goid/goid_go1.4.go index ec7fc52d..4798980b 100644 --- a/vendor/github.com/petermattis/goid/goid_go1.4.go +++ b/vendor/github.com/petermattis/goid/goid_go1.4.go @@ -13,6 +13,7 @@ // permissions and limitations under the License. See the AUTHORS file // for names of contributors. +//go:build go1.4 && !go1.5 // +build go1.4,!go1.5 package goid diff --git a/vendor/github.com/petermattis/goid/goid_go1.5_amd64.go b/vendor/github.com/petermattis/goid/goid_go1.5_amd64.go index 269abb3f..d6893559 100644 --- a/vendor/github.com/petermattis/goid/goid_go1.5_amd64.go +++ b/vendor/github.com/petermattis/goid/goid_go1.5_amd64.go @@ -13,8 +13,10 @@ // permissions and limitations under the License. See the AUTHORS file // for names of contributors. +//go:build (amd64 || amd64p32) && gc && go1.5 // +build amd64 amd64p32 -// +build gc,go1.5 +// +build gc +// +build go1.5 package goid diff --git a/vendor/github.com/petermattis/goid/goid_go1.5_arm.go b/vendor/github.com/petermattis/goid/goid_go1.5_arm.go index 97fb8165..dbd653e1 100644 --- a/vendor/github.com/petermattis/goid/goid_go1.5_arm.go +++ b/vendor/github.com/petermattis/goid/goid_go1.5_arm.go @@ -13,8 +13,8 @@ // permissions and limitations under the License. See the AUTHORS file // for names of contributors. -// +build arm -// +build gc,go1.5 +//go:build arm && gc && go1.5 +// +build arm,gc,go1.5 package goid diff --git a/vendor/github.com/petermattis/goid/goid_slow.go b/vendor/github.com/petermattis/goid/goid_slow.go index d2d37650..d3c87b2c 100644 --- a/vendor/github.com/petermattis/goid/goid_slow.go +++ b/vendor/github.com/petermattis/goid/goid_slow.go @@ -13,6 +13,7 @@ // permissions and limitations under the License. See the AUTHORS file // for names of contributors. +//go:build (go1.4 && !go1.5 && !amd64 && !amd64p32 && !arm && !386) || (go1.5 && !go1.6 && !amd64 && !amd64p32 && !arm) || (go1.6 && !amd64 && !amd64p32 && !arm) || (go1.9 && !amd64 && !amd64p32 && !arm) // +build go1.4,!go1.5,!amd64,!amd64p32,!arm,!386 go1.5,!go1.6,!amd64,!amd64p32,!arm go1.6,!amd64,!amd64p32,!arm go1.9,!amd64,!amd64p32,!arm package goid diff --git a/vendor/github.com/petermattis/goid/runtime_gccgo_go1.8.go b/vendor/github.com/petermattis/goid/runtime_gccgo_go1.8.go index 42c12bcc..625e75ca 100644 --- a/vendor/github.com/petermattis/goid/runtime_gccgo_go1.8.go +++ b/vendor/github.com/petermattis/goid/runtime_gccgo_go1.8.go @@ -1,3 +1,4 @@ +//go:build gccgo && go1.8 // +build gccgo,go1.8 package goid diff --git a/vendor/github.com/petermattis/goid/runtime_go1.5.go b/vendor/github.com/petermattis/goid/runtime_go1.5.go index e1279a01..6ce2ab8e 100644 --- a/vendor/github.com/petermattis/goid/runtime_go1.5.go +++ b/vendor/github.com/petermattis/goid/runtime_go1.5.go @@ -13,6 +13,7 @@ // permissions and limitations under the License. See the AUTHORS file // for names of contributors. +//go:build go1.5 && !go1.6 // +build go1.5,!go1.6 package goid diff --git a/vendor/github.com/petermattis/goid/runtime_go1.6.go b/vendor/github.com/petermattis/goid/runtime_go1.6.go index 6b0067b1..983d55bc 100644 --- a/vendor/github.com/petermattis/goid/runtime_go1.6.go +++ b/vendor/github.com/petermattis/goid/runtime_go1.6.go @@ -1,3 +1,4 @@ +//go:build gc && go1.6 && !go1.9 // +build gc,go1.6,!go1.9 package goid diff --git a/vendor/github.com/petermattis/goid/runtime_go1.9.go b/vendor/github.com/petermattis/goid/runtime_go1.9.go index bf2c6966..5283ae04 100644 --- a/vendor/github.com/petermattis/goid/runtime_go1.9.go +++ b/vendor/github.com/petermattis/goid/runtime_go1.9.go @@ -1,3 +1,4 @@ +//go:build gc && go1.9 // +build gc,go1.9 package goid diff --git a/vendor/github.com/pkg/errors/errors.go b/vendor/github.com/pkg/errors/errors.go index 161aea25..5d90dd4c 100644 --- a/vendor/github.com/pkg/errors/errors.go +++ b/vendor/github.com/pkg/errors/errors.go @@ -2,89 +2,89 @@ // // The traditional error handling idiom in Go is roughly akin to // -// if err != nil { -// return err -// } +// if err != nil { +// return err +// } // // which when applied recursively up the call stack results in error reports // without context or debugging information. The errors package allows // programmers to add context to the failure path in their code in a way // that does not destroy the original value of the error. // -// Adding context to an error +// # Adding context to an error // // The errors.Wrap function returns a new error that adds context to the // original error by recording a stack trace at the point Wrap is called, // together with the supplied message. For example // -// _, err := ioutil.ReadAll(r) -// if err != nil { -// return errors.Wrap(err, "read failed") -// } +// _, err := ioutil.ReadAll(r) +// if err != nil { +// return errors.Wrap(err, "read failed") +// } // // If additional control is required, the errors.WithStack and // errors.WithMessage functions destructure errors.Wrap into its component // operations: annotating an error with a stack trace and with a message, // respectively. // -// Retrieving the cause of an error +// # Retrieving the cause of an error // // Using errors.Wrap constructs a stack of errors, adding context to the // preceding error. Depending on the nature of the error it may be necessary // to reverse the operation of errors.Wrap to retrieve the original error // for inspection. Any error value which implements this interface // -// type causer interface { -// Cause() error -// } +// type causer interface { +// Cause() error +// } // // can be inspected by errors.Cause. errors.Cause will recursively retrieve // the topmost error that does not implement causer, which is assumed to be // the original cause. For example: // -// switch err := errors.Cause(err).(type) { -// case *MyError: -// // handle specifically -// default: -// // unknown error -// } +// switch err := errors.Cause(err).(type) { +// case *MyError: +// // handle specifically +// default: +// // unknown error +// } // // Although the causer interface is not exported by this package, it is // considered a part of its stable public interface. // -// Formatted printing of errors +// # Formatted printing of errors // // All error values returned from this package implement fmt.Formatter and can // be formatted by the fmt package. The following verbs are supported: // -// %s print the error. If the error has a Cause it will be -// printed recursively. -// %v see %s -// %+v extended format. Each Frame of the error's StackTrace will -// be printed in detail. +// %s print the error. If the error has a Cause it will be +// printed recursively. +// %v see %s +// %+v extended format. Each Frame of the error's StackTrace will +// be printed in detail. // -// Retrieving the stack trace of an error or wrapper +// # Retrieving the stack trace of an error or wrapper // // New, Errorf, Wrap, and Wrapf record a stack trace at the point they are // invoked. This information can be retrieved with the following interface: // -// type stackTracer interface { -// StackTrace() errors.StackTrace -// } +// type stackTracer interface { +// StackTrace() errors.StackTrace +// } // // The returned errors.StackTrace type is defined as // -// type StackTrace []Frame +// type StackTrace []Frame // // The Frame type represents a call site in the stack trace. Frame supports // the fmt.Formatter interface that can be used for printing information about // the stack trace of this error. For example: // -// if err, ok := err.(stackTracer); ok { -// for _, f := range err.StackTrace() { -// fmt.Printf("%+s:%d\n", f, f) -// } -// } +// if err, ok := err.(stackTracer); ok { +// for _, f := range err.StackTrace() { +// fmt.Printf("%+s:%d\n", f, f) +// } +// } // // Although the stackTracer interface is not exported by this package, it is // considered a part of its stable public interface. @@ -265,9 +265,9 @@ func (w *withMessage) Format(s fmt.State, verb rune) { // An error value has a cause if it implements the following // interface: // -// type causer interface { -// Cause() error -// } +// type causer interface { +// Cause() error +// } // // If the error does not implement Cause, the original error will // be returned. If the error is nil, nil will be returned without further diff --git a/vendor/github.com/pkg/errors/go113.go b/vendor/github.com/pkg/errors/go113.go index be0d10d0..2c83c724 100644 --- a/vendor/github.com/pkg/errors/go113.go +++ b/vendor/github.com/pkg/errors/go113.go @@ -1,3 +1,4 @@ +//go:build go1.13 // +build go1.13 package errors diff --git a/vendor/github.com/pkg/errors/stack.go b/vendor/github.com/pkg/errors/stack.go index 779a8348..82784d70 100644 --- a/vendor/github.com/pkg/errors/stack.go +++ b/vendor/github.com/pkg/errors/stack.go @@ -51,16 +51,16 @@ func (f Frame) name() string { // Format formats the frame according to the fmt.Formatter interface. // -// %s source file -// %d source line -// %n function name -// %v equivalent to %s:%d +// %s source file +// %d source line +// %n function name +// %v equivalent to %s:%d // // Format accepts flags that alter the printing of some verbs, as follows: // -// %+s function name and path of source file relative to the compile time -// GOPATH separated by \n\t (\n\t) -// %+v equivalent to %+s:%d +// %+s function name and path of source file relative to the compile time +// GOPATH separated by \n\t (\n\t) +// %+v equivalent to %+s:%d func (f Frame) Format(s fmt.State, verb rune) { switch verb { case 's': @@ -98,12 +98,12 @@ type StackTrace []Frame // Format formats the stack of Frames according to the fmt.Formatter interface. // -// %s lists source files for each Frame in the stack -// %v lists the source file and line number for each Frame in the stack +// %s lists source files for each Frame in the stack +// %v lists the source file and line number for each Frame in the stack // // Format accepts flags that alter the printing of some verbs, as follows: // -// %+v Prints filename, function, and line number for each Frame in the stack. +// %+v Prints filename, function, and line number for each Frame in the stack. func (st StackTrace) Format(s fmt.State, verb rune) { switch verb { case 'v': diff --git a/vendor/github.com/pmezard/go-difflib/difflib/difflib.go b/vendor/github.com/pmezard/go-difflib/difflib/difflib.go index 003e99fa..6eb45526 100644 --- a/vendor/github.com/pmezard/go-difflib/difflib/difflib.go +++ b/vendor/github.com/pmezard/go-difflib/difflib/difflib.go @@ -161,12 +161,12 @@ func (m *SequenceMatcher) chainB() { m.bJunk = map[string]struct{}{} if m.IsJunk != nil { junk := m.bJunk - for s, _ := range b2j { + for s := range b2j { if m.IsJunk(s) { junk[s] = struct{}{} } } - for s, _ := range junk { + for s := range junk { delete(b2j, s) } } @@ -181,7 +181,7 @@ func (m *SequenceMatcher) chainB() { popular[s] = struct{}{} } } - for s, _ := range popular { + for s := range popular { delete(b2j, s) } } @@ -199,12 +199,15 @@ func (m *SequenceMatcher) isBJunk(s string) bool { // If IsJunk is not defined: // // Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where -// alo <= i <= i+k <= ahi -// blo <= j <= j+k <= bhi +// +// alo <= i <= i+k <= ahi +// blo <= j <= j+k <= bhi +// // and for all (i',j',k') meeting those conditions, -// k >= k' -// i <= i' -// and if i == i', j <= j' +// +// k >= k' +// i <= i' +// and if i == i', j <= j' // // In other words, of all maximal matching blocks, return one that // starts earliest in a, and of all those maximal matching blocks that @@ -416,7 +419,7 @@ func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode { } codes := m.GetOpCodes() if len(codes) == 0 { - codes = []OpCode{OpCode{'e', 0, 1, 0, 1}} + codes = []OpCode{{'e', 0, 1, 0, 1}} } // Fixup leading and trailing groups if they show no changes. if codes[0].Tag == 'e' { diff --git a/vendor/github.com/sasha-s/go-deadlock/deadlock_map.go b/vendor/github.com/sasha-s/go-deadlock/deadlock_map.go index ec66bdc0..70277f2b 100644 --- a/vendor/github.com/sasha-s/go-deadlock/deadlock_map.go +++ b/vendor/github.com/sasha-s/go-deadlock/deadlock_map.go @@ -1,3 +1,4 @@ +//go:build go1.9 // +build go1.9 package deadlock diff --git a/vendor/github.com/sirupsen/logrus/doc.go b/vendor/github.com/sirupsen/logrus/doc.go index da67aba0..51392be8 100644 --- a/vendor/github.com/sirupsen/logrus/doc.go +++ b/vendor/github.com/sirupsen/logrus/doc.go @@ -1,25 +1,25 @@ /* Package logrus is a structured logger for Go, completely API compatible with the standard library logger. - The simplest way to use Logrus is simply the package-level exported logger: - package main + package main - import ( - log "github.com/sirupsen/logrus" - ) + import ( + log "github.com/sirupsen/logrus" + ) - func main() { - log.WithFields(log.Fields{ - "animal": "walrus", - "number": 1, - "size": 10, - }).Info("A walrus appears") - } + func main() { + log.WithFields(log.Fields{ + "animal": "walrus", + "number": 1, + "size": 10, + }).Info("A walrus appears") + } Output: - time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 + + time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 For a full guide visit https://github.com/sirupsen/logrus */ diff --git a/vendor/github.com/sirupsen/logrus/formatter.go b/vendor/github.com/sirupsen/logrus/formatter.go index 40888377..8c761551 100644 --- a/vendor/github.com/sirupsen/logrus/formatter.go +++ b/vendor/github.com/sirupsen/logrus/formatter.go @@ -30,12 +30,12 @@ type Formatter interface { // This is to not silently overwrite `time`, `msg`, `func` and `level` fields when // dumping it. If this code wasn't there doing: // -// logrus.WithField("level", 1).Info("hello") +// logrus.WithField("level", 1).Info("hello") // // Would just silently drop the user provided level. Instead with this code // it'll logged as: // -// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} +// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} // // It's not exported because it's still using Data in an opinionated way. It's to // avoid code duplication between the two default formatters. diff --git a/vendor/github.com/sirupsen/logrus/logger.go b/vendor/github.com/sirupsen/logrus/logger.go index 5ff0aef6..df059412 100644 --- a/vendor/github.com/sirupsen/logrus/logger.go +++ b/vendor/github.com/sirupsen/logrus/logger.go @@ -76,12 +76,12 @@ func (mw *MutexWrap) Disable() { // `Out` and `Hooks` directly on the default logger instance. You can also just // instantiate your own: // -// var log = &logrus.Logger{ -// Out: os.Stderr, -// Formatter: new(logrus.TextFormatter), -// Hooks: make(logrus.LevelHooks), -// Level: logrus.DebugLevel, -// } +// var log = &logrus.Logger{ +// Out: os.Stderr, +// Formatter: new(logrus.TextFormatter), +// Hooks: make(logrus.LevelHooks), +// Level: logrus.DebugLevel, +// } // // It's recommended to make this a global instance called `log`. func New() *Logger { @@ -347,9 +347,9 @@ func (logger *Logger) Exit(code int) { logger.ExitFunc(code) } -//When file is opened with appending mode, it's safe to -//write concurrently to a file (within 4k message on Linux). -//In these cases user can choose to disable the lock. +// When file is opened with appending mode, it's safe to +// write concurrently to a file (within 4k message on Linux). +// In these cases user can choose to disable the lock. func (logger *Logger) SetNoLock() { logger.mu.Disable() } diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go index 2403de98..45de3e2b 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go +++ b/vendor/github.com/sirupsen/logrus/terminal_check_appengine.go @@ -1,3 +1,4 @@ +//go:build appengine // +build appengine package logrus diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go index 49978998..e3fa38b7 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go +++ b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go @@ -1,3 +1,4 @@ +//go:build (darwin || dragonfly || freebsd || netbsd || openbsd) && !js // +build darwin dragonfly freebsd netbsd openbsd // +build !js diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_js.go b/vendor/github.com/sirupsen/logrus/terminal_check_js.go index ebdae3ec..9e951f1b 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_check_js.go +++ b/vendor/github.com/sirupsen/logrus/terminal_check_js.go @@ -1,3 +1,4 @@ +//go:build js // +build js package logrus diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go b/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go index 97af92c6..04232da1 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go +++ b/vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go @@ -1,3 +1,4 @@ +//go:build js || nacl || plan9 // +build js nacl plan9 package logrus diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go index 3293fb3c..1b4a99e3 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go +++ b/vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go @@ -1,3 +1,4 @@ +//go:build !appengine && !js && !windows && !nacl && !plan9 // +build !appengine,!js,!windows,!nacl,!plan9 package logrus diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go index 04748b85..f3154b17 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go +++ b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go @@ -1,3 +1,4 @@ +//go:build (linux || aix || zos) && !js // +build linux aix zos // +build !js diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go index 2879eb50..893c6241 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_check_windows.go +++ b/vendor/github.com/sirupsen/logrus/terminal_check_windows.go @@ -1,3 +1,4 @@ +//go:build !appengine && !js && windows // +build !appengine,!js,windows package logrus diff --git a/vendor/github.com/spkg/bom/discard_go14.go b/vendor/github.com/spkg/bom/discard_go14.go index 782cd062..74ac0a21 100644 --- a/vendor/github.com/spkg/bom/discard_go14.go +++ b/vendor/github.com/spkg/bom/discard_go14.go @@ -1,3 +1,4 @@ +//go:build !go1.5 // +build !go1.5 package bom diff --git a/vendor/github.com/spkg/bom/discard_go15.go b/vendor/github.com/spkg/bom/discard_go15.go index 2d17d5c5..05ff40fb 100644 --- a/vendor/github.com/spkg/bom/discard_go15.go +++ b/vendor/github.com/spkg/bom/discard_go15.go @@ -1,3 +1,4 @@ +//go:build go1.5 // +build go1.5 package bom diff --git a/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go b/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go index 312ae6ac..f97296d2 100644 --- a/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go +++ b/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go @@ -816,10 +816,10 @@ func Lstat(path string, stat *Stat_t) (err error) { // for checking symlinks begins with $VERSION/ $SYSNAME/ $SYSSYMR/ $SYSSYMA/ func isSpecialPath(path []byte) (v bool) { var special = [4][8]byte{ - [8]byte{'V', 'E', 'R', 'S', 'I', 'O', 'N', '/'}, - [8]byte{'S', 'Y', 'S', 'N', 'A', 'M', 'E', '/'}, - [8]byte{'S', 'Y', 'S', 'S', 'Y', 'M', 'R', '/'}, - [8]byte{'S', 'Y', 'S', 'S', 'Y', 'M', 'A', '/'}} + {'V', 'E', 'R', 'S', 'I', 'O', 'N', '/'}, + {'S', 'Y', 'S', 'N', 'A', 'M', 'E', '/'}, + {'S', 'Y', 'S', 'S', 'Y', 'M', 'R', '/'}, + {'S', 'Y', 'S', 'S', 'Y', 'M', 'A', '/'}} var i, j int for i = 0; i < len(special); i++ { diff --git a/vendor/golang.org/x/xerrors/doc.go b/vendor/golang.org/x/xerrors/doc.go index eef99d9d..2ef99f5a 100644 --- a/vendor/golang.org/x/xerrors/doc.go +++ b/vendor/golang.org/x/xerrors/doc.go @@ -5,7 +5,8 @@ // Package xerrors implements functions to manipulate errors. // // This package is based on the Go 2 proposal for error values: -// https://golang.org/design/29934-error-values +// +// https://golang.org/design/29934-error-values // // These functions were incorporated into the standard library's errors package // in Go 1.13: diff --git a/vendor/gopkg.in/yaml.v3/apic.go b/vendor/gopkg.in/yaml.v3/apic.go index ae7d049f..05fd305d 100644 --- a/vendor/gopkg.in/yaml.v3/apic.go +++ b/vendor/gopkg.in/yaml.v3/apic.go @@ -1,17 +1,17 @@ -// +// // Copyright (c) 2011-2019 Canonical Ltd // Copyright (c) 2006-2010 Kirill Simonov -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies // of the Software, and to permit persons to whom the Software is furnished to do // so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/vendor/gopkg.in/yaml.v3/emitterc.go b/vendor/gopkg.in/yaml.v3/emitterc.go index 0f47c9ca..dde20e50 100644 --- a/vendor/gopkg.in/yaml.v3/emitterc.go +++ b/vendor/gopkg.in/yaml.v3/emitterc.go @@ -162,10 +162,9 @@ func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool { // Check if we need to accumulate more events before emitting. // // We accumulate extra -// - 1 event for DOCUMENT-START -// - 2 events for SEQUENCE-START -// - 3 events for MAPPING-START -// +// - 1 event for DOCUMENT-START +// - 2 events for SEQUENCE-START +// - 3 events for MAPPING-START func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool { if emitter.events_head == len(emitter.events) { return true @@ -241,7 +240,7 @@ func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool emitter.indent += 2 } else { // Everything else aligns to the chosen indentation. - emitter.indent = emitter.best_indent*((emitter.indent+emitter.best_indent)/emitter.best_indent) + emitter.indent = emitter.best_indent * ((emitter.indent + emitter.best_indent) / emitter.best_indent) } } return true diff --git a/vendor/gopkg.in/yaml.v3/parserc.go b/vendor/gopkg.in/yaml.v3/parserc.go index 268558a0..25fe8236 100644 --- a/vendor/gopkg.in/yaml.v3/parserc.go +++ b/vendor/gopkg.in/yaml.v3/parserc.go @@ -227,7 +227,8 @@ func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool // Parse the production: // stream ::= STREAM-START implicit_document? explicit_document* STREAM-END -// ************ +// +// ************ func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -249,9 +250,12 @@ func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) // Parse the productions: // implicit_document ::= block_node DOCUMENT-END* -// * +// +// * +// // explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// ************************* +// +// ************************* func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool { token := peek_token(parser) @@ -356,8 +360,8 @@ func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t // Parse the productions: // explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// *********** // +// *********** func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -379,9 +383,10 @@ func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event // Parse the productions: // implicit_document ::= block_node DOCUMENT-END* -// ************* -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* // +// ************* +// +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -428,30 +433,41 @@ func yaml_parser_set_event_comments(parser *yaml_parser_t, event *yaml_event_t) // Parse the productions: // block_node_or_indentless_sequence ::= -// ALIAS -// ***** -// | properties (block_content | indentless_block_sequence)? -// ********** * -// | block_content | indentless_block_sequence -// * +// +// ALIAS +// ***** +// | properties (block_content | indentless_block_sequence)? +// ********** * +// | block_content | indentless_block_sequence +// * +// // block_node ::= ALIAS -// ***** -// | properties block_content? -// ********** * -// | block_content -// * +// +// ***** +// | properties block_content? +// ********** * +// | block_content +// * +// // flow_node ::= ALIAS -// ***** -// | properties flow_content? -// ********** * -// | flow_content -// * +// +// ***** +// | properties flow_content? +// ********** * +// | flow_content +// * +// // properties ::= TAG ANCHOR? | ANCHOR TAG? -// ************************* +// +// ************************* +// // block_content ::= block_collection | flow_collection | SCALAR -// ****** +// +// ****** +// // flow_content ::= flow_collection | SCALAR -// ****** +// +// ****** func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool { //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)() @@ -682,8 +698,8 @@ func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, i // Parse the productions: // block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END -// ******************** *********** * ********* // +// ******************** *********** * ********* func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) @@ -740,7 +756,8 @@ func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_e // Parse the productions: // indentless_sequence ::= (BLOCK-ENTRY block_node?)+ -// *********** * +// +// *********** * func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -805,14 +822,14 @@ func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) { // Parse the productions: // block_mapping ::= BLOCK-MAPPING_START -// ******************* -// ((KEY block_node_or_indentless_sequence?)? -// *** * -// (VALUE block_node_or_indentless_sequence?)?)* // -// BLOCK-END -// ********* +// ******************* +// ((KEY block_node_or_indentless_sequence?)? +// *** * +// (VALUE block_node_or_indentless_sequence?)?)* // +// BLOCK-END +// ********* func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) @@ -881,13 +898,11 @@ func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_even // Parse the productions: // block_mapping ::= BLOCK-MAPPING_START // -// ((KEY block_node_or_indentless_sequence?)? -// -// (VALUE block_node_or_indentless_sequence?)?)* -// ***** * -// BLOCK-END -// +// ((KEY block_node_or_indentless_sequence?)? // +// (VALUE block_node_or_indentless_sequence?)?)* +// ***** * +// BLOCK-END func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -915,16 +930,18 @@ func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_ev // Parse the productions: // flow_sequence ::= FLOW-SEQUENCE-START -// ******************* -// (flow_sequence_entry FLOW-ENTRY)* -// * ********** -// flow_sequence_entry? -// * -// FLOW-SEQUENCE-END -// ***************** -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * // +// ******************* +// (flow_sequence_entry FLOW-ENTRY)* +// * ********** +// flow_sequence_entry? +// * +// FLOW-SEQUENCE-END +// ***************** +// +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// +// * func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) @@ -987,11 +1004,10 @@ func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_ev return true } -// // Parse the productions: // flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// *** * // +// *** * func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -1011,8 +1027,8 @@ func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, ev // Parse the productions: // flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// ***** * // +// ***** * func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -1035,8 +1051,8 @@ func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, // Parse the productions: // flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * // +// * func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool { token := peek_token(parser) if token == nil { @@ -1053,16 +1069,17 @@ func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, ev // Parse the productions: // flow_mapping ::= FLOW-MAPPING-START -// ****************** -// (flow_mapping_entry FLOW-ENTRY)* -// * ********** -// flow_mapping_entry? -// ****************** -// FLOW-MAPPING-END -// **************** -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * *** * // +// ****************** +// (flow_mapping_entry FLOW-ENTRY)* +// * ********** +// flow_mapping_entry? +// ****************** +// FLOW-MAPPING-END +// **************** +// +// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// - *** * func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { if first { token := peek_token(parser) @@ -1128,8 +1145,7 @@ func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event // Parse the productions: // flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * ***** * -// +// - ***** * func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool { token := peek_token(parser) if token == nil { diff --git a/vendor/gopkg.in/yaml.v3/readerc.go b/vendor/gopkg.in/yaml.v3/readerc.go index b7de0a89..56af2453 100644 --- a/vendor/gopkg.in/yaml.v3/readerc.go +++ b/vendor/gopkg.in/yaml.v3/readerc.go @@ -1,17 +1,17 @@ -// +// // Copyright (c) 2011-2019 Canonical Ltd // Copyright (c) 2006-2010 Kirill Simonov -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies // of the Software, and to permit persons to whom the Software is furnished to do // so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/vendor/gopkg.in/yaml.v3/scannerc.go b/vendor/gopkg.in/yaml.v3/scannerc.go index ca007010..30b1f089 100644 --- a/vendor/gopkg.in/yaml.v3/scannerc.go +++ b/vendor/gopkg.in/yaml.v3/scannerc.go @@ -1614,11 +1614,11 @@ func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool { // Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. // // Scope: -// %YAML 1.1 # a comment \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // +// %YAML 1.1 # a comment \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool { // Eat '%'. start_mark := parser.mark @@ -1719,11 +1719,11 @@ func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool // Scan the directive name. // // Scope: -// %YAML 1.1 # a comment \n -// ^^^^ -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^ // +// %YAML 1.1 # a comment \n +// ^^^^ +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^ func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool { // Consume the directive name. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { @@ -1758,8 +1758,9 @@ func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark // Scan the value of VERSION-DIRECTIVE. // // Scope: -// %YAML 1.1 # a comment \n -// ^^^^^^ +// +// %YAML 1.1 # a comment \n +// ^^^^^^ func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool { // Eat whitespaces. if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { @@ -1797,10 +1798,11 @@ const max_number_length = 2 // Scan the version number of VERSION-DIRECTIVE. // // Scope: -// %YAML 1.1 # a comment \n -// ^ -// %YAML 1.1 # a comment \n -// ^ +// +// %YAML 1.1 # a comment \n +// ^ +// %YAML 1.1 # a comment \n +// ^ func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool { // Repeat while the next character is digit. @@ -1834,9 +1836,9 @@ func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark // Scan the value of a TAG-DIRECTIVE token. // // Scope: -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool { var handle_value, prefix_value []byte @@ -2847,7 +2849,7 @@ func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t continue } if parser.buffer[parser.buffer_pos+peek] == '#' { - seen := parser.mark.index+peek + seen := parser.mark.index + peek for { if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false @@ -2876,7 +2878,7 @@ func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t parser.comments = append(parser.comments, yaml_comment_t{ token_mark: token_mark, start_mark: start_mark, - line: text, + line: text, }) } return true @@ -2910,7 +2912,7 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo // the foot is the line below it. var foot_line = -1 if scan_mark.line > 0 { - foot_line = parser.mark.line-parser.newlines+1 + foot_line = parser.mark.line - parser.newlines + 1 if parser.newlines == 0 && parser.mark.column > 1 { foot_line++ } @@ -2996,7 +2998,7 @@ func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) boo recent_empty = false // Consume until after the consumed comment line. - seen := parser.mark.index+peek + seen := parser.mark.index + peek for { if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { return false diff --git a/vendor/gopkg.in/yaml.v3/writerc.go b/vendor/gopkg.in/yaml.v3/writerc.go index b8a116bf..266d0b09 100644 --- a/vendor/gopkg.in/yaml.v3/writerc.go +++ b/vendor/gopkg.in/yaml.v3/writerc.go @@ -1,17 +1,17 @@ -// +// // Copyright (c) 2011-2019 Canonical Ltd // Copyright (c) 2006-2010 Kirill Simonov -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies // of the Software, and to permit persons to whom the Software is furnished to do // so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/vendor/gopkg.in/yaml.v3/yaml.go b/vendor/gopkg.in/yaml.v3/yaml.go index 8cec6da4..f0bedf3d 100644 --- a/vendor/gopkg.in/yaml.v3/yaml.go +++ b/vendor/gopkg.in/yaml.v3/yaml.go @@ -17,8 +17,7 @@ // // Source code and other details for the project are available at GitHub: // -// https://github.com/go-yaml/yaml -// +// https://github.com/go-yaml/yaml package yaml import ( @@ -75,16 +74,15 @@ type Marshaler interface { // // For example: // -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// var t T -// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// var t T +// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) // // See the documentation of Marshal for the format of tags and a list of // supported tag options. -// func Unmarshal(in []byte, out interface{}) (err error) { return unmarshal(in, out, false) } @@ -185,36 +183,35 @@ func unmarshal(in []byte, out interface{}, strict bool) (err error) { // // The field tag format accepted is: // -// `(...) yaml:"[][,[,]]" (...)` +// `(...) yaml:"[][,[,]]" (...)` // // The following flags are currently supported: // -// omitempty Only include the field if it's not set to the zero -// value for the type or to empty slices or maps. -// Zero valued structs will be omitted if all their public -// fields are zero, unless they implement an IsZero -// method (see the IsZeroer interface type), in which -// case the field will be excluded if IsZero returns true. +// omitempty Only include the field if it's not set to the zero +// value for the type or to empty slices or maps. +// Zero valued structs will be omitted if all their public +// fields are zero, unless they implement an IsZero +// method (see the IsZeroer interface type), in which +// case the field will be excluded if IsZero returns true. // -// flow Marshal using a flow style (useful for structs, -// sequences and maps). +// flow Marshal using a flow style (useful for structs, +// sequences and maps). // -// inline Inline the field, which must be a struct or a map, -// causing all of its fields or keys to be processed as if -// they were part of the outer struct. For maps, keys must -// not conflict with the yaml keys of other struct fields. +// inline Inline the field, which must be a struct or a map, +// causing all of its fields or keys to be processed as if +// they were part of the outer struct. For maps, keys must +// not conflict with the yaml keys of other struct fields. // // In addition, if the key is "-", the field is ignored. // // For example: // -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" -// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" -// +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" +// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" func Marshal(in interface{}) (out []byte, err error) { defer handleErr(&err) e := newEncoder() @@ -358,22 +355,21 @@ const ( // // For example: // -// var person struct { -// Name string -// Address yaml.Node -// } -// err := yaml.Unmarshal(data, &person) -// +// var person struct { +// Name string +// Address yaml.Node +// } +// err := yaml.Unmarshal(data, &person) +// // Or by itself: // -// var person Node -// err := yaml.Unmarshal(data, &person) -// +// var person Node +// err := yaml.Unmarshal(data, &person) type Node struct { // Kind defines whether the node is a document, a mapping, a sequence, // a scalar value, or an alias to another node. The specific data type of // scalar nodes may be obtained via the ShortTag and LongTag methods. - Kind Kind + Kind Kind // Style allows customizing the apperance of the node in the tree. Style Style @@ -421,7 +417,6 @@ func (n *Node) IsZero() bool { n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0 } - // LongTag returns the long form of the tag that indicates the data type for // the node. If the Tag field isn't explicitly defined, one will be computed // based on the node properties. diff --git a/vendor/gopkg.in/yaml.v3/yamlh.go b/vendor/gopkg.in/yaml.v3/yamlh.go index 7c6d0077..ddcd5513 100644 --- a/vendor/gopkg.in/yaml.v3/yamlh.go +++ b/vendor/gopkg.in/yaml.v3/yamlh.go @@ -438,7 +438,9 @@ type yaml_document_t struct { // The number of written bytes should be set to the size_read variable. // // [in,out] data A pointer to an application data specified by -// yaml_parser_set_input(). +// +// yaml_parser_set_input(). +// // [out] buffer The buffer to write the data from the source. // [in] size The size of the buffer. // [out] size_read The actual number of bytes read from the source. @@ -639,7 +641,6 @@ type yaml_parser_t struct { } type yaml_comment_t struct { - scan_mark yaml_mark_t // Position where scanning for comments started token_mark yaml_mark_t // Position after which tokens will be associated with this comment start_mark yaml_mark_t // Position of '#' comment mark @@ -659,13 +660,14 @@ type yaml_comment_t struct { // @a buffer to the output. // // @param[in,out] data A pointer to an application data specified by -// yaml_emitter_set_output(). +// +// yaml_emitter_set_output(). +// // @param[in] buffer The buffer with bytes to be written. // @param[in] size The size of the buffer. // // @returns On success, the handler should return @c 1. If the handler failed, // the returned value should be @c 0. -// type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error type yaml_emitter_state_t int diff --git a/vendor/gopkg.in/yaml.v3/yamlprivateh.go b/vendor/gopkg.in/yaml.v3/yamlprivateh.go index e88f9c54..dea1ba96 100644 --- a/vendor/gopkg.in/yaml.v3/yamlprivateh.go +++ b/vendor/gopkg.in/yaml.v3/yamlprivateh.go @@ -1,17 +1,17 @@ -// +// // Copyright (c) 2011-2019 Canonical Ltd // Copyright (c) 2006-2010 Kirill Simonov -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies // of the Software, and to permit persons to whom the Software is furnished to do // so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -137,8 +137,8 @@ func is_crlf(b []byte, i int) bool { func is_breakz(b []byte, i int) bool { //return is_break(b, i) || is_z(b, i) return ( - // is_break: - b[i] == '\r' || // CR (#xD) + // is_break: + b[i] == '\r' || // CR (#xD) b[i] == '\n' || // LF (#xA) b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) @@ -151,8 +151,8 @@ func is_breakz(b []byte, i int) bool { func is_spacez(b []byte, i int) bool { //return is_space(b, i) || is_breakz(b, i) return ( - // is_space: - b[i] == ' ' || + // is_space: + b[i] == ' ' || // is_breakz: b[i] == '\r' || // CR (#xD) b[i] == '\n' || // LF (#xA) @@ -166,8 +166,8 @@ func is_spacez(b []byte, i int) bool { func is_blankz(b []byte, i int) bool { //return is_blank(b, i) || is_breakz(b, i) return ( - // is_blank: - b[i] == ' ' || b[i] == '\t' || + // is_blank: + b[i] == ' ' || b[i] == '\t' || // is_breakz: b[i] == '\r' || // CR (#xD) b[i] == '\n' || // LF (#xA)