]> git.bundesbrandschatzamt.de Git - emacsconfig.git/commitdiff
update kubed
authorAndreas Gerler <baronNOSPAMbundesbrandschatzamt.de>
Wed, 24 Dec 2025 12:40:26 +0000 (13:40 +0100)
committerAndreas Gerler <baronNOSPAMbundesbrandschatzamt.de>
Wed, 24 Dec 2025 13:54:50 +0000 (14:54 +0100)
35 files changed:
elpa/kubed-0.4.3/.elpaignore [deleted file]
elpa/kubed-0.4.3/LICENSE [deleted file]
elpa/kubed-0.4.3/NEWS.org [deleted file]
elpa/kubed-0.4.3/cobra.el [deleted file]
elpa/kubed-0.4.3/dir [deleted file]
elpa/kubed-0.4.3/kubed-autoloads.el [deleted file]
elpa/kubed-0.4.3/kubed-common.el [deleted file]
elpa/kubed-0.4.3/kubed-pkg.el [deleted file]
elpa/kubed-0.4.3/kubed-tramp.el [deleted file]
elpa/kubed-0.4.3/kubed-transient.el [deleted file]
elpa/kubed-0.4.3/kubed.el [deleted file]
elpa/kubed-0.4.3/kubed.info [deleted file]
elpa/kubed-0.4.3/kubed.texi [deleted file]
elpa/kubed-0.5.0.signed [new file with mode: 0644]
elpa/kubed-0.5.0/.elpaignore [new file with mode: 0644]
elpa/kubed-0.5.0/LICENSE [new file with mode: 0644]
elpa/kubed-0.5.0/NEWS.org [new file with mode: 0644]
elpa/kubed-0.5.0/assets/kubed-deployment-prefix-map.png [new file with mode: 0644]
elpa/kubed-0.5.0/assets/kubed-list-transient.png [new file with mode: 0644]
elpa/kubed-0.5.0/assets/kubed-overview.png [new file with mode: 0644]
elpa/kubed-0.5.0/assets/kubed-prefix-map.png [new file with mode: 0644]
elpa/kubed-0.5.0/assets/kubed-replace-diff.png [new file with mode: 0644]
elpa/kubed-0.5.0/assets/kubed-scale-deployments.png [new file with mode: 0644]
elpa/kubed-0.5.0/assets/kubed-transient-exec.png [new file with mode: 0644]
elpa/kubed-0.5.0/assets/kubed-transient.png [new file with mode: 0644]
elpa/kubed-0.5.0/cobra.el [new file with mode: 0644]
elpa/kubed-0.5.0/dir [new file with mode: 0644]
elpa/kubed-0.5.0/kubed-autoloads.el [new file with mode: 0644]
elpa/kubed-0.5.0/kubed-common.el [new file with mode: 0644]
elpa/kubed-0.5.0/kubed-pkg.el [new file with mode: 0644]
elpa/kubed-0.5.0/kubed-tramp.el [new file with mode: 0644]
elpa/kubed-0.5.0/kubed-transient.el [new file with mode: 0644]
elpa/kubed-0.5.0/kubed.el [new file with mode: 0644]
elpa/kubed-0.5.0/kubed.info [new file with mode: 0644]
elpa/kubed-0.5.0/kubed.texi [new file with mode: 0644]

diff --git a/elpa/kubed-0.4.3/.elpaignore b/elpa/kubed-0.4.3/.elpaignore
deleted file mode 100644 (file)
index 206be02..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-.dir-locals.el
-README.md
-*.png
diff --git a/elpa/kubed-0.4.3/LICENSE b/elpa/kubed-0.4.3/LICENSE
deleted file mode 100644 (file)
index cfd527c..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright 2024-2025 Eshel Yaron
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/elpa/kubed-0.4.3/NEWS.org b/elpa/kubed-0.4.3/NEWS.org
deleted file mode 100644 (file)
index d63a217..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-#+title:                 Kubed NEWS -- history of user-visible changes
-#+author:                Eshel Yaron
-#+email:                 meNOSPAMeshelyaron.com
-#+language:              en
-#+options:               ':t toc:nil num:nil ^:{}
-
-This file contains the release notes for Kubed, a rich Emacs interface
-for Kubernetes.
-
-For further details, see the Kubed manual:
-[[https://eshelyaron.com/kubed.html][https://eshelyaron.com/kubed.html]].
-
-* Version 0.4.3 on 2025-01-21
-
-This is a maintenance release, it includes minor improvements and one
-important bug fix:
-
-** Fix 'kubed-list-delete-marked' in non-default context
-
-Marking resources with ~d~ and deleting them with ~x~ now works also
-in resource tables of resources in non-default contexts or namespaces.
-
-* Version 0.4.2 on 2024-10-22
-
-** New user option 'kubed-list-mode-line-format'
-
-This user option lets you customize the indicator that Kubed shows in
-the mode line of resource table buffers when update is in progress.
-
-** Fix Tramp method autoload issue
-
-This version arranges for the Kubed Tramp integration to be loaded
-earlier, which circumvents the "Method ‘kubedv1’ is not known" error
-that some users have experienced.
-
-* Version 0.4.1 on 2024-09-23
-
-** New command and transient menu for scaling deployments
-
-You can now scale Kubernetes deployment with Kubed, directly with
-~kubed-scale-deployment~, from the deployments table buffer, or via
-the new transient menu ~kubed-transient-scale-deployment~.
-
-** New commands and transient menu for managing Kubernetes API proxies
-
-You can now use Kubed to create proxy servers that give access to the
-Kubernetes API server.  The commands ~kubed-proxy~ and
-~kubed-stop-proxy~ start and stop proxy servers, respectively.  The
-new transient menu ~kubed-transient-proxy~ lets specify options when
-starting a proxy, such as the local port to use.
-
-* Version 0.4.0 on 2024-08-23
-
-** ~kubed-list-update~ is now bound to ~g~ in resource table buffers.
-
-Previously, this command was bound to the slightly less convenient
-capital ~G~.  This shadows the default binding of ~revert-buffer~,
-which you can still invoke via ~C-x x g~.
-
-** Introduce resource type specific bindings in resource table help transients.
-
-The help transient menu that you get with ~?~ in resource table
-buffers now includes type-specific bindings, such as the ~F~ key for
-forwarding a local port to a pod in the Kubed pods buffer.
-
-** New transient menu ~kubed-transient-logs~ for showing container logs.
-
-** Improved Tramp integration.
-
-Kubed now uses a bespoke Tramp method to open Dired and Shell buffers
-inside Kubernetes pods.  The main advantage of this method is the
-ability to work with multiple ~kubectl~ contexts simultaneously.  This
-method requires Tramp 2.7 or later, Kubed will complain if you try to
-start remote Dired or Shell with an earlier Tramp version.
-
-* Version 0.3.2 on 2024-08-15
-
-** Improved support for multiple contexts and namespaces
-
-Each buffer now has a local context and namespace, which acts as the
-default/current context and namespace when you invoke Kubed commands
-from that buffer.  See new manual section "Context and Namespace" for
-more details.
-
-** New filter operators ~<~ and ~>~ in resource tables.
-
-These operators let you filter line with columns that are less than or
-greater than a given value.
-
-** New command for applying changes to displayed resource.
-
-You can now edit displayed resource YAML buffers after you select a
-resource with ~RET~ in the table buffer, and apply your changes to the
-live resource with ~C-c C-c~.
-
-* Version 0.3.1 on 2024-08-06
-
-** New command for fitting column width to content in resource tables.
-
-** New transient menu showing help in resource table buffers.
-
-* Version 0.3.0 on 2024-08-05
-
-** New command for copying name of resource at point to kill ring.
-
-** New commands for running ~kubectl~ command on resource at point.
-
-** Support bookmarking resource list and resource details buffers.
-
-** New command for jumping from resource details buffer to list buffer.
-
-** Fix installation on Doom Emacs.
-
-** New transient menu for displaying resources.
-
-** Support multiple resource list buffers with different namespaces or contexts.
-
-* Version 0.2.0 on 2024-08-02
-
-** Ensure compatibility with Emacs 29.
-
-** Add right-click context menus in resource tables.
-
-** New menu-bar "Kubernetes" menu.
-
-** New commands for restarting and watching deployments.
-
-** Add filtering capability to all resource tables.
-
-** New cron job commands: suspend, resume, and start job now.
-
-** New commands for patching resources.
-
-** New useful columns in services table and deployments table.
-
-** Use multi-column layout in transient menus.
-
-* Version 0.1.0 on 2024-07-28
-
-Initial release.
diff --git a/elpa/kubed-0.4.3/cobra.el b/elpa/kubed-0.4.3/cobra.el
deleted file mode 100644 (file)
index c7d5ffb..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-;;; cobra.el --- Complete Cobra command lines   -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2024-2025  Free Software Foundation, Inc.
-
-;; Author: Eshel Yaron <meNOSPAMeshelyaron.com>
-;; Keywords: tools
-
-;;; Commentary:
-
-;; Cobra is a popular Golang framework for CLI programs.  This library
-;; defines function `cobra-read-command-line', which helps you read a
-;; command line for a program that uses Cobra, with completion.
-;; Prominent examples of Cobra programs are `kubectl' and `docker'.
-
-;;; Code:
-
-(defvar cobra--cache nil)
-
-(defun cobra-completion-table (executable s p a)
-  "Completion table for command lines that invoke EXECUTABLE.
-
-Perform completion action A on string S with predicate P."
-  (let ((start 0))
-    (while (string-match "[[:space:]=]" s start)
-      (setq start (match-end 0)))
-    (if (eq a 'metadata)
-        `(metadata
-          (category . cobra-command-line)
-          (affixation-function
-           . ,(lambda (cands)
-                (let ((max (seq-max
-                            (cons 0 (mapcar #'string-width cands)))))
-                  (mapcar
-                   (lambda (cand)
-                     (list
-                      cand ""
-                      (if-let
-                          ((desc (get-text-property
-                                  0 'cobra-argument-description
-                                  cand)))
-                          (concat
-                           (make-string (1+ (- max (string-width cand))) ?\s)
-                           (propertize desc 'face 'completions-annotations))
-                        "")))
-                   cands)))))
-      (let* ((lines
-              (cdr
-               (if (string= s (car cobra--cache))
-                   ;; Cache hit.
-                   cobra--cache
-                 (setq
-                  cobra--cache
-                  (cons s
-                        (apply #'process-lines-ignore-status
-                               executable "__complete"
-                               (let ((args (cdr (split-string-and-unquote s))))
-                                 (if (string-suffix-p " " s)
-                                     ;; Restore omitted empty argument.
-                                     (nconc args '(""))
-                                   args))))))))
-             (code nil)
-             (comps (seq-take-while
-                     (lambda (line)
-                       (not (and (string-match "^:\\([0-9]+\\)$" line)
-                                 (setq code (string-to-number
-                                             (match-string 1 line))))))
-                     lines)))
-        ;; `code' encodes "completion directives", as follows:
-        ;; #b000001: An error occurred, ignore completions.
-        ;; #b000010: Don't add space after completion.  (TODO.)
-        ;; #b000100: Don't fall back to file completion.
-        ;; #b001000: Completions are really file extension filters.
-        ;; #b010000: Complete directory names.
-        ;; #b100000: Preserve completions order.
-        (when (and code (zerop (logand 1 code)))
-          ;; Error bit in unset, proceed.
-          (if (= #b100 (logand #b100 code))
-              ;; No file name completion.
-              (if (eq (car-safe a) 'boundaries)
-                  `(boundaries
-                    ,start . ,(and (string-match "[[:space:]=]" (cdr a))
-                                   (match-beginning 0)))
-                (let ((table
-                       (mapcar
-                        ;; Annotate completion candidates.
-                        (lambda (comp)
-                          (pcase (split-string comp "\t" t)
-                            (`(,c ,d . ,_)
-                             (propertize
-                              c 'cobra-argument-description
-                              ;; Only keep first sentence.
-                              (car (split-string d "\\." t))))
-                            (`(,c . ,_)  c)))
-                        comps)))
-                  (if a (complete-with-action a table (substring s start) p)
-                    ;; `try-completion'.
-                    (let ((comp (complete-with-action a table (substring s start) p)))
-                      (if (stringp comp) (concat (substring s 0 start) comp) comp)))))
-            ;; File name completion.
-            (setq p
-                  (cond
-                   ((= #b1000 (logand #b1000 code))
-                    ;; `comps' are valid extensions.
-                    (lambda (f)
-                      (or (file-directory-p f)
-                          (when (string-match "\\.[^.]*\\'" f)
-                            (member (substring f (1+ (match-beginning 0)))
-                                    comps)))))
-                   ((= #b10000 (logand #b10000 code))
-                    ;; Directory name completion.
-                    #'file-directory-p)))
-            (if (eq (car-safe a) 'boundaries)
-                ;; Find nested boundaries.
-                (let* ((suf (cdr a))
-                       (bounds (completion-boundaries
-                                (substring s start) #'completion-file-name-table p
-                                (substring suf 0 (string-match "[[:space:]=]" suf)))))
-                  `(boundaries ,(+ (car bounds) start) . ,(cdr bounds)))
-              (if a (complete-with-action a #'completion-file-name-table
-                                          (substring s start) p)
-                (let ((comp (complete-with-action a #'completion-file-name-table
-                                                  (substring s start) p)))
-                  (if (stringp comp) (concat (substring s 0 start) comp) comp))))))))))
-
-;;;###autoload
-(defun cobra-read-command-line (prompt initial &optional hist)
-  "Prompt with PROMPT for a command line starting with INITIAL.
-
-Optional argument HIST is the name of the history list variable to use,
-if it is nil or omitted, it defaults to `shell-command-history'."
-  (let ((exec (car (split-string-and-unquote (car (ensure-list initial))))))
-    (minibuffer-with-setup-hook
-        (:append (lambda ()
-                   (let ((map (make-sparse-keymap)))
-                     ;; Ensure SPC is self-inserting.
-                     (keymap-unset map "SPC")
-                     (use-local-map
-                      (make-composed-keymap map (current-local-map))))))
-      (completing-read prompt (apply-partially #'cobra-completion-table exec)
-                       nil nil initial (or hist 'shell-command-history)))))
-
-(provide 'cobra)
-;;; cobra.el ends here
diff --git a/elpa/kubed-0.4.3/dir b/elpa/kubed-0.4.3/dir
deleted file mode 100644 (file)
index c2a3104..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-This is the file .../info/dir, which contains the
-topmost node of the Info hierarchy, called (dir)Top.
-The first time you invoke Info you start off looking at this node.
-\1f
-File: dir,     Node: Top       This is the top of the INFO tree
-
-  This (the Directory node) gives a menu of major topics.
-  Typing "q" exits, "H" lists all Info commands, "d" returns here,
-  "h" gives a primer for first-timers,
-  "mEmacs<Return>" visits the Emacs manual, etc.
-
-  In Emacs, you can click mouse button 2 on a menu item or cross reference
-  to select it.
-
-* Menu:
-
-Emacs
-* Kubed: (kubed).               Kubernetes, Emacs, done!
diff --git a/elpa/kubed-0.4.3/kubed-autoloads.el b/elpa/kubed-0.4.3/kubed-autoloads.el
deleted file mode 100644 (file)
index 23deb7e..0000000
+++ /dev/null
@@ -1,501 +0,0 @@
-;;; kubed-autoloads.el --- automatically extracted autoloads (do not edit)   -*- lexical-binding: t -*-
-;; Generated by the `loaddefs-generate' function.
-
-;; This file is part of GNU Emacs.
-
-;;; Code:
-
-(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
-
-
-\f
-;;; Generated autoloads from cobra.el
-
-(autoload 'cobra-read-command-line "cobra" "\
-Prompt with PROMPT for a command line starting with INITIAL.
-
-Optional argument HIST is the name of the history list variable to use,
-if it is nil or omitted, it defaults to `shell-command-history'.
-
-(fn PROMPT INITIAL &optional HIST)")
-(register-definition-prefixes "cobra" '("cobra-"))
-
-\f
-;;; Generated autoloads from kubed.el
-
-(autoload 'kubed-display-resource "kubed" "\
-Display Kubernetes RESOURCE of type TYPE in CONTEXT.
-
-For namespaced resource types, NAMESPACE is the namespace of RESOURCE.
-
-Interactively, use the current context and namespace by default, and
-prompt for TYPE and RESOURCE.  With a prefix argument \\[universal-argument],
-prompt for NAMESPACE.  With a double prefix argument \\[universal-argument] \\[universal-argument],
-prompt for CONTEXT as well.
-
-(fn TYPE RESOURCE CONTEXT &optional NAMESPACE)" t)
-(autoload 'kubed-display-resource-handle-bookmark "kubed" "\
-Display Kubernetes resource according to BOOKMARK.
-
-(fn BOOKMARK)")
-(autoload 'kubed-list-handle-bookmark "kubed" "\
-Display Kubernetes resource according to BOOKMARK.
-
-(fn BOOKMARK)")
-(autoload 'kubed-delete-resources "kubed" "\
-Delete Kubernetes RESOURCES of type TYPE in context CONTEXT.
-
-For namespaced resource types, NAMESPACE is the namespace of RESOURCE.
-
-Interactively, use the current context and namespace by default, and
-prompt for TYPE and RESOURCES.  With a prefix argument \\[universal-argument],
-prompt for NAMESPACE.  With a double prefix argument \\[universal-argument] \\[universal-argument],
-prompt for CONTEXT as well.
-
-(fn TYPE RESOURCES CONTEXT &optional NAMESPACE)" t)
-(autoload 'kubed-edit-resource "kubed" "\
-Edit Kubernetes RESOURCE of type TYPE in context CONTEXT.
-
-For namespaced resource types, NAMESPACE is the namespace of RESOURCE.
-
-Interactively, use the current context and namespace by default, and
-prompt for TYPE and RESOURCES.  With a prefix argument \\[universal-argument],
-prompt for NAMESPACE.  With a double prefix argument \\[universal-argument] \\[universal-argument],
-prompt for CONTEXT as well.
-
-(fn TYPE RESOURCE CONTEXT &optional NAMESPACE)" t)
-(autoload 'kubed-define-resource "kubed" "\
-Define Kubernetes RESOURCE with associated PROPERTIES and COMMANDS.
-
-RESOURCE is a symbol corresponding to a Kubernetes resource type, such
-as `pod' or `service'.  This macro defines the following commands for
-interacting with Kubernetes RESOURCEs:
-
-- `kubed-display-RESOURCE': prompt for a RESOURCE and display its
-  description in YAML format.  See also `kubed-yaml-setup-hook'.
-- `kubed-edit-RESOURCE': prompt for a RESOURCE and edit it.
-- `kubed-delete-RESOURCE': prompt for a RESOURCE and delete it.
-- `kubed-list-RESOURCEs': display a buffer listing all RESOURCEs in the
-  current namespace.  The RESOURCEs list buffer uses a dedicated major
-  mode, `kubed-RESOURCEs-mode', which is also defined by this macro.
-- `kubed-create-RESOURCE': create a RESOURCE from a YAML or a JSON file.
-- `kubed-explain-RESOURCEs': show buffer with help about RESOURCEs.
-
-This macro also defines a prefix keymap, `kubed-RESOURCE-prefix-map',
-with bindings for the above commands.
-
-PROPERTIES is a list of lists (PROP JSON-PATH WIDTH SORT FORMAT . ATTRS)
-that specify properties of RESOURCEs.  PROP is the name of the property,
-as a symbol; JSON-PATH is a JSONPath expression that evaluates to the
-value of PROP when applied to the JSON representation of a RESOURCE.
-WIDTH, SORT, FORMAT and ATTRS are optional and can be omitted.  WIDTH is
-used as the default width of the column corresponding to PROP in
-RESOURCEs list buffers; SORT is sort predicate, a function that takes
-two values of PROP as strings and returns non-nil if the first should
-sort before the second; FORMAT is a function that takes a value of PROP
-and formats it.  If you provide a FORMAT function and a SORT function,
-then the SORT function gets the formatted values (the output of the
-FORMAT function), not the original values.  If you want to sort based on
-the unformatted original values, you can store them as text properties
-in your FORMAT function and access them in your SORT function.
-
-ATTRS is a plist of additional attributes of the PROP column, see
-`tabulated-list-format' for available attributes.
-
-For example, if PROPERTIES is (phase \".status.phase\" 10) that means
-that RESOURCE has a `phase' property at JSONPath \".status.phase\" whose
-values are typically 10 columns wide.  The first property in PROPERTIES
-is used to annotate completion candidates when prompting for a RESOURCE.
-
-COMMANDS is a list of elements (COMMAND KEYS DOC-PREFIX . BODY) that
-define commands for RESOURCE list buffers.  COMMAND is a symbol
-specifying the suffix of the command name, the full name of the command
-is `kubed-RESOURCEs-COMMAND' (for example, `kubed-pods-shell'); KEYS is
-either a string that specifies a key sequence to bind to the command in
-`kubed-RESOURCEs-mode-map', or nil if the command should not be bound;
-DOC-PREFIX is a string used to construct the docstring of the command,
-this macro appends the string \" Kubernetes RESOURCE at point.\" to it
-to obtain the final docstring; lastly, BODY is the body the command.
-Within BODY, the variable RESOURCE is let-bound to the name of the
-RESOURCE at point.  For example, if RESOURCE is `pod', the following
-COMMANDS element defines a command `kubed-pods-frob' and binds it to the
-key \"f\" in `kubed-pods-mode-map':
-
-  (frob \"f\" \"Frobnicate\"
-        (message \"Preparing...\")
-        (frobnicate-pod pod)
-        (message \"Done.\"))
-
-By default, this macro assumes that RESOURCE is namespaced.  To define a
-namespaceless resource type, put `:namespaced nil' before COMMANDS:
-
-  (kubed-define-resource global-thingy (PROP1 PROP2 ...) :namespaced nil
-    CMD1
-    CMD2
-    ...)
-
-Other keyword arguments that go between PROPERTIES and COMMANDS are:
-
-- `:create (ARGLIST DOCSTRING INTERACTIVE BODY...)': specialize the
-  resource creation command, `kubed-create-RESOURCE'.  ARGLIST,
-  DOCSTRING, INTERACTIVE and BODY have the same meaning as in `defun'.
-- `:prefix ((KEY LABEL DEFINITION)...)': additional keybinding for the
-  prefix keymap `kubed-RESOURCE-prefix-map' and the
-  `kubed-RESOURCE-menu-map' menu.  Each element (KEY LABEL DEFINITION)
-  says to bind KEY to DEFINITION in `kubed-RESOURCE-menu-map', and to
-  add DEFINITION to `kubed-RESOURCE-menu-map' with the label LABEL.
-- `:plural PLURAL': specify plural form of RESOURCE, as a symbol.  If
-  you omit this keyword argument, the plural form defaults to RESOURCE
-  followed by \"s\".
-- `:logs t': generate `kubed-logs-for-RESOURCE' command.
-- `:suffixes (SUFFIX...)': add type-specific transient suffixes to
-  `kubed-list-transient'.
-
-(fn RESOURCE &optional PROPERTIES &rest COMMANDS)" nil t)
-(function-put 'kubed-define-resource 'lisp-indent-function 2)
- (autoload 'kubed-display-pod "kubed" nil t)
- (autoload 'kubed-edit-pod "kubed" nil t)
- (autoload 'kubed-delete-pods "kubed" nil t)
- (autoload 'kubed-list-pods "kubed" nil t)
- (autoload 'kubed-create-pod "kubed" nil t)
- (autoload 'kubed-logs-for-pod "kubed" nil t)
- (autoload 'kubed-pod-prefix-map "kubed" nil t 'keymap)
- (autoload 'kubed-display-namespace "kubed" nil t)
- (autoload 'kubed-edit-namespace "kubed" nil t)
- (autoload 'kubed-delete-namespaces "kubed" nil t)
- (autoload 'kubed-list-namespaces "kubed" nil t)
- (autoload 'kubed-create-namespace "kubed" nil t)
- (autoload 'kubed-namespace-prefix-map "kubed" nil t 'keymap)
- (autoload 'kubed-display-persistentvolume "kubed" nil t)
- (autoload 'kubed-edit-persistentvolume "kubed" nil t)
- (autoload 'kubed-delete-persistentvolumes "kubed" nil t)
- (autoload 'kubed-list-persistentvolumes "kubed" nil t)
- (autoload 'kubed-create-persistentvolume "kubed" nil t)
- (autoload 'kubed-persistentvolume-prefix-map "kubed" nil t 'keymap)
- (autoload 'kubed-display-service "kubed" nil t)
- (autoload 'kubed-edit-service "kubed" nil t)
- (autoload 'kubed-delete-services "kubed" nil t)
- (autoload 'kubed-list-services "kubed" nil t)
- (autoload 'kubed-create-service "kubed" nil t)
- (autoload 'kubed-logs-for-service "kubed" nil t)
- (autoload 'kubed-service-prefix-map "kubed" nil t 'keymap)
- (autoload 'kubed-display-secret "kubed" nil t)
- (autoload 'kubed-edit-secret "kubed" nil t)
- (autoload 'kubed-delete-secrets "kubed" nil t)
- (autoload 'kubed-list-secrets "kubed" nil t)
- (autoload 'kubed-create-secret "kubed" nil t)
- (autoload 'kubed-secret-prefix-map "kubed" nil t 'keymap)
- (autoload 'kubed-display-job "kubed" nil t)
- (autoload 'kubed-edit-job "kubed" nil t)
- (autoload 'kubed-delete-jobs "kubed" nil t)
- (autoload 'kubed-list-jobs "kubed" nil t)
- (autoload 'kubed-create-job "kubed" nil t)
- (autoload 'kubed-logs-for-job "kubed" nil t)
- (autoload 'kubed-job-prefix-map "kubed" nil t 'keymap)
-(autoload 'kubed-watch-deployment-status "kubed" "\
-Show and update status of Kubernetes deployment DEP in a dedicate buffer.
-
-Optional argument CONTEXT is the `kubectl' context to use, defaulting to
-the current context; NAMESPACE is the namespace of DEP, defaulting to
-the current namespace.  CB is an optional callback function to call with
-no arguments when the deployment ends.
-
-Interactively, prompt for DEP.  With a prefix argument, prompt for
-NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
-
-(fn DEP &optional CONTEXT NAMESPACE CB)" t)
-(autoload 'kubed-scale-deployment "kubed" "\
-Scale deployment DEP in namespace NAMESPACE via CONTEXT to REPS replicas.
-
-Optional argument CONTEXT is the `kubectl' context to use, defaulting to
-the current context; NAMESPACE is the namespace of DEP, defaulting to
-the current namespace.
-
-Interactively, prompt for DEP.  With a prefix argument, prompt for
-NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
-
-(fn DEP REPS &optional CONTEXT NAMESPACE)" t)
-(autoload 'kubed-restart-deployment "kubed" "\
-Restart Kubernetes deployment DEP in namespace NAMESPACE via CONTEXT.
-
-Optional argument CONTEXT is the `kubectl' context to use, defaulting to
-the current context; NAMESPACE is the namespace of DEP, defaulting to
-the current namespace.  CB is an optional callback function to call with
-no arguments when the deployment ends.
-
-Interactively, prompt for DEP.  With a prefix argument, prompt for
-NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
-
-(fn DEP &optional CONTEXT NAMESPACE)" t)
- (autoload 'kubed-display-deployment "kubed" nil t)
- (autoload 'kubed-edit-deployment "kubed" nil t)
- (autoload 'kubed-delete-deployments "kubed" nil t)
- (autoload 'kubed-list-deployments "kubed" nil t)
- (autoload 'kubed-create-deployment "kubed" nil t)
- (autoload 'kubed-logs-for-deployment "kubed" nil t)
- (autoload 'kubed-deployment-prefix-map "kubed" nil t 'keymap)
- (autoload 'kubed-display-replicaset "kubed" nil t)
- (autoload 'kubed-edit-replicaset "kubed" nil t)
- (autoload 'kubed-delete-replicasets "kubed" nil t)
- (autoload 'kubed-list-replicasets "kubed" nil t)
- (autoload 'kubed-create-replicaset "kubed" nil t)
- (autoload 'kubed-logs-for-replicaset "kubed" nil t)
- (autoload 'kubed-replicaset-prefix-map "kubed" nil t 'keymap)
- (autoload 'kubed-display-statefulset "kubed" nil t)
- (autoload 'kubed-edit-statefulset "kubed" nil t)
- (autoload 'kubed-delete-statefulsets "kubed" nil t)
- (autoload 'kubed-list-statefulsets "kubed" nil t)
- (autoload 'kubed-create-statefulset "kubed" nil t)
- (autoload 'kubed-logs-for-statefulset "kubed" nil t)
- (autoload 'kubed-statefulset-prefix-map "kubed" nil t 'keymap)
- (autoload 'kubed-display-cronjob "kubed" nil t)
- (autoload 'kubed-edit-cronjob "kubed" nil t)
- (autoload 'kubed-delete-cronjobs "kubed" nil t)
- (autoload 'kubed-list-cronjobs "kubed" nil t)
- (autoload 'kubed-create-cronjob "kubed" nil t)
- (autoload 'kubed-cronjob-prefix-map "kubed" nil t 'keymap)
- (autoload 'kubed-display-ingressclass "kubed" nil t)
- (autoload 'kubed-edit-ingressclass "kubed" nil t)
- (autoload 'kubed-delete-ingressclasses "kubed" nil t)
- (autoload 'kubed-list-ingressclasss "kubed" nil t)
- (autoload 'kubed-create-ingressclass "kubed" nil t)
- (autoload 'kubed-ingressclass-prefix-map "kubed" nil t 'keymap)
- (autoload 'kubed-display-ingress "kubed" nil t)
- (autoload 'kubed-edit-ingress "kubed" nil t)
- (autoload 'kubed-delete-ingresses "kubed" nil t)
- (autoload 'kubed-list-ingresss "kubed" nil t)
- (autoload 'kubed-create-ingress "kubed" nil t)
- (autoload 'kubed-ingress-prefix-map "kubed" nil t 'keymap)
-(autoload 'kubed-use-context "kubed" "\
-Set current Kubernetes context to CONTEXT.
-
-(fn CONTEXT)" t)
-(autoload 'kubed-rename-context "kubed" "\
-Rename Kubernetes context OLD to NEW.
-
-(fn OLD NEW)" t)
-(autoload 'kubed-display-config "kubed" "\
-Display current Kubernetes client settings in a YAML buffer." t)
-(autoload 'kubed-set-namespace "kubed" "\
-Set default Kubernetes namespace in CONTEXT to NAMESPACE.
-
-Interactively, prompt for NAMESPACE and use the current context.  With a
-prefix argument, prompt for CONTEXT as well.
-
-(fn NAMESPACE &optional CONTEXT)" t)
-(autoload 'kubed-apply "kubed" "\
-Apply CONFIG to Kubernetes resource of kind KIND via CONTEXT.
-
-(fn CONFIG &optional KIND CONTEXT)" t)
-(autoload 'kubed-create "kubed" "\
-Create resource of kind KIND with definition DEFINITION via CONTEXT.
-
-(fn DEFINITION &optional KIND CONTEXT)" t)
-(autoload 'kubed-run "kubed" "\
-Run container IMAGE in a new Kubernetes POD.
-
-Optional argument CONTEXT is the `kubectl' context to use, defaulting to
-the current context.  NAMESPACE is the namespace in which to create POD,
-defaulting to the current namespace.  PORT is the port to expose,
-defaulting to none.  If ATTACH is non-nil, then attach to the created
-image with a `comint-mode' buffer, and pop to that buffer.  Non-nil
-STDIN says to keep the standard input of the container open; non-nil TTY
-says to allocate a TTY for the container; and non-nil RM says to remove
-the container after it exits.  ENVS is a list of strings \"VAR=VAL\"
-which specify environment variables VAR and values VAL to give them in
-the created container.  ARGS are command line arguments for the
-container command.  If COMMAND is non-nil, ARGS consist of a complete
-command line, that overrides the container command instead of just
-providing it with arguments.
-
-Interactively, prompt for POD and IMAGE.  With a prefix argument, prompt
-for NAMESPACE; with a double prefix argument, also prompt for CONTEXT.
-
-(fn POD IMAGE &optional CONTEXT NAMESPACE PORT ATTACH STDIN TTY RM ENVS COMMAND ARGS)" t)
-(autoload 'kubed-logs "kubed" "\
-Show logs for container CONTAINER in Kubernetes RESOURCE of type TYPE.
-
-Optional argument CONTEXT is the `kubectl' context to use; NAMESPACE is
-the namespace for RESOURCE; CONTAINER is the name of the container in
-RESOURCE to show logs for, or t which specifies all relevant containers.
-
-With a prefix argument, prompt for NAMESPACE; with a double prefix
-argument, also prompt for CONTEXT.
-
-(fn TYPE RESOURCE &optional CONTEXT NAMESPACE CONTAINER FOLLOW LIMIT PREFIX SINCE TAIL TIMESTAMPS)" t)
-(autoload 'kubed-forward-port-to-pod "kubed" "\
-Forward LOCAL-PORT to REMOTE-PORT of Kubernetes pod POD.
-
-(fn POD LOCAL-PORT REMOTE-PORT CONTEXT NAMESPACE)" t)
-(autoload 'kubed-attach "kubed" "\
-Attach to running process in CONTAINER in Kubernetes POD.
-
-Optional argument NAMESPACE is the namespace in which to look for POD.
-Non-nil STDIN says to connect local standard input to remote process.
-Non-nil TTY says to use a TTY for standard input.
-
-Interactively, prompt for POD; if there are multiple pod containers,
-prompt for CONTAINER as well.  With a prefix argument, prompt for
-NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
-STDIN and TTY are t interactively.
-
-(fn POD &optional CONTAINER CONTEXT NAMESPACE STDIN TTY)" t)
-(autoload 'kubed-diff "kubed" "\
-Display difference between Kubernetes resource DEFINITION and current state.
-
-DEFINITION is either a file name or a buffer.  Interactively, prompt for
-a YAML or JSON file name to use as DEFINITION.
-
-Optional argument CONTEXT is the `kubectl' context to use, defaulting to
-the current context; non-nil INCLUDE-MANAGED (interactively, the prefix
-argument) says to include managed fields in the comparison.
-
-(fn DEFINITION &optional INCLUDE-MANAGED CONTEXT)" t)
-(autoload 'kubed-exec "kubed" "\
-Execute COMMAND with ARGS in CONTAINER in Kubernetes POD.
-
-Optional argument NAMESPACE is the namespace in which to look for POD.
-Non-nil STDIN says to connect local standard input to remote process.
-Non-nil TTY says to use a TTY for standard input.
-
-Interactively, prompt for POD; if there are multiple pod containers,
-prompt for CONTAINER as well.  With a prefix argument, prompt for
-NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
-STDIN and TTY are t interactively.
-
-(fn POD COMMAND &optional CONTAINER CONTEXT NAMESPACE STDIN TTY ARGS)" t)
-(autoload 'kubed-patch "kubed" "\
-Patch Kubernetes resource NAME of TYPE with patch PATCH.
-
-Optional argument NAMESPACE is the namespace in which to look for NAME.
-STRATEGY is the patch type to use, one of \"json\", \"merge\" and
-\"strategic\", defaulting to \"strategic\".
-
-Interactively, prompt for TYPE, NAME and PATCH.  With a prefix argument,
-prompt for NAMESPACE too.  With a double prefix argument, also prompt
-for CONTEXT.
-
-(fn TYPE NAME PATCH &optional CONTEXT NAMESPACE STRATEGY)" t)
-(autoload 'kubed-proxy "kubed" "\
-Start a web server on localhost proxying the Kubernetes API server.
-
-ADDR and PORT are the local address and port to bind the proxy server
-to.  They default to 127.0.0.1 and 8001, respectively.  API-PREFIX is a
-prefix under which to proxy the Kubernetes API.  WWW-DIR is a local
-directory to serve under WWW-PREFIX, which defaults to \"/static/\".
-Lastly, CONTEXT is the the `kubectl' context to use, defaulting to the
-local context.
-
-(fn &optional ADDR PORT API-PREFIX WWW-DIR WWW-PREFIX CONTEXT)" t)
-(autoload 'kubed-stop-proxy "kubed" "\
-Stop local proxy for context CONTEXT, defaulting to the local context.
-
-(fn &optional CONTEXT)" t)
-(autoload 'kubed-explain "kubed" "\
-Show help buffer with explanation about Kubernetes resource FIELD.
-
-(fn FIELD)" t)
-(autoload 'kubed-kubectl-command "kubed" "\
-Execute `kubectl' COMMAND.
-
-This function calls `shell-command' (which see) to do the work.
-
-Interactively, prompt for COMMAND with completion for `kubectl' arguments.
-
-(fn COMMAND)" t)
- (autoload 'kubed-prefix-map "kubed" nil t 'keymap)
-(defvar kubed-menu-bar-mode nil "\
-Non-nil if Kubed-Menu-Bar mode is enabled.
-See the `kubed-menu-bar-mode' command
-for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `kubed-menu-bar-mode'.")
-(custom-autoload 'kubed-menu-bar-mode "kubed" nil)
-(autoload 'kubed-menu-bar-mode "kubed" "\
-Add \"Kubernetes\" menu to your menu bar.
-
-This is a global minor mode.  If called interactively, toggle the
-`Kubed-Menu-Bar mode' mode.  If the prefix argument is positive, enable
-the mode, and if it is zero or negative, disable the mode.
-
-If called from Lisp, toggle the mode if ARG is `toggle'.  Enable the
-mode if ARG is nil, omitted, or is a positive number.  Disable the mode
-if ARG is a negative number.
-
-To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value \\='kubed-menu-bar-mode)'.
-
-The mode's hook is called both when the mode is enabled and when it is
-disabled.
-
-(fn &optional ARG)" t)
-(register-definition-prefixes "kubed" '("kubed-"))
-
-\f
-;;; Generated autoloads from kubed-common.el
-
-(register-definition-prefixes "kubed-common" '("kubed-"))
-
-\f
-;;; Generated autoloads from kubed-tramp.el
-
-(autoload 'kubed-tramp-context "kubed-tramp" "\
-Extract `kubectl' context from Kubed Tramp remote file name FILE-NAME.
-
-(fn FILE-NAME)")
-(autoload 'kubed-tramp-namespace "kubed-tramp" "\
-Extract Kubernetes namespace from Kubed Tramp remote file name FILE-NAME.
-
-(fn FILE-NAME)")
-(autoload 'kubed-tramp-assert-support "kubed-tramp" "\
-Check if Kubed Tramp support is available, throw `user-error' if not.")
-(autoload 'kubed-tramp-enable "kubed-tramp" "\
-Enable Kubed integration with Tramp.")
- (with-eval-after-load 'tramp (kubed-tramp-enable))
-(register-definition-prefixes "kubed-tramp" '("kubed-tramp--"))
-
-\f
-;;; Generated autoloads from kubed-transient.el
-
- (autoload 'kubed-transient "kubed-transient" nil t)
- (autoload 'kubed-transient-logs-for-pod "kubed-transient" nil t)
- (autoload 'kubed-transient-logs-for-deployment "kubed-transient" nil t)
- (autoload 'kubed-transient-logs-for-service "kubed-transient" nil t)
- (autoload 'kubed-transient-logs-for-job "kubed-transient" nil t)
- (autoload 'kubed-transient-logs-for-replicaset "kubed-transient" nil t)
- (autoload 'kubed-transient-logs-for-statefulset "kubed-transient" nil t)
- (autoload 'kubed-transient-logs "kubed-transient" nil t)
- (autoload 'kubed-transient-scale-deployment "kubed-transient" nil t)
- (autoload 'kubed-transient-proxy "kubed-transient" nil t)
- (autoload 'kubed-transient-rollout "kubed-transient" nil t)
- (autoload 'kubed-transient-attach "kubed-transient" nil t)
- (autoload 'kubed-transient-diff "kubed-transient" nil t)
- (autoload 'kubed-transient-exec "kubed-transient" nil t)
- (autoload 'kubed-transient-run "kubed-transient" nil t)
- (autoload 'kubed-transient-apply "kubed-transient" nil t)
- (autoload 'kubed-transient-patch "kubed-transient" nil t)
- (autoload 'kubed-transient-create "kubed-transient" nil t)
- (autoload 'kubed-transient-display "kubed-transient" nil t)
- (autoload 'kubed-transient-edit "kubed-transient" nil t)
- (autoload 'kubed-transient-delete "kubed-transient" nil t)
- (autoload 'kubed-transient-create-cronjob "kubed-transient" nil t)
- (autoload 'kubed-transient-create-ingress "kubed-transient" nil t)
- (autoload 'kubed-transient-create-deployment "kubed-transient" nil t)
- (autoload 'kubed-transient-create-job "kubed-transient" nil t)
- (autoload 'kubed-list-transient "kubed-transient" nil t)
-(register-definition-prefixes "kubed-transient" '("kubed-transient-"))
-\f
-;;; End of scraped data
-
-(provide 'kubed-autoloads)
-
-;; Local Variables:
-;; version-control: never
-;; no-byte-compile: t
-;; no-update-autoloads: t
-;; no-native-compile: t
-;; coding: utf-8-emacs-unix
-;; End:
-
-;;; kubed-autoloads.el ends here
diff --git a/elpa/kubed-0.4.3/kubed-common.el b/elpa/kubed-0.4.3/kubed-common.el
deleted file mode 100644 (file)
index 15e4309..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-;;; kubed-common.el --- Common definitons for Kubed   -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2024-2025  Free Software Foundation, Inc.
-
-;; Author: Eshel Yaron <me@eshelyaron.com>
-;; Keywords: tools
-
-;;; Commentary:
-
-;; This library provides definitions that both `kubed' and `kubed-tramp'
-;; require.
-
-;;; Code:
-
-(defvar kubed-tramp-method "kubedv1"    ;Versioned, for compatibility.
-  ;; (find-file "/kubedv1:CONTEXT%NAMESPACE%POD%CONTAINER:/some/file")
-  "Name of the Kubed Tramp method.")
-
-(defcustom kubed-kubectl-program "kubectl"
-  "Name of `kubectl' executable to use for interacting with Kubernetes."
-  :type 'string
-  :group 'kubed)
-
-(provide 'kubed-common)
-;;; kubed-tramp.el ends here
diff --git a/elpa/kubed-0.4.3/kubed-pkg.el b/elpa/kubed-0.4.3/kubed-pkg.el
deleted file mode 100644 (file)
index b7ede82..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-;; Generated package description from kubed.el  -*- no-byte-compile: t -*-
-(define-package "kubed" "0.4.3" "Kubernetes, Emacs, done!" '((emacs "29.1")) :commit "8f979a198537532ce7749951ee6a85072eeb0610" :authors '(("Eshel Yaron" . "meNOSPAMeshelyaron.com")) :maintainer '("Eshel Yaron" . "~eshel/kubed-develNOSPAMlists.sr.ht") :keywords '("tools" "kubernetes" "containers") :url "https://eshelyaron.com/kubed.html")
diff --git a/elpa/kubed-0.4.3/kubed-tramp.el b/elpa/kubed-0.4.3/kubed-tramp.el
deleted file mode 100644 (file)
index f355c49..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-;;; kubed-tramp.el --- Kubed Tramp integration   -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2024-2025  Free Software Foundation, Inc.
-
-;; Author: Eshel Yaron <meNOSPAMeshelyaron.com>
-;; Keywords: tools
-
-;;; Commentary:
-
-;; This library provides Tramp integration for Kubed.  This is similar
-;; to the built-in "kubernetes" Tramp method from tramp-container.el,
-;; except that the Kubed method always requires the container name and
-;; Kubernetes namespace to be specified, as well a `kubectl' context.
-;; In other words, the filename syntax of this method is fully explicit.
-;; An explicit syntax is useful when juggling between different contexts
-;; and namespaces with Kubed; on the other hand, for finding a remote
-;; file with C-x C-f, the concise syntax of the built-in "kubernetes"
-;; method is probably more convenient.
-
-;;; Code:
-
-(require 'kubed-common)
-(require 'tramp)
-
-(defun kubed-tramp--context (vec)
-  "Extract the context name from a kubernetes host name in VEC."
-  (or (when-let ((host (and vec (tramp-file-name-host vec))))
-        (nth 0 (split-string host "%")))
-      ""))
-
-(defun kubed-tramp--namespace (vec)
-  "Extract the namespace from a kubernetes host name in VEC."
-  (or (when-let ((host (and vec (tramp-file-name-host vec))))
-        (nth 1 (split-string host "%")))
-      ""))
-
-(defun kubed-tramp--pod (vec)
-  "Extract the pod name from a kubernetes host name in VEC."
-  (or (when-let ((host (and vec (tramp-file-name-host vec))))
-        (nth 2 (split-string host "%")))
-      ""))
-
-(defun kubed-tramp--container (vec)
-  "Extract the container name from a kubernetes host name in VEC."
-  (or (when-let ((host (and vec (tramp-file-name-host vec))))
-        (nth 3 (split-string host "%")))
-      ""))
-
-;;;###autoload
-(defun kubed-tramp-context (file-name)
-  "Extract `kubectl' context from Kubed Tramp remote file name FILE-NAME."
-  (nth 0 (split-string
-          (tramp-file-name-host (tramp-dissect-file-name file-name)) "%")))
-
-;;;###autoload
-(defun kubed-tramp-namespace (file-name)
-  "Extract Kubernetes namespace from Kubed Tramp remote file name FILE-NAME."
-  (nth 1 (split-string
-          (tramp-file-name-host (tramp-dissect-file-name file-name)) "%")))
-
-;;;###autoload
-(defun kubed-tramp-assert-support ()
-  "Check if Kubed Tramp support is available, throw `user-error' if not."
-  (unless (assoc kubed-tramp-method tramp-methods)
-    (user-error "Kubed Tramp support requires Tramp version 2.7 or later")))
-
-;;;###autoload
-(defun kubed-tramp-enable ()
-  "Enable Kubed integration with Tramp."
-  (when (boundp 'tramp-extra-expand-args) ; Tramp 2.7+
-
-    (setf (alist-get kubed-tramp-method tramp-methods nil nil #'string=)
-          `((tramp-login-program ,kubed-kubectl-program)
-            (tramp-login-args (("exec")
-                               ("--context" "%x")
-                               ("--namespace" "%y")
-                               ("-c" "%a")
-                               ("%h")
-                               ("-it")
-                               ("--")
-                              ("%l")))
-            (tramp-direct-async (,tramp-default-remote-shell "-c"))
-            (tramp-remote-shell ,tramp-default-remote-shell)
-            (tramp-remote-shell-login ("-l"))
-            (tramp-remote-shell-args ("-i" "-c"))))
-
-    (connection-local-set-profile-variables
-     'kubed-tramp-connection-local-default-profile
-     '((tramp-extra-expand-args
-        ?a (kubed-tramp--container (car tramp-current-connection))
-        ?h (kubed-tramp--pod       (car tramp-current-connection))
-        ?x (kubed-tramp--context   (car tramp-current-connection))
-        ?y (kubed-tramp--namespace (car tramp-current-connection)))))
-
-    (connection-local-set-profiles
-     `(:application tramp :protocol ,kubed-tramp-method)
-     'kubed-tramp-connection-local-default-profile)))
-
-;;;###autoload (with-eval-after-load 'tramp (kubed-tramp-enable))
-
-(provide 'kubed-tramp)
-;;; kubed-tramp.el ends here
diff --git a/elpa/kubed-0.4.3/kubed-transient.el b/elpa/kubed-0.4.3/kubed-transient.el
deleted file mode 100644 (file)
index b2deb0f..0000000
+++ /dev/null
@@ -1,585 +0,0 @@
-;;; kubed-transient.el --- Kubernetes transient menus   -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2024-2025  Free Software Foundation, Inc.
-
-;; Author: Eshel Yaron <meNOSPAMeshelyaron.com>
-;; Keywords: tools
-
-;;; Commentary:
-
-;; This library extends Kubed with transient menus for various
-;; Kubernetes operations.
-
-;;; Code:
-
-(require 'kubed)
-(require 'transient)
-
-(defun kubed-transient-read-date (prompt default _history)
-  "Prompt with PROMPT for a date, defaulting to DEFAULT.
-
-Return an RFC3339 string representation of the selected date."
-  (require 'org)
-  (when (fboundp 'org-read-date)
-    (format-time-string "%Y-%m-%dT%H:%M:%S%:z"
-                        (org-read-date 'with-time t nil prompt default))))
-
-(defun kubed-transient-read-context (prompt _initial-input _history)
-  "Prompt with PROMPT for Kubernetes context."
-  (kubed-read-context prompt (kubed-local-context)))
-
-(defun kubed-transient-read-namespace (prompt _initial-input _history)
-  "Prompt with PROMPT for Kubernetes namespace."
-  (let ((context (or (seq-some (lambda (s)
-                                 (and (cl-typep s 'transient-infix)
-                                      (equal (oref s argument) "--context=")
-                                      (oref s value)))
-                               transient--suffixes)
-                     (kubed-local-context))))
-    (kubed-read-namespace prompt (kubed--namespace context) nil context)))
-
-(defun kubed-transient-read-ingressclass (prompt _initial-input _history)
-  "Prompt with PROMPT for Kubernetes ingress class."
-  (kubed-read-ingressclass prompt))
-
-(defun kubed-transient-read-service-and-port (prompt _initial-input _history)
-  "Prompt with PROMPT for Kubernetes service and port number."
-  (let ((service (kubed-read-service prompt)))
-    (concat service ":" (number-to-string (read-number "Port number: ")))))
-
-(defun kubed-transient-read-resource-definition-file-name
-    (_prompt _initial-input _history)
-  "Read and return Kubernetes resource definition file name."
-  (kubed-read-resource-definition-file-name))
-
-;;;###autoload (autoload 'kubed-transient "kubed-transient" nil t)
-(transient-define-prefix kubed-transient ()
-  "Perform Kubernetes operation."
-  ["Kubernetes"
-   [ :pad-keys t
-     ("RET" "Display" kubed-transient-display)
-     ("+" "Create"  kubed-transient-create)
-     ("*" "Apply"   kubed-transient-apply)
-     ("D" "Delete"  kubed-transient-delete)]
-   [("e" "Edit"    kubed-transient-edit)
-    ("r" "Run"     kubed-transient-run)
-    ("a" "Attach"  kubed-transient-attach)
-    ("X" "Exec"    kubed-transient-exec)]
-   [("l" "Logs"    kubed-transient-logs)
-    ("d" "Diff"    kubed-transient-diff)
-    ("P" "Patch"   kubed-transient-patch)
-    ("R" "Rollout" kubed-transient-rollout)]
-   [("$" "Scale" kubed-transient-scale-deployment)
-    (":" "Proxy" kubed-transient-proxy)
-    ("E" "Explain" kubed-explain)
-    ("!" "Command line" kubed-kubectl-command)]])
-
-(defmacro kubed-transient-logs-for-resource (resource &optional plural)
-  "Define transient menu for showing logs for Kubernetes RESOURCE.
-
-Optional argument PLURAL is the plural form of RESOURCE.  If nil, it
-defaults to \"RESOURCEs\"."
-  (let ((name (intern (concat "kubed-transient-logs-for-" resource))))
-    `(transient-define-prefix ,name (&optional value)
-       ,(format "Show logs for a Kubernetes %s." resource)
-       [,(format "Kubernetes Logs for %s\n" (capitalize resource))
-        ["Actions"
-         ("l" "Show Logs" ,(intern (concat "kubed-logs-for-" resource)))
-         ("!" "Command line" kubed-kubectl-command)]
-        ["Options"
-         ("-n" "Namespace" "--namespace="
-          :prompt "Namespace" :reader kubed-transient-read-namespace)
-         ("-C" "Context" "--context="
-          :prompt "Context" :reader kubed-transient-read-context)
-         ("-b" "Limit bytes" "--limit-bytes="
-          :prompt "Byte limit: " :reader transient-read-number-N+)
-         ("-t" "Limit lines" "--tail="
-          :prompt "Line limit: " :reader transient-read-number-N+)
-         ("-S" "Since time" "--since-time="
-          :prompt "Since time: " :reader kubed-transient-read-date)]
-        ["Switches"
-         ("-A" "All containers" "--all-containers")
-         ("-f" "Stream logs" "--follow")
-         ("-P" "Add pod and container" "--prefix")
-         ("-T" "Add timestamps" "--timestamps")]]
-       (interactive
-        (list (kubed-transient-args 'kubed-transient-logs)))
-       (transient-setup ',name nil nil
-                        :value value
-                        :scope '("logs" ,(concat (or plural
-                                                     (concat resource "s"))
-                                                 "/"))))))
-
-;;;###autoload (autoload 'kubed-transient-logs-for-pod "kubed-transient" nil t)
-(kubed-transient-logs-for-resource "pod")
-
-;;;###autoload (autoload 'kubed-transient-logs-for-deployment "kubed-transient" nil t)
-(kubed-transient-logs-for-resource "deployment")
-
-;;;###autoload (autoload 'kubed-transient-logs-for-service "kubed-transient" nil t)
-(kubed-transient-logs-for-resource "service")
-
-;;;###autoload (autoload 'kubed-transient-logs-for-job "kubed-transient" nil t)
-(kubed-transient-logs-for-resource "job")
-
-;;;###autoload (autoload 'kubed-transient-logs-for-replicaset "kubed-transient" nil t)
-(kubed-transient-logs-for-resource "replicaset")
-
-;;;###autoload (autoload 'kubed-transient-logs-for-statefulset "kubed-transient" nil t)
-(kubed-transient-logs-for-resource "statefulset")
-
-;;;###autoload (autoload 'kubed-transient-logs "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-logs ()
-  "Show logs for containers running in Kubernetes."
-  ["Kubernetes Logs\n"
-   ["Kinds"
-    ("p" "Pod" kubed-transient-logs-for-pod)
-    ("d" "Deployment" kubed-transient-logs-for-deployment)
-    ("j" "Job" kubed-transient-logs-for-job)
-    ("s" "Service" kubed-transient-logs-for-service)
-    ("l" "Any type" kubed-logs)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)
-    ("-b" "Limit bytes" "--limit-bytes="
-     :prompt "Byte limit: " :reader transient-read-number-N+)
-    ("-t" "Limit lines" "--tail="
-     :prompt "Byte limit: " :reader transient-read-number-N+)
-    ("-S" "Since time" "--since-time="
-     :prompt "Since time: " :reader kubed-transient-read-date)]
-   ["Switches"
-    ("-A" "All containers" "--all-containers")
-    ("-f" "Stream logs" "--follow")
-    ("-P" "Add pod and container" "--prefix")
-    ("-T" "Add timestamps" "--timestamps")]]
-  (interactive)
-  (transient-setup 'kubed-transient-logs nil nil
-                   :scope '("logs")))
-
-;;;###autoload (autoload 'kubed-transient-scale-deployment "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-scale-deployment ()
-  "Scale Kubernetes deployments."
-  ["Kubernetes Scale Deployment\n"
-   ["Action"
-    ("$" "Scale" kubed-scale-deployment)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)
-    ("-r" "Replicas" "--replicas="
-     :prompt "Number of replicas: " :reader transient-read-number-N+)]]
-  (interactive)
-  (transient-setup 'kubed-transient-scale-deployment nil nil
-                   :scope '("scale" "deployment")))
-
-;;;###autoload (autoload 'kubed-transient-proxy "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-proxy ()
-  "Create a proxy between localhost and the Kubernetes API server."
-  ["Kubernetes Proxy\n"
-   ["Action"
-    (":" "Start proxy" kubed-proxy)
-    ("|" "Stop proxy" kubed-stop-proxy)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)
-    ("-a" "Address" "--address="
-     :prompt "Local proxy address: ")
-    ("-p" "Port" "--port="
-     :prompt "Local proxy port: " :reader transient-read-number-N0)
-    ("-w" "WWW directory" "--www="
-     :prompt "Local WWW directory: " :reader transient-read-existing-directory)
-    ("-P" "WWW prefix" "--www-prefix="
-     :prompt "WWW prefix: ")
-    ("-A" "API prefix" "--api-prefix="
-     :prompt "API prefix: ")]]
-  (interactive)
-  (transient-setup 'kubed-transient-proxy nil nil
-                   :scope '("proxy")))
-
-;;;###autoload (autoload 'kubed-transient-rollout "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-rollout ()
-  "Manage Kubernetes deployments."
-  ["Kubernetes Rollout\n"
-   ["Actions"
-    ("W" "Watch"   kubed-watch-deployment-status)
-    ("R" "Restart" kubed-restart-deployment)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)]]
-  (interactive)
-  (transient-setup 'kubed-transient-rollout nil nil
-                   :scope '("rollout")))
-
-;;;###autoload (autoload 'kubed-transient-attach "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-attach ()
-  "Attach to running process in container in Kubernetes pod."
-  ["Kubernetes Attach\n"
-   ["Actions"
-    ("a" "Attach" kubed-attach)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Switches"
-    ("-i" "Open stdin" "--stdin")
-    ("-t" "Allocate TTY" "--tty")]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)]]
-  (interactive)
-  (transient-setup 'kubed-transient-attach nil nil
-                   :value '("--stdin" "--tty")
-                   :scope '("attach")))
-
-;;;###autoload (autoload 'kubed-transient-diff "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-diff ()
-  "Display difference between Kubernetes resource definition and current state."
-  ["Kubernetes Diff\n"
-   ["Actions"
-    ("d" "Diff" kubed-diff)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Switches"
-    ("-M" "Include managed fields" "--show-managed-fields")]
-   ["Options"
-    ("-f" "Definition file" "--filename="
-     :reader kubed-transient-read-resource-definition-file-name)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)]]
-  (interactive)
-  (transient-setup 'kubed-transient-diff nil nil
-                   :scope '("diff")))
-
-;;;###autoload (autoload 'kubed-transient-exec "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-exec ()
-  "Execute command in Kubernetes pod."
-  ["Kubernetes Exec\n"
-   ["Actions"
-    ("X" "Execute" kubed-exec)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Switches"
-    ("-i" "Open stdin" "--stdin")
-    ("-t" "Allocate TTY" "--tty")]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)
-    ("--" "Command" "-- ="
-     :prompt "Command: ")]]
-  (interactive)
-  (transient-setup 'kubed-transient-exec nil nil
-                   :value '("--stdin" "--tty")
-                   :scope '("exec")))
-
-;;;###autoload (autoload 'kubed-transient-run "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-run ()
-  "Run container image in a Kubernetes pod."
-  ["Kubernetes Run\n"
-   ["Actions"
-    ("r" "Run" kubed-run)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Switches"
-    ("-A" "Attach" "--attach")
-    ("-i" "Open stdin" "--stdin")
-    ("-t" "Allocate TTY" "--tty")
-    ("-R" "Remove after exit" "--rm")
-    ("-c" "Override container command" "--command")]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)
-    ("-I" "Image" "--image="
-     :prompt "Image to deploy: ")
-    ("-p" "Port" "--port="
-     :prompt "Port to expose: " :reader transient-read-number-N+)
-    ("-E" "Env vars" "--env="
-     :prompt "Set environment VAR=VAL: "
-     :multi-value repeat)
-    ("--" "Arguments" "-- ="
-     :prompt "Arguments for container command: ")]]
-  (interactive)
-  (transient-setup 'kubed-transient-run nil nil
-                   :scope '("run")))
-
-;;;###autoload (autoload 'kubed-transient-apply "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-apply ()
-  "Apply configuration to Kubernetes resource."
-  ["Kubernetes Apply\n"
-   ["Actions"
-    ("*" "Apply" kubed-apply)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-f" "Definition file" "--filename="
-     :reader kubed-transient-read-resource-definition-file-name)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)]]
-  (interactive)
-  (transient-setup 'kubed-transient-apply nil nil
-                   :scope '("apply")))
-
-;;;###autoload (autoload 'kubed-transient-patch "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-patch ()
-  "Apply patch to Kubernetes resource."
-  ["Kubernetes Patch\n"
-   ["Actions"
-    ("P" "Patch" kubed-patch)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)
-    ("-t" "Patch type" "--type="
-     :prompt "Patch type: "
-     :choices ("strategic" "merge" "json"))]]
-  (interactive)
-  (transient-setup 'kubed-transient-patch nil nil
-                   :scope '("patch")))
-
-;;;###autoload (autoload 'kubed-transient-create "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-create ()
-  "Create Kubernetes resource."
-  ["Kubernetes Create\n"
-   ["Kinds"
-    ("p" "Pod" kubed-create-pod)
-    ("d" "Deployment" kubed-transient-create-deployment)
-    ("j" "Job" kubed-transient-create-job)
-    ("c" "CronJob" kubed-transient-create-cronjob)
-    ("s" "Service" kubed-create-service)]
-   ["More"
-    :pad-keys t
-    ("S" "Secret" kubed-create-secret)
-    ("N" "Namespace" kubed-create-namespace)
-    ("i" "Ingress" kubed-transient-create-ingress)
-    ("+" "Any type" kubed-create)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-f" "Definition file" "--filename="
-     :reader kubed-transient-read-resource-definition-file-name)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)]]
-  (interactive)
-  (transient-setup 'kubed-transient-create nil nil
-                   :scope '("create")))
-
-;;;###autoload (autoload 'kubed-transient-display "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-display ()
-  "Display Kubernetes resource."
-  ["Kubernetes Display\n"
-   ["Kinds"
-    ("p" "Pod" kubed-display-pod)
-    ("d" "Deployment" kubed-display-deployment)
-    ("j" "Job" kubed-display-job)
-    ("c" "CronJob" kubed-display-cronjob)
-    ("s" "Service" kubed-display-service)]
-   ["More"
-    :pad-keys t
-    ("S" "Secret" kubed-display-secret)
-    ("N" "Namespace" kubed-display-namespace)
-    ("i" "Ingress" kubed-display-ingress)
-    ("RET" "Any type" kubed-display-resource)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)]]
-  (interactive)
-  (transient-setup 'kubed-transient-display nil nil
-                   :scope '("get")))
-
-;;;###autoload (autoload 'kubed-transient-edit "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-edit ()
-  "Edit Kubernetes resource."
-  ["Kubernetes Edit\n"
-   ["Kinds"
-    ("p" "Pod" kubed-edit-pod)
-    ("d" "Deployment" kubed-edit-deployment)
-    ("j" "Job" kubed-edit-job)
-    ("c" "CronJob" kubed-edit-cronjob)
-    ("s" "Service" kubed-edit-service)]
-   ["More"
-    :pad-keys t
-    ("S" "Secret" kubed-edit-secret)
-    ("N" "Namespace" kubed-edit-namespace)
-    ("i" "Ingress" kubed-edit-ingress)
-    ("RET" "Any type" kubed-edit-resource)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)]]
-  (interactive)
-  (transient-setup 'kubed-transient-edit nil nil
-                   :scope '("edit")))
-
-;;;###autoload (autoload 'kubed-transient-delete "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-delete ()
-  "Delete Kubernetes resource."
-  ["Kubernetes Delete\n"
-   ["Kinds"
-    ("p" "Pod" kubed-delete-pods)
-    ("d" "Deployment" kubed-delete-deployments)
-    ("j" "Job" kubed-delete-jobs)
-    ("c" "CronJob" kubed-delete-cronjobs)
-    ("s" "Service" kubed-delete-services)]
-   ["More"
-    :pad-keys t
-    ("S" "Secret" kubed-delete-secrets)
-    ("N" "Namespace" kubed-delete-namespaces)
-    ("i" "Ingress" kubed-delete-ingresses)
-    ("D" "Any type" kubed-delete-resources)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)]]
-  (interactive)
-  (transient-setup 'kubed-transient-delete nil nil
-                   :scope '("delete")))
-
-;;;###autoload (autoload 'kubed-transient-create-cronjob "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-create-cronjob ()
-  "Create Kubernetes cronjob."
-  ["Kubernetes Create CronJob\n"
-   ["Actions"
-    ("+" "Create" kubed-create-cronjob)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)
-    ("-I" "Image" "--image="
-     :prompt "Image to run: ")
-    ("-S" "Schedule" "--schedule="
-     :prompt "Cron schedule: ")
-    ("--" "Command" "-- ="
-     :prompt "Command: ")]]
-  (interactive)
-  (transient-setup 'kubed-transient-create-cronjob nil nil
-                   :scope '("create" "cronjob")))
-
-;;;###autoload (autoload 'kubed-transient-create-ingress "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-create-ingress ()
-  "Create Kubernetes ingress."
-  ["Kubernetes Create Ingress\n"
-   ["Actions"
-    ("+" "Create" kubed-create-ingress)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)
-    ("-c" "Class" "--class="
-     :prompt "Class" :reader kubed-transient-read-ingressclass)
-    ("-d" "Default backend service" "--default-backend="
-     :prompt "Default backend service"
-     :reader kubed-transient-read-service-and-port)
-    ("-a" "Annotation" "--annotation="
-     :prompt "Ingress annotations: "
-     :multi-value repeat)
-    ("-r" "Rule" "--rule="
-     :prompt "Ingress rule: ")]]
-  (interactive)
-  (transient-setup 'kubed-transient-create-ingress nil nil
-                   :scope '("create" "ingress")))
-
-;;;###autoload (autoload 'kubed-transient-create-deployment "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-create-deployment ()
-  "Create Kubernetes deployment."
-  ["Kubernetes Create Deployment\n"
-   ["Actions"
-    ("+" "Create" kubed-create-deployment)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)
-    ("-r" "Replicas" "--replicas="
-     :prompt "Number of replicas: " :reader transient-read-number-N+)
-    ("-I" "Image" "--image="
-     :prompt "Images to deploy: "
-     :multi-value repeat)
-    ("-p" "Port" "--port="
-     :prompt "Port to expose: " :reader transient-read-number-N+)
-    ("--" "Command" "-- ="
-     :prompt "Command: ")]]
-  (interactive)
-  (transient-setup 'kubed-transient-create-deployment nil nil
-                   :scope '("create" "deployment")))
-
-;;;###autoload (autoload 'kubed-transient-create-job "kubed-transient" nil t)
-(transient-define-prefix kubed-transient-create-job ()
-  "Create Kubernetes job."
-  ["Kubernetes Create Job\n"
-   ["Actions"
-    ("+" "Create" kubed-create-job)
-    ("c" "Create from cronjob" kubed-create-job-from-cronjob)
-    ("!" "Command line" kubed-kubectl-command)]
-   ["Options"
-    ("-n" "Namespace" "--namespace="
-     :prompt "Namespace" :reader kubed-transient-read-namespace)
-    ("-C" "Context" "--context="
-     :prompt "Context" :reader kubed-transient-read-context)
-    ("-I" "Image" "--image="
-     :prompt "Image to run: ")
-    ("--" "Command" "-- ="
-     :prompt "Command: ")]]
-  (interactive)
-  (transient-setup 'kubed-transient-create-job nil nil
-                   :scope '("create" "job")))
-
-;;;###autoload (autoload 'kubed-list-transient "kubed-transient" nil t)
-(transient-define-prefix kubed-list-transient ()
-  "Help for Kubernetes resource list buffers."
-  ;; TODO: Add a type-specific group with `:setup-children'.
-  ["Kubernetes Resources:"
-   ["Select"
-    :pad-keys t
-    ("RET" "Select" kubed-list-select-resource)
-    ("C-o" "Display" kubed-list-display-resource :transient t)
-    ("e" "Edit" kubed-list-edit :transient t)
-    ("w" "Copy name" kubed-list-copy-as-kill :transient t)
-    ("!" "Command line" kubed-list-kubectl-command :transient t)]
-   ["Delete"
-    ("D" "Delete" kubed-list-delete :transient t)
-    ("d" "Mark" kubed-list-mark-for-deletion :transient t)
-    ("u" "Unmark" kubed-list-unmark :transient t)
-    ("x" "Delete marked" kubed-list-delete-marked :transient t)
-    ("+" "Create" kubed-list-create :transient t)]
-   ["Table"
-    ("|" "Fit column" kubed-list-fit-column-width-to-content :transient t)
-    ("}" "Widen column" tabulated-list-widen-current-column :transient t)
-    ("{" "Narrow column" tabulated-list-narrow-current-column :transient t)
-    ("S" "Sort" tabulated-list-sort :transient t)
-    ("/" "Filter" kubed-list-set-filter :transient t)]
-   ["Movement"
-    :pad-keys t
-    ("n" "Next line" next-line :transient t)
-    ("p" "Previous line" previous-line :transient t)
-    ("TAB" "Next column" kubed-list-next-column :transient t)
-    ("S-TAB" "Previous column" kubed-list-previous-column :transient t)
-    ("g" "Update" kubed-list-update :transient t)]]
-  ["Type Specific"
-   :class transient-columns
-   :setup-children
-   (lambda (_)
-     (transient-parse-suffixes 'kubed-list-transient
-                               kubed-list-transient-extra-suffixes))])
-
-(provide 'kubed-transient)
-;;; kubed-transient.el ends here
diff --git a/elpa/kubed-0.4.3/kubed.el b/elpa/kubed-0.4.3/kubed.el
deleted file mode 100644 (file)
index c5f7287..0000000
+++ /dev/null
@@ -1,3522 +0,0 @@
-;;; kubed.el --- Kubernetes, Emacs, done!   -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2024-2025  Free Software Foundation, Inc.
-
-;; Author: Eshel Yaron <meNOSPAMeshelyaron.com>
-;; Maintainer: Eshel Yaron <~eshel/kubed-develNOSPAMlists.sr.ht>
-;; Keywords: tools kubernetes containers
-;; URL: https://eshelyaron.com/kubed.html
-;; Package-Version: 0.4.3
-;; Package-Requires: ((emacs "29.1"))
-
-;;; Commentary:
-
-;; This library defines commands for interacting with Kubernetes
-;; resources, such as Kubernetes pods, services, deployments, and more.
-;;
-;; Use `kubed-display-pod' to display a Kubernetes pod,
-;; `kubed-edit-pod' to edit it, `kubed-delete-pods' to delete it, and
-;; `kubed-list-pods' to see a menu of all pods.  You can create new pods
-;; from YAML or JSON files with `kubed-create-pod'.
-;;
-;; Similar commands are defined for other types of resources as well.
-;;
-;; This library interacts with Kubernetes via `kubectl', and uses the
-;; current `kubectl' context and namespace by default.  To change your
-;; current context or namespace, use commands `kubed-use-context' and
-;; `kubed-set-namespace' respectively; you can also interact with
-;; resources in other namespaces without changing your default
-;; namespace, for example you can call `kubed-list-pods' with a prefix
-;; argument to choose another namespace for listing pods.  The prefix
-;; keymap `kubed-prefix-map' gives you quick access to these and other
-;; useful commands, you may want to bind it globally to a convenient key
-;; with `keymap-global-set':
-;;
-;;   (keymap-global-set "C-c k" 'kubed-prefix-map)
-;;
-;; In addition, the command `kubed-transient' lets you explore various
-;; Kubernetes operations with a transient menu interface.  You may also
-;; want to enable `kubed-menu-bar-mode', which add a "Kubernetes" menu
-;; to your menu-bar with many useful entries.
-;;
-;; If you want to work with more or different types of Kubernetes
-;; resources, use the macro `kubed-define-resource'.  This macro defines
-;; some common functions and commands that'll get you started with ease.
-;;
-;; For more information, see the Kubed manual at (info "(kubed)Top"), or
-;; online at https://eshelyaron.com/kubed.html
-
-;;; Code:
-
-(require 'kubed-common)
-
-(defgroup kubed nil
-  "Kubernetes interface."
-  :group 'tools)
-
-(defcustom kubed-default-context-and-namespace nil
-  "Default `kubectl' context and Kubernetes namespace.
-
-This is either a cons cell (CONTEXT . NAMESPACE), or nil.  If nil, Kubed
-initializes this option to a non-nil value next time Kubed consults it."
-  :type '(choice (const :tag "Initialize from `kubectl' on first use" nil)
-                 (cons :tag "Context and namespace"
-                       (string :tag "Context")
-                       (string :tag "Namespace"))))
-
-(defcustom kubed-yaml-setup-hook '(yaml-ts-mode view-mode)
-  "List of functions to call in Kubernetes resource description YAML buffers.
-
-The first function in the list should normally be the major mode to use,
-by default it is `yaml-ts-mode'."
-  :type 'hook)
-
-(defcustom kubed-logs-setup-hook '(view-mode)
-  "List of functions to call when setting up Kubernetes pod logs buffers."
-  :type 'hook)
-
-(defcustom kubed-name-column '("Name" 48 t)
-  "Specification of resource name column in Kubernetes resource list buffers."
-  :type '(list string natnum boolean))
-
-(defvar kubed--data nil)
-
-(defun kubed--alist (type context namespace)
-  "Return information about resources in CONTEXT of type TYPE in NAMESPACE."
-  (alist-get namespace
-             (alist-get type
-                        (alist-get context
-                                   kubed--data nil nil #'string=)
-                        nil nil #'string=)
-             nil nil #'equal))
-
-(gv-define-setter kubed--alist (value type context namespace)
-  `(setf (alist-get ,namespace
-                    (alist-get ,type
-                               (alist-get ,context
-                                          kubed--data nil nil #'string=)
-                               nil nil #'string=)
-                    nil nil #'equal)
-         ,value))
-
-(defvar kubed--columns nil)
-
-(defun kubed-update (type context &optional namespace)
-  "Update list of resources of type TYPE in CONTEXT and NAMESPACE."
-  (when (process-live-p (alist-get 'process (kubed--alist type context namespace)))
-    (user-error "Update in progress"))
-  (let* ((out (get-buffer-create (format " *kubed-get-%s*"        type)))
-         (err (get-buffer-create (format " *kubed-get-%s-stderr*" type)))
-         (columns (alist-get type kubed--columns nil nil #'string=)))
-    (with-current-buffer out (erase-buffer))
-    (setf (alist-get 'process (kubed--alist type context namespace))
-          (make-process
-           :name (format "*kubed-get-%s*" type)
-           :buffer out
-           :stderr err
-           :command (append
-                     (list kubed-kubectl-program "get" type
-                           "--context" context
-                           (format "--output=custom-columns=%s"
-                                   (mapconcat #'car columns ",")))
-                     (when namespace (list "--namespace" namespace)))
-           :sentinel
-           (lambda (_proc status)
-             (cond
-              ((string= status "finished\n")
-               (let (new offsets eol)
-                 (with-current-buffer out
-                   (goto-char (point-min))
-                   (setq eol (pos-eol))
-                   (while (re-search-forward "[^ ]+" eol t)
-                     (push (1- (match-beginning 0)) offsets))
-                   (setq offsets (nreverse offsets))
-                   (forward-char 1)
-                   (while (not (eobp))
-                     (let ((cols nil)
-                           (beg (car offsets))
-                           (ends (append (cdr offsets)
-                                         (list (- (pos-eol) (point))))))
-                       (dolist (column columns)
-                         (let ((str (string-trim (buffer-substring
-                                                  (+ (point) beg)
-                                                  (+ (point) (car ends))))))
-                           (push (if-let ((f (cdr column))) (funcall f str) str)
-                                 cols)
-                           (setq beg (pop ends))))
-                       (push (nreverse cols) new))
-                     (forward-line 1)))
-                 (setf (kubed--alist type context namespace)
-                       (list (cons 'resources
-                                   (mapcar (lambda (c) (list (car c) (apply #'vector c)))
-                                           new))))
-                 (let ((bufs nil))
-                   (dolist (buf (buffer-list))
-                     (and (equal (buffer-local-value 'kubed-list-type buf) type)
-                          (equal (buffer-local-value 'kubed-list-context buf) context)
-                          (equal (buffer-local-value 'kubed-list-namespace buf) namespace)
-                          (with-current-buffer buf
-                            (when (derived-mode-p 'kubed-list-mode)
-                              (revert-buffer)
-                              (when-let ((win (get-buffer-window)))
-                                (set-window-point win (point))
-                                (push buf bufs))))))
-                   (walk-windows
-                    (lambda (win)
-                      (let ((buf (window-buffer win)))
-                        (when (memq buf bufs)
-                          (set-window-point
-                           win (with-current-buffer buf (point))))))))
-                 (message (format "Updated Kubernetes %S." type))))
-              ((string= status "exited abnormally with code 1\n")
-               (with-current-buffer err
-                 (goto-char (point-max))
-                 (insert "\n" status))
-               (display-buffer err))))))))
-
-(defvar-local kubed-display-resource-info nil
-  "Information about Kubernetes resource that current buffer displays.
-
-The value is a list (TYPE NAME CONTEXT NAMESPACE), where TYPE is the
-type of the resource, NAME is the name of the resource, CONTEXT is the
-`kubectl' context to use for accessing the resource, and NAMESPACE is
-the namespace of the resource, or nil if TYPE is not namespaced.")
-
-(put 'kubed-display-resource-info 'permanent-local t)
-
-(defun kubed-display-resource-revert (&optional _ _)
-  "Clear and populate current Kubernetes resource buffer."
-  (seq-let (type name context namespace)
-      kubed-display-resource-info
-    (let ((inhibit-read-only t)
-          (target (current-buffer)))
-      (buffer-disable-undo)
-      (with-temp-buffer
-        (unless (zerop
-                 (apply
-                  #'call-process
-                  kubed-kubectl-program nil t nil "get"
-                  type "--output=yaml" name
-                  (append (when namespace (list "-n" namespace))
-                          (when context (list "--context" context)))))
-          (error "Failed to display Kubernetes resource `%s'" name))
-        (let ((source (current-buffer)))
-          (with-current-buffer target
-            (replace-buffer-contents source)
-            (set-buffer-modified-p nil)
-            (buffer-enable-undo)))))))
-
-(defun kubed-display-resource-in-buffer
-    (buffer type resource &optional context namespace)
-  "Display Kubernetes RESOURCE of type TYPE in BUFFER."
-  (let ((info (list type resource context namespace)))
-    (with-current-buffer (get-buffer-create buffer)
-      (setq-local kubed-display-resource-info info)
-      (kubed-display-resource-revert)
-      (goto-char (point-min))
-      (run-hooks 'kubed-yaml-setup-hook)
-      (kubed-display-resource-mode)
-      (current-buffer))))
-
-(defun kubed-display-resource-short-description
-    (type resource context namespace)
-  "Return short string to use as a label for RESOURCE of type TYPE."
-  (concat type "/" resource
-          (when namespace (concat "@" namespace))
-          (when context   (concat "[" context "]"))))
-
-(defun kubed-namespaced-p (type &optional context)
-  "Return non-nil if TYPE is a namespaced resource type in context CONTEXT."
-  (member type (kubed-api-resources context t)))
-
-(defun kubed--namespace (context &optional prompt-p)
-  "Return Kubernetes namespace for CONTEXT.
-
-Non-nil optional argument PROMPT-P says to prompt for a namespace."
-  (let ((ns (if (equal context (kubed-local-context))
-                (kubed-local-namespace)
-              (kubed-current-namespace context))))
-    ;; If CONTEXT is another context that has no configured namespace,
-    ;; then NS is nil and we must prompt.
-    (unless ns (setq prompt-p t))
-    (if prompt-p
-        (kubed-read-namespace "Namespace" ns nil context)
-      ns)))
-
-;;;###autoload
-(defun kubed-display-resource
-    (type resource context &optional namespace)
-  "Display Kubernetes RESOURCE of type TYPE in CONTEXT.
-
-For namespaced resource types, NAMESPACE is the namespace of RESOURCE.
-
-Interactively, use the current context and namespace by default, and
-prompt for TYPE and RESOURCE.  With a prefix argument \
-\\[universal-argument],
-prompt for NAMESPACE.  With a double prefix argument \
-\\[universal-argument] \\[universal-argument],
-prompt for CONTEXT as well."
-  (interactive
-   (let ((type nil) (context nil) (namespace nil))
-     (dolist (arg (kubed-transient-args 'kubed-transient-display))
-       (cond
-        ((string-match "--namespace=\\(.+\\)" arg)
-         (setq namespace (match-string 1 arg)))
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (unless type
-       (setq type (kubed-read-resource-type "Type of resource to display"
-                                            nil context)))
-     (when (and (null namespace) (kubed-namespaced-p type context))
-       (setq namespace (kubed--namespace context current-prefix-arg)))
-     (list type (kubed-read-resource-name type "Display" nil nil
-                                          context namespace)
-           context namespace)))
-  (display-buffer
-   (kubed-display-resource-in-buffer
-    (concat "*Kubed "
-            (kubed-display-resource-short-description
-             type resource context namespace)
-            "*")
-    type resource context namespace)))
-
-(declare-function bookmark-prop-get                 "bookmark")
-(declare-function bookmark-get-front-context-string "bookmark")
-(declare-function bookmark-get-rear-context-string  "bookmark")
-(declare-function bookmark-make-record-default      "bookmark")
-
-;;;###autoload
-(defun kubed-display-resource-handle-bookmark (bookmark)
-  "Display Kubernetes resource according to BOOKMARK."
-  (require 'bookmark)
-  (seq-let (type name context namespace)
-      (bookmark-prop-get bookmark 'resource)
-    (set-buffer
-     (kubed-display-resource-in-buffer
-      (concat "*Kubed "
-              (kubed-display-resource-short-description
-               type name context namespace)
-              "*")
-      type name context namespace))
-    (when-let ((str (bookmark-get-front-context-string bookmark))
-               ((search-forward str (point-max) t)))
-      (goto-char (match-beginning 0)))
-    (when-let ((str (bookmark-get-rear-context-string bookmark))
-               ((search-backward str (point-min) t)))
-      (goto-char (match-end 0)))))
-
-(put 'kubed-display-resource-handle-bookmark 'bookmark-handler-type "KubedResource")
-
-(defun kubed-display-resource-make-bookmark ()
-  "Return bookmark pointing to currently displayed Kubernetes resource."
-  (require 'bookmark)
-  (seq-let (type name context namespace) kubed-display-resource-info
-    (cons
-     (kubed-display-resource-short-description type name context namespace)
-     (append
-      (list
-       (cons 'handler #'kubed-display-resource-handle-bookmark)
-       (cons 'resource kubed-display-resource-info))
-      (bookmark-make-record-default t)))))
-
-(defun kubed-display-resource-jump-to-list ()
-  "Jump to line in resources list that corresponds to the displayed resource."
-  (interactive)
-  (seq-let (type name context namespace) kubed-display-resource-info
-    (apply (intern (concat "kubed-list-" type)) context
-           (when namespace (list namespace)))
-    (kubed-list-go-to-line name)))
-
-(defun kubed-display-resource-diff ()
-  "Show diff of current buffer with current state of the displayed resource."
-  (interactive)
-  (kubed-diff (current-buffer) nil (nth 2 kubed-display-resource-info)))
-
-(defun kubed-display-resource-replace ()
-  "Replace displayed Kubernetes resource with current buffer contents."
-  (interactive)
-  (let (choice)
-    (while (= ?d (setq choice
-                       (car (read-multiple-choice
-                             "Replace resource with changes in current buffer?"
-                             '((?y "yes") (?n "no") (?d "diff"))))))
-      (kubed-display-resource-diff))
-    (when (= ?y choice)
-      (let ((err-buf (get-buffer-create " *kubed-replace*")))
-        (with-current-buffer err-buf (erase-buffer))
-        (unless (zerop (call-process-region nil nil kubed-kubectl-program
-                                            nil err-buf nil "replace" "-f" "-"))
-          (display-buffer err-buf)
-          (user-error "`kubectl replace' failed!")))
-      (message "Replaced Kubernetes resource with changes in current buffer.")
-      (revert-buffer))))
-
-(defun kubed-display-resource-p (_symbol buffer)
-  "Return non-nil if `kubed-display-resource-mode' is enabled in BUFFER.
-
-The first argument, SYMBOL, is ignored.  You can use this function as
-the `completion-predicate' property of commands that you define that
-should only be available in buffers that display Kubernetes resources."
-  (buffer-local-value 'kubed-display-resource-mode buffer))
-
-(dolist (cmd '(kubed-display-resource-jump-to-list
-               kubed-display-resource-diff
-               kubed-display-resource-replace))
-  (put cmd 'completion-predicate #'kubed-display-resource-p))
-
-(defvar-keymap kubed-display-resource-mode-map
-  :doc "Keymap buffers that display Kubernetes resource."
-  "C-c C-j" #'kubed-display-resource-jump-to-list
-  "C-c C-=" #'kubed-display-resource-diff
-  "C-c C-c" #'kubed-display-resource-replace)
-
-(define-minor-mode kubed-display-resource-mode
-  "Minor mode for buffers that display a Kubernetes resource."
-  :interactive nil
-  :lighter " Kubed"
-  (when kubed-display-resource-mode
-    (setq-local
-     revert-buffer-function        #'kubed-display-resource-revert
-     bookmark-make-record-function #'kubed-display-resource-make-bookmark)))
-
-(defun kubed-list-filter-lt-operator (v s)
-  "Return non-nil if S is less than V as a number or as a string."
-  (let ((l (string-to-number s)) (r (string-to-number v)))
-    (if (= l r) (string< s v) (< l r))))
-
-(defun kubed-list-filter-gt-operator (v s)
-  "Return non-nil if S is greater than V as a number or as a string."
-  (let ((l (string-to-number s)) (r (string-to-number v)))
-    (if (= l r) (string> s v) (> l r))))
-
-(defcustom kubed-list-filter-operator-alist
-  '((= . string=)
-    (~ . string-match-p)
-    (< . kubed-list-filter-lt-operator)
-    (> . kubed-list-filter-gt-operator))
-  "Association list of filter operators and functions that implement them.
-
-Elements of the list are cons cells (OP . FN), where OP is a symbol that
-is used as a filter operator and FN is a function that implements OP.
-FN takes two arguments, a string STR and a parameter VAL.  FN should
-return non-nil if STR and VAL are related according to OP: to determine
-if a line in which column COL is STR satisfies the filter (OP COL VAL),
-Kubed checks if the form (FN VAL STR) evaluates to non-nil."
-  :type '(alist :key-type (symbol :tag "Operator") :value-type function))
-
-(defun kubed-list-interpret-atomic-filter (atom)
-  "Return function that implements atomic filter ATOM."
-  (if (eq (car-safe atom) 'quote)
-      (let ((p (kubed-list-interpret-atomic-filter (cadr atom))))
-        (lambda (x) (not (funcall p x))))
-    (let* ((column-number (tabulated-list--column-number (symbol-name (nth 1 atom))))
-           (value (nth 2 atom))
-           (value (if (stringp value) value (prin1-to-string value)))
-           (op (alist-get (car atom) kubed-list-filter-operator-alist)))
-      (unless op (user-error "Unknown filter operator `%S'" (car atom)))
-      (lambda (x) (funcall op value (aref (cadr x) column-number))))))
-
-(defvar-local kubed-list-filter nil "Filter in effect in the current buffer.")
-
-(defun kubed-list-interpret-filter (&optional filter)
-  "Return function that implements FILTER.
-
-If FILTER is omitted or nil, it defaults to `kubed-list-filter'."
-  (let ((conjunction (or filter kubed-list-filter)))
-    (if (listp (car conjunction))
-        (let ((conjuncts
-               (mapcar (lambda (disjunction)
-                         (if (listp (car disjunction))
-                             (let ((disjuncts
-                                    (mapcar #'kubed-list-interpret-atomic-filter
-                                            disjunction)))
-                               (lambda (entry)
-                                 (catch 'keep-it
-                                   (dolist (pred disjuncts)
-                                     (when (funcall pred entry)
-                                       (throw 'keep-it t)))
-                                   nil)))
-                           ;; Single atomic disjunct.
-                           (kubed-list-interpret-atomic-filter disjunction)))
-                       (or conjunction kubed-list-filter))))
-          (lambda (entry)
-            (catch 'keep-it
-              (dolist (pred conjuncts)
-                (unless (funcall pred entry)
-                  (throw 'keep-it nil)))
-              t)))
-      ;; Single atomic conjunct.
-      (kubed-list-interpret-atomic-filter conjunction))))
-
-(defun kubed-list-validate-atomic-filter (atom)
-  "Return string explaining why ATOM is invalid, or nil if it is valid."
-  (unless (consp atom)
-    (throw 'validation-error
-           (format (substitute-quotes
-                    "Invalid atomic filter `%S', must be a list")
-                   atom)))
-  (if (eq (car-safe atom) 'quote)
-      (kubed-list-validate-atomic-filter (cadr atom))
-    (unless (length= atom 3)
-      (throw 'validation-error
-             (format (substitute-quotes
-                      "Invalid atomic filter `%S', must have three elements")
-                     atom)))
-    (unless (assq (car atom) kubed-list-filter-operator-alist)
-      (throw 'validation-error
-             (format (substitute-quotes
-                      "No operator `%S' in `kubed-list-filter-operator-alist'")
-                     (car atom))))
-    (unless (ignore-errors
-              (tabulated-list--column-number (symbol-name (nth 1 atom))))
-      (throw 'validation-error (format (substitute-quotes
-                                        "Invalid column name `%S'")
-                                       (nth 1 atom))))))
-
-(defun kubed-list-validate-filter (filter)
-  "Return string explaining why FILTER is invalid, or nil if it is valid."
-  (catch 'validation-error
-    (if (listp (car-safe filter))
-        (dolist (disjunction filter)
-          (if (and (consp disjunction) (listp (car disjunction)))
-              (dolist (disjunct disjunction)
-                (kubed-list-validate-atomic-filter disjunct))
-            (kubed-list-validate-atomic-filter disjunction)))
-      (kubed-list-validate-atomic-filter filter))))
-
-(defvar-local kubed-list-filter-history-variable nil
-  "History list variable to use for filter history in the current buffer.")
-
-(defvar-local kubed--list-read-filter-target-buffer nil
-  "Resource list buffer for which this minibuffer is reading a filter.")
-
-(defvar-local kubed-list-type nil)
-(defvar-local kubed-list-context nil)
-(defvar-local kubed-list-namespace nil)
-
-(defvar-local kubed-list-transient-extra-suffixes nil
-  "List of transient suffixes for the type of resources in current buffer.")
-
-(defun kubed-list-go-to-line (id)
-  "Go to beginning of table line with ID."
-  (let ((pos nil))
-    (save-excursion
-      ;; Wait for refresh to finish, if currently underway.
-      (while (process-live-p
-              (alist-get 'process (kubed--alist kubed-list-type
-                                                kubed-list-context
-                                                kubed-list-namespace)))
-        (accept-process-output
-         (alist-get 'process (kubed--alist kubed-list-type
-                                           kubed-list-context
-                                           kubed-list-namespace))
-         1))
-      (goto-char (point-min))
-      (while (not (or pos (eobp)))
-        (if (equal id (tabulated-list-get-id))
-            (setq pos (point))
-          (forward-line))))
-    (goto-char pos)))
-
-(defun kubed-list-try-read-filter ()
-  "Try to read a resource list filter in the minibuffer.
-
-Exit the minibuffer if successful, else report the error and move point
-to the location of the error.  If point is not already at the location
-of the error, push a mark before moving point."
-  (interactive "" minibuffer-mode)
-  (let* ((prompt-end (minibuffer-prompt-end))
-         (contents (minibuffer-contents))
-         (error-point nil) (error-message nil) (form nil) (inval nil))
-    (with-temp-buffer
-      (condition-case err
-          (progn
-            ;; FIXME: There is a small edge case here that could get
-            ;; better treatment: when `contents' ends with " ?", it
-            ;; espaces the terminating closing parenthesis and leads us
-            ;; to incorrectly report the input as incomplete.
-            (insert "(" contents ")")
-            (goto-char (point-min))
-            (setq form (read (current-buffer))))
-        (error (setq error-point (+ prompt-end (1- (point)))
-                     error-message err))))
-    (cond
-     (error-point
-      (unless (= (point) error-point) (push-mark))
-      (goto-char error-point)
-      (minibuffer-message (error-message-string error-message)))
-     ((setq inval (with-current-buffer kubed--list-read-filter-target-buffer
-                    (kubed-list-validate-filter form)))
-      (minibuffer-message inval))
-     (t (exit-minibuffer)))))
-
-(defvar-keymap kubed-list-read-filter-map
-  :parent minibuffer-local-map
-  "TAB" #'completion-at-point
-  "M-?" #'completion-help-at-point
-  "<remap> <exit-minibuffer>" #'kubed-list-try-read-filter)
-
-(defun kubed-list-read-filter (prompt)
-  "Prompt with PROMPT for a filter for the current buffer."
-  (let* ((buf (current-buffer))
-         (cols (seq-map #'car tabulated-list-format))
-         (vals (let ((tmp nil))
-                 (dolist (ent (alist-get 'resources
-                                         (kubed--alist kubed-list-type
-                                                       kubed-list-context
-                                                       kubed-list-namespace)))
-                   (let ((i 0))
-                     (dolist (col cols)
-                       (push (aref (cadr ent) i)
-                             (alist-get col tmp nil nil #'string=))
-                       (setq i (1+ i)))))
-                 (mapcar #'delete-dups tmp)))
-         (filter
-          (minibuffer-with-setup-hook
-              (lambda ()
-                (set-syntax-table emacs-lisp-mode-syntax-table)
-                (setq-local kubed--list-read-filter-target-buffer buf)
-                (add-hook
-                 'completion-at-point-functions
-                 (lambda ()
-                   (let ((cont (buffer-substring
-                                (minibuffer-prompt-end) (point)))
-                         (bounds (or (bounds-of-thing-at-point 'symbol)
-                                     (cons (point) (point)))))
-                     (with-temp-buffer
-                       (set-syntax-table emacs-lisp-mode-syntax-table)
-                       (insert "(" cont)
-                       (when-let ((fn-argi (elisp--fnsym-in-current-sexp))
-                                  (argi (cadr fn-argi)))
-                         (if (= argi 0)
-                             ;; Complete operators.
-                             (list
-                              (car bounds) (cdr bounds)
-                              (mapcar #'car kubed-list-filter-operator-alist))
-                           (when (car fn-argi)
-                             (cond
-                              ((= argi 1)
-                               ;; Complete column names.
-                               (list (car bounds) (cdr bounds) cols))
-                              ((= argi 2)
-                               ;; Complete column values.
-                               (when-let ((beg (nth 1 (syntax-ppss)))
-                                          ;; Grab preceding symbol.
-                                          (col (save-excursion
-                                                 (goto-char beg)
-                                                 (forward-char 1)
-                                                 (forward-sexp 2)
-                                                 (thing-at-point 'symbol))))
-                                 (list (car bounds) (cdr bounds)
-                                       (alist-get col vals
-                                                  nil nil #'string=)))))))))))
-                 nil t))
-            (read-from-minibuffer
-             (format-prompt prompt "disable")
-             (mapconcat #'prin1-to-string kubed-list-filter " ")
-             kubed-list-read-filter-map nil
-             kubed-list-filter-history-variable ""))))
-    (car (ignore-errors (read-from-string (format "(%s)" filter))))))
-
-(defun kubed-list-set-filter (filter)
-  "Set the filter of the current buffer to FILTER.
-
-FILTER determines which resources to keep.  FILTER can be an atomic
-filter, which is a list (OP COL VAL), where OP is an operator defined in
-`kubed-list-filter-operator-alist' (which see), COL is a symbol whose
-name is a column name, and VAL is a string or an object whose printed
-representation is compared to the value of the column COL according to
-OP.  For example, the atomic filter (= Name foobar) keeps only resources
-whose name is \"foobar\".  (= Name \"foobar\") does exactly the same.
-To negate an atomic filter, quote it.  E.g. use \\='(~ Namespace kube)
-to hide all resources in namespaces whose name contains \"kube\".
-
-FILTER can also be a list of sub-filters (SUB1 SUB2 ...) where each
-sub-filter is either an atomic filter or a list of atomic filters.  If a
-sub-filter is a list of atomic filters, then that sub-filter denotes the
-disjunction of those atomic filters.  FILTER denotes the conjunction of
-the sub-filters.  In particular, FILTER nil denotes the empty
-conjunction which is always true (keeps all resources).
-
-More examples:
-
-- `((= Name foobar) (~ Namespace kube))': keep only resources named
-  \"foobar\" in namespaces that contain \"kube\".
-- `(((= Name foobar) (~ Namespace kube)))': keep resources that are
-  either named \"foobar\" or in a namespace that contains \"kube\".
-- `(((= Name foobar) (~ Namespace kube)) \\='(~ Starttime 2024-07))':
-  keep only resources that are either named \"foobar\" or in a namespace
-  that contains \"kube\", and were not started during July 2024.
-
-Interactively, prompt for FILTER sans the outermost set of parenthesis.
-For example, enter \"= Name foobar\" in the minibuffer to specify the
-atomic FILTER (= Name foobar).
-
-See also Info node \"(kubed) List Filter\"."
-  (interactive (list (kubed-list-read-filter "Set filter")) kubed-list-mode)
-  (when-let ((validation-error (kubed-list-validate-filter filter)))
-    (user-error validation-error))
-  (setq-local kubed-list-filter filter)
-  (revert-buffer))
-
-(defun kubed-list-mark-for-deletion ()
-  "Mark Kubernetes resource at point for deletion."
-  (interactive "" kubed-list-mode)
-  (tabulated-list-put-tag (propertize "D" 'help-echo "Marked for deletion") t))
-
-(defun kubed-list-unmark ()
-  "Remove mark from Kubernetes resource at point."
-  (interactive "" kubed-list-mode)
-  (tabulated-list-put-tag " " t))
-
-(defun kubed-list-previous-column (&optional n)
-  "Move backward N columns.
-
-Interactively, N is the numeric value of the prefix argument, defaulting
-to 1."
-  (interactive "p" kubed-list-mode)
-  (kubed-list-next-column (- n)))
-
-(defun kubed-list-next-column (&optional n)
-  "Move forward N columns.
-
-Interactively, N is the numeric value of the prefix argument, defaulting
-to 1."
-  (interactive "p" kubed-list-mode)
-  (let ((next (point))
-        (times (abs (or n 1)))
-        (dir-fn (if (< 0 n)
-                    #'next-single-property-change
-                  #'previous-single-property-change)))
-    (dotimes (_ times)
-      (setq next (funcall dir-fn next 'tabulated-list-column-name))
-      (when (= (char-after next) ?\n)
-        ;; At line boundary, go to first/last column of next line.
-        (setq next (funcall dir-fn next 'tabulated-list-column-name)))
-      (unless next (user-error "End of table")))
-    (goto-char next)))
-
-(defun kubed-list-copy-as-kill (click)
-  "Copy name of Kubernetes resource at CLICK into the kill ring."
-  (interactive (list last-nonmenu-event) kubed-list-mode)
-  (if-let ((ent (tabulated-list-get-entry (mouse-set-point click)))
-           (new (aref ent 0)))
-      (progn
-        (kill-new new)
-        (message "Copied resource name `%s'" new))
-    (user-error "No Kubernetes resource at point")))
-
-(defun kubed-list-context-menu (menu click)
-  "Extend MENU with common actions on Kubernetes resource at CLICK."
-  (when (tabulated-list-get-entry (posn-point (event-start click)))
-    (define-key menu [kubed-list-select-resource]
-                '(menu-item "Select" kubed-list-select-resource))
-    (define-key menu [kubed-list-display-resource]
-                '(menu-item "Display" kubed-list-display-resource))
-    (define-key menu [kubed-list-delete]
-                '(menu-item "Delete" kubed-list-delete))
-    (define-key menu [kubed-list-patch]
-                '(menu-item "Patch" kubed-list-patch))
-    (define-key menu [kubed-list-edit]
-                '(menu-item "Edit" kubed-list-edit))
-    (define-key menu [kubed-list-kubectl-command]
-                '(menu-item "Execute `kubectl' command" kubed-list-kubectl-command))
-    (define-key menu [kubed-list-copy-as-kill]
-                '(menu-item "Copy name" kubed-list-copy-as-kill)))
-  menu)
-
-(defun kubed-list-update (&optional quiet)
-  "Update list of Kubernetes resources.
-
-If optional argument QUIET is non-nil, do not emit a message when
-starting to update.  Display a message when the update is done
-regardless of QUIET."
-  (interactive "" kubed-list-mode)
-  (kubed-update kubed-list-type kubed-list-context kubed-list-namespace)
-  (force-mode-line-update)
-  (unless quiet (minibuffer-message (format "Updating Kubernetes %S..." kubed-list-type))))
-
-(defun kubed-list-delete-marked ()
-  "Delete marked Kubernetes resources."
-  (interactive "" kubed-list-mode)
-  (let (delete-list)
-    (save-excursion
-      (goto-char (point-min))
-      (while (not (eobp))
-        (when (eq (char-after) ?D)
-          (push (tabulated-list-get-id) delete-list))
-        (forward-line)))
-    (if delete-list
-        (when (y-or-n-p (format "Delete %d marked Kubernetes resources?"
-                                (length delete-list)))
-          (save-excursion
-            (goto-char (point-min))
-            (while (not (eobp))
-              (when (member (tabulated-list-get-id) delete-list)
-                (tabulated-list-put-tag
-                 (propertize "K" 'help-echo "Deletion in progress")))
-              (forward-line)))
-          (let ((errb (generate-new-buffer " *kubed-list-delete-marked-stderr*"))
-                (buf (current-buffer)))
-            (make-process
-             :name "*kubed-list-delete-marked*"
-             :stderr errb
-             :command (cons kubed-kubectl-program
-                            (append
-                             (when kubed-list-context
-                               (list "--context" kubed-list-context))
-                             (when kubed-list-namespace
-                               (list "--namespace" kubed-list-namespace))
-                             (list "delete" kubed-list-type)
-                             delete-list))
-             :sentinel (lambda (_proc status)
-                         (cond
-                          ((string= status "finished\n")
-                           (message (format "Deleted %d marked Kubernetes resources."
-                                            (length delete-list)))
-                           (when (buffer-live-p buf)
-                             (with-current-buffer buf
-                               (kubed-list-update t))))
-                          ((string= status "exited abnormally with code 1\n")
-                           (with-current-buffer errb
-                             (goto-char (point-max))
-                             (insert "\n" status))
-                           (display-buffer errb)))))))
-      (user-error "No Kubernetes resources marked for deletion"))))
-
-(defun kubed-list-display-resource (click)
-  "Display Kubernetes resource at CLICK in another window."
-  (interactive (list last-nonmenu-event) kubed-list-mode)
-  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
-      (kubed-display-resource
-       kubed-list-type resource kubed-list-context kubed-list-namespace)
-    (user-error "No Kubernetes resource at point")))
-
-(defun kubed-list-select-resource (click)
-  "Display Kubernetes resource at CLICK in current window."
-  (interactive (list last-nonmenu-event) kubed-list-mode)
-  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
-      (switch-to-buffer
-       (kubed-display-resource-in-buffer
-        (concat "*Kubed "
-                (kubed-display-resource-short-description
-                 kubed-list-type resource kubed-list-context kubed-list-namespace)
-                "*")
-        kubed-list-type resource kubed-list-context kubed-list-namespace))
-    (user-error "No Kubernetes resource at point")))
-
-(defun kubed-list-select-resource-other-window (click)
-  "Display Kubernetes resource at CLICK in other window and select that window."
-  (interactive (list last-nonmenu-event) kubed-list-mode)
-  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
-      (switch-to-buffer-other-window
-       (kubed-display-resource-in-buffer
-        (concat "*Kubed "
-                (kubed-display-resource-short-description
-                 kubed-list-type resource kubed-list-context kubed-list-namespace)
-                "*")
-        kubed-list-type resource kubed-list-context kubed-list-namespace))
-    (user-error "No Kubernetes resource at point")))
-
-(defun kubed-list-delete (click)
-  "Delete Kubernetes resource at CLICK."
-  (interactive (list last-nonmenu-event) kubed-list-mode)
-  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
-      (when (y-or-n-p (format "Delete `%s'?" resource))
-        (kubed-delete-resources kubed-list-type (list resource)
-                                kubed-list-context kubed-list-namespace))
-    (user-error "No Kubernetes resource at point")))
-
-(defun kubed-list-patch (click)
-  "Patch Kubernetes resource at CLICK."
-  (interactive (list last-nonmenu-event) kubed-list-mode)
-  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
-      (kubed-patch kubed-list-type resource
-                   (kubed-read-patch) kubed-list-context kubed-list-namespace)
-    (user-error "No Kubernetes resource at point")))
-
-(defun kubed-list-edit (click)
-  "Edit Kubernetes resource at CLICK."
-  (interactive (list last-nonmenu-event) kubed-list-mode)
-  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
-      (kubed-edit-resource kubed-list-type resource
-                           kubed-list-context kubed-list-namespace)
-    (user-error "No Kubernetes resource at point")))
-
-(defun kubed-list-kubectl-command (click)
-  "Use Kubernetes resource at CLICK as argument for `kubectl' command."
-  (interactive (list last-nonmenu-event) kubed-list-mode)
-  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
-      (kubed-kubectl-command
-       (kubed-read-kubectl-command
-        "Execute command: "
-        (cons (concat
-               " "
-               (when kubed-list-namespace (concat "-n " kubed-list-namespace " "))
-               (when kubed-list-context (concat "--context " kubed-list-context " "))
-               kubed-list-type " " resource)
-              ;; Put point after "kubectl ".
-              0)))
-    (user-error "No Kubernetes resource at point")))
-
-(defun kubed-list-logs (click)
-  "Show logs for Kubernetes resource at CLICK."
-  (interactive (list last-nonmenu-event) kubed-list-mode)
-  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
-      (kubed-logs kubed-list-type resource kubed-list-context kubed-list-namespace
-                  t t nil t)
-    (user-error "No Kubernetes resource at point")))
-
-(defun kubed-list-create (definition &optional kind)
-  "Create Kubernetes resource of kind KIND from definition file DEFINITION."
-  (interactive (list (kubed-read-resource-definition-file-name)) kubed-list-mode)
-  (kubed-create definition kind kubed-list-context)
-  (kubed-list-update t))
-
-(defun kubed-list-column-number-at-point ()
-  "Return table column number at point."
-  (let ((start (current-column))
-        (nb-cols (1- (length tabulated-list-format)))
-        (col-nb 0)
-        (total-width tabulated-list-padding)
-        (found nil))
-    (while (and (not found) (< col-nb nb-cols))
-      (if (>= start
-              (setq total-width
-                    (+ total-width
-                       (cadr (aref tabulated-list-format col-nb))
-                       (or (plist-get (nthcdr 3 (aref tabulated-list-format
-                                                      col-nb))
-                                      :pad-right)
-                           1))))
-          (setq col-nb (1+ col-nb))
-        (setq found t)))
-    col-nb))
-
-(defun kubed-list-fit-column-width-to-content (n)
-  "Fit width of Nth table column to its content.
-
-If N is negative, fit all columns.  Interactively, N is the column
-number at point, or the numeric prefix argument if you provide one."
-  (interactive
-   (list (if current-prefix-arg
-             (prefix-numeric-value current-prefix-arg)
-           (kubed-list-column-number-at-point)))
-   kubed-list-mode)
-  (if (< n 0)
-      ;; Fit all columns.
-      (let* ((num-cols (length tabulated-list-format))
-             (widths (apply #'vector (seq-map
-                                      ;; +2 to make room for sorting icon.
-                                      (lambda (col) (+ 2 (length (car col))))
-                                      tabulated-list-format))))
-        (save-excursion
-          (goto-char (point-min))
-          (while-let ((entry (tabulated-list-get-entry)))
-            (dotimes (i num-cols)
-              (aset widths i (max (aref widths i) (length (aref entry i)))))
-            (forward-line)))
-        (setq tabulated-list-format (copy-tree tabulated-list-format t))
-        (dotimes (i num-cols)
-          (setf (cadr (aref tabulated-list-format i))
-                (1+ (aref widths i)))))
-    ;; Fit Nth column.
-    (let* ((width (+ 2 (length (car (aref tabulated-list-format n))))))
-      (save-excursion
-        (goto-char (point-min))
-        (while-let ((entry (tabulated-list-get-entry)))
-          (setq width (max width (length (aref entry n))))
-          (forward-line)))
-      (setq tabulated-list-format (copy-tree tabulated-list-format t))
-      (setf (cadr (aref tabulated-list-format n)) (1+ width))))
-  (tabulated-list-print t)
-  (tabulated-list-init-header))
-
-(declare-function kubed-list-transient                 "kubed-transient" ())
-(declare-function kubed-transient-logs-for-pod         "kubed-transient" (val))
-(declare-function kubed-transient-logs-for-deployment  "kubed-transient" (val))
-(declare-function kubed-transient-logs-for-statefulset "kubed-transient" (val))
-(declare-function kubed-transient-logs-for-replicaset  "kubed-transient" (val))
-(declare-function kubed-transient-logs-for-job         "kubed-transient" (val))
-(declare-function kubed-transient-logs-for-service     "kubed-transient" (val))
-
-(defvar-keymap kubed-list-mode-map
-  :doc "Common keymap for Kubernetes resource list buffers."
-  "RET" #'kubed-list-select-resource
-  "o" #'kubed-list-select-resource-other-window
-  "C-o" #'kubed-list-display-resource
-  "D" #'kubed-list-delete
-  "P" #'kubed-list-patch
-  "x" #'kubed-list-delete-marked
-  "e" #'kubed-list-edit
-  "!" #'kubed-list-kubectl-command
-  "g" #'kubed-list-update
-  "/" #'kubed-list-set-filter
-  "|" #'kubed-list-fit-column-width-to-content
-  "d" #'kubed-list-mark-for-deletion
-  "u" #'kubed-list-unmark
-  "w" #'kubed-list-copy-as-kill
-  "C-i" #'kubed-list-next-column
-  "TAB" #'kubed-list-next-column
-  "C-S-i" #'kubed-list-previous-column
-  "S-TAB" #'kubed-list-previous-column
-  "<backtab>" #'kubed-list-previous-column
-  "+" #'kubed-list-create
-  "?" #'kubed-list-transient)
-
-(defun kubed-list-entries ()
-  "`tabulated-list-entries' function for `kubed-list-mode'."
-  (let ((pred (kubed-list-interpret-filter))
-        (ents nil))
-    (dolist (ent (alist-get 'resources (kubed--alist kubed-list-type
-                                                     kubed-list-context
-                                                     kubed-list-namespace)))
-      (when (funcall pred ent) (push ent ents)))
-    (reverse ents)))
-
-;;;###autoload
-(defun kubed-list-handle-bookmark (bookmark)
-  "Display Kubernetes resource according to BOOKMARK."
-  (require 'bookmark)
-  (let* ((type (bookmark-prop-get bookmark 'type))
-         (context (bookmark-prop-get bookmark 'context))
-         (namespace (bookmark-prop-get bookmark 'namespace))
-         (current (bookmark-prop-get bookmark 'current))
-         (buff-fn (intern (format "kubed-%s-buffer" type)))
-         (buff (apply buff-fn context (when namespace (list namespace)))))
-    (set-buffer buff)
-    (when current (kubed-list-go-to-line current))))
-
-(put 'kubed-list-handle-bookmark 'bookmark-handler-type "KubedList")
-
-(defun kubed-list-make-bookmark ()
-  "Return bookmark pointing to currently displayed Kubernetes resource."
-  (require 'bookmark)
-  (cons
-   (concat kubed-list-type
-           (when kubed-list-namespace (concat "@" kubed-list-namespace))
-           (when kubed-list-context   (concat "[" kubed-list-context "]")))
-   (append
-    (list
-     (cons 'handler #'kubed-list-handle-bookmark)
-     (cons 'filter kubed-list-filter)
-     (cons 'type kubed-list-type)
-     (cons 'context kubed-list-context)
-     (cons 'current (tabulated-list-get-id))
-     (cons 'namespace kubed-list-namespace)))))
-
-(defun kubed-list-revert (&rest _)
-  "Revert the current Kubernetes resources list buffer.
-
-This is the `revert-buffer-function' for `kubed-list-mode' and its
-derivatives.  This function does not fetch new data from Kubernetes, it
-only (re)displays the existing data."
-  (let (marks)
-    (save-excursion
-      (goto-char (point-min))
-      (while (not (eobp))
-        (unless (eq (char-after) ?\s)
-          (push (cons (tabulated-list-get-id)
-                      ;; Preserve mark text properties.
-                      (buffer-substring (point) (1+ (point))))
-                marks))
-        (forward-line)))
-    (tabulated-list-revert)
-    (save-excursion
-      (goto-char (point-min))
-      (while (not (eobp))
-        (let ((id (tabulated-list-get-id)))
-          (when-let ((mark (alist-get id marks nil nil #'equal)))
-            (tabulated-list-put-tag mark)))
-        (forward-line)))))
-
-(define-derived-mode kubed-list-mode tabulated-list-mode "Kubernetes Resources"
-  "Major mode for listing Kubernetes resources.
-
-Modes for specific resource types, such as `kubed-pods-mode', use this
-mode as their parent."
-  :interactive nil
-  (setq-local truncate-string-ellipsis (propertize ">" 'face 'shadow)
-              tabulated-list-entries #'kubed-list-entries
-              bookmark-make-record-function #'kubed-list-make-bookmark
-              revert-buffer-function #'kubed-list-revert)
-  (add-hook 'context-menu-functions #'kubed-list-context-menu nil t))
-
-;;;###autoload
-(defun kubed-delete-resources (type resources context &optional namespace)
-  "Delete Kubernetes RESOURCES of type TYPE in context CONTEXT.
-
-For namespaced resource types, NAMESPACE is the namespace of RESOURCE.
-
-Interactively, use the current context and namespace by default, and
-prompt for TYPE and RESOURCES.  With a prefix argument \
-\\[universal-argument],
-prompt for NAMESPACE.  With a double prefix argument \
-\\[universal-argument] \\[universal-argument],
-prompt for CONTEXT as well."
-  (interactive
-   (let ((type nil) (context nil) (namespace nil))
-     (dolist (arg (kubed-transient-args 'kubed-transient-delete))
-       (cond
-        ((string-match "--namespace=\\(.+\\)" arg)
-         (setq namespace (match-string 1 arg)))
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (unless type
-       (setq type (kubed-read-resource-type "Type of resource to delete"
-                                            nil context)))
-     (when (and (null namespace) (kubed-namespaced-p type context))
-       (setq namespace (kubed--namespace context current-prefix-arg)))
-     (list type (kubed-read-resource-name type "Delete" nil t
-                                          context namespace)
-           context namespace)))
-  (unless resources (user-error "You didn't specify %s to delete" type))
-  (message (format "Deleting Kubernetes %s `%s'..."
-                   type (string-join resources "', `")))
-  (if (zerop (apply #'call-process
-                    kubed-kubectl-program nil nil nil
-                    "delete" type
-                    (append (when namespace (list "-n" namespace))
-                            (when context (list "--context" context))
-                            resources)))
-      (message (format "Deleting Kubernetes %s `%s'...  Done."
-                       type (string-join resources "', `")))
-    (error (format "Failed to delete Kubernetes %s `%s'"
-                   type (string-join resources "', `")))))
-
-;;;###autoload
-(defun kubed-edit-resource (type resource context &optional namespace)
-  "Edit Kubernetes RESOURCE of type TYPE in context CONTEXT.
-
-For namespaced resource types, NAMESPACE is the namespace of RESOURCE.
-
-Interactively, use the current context and namespace by default, and
-prompt for TYPE and RESOURCES.  With a prefix argument \
-\\[universal-argument],
-prompt for NAMESPACE.  With a double prefix argument \
-\\[universal-argument] \\[universal-argument],
-prompt for CONTEXT as well."
-  (interactive
-   (let ((type nil) (context nil) (namespace nil))
-     (dolist (arg (kubed-transient-args 'kubed-transient-edit))
-       (cond
-        ((string-match "--namespace=\\(.+\\)" arg)
-         (setq namespace (match-string 1 arg)))
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (unless type
-       (setq type (kubed-read-resource-type "Type of resource to edit"
-                                            nil context)))
-     (when (and (null namespace) (kubed-namespaced-p type context))
-       (setq namespace (kubed--namespace context current-prefix-arg)))
-     (list type (kubed-read-resource-name type "Edit" nil nil
-                                          context namespace)
-           context namespace)))
-  (unless (bound-and-true-p server-process) (server-start))
-  (let ((process-environment
-         (cons (if (boundp 'emacsclient-program-name)
-                   (concat "KUBE_EDITOR=" emacsclient-program-name)
-                 "KUBE_EDITOR=emacsclient")
-               process-environment)))
-    (apply #'start-process
-           (format "*kubed-%S-edit*" type) nil
-           kubed-kubectl-program "edit" type resource
-           (append
-            (when namespace (list "-n" namespace))
-            (when context (list "--context" context))))))
-
-(defcustom kubed-list-mode-line-format
-  '(:eval (cond
-           ((process-live-p
-             (alist-get 'process
-                        (kubed--alist kubed-list-type
-                                      kubed-list-context
-                                      kubed-list-namespace)))
-            (propertize "[...]" 'help-echo "Updating..."))
-           (kubed-list-filter
-            (propertize
-             (concat "[" (mapconcat #'prin1-to-string kubed-list-filter " ") "]")
-             'help-echo "Current filter"))))
-  "Mode line construct for indicating status of Kubernetes resources list."
-  :type 'sexp
-  :risky t)
-
-;;;###autoload
-(defmacro kubed-define-resource (resource &optional properties &rest commands)
-  "Define Kubernetes RESOURCE with associated PROPERTIES and COMMANDS.
-
-RESOURCE is a symbol corresponding to a Kubernetes resource type, such
-as `pod' or `service'.  This macro defines the following commands for
-interacting with Kubernetes RESOURCEs:
-
-- `kubed-display-RESOURCE': prompt for a RESOURCE and display its
-  description in YAML format.  See also `kubed-yaml-setup-hook'.
-- `kubed-edit-RESOURCE': prompt for a RESOURCE and edit it.
-- `kubed-delete-RESOURCE': prompt for a RESOURCE and delete it.
-- `kubed-list-RESOURCEs': display a buffer listing all RESOURCEs in the
-  current namespace.  The RESOURCEs list buffer uses a dedicated major
-  mode, `kubed-RESOURCEs-mode', which is also defined by this macro.
-- `kubed-create-RESOURCE': create a RESOURCE from a YAML or a JSON file.
-- `kubed-explain-RESOURCEs': show buffer with help about RESOURCEs.
-
-This macro also defines a prefix keymap, `kubed-RESOURCE-prefix-map',
-with bindings for the above commands.
-
-PROPERTIES is a list of lists (PROP JSON-PATH WIDTH SORT FORMAT . ATTRS)
-that specify properties of RESOURCEs.  PROP is the name of the property,
-as a symbol; JSON-PATH is a JSONPath expression that evaluates to the
-value of PROP when applied to the JSON representation of a RESOURCE.
-WIDTH, SORT, FORMAT and ATTRS are optional and can be omitted.  WIDTH is
-used as the default width of the column corresponding to PROP in
-RESOURCEs list buffers; SORT is sort predicate, a function that takes
-two values of PROP as strings and returns non-nil if the first should
-sort before the second; FORMAT is a function that takes a value of PROP
-and formats it.  If you provide a FORMAT function and a SORT function,
-then the SORT function gets the formatted values (the output of the
-FORMAT function), not the original values.  If you want to sort based on
-the unformatted original values, you can store them as text properties
-in your FORMAT function and access them in your SORT function.
-
-ATTRS is a plist of additional attributes of the PROP column, see
-`tabulated-list-format' for available attributes.
-
-For example, if PROPERTIES is (phase \".status.phase\" 10) that means
-that RESOURCE has a `phase' property at JSONPath \".status.phase\" whose
-values are typically 10 columns wide.  The first property in PROPERTIES
-is used to annotate completion candidates when prompting for a RESOURCE.
-
-COMMANDS is a list of elements (COMMAND KEYS DOC-PREFIX . BODY) that
-define commands for RESOURCE list buffers.  COMMAND is a symbol
-specifying the suffix of the command name, the full name of the command
-is `kubed-RESOURCEs-COMMAND' (for example, `kubed-pods-shell'); KEYS is
-either a string that specifies a key sequence to bind to the command in
-`kubed-RESOURCEs-mode-map', or nil if the command should not be bound;
-DOC-PREFIX is a string used to construct the docstring of the command,
-this macro appends the string \" Kubernetes RESOURCE at point.\" to it
-to obtain the final docstring; lastly, BODY is the body the command.
-Within BODY, the variable RESOURCE is let-bound to the name of the
-RESOURCE at point.  For example, if RESOURCE is `pod', the following
-COMMANDS element defines a command `kubed-pods-frob' and binds it to the
-key \"f\" in `kubed-pods-mode-map':
-
-  (frob \"f\" \"Frobnicate\"
-        (message \"Preparing...\")
-        (frobnicate-pod pod)
-        (message \"Done.\"))
-
-By default, this macro assumes that RESOURCE is namespaced.  To define a
-namespaceless resource type, put `:namespaced nil' before COMMANDS:
-
-  (kubed-define-resource global-thingy (PROP1 PROP2 ...) :namespaced nil
-    CMD1
-    CMD2
-    ...)
-
-Other keyword arguments that go between PROPERTIES and COMMANDS are:
-
-- `:create (ARGLIST DOCSTRING INTERACTIVE BODY...)': specialize the
-  resource creation command, `kubed-create-RESOURCE'.  ARGLIST,
-  DOCSTRING, INTERACTIVE and BODY have the same meaning as in `defun'.
-- `:prefix ((KEY LABEL DEFINITION)...)': additional keybinding for the
-  prefix keymap `kubed-RESOURCE-prefix-map' and the
-  `kubed-RESOURCE-menu-map' menu.  Each element (KEY LABEL DEFINITION)
-  says to bind KEY to DEFINITION in `kubed-RESOURCE-menu-map', and to
-  add DEFINITION to `kubed-RESOURCE-menu-map' with the label LABEL.
-- `:plural PLURAL': specify plural form of RESOURCE, as a symbol.  If
-  you omit this keyword argument, the plural form defaults to RESOURCE
-  followed by \"s\".
-- `:logs t': generate `kubed-logs-for-RESOURCE' command.
-- `:suffixes (SUFFIX...)': add type-specific transient suffixes to
-  `kubed-list-transient'."
-  (declare (indent 2))
-  (let ((plrl-var (intern (format "%Ss"                         resource)))
-        (read-fun (intern (format "kubed-read-%S"               resource)))
-        (dsp-name (intern (format "kubed-display-%S"            resource)))
-        (edt-name (intern (format "kubed-edit-%S"               resource)))
-        (crt-name (intern (format "kubed-create-%S"             resource)))
-        (map-name (intern (format "kubed-%S-prefix-map"         resource)))
-        (menu-map (intern (format "kubed-%S-menu-map"           resource)))
-        (logs-cmd (intern (format "kubed-logs-for-%S"           resource)))
-        (logs-trs (intern (format "kubed-transient-logs-for-%S" resource)))
-        (namespaced t) (logs nil)
-        (keyword nil)
-        frmt-var buff-fun list-cmd expl-cmd dlt-name mod-name
-        ctxt-fun crt-spec prf-keys hist-var trs-cols)
-
-    ;; Process keyword arguments.
-    (while (keywordp (car commands))
-      (setq keyword (pop commands))
-      (cond
-       ((eq keyword :namespaced) (setq namespaced (pop commands)))
-       ((eq keyword :logs)       (setq logs       (pop commands)))
-       ((eq keyword :create)     (setq crt-spec   (pop commands)))
-       ((eq keyword :prefix)     (setq prf-keys   (pop commands)))
-       ((eq keyword :plural)     (setq plrl-var   (pop commands)))
-       ((eq keyword :suffixes)   (setq trs-cols   (pop commands)))
-       ;; FIXME: Add error for unknown keywords.
-       (t (pop commands))))
-
-    (setq frmt-var (intern (format "kubed-%S-columns"       plrl-var))
-          hist-var (intern (format "kubed-%S-history"       plrl-var))
-          buff-fun (intern (format "kubed-%S-buffer"        plrl-var))
-          list-cmd (intern (format "kubed-list-%S"          plrl-var))
-          expl-cmd (intern (format "kubed-explain-%S"       plrl-var))
-          dlt-name (intern (format "kubed-delete-%S"        plrl-var))
-          mod-name (intern (format "kubed-%S-mode"          plrl-var))
-          ctxt-fun (intern (format "kubed-%S-context-menu"  plrl-var)))
-
-    (when logs (push `("L" "Show Logs" ,logs-cmd) prf-keys))
-
-    ;; Generate code.
-    `(progn
-       (setf (alist-get ,(symbol-name plrl-var) kubed--columns nil nil #'string=)
-             (list
-              '("NAME:.metadata.name")
-              ,@(mapcar (lambda (p)
-                          `(cons ,(concat (upcase (symbol-name (car p)))
-                                          ":"
-                                          (cadr p))
-                                 ,(nth 4 p)))
-                        properties)))
-
-       (defvar ,hist-var nil
-         ,(format "History list for `%S'." read-fun))
-
-       (defun ,read-fun (prompt &optional default multi context
-                                . ,(when namespaced '(namespace)))
-         ,(format "Prompt with PROMPT for a Kubernetes %S name.
-
-Optional argument DEFAULT is the minibuffer default argument.
-
-Non-nil optional argument MULTI says to read and return a list
-of %S, instead of just one." resource plrl-var)
-         (kubed-read-resource-name ,(symbol-name plrl-var) prompt default multi context . ,(when namespaced '(namespace))))
-
-       (defun ,dsp-name (,resource &optional context . ,(when namespaced '(namespace)))
-         ,(if namespaced
-              (format "Display Kubernetes %S %s in CONTEXT and NAMESPACE.
-
-Interactively, use the current context and namespace by default.  With a
-prefix argument \\[universal-argument], prompt for NAMESPACE.  With a
-double prefix argument \\[universal-argument] \\[universal-argument], \
-prompt for CONTEXT as well." resource (upcase (symbol-name resource)))
-            (format "Display Kubernetes %S %s in context CONTEXT.
-
-Interactively, use the current context.  With a prefix argument
-\\[universal-argument], prompt for CONTEXT." resource (upcase (symbol-name resource))))
-         (interactive
-          ,(if namespaced
-               `(let ((context nil) (namespace nil))
-                  (dolist (arg (kubed-transient-args 'kubed-transient-display))
-                    (cond
-                     ((string-match "--namespace=\\(.+\\)" arg)
-                      (setq namespace (match-string 1 arg)))
-                     ((string-match "--context=\\(.+\\)" arg)
-                      (setq context (match-string 1 arg)))))
-                  (unless context
-                    (setq context
-                          (let ((cxt (kubed-local-context)))
-                            (if (equal current-prefix-arg '(16))
-                                (kubed-read-context "Context" cxt)
-                              cxt))))
-                  (unless namespace
-                    (setq namespace (kubed--namespace context current-prefix-arg)))
-                  (list (,read-fun "Display" nil nil context namespace) context namespace))
-             `(let ((context nil))
-                (dolist (arg (kubed-transient-args 'kubed-transient-display))
-                  (cond
-                   ((string-match "--context=\\(.+\\)" arg)
-                    (setq context (match-string 1 arg)))))
-                (unless context
-                  (setq context
-                        (let ((cxt (kubed-local-context)))
-                          (if current-prefix-arg
-                              (kubed-read-context "Context" cxt)
-                            cxt))))
-                (list (,read-fun "Display" nil nil context) context))))
-         (let ((context (or context (kubed-local-context))))
-           (kubed-display-resource
-            ,(symbol-name plrl-var) ,resource context
-            . ,(when namespaced '((or namespace (kubed--namespace context)))))))
-
-       (defun ,edt-name (,resource &optional context . ,(when namespaced '(namespace)))
-         ,(if namespaced
-              (format "Edit Kubernetes %S %s in CONTEXT and NAMESPACE.
-
-Interactively, use the current context and namespace by default.  With a
-prefix argument \\[universal-argument], prompt for NAMESPACE.  With a
-double prefix argument \\[universal-argument] \\[universal-argument], \
-prompt for CONTEXT as well." resource (upcase (symbol-name resource)))
-            (format "Edit Kubernetes %S %s in context CONTEXT.
-
-Interactively, use the current context.  With a prefix argument
-\\[universal-argument], prompt for CONTEXT." resource (upcase (symbol-name resource))))
-         (interactive
-          ,(if namespaced
-               `(let ((context nil) (namespace nil))
-                  (dolist (arg (kubed-transient-args 'kubed-transient-edit))
-                    (cond
-                     ((string-match "--namespace=\\(.+\\)" arg)
-                      (setq namespace (match-string 1 arg)))
-                     ((string-match "--context=\\(.+\\)" arg)
-                      (setq context (match-string 1 arg)))))
-                  (unless context
-                    (setq context
-                          (let ((cxt (kubed-local-context)))
-                            (if (equal current-prefix-arg '(16))
-                                (kubed-read-context "Context" cxt)
-                              cxt))))
-                  (unless namespace
-                    (setq namespace (kubed--namespace context current-prefix-arg)))
-                  (list (,read-fun "Edit" nil nil context namespace) context namespace))
-             `(let ((context nil))
-                (dolist (arg (kubed-transient-args 'kubed-transient-edit))
-                  (cond
-                   ((string-match "--context=\\(.+\\)" arg)
-                    (setq context (match-string 1 arg)))))
-                (unless context
-                  (setq context
-                        (let ((cxt (kubed-local-context)))
-                          (if current-prefix-arg
-                              (kubed-read-context "Context" cxt)
-                            cxt))))
-                (list (,read-fun "Edit" nil nil context) context))))
-         (let ((context (or context (kubed-local-context))))
-           (kubed-edit-resource
-            ,(symbol-name plrl-var) ,resource context
-            . ,(when namespaced '((or namespace (kubed--namespace context)))))))
-
-       (defun ,dlt-name (,plrl-var &optional context
-                                   . ,(when namespaced '(namespace)))
-         ,(if namespaced
-              (format "Delete Kubernetes %S %s in CONTEXT and NAMESPACE.
-
-Interactively, use the current context and namespace by default.  With a
-prefix argument \\[universal-argument], prompt for NAMESPACE.  With a
-double prefix argument \\[universal-argument] \\[universal-argument], \
-prompt for CONTEXT as well." plrl-var (upcase (symbol-name plrl-var)))
-            (format "Delete Kubernetes %S %s in context CONTEXT.
-
-Interactively, use the current context.  With a prefix argument
-\\[universal-argument], prompt for CONTEXT." plrl-var (upcase (symbol-name plrl-var))))
-         (interactive
-          ,(if namespaced
-               `(let ((context nil) (namespace nil))
-                  (dolist (arg (kubed-transient-args 'kubed-transient-delete))
-                    (cond
-                     ((string-match "--namespace=\\(.+\\)" arg)
-                      (setq namespace (match-string 1 arg)))
-                     ((string-match "--context=\\(.+\\)" arg)
-                      (setq context (match-string 1 arg)))))
-                  (unless context
-                    (setq context
-                          (let ((cxt (kubed-local-context)))
-                            (if (equal current-prefix-arg '(16))
-                                (kubed-read-context "Context" cxt)
-                              cxt))))
-                  (unless namespace
-                    (setq namespace (kubed--namespace context current-prefix-arg)))
-                  (list (,read-fun "Delete" nil t context namespace) context namespace))
-             `(let ((context nil))
-                (dolist (arg (kubed-transient-args 'kubed-transient-delete))
-                  (cond
-                   ((string-match "--context=\\(.+\\)" arg)
-                    (setq context (match-string 1 arg)))))
-                (unless context
-                  (setq context
-                        (let ((cxt (kubed-local-context)))
-                          (if current-prefix-arg
-                              (kubed-read-context "Context" cxt)
-                            cxt))))
-                (list (,read-fun "Delete" nil t context) context))))
-         (unless ,plrl-var
-           (user-error ,(format "You didn't specify %S to delete" plrl-var)))
-         (let ((context (or context (kubed-local-context))))
-           (kubed-delete-resources
-            ,(symbol-name plrl-var) ,plrl-var context
-            . ,(when namespaced '((or namespace (kubed--namespace context)))))))
-
-       ,(if crt-spec `(defun ,crt-name . ,crt-spec)
-          `(defun ,crt-name (definition &optional context)
-             ,(format "Create Kubernetes %s from file DEFINITION in CONTEXT.
-
-Interactively, prompt for DEFINITION and use the current context.  With
-a prefix argument \\[universal-argument], prompt for CONTEXT too."
-                      (symbol-name resource))
-             (interactive
-              (let ((context nil))
-                (dolist (arg (kubed-transient-args 'kubed-transient-create))
-                  (cond
-                   ((string-match "--context=\\(.+\\)" arg)
-                    (setq context (match-string 1 arg)))))
-                (unless context
-                  (setq context
-                        (let ((cxt (kubed-local-context)))
-                          (if current-prefix-arg
-                              (kubed-read-context "Context" cxt)
-                            cxt))))
-                (list (kubed-read-resource-definition-file-name ,(symbol-name resource))
-                      context)))
-             (kubed-create definition ,(symbol-name resource) context)
-             (kubed-update ,(symbol-name plrl-var) context)))
-
-       ,@(when logs
-           `((defun ,logs-cmd
-                 ( ,resource &optional context namespace
-                   container follow limit prefix since tail timestamps)
-               ,(format "Show logs for Kubernetes %S %s."
-                        resource (upcase (symbol-name resource)))
-               (interactive
-                (let ( ,resource context namespace
-                       container follow limit prefix since tail timestamps)
-                  (dolist (arg (kubed-transient-args
-                                ',logs-trs))
-                    (cond
-                     ((string-match "--namespace=\\(.+\\)" arg)
-                      (setq namespace (match-string 1 arg)))
-                     ((string-match "--context=\\(.+\\)" arg)
-                      (setq context (match-string 1 arg)))
-                     ((string-match "--limit-bytes=\\(.+\\)" arg)
-                      (setq limit (string-to-number (match-string 1 arg))))
-                     ((string-match "--tail=\\(.+\\)" arg)
-                      (setq tail (string-to-number (match-string 1 arg))))
-                     ((string-match "--since-time=\\(.+\\)" arg)
-                      (setq since (match-string 1 arg)))
-                     ((equal "--all-containers" arg) (setq container t))
-                     ((equal "--follow" arg) (setq follow t))
-                     ((equal "--prefix" arg) (setq prefix t))
-                     ((equal "--timestamps" arg) (setq timestamps t))))
-                  (unless context
-                    (setq context
-                          (let ((cxt (kubed-local-context)))
-                            (if (equal current-prefix-arg '(16))
-                                (kubed-read-context "Context" cxt)
-                              cxt))))
-                  (unless namespace
-                    (setq namespace (kubed--namespace context current-prefix-arg)))
-                  (setq ,resource (,read-fun "Show logs for"
-                                             (and (equal context kubed-list-context)
-                                                  (equal namespace kubed-list-namespace)
-                                                  (equal ,(symbol-name plrl-var) kubed-list-type)
-                                                  (tabulated-list-get-id (mouse-set-point last-nonmenu-event)))
-                                             nil context namespace))
-                  (list ,resource context namespace
-                        ,(if (eq resource 'pod)
-                             '(or container
-                                  (kubed-read-container pod "Container" t
-                                                        context namespace))
-                           'container)
-                        follow limit prefix since tail timestamps)))
-               (kubed-logs ,(symbol-name plrl-var) ,resource context namespace container
-                           follow limit prefix since tail timestamps))))
-
-       ,@(let ((click-var (gensym "click")))
-           (mapcar
-            (pcase-lambda (`(,suffix ,_key ,desc . ,body))
-              `(defun ,(intern (format "kubed-%S-%S" plrl-var suffix)) (,click-var)
-                 ,(format "%s Kubernetes %S at point." desc resource)
-                 (interactive (list last-nonmenu-event) ,mod-name)
-                 (if-let ((,resource (tabulated-list-get-id (mouse-set-point ,click-var))))
-                     (progn ,@body)
-                   (user-error ,(format "No Kubernetes %S at point" resource)))))
-            commands))
-
-       (defvar-keymap ,(intern (format "kubed-%S-mode-map" plrl-var))
-         :doc ,(format "Keymap for `%S" mod-name)
-         "+" #',crt-name
-         ,@(when logs
-             `("l" #'kubed-list-logs
-               "L" #',logs-trs))
-         ,@(mapcan
-            (pcase-lambda (`(,suffix ,key ,_desc . ,_body))
-              (when key
-                (list key `#',(intern (format "kubed-%S-%S" plrl-var suffix)))))
-            commands))
-
-       (defvar ,frmt-var
-         ',(let ((i 0)
-                 (res nil))
-             (dolist (p properties)
-               (setq i (1+ i))
-               (push
-                (append
-                 (list (capitalize (symbol-name (car p)))
-                       (caddr p)
-                       (if-let ((sorter (cadddr p)))
-                           `(lambda (l r)
-                              (funcall ,sorter (aref (cadr l) ,i) (aref (cadr r) ,i)))
-                         t))
-                 (nthcdr 5 p))
-                res))
-             (reverse res)))
-
-       (defun ,ctxt-fun (menu . ,(if commands '(click) '(_click)))
-         ,@(when commands
-             `((when (tabulated-list-get-entry (posn-point (event-start click)))
-                 ,@(mapcar
-                    (pcase-lambda (`(,suffix ,_key ,desc . ,_body))
-                      `(define-key
-                        menu [,(intern (format "kubed-%S-%S" plrl-var suffix))]
-                        (list 'menu-item ,(format "%s this %S" desc resource)
-                              #',(intern (format "kubed-%S-%S" plrl-var suffix)))))
-                    (reverse commands)))))
-         menu)
-
-       (define-derived-mode ,mod-name kubed-list-mode
-         '(,(format "Kubernetes %s" (capitalize (symbol-name plrl-var)))
-           kubed-list-mode-line-format)
-         ,(format "Major mode for listing Kubernetes %S." plrl-var)
-         :interactive nil
-         (setq kubed-list-filter-history-variable
-               ',(intern (format "kubed-%S-filter-history" plrl-var))
-               kubed-list-type ,(symbol-name plrl-var)
-               ,@(when trs-cols
-                   `(kubed-list-transient-extra-suffixes ',trs-cols))
-               tabulated-list-padding 2
-               tabulated-list-format (apply #'vector (cons kubed-name-column ,frmt-var)))
-         (add-hook 'context-menu-functions #',ctxt-fun nil t)
-         (tabulated-list-init-header))
-
-       (defun ,buff-fun (context . ,(when namespaced '(namespace)))
-         (let ((buf-name (format ,(format "*Kubed %S%%s*" plrl-var)
-                                 ,(if namespaced
-                                      `(concat "@" namespace "[" context "]")
-                                    `(concat "[" context "]")))))
-           (if-let ((buf (get-buffer buf-name))) buf
-             (with-current-buffer (get-buffer-create buf-name)
-               (,mod-name)
-               (setq kubed-list-context context
-                     ,@(when namespaced
-                         '(kubed-list-namespace namespace)))
-               (kubed-list-update)
-               (tabulated-list-print)
-               (current-buffer)))))
-
-       (defun ,list-cmd (context . ,(when namespaced '(namespace)))
-         ,(if namespaced
-              (format "List Kubernetes %S in context CONTEXT and namespace NAMESPACE.
-
-Interactively, use the current context and namespace by default.  With a
-prefix argument \\[universal-argument], prompt for NAMESPACE.  With a
-double prefix argument \\[universal-argument] \\[universal-argument], \
-prompt for CONTEXT as well." plrl-var)
-            (format "List Kubernetes %S in context CONTEXT.
-
-Interactively, use the current context.  With a prefix argument
-\\[universal-argument], prompt for CONTEXT." plrl-var))
-         (interactive
-          (let* ((context (kubed-local-context))
-                 (context (if (equal current-prefix-arg
-                                     ,(if namespaced ''(16) ''(4)))
-                              (kubed-read-context "Context" context)
-                            context)))
-            (list context
-                  . ,(when namespaced '((kubed--namespace context current-prefix-arg))))))
-         (pop-to-buffer (,buff-fun context . ,(when namespaced '(namespace)))))
-
-       (defun ,expl-cmd ()
-         ,(format "Show help buffer with explanation about Kubernetes %S." plrl-var)
-         (interactive)
-         (kubed-explain ,(symbol-name plrl-var)))
-
-       (defvar-keymap ,map-name
-         :doc ,(format "Prefix keymap for Kubed %S commands." resource)
-         :prefix ',map-name
-         "l" #',list-cmd
-         "+" #',crt-name
-         "e" #',edt-name
-         "d" #',dlt-name
-         "RET" #',dsp-name
-         "E" #',expl-cmd
-         ,@(mapcan
-            (pcase-lambda (`(,key ,_label ,cmd))
-              (list key `#',cmd))
-            prf-keys))
-
-       (defvar-keymap ,menu-map
-         :doc ,(format "Keymap with Kubernetes %S related menu entries." resource)
-         :prefix ',menu-map
-         "<list>"    '("List"           . ,list-cmd)
-         "<create>"  '("Create"         . ,crt-name)
-         "<edit>"    '("Edit"           . ,edt-name)
-         "<delete>"  '("Delete"         . ,dlt-name)
-         "<display>" '("Display"        . ,dsp-name)
-         "<explain>" '("Explain Fields" . ,expl-cmd)
-         ,@(mapcan
-            (pcase-lambda (`(,key ,label ,cmd))
-              (list key `'(,label . ,cmd)))
-            prf-keys)))))
-
-(setf
- ;; Teach Imenu about `kubed-define-resource'.
- (alist-get "KubedResource" lisp-imenu-generic-expression nil nil #'equal)
- (list (concat "^\\s-*(kubed-define-resource\\s-+\\("
-               lisp-mode-symbol-regexp
-               "\\)")
-       1))
-
-(defun kubed-remote-file-name (context namespace pod &optional file-name)
-  "Return remote FILE-NAME for POD in NAMESPACE and CONTEXT."
-  (concat "/" kubed-tramp-method ":"
-          context "%" namespace "%" pod
-          "%" (kubed-read-container pod "Container" t context namespace)
-          ":" file-name))
-
-(declare-function kubed-tramp-context          "kubed-tramp" (file-name))
-(declare-function kubed-tramp-namespace        "kubed-tramp" (file-name))
-(declare-function kubed-tramp-assert-support   "kubed-tramp" ())
-
-;;;###autoload (autoload 'kubed-display-pod "kubed" nil t)
-;;;###autoload (autoload 'kubed-edit-pod "kubed" nil t)
-;;;###autoload (autoload 'kubed-delete-pods "kubed" nil t)
-;;;###autoload (autoload 'kubed-list-pods "kubed" nil t)
-;;;###autoload (autoload 'kubed-create-pod "kubed" nil t)
-;;;###autoload (autoload 'kubed-logs-for-pod "kubed" nil t)
-;;;###autoload (autoload 'kubed-pod-prefix-map "kubed" nil t 'keymap)
-(kubed-define-resource pod
-    ((phase ".status.phase" 10
-            nil                         ; sorting function
-            (lambda (ph)
-              (if-let ((face (pcase ph
-                               ;; TODO: Define/derive bespoke faces.
-                               ("Pending"   'warning)
-                               ("Running"   'success)
-                               ("Succeeded" 'shadow)
-                               ("Failed"    'error))))
-                  (propertize ph 'face face)
-                ph)))
-     (ready ".status.containerStatuses[?(.ready==true)].name" 6
-            (lambda (l r) (< (string-to-number l) (string-to-number r)))
-            (lambda (cs)
-              (if (string= cs "<none>") "0"
-                (number-to-string (1+ (seq-count (lambda (c) (= c ?,)) cs)))))
-            :right-align t)
-     (total ".status.containerStatuses[*].name" 6
-            (lambda (l r) (< (string-to-number l) (string-to-number r)))
-            (lambda (cs)
-              (if (string= cs "<none>") "0"
-                (number-to-string (1+ (seq-count (lambda (c) (= c ?,)) cs)))))
-            :right-align t)
-     (starttime ".status.startTime" 20))
-  :logs t
-  :prefix (("A" "Attach"       kubed-attach)
-           ("X" "Execute"      kubed-exec)
-           ("F" "Forward Port" kubed-forward-port-to-pod))
-  :suffixes ([ ("L" "Logs" kubed-transient-logs-for-pod)
-               ("X" "Exec" kubed-pods-exec)
-               ("a" "Attach" kubed-pods-attach)]
-             [ :pad-keys t
-               ("C-d" "Dired" kubed-pods-dired)
-               ("s" "Shell" kubed-pods-shell)
-               ("F" "Forward port" kubed-pods-forward-port)])
-  (dired "C-d" "Start Dired in"
-         (kubed-tramp-assert-support)
-         (dired (kubed-remote-file-name
-                 kubed-list-context kubed-list-namespace pod)))
-  (shell "s" "Start shell in"
-         (kubed-tramp-assert-support)
-         (let* ((default-directory (kubed-remote-file-name
-                                    kubed-list-context kubed-list-namespace pod)))
-           (shell
-            (concat "*Kubed Shell "
-                    (kubed-display-resource-short-description
-                     "pods" pod kubed-list-context kubed-list-namespace)
-                    "*"))))
-  (attach "a" "Attach to remote process running on"
-          (kubed-attach pod (kubed-read-container pod "Container" t
-                                                  kubed-list-context
-                                                  kubed-list-namespace)
-                        kubed-list-context kubed-list-namespace t t))
-  (exec "X" "Execute command in"
-        (let ((container (kubed-read-container pod "Container" t
-                                               kubed-list-context
-                                               kubed-list-namespace))
-              (cmd-args (split-string-and-unquote
-                         (read-string "Execute command: "))))
-          (kubed-exec pod (car cmd-args) container kubed-list-context
-                      kubed-list-namespace t t (cdr cmd-args))))
-  (forward-port "F" "Forward local network port to remote port of"
-                (let ((local-port (read-number "Forward local port: ")))
-                  (kubed-forward-port-to-pod
-                   pod local-port
-                   (read-number (format "Forward local port %d to remote port: "
-                                        local-port))
-                   kubed-list-context
-                   kubed-list-namespace))))
-
-;;;###autoload (autoload 'kubed-display-namespace "kubed" nil t)
-;;;###autoload (autoload 'kubed-edit-namespace "kubed" nil t)
-;;;###autoload (autoload 'kubed-delete-namespaces "kubed" nil t)
-;;;###autoload (autoload 'kubed-list-namespaces "kubed" nil t)
-;;;###autoload (autoload 'kubed-create-namespace "kubed" nil t)
-;;;###autoload (autoload 'kubed-namespace-prefix-map "kubed" nil t 'keymap)
-(kubed-define-resource namespace
-    ((phase ".status.phase" 10
-            nil                         ; sorting function
-            (lambda (ph)
-              (if-let ((face (pcase ph
-                               ;; TODO: Define/derive bespoke faces.
-                               ("Active"      'success)
-                               ("Terminating" 'shadow))))
-                  (propertize ph 'face face)
-                ph)))
-     (creationtimestamp ".metadata.creationTimestamp" 20))
-  :namespaced nil
-  :prefix (("S" "Set" kubed-set-namespace))
-  :create
-  ((name &optional context)
-   "Create Kubernetes namespace NAME in CONTEXT.
-
-Interactively, prompt for NAME and use the current context by default.
-With a prefix argument, prompt for CONTEXT instead."
-   (interactive
-    (let ((context nil))
-      (dolist (arg (kubed-transient-args 'kubed-transient-create))
-        (cond
-         ((string-match "--context=\\(.+\\)" arg)
-          (setq context (match-string 1 arg)))))
-      (unless context
-        (setq context
-              (let ((cxt (kubed-local-context)))
-                (if current-prefix-arg
-                    (kubed-read-context "Context" cxt)
-                  cxt))))
-      (list (read-string "Create namespace with name: ") context)))
-   (unless (zerop
-            (apply #'call-process
-                   kubed-kubectl-program nil nil nil
-                   "create" "namespace" name
-                   (when context (list "--context" context))))
-     (user-error "Failed to create Kubernetes namespace with name `%s'" name))
-   (kubed-update "namespaces" (or context (kubed-local-context)))
-   (message "Created Kubernetes namespace with name `%s'." name))
-  (set "s" "Set current namespace to"
-       (save-excursion
-         (goto-char (point-min))
-         (while (not (eobp))
-           (when (eq (char-after) ?*)
-             (tabulated-list-put-tag " "))
-           (forward-line)))
-       (kubed-set-namespace namespace kubed-list-context)
-       (tabulated-list-put-tag
-        (propertize "*" 'help-echo "Current namespace"))))
-
-;;;###autoload (autoload 'kubed-display-persistentvolume "kubed" nil t)
-;;;###autoload (autoload 'kubed-edit-persistentvolume "kubed" nil t)
-;;;###autoload (autoload 'kubed-delete-persistentvolumes "kubed" nil t)
-;;;###autoload (autoload 'kubed-list-persistentvolumes "kubed" nil t)
-;;;###autoload (autoload 'kubed-create-persistentvolume "kubed" nil t)
-;;;###autoload (autoload 'kubed-persistentvolume-prefix-map "kubed" nil t 'keymap)
-(kubed-define-resource persistentvolume () :namespaced nil)
-
-;;;###autoload (autoload 'kubed-display-service "kubed" nil t)
-;;;###autoload (autoload 'kubed-edit-service "kubed" nil t)
-;;;###autoload (autoload 'kubed-delete-services "kubed" nil t)
-;;;###autoload (autoload 'kubed-list-services "kubed" nil t)
-;;;###autoload (autoload 'kubed-create-service "kubed" nil t)
-;;;###autoload (autoload 'kubed-logs-for-service "kubed" nil t)
-;;;###autoload (autoload 'kubed-service-prefix-map "kubed" nil t 'keymap)
-(kubed-define-resource service
-    ((type ".spec.type" 12)
-     (clusterip ".spec.clusterIP" 16)
-     (externalip ".spec.externalIPs[*]" 16)
-     (ports ".spec.ports[*].port" 6)
-     (creationtimestamp ".metadata.creationTimestamp" 20))
-  :logs t)
-
-;;;###autoload (autoload 'kubed-display-secret "kubed" nil t)
-;;;###autoload (autoload 'kubed-edit-secret "kubed" nil t)
-;;;###autoload (autoload 'kubed-delete-secrets "kubed" nil t)
-;;;###autoload (autoload 'kubed-list-secrets "kubed" nil t)
-;;;###autoload (autoload 'kubed-create-secret "kubed" nil t)
-;;;###autoload (autoload 'kubed-secret-prefix-map "kubed" nil t 'keymap)
-(kubed-define-resource secret
-    ((type ".type" 32) (creationtimestamp ".metadata.creationTimestamp" 20)))
-
-(defun kubed-create-job-from-cronjob (name cronjob &optional context namespace)
-  "Create Kubernetes job with name NAME from cronjob CRONJOB.
-
-Optional argument CONTEXT is the `kubectl' context to use, defaulting to
-the current context; NAMESPACE is the namespace to use for the job,
-defaulting to the current namespace."
-  (interactive
-   (let ((name (read-string "Create job with name: "))
-         (context nil) (namespace nil))
-     (dolist (arg (kubed-transient-args 'kubed-transient-create-job))
-       (cond
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))
-        ((string-match "--namespace=\\(.+\\)" arg)
-         (setq namespace (match-string 1 arg)))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (unless namespace
-       (setq namespace (kubed--namespace context current-prefix-arg)))
-     (list name
-           (kubed-read-cronjob
-            (format "Create job `%s' from cronjob" name) nil nil context namespace)
-           context namespace)))
-  (let* ((context (or context (kubed-local-context)))
-         (namespace (or namespace (kubed--namespace context))))
-    (unless (zerop
-             (call-process
-              kubed-kubectl-program nil nil nil
-              "create" "job" name "--from" (concat "cronjob/" cronjob)
-              "-n" namespace "--context" context))
-      (user-error "Failed to create Kubernetes job `%s'" name))
-    (kubed-update "jobs" context namespace)
-    (message "Created Kubernetes job `%s'." name)))
-
-;;;###autoload (autoload 'kubed-display-job "kubed" nil t)
-;;;###autoload (autoload 'kubed-edit-job "kubed" nil t)
-;;;###autoload (autoload 'kubed-delete-jobs "kubed" nil t)
-;;;###autoload (autoload 'kubed-list-jobs "kubed" nil t)
-;;;###autoload (autoload 'kubed-create-job "kubed" nil t)
-;;;###autoload (autoload 'kubed-logs-for-job "kubed" nil t)
-;;;###autoload (autoload 'kubed-job-prefix-map "kubed" nil t 'keymap)
-(kubed-define-resource job
-    ((status ".status.conditions[0].type" 10) (starttime ".status.startTime" 20))
-  :prefix (("c" "Create from Cron" kubed-create-job-from-cronjob))
-  :logs t
-  :create
-  ((name image &optional context namespace command)
-   "Create Kubernetes job with name NAME executing COMMAND in IMAGE.
-
-Optional argument CONTEXT is the `kubectl' context to use, defaulting to
-the current context; NAMESPACE is the namespace to use for the job,
-defaulting to the current namespace."
-   (interactive
-    (let ((name (read-string "Create job with name: "))
-          (image nil) (context nil) (namespace nil) (command nil))
-      (dolist (arg (kubed-transient-args 'kubed-transient-create-job))
-        (cond
-         ((string-match "--image=\\(.+\\)" arg)
-          (setq image (match-string 1 arg)))
-         ((string-match "--context=\\(.+\\)" arg)
-          (setq context (match-string 1 arg)))
-         ((string-match "--namespace=\\(.+\\)" arg)
-          (setq namespace (match-string 1 arg)))
-         ((string-match "-- =\\(.+\\)" arg)
-          (setq command (split-string-and-unquote (match-string 1 arg))))))
-      (unless context
-        (setq context
-              (let ((cxt (kubed-local-context)))
-                (if (equal current-prefix-arg '(16))
-                    (kubed-read-context "Context" cxt)
-                  cxt))))
-      (unless namespace
-        (setq namespace (kubed--namespace context current-prefix-arg)))
-      (unless image
-        (setq image (kubed-read-container-image "Image to run in job")))
-      (list name image context namespace command)))
-   (unless (zerop
-            (apply #'call-process
-                   kubed-kubectl-program nil nil nil
-                   "create" "job" name "--image" image
-                   (append
-                    (when namespace (list "-n" namespace))
-                    (when context (list "--context" context))
-                    (when command (cons "--" command)))))
-     (user-error "Failed to create Kubernetes job `%s'" name))
-   (message "Created Kubernetes job `%s'." name)))
-
-;;;###autoload
-(defun kubed-watch-deployment-status (dep &optional context namespace cb)
-  "Show and update status of Kubernetes deployment DEP in a dedicate buffer.
-
-Optional argument CONTEXT is the `kubectl' context to use, defaulting to
-the current context; NAMESPACE is the namespace of DEP, defaulting to
-the current namespace.  CB is an optional callback function to call with
-no arguments when the deployment ends.
-
-Interactively, prompt for DEP.  With a prefix argument, prompt for
-NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT."
-  (interactive
-   (let (context namespace)
-     (dolist (arg (kubed-transient-args 'kubed-transient-rollout))
-       (cond
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))
-        ((string-match "--namespace=\\(.+\\)" arg)
-         (setq namespace (match-string 1 arg)))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (unless namespace
-       (setq namespace (kubed--namespace context current-prefix-arg)))
-     (list (kubed-read-deployment "Watch deployment status" nil nil
-                                  context namespace)
-           context namespace)))
-  (let* ((buf (get-buffer-create "*kubed-deployment-status*"))
-         (context (or context (kubed-local-context)))
-         (namespace (or namespace (kubed--namespace context))))
-    (with-current-buffer buf (erase-buffer))
-    (make-process
-     :name "*kubed-watch-deployment-status*"
-     :buffer buf
-     :command (list kubed-kubectl-program "rollout" "status"
-                    "deployment" dep "-n" namespace "--context" context)
-     :sentinel (when cb
-                 (lambda (_proc status)
-                   (when (member status '("finished\n"
-                                          "exited abnormally with code 1\n"))
-                     (funcall cb)))))
-    (display-buffer buf)))
-
-(defcustom kubed-restart-deployment-watch-status t
-  "Whether to pop up a progress buffer when restarting Kubernetes deployments."
-  :type 'boolean)
-
-;;;###autoload
-(defun kubed-scale-deployment (dep reps &optional context namespace)
-  "Scale deployment DEP in namespace NAMESPACE via CONTEXT to REPS replicas.
-
-Optional argument CONTEXT is the `kubectl' context to use, defaulting to
-the current context; NAMESPACE is the namespace of DEP, defaulting to
-the current namespace.
-
-Interactively, prompt for DEP.  With a prefix argument, prompt for
-NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT."
-  (interactive
-   (let (reps context namespace)
-     (dolist (arg (kubed-transient-args 'kubed-transient-rollout))
-       (cond
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))
-        ((string-match "--namespace=\\(.+\\)" arg)
-         (setq namespace (match-string 1 arg)))
-        ((string-match "--replicas=\\(.+\\)" arg)
-         (setq reps (string-to-number (match-string 1 arg))))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (unless namespace
-       (setq namespace (kubed--namespace context current-prefix-arg)))
-     (list (kubed-read-deployment "Scale deployment" nil nil context namespace)
-           (or reps (read-number "Number of replicas: ")) context namespace)))
-  (let* ((context (or context (kubed-local-context)))
-         (namespace (or namespace (kubed--namespace context))))
-    (unless (zerop
-             (apply #'call-process
-                    kubed-kubectl-program nil nil nil
-                    "scale" "deployment" dep
-                    "--replicas" (number-to-string reps)
-                    (append
-                     (when namespace (list "-n" namespace))
-                     (when context (list "--context" context)))))
-      (user-error "Failed to scale Kubernetes deployment `%s'" dep))
-    (message "Scaled Kubernetes deployment `%s' to %d replicas." dep reps)))
-
-;;;###autoload
-(defun kubed-restart-deployment (dep &optional context namespace)
-  "Restart Kubernetes deployment DEP in namespace NAMESPACE via CONTEXT.
-
-Optional argument CONTEXT is the `kubectl' context to use, defaulting to
-the current context; NAMESPACE is the namespace of DEP, defaulting to
-the current namespace.  CB is an optional callback function to call with
-no arguments when the deployment ends.
-
-Interactively, prompt for DEP.  With a prefix argument, prompt for
-NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT."
-  (interactive
-   (let (context namespace)
-     (dolist (arg (kubed-transient-args 'kubed-transient-rollout))
-       (cond
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))
-        ((string-match "--namespace=\\(.+\\)" arg)
-         (setq namespace (match-string 1 arg)))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (unless namespace
-       (setq namespace (kubed--namespace context current-prefix-arg)))
-     (list (kubed-read-deployment "Restart deployment" nil nil
-                                  context namespace)
-           context namespace)))
-  (let* ((context (or context (kubed-local-context)))
-         (namespace (or namespace (kubed--namespace context))))
-    (unless (zerop
-             (apply #'call-process
-                    kubed-kubectl-program nil nil nil
-                    "rollout" "restart" "deployment" dep
-                    (append
-                     (when namespace (list "-n" namespace))
-                     (when context (list "--context" context)))))
-      (user-error "Failed to restart Kubernetes deployment `%s'" dep))
-    (message "Restarting Kubernetes deployment `%s'." dep)
-    (when kubed-restart-deployment-watch-status
-      (kubed-watch-deployment-status
-       dep context namespace
-       (lambda ()
-         (kubed-update "deployments" context namespace))))))
-
-;;;###autoload (autoload 'kubed-display-deployment "kubed" nil t)
-;;;###autoload (autoload 'kubed-edit-deployment "kubed" nil t)
-;;;###autoload (autoload 'kubed-delete-deployments "kubed" nil t)
-;;;###autoload (autoload 'kubed-list-deployments "kubed" nil t)
-;;;###autoload (autoload 'kubed-create-deployment "kubed" nil t)
-;;;###autoload (autoload 'kubed-logs-for-deployment "kubed" nil t)
-;;;###autoload (autoload 'kubed-deployment-prefix-map "kubed" nil t 'keymap)
-(kubed-define-resource deployment
-    (( ready ".status.readyReplicas" 6
-       (lambda (l r) (< (string-to-number l) (string-to-number r)))
-       (lambda (s) (if (string= s "<none>") "0" s))
-       :right-align t)
-     ( updated ".status.updatedReplicas" 8
-       (lambda (l r) (< (string-to-number l) (string-to-number r)))
-       (lambda (s) (if (string= s "<none>") "0" s))
-       :right-align t)
-     ( available ".status.availableReplicas" 10
-       (lambda (l r) (< (string-to-number l) (string-to-number r)))
-       (lambda (s) (if (string= s "<none>") "0" s))
-       :right-align t)
-     ( reps ".status.replicas" 4
-       (lambda (l r) (< (string-to-number l) (string-to-number r)))
-       nil                              ; formatting function
-       :right-align t)
-     ( creationtimestamp ".metadata.creationTimestamp" 20))
-  :prefix (("R" "Restart" kubed-restart-deployment)
-           ("W" "Watch"   kubed-watch-deployment-status)
-           ("$" "Scale"   kubed-scale-deployment))
-  :logs t
-  :suffixes ([("L" "Logs" kubed-transient-logs-for-deployment)
-              ("W" "Watch" kubed-deployments-watch)
-              ("R" "Restart" kubed-deployments-restart)
-              ("$" "Scale" kubed-deployments-scale)])
-  :create
-  ((name images &optional context namespace replicas port command)
-   "Deploy IMAGES to Kubernetes in deployment with name NAME.
-
-Optional argument NAMESPACE is the namespace to use for the deployment,
-defaulting to the current namespace, REPLICAS in the number of replicas
-to create for each image, PORT is the port to expose, and COMMAND is an
-optional command to run in the images."
-   (interactive
-    (let ((name (read-string "Create deployment with name: "))
-          (images nil) (replicas nil) (port nil) (command nil)
-          (context nil) (namespace nil))
-      (dolist (arg (kubed-transient-args 'kubed-transient-create-deployment))
-        (cond
-         ((string-match "--replicas=\\(.+\\)" arg)
-          (setq replicas (string-to-number (match-string 1 arg))))
-         ((string-match "--image=\\(.+\\)" arg)
-          (push (match-string 1 arg) images))
-         ((string-match "--port=\\(.+\\)" arg)
-          (setq port (string-to-number (match-string 1 arg))))
-         ((string-match "--namespace=\\(.+\\)" arg)
-          (setq namespace (match-string 1 arg)))
-         ((string-match "--context=\\(.+\\)" arg)
-          (setq context (match-string 1 arg)))
-         ((string-match "-- =\\(.+\\)" arg)
-          (setq command (split-string-and-unquote (match-string 1 arg))))))
-      (unless images
-        (setq images (kubed-read-container-image "Images to deploy" nil t)))
-      (unless context
-        (setq context
-              (let ((cxt (kubed-local-context)))
-                (if (equal current-prefix-arg '(16))
-                    (kubed-read-context "Context" cxt)
-                  cxt))))
-      (unless namespace
-        (setq namespace (kubed--namespace context current-prefix-arg)))
-      (list name images context namespace replicas port command)))
-   (let* ((context (or context (kubed-local-context)))
-          (namespace (or namespace (kubed--namespace context))))
-     (unless (zerop
-              (apply #'call-process
-                     kubed-kubectl-program nil nil nil
-                     "create" "deployment" name
-                     (append
-                      (mapcar (lambda (image) (concat "--image=" image)) images)
-                      (when namespace (list (concat "--namespace=" namespace)))
-                      (when context (list (concat "--context=" context)))
-                      (when replicas (list (format "--replicas=%d" replicas)))
-                      (when port (list (format "--port=%d" port)))
-                      (when command (cons "--" command)))))
-       (user-error "Failed to create Kubernetes deployment `%s'" name))
-     (message "Created Kubernetes deployment `%s'." name)
-     (kubed-update "deployments" context namespace)))
-  (restart "R" "Restart"
-           (kubed-restart-deployment deployment kubed-list-context kubed-list-namespace)
-           (unless kubed-restart-deployment-watch-status
-             (message "Deployment restarting")
-             (kubed-list-update t)))
-  (watch "W" "Watch" (kubed-watch-deployment-status
-                      deployment kubed-list-context kubed-list-namespace))
-  (scale "$" "Scale" (kubed-scale-deployment
-                      deployment (if current-prefix-arg
-                                     (prefix-numeric-value current-prefix-arg)
-                                   (read-number "Number of replicas: "))
-                      kubed-list-context kubed-list-namespace)))
-
-;;;###autoload (autoload 'kubed-display-replicaset "kubed" nil t)
-;;;###autoload (autoload 'kubed-edit-replicaset "kubed" nil t)
-;;;###autoload (autoload 'kubed-delete-replicasets "kubed" nil t)
-;;;###autoload (autoload 'kubed-list-replicasets "kubed" nil t)
-;;;###autoload (autoload 'kubed-create-replicaset "kubed" nil t)
-;;;###autoload (autoload 'kubed-logs-for-replicaset "kubed" nil t)
-;;;###autoload (autoload 'kubed-replicaset-prefix-map "kubed" nil t 'keymap)
-(kubed-define-resource replicaset
-    ((reps ".status.replicas" 4
-           (lambda (l r) (< (string-to-number l) (string-to-number r)))
-           nil                          ; formatting function
-           :right-align t)
-     (ownerkind ".metadata.ownerReferences[0].kind" 12)
-     (ownername ".metadata.ownerReferences[0].name" 16)
-     (creationtimestamp ".metadata.creationTimestamp" 20))
-  :logs t)
-
-;;;###autoload (autoload 'kubed-display-statefulset "kubed" nil t)
-;;;###autoload (autoload 'kubed-edit-statefulset "kubed" nil t)
-;;;###autoload (autoload 'kubed-delete-statefulsets "kubed" nil t)
-;;;###autoload (autoload 'kubed-list-statefulsets "kubed" nil t)
-;;;###autoload (autoload 'kubed-create-statefulset "kubed" nil t)
-;;;###autoload (autoload 'kubed-logs-for-statefulset "kubed" nil t)
-;;;###autoload (autoload 'kubed-statefulset-prefix-map "kubed" nil t 'keymap)
-(kubed-define-resource statefulset
-    ((reps ".status.replicas" 4
-           (lambda (l r) (< (string-to-number l) (string-to-number r)))
-           nil                          ; formatting function
-           :right-align t)
-     (ownerkind ".metadata.ownerReferences[0].kind" 12)
-     (ownername ".metadata.ownerReferences[0].name" 16)
-     (creationtimestamp ".metadata.creationTimestamp" 20))
-  :logs t)
-
-(defun kubed-cronjob-suspended-p (cj &optional context ns)
-  "Return non-nil if cronjob CJ in CONTEXT and namespace NS is suspended."
-  (equal (car (apply #'process-lines
-                     kubed-kubectl-program
-                     "get" "cronjobs" cj
-                     "-o" "custom-columns=SUSPENDED:.spec.suspend" "--no-headers"
-                     (append
-                      (when ns (list "-n" ns))
-                      (when context (list "--context" context)))))
-         "true"))
-
-;;;###autoload (autoload 'kubed-display-cronjob "kubed" nil t)
-;;;###autoload (autoload 'kubed-edit-cronjob "kubed" nil t)
-;;;###autoload (autoload 'kubed-delete-cronjobs "kubed" nil t)
-;;;###autoload (autoload 'kubed-list-cronjobs "kubed" nil t)
-;;;###autoload (autoload 'kubed-create-cronjob "kubed" nil t)
-;;;###autoload (autoload 'kubed-cronjob-prefix-map "kubed" nil t 'keymap)
-(kubed-define-resource cronjob
-    ((schedule ".spec.schedule" 20)
-     (suspend ".spec.suspend" 20)
-     (lastschedule ".status.lastScheduleTime" 20)
-     (lastsuccess ".status.lastSuccessfulTime" 20)
-     (activejob ".status.active[0].name" 36))
-  :create
-  ((name image schedule &optional context namespace command)
-   "Schedule IMAGE to run in a cronjob with name NAME according to SCHEDULE.
-
-Optional argument NAMESPACE is the namespace to use for the cronjob,
-defaulting to the current namespace.  COMMAND is a list of strings that
-represent a program followed by its arguments, if it non-nil then it
-overrides the default command IMAGE runs."
-   (interactive
-    (let ((name (read-string "Create cronjob with name: "))
-          (image nil)
-          (schedule nil)
-          (command nil)
-          (context nil)
-          (namespace nil))
-      (dolist (arg (kubed-transient-args 'kubed-transient-create-cronjob))
-        (cond
-         ((string-match "--image=\\(.+\\)" arg)
-          (setq image (match-string 1 arg)))
-         ((string-match "--schedule=\\(.+\\)" arg)
-          (setq schedule (match-string 1 arg)))
-         ((string-match "--namespace=\\(.+\\)" arg)
-          (setq namespace (match-string 1 arg)))
-         ((string-match "--context=\\(.+\\)" arg)
-          (setq context (match-string 1 arg)))
-         ((string-match "-- =\\(.+\\)" arg)
-          (setq command (split-string-and-unquote (match-string 1 arg))))))
-      (unless context
-        (setq context
-              (let ((cxt (kubed-local-context)))
-                (if (equal current-prefix-arg '(16))
-                    (kubed-read-context "Context" cxt)
-                  cxt))))
-      (unless namespace
-        (setq namespace (kubed--namespace context current-prefix-arg)))
-      (unless image
-        (setq image (kubed-read-container-image "Image to run")))
-      (unless schedule
-        (setq schedule (read-string "Cron schedule: " "* * * * *")))
-      (list name image schedule context namespace command)))
-   (unless (zerop
-            (apply #'call-process
-                   kubed-kubectl-program nil nil nil
-                   "create" "cronjob" name
-                   "--image" image "--schedule" schedule
-                   (append
-                    (when context (list "--context" context))
-                    (when namespace (list "--namespace" namespace))
-                    (when command (cons "--" command)))))
-     (user-error "Failed to create Kubernetes cronjob `%s'" name))
-   (message "Created Kubernetes cronjob `%s'." name))
-  ;; Commands in *kubed-cronjobs* buffer.
-  ( toggle-suspension "T" "Toggle suspension of"
-    (kubed-patch "cronjobs" cronjob
-                 (format
-                  "{\"spec\": {\"suspend\": %s}}"
-                  (if (kubed-cronjob-suspended-p
-                       cronjob kubed-list-context kubed-list-namespace)
-                      "false" "true"))
-                 kubed-list-context kubed-list-namespace))
-  ( create-job "j" "Create job from"
-    (kubed-create-job-from-cronjob
-     (read-string "Create job with name: ") cronjob
-     kubed-list-context kubed-list-namespace)))
-
-;;;###autoload (autoload 'kubed-display-ingressclass "kubed" nil t)
-;;;###autoload (autoload 'kubed-edit-ingressclass "kubed" nil t)
-;;;###autoload (autoload 'kubed-delete-ingressclasses "kubed" nil t)
-;;;###autoload (autoload 'kubed-list-ingressclasss "kubed" nil t)
-;;;###autoload (autoload 'kubed-create-ingressclass "kubed" nil t)
-;;;###autoload (autoload 'kubed-ingressclass-prefix-map "kubed" nil t 'keymap)
-(kubed-define-resource ingressclass
-    ((controller ".spec.controller" 32)
-     (creationtimestamp ".metadata.creationTimestamp" 20))
-  :namespaced nil
-  :plural ingressclasses)
-
-;;;###autoload (autoload 'kubed-display-ingress "kubed" nil t)
-;;;###autoload (autoload 'kubed-edit-ingress "kubed" nil t)
-;;;###autoload (autoload 'kubed-delete-ingresses "kubed" nil t)
-;;;###autoload (autoload 'kubed-list-ingresss "kubed" nil t)
-;;;###autoload (autoload 'kubed-create-ingress "kubed" nil t)
-;;;###autoload (autoload 'kubed-ingress-prefix-map "kubed" nil t 'keymap)
-(kubed-define-resource ingress
-    ((class ".spec.ingressClassName" 8)
-     (creationtimestamp ".metadata.creationTimestamp" 20))
-  :plural ingresses
-  :create
-  ((name rules &optional context namespace class default-backend annotations)
-   "Create Kubernetes ingress with name NAME and rules RULES.
-
-Optional argument NAMESPACE is the namespace to use for the ingress,
-defaulting to the current namespace.  CLASS is the ingress class,
-ANNOTATIONS are a list of annotations for the created ingress, and
-DEFAULT-BACKEND is the service to use as a backend for unhandled URLs."
-   (interactive
-    (let ((name (read-string "Create ingress with name: "))
-          (rules nil)
-          (context nil)
-          (namespace nil)
-          (class nil)
-          (annotations nil)
-          (default-backend nil))
-      (dolist (arg (kubed-transient-args 'kubed-transient-create-ingress))
-        (cond
-         ((string-match "--rule=\\(.+\\)" arg)
-          (push (match-string 1 arg) rules))
-         ((string-match "--context=\\(.+\\)" arg)
-          (setq context (match-string 1 arg)))
-         ((string-match "--namespace=\\(.+\\)" arg)
-          (setq namespace (match-string 1 arg)))
-         ((string-match "--class=\\(.+\\)" arg)
-          (setq class (match-string 1 arg)))
-         ((string-match "--default-backend=\\(.+\\)" arg)
-          (setq default-backend (match-string 1 arg)))
-         ((string-match "--annotation=\\(.+\\)" arg)
-          (push (match-string 1 arg) annotations))))
-      (unless context
-        (setq context
-              (let ((cxt (kubed-local-context)))
-                (if (equal current-prefix-arg '(16))
-                    (kubed-read-context "Context" cxt)
-                  cxt))))
-      (unless namespace
-        (setq namespace (kubed--namespace context current-prefix-arg)))
-      (unless rules (setq rules (kubed-read-ingress-rules)))
-      (list name rules context namespace class default-backend annotations)))
-   (unless (zerop
-            (apply #'call-process
-                   kubed-kubectl-program nil nil nil
-                   "create" "ingress" name
-                   (append
-                    (mapcan (lambda (rule) (list "--rule" rule)) rules)
-                    (when namespace (list "--namespace" namespace))
-                    (when context (list "--context" context))
-                    (when class (list "--class" class))
-                    (when default-backend
-                      (list "--default-backend" default-backend))
-                    (mapcan (lambda (ann) (list "--annotation" ann))
-                            annotations))))
-     (user-error "Failed to create Kubernetes ingress `%s'" name))
-   (message "Created Kubernetes ingress `%s'." name)))
-
-;; TODO: Events may be numerous.  Need to only get a few.
-;; ;;;###autoload (autoload 'kubed-list-events "kubed" nil t)
-;; ;;;###autoload (autoload 'kubed-event-prefix-map "kubed" nil t 'keymap)
-;; (kubed-define-resource event
-;;     ((last ".lastTimestamp" 20)
-;;      (type ".type" 10)
-;;      (reason ".reason" 20)
-;;      (objectkind ".involvedObject.kind" 12)
-;;      (objectname ".involvedObject.name" 16)
-;;      (message ".message" 36)))
-
-(defun kubed-contexts ()
-  "Return list of Kubernetes contexts."
-  (process-lines kubed-kubectl-program "config" "get-contexts" "-o" "name"))
-
-(defun kubed-current-context ()
-  "Return current Kubernetes context."
-  (car (process-lines kubed-kubectl-program "config" "current-context")))
-
-(defun kubed-read-default-namespace-non-empty (context)
-  "Prompt for a default namespace for CONTEXT, refusing empty input."
-  (let ((ns (kubed-read-namespace
-             (format "Default namespace for context `%s'" context)
-             nil nil context)))
-    (when (string-empty-p ns)
-      (user-error "You didn't specify a default namespace"))
-    ns))
-
-(defun kubed-default-context-and-namespace ()
-  "Return default context and namespace as a cons cell (CONTEXT . NAMESPACE)."
-  (or kubed-default-context-and-namespace
-      (setq kubed-default-context-and-namespace
-            (let ((context (kubed-current-context)))
-              (cons context
-                    (or (kubed-current-namespace context)
-                        (kubed-read-default-namespace-non-empty context)))))))
-
-(defun kubed-default-context ()
-  "Return default `kubectl' context."
-  (car (kubed-default-context-and-namespace)))
-
-(defun kubed-default-namespace ()
-  "Return default Kubernetes namespace in the default context."
-  (cdr (kubed-default-context-and-namespace)))
-
-(defun kubed-remote-file-name-p (file-name)
-  "Check whether FILE-NAME is a Kubed Tramp remote file name."
-  ;; We use this function to heuristically check file names without
-  ;; loading `kubed-tramp' (which in turn loads `tramp').
-  (string-match-p "[/|]kubedv[0-9]+:" file-name))
-
-(defun kubed-local-context ()
-  "Return Kubernetes context local to the current buffer."
-  (or kubed-list-context
-      (nth 2 kubed-display-resource-info)
-      (and (kubed-remote-file-name-p default-directory)
-           (kubed-tramp-context default-directory))
-      (kubed-default-context)))
-
-(defvar kubed-context-history nil
-  "History list for `kubed-read-context'.")
-
-(defun kubed-read-context (prompt &optional default)
-  "Prompt with PROMPT for a Kubernetes context.
-
-Optional argument DEFAULT is the minibuffer default argument."
-  (completing-read (format-prompt prompt default)
-                   (kubed-contexts)
-                   nil 'confirm nil 'kubed-context-history default))
-
-;;;###autoload
-(defun kubed-use-context (context)
-  "Set current Kubernetes context to CONTEXT."
-  (interactive
-   (list (kubed-read-context "Use context" (kubed-local-context))))
-  (unless (zerop
-           (call-process
-            kubed-kubectl-program nil nil nil
-            "config" "use-context" context))
-    (user-error "Failed to use Kubernetes context `%s'" context))
-  (message "Now using Kubernetes context `%s'." context))
-
-;;;###autoload
-(defun kubed-rename-context (old new)
-  "Rename Kubernetes context OLD to NEW."
-  (interactive
-   (let ((old (kubed-read-context "Rename context" (kubed-local-context))))
-     (list old (read-string (format-prompt "Rename context to" old)
-                            nil 'kubed-context-history old))))
-  (unless (zerop
-           (call-process
-            kubed-kubectl-program nil nil nil
-            "config" "rename-context" old new))
-    (user-error "Failed to rename Kubernetes context `%s' to `%s'" old new))
-  (message "Renamed Kubernetes context `%s' to `%s'." old new))
-
-;;;###autoload
-(defun kubed-display-config ()
-  "Display current Kubernetes client settings in a YAML buffer."
-  (interactive)
-  (let* ((buf (get-buffer-create "*kubed-config*"))
-         (fun (lambda (&optional _ _)
-                (let ((inhibit-read-only t)
-                      (target (current-buffer)))
-                  (buffer-disable-undo)
-                  (with-temp-buffer
-                    (unless (zerop
-                             (call-process
-                              kubed-kubectl-program nil t nil "config" "view"))
-                      (error "`kubectl config view' failed"))
-                    (let ((source (current-buffer)))
-                      (with-current-buffer target
-                        (replace-buffer-contents source)
-                        (set-buffer-modified-p nil)
-                        (buffer-enable-undo))))))))
-    (with-current-buffer buf
-      (funcall fun)
-      (goto-char (point-min))
-      (run-hooks 'kubed-yaml-setup-hook)
-      (setq-local revert-buffer-function fun))
-    (display-buffer buf)))
-
-(defun kubed-current-namespace (&optional context)
-  "Return current Kubernetes namespace for context CONTEXT.
-
-If no namespace is configured for CONTEXT, return nil."
-  (or (car (process-lines
-            kubed-kubectl-program
-            "config" "view" "-o"
-            (format "jsonpath={.contexts[?(.name==\"%s\")].context.namespace}"
-                    (or context (kubed-current-context)))))))
-
-(defun kubed-local-namespace ()
-  "Return Kubernetes namespace in CONTEXT local to the current buffer."
-  (or kubed-list-namespace
-      (nth 3 kubed-display-resource-info)
-      (and (kubed-remote-file-name-p default-directory)
-           (kubed-tramp-namespace default-directory))
-      (kubed-default-namespace)))
-
-(defun kubed-local-context-and-namespace ()
-  "Return (CONTEXT . NAMESPACE) pair local to the current buffer."
-  (or (when-let ((context kubed-list-context))
-        (cons context
-              (or kubed-list-namespace
-                  (kubed-current-namespace context))))
-      (when-let ((context (nth 2 kubed-display-resource-info)))
-        (cons context
-              (or (nth 3 kubed-display-resource-info)
-                  (kubed-current-namespace context))))
-      (when-let ((context (and (kubed-remote-file-name-p default-directory)
-                               (kubed-tramp-context default-directory))))
-        (cons context (kubed-tramp-namespace default-directory)))
-      (kubed-default-context-and-namespace)))
-
-;;;###autoload
-(defun kubed-set-namespace (namespace &optional context)
-  "Set default Kubernetes namespace in CONTEXT to NAMESPACE.
-
-Interactively, prompt for NAMESPACE and use the current context.  With a
-prefix argument, prompt for CONTEXT as well."
-  (interactive
-   (let* ((context (kubed-local-context))
-          (context (if current-prefix-arg
-                       (kubed-read-context "Context" context)
-                     context)))
-     (list (kubed-read-namespace "Set namespace" (kubed--namespace context)
-                                 nil context)
-           context)))
-  (unless (zerop
-           (call-process
-            kubed-kubectl-program nil nil nil
-            "config" "set-context" (or context "--current")
-            "--namespace" namespace))
-    (user-error "Failed to set Kubernetes namespace to `%s'" namespace))
-  (message "Kubernetes namespace is now `%s'." namespace))
-
-(defcustom kubed-read-resource-definition-filter-files-by-kind t
-  "Whether to filter file completion candidates by their Kubernetes \"kind\".
-
-If this is non-nil, `kubed-read-resource-definition-file-name' only
-suggests files with the right \"kind\" as completion candidates when you
-call it with non-nil KIND argument.  This is useful because you get more
-relevant completions, but it may become slow in directories with many
-large JSON and YAML files, in which case you can set this option to nil."
-  :type 'boolean)
-
-(defun kubed-read-resource-definition-file-name (&optional kind)
-  "Prompt for Kubernetes resource definition file name.
-
-Optional argument KIND is the kind of resource the file should define.
-If `kubed-read-resource-definition-filter-files-by-kind' is non-nil,
-this function suggests only files that define resources of kind KIND as
-completion candidates."
-  (read-file-name
-   (format "%s definition file: " (or kind "Resource")) nil nil t nil
-   (if (and kind kubed-read-resource-definition-filter-files-by-kind
-            (executable-find "grep"))
-       (let ((cache (make-hash-table :test 'equal)))
-         (lambda (f)
-           (or (file-directory-p f)
-               (when-let ((ext (and (string-match "\\.[^.]*\\'" f)
-                                    (substring f (1+ (match-beginning 0))))))
-                 (or (and (member ext '("yaml" "yml"))
-                          (pcase (gethash (expand-file-name f) cache 'noval)
-                            ('noval
-                             (puthash (expand-file-name f)
-                                      (zerop (call-process
-                                              "grep" f nil nil "-i"
-                                              (format "^kind: %s$" kind)))
-                                      cache))
-                            (val val)))
-                     (and (equal ext "json")
-                          (pcase (gethash (expand-file-name f) cache 'noval)
-                            ('noval
-                             (puthash (expand-file-name f)
-                                      (zerop (call-process
-                                              "grep" f nil nil "-i"
-                                              (format "^kind: %s$" kind)))
-                                      cache))
-                            (val val))))))))
-     (lambda (f)
-       (or (file-directory-p f)
-           (when (string-match "\\.[^.]*\\'" f)
-             (member (substring f (1+ (match-beginning 0)))
-                     '("yaml" "yml" "json"))))))))
-
-;;;###autoload
-(defun kubed-apply (config &optional kind context)
-  "Apply CONFIG to Kubernetes resource of kind KIND via CONTEXT."
-  (interactive
-   (let ((config nil) (context nil))
-     (dolist (arg (kubed-transient-args 'kubed-transient-apply))
-       (cond
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))
-        ((string-match "--filename=\\(.+\\)" arg)
-         (setq config (match-string 1 arg)))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if current-prefix-arg
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (unless config
-       (setq config (kubed-read-resource-definition-file-name)))
-     (list config nil context)))
-  (let ((kind (or kind "resource"))
-        (context (or context (kubed-local-context))))
-    (message "Applying Kubernetes %s configuration `%s'..." kind config)
-    (call-process kubed-kubectl-program nil nil nil
-                  "apply" "-f" (expand-file-name config) "--context" context)
-    (message "Applying Kubernetes %s configuration `%s'... Done." kind config)))
-
-;;;###autoload
-(defun kubed-create (definition &optional kind context)
-  "Create resource of kind KIND with definition DEFINITION via CONTEXT."
-  (interactive
-   (let ((definition nil) (context nil))
-     (dolist (arg (kubed-transient-args 'kubed-transient-create))
-       (cond
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))
-        ((string-match "--filename=\\(.+\\)" arg)
-         (setq definition (match-string 1 arg)))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if current-prefix-arg
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (unless definition
-       (setq definition (kubed-read-resource-definition-file-name)))
-     (list definition nil context)))
-  (let ((kind (or kind "resource")))
-    (message "Creating Kubernetes %s with definition `%s'..." kind definition)
-    (message "Creating Kubernetes %s with definition `%s'... Done.  New %s name is `%s'."
-             kind definition kind
-             (car (apply #'process-lines kubed-kubectl-program
-                         "create" "-f" (expand-file-name definition)
-                         "-o" "jsonpath={.metadata.name}"
-                         (when context (list "--context" context)))))))
-
-;;;###autoload
-(defun kubed-run
-    ( pod image
-      &optional context namespace port attach stdin tty rm envs command args)
-  "Run container IMAGE in a new Kubernetes POD.
-
-Optional argument CONTEXT is the `kubectl' context to use, defaulting to
-the current context.  NAMESPACE is the namespace in which to create POD,
-defaulting to the current namespace.  PORT is the port to expose,
-defaulting to none.  If ATTACH is non-nil, then attach to the created
-image with a `comint-mode' buffer, and pop to that buffer.  Non-nil
-STDIN says to keep the standard input of the container open; non-nil TTY
-says to allocate a TTY for the container; and non-nil RM says to remove
-the container after it exits.  ENVS is a list of strings \"VAR=VAL\"
-which specify environment variables VAR and values VAL to give them in
-the created container.  ARGS are command line arguments for the
-container command.  If COMMAND is non-nil, ARGS consist of a complete
-command line, that overrides the container command instead of just
-providing it with arguments.
-
-Interactively, prompt for POD and IMAGE.  With a prefix argument, prompt
-for NAMESPACE; with a double prefix argument, also prompt for CONTEXT."
-  (interactive
-   (let ((pod nil) (image nil) (port nil) (context nil) (namespace nil)
-         (attach nil) (stdin nil) (tty nil) (rm nil) (envs nil)
-         (command nil) (args nil))
-     (dolist (arg (kubed-transient-args 'kubed-transient-run))
-       (cond
-        ((string-match "--image=\\(.+\\)" arg)
-         (setq image (match-string 1 arg)))
-        ((string-match "--port=\\(.+\\)" arg)
-         (setq port (string-to-number (match-string 1 arg))))
-        ((string-match "--namespace=\\(.+\\)" arg)
-         (setq namespace (match-string 1 arg)))
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))
-        ((equal "--attach" arg) (setq attach t))
-        ((equal "--stdin" arg) (setq stdin t))
-        ((equal "--tty" arg) (setq tty t))
-        ((equal "--rm" arg) (setq rm t))
-        ((equal "--command" arg) (setq command t))
-        ((string-match "--env=\\(.+\\)" arg)
-         (push (match-string 1 arg) envs))
-        ((string-match "-- =\\(.+\\)" arg)
-         (setq args (split-string-and-unquote (match-string 1 arg))))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (unless namespace
-       (setq namespace (kubed--namespace context current-prefix-arg)))
-     (setq pod (read-string "Run image in pod with name: "))
-     (unless image
-       (setq image (read-string "Image to run: " nil 'kubed-container-image-history)))
-     (list pod image context namespace port attach stdin tty rm envs command args)))
-  (if attach
-      (pop-to-buffer
-       (apply #'make-comint "kubed-run" kubed-kubectl-program nil
-              "run" pod (concat "--image=" image) "--attach"
-              (append
-               (mapcar (lambda (env) (concat "--env=" env))
-                       (cons "TERM=dumb" envs))
-               (when namespace (list (concat "--namespace=" namespace)))
-               (when stdin '("-i"))
-               (when tty '("-t"))
-               (when rm '("--rm"))
-               (when port (list (format "--port=%d" port)))
-               (when command '("--command"))
-               (when args (cons "--" args)))))
-    (unless (zerop
-             (apply #'call-process
-                    kubed-kubectl-program nil nil nil
-                    "run" pod (concat "--image=" image)
-                    (append
-                     (mapcar (lambda (env) (concat "--env=" env)) envs)
-                     (when namespace (list (concat "--namespace=" namespace)))
-                     (when context (list (concat "--context=" context)))
-                     (when stdin '("-i"))
-                     (cond
-                      (attach '("--attach"))
-                      (stdin  '("--attach=false")))
-                     (when tty '("-t"))
-                     (when rm '("--rm"))
-                     (when port (list (format "--port=%d" port)))
-                     (when command '("--command"))
-                     (when args (cons "--" args)))))
-      (user-error "Failed to run image `%s'" image))
-    (message "Image `%s' is now running in pod `%s'." image pod)))
-
-(defun kubed-pod-containers (pod &optional context namespace)
-  "Return list of containers in Kubernetes pod POD in NAMESPACE in CONTEXT."
-  (string-split
-   (car (apply #'process-lines
-               kubed-kubectl-program "get"
-               "pod" pod "-o" "jsonpath={.spec.containers[*].name}"
-               (append
-                (when namespace (list "--namespace" namespace))
-                (when context (list "--context" context)))))
-   " "))
-
-(defun kubed-pod-default-container (pod &optional context namespace)
-  "Return default container of Kubernetes pod POD in NAMESPACE in CONTEXT."
-  (car (apply #'process-lines
-              kubed-kubectl-program
-              "get" "pod" pod "-o"
-              "jsonpath={.metadata.annotations.kubectl\\.kubernetes\\.io/default-container}"
-              (append
-               (when namespace (list "--namespace" namespace))
-               (when context (list "--context" context))))))
-
-(defun kubed-read-container
-    (pod prompt &optional guess context namespace)
-  "Prompt with PROMPT for a container in POD and return its name.
-
-Non-nil optional argument GUESS says to try and guess which container to
-use without prompting: if the pod has a
-\"kubectl.kubernetes.id/default-container\" annotation, use the
-container that this annotation specifes; if there's just one container,
-use it; otherwise, fall back to prompting."
-  (let ((default (kubed-pod-default-container pod context namespace))
-        (all 'unset))
-    (or
-     ;; There's a default container, so that's our guess.
-     (and guess default)
-     ;; No default, but we're allowed to guess, so check if there's just
-     ;; one container, and if so that's our guess.
-     (and guess (setq all (kubed-pod-containers pod context namespace))
-          (null (cdr all))
-          (car all))
-     ;; No guessing, prompt.
-     (completing-read (format-prompt prompt default)
-                      (completion-table-dynamic
-                       (lambda (_)
-                         (if (eq all 'unset)
-                             (setq all (kubed-pod-containers pod context namespace))
-                           all)))
-                      nil t nil nil default))))
-
-;;;###autoload
-(defun kubed-logs
-    ( type resource &optional context namespace
-      container follow limit prefix since tail timestamps)
-  "Show logs for container CONTAINER in Kubernetes RESOURCE of type TYPE.
-
-Optional argument CONTEXT is the `kubectl' context to use; NAMESPACE is
-the namespace for RESOURCE; CONTAINER is the name of the container in
-RESOURCE to show logs for, or t which specifies all relevant containers.
-
-With a prefix argument, prompt for NAMESPACE; with a double prefix
-argument, also prompt for CONTEXT."
-  (interactive
-   (let ( type resource context namespace
-          container follow limit prefix since tail timestamps)
-     (dolist (arg (kubed-transient-args 'kubed-transient-logs))
-       (cond
-        ((string-match "--namespace=\\(.+\\)" arg)
-         (setq namespace (match-string 1 arg)))
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))
-        ((string-match "--limit-bytes=\\(.+\\)" arg)
-         (setq limit (string-to-number (match-string 1 arg))))
-        ((string-match "--tail=\\(.+\\)" arg)
-         (setq tail (string-to-number (match-string 1 arg))))
-        ((string-match "--since-time=\\(.+\\)" arg)
-         (setq since (match-string 1 arg)))
-        ((equal "--all-containers" arg) (setq container t))
-        ((equal "--follow" arg) (setq follow t))
-        ((equal "--prefix" arg) (setq prefix t))
-        ((equal "--timestamps" arg) (setq timestamps t))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (setq type (kubed-read-resource-type "Type of resource to display"
-                                          nil context))
-     (unless namespace
-       (setq namespace (kubed--namespace context current-prefix-arg)))
-     (setq resource (kubed-read-resource-name type "Show logs for" nil nil
-                                              context namespace))
-     (list type resource context namespace
-           (or container
-               (and (string= type "pods")
-                    (kubed-read-container resource "Container" t
-                                          context namespace)))
-           follow limit prefix since tail timestamps)))
-  (let* ((context (or context (kubed-local-context)))
-         (namespace (or namespace (kubed--namespace context)))
-         (buf (generate-new-buffer
-               (format "*kubed-logs %s/%s%s in %s[%s]*"
-                       type resource
-                       (cond
-                        ((stringp container) (concat "[" container "]"))
-                        (container "[all containers]")
-                        (t ""))
-                       namespace context))))
-    (with-current-buffer buf (run-hooks 'kubed-logs-setup-hook))
-    (apply #'start-process "*kubed-logs*" buf
-           kubed-kubectl-program "logs" (concat type "/" resource)
-           "--context" context "-n" namespace
-           (append
-            (cond
-             ((stringp container) (list "-c" container))
-             (container '("--all-containers")))
-            (when follow '("--follow"))
-            (when prefix '("--prefix"))
-            (when timestamps '("--timestamps"))
-            (when since (list "--since-time" since))
-            (when tail (list "--tail" (number-to-string tail)))
-            (when limit (list "--limit-bytes" (number-to-string limit)))))
-    (display-buffer buf)))
-
-(defvar kubed-port-forward-process-alist nil
-  "Alist of current port-forwarding descriptors and corresponding processes.")
-
-(defun kubed-port-forward-process-alist (&optional _ignored)
-  "Update and return value of variable `kubed-port-forward-process-alist'."
-  (setq kubed-port-forward-process-alist
-        (seq-filter (lambda (pair)
-                      (process-live-p (cdr pair)))
-                    kubed-port-forward-process-alist)))
-
-;;;###autoload
-(defun kubed-forward-port-to-pod
-    (pod local-port remote-port context namespace)
-  "Forward LOCAL-PORT to REMOTE-PORT of Kubernetes pod POD."
-  (interactive
-   (let* ((c (kubed-local-context))
-          (c (if (equal current-prefix-arg '(16))
-                 (kubed-read-context "Context" c)
-               c))
-          (n (kubed--namespace c current-prefix-arg))
-          (n (if current-prefix-arg
-                 (kubed-read-namespace "Namespace" n nil c)
-               n))
-          (p (kubed-read-pod "Forward port to pod" nil nil c n))
-          (l (read-number "Local port: "))
-          (r (read-number "Remote port: ")))
-     (list p l r c n)))
-  (message "Forwarding local port %d to remote port %d of pod `%s' in namespace `%s'..."
-           local-port remote-port pod namespace)
-  (push
-   (cons
-    (format "%s %d:%d in %s[%s]" pod local-port remote-port namespace context)
-    (apply #'start-process
-           "*kubed-port-forward*" nil
-           kubed-kubectl-program "port-forward"
-           pod (format "%d:%d" local-port remote-port)
-           (append
-            (when namespace (list "-n" namespace))
-            (when context (list "--context" context)))))
-   kubed-port-forward-process-alist))
-
-(defun kubed-stop-port-forward (descriptor)
-  "Stop Kubernetes port-forwarding with descriptor DESCRIPTOR.
-
-DESCRIPTOR is a string that says which port-forwarding process to stop,
-it has the format \"POD LOCAL-PORT:REMOTE-PORT in NAMESPACE[CONTEXT]\",
-where POD is the name of the pod that is the target of the
-port-forwarding, LOCAL-PORT is the local port that is being forwarded,
-REMOTE-PORT is the correspoding remote port of POD, NAMESPACE is the
-namespace of POD and CONTEXT is the `kubectl' context.
-
-Interactively, prompt for DESCRIPTOR with completion.  If there is only
-one port-forwarding process, stop that process without prompting."
-  (interactive
-   (list
-    (cond
-     ((cdr (kubed-port-forward-process-alist))
-      (completing-read "Stop port-forwarding: "
-                       (completion-table-dynamic
-                        #'kubed-port-forward-process-alist)
-                       nil t))
-     ((caar kubed-port-forward-process-alist))
-     (t (user-error "No port-forwarding to Kubernetes in progress")))))
-  (if-let ((pair (assoc descriptor kubed-port-forward-process-alist)))
-      (delete-process (cdr pair))
-    (error "No port-forwarding for %s" descriptor))
-  (message "Stopped port-forwarding for %s" descriptor))
-
-(defvar kubed-container-image-history nil
-  "Minibuffer history for `kubed-read-container-image'.")
-
-(defun kubed-read-container-image (prompt &optional default multi)
-  "Prompt with PROMPT for names of container images.
-
-Optional argument DEFAULT is the minibuffer default argument.  Non-nil
-optional argument MULTI says to read multiple image names and return
-them as list."
-  (funcall (if multi #'completing-read-multiple #'completing-read)
-           (format-prompt prompt default) nil nil nil nil
-           'kubed-container-images-history default))
-
-(defvar kubed-ingress-rule-history nil
-  "Minibuffer history for `kubed-read-ingress-rules'.")
-
-(defun kubed-read-ingress-rules ()
-  "Prompt with PROMPT for Kubernetes ingress rules."
-  (let ((rules (list (read-string "Ingress rule: "
-                                  nil 'kubed-ingress-rule-history))))
-    (while (not
-            (string-empty-p
-             (car (push (read-string (format-prompt "Additional rules" "done")
-                                     nil 'kubed-ingress-rule-history)
-                        rules)))))
-    (nreverse (cdr rules))))
-
-(defvar transient-current-command)
-
-(defun kubed-transient-args (&optional prefix)
-  "Return current arguments from transient PREFIX.
-
-If PREFIX nil, it defaults to the value of `transient-current-command'."
-  (when-let ((prefix (or prefix (bound-and-true-p transient-current-command))))
-    (and (featurep 'kubed-transient)
-         (fboundp 'transient-args)
-         (transient-args prefix))))
-
-;;;###autoload
-(defun kubed-attach (pod &optional container context namespace stdin tty)
-  "Attach to running process in CONTAINER in Kubernetes POD.
-
-Optional argument NAMESPACE is the namespace in which to look for POD.
-Non-nil STDIN says to connect local standard input to remote process.
-Non-nil TTY says to use a TTY for standard input.
-
-Interactively, prompt for POD; if there are multiple pod containers,
-prompt for CONTAINER as well.  With a prefix argument, prompt for
-NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
-STDIN and TTY are t interactively."
-  (interactive
-   (let ((context nil) (namespace nil) (stdin t) (tty t))
-     (dolist (arg (kubed-transient-args 'kubed-transient-attach))
-       (cond
-        ((string-match "--namespace=\\(.+\\)" arg)
-         (setq namespace (match-string 1 arg)))
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))
-        ((equal "--stdin" arg) (setq stdin t))
-        ((equal "--tty" arg) (setq tty t))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (unless namespace
-       (setq namespace (kubed--namespace context current-prefix-arg)))
-     (let* ((p (kubed-read-pod "Exec on pod" nil nil context namespace))
-            (c (kubed-read-container p "Container" t context namespace)))
-       (list p c context namespace stdin tty))))
-  (pop-to-buffer
-   (apply #'make-comint "kubed-attach" kubed-kubectl-program nil
-          "attach" pod
-          (append
-           (when namespace (list "-n" namespace))
-           (when context (list "--context" context))
-           (when container (list "-c" container))
-           (when stdin '("-i"))
-           (when tty   '("-t"))))))
-
-;;;###autoload
-(defun kubed-diff (definition &optional include-managed context)
-  "Display difference between Kubernetes resource DEFINITION and current state.
-
-DEFINITION is either a file name or a buffer.  Interactively, prompt for
-a YAML or JSON file name to use as DEFINITION.
-
-Optional argument CONTEXT is the `kubectl' context to use, defaulting to
-the current context; non-nil INCLUDE-MANAGED (interactively, the prefix
-argument) says to include managed fields in the comparison."
-  (interactive
-   (let ((definition nil) (context nil) (include-managed nil))
-     (dolist (arg (kubed-transient-args 'kubed-transient-diff))
-       (cond
-        ((string-match "--filename=\\(.+\\)" arg)
-         (setq definition (match-string 1 arg)))
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))
-        ((equal "--show-managed-fields" arg) (setq include-managed t))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (list (or definition (kubed-read-resource-definition-file-name))
-           (or include-managed current-prefix-arg)
-           context)))
-  (let ((buf (get-buffer-create "*kubed-diff*"))
-        (args (cons "diff"
-                    (append
-                     (when context (list "--context" context))
-                     (when include-managed
-                       (list "--show-managed-fields" "true"))
-                     (list "-f" (if (bufferp definition) "-"
-                                  (expand-file-name definition)))))))
-    (with-current-buffer buf
-      (setq buffer-read-only nil)
-      (delete-region (point-min) (point-max))
-      (fundamental-mode)
-      (if (bufferp definition)
-          (with-current-buffer definition
-            (apply #'call-process-region nil nil kubed-kubectl-program
-                   nil buf nil args))
-        (apply #'call-process kubed-kubectl-program
-               nil t nil args))
-      (setq buffer-read-only t)
-      (diff-mode)
-      (goto-char (point-min)))
-    (display-buffer buf)))
-
-;;;###autoload
-(defun kubed-exec
-    (pod command &optional container context namespace stdin tty args)
-  "Execute COMMAND with ARGS in CONTAINER in Kubernetes POD.
-
-Optional argument NAMESPACE is the namespace in which to look for POD.
-Non-nil STDIN says to connect local standard input to remote process.
-Non-nil TTY says to use a TTY for standard input.
-
-Interactively, prompt for POD; if there are multiple pod containers,
-prompt for CONTAINER as well.  With a prefix argument, prompt for
-NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
-STDIN and TTY are t interactively."
-  (interactive
-   (let ((context nil) (namespace nil) (stdin t) (tty t) (command nil) (args nil))
-     (dolist (arg (kubed-transient-args 'kubed-transient-exec))
-       (cond
-        ((string-match "--namespace=\\(.+\\)" arg)
-         (setq namespace (match-string 1 arg)))
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))
-        ((equal "--stdin" arg) (setq stdin t))
-        ((equal "--tty" arg) (setq tty t))
-        ((string-match "-- =\\(.+\\)" arg)
-         (setq args    (split-string-and-unquote (match-string 1 arg))
-               command (car args)
-               args    (cdr args)))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (unless namespace
-       (setq namespace (kubed--namespace context current-prefix-arg)))
-     (unless command
-       (setq args    (split-string-and-unquote
-                      (read-string "Execute command: "))
-             command (car args)
-             args    (cdr args)))
-     (let* ((p (kubed-read-pod "Exec on pod" nil nil context namespace))
-            (c (kubed-read-container p "Container" t context namespace)))
-       (list p command c context namespace stdin tty args))))
-  (pop-to-buffer
-   (apply #'make-comint "kubed-exec" kubed-kubectl-program nil
-          "exec" pod
-          (append
-           (when namespace (list "-n" namespace))
-           (when context (list "--context" context))
-           (when container (list "-c" container))
-           (when stdin '("-i"))
-           (when tty '("-t"))
-           (list "--" command)
-           args))))
-
-(defvar kubed-patch-history nil
-  "Minibuffer history for `kubed-read-patch'.")
-
-(defun kubed-read-patch ()
-  "Prompt for a Kubernetes resource patch in JSON or YAML format."
-  (read-string "Patch (JSON or YAML): " nil 'kubed-patch-history))
-
-;;;###autoload
-(defun kubed-patch (type name patch &optional context namespace strategy)
-  "Patch Kubernetes resource NAME of TYPE with patch PATCH.
-
-Optional argument NAMESPACE is the namespace in which to look for NAME.
-STRATEGY is the patch type to use, one of \"json\", \"merge\" and
-\"strategic\", defaulting to \"strategic\".
-
-Interactively, prompt for TYPE, NAME and PATCH.  With a prefix argument,
-prompt for NAMESPACE too.  With a double prefix argument, also prompt
-for CONTEXT."
-  (interactive
-   (let ((type nil) (context nil) (namespace nil) (strategy nil))
-     (dolist (arg (kubed-transient-args 'kubed-transient-patch))
-       (cond
-        ((string-match "--namespace=\\(.+\\)" arg)
-         (setq namespace (match-string 1 arg)))
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))
-        ((string-match "--type=\\(.+\\)" arg)
-         (setq strategy (match-string 1 arg)))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (unless namespace
-       (setq namespace (kubed--namespace context current-prefix-arg)))
-     (list (kubed-read-resource-type "Resource type to patch" nil context)
-           (kubed-read-resource-name type "Resource to patch" nil nil context namespace)
-           (kubed-read-patch) context namespace strategy)))
-  (message "Applying patch to `%s'..." name)
-  (unless (zerop
-           (apply #'call-process
-                  kubed-kubectl-program nil nil nil
-                  "patch" type name "-p" patch
-                  (append
-                   (when namespace (list "-n" namespace))
-                   (when context (list "--context" context))
-                   (when strategy (list "--type" strategy)))))
-    (user-error "Patching `%s' failed" name))
-  (message "Applying patch to `%s'...  Done." name))
-
-(defvar kubed--proxy-alist nil
-  "Alist associating `kubectl' context names and their proxy processes.")
-
-;;;###autoload
-(defun kubed-proxy
-    (&optional addr port api-prefix www-dir www-prefix context)
-  "Start a web server on localhost proxying the Kubernetes API server.
-
-ADDR and PORT are the local address and port to bind the proxy server
-to.  They default to 127.0.0.1 and 8001, respectively.  API-PREFIX is a
-prefix under which to proxy the Kubernetes API.  WWW-DIR is a local
-directory to serve under WWW-PREFIX, which defaults to \"/static/\".
-Lastly, CONTEXT is the the `kubectl' context to use, defaulting to the
-local context."
-  (interactive
-   (let ((addr nil) (port nil)
-         (api-prefix nil) (www-dir nil) (www-prefix nil)
-         (context nil))
-     (dolist (arg (kubed-transient-args 'kubed-transient-proxy))
-       (cond
-        ((string-match "--address=\\(.+\\)" arg)
-         (setq addr (match-string 1 arg)))
-        ((string-match "--port=\\(.+\\)" arg)
-         (setq port (string-to-number (match-string 1 arg))))
-        ((string-match "--api-prefix=\\(.+\\)" arg)
-         (setq api-prefix (match-string 1 arg)))
-        ((string-match "--www-dir=\\(.+\\)" arg)
-         (setq www-dir (match-string 1 arg)))
-        ((string-match "--www-prefix=\\(.+\\)" arg)
-         (setq www-prefix (match-string 1 arg)))
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (list addr port api-prefix www-dir www-prefix context)))
-  (let ((context (or context (kubed-local-context))))
-    (when-let ((proc (alist-get context kubed--proxy-alist
-                                nil nil #'string=))
-               ((process-live-p proc)))
-      (if (y-or-n-p (concat "Proxy already running for context `" context
-                            "'.  Stop it and start new proxy?"))
-          (kill-process proc)
-        (user-error "Proxy already running for context `%s'" context))
-      (message "Stopped proxy for context `%s'." context))
-    (setf (alist-get context kubed--proxy-alist nil nil #'string=)
-          (apply #'start-process (format "*kubed-proxy[%s]*" context) nil
-                 kubed-kubectl-program "proxy"
-                 "--context" context
-                 (append
-                  (when addr (list "--address" addr))
-                  (when port (list "--port" (number-to-string port)))
-                  (when api-prefix (list "--api-prefix" api-prefix))
-                  (when www-dir (list "--www-dir" www-dir))
-                  (when www-prefix (list "--www-prefix" www-prefix)))))
-    (message "Started proxy for context `%s'." context)))
-
-;;;###autoload
-(defun kubed-stop-proxy (&optional context)
-  "Stop local proxy for context CONTEXT, defaulting to the local context."
-  (interactive
-   (let ((context nil))
-     (dolist (arg (kubed-transient-args 'kubed-transient-proxy))
-       (cond
-        ((string-match "--context=\\(.+\\)" arg)
-         (setq context (match-string 1 arg)))))
-     (unless context
-       (setq context
-             (let ((cxt (kubed-local-context)))
-               (if (equal current-prefix-arg '(16))
-                   (kubed-read-context "Context" cxt)
-                 cxt))))
-     (list context)))
-  (let ((context (or context (kubed-local-context))))
-    (if-let ((proc (alist-get context kubed--proxy-alist
-                              nil nil #'string=))
-             ((process-live-p proc)))
-        (kill-process proc)
-      (user-error "No proxy running for context `%s'" context))
-    (message "Stopped proxy for context `%s'." context)))
-
-(with-eval-after-load 'help-mode
-  ;; Wait for `help-mode' to define `help-xref'.  It's always loaded by
-  ;; the time we actually need it in `kubed-explain'.
-  (define-button-type 'kubed-explain
-    :supertype 'help-xref
-    'help-function 'kubed-explain
-    'help-echo "mouse-2, RET: explain"))
-
-(defvar kubed-resource-field-history nil
-  "Minibuffer history for `kubed-read-resource-field'.")
-
-(defun kubed-api-resources (&optional context only-namespaced)
-  "Return list of resource types in the context CONTEXT.
-
-Non-nil optional argument ONLY-NAMESPACED says to return only namespaced
-resource types."
-  (mapcar
-   (lambda (line)
-     (car (split-string line)))
-   (apply #'process-lines
-          kubed-kubectl-program
-          "api-resources" "--no-headers"
-          (append
-           (when only-namespaced '("--namespaced=true"))
-           (when context (list (concat "--context=" context)))))))
-
-(defun kubed-resource-names (type context &optional namespace)
-  "Return list of Kubernetes resources of type TYPE in NAMESPACE via CONTEXT."
-  (unless (kubed--alist type context namespace)
-    (let ((proc (kubed-update type context namespace)))
-      (while (process-live-p proc)
-        (accept-process-output proc 1))))
-  (mapcar #'car (alist-get 'resources (kubed--alist type context namespace))))
-
-(defun kubed-read-resource-name (type prompt &optional default multi context namespace)
-  "Prompt with PROMPT for Kubernetes resource name of type TYPE.
-
-Optional argument DEFAULT is the minibuffer default argument; non-nil
-MULTI says to read multiple names and return them as a list; CONTEXT is
-the `kubectl' context to use, defaulting to the local context; and
-NAMESPACE is the namespace to use, or nil if TYPE is non-namespaced."
-  (funcall
-   (if multi #'completing-read-multiple #'completing-read)
-   (format-prompt prompt default)
-   (let ((table 'unset))
-     (lambda (s p a)
-       (if (eq a 'metadata)
-           `(metadata (category . ,(intern (concat "kubernetes-" type))))
-         (when (eq table 'unset)
-           (setq table (kubed-resource-names
-                        type (or context (kubed-local-context)) namespace)))
-         (complete-with-action a table s p))))
-   nil 'confirm nil (intern (concat "kubed-" type "-history")) default))
-
-(defun kubed-read-resource-type (prompt &optional default context)
-  "Prompt with PROMPT for Kubernetes resource type in context CONTEXT.
-
-Optional argument DEFAULT is the minibuffer default argument."
-  (completing-read
-   (format-prompt prompt default)
-   (kubed-api-resources context)
-   nil 'confirm nil nil default))
-
-(defun kubed-read-resource-field (prompt &optional default context)
-  "Prompt with PROMPT for Kubernetes resource type or field name.
-
-Optional argument DEFAULT is the minibuffer default argument, and
-CONTEXT is the `kubectl' context to use."
-  (completing-read
-   (format-prompt prompt default)
-   (lambda (s p a)
-     (unless (eq a 'metadata)
-       (let ((start 0))
-         (while (string-match "\\." s start)
-           (setq start (match-end 0)))
-         (if (eq (car-safe a) 'boundaries)
-             `(boundaries ,start . ,(and (string-match "\\." (cdr a))
-                                         (match-beginning 0)))
-           (let ((table
-                  (if (zerop start)
-                      ;; Complete resource type.
-                      (kubed-api-resources context)
-                    ;; Complete (sub-)field name.
-                    (with-temp-buffer
-                      (call-process
-                       kubed-kubectl-program nil t nil
-                       "explain" (substring s 0 start))
-                      (goto-char (point-min))
-                      (let ((res nil))
-                        (while (re-search-forward
-                                (rx line-start (+ " ") (group-n 1 (* alnum)) "\t")
-                                nil t)
-                          (push (match-string 1) res))
-                        res)))))
-             (if a (complete-with-action a table (substring s start) p)
-               ;; `try-completion'.
-               (let ((comp (complete-with-action a table (substring s start) p)))
-                 (if (stringp comp) (concat (substring s 0 start) comp) comp))))))))
-   nil 'confirm nil 'kubed-resource-field-history default))
-
-;;;###autoload
-(defun kubed-explain (field)
-  "Show help buffer with explanation about Kubernetes resource FIELD."
-  (interactive
-   (list (kubed-read-resource-field "Explain type or field")))
-  (let ((help-buffer-under-preparation t))
-    (help-setup-xref (list #'kubed-explain field)
-                     (called-interactively-p 'interactive))
-    (with-help-window (help-buffer)
-      (with-current-buffer (help-buffer)
-        (insert (substitute-quotes
-                 (concat "`kubed explain " field "' says:\n\n")))
-        (save-excursion
-          ;; Add button that goes to parent.
-          (goto-char (point-min))
-          (when (re-search-forward (rx " "
-                                       (group-n 1 (* graph))
-                                       "."
-                                       (+ (not (any ?.)))
-                                       line-end)
-                                   nil t)
-            (help-xref-button 1 'kubed-explain (match-string 1))))
-
-        (call-process kubed-kubectl-program nil t nil "explain" field)
-        ;; Buttonize references to other fields.
-        (goto-char (point-min))
-        (while (re-search-forward (rx line-start
-                                      (+ " ")
-                                      (group-n 1 (* alnum))
-                                      "\t")
-                                  nil t)
-          (help-xref-button 1 'kubed-explain
-                            (concat field "." (match-string 1))))))))
-
-(defvar kubed-kubectl-command-history nil
-  "Minibuffer history for `kubed-kubectl-command'.")
-
-(declare-function cobra-read-command-line "cobra"
-                  (prompt initial &optional hist))
-
-(defun kubed-read-kubectl-command (prompt &optional initial)
-  "Prompt with PROMPT for a `kubectl' command line.
-
-Optional argument INITIAL added to the initial minibuffer input
-following the value of `kubed-kubectl-program' and a space character."
-  (let ((init (if (consp initial)
-                  (cons    (concat kubed-kubectl-program " " (car initial))
-                        (+ (length kubed-kubectl-program) 1  (cdr initial)))
-                (concat kubed-kubectl-program " " initial))))
-    (cobra-read-command-line prompt init 'kubed-kubectl-command-history)))
-
-;;;###autoload
-(defun kubed-kubectl-command (command)
-  "Execute `kubectl' COMMAND.
-
-This function calls `shell-command' (which see) to do the work.
-
-Interactively, prompt for COMMAND with completion for `kubectl' arguments."
-  (interactive
-   (list (kubed-read-kubectl-command
-          "Command: "
-          (let* ((args (kubed-transient-args))
-                 (prefix (and (fboundp 'transient-prefix-object)
-                              (transient-prefix-object)))
-                 (scope (and prefix (fboundp 'eieio-oref)
-                             (eieio-oref prefix 'scope))))
-            (when (or args scope)
-              (concat (string-join (append scope args) " ") " "))))))
-  (shell-command command))
-
-;;;###autoload (autoload 'kubed-prefix-map "kubed" nil t 'keymap)
-(defvar-keymap kubed-prefix-map
-  :doc "Prefix keymap for Kubed commands."
-  :prefix 'kubed-prefix-map
-  "p" 'kubed-pod-prefix-map
-  "N" 'kubed-namespace-prefix-map
-  "s" 'kubed-service-prefix-map
-  "S" 'kubed-secret-prefix-map
-  "j" 'kubed-job-prefix-map
-  "d" 'kubed-deployment-prefix-map
-  "i" 'kubed-ingress-prefix-map
-  "c" 'kubed-cronjob-prefix-map
-  "C" #'kubed-use-context
-  "+" #'kubed-create
-  "*" #'kubed-apply
-  "R" #'kubed-run
-  "=" #'kubed-diff
-  "E" #'kubed-explain
-  "P" #'kubed-patch
-  ":" #'kubed-proxy
-  "RET" #'kubed-display-resource
-  "!" #'kubed-kubectl-command)
-
-(defvar-keymap kubed-menu-map
-  :doc "Keymap with Kubed menu entries."
-  :prefix 'kubed-menu-map
-  "<namespace>"        '("Namespaces..."         . kubed-namespace-menu-map)
-  "<pod>"              '("Pods..."               . kubed-pod-menu-map)
-  "<persistentvolume>" '("Persistent Volumes..." . kubed-persistentvolume-menu-map)
-  "<service>"          '("Services..."           . kubed-service-menu-map)
-  "<secret>"           '("Secrets..."            . kubed-secret-menu-map)
-  "<job>"              '("Jobs..."               . kubed-job-menu-map)
-  "<deployment>"       '("Deployments..."        . kubed-deployment-menu-map)
-  "<replicaset>"       '("Replica Sets..."       . kubed-replicaset-menu-map)
-  "<statefulset>"      '("Stateful Sets..."      . kubed-statefulset-menu-map)
-  "<cronjob>"          '("Cron Jobs..."          . kubed-cronjob-menu-map)
-  "<ingressclass>"     '("Ingress Classes..."    . kubed-ingressclass-menu-map)
-  "<ingress>"          '("Ingresses..."          . kubed-ingress-menu-map)
-  "<proxy>"            '("Proxy Kubernetes API"  . kubed-proxy)
-  "<patch>"            '("Patch Resource"        . kubed-patch)
-  "<diff>"             '("Diff Config with Live" . kubed-diff)
-  "<kubectl-command>"  '("Invoke kubectl"        . kubed-kubectl-command)
-  "<explain>"          '("Explain Type or Field" . kubed-explain)
-  "<use-context>"      '("Set Current Context"   . kubed-use-context)
-  "<run>"              '("Run Image"             . kubed-run)
-  "<apply>"            '("Apply Config"          . kubed-apply)
-  "<create>"           '("Create Resource"       . kubed-create)
-  "<display>"          '("Display Resource"      . kubed-display-resource))
-
-;;;###autoload
-(define-minor-mode kubed-menu-bar-mode
-  "Add \"Kubernetes\" menu to your menu bar."
-  :global t
-  (if kubed-menu-bar-mode
-      (keymap-set-after (current-global-map)
-        "<menu-bar> <kubed>" '("Kubernetes" . kubed-menu-map))
-    (keymap-global-unset "<menu-bar> <kubed>")))
-
-(defvar reporter-prompt-for-summary-p)
-
-(defun kubed-submit-bug-report ()
-  "Report a Kubed issue to the maintainers via email."
-  (interactive)
-  (require 'reporter)
-  (let ((reporter-prompt-for-summary-p t))
-    (reporter-submit-bug-report
-     "Kubed Development <~eshel/kubed-develNOSPAMlists.sr.ht>"
-     (format "Kubed")
-     '(kubed-kubectl-program)
-     nil nil
-     (propertize " "
-                 'display
-                 (propertize
-                  "Insert your bug report below.
-If possible, specify where you got Emacs, kubectl and Kubed,
-and include a recipe for reproducing your issue.
-[This line and the above text are not included in your report.]"
-                  'face 'italic)))))
-
-(provide 'kubed)
-;;; kubed.el ends here
diff --git a/elpa/kubed-0.4.3/kubed.info b/elpa/kubed-0.4.3/kubed.info
deleted file mode 100644 (file)
index 48b0582..0000000
+++ /dev/null
@@ -1,754 +0,0 @@
-This is docHlL4Z1.info, produced by makeinfo version 6.8 from
-kubed.texi.
-
-This manual is for Kubed 0.4.3, a rich Emacs interface for Kubernetes.
-
-   Copyright © 2024-2025 Eshel Yaron.
-
-     Permission is granted to copy, distribute and/or modify this
-     document under the terms of the GNU Free Documentation License,
-     Version 1.3 or any later version published by the Free Software
-     Foundation; with no Invariant Sections, no Front-Cover Texts, and
-     no Back-Cover Texts.
-INFO-DIR-SECTION Emacs
-START-INFO-DIR-ENTRY
-* Kubed: (kubed).       Kubernetes, Emacs, done!
-END-INFO-DIR-ENTRY
-
-\1f
-File: docHlL4Z1.info,  Node: Top,  Next: Overview,  Up: (dir)
-
-Kubed: Kubernetes, Emacs, done!
-*******************************
-
-This manual is for Kubed 0.4.3, a rich Emacs interface for Kubernetes.
-
-* Menu:
-
-* Overview::                    Introduction to Kubed
-* Getting Started::             First steps with Kubed
-* Usage::                       Using Kubed to interact with Kubernetes
-* Extending Kubed::             Adding support for your custom resources
-* Contributing::                Get involved in Kubed development
-* Indices::
-
-\1f
-File: docHlL4Z1.info,  Node: Overview,  Next: Getting Started,  Prev: Top,  Up: Top
-
-1 Overview
-**********
-
-Kubed is a rich Kubernetes interface within Emacs.  It helps you work
-with your Kubernetes clusters and deployments with the full power of
-‘kubectl’, and with the comfort and confidence of an intuitive
-interactive interface.
-
-   You can use Kubed to:
-
-   • Browse and manage Kubernetes workloads
-   • Connect to pods and edit files or execute commands
-   • Create new resources, edit and delete them
-   • Work with multiple clusters
-   • Get help about various Kubernetes objects
-   • ...
-
-   These features and others are documented in the rest of this manual,
-along with many options that Kubed provides for you to customize its
-behavior.
-
-\1f
-File: docHlL4Z1.info,  Node: Getting Started,  Next: Usage,  Prev: Overview,  Up: Top
-
-2 Getting Started
-*****************
-
-Get Kubed from GNU ELPA with ‘M-x package-install’, or use your favorite
-Emacs package manager to install Kubed from Git.  You can clone the
-Kubed Git repository from any of the following locations:
-
-   • <https://git.sr.ht/~eshel/kubed>
-   • <https://github.com/eshelyaron/kubed.git>
-   • <git://git.eshelyaron.com/kubed.git>
-
-   To get started with Kubed, all you need is ‘kubectl’ and Emacs.
-
-   Kubed tries to find ‘kubectl’ in the directories listed in the Emacs
-variable ‘exec-path’.  When Emacs is started from a shell, it
-initializes ‘exec-path’ from the shell’s ‘PATH’ environment variable
-which normally includes the location of ‘kubectl’ in common ‘kubectl’
-installations.  If Emacs doesn’t find the ‘kubectl’ executable via
-‘exec-path’, you can tell Kubed where to find it by customizing
-‘kubed-kubectl-program’.
-
- -- User Option: kubed-kubectl-program
-     Name of ‘kubectl’ executable file to use.
-
-\1f
-File: docHlL4Z1.info,  Node: Usage,  Next: Extending Kubed,  Prev: Getting Started,  Up: Top
-
-3 Usage
-*******
-
-Kubed comes with a large number of Emacs command for interacting with
-Kubernetes.  Some commands perform one action on one resource, while
-others show you a menu with many resources and let you interact with any
-number of them.  Some commands are specific to one type of resources,
-while others act on resources of any type.  There are different ways to
-use Kubed, depending on your use case.
-
-   The two most important entry points for Kubed are ‘kubed-prefix-map’
-and ‘kubed-transient’:
-
- -- Keymap: kubed-prefix-map
-     Keymap with bindings for many useful Kubed commands.
-
-   The prefix keymap ‘kubed-prefix-map’ gives you quick access to the
-main Kubed commands.  You may want to bind it to a convenient key in
-your global keymap, for example:
-
-     (keymap-global-set "C-c k" 'kubed-prefix-map)
-
-   With this binding in place, you can create a new Kubernetes resource
-with ‘C-c k +’ and attach to a running pod with ‘C-c k p a’.  The ‘C-c
-k’ binding is just a suggestion of course, feel free to pick any key
-sequence you like.
-
-   You can also access all of the commands in ‘kubed-prefix-map’ via the
-menu-bar ‘Kubernetes’ menu—to add this menu to your menu-bar, enable the
-global minor mode ‘kubed-menu-bar-mode’:
-
- -- Minor Mode: kubed-menu-bar-mode
-     Add ‘Kubernetes’ menu to your menu bar.
-
-   The other important entry point that Kubed provides for exploring and
-performing different Kubernetes operations is ‘kubed-transient’:
-
- -- Command: kubed-transient
-     Open the main Kubed transient menu.
-
-   This command pops up the Kubed transient menu, which gives you
-interactive guidance for invoking Kubed commands.  *Note
-(transient)Top::.
-
-   The following sections describe in detail the various Kubed commands.
-
-* Menu:
-
-* Display Resource::
-* Browse Resources::
-* Context and Namespace::
-* Transient Menus::
-* Scale Deployment::
-
-\1f
-File: docHlL4Z1.info,  Node: Display Resource,  Next: Browse Resources,  Up: Usage
-
-3.1 Display Resource
-====================
-
-You can view the YAML description of any resource in your Kubernetes
-cluster.  In Kubed, this is referred to as “displaying” the given
-resource.  The following commands display a Kubernetes resource:
-
- -- Command: kubed-display-resource
-     Display a Kubernetes resource.
-
- -- Command: kubed-display-pod
- -- Command: kubed-display-deployment
- -- Command: kubed-display-namespace
- -- Command: kubed-display-FOO
-     Display Kubernetes resource of a given type.
-
-   Command ‘kubed-display-resource’ can display any Kubernetes resource.
-It prompts you to select a resource type and a resource name, and
-displays that resource in a dedicated buffer.  By default, this command
-assumes you want to display a resource that is in the current namespace,
-but if you invoke ‘kubed-display-resource’ with a prefix argument
-(‘C-u’) and choose a namespaced resource type, then it also lets you
-select the namespace of the resource.  With a double prefix argument, it
-lets you select which ‘kubectl’ context to use too.  *Note Context and
-Namespace::.
-
-   If you have ‘kubed-prefix-map’ bound to ‘C-c k’, you can invoke
-‘kubed-display-resource’ with ‘C-c k <RET>’.  This command is also
-available from the menu-bar “Kubernetes” menu (*note Definition of
-kubed-menu-bar-mode::), and from the transient “Kubernetes Display” menu
-(*note Transient Menus::).
-
-   You can also display the resource at point in resources list buffers
-by simply typing ‘<RET>’.  *Note Browse Resources::.
-
-   Kubed also provides a dedicated ‘kubed-display-FOO’ command for each
-supported resource type FOO.  These commands are just like
-‘kubed-display-resource’, except that they do not prompt you for a type,
-since they are type-specific.  For example, ‘kubed-display-pod’ only
-prompts you for a pod name, and then displays it like
-‘kubed-display-resource’ does.
-
-   You can invoke these commands by adding a type-specific key before
-‘<RET>’ in ‘C-c k <RET>’: ‘C-c k p <RET>’ invokes ‘kubed-display-pod’,
-‘C-c k d <RET>’ invokes ‘kubed-display-deployment’, and so on.
-
-   When Kubed prepares a buffer for displaying a resource, it runs the
-hook ‘kubed-yaml-setup-hook’ right after populating the buffer with the
-YAML description of the resource:
-
- -- User Option: kubed-yaml-setup-hook
-     List of functions to call, in order, to prepare YAML buffers.  The
-     first function on this hook is normally the major mode you want to
-     use for YAML buffers that display Kubernetes resources.  By
-     default, this is the list ‘(yaml-ts-mode view-mode)’.
-
-   In addition, Kubed enables a bespoke minor mode
-‘kubed-display-resource-mode’ in buffers that display Kubernetes
-resources:
-
- -- Minor Mode: kubed-display-resource-mode
-     Minor mode for buffers that display a Kubernetes resource.
-
-This minor mode does the following:
-
-   • It shows the word ‘Kubed’ in the mode line, so you know you’re
-     seeing a rendered Kubernetes resource, rather than any old YAML
-     file.
-   • It allows you to _bookmark_ the resource your viewing and your
-     position in its YAML description with the regular Emacs bookmarks
-     commands (*note (emacs)Bookmarks::), namely ‘C-x r m’.
-   • It binds the key sequence ‘C-c C-j’ to command
-     ‘kubed-display-resource-jump-to-list’, which pops up the resources
-     list buffer for the type of the displayed resource, and takes you
-     to the line corresponding to it.
-   • It binds ‘C-c C-c’ to command ‘kubed-display-resource-replace’,
-     which lets you apply any changes that you make in the YAML buffer
-     back to the resource.  When you hit ‘C-c C-c’, Kubed asks you for
-     confirmation before proceeding; you can reply with ‘d’ (‘diff’) to
-     show a diff between the current state of the resource and the
-     current buffer contents.  You can also display this diff anytime
-     with ‘C-c C-=’.  Note that by default Kubed displays resources in
-     read-only buffers, so you may need to hit ‘C-x C-q’
-     (‘read-only-mode’) before making changes in the buffer.
-   • It lets you repopulate the buffer with updated information about
-     the resource with ‘C-x x g’ (‘revert-buffer-quick’) and
-     ‘M-x revert-buffer’.  This is also useful if you edit the resource
-     and want to restart from a clean slate.
-
-\1f
-File: docHlL4Z1.info,  Node: Browse Resources,  Next: Context and Namespace,  Prev: Display Resource,  Up: Usage
-
-3.2 Browse Resources
-====================
-
-Kubed gives you an interactive list of resources for each type, that you
-access with the ‘kubed-list-RESOURCEs’ commands, such as
-‘kubed-list-pods’.
-
-   These commands are bound to ‘l’ in Kubed’s type-specific prefix
-keymaps, most of which are accessible via the global ‘kubed-prefix-map’
-by default (*note Definition of kubed-prefix-map::).  So if you’ve bound
-‘kubed-prefix-map’ to ‘C-c k’, you can pop up the pods list with ‘C-c k
-p l’, the deployments list with ‘C-c k d l’, the jobs list with
-‘C-c k j l’, etc.  Normally, Kubed shows the list of resources in the
-current namespace, but if you invoke these commands with a prefix
-argument (say, ‘C-u C-c k p l’), they first prompt you to select a
-namespace, and then show resources in the namespace you selected.
-
-   The list of RESOURCEs in shown a buffer called
-‘*Kubed RESOURCEs@NAMESPACE[CONTEXT]*’, where CONTEXT is a ‘kubectl’
-context, and NAMESPACE is a namespace in CONTEXT.  For example, Kubed
-shows the list of pods in namespace ‘default’ for context ‘minikube’ in
-buffer ‘*Kubed pos@default[minikube]’.  For non-namespaced resources,
-the ‘@NAMESPACE’ part is omitted.
-
-   Each resource type has its own major mode for list buffers with
-type-specific commands and operations, but they are all also derived
-from a shared parent mode.  The pods list uses the ‘kubed-pods-mode’
-(‘Kubernetes Pods’) major mode, the list of Kubernetes deployments uses
-‘kubed-deployments-mode’, and so on.
-
-   The common parent major mode is ‘kubed-list-mode’:
-
- -- Major Mode: kubed-list-mode
-     Major mode for listing generic Kubernetes resources.
-
-   This mode provides the following commands for all type-specific
-derived modes:
-
-‘<?>’
-     Show help in transient menu (‘kubed-list-transient’).
-‘<RET>’
-     Display the resource at point in the current window
-     (‘kubed-list-select-resource’).
-‘o’
-     Display the resource at point in another window and select that
-     window (‘kubed-list-select-resource-other-window’).
-‘C-o’
-     Display the resource at point in another window without selecting
-     it (‘kubed-list-display-resource’).
-‘D’
-     Delete the resource at point (‘kubed-list-delete’).
-‘e’
-     Edit the resource at point (‘kubed-list-edit’).
-‘P’
-     Patch the resource at point (‘kubed-list-patch’).
-‘g’
-     Update the resources list by fetching new information from
-     Kubernetes (‘kubed-list-update’).
-‘/’
-     Filter the current list of resources (‘kubed-list-set-filter’).
-     *Note List Filter::.
-‘d’
-     Mark the resource at point for deletion
-     (‘kubed-list-mark-for-deletion’).  Resources marked for deletion
-     have a ‘D’ in the beginning of their line.
-‘x’
-     Delete marked resources (‘kubed-list-delete-marked’).
-‘u’
-     Unmark from resource at point (‘kubed-list-unmark’).
-‘w’
-     Copy name of resource at point into the kill ring
-     (‘kubed-list-copy-as-kill’).
-‘n’
-     Move point to the next line (‘next-line’).
-‘p’
-     Move point to the previous line (‘previous-line’).
-‘<TAB>’
-     Move point to the next column.  If point is already at the last
-     column, move to the first column of the next line instead
-     (‘kubed-list-next-column’).
-‘S-<TAB>’
-     Move point to the previous column.  If point is already at the
-     first column, move to the last column of the previous line instead
-     (‘kubed-list-previous-column’).
-‘S’
-     Sort lines by the column at point (‘tabulated-list-sort’).
-‘|’
-     Fit width of column at point to its content
-     (‘kubed-list-fit-column-width-to-content’).  With non-negative
-     prefix argument N (for example, ‘0 |’), fit Nth column.  With
-     negative prefix argument (‘- |’), fit all columns.
-‘{’
-     Narrow the column at point
-     (‘tabulated-list-narrow-current-column’).
-‘}’
-     Widen the column at point (‘tabulated-list-widen-current-column’).
-
-   In addition, you can bookmark any Kubed resources list buffer with
-the usual ‘C-x r m’.  *Note (emacs)Bookmarks::.
-
-   Note that ‘kubed-list-mode’ (and its type-specific derivatives) bind
-the ‘g’ key, which is commonly bound to ‘revert-buffer’, to
-‘kubed-list-update’.  The difference between these commands is that
-‘revert-buffer’ only refreshes the list display, without fetching
-updated data from Kubernetes.  You can still invoke ‘revert-buffer’ with
-‘C-x x g’ or ‘M-x’, if you need it.
-
-   Whenever Kubed is fetching data from Kubernetes to update a resources
-list buffer, the mode line of that list buffer shows the ‘[...]’
-indicator.  You can set user option ‘kubed-list-mode-line-format’ to
-customize this indicator.
-
-* Menu:
-
-* List Filter::
-
-\1f
-File: docHlL4Z1.info,  Node: List Filter,  Up: Browse Resources
-
-3.2.1 Filtering Resource Lists
-------------------------------
-
-In all Kubernetes resource list buffers, you can use ‘/’
-(‘kubed-list-set-filter’) to “filter” the list of resources.  This
-command sets the filter of the current buffer, which specifies
-conditions on resources (lines).  Resources that don’t satisfy the
-conditions are hidden, so you can focus on those that do.
-
-   Filters can be simple (“atomic filters”) or complex (“composed
-filters”).  In the simple case, you enter a filter in the minibuffer in
-the format ‘OP COL VAL’, where OP is a comparison operator, one of ‘=’,
-‘~’, ‘<’ and ‘>’; COL is a column name; and VAL is a value to compare to
-values of COL with OP.
-
-   If OP is ‘=’, it says to keep only lines whose COL equals VAL.  If OP
-is ‘~’, it says to keep lines whose COL matches the VAL as a regular
-expression.  ‘<’ and ‘>’ compare column values to numeric values.  For
-example, the filter ‘= Name foobar’ keeps only resources whose name is
-‘foobar’.  To include whitespace in VAL, wrap VAL in double quotes: ‘=
-Name "foo bar"’.
-
-   The possible values of OP and their meanings are defined in
-‘kubed-list-filter-operator-alist’, which is a user option you can use
-to add or change the meaning of filter operators:
-
- -- User Option: kubed-list-filter-operator-alist
-     Association list of filter operators and corresponding Emacs Lisp
-     functions.  See the documentation string of this option for
-     specifics.
-
-   You can use more refined filters by composing simple filters.  To add
-another filter that resources must satisfy, wrap your two filters in
-parentheses and put them next to each other:
-
-     (= Name foobar) (~ Namespace kube)
-
-This filter keeps only resources whose name is ‘foobar’ in namespaces
-that include ‘kube’ as a substring, it expresses the conjunction of the
-two simple filters.
-
-   To negate a simple filter, put a single quote ahead of it, like so:
-
-     (= Name foobar) '(~ Namespace kube)
-
-This matches resources named ‘foobar’ in namespaces that do _not_
-contain ‘kube’.
-
-   To specify a disjunction of simple filters (and negated simple
-filters), add another level of nesting:
-
-     ((= Name spam) (= Name foobar)) '(~ Namespace kube)
-
-This filter matches resources named either ‘spam’ or ‘foobar’, in
-namespaces that do not contain ‘kube’.
-
-   While entering a filter in the minibuffer, ‘<TAB>’ completion is
-available for column names and values.  To clear the filter, just exit
-the minibuffer with an empty input.
-
-\1f
-File: docHlL4Z1.info,  Node: Context and Namespace,  Next: Transient Menus,  Prev: Browse Resources,  Up: Usage
-
-3.3 Context and Namespace
-=========================
-
-Kubed uses ‘kubectl’ to interact with Kubernetes clusters, and you can
-use multiple ‘kubectl’ “contexts” in Kubed to work with different
-Kubernetes clusters in parallel.  Within each context, Kubed lets you
-work in multiple “namespaces” too.  In general, each buffer has its own
-“local context” and “local namespace”, and Kubed commands use these
-local context and namespace by default.  This is similar to how
-different buffers have different values of ‘default-directory’ (*note
-(emacs)File Names::), and how that affects commands that interact with
-the filesystem.
-
-   For Kubed buffers that display a Kubernetes resource (*note Display
-Resource::) or a list of resources (*note Browse Resources::), the
-buffer-local context and namespace are the context and namespace of the
-resources the buffer displays.  For non-Kubed buffers, the user option
-‘kubed-default-context-and-namespace’ determines the default local
-context and namespace.
-
- -- User Option: kubed-default-context-and-namespace
-     Default ‘kubectl’ context and Kubernetes namespace for Kubed
-     commands.  The value of this option is either a cons cell
-     ‘(CONTEXT . NAMESPACE)’ or ‘nil’.  If it is ‘nil’, Kubed
-     initializes this option to a cons cell with the current ‘kubectl’
-     context and namespace for that context on the first time Kubed
-     consults this option.
-
-   As mentioned above, most Kubed commands use the local context and
-namespace by default—it is also conventional for Kubed commands to let
-you choose a different namespace if you invoke them with a prefix
-argument (‘C-u’), and to also let you choose a different context if you
-invoke them with a double prefix argument (‘C-u C-u’).
-
-   The following functions return the local context and namespace for
-buffer in which you call them:
-
- -- Function: kubed-local-context
-     Return the local ‘kubectl’ context for the current buffer.
-
- -- Function: kubed-local-namespace
-     Return the local Kubernetes namespace for the current buffer.
-
- -- Function: kubed-local-context-and-namespace
-     Return the local context and namespace for the current buffer as a
-     cons cell ‘(CONTEXT . NAMESPACE)’.
-
-\1f
-File: docHlL4Z1.info,  Node: Transient Menus,  Next: Scale Deployment,  Prev: Context and Namespace,  Up: Usage
-
-3.4 Transient Menus
-===================
-
-Kubed provides a set of keyboard-driven “transient menus” (*note
-(transient)Top::) that you can use to explore and invoke various
-commands.  Transient menus show you available commands along with their
-key bindings, which helps you use many different commands without the
-need to remember the key bindings for all them.  Additionally, the
-transient menus allow you to specify options and switches for the
-commands you invoke, which may not be available when invoking these
-commands directly.  For example, while you can invoke command
-‘kubed-logs’ directly to view logs from a container running in
-Kubernetes, the “Kubernetes Logs” transient menu which you open with
-‘kubed-transient-logs’ lets you set a maximum number of logs to
-retrieve, among other knobs and handles.
-
-   Command ‘kubed-transient’ opens the Kubed “root” transient menu,
-which is a dispatch that lets you access different transient menus, such
-as the aforementioned “Kubernetes Logs” transient menu.  It’s a good
-idea to bind ‘kubed-transient’ to a convenient key, either in the global
-keymap or under ‘kubed-prefix-map’:
-
-     (keymap-global-set "s-k" #'kubed-transient)
-     (keymap-set kubed-prefix-map "k" #'kubed-transient)
-
-   In Kubed resource list buffers, type ‘?’ to pop up a transient menu
-with commands that are specific to the type of resources the buffer
-displays.  *Note Browse Resources::.
-
-\1f
-File: docHlL4Z1.info,  Node: Scale Deployment,  Prev: Transient Menus,  Up: Usage
-
-3.5 Scale Deployment
-====================
-
-You can use Kubed to “scale” Kubernetes a deployment, which means
-setting the size of the deployment in terms of the number of replicas it
-governs.
-
- -- Command: kubed-scale-deployment
-     Scale a Kubernetes deployment.
-
-   ‘kubed-scale-deployment’ is bound to ‘$’ in the
-‘kubed-deployment-prefix-map’, so if you have ‘kubed-prefix-map’ bound
-to ‘C-c k’ then you can invoke it with ‘C-c k d $’.  *Note Definition of
-kubed-prefix-map::.  This command prompts you for a deployment and then
-lets you select a new number of replicas for that deployment.  By
-default you are prompted for deployment in the local context and
-namespace (*note Context and Namespace::); with a prefix argument, you
-can specify a different namespace; with a double prefix argument (‘C-u
-C-u’), you can specify a different context too.
-
-   In the deployments list buffer, you can scale the deployment at point
-by simply typing ‘$’.  *Note Browse Resources::.
-
-   Lastly, you can scale deployments using the transient menu
-‘kubed-transient-scale-deployment’, which is available from the main
-Kubed transient by pressing ‘$’.  *Note Transient Menus::.
-
-\1f
-File: docHlL4Z1.info,  Node: Extending Kubed,  Next: Contributing,  Prev: Usage,  Up: Top
-
-4 Extending Kubed
-*****************
-
-Kubed has built-in support for many common types of Kubernetes
-resources.  “Support” for a resource type in Kubed just means providing
-common commands for working with resources of that type, such as a
-command for showing the interactive list of these resources, like
-‘kubed-list-pods’ for Kubernetes pods.  In Kubed, the macro
-‘kubed-define-resource’ is used to define these common commands and add
-support for more resource types:
-
- -- Macro: kubed-define-resource resource &optional properties &rest [
-          keyword argument ]... commands
-     Define commands for RESOURCE.
-
-   Say you want to add support for your Kubernetes service accounts.
-With ‘kubed-define-resource’, all you need to do is to add the following
-line to your Emacs initialization file:
-
-     (kubed-define-resource serviceaccount)
-
-   This line defines the following commands for you:
-
-   • ‘kubed-display-serviceaccount’
-   • ‘kubed-list-serviceaccounts’
-   • ‘kubed-edit-serviceaccount’
-   • ‘kubed-delete-serviceaccount’
-   • ‘kubed-create-serviceaccount’
-   • ‘kubed-explain-serviceaccounts’
-
-   See the documentation string of ‘kubed-define-resource’ (‘C-h f’) for
-details about the optional arguments of this macro: the PROPERTIES
-argument which lets you specify what Kubed should show in the resource
-list buffer and the ‘commands’ argument which lets you associate
-additional commands with your resource type.
-
-\1f
-File: docHlL4Z1.info,  Node: Contributing,  Next: Indices,  Prev: Extending Kubed,  Up: Top
-
-5 Contributing
-**************
-
-We highly appreciate all contributions, including bug reports, patches,
-improvement suggestions, and general feedback!
-
-   The best way to get in touch with the Kubed maintainers is via the
-Kubed mailing list (https://lists.sr.ht/~eshel/kubed-devel).
-
- -- Command: kubed-submit-bug-report
-     Report a bug in Kubed to the maintainers via mail.
-
-   You can use the command ‘M-x kubed-submit-bug-report’ to easily
-contact the Kubed maintainers from within Emacs.  This command opens a
-new buffer with a message template ready to be sent to the development
-mailing list.
-
-\1f
-File: docHlL4Z1.info,  Node: Indices,  Prev: Contributing,  Up: Top
-
-Indices
-*******
-
-* Menu:
-
-* Function Index::
-* Variable Index::
-* Keystroke Index::
-* Concept Index::
-
-\1f
-File: docHlL4Z1.info,  Node: Function Index,  Next: Variable Index,  Up: Indices
-
-Function index
-==============
-
-\0\b[index\0\b]
-* Menu:
-
-* kubed-define-resource:                 Extending Kubed.      (line 14)
-* kubed-display-deployment:              Display Resource.     (line 14)
-* kubed-display-FOO:                     Display Resource.     (line 16)
-* kubed-display-namespace:               Display Resource.     (line 15)
-* kubed-display-pod:                     Display Resource.     (line 13)
-* kubed-display-resource:                Display Resource.     (line 10)
-* kubed-display-resource-diff:           Display Resource.     (line 78)
-* kubed-display-resource-jump-to-list:   Display Resource.     (line 74)
-* kubed-display-resource-mode:           Display Resource.     (line 63)
-* kubed-display-resource-replace:        Display Resource.     (line 78)
-* kubed-list-copy-as-kill:               Browse Resources.     (line 71)
-* kubed-list-delete:                     Browse Resources.     (line 51)
-* kubed-list-delete-marked:              Browse Resources.     (line 67)
-* kubed-list-display-resource:           Browse Resources.     (line 48)
-* kubed-list-edit:                       Browse Resources.     (line 53)
-* kubed-list-fit-column-width-to-content: Browse Resources.    (line 88)
-* kubed-list-mark-for-deletion:          Browse Resources.     (line 63)
-* kubed-list-mode:                       Browse Resources.     (line 35)
-* kubed-list-next-column:                Browse Resources.     (line 78)
-* kubed-list-patch:                      Browse Resources.     (line 55)
-* kubed-list-previous-column:            Browse Resources.     (line 82)
-* kubed-list-select-resource:            Browse Resources.     (line 42)
-* kubed-list-select-resource-other-window: Browse Resources.   (line 45)
-* kubed-list-set-filter:                 Browse Resources.     (line 60)
-* kubed-list-transient:                  Browse Resources.     (line 41)
-* kubed-list-unmark:                     Browse Resources.     (line 69)
-* kubed-list-update:                     Browse Resources.     (line 57)
-* kubed-local-context:                   Context and Namespace.
-                                                               (line 40)
-* kubed-local-context-and-namespace:     Context and Namespace.
-                                                               (line 46)
-* kubed-local-namespace:                 Context and Namespace.
-                                                               (line 43)
-* kubed-menu-bar-mode:                   Usage.                (line 34)
-* kubed-scale-deployment:                Scale Deployment.     (line 10)
-* kubed-submit-bug-report:               Contributing.         (line 12)
-* kubed-transient:                       Usage.                (line 40)
-* next-line:                             Browse Resources.     (line 74)
-* previous-line:                         Browse Resources.     (line 76)
-* read-only-mode:                        Display Resource.     (line 78)
-* revert-buffer:                         Display Resource.     (line 87)
-* revert-buffer-quick:                   Display Resource.     (line 87)
-* tabulated-list-narrow-current-column:  Browse Resources.     (line 93)
-* tabulated-list-sort:                   Browse Resources.     (line 86)
-* tabulated-list-widen-current-column:   Browse Resources.     (line 96)
-
-\1f
-File: docHlL4Z1.info,  Node: Variable Index,  Next: Keystroke Index,  Prev: Function Index,  Up: Indices
-
-Variable index
-==============
-
-\0\b[index\0\b]
-* Menu:
-
-* kubed-default-context-and-namespace:   Context and Namespace.
-                                                              (line  23)
-* kubed-kubectl-program:                 Getting Started.     (line  24)
-* kubed-list-filter-operator-alist:      List Filter.         (line  29)
-* kubed-list-mode-line-format:           Browse Resources.    (line 110)
-* kubed-prefix-map:                      Usage.               (line  16)
-* kubed-yaml-setup-hook:                 Display Resource.    (line  53)
-
-\1f
-File: docHlL4Z1.info,  Node: Keystroke Index,  Next: Concept Index,  Prev: Variable Index,  Up: Indices
-
-Keystroke index
-===============
-
-\0\b[index\0\b]
-* Menu:
-
-* /:                                     Browse Resources.     (line 60)
-* <?>:                                   Browse Resources.     (line 41)
-* {:                                     Browse Resources.     (line 93)
-* |:                                     Browse Resources.     (line 88)
-* }:                                     Browse Resources.     (line 96)
-* C-c C-=:                               Display Resource.     (line 78)
-* C-c C-c:                               Display Resource.     (line 78)
-* C-c C-j:                               Display Resource.     (line 74)
-* C-o:                                   Browse Resources.     (line 48)
-* C-x C-q:                               Display Resource.     (line 78)
-* C-x x g:                               Display Resource.     (line 87)
-* D:                                     Browse Resources.     (line 51)
-* d:                                     Browse Resources.     (line 63)
-* e:                                     Browse Resources.     (line 53)
-* g:                                     Browse Resources.     (line 57)
-* n:                                     Browse Resources.     (line 74)
-* o:                                     Browse Resources.     (line 45)
-* P:                                     Browse Resources.     (line 55)
-* p:                                     Browse Resources.     (line 76)
-* <RET>:                                 Browse Resources.     (line 42)
-* S:                                     Browse Resources.     (line 86)
-* S-<TAB>:                               Browse Resources.     (line 82)
-* <TAB>:                                 Browse Resources.     (line 78)
-* u:                                     Browse Resources.     (line 69)
-* w:                                     Browse Resources.     (line 71)
-* x:                                     Browse Resources.     (line 67)
-
-\1f
-File: docHlL4Z1.info,  Node: Concept Index,  Prev: Keystroke Index,  Up: Indices
-
-Concept index
-=============
-
-\0\b[index\0\b]
-* Menu:
-
-* global prefix keymap:                  Usage.                (line 16)
-* installation:                          Getting Started.      (line  6)
-* keymap, for global commands:           Usage.                (line 16)
-* Kubed:                                 Overview.             (line  6)
-* kubed:                                 Overview.             (line  6)
-* prefix keymap, global commands:        Usage.                (line 16)
-* requirements:                          Getting Started.      (line 14)
-
-
-\1f
-Tag Table:
-Node: Top\7f601
-Node: Overview\7f1145
-Node: Getting Started\7f1913
-Node: Usage\7f3010
-Ref: Definition of kubed-prefix-map\7f3621
-Ref: Definition of kubed-menu-bar-mode\7f4384
-Node: Display Resource\7f5019
-Node: Browse Resources\7f9549
-Node: List Filter\7f14576
-Node: Context and Namespace\7f17229
-Node: Transient Menus\7f19619
-Node: Scale Deployment\7f21194
-Node: Extending Kubed\7f22491
-Node: Contributing\7f24082
-Node: Indices\7f24782
-Node: Function Index\7f24956
-Node: Variable Index\7f28351
-Node: Keystroke Index\7f29014
-Node: Concept Index\7f31074
-\1f
-End Tag Table
-
-\1f
-Local Variables:
-coding: utf-8
-End:
diff --git a/elpa/kubed-0.4.3/kubed.texi b/elpa/kubed-0.4.3/kubed.texi
deleted file mode 100644 (file)
index ae5ab9a..0000000
+++ /dev/null
@@ -1,789 +0,0 @@
-\input texinfo    @c -*- texinfo -*-
-@c %**start of header
-@setfilename kubed.info
-@settitle Kubed: Kubernetes, Emacs, done!
-@documentencoding UTF-8
-@documentlanguage en
-@set MAINTAINERSITE @uref{https://eshelyaron.com,maintainer webpage}
-@set MAINTAINER Eshel Yaron
-@set MAINTAINEREMAIL @email{meNOSPAMeshelyaron.com}
-@set MAINTAINERCONTACT @uref{mailto:meNOSPAMeshelyaron.com,contact the maintainer}
-@c %**end of header
-
-@copying
-This manual is for Kubed 0.4.3, a rich Emacs interface for Kubernetes.
-
-Copyright @copyright{} 2024-2025 Eshel Yaron.
-
-@quotation
-Permission is granted to copy, distribute and/or modify this document
-under the terms of the GNU Free Documentation License, Version 1.3 or
-any later version published by the Free Software Foundation; with no
-Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
-@end quotation
-@end copying
-
-@dircategory Emacs
-@direntry
-* Kubed: (kubed).       Kubernetes, Emacs, done!
-@end direntry
-
-@finalout
-@titlepage
-@title Kubed: Kubernetes, Emacs, done!
-@author Eshel Yaron (@email{me@@eshelyaron.com})
-@end titlepage
-
-@contents
-
-@ifnottex
-@node Top
-@top Kubed: Kubernetes, Emacs, done!
-
-This manual is for Kubed 0.4.3, a rich Emacs interface for Kubernetes.
-
-@end ifnottex
-
-@menu
-* Overview::                    Introduction to Kubed
-* Getting Started::             First steps with Kubed
-* Usage::                       Using Kubed to interact with Kubernetes
-* Extending Kubed::             Adding support for your custom resources
-* Contributing::                Get involved in Kubed development
-* Indices::
-@end menu
-
-@node Overview
-@chapter Overview
-
-@cindex Kubed
-@cindex kubed
-Kubed is a rich Kubernetes interface within Emacs.  It helps you work
-with your Kubernetes clusters and deployments with the full power of
-@command{kubectl}, and with the comfort and confidence of an intuitive
-interactive interface.
-
-@ifhtml
-@float
-@image{/assets/kubed-overview,,,Image: Four different kinds of Kubed buffers in Emacs,.png}
-@caption{Pods, logs, shells, YAMLs, all in one integrated interface}
-@end float
-@end ifhtml
-
-You can use Kubed to:
-
-@itemize
-@item
-Browse and manage Kubernetes workloads
-@item
-Connect to pods and edit files or execute commands
-@item
-Create new resources, edit and delete them
-@item
-Work with multiple clusters
-@item
-Get help about various Kubernetes objects
-@item
-@dots{}
-@end itemize
-
-These features and others are documented in the rest of this manual,
-along with many options that Kubed provides for you to customize its
-behavior.
-
-@node Getting Started
-@chapter Getting Started
-
-@cindex installation
-
-Get Kubed from GNU ELPA with @kbd{M-x package-install}, or use your
-favorite Emacs package manager to install Kubed from Git.  You can
-clone the Kubed Git repository from any of the following locations:
-
-@itemize
-@item
-@url{https://git.sr.ht/~eshel/kubed}
-@item
-@url{https://github.com/eshelyaron/kubed.git}
-@item
-@url{git://git.eshelyaron.com/kubed.git}
-@end itemize
-
-@cindex requirements
-To get started with Kubed, all you need is @command{kubectl} and Emacs.
-
-Kubed tries to find @command{kubectl} in the directories listed in the
-Emacs variable @code{exec-path}.  When Emacs is started from a shell, it
-initializes @code{exec-path} from the shell's @env{PATH} environment
-variable which normally includes the location of @command{kubectl} in
-common @command{kubectl} installations.  If Emacs doesn't find the
-@command{kubectl} executable via @code{exec-path}, you can tell Kubed
-where to find it by customizing @code{kubed-kubectl-program}.
-
-@defopt kubed-kubectl-program
-Name of @command{kubectl} executable file to use.
-@end defopt
-
-@node Usage
-@chapter Usage
-
-Kubed comes with a large number of Emacs command for interacting with
-Kubernetes.  Some commands perform one action on one resource, while
-others show you a menu with many resources and let you interact with any
-number of them.  Some commands are specific to one type of resources,
-while others act on resources of any type.  There are different ways to
-use Kubed, depending on your use case.
-
-The two most important entry points for Kubed are
-@code{kubed-prefix-map} and @code{kubed-transient}:
-
-@anchor{Definition of kubed-prefix-map}
-@cindex global prefix keymap
-@cindex prefix keymap, global commands
-@cindex keymap, for global commands
-@defvr Keymap kubed-prefix-map
-Keymap with bindings for many useful Kubed commands.
-@end defvr
-
-The prefix keymap @code{kubed-prefix-map} gives you quick access to the
-main Kubed commands.  You may want to bind it to a convenient key in
-your global keymap, for example:
-
-@lisp
-(keymap-global-set "C-c k" 'kubed-prefix-map)
-@end lisp
-
-With this binding in place, you can create a new Kubernetes resource
-with @kbd{C-c k +} and attach to a running pod with @kbd{C-c k p a}.
-The @kbd{C-c k} binding is just a suggestion of course, feel free to
-pick any key sequence you like.
-
-@ifhtml
-@float
-
-@image{/assets/kubed-prefix-map,,,Image: Emacs which-key popup for kubed-prefix-map keymap,.png}
-
-@image{/assets/kubed-deployment-prefix-map,,,Image: Emacs which-key popup for kubed-deployment-prefix-map,.png}
-
-@caption{Use @code{kubed-prefix-map} for quick access to the main Kubed commands}
-@end float
-@end ifhtml
-
-You can also access all of the commands in @code{kubed-prefix-map} via
-the menu-bar @samp{Kubernetes} menu---to add this menu to your
-menu-bar, enable the global minor mode @code{kubed-menu-bar-mode}:
-
-@anchor{Definition of kubed-menu-bar-mode}
-@deffn {Minor Mode} kubed-menu-bar-mode
-Add @samp{Kubernetes} menu to your menu bar.
-@end deffn
-
-The other important entry point that Kubed provides for exploring and
-performing different Kubernetes operations is @code{kubed-transient}:
-
-@deffn Command kubed-transient
-Open the main Kubed transient menu.
-@end deffn
-
-This command pops up the Kubed transient menu, which gives you
-interactive guidance for invoking Kubed commands.
-@xref{Top,,,transient}.
-
-The following sections describe in detail the various Kubed commands.
-
-@menu
-* Display Resource::
-* Browse Resources::
-* Context and Namespace::
-* Transient Menus::
-* Scale Deployment::
-@end menu
-
-@node Display Resource
-@section Display Resource
-
-You can view the YAML description of any resource in your Kubernetes
-cluster.  In Kubed, this is referred to as @dfn{displaying} the given
-resource.  The following commands display a Kubernetes resource:
-
-@deffn Command kubed-display-resource
-Display a Kubernetes resource.
-@end deffn
-
-@deffn Command kubed-display-pod
-@deffnx Command kubed-display-deployment
-@deffnx Command kubed-display-namespace
-@deffnx Command kubed-display-@var{foo}
-Display Kubernetes resource of a given type.
-@end deffn
-
-Command @code{kubed-display-resource} can display any Kubernetes
-resource.  It prompts you to select a resource type and a resource
-name, and displays that resource in a dedicated buffer.  By default,
-this command assumes you want to display a resource that is in the
-current namespace, but if you invoke @code{kubed-display-resource}
-with a prefix argument (@kbd{C-u}) and choose a namespaced resource
-type, then it also lets you select the namespace of the resource.
-With a double prefix argument, it lets you select which
-@command{kubectl} context to use too.  @xref{Context and Namespace}.
-
-If you have @code{kubed-prefix-map} bound to @kbd{C-c k}, you can
-invoke @code{kubed-display-resource} with @kbd{C-c k @key{RET}}.  This
-command is also available from the menu-bar ``Kubernetes'' menu
-(@pxref{Definition of kubed-menu-bar-mode}), and from the transient
-``Kubernetes Display'' menu (@pxref{Transient Menus}).
-
-You can also display the resource at point in resources list buffers
-by simply typing @kbd{@key{RET}}.  @xref{Browse Resources}.
-
-Kubed also provides a dedicated @code{kubed-display-@var{foo}} command
-for each supported resource type @var{foo}.  These commands are just
-like @code{kubed-display-resource}, except that they do not prompt you
-for a type, since they are type-specific.  For example,
-@code{kubed-display-pod} only prompts you for a pod name, and then
-displays it like @code{kubed-display-resource} does.
-
-You can invoke these commands by adding a type-specific key before
-@kbd{@key{RET}} in @kbd{C-c k @key{RET}}: @kbd{C-c k p @key{RET}}
-invokes @code{kubed-display-pod}, @kbd{C-c k d @key{RET}} invokes
-@code{kubed-display-deployment}, and so on.
-
-When Kubed prepares a buffer for displaying a resource, it runs the
-hook @code{kubed-yaml-setup-hook} right after populating the buffer
-with the YAML description of the resource:
-
-@defopt kubed-yaml-setup-hook
-List of functions to call, in order, to prepare YAML buffers.  The
-first function on this hook is normally the major mode you want to use
-for YAML buffers that display Kubernetes resources.  By default, this
-is the list @code{(yaml-ts-mode view-mode)}.
-@end defopt
-
-In addition, Kubed enables a bespoke minor mode
-@code{kubed-display-resource-mode} in buffers that display Kubernetes
-resources:
-
-@deffn {Minor Mode} kubed-display-resource-mode
-Minor mode for buffers that display a Kubernetes resource.
-@end deffn
-
-@noindent
-This minor mode does the following:
-
-@itemize
-@item
-It shows the word @samp{Kubed} in the mode line, so you know you're
-seeing a rendered Kubernetes resource, rather than any old YAML file.
-@item
-It allows you to @emph{bookmark} the resource your viewing and your
-position in its YAML description with the regular Emacs bookmarks
-commands (@pxref{Bookmarks,,,emacs}), namely @kbd{C-x r m}.
-@item
-@kindex C-c C-j
-@findex kubed-display-resource-jump-to-list
-It binds the key sequence @kbd{C-c C-j} to command
-@code{kubed-display-resource-jump-to-list}, which pops up the
-resources list buffer for the type of the displayed resource, and
-takes you to the line corresponding to it.
-@item
-@kindex C-c C-c
-@findex kubed-display-resource-replace
-@kindex C-c C-=
-@findex kubed-display-resource-diff
-@kindex C-x C-q
-@findex read-only-mode
-It binds @kbd{C-c C-c} to command
-@code{kubed-display-resource-replace}, which lets you apply any
-changes that you make in the YAML buffer back to the resource.  When
-you hit @kbd{C-c C-c}, Kubed asks you for confirmation before
-proceeding; you can reply with @kbd{d} (@samp{diff}) to show a diff
-between the current state of the resource and the current buffer
-contents.  You can also display this diff anytime with @kbd{C-c C-=}.
-Note that by default Kubed displays resources in read-only buffers, so
-you may need to hit @kbd{C-x C-q} (@code{read-only-mode}) before
-making changes in the buffer.
-@item
-@kindex C-x x g
-@findex revert-buffer
-@findex revert-buffer-quick
-It lets you repopulate the buffer with updated information about the
-resource with @kbd{C-x x g} (@code{revert-buffer-quick}) and
-@w{@kbd{M-x revert-buffer}}.  This is also useful if you edit the
-resource and want to restart from a clean slate.
-@end itemize
-
-@ifhtml
-@float
-@image{/assets/kubed-replace-diff,,,Image: Displaying and editing YAML of Kubernetes pod with Kubed,.png}
-@caption{Type @kbd{C-x C-q} in a resource YAML buffer to edit it, @kbd{C-c C-c} to apply}
-@end float
-@end ifhtml
-
-@node Browse Resources
-@section Browse Resources
-
-Kubed gives you an interactive list of resources for each type, that
-you access with the @code{kubed-list-@var{resource}s} commands, such
-as @code{kubed-list-pods}.
-
-These commands are bound to @kbd{l} in Kubed's type-specific prefix
-keymaps, most of which are accessible via the global
-@code{kubed-prefix-map} by default (@pxref{Definition of
-kubed-prefix-map}).  So if you've bound @code{kubed-prefix-map} to
-@kbd{C-c k}, you can pop up the pods list with @kbd{C-c k p l}, the
-deployments list with @kbd{C-c k d l}, the jobs list with @w{@kbd{C-c
-k j l}}, etc.  Normally, Kubed shows the list of resources in the
-current namespace, but if you invoke these commands with a prefix
-argument (say, @kbd{C-u C-c k p l}), they first prompt you to select a
-namespace, and then show resources in the namespace you selected.
-
-The list of @var{resource}s in shown a buffer called @w{@file{*Kubed
-@var{resource}s@@@var{namespace}[@var{context}]*}}, where
-@var{context} is a @command{kubectl} context, and @var{namespace} is a
-namespace in @var{context}.  For example, Kubed shows the list of pods
-in namespace @samp{default} for context @samp{minikube} in buffer
-@file{*Kubed pos@@default[minikube]}.  For non-namespaced resources,
-the @w{@samp{@@@var{namespace}}} part is omitted.
-
-Each resource type has its own major mode for list buffers with
-type-specific commands and operations, but they are all also derived
-from a shared parent mode.  The pods list uses the
-@code{kubed-pods-mode} (@samp{Kubernetes Pods}) major mode, the list
-of Kubernetes deployments uses @code{kubed-deployments-mode}, and so
-on.
-
-@ifhtml
-@float
-@image{/assets/kubed-list-transient,,,Image: Kubed pods list buffer with the help transient menu visible,.png}
-@caption{Browse your pods, deployments, and other resources with Kubed list buffers}
-@end float
-@end ifhtml
-
-The common parent major mode is @code{kubed-list-mode}:
-
-@deffn {Major Mode} kubed-list-mode
-Major mode for listing generic Kubernetes resources.
-@end deffn
-
-This mode provides the following commands for all type-specific
-derived modes:
-
-@table @kbd
-@kindex @key{?}
-@findex kubed-list-transient
-@item @key{?}
-Show help in transient menu (@code{kubed-list-transient}).
-@kindex @key{RET}
-@findex kubed-list-select-resource
-@item @key{RET}
-Display the resource at point in the current window
-(@code{kubed-list-select-resource}).
-@kindex o
-@findex kubed-list-select-resource-other-window
-@item o
-Display the resource at point in another window and select that window
-(@code{kubed-list-select-resource-other-window}).
-@kindex C-o
-@findex kubed-list-display-resource
-@item C-o
-Display the resource at point in another window without selecting it
-(@code{kubed-list-display-resource}).
-@kindex D
-@findex kubed-list-delete
-@item D
-Delete the resource at point (@code{kubed-list-delete}).
-@kindex e
-@findex kubed-list-edit
-@item e
-Edit the resource at point (@code{kubed-list-edit}).
-@kindex P
-@findex kubed-list-patch
-@item P
-Patch the resource at point (@code{kubed-list-patch}).
-@kindex g
-@findex kubed-list-update
-@item g
-Update the resources list by fetching new information from Kubernetes
-(@code{kubed-list-update}).
-@kindex /
-@findex kubed-list-set-filter
-@item /
-Filter the current list of resources (@code{kubed-list-set-filter}).
-@xref{List Filter}.
-@kindex d
-@findex kubed-list-mark-for-deletion
-@item d
-Mark the resource at point for deletion
-(@code{kubed-list-mark-for-deletion}).  Resources marked for deletion
-have a @samp{D} in the beginning of their line.
-@kindex x
-@findex kubed-list-delete-marked
-@item x
-Delete marked resources (@code{kubed-list-delete-marked}).
-@kindex u
-@findex kubed-list-unmark
-@item u
-Unmark from resource at point (@code{kubed-list-unmark}).
-@kindex w
-@findex kubed-list-copy-as-kill
-@item w
-Copy name of resource at point into the kill ring
-(@code{kubed-list-copy-as-kill}).
-@kindex n
-@findex next-line
-@item n
-Move point to the next line (@code{next-line}).
-@kindex p
-@findex previous-line
-@item p
-Move point to the previous line (@code{previous-line}).
-@kindex @key{TAB}
-@findex kubed-list-next-column
-@item @key{TAB}
-Move point to the next column.  If point is already at the last
-column, move to the first column of the next line instead
-(@code{kubed-list-next-column}).
-@kindex S-@key{TAB}
-@findex kubed-list-previous-column
-@item S-@key{TAB}
-Move point to the previous column.  If point is already at the first
-column, move to the last column of the previous line instead
-(@code{kubed-list-previous-column}).
-@kindex S
-@findex tabulated-list-sort
-@item S
-Sort lines by the column at point (@code{tabulated-list-sort}).
-@kindex |
-@findex kubed-list-fit-column-width-to-content
-@item |
-Fit width of column at point to its content
-(@code{kubed-list-fit-column-width-to-content}).  With non-negative
-prefix argument @var{n} (for example, @kbd{0 |}), fit @var{n}th
-column.  With negative prefix argument (@kbd{- |}), fit all columns.
-@kindex @{
-@findex tabulated-list-narrow-current-column
-@item @{
-Narrow the column at point
-(@code{tabulated-list-narrow-current-column}).
-@kindex @}
-@findex tabulated-list-widen-current-column
-@item @}
-Widen the column at point
-(@code{tabulated-list-widen-current-column}).
-@end table
-
-In addition, you can bookmark any Kubed resources list buffer with the
-usual @kbd{C-x r m}.  @xref{Bookmarks,,,emacs}.
-
-Note that @code{kubed-list-mode} (and its type-specific derivatives)
-bind the @kbd{g} key, which is commonly bound to @code{revert-buffer},
-to @code{kubed-list-update}.  The difference between these commands is
-that @code{revert-buffer} only refreshes the list display, without
-fetching updated data from Kubernetes.  You can still invoke
-@code{revert-buffer} with @kbd{C-x x g} or @kbd{M-x}, if you need it.
-
-@vindex kubed-list-mode-line-format
-Whenever Kubed is fetching data from Kubernetes to update a resources
-list buffer, the mode line of that list buffer shows the @samp{[...]}
-indicator.  You can set user option @code{kubed-list-mode-line-format}
-to customize this indicator.
-
-@menu
-* List Filter::
-@end menu
-
-@node List Filter
-@subsection Filtering Resource Lists
-
-In all Kubernetes resource list buffers, you can use @kbd{/}
-(@code{kubed-list-set-filter}) to @dfn{filter} the list of resources.
-This command sets the filter of the current buffer, which specifies
-conditions on resources (lines).  Resources that don't satisfy the
-conditions are hidden, so you can focus on those that do.
-
-Filters can be simple (@dfn{atomic filters}) or complex (@dfn{composed
-filters}).  In the simple case, you enter a filter in the minibuffer
-in the format @w{@samp{@var{op} @var{col} @var{val}}}, where @var{op}
-is a comparison operator, one of @samp{=}, @samp{~}, @samp{<} and
-@samp{>}; @var{col} is a column name; and @var{val} is a value to
-compare to values of @var{col} with @var{op}.
-
-If @var{op} is @samp{=}, it says to keep only lines whose @var{col}
-equals @var{val}.  If @var{op} is @samp{~}, it says to keep lines
-whose @var{col} matches the @var{val} as a regular expression.
-@samp{<} and @samp{>} compare column values to numeric values.  For
-example, the filter @samp{= Name foobar} keeps only resources whose
-name is @samp{foobar}.  To include whitespace in @var{val}, wrap
-@var{val} in double quotes: @samp{= Name "foo bar"}.
-
-The possible values of @var{op} and their meanings are defined in
-@code{kubed-list-filter-operator-alist}, which is a user option you
-can use to add or change the meaning of filter operators:
-
-@defopt kubed-list-filter-operator-alist
-Association list of filter operators and corresponding Emacs Lisp
-functions.  See the documentation string of this option for specifics.
-@end defopt
-
-You can use more refined filters by composing simple filters.  To add
-another filter that resources must satisfy, wrap your two filters in
-parentheses and put them next to each other:
-
-@lisp
-(= Name foobar) (~ Namespace kube)
-@end lisp
-
-@noindent
-This filter keeps only resources whose name is @samp{foobar} in
-namespaces that include @samp{kube} as a substring, it expresses the
-conjunction of the two simple filters.
-
-To negate a simple filter, put a single quote ahead of it, like so:
-
-@lisp
-(= Name foobar) '(~ Namespace kube)
-@end lisp
-
-@noindent
-This matches resources named @samp{foobar} in namespaces that do
-@emph{not} contain @samp{kube}.
-
-To specify a disjunction of simple filters (and negated simple
-filters), add another level of nesting:
-
-@lisp
-((= Name spam) (= Name foobar)) '(~ Namespace kube)
-@end lisp
-
-@noindent
-This filter matches resources named either @samp{spam} or
-@samp{foobar}, in namespaces that do not contain @samp{kube}.
-
-While entering a filter in the minibuffer, @kbd{@key{TAB}} completion
-is available for column names and values.  To clear the filter, just
-exit the minibuffer with an empty input.
-
-@node Context and Namespace
-@section Context and Namespace
-
-Kubed uses @command{kubectl} to interact with Kubernetes clusters, and
-you can use multiple @command{kubectl} @dfn{contexts} in Kubed to work
-with different Kubernetes clusters in parallel.  Within each context,
-Kubed lets you work in multiple @dfn{namespaces} too.  In general,
-each buffer has its own @dfn{local context} and @dfn{local namespace},
-and Kubed commands use these local context and namespace by default.
-This is similar to how different buffers have different values of
-@code{default-directory} (@pxref{File Names,,,emacs}), and how that
-affects commands that interact with the filesystem.
-
-For Kubed buffers that display a Kubernetes resource (@pxref{Display
-Resource}) or a list of resources (@pxref{Browse Resources}), the
-buffer-local context and namespace are the context and namespace of
-the resources the buffer displays.  For non-Kubed buffers, the user
-option @code{kubed-default-context-and-namespace} determines the
-default local context and namespace.
-
-@defopt kubed-default-context-and-namespace
-Default @command{kubectl} context and Kubernetes namespace for Kubed
-commands.  The value of this option is either a cons cell
-@w{@code{(@var{context} . @var{namespace})}} or @code{nil}.  If it is
-@code{nil}, Kubed initializes this option to a cons cell with the
-current @command{kubectl} context and namespace for that context on
-the first time Kubed consults this option.
-@end defopt
-
-As mentioned above, most Kubed commands use the local context and
-namespace by default---it is also conventional for Kubed commands to
-let you choose a different namespace if you invoke them with a prefix
-argument (@kbd{C-u}), and to also let you choose a different context
-if you invoke them with a double prefix argument (@kbd{C-u C-u}).
-
-The following functions return the local context and namespace for
-buffer in which you call them:
-
-@defun kubed-local-context
-Return the local @command{kubectl} context for the current buffer.
-@end defun
-
-@defun kubed-local-namespace
-Return the local Kubernetes namespace for the current buffer.
-@end defun
-
-@defun kubed-local-context-and-namespace
-Return the local context and namespace for the current buffer as a
-cons cell @w{@code{(@var{context} . @var{namespace})}}.
-@end defun
-
-@node Transient Menus
-@section Transient Menus
-
-Kubed provides a set of keyboard-driven @dfn{transient menus}
-(@pxref{Top,,,transient}) that you can use to explore and invoke
-various commands.  Transient menus show you available commands along
-with their key bindings, which helps you use many different commands
-without the need to remember the key bindings for all them.
-Additionally, the transient menus allow you to specify options and
-switches for the commands you invoke, which may not be available when
-invoking these commands directly.  For example, while you can invoke
-command @code{kubed-logs} directly to view logs from a container
-running in Kubernetes, the ``Kubernetes Logs'' transient menu which
-you open with @code{kubed-transient-logs} lets you set a maximum
-number of logs to retrieve, among other knobs and handles.
-
-@ifhtml
-@float
-
-@image{/assets/kubed-transient,,,Image: The Kubed main transient menu,.png}
-
-@image{/assets/kubed-transient-exec,,,Image: The Kubed Exec transient menu,.png}
-
-@caption{Explore Kubed commands with transient menus}
-@end float
-@end ifhtml
-
-Command @code{kubed-transient} opens the Kubed ``root'' transient
-menu, which is a dispatch that lets you access different transient
-menus, such as the aforementioned ``Kubernetes Logs'' transient menu.
-It's a good idea to bind @code{kubed-transient} to a convenient key,
-either in the global keymap or under @code{kubed-prefix-map}:
-
-@lisp
-(keymap-global-set "s-k" #'kubed-transient)
-(keymap-set kubed-prefix-map "k" #'kubed-transient)
-@end lisp
-
-In Kubed resource list buffers, type @kbd{?} to pop up a transient
-menu with commands that are specific to the type of resources the
-buffer displays.  @xref{Browse Resources}.
-
-@node Scale Deployment
-@section Scale Deployment
-
-You can use Kubed to @dfn{scale} Kubernetes a deployment, which means
-setting the size of the deployment in terms of the number of replicas
-it governs.
-
-@deffn Command kubed-scale-deployment
-Scale a Kubernetes deployment.
-@end deffn
-
-@code{kubed-scale-deployment} is bound to @kbd{$} in the
-@code{kubed-deployment-prefix-map}, so if you have
-@code{kubed-prefix-map} bound to @kbd{C-c k} then you can invoke it
-with @kbd{C-c k d $}.  @xref{Definition of kubed-prefix-map}.  This
-command prompts you for a deployment and then lets you select a new
-number of replicas for that deployment.  By default you are prompted
-for deployment in the local context and namespace (@pxref{Context and
-Namespace}); with a prefix argument, you can specify a different
-namespace; with a double prefix argument (@kbd{C-u C-u}), you can
-specify a different context too.
-
-In the deployments list buffer, you can scale the deployment at point
-by simply typing @kbd{$}.  @xref{Browse Resources}.
-
-@ifhtml
-@float
-@image{/assets/kubed-scale-deployments,,,Image: Help transient menu in Kubed deployments list buffer,.png}
-@caption{Scale deployments with @kbd{$} in the deployments list buffer}
-@end float
-@end ifhtml
-
-Lastly, you can scale deployments using the transient menu
-@code{kubed-transient-scale-deployment}, which is available from the
-main Kubed transient by pressing @kbd{$}.  @xref{Transient Menus}.
-
-@node Extending Kubed
-@chapter Extending Kubed
-
-Kubed has built-in support for many common types of Kubernetes
-resources.  ``Support'' for a resource type in Kubed just means
-providing common commands for working with resources of that type,
-such as a command for showing the interactive list of these resources,
-like @code{kubed-list-pods} for Kubernetes pods.  In Kubed, the macro
-@code{kubed-define-resource} is used to define these common commands
-and add support for more resource types:
-
-@deffn Macro kubed-define-resource resource &optional properties &rest [ keyword argument ]@dots{} commands
-Define commands for @var{resource}.
-@end deffn
-
-Say you want to add support for your Kubernetes service accounts.
-With @code{kubed-define-resource}, all you need to do is to add the
-following line to your Emacs initialization file:
-
-@lisp
-(kubed-define-resource serviceaccount)
-@end lisp
-
-This line defines the following commands for you:
-
-@itemize
-@item
-@code{kubed-display-serviceaccount}
-@item
-@code{kubed-list-serviceaccounts}
-@item
-@code{kubed-edit-serviceaccount}
-@item
-@code{kubed-delete-serviceaccount}
-@item
-@code{kubed-create-serviceaccount}
-@item
-@code{kubed-explain-serviceaccounts}
-@end itemize
-
-See the documentation string of @code{kubed-define-resource}
-(@w{@kbd{C-h f}}) for details about the optional arguments of this
-macro: the @var{properties} argument which lets you specify what Kubed
-should show in the resource list buffer and the @code{commands} argument
-which lets you associate additional commands with your resource type.
-
-@node Contributing
-@chapter Contributing
-
-We highly appreciate all contributions, including bug reports,
-patches, improvement suggestions, and general feedback!
-
-The best way to get in touch with the Kubed maintainers is via
-@uref{https://lists.sr.ht/~eshel/kubed-devel, the Kubed mailing list}.
-
-@deffn Command kubed-submit-bug-report
-Report a bug in Kubed to the maintainers via mail.
-@end deffn
-
-You can use the command @kbd{M-x kubed-submit-bug-report} to easily
-contact the Kubed maintainers from within Emacs.  This command opens a
-new buffer with a message template ready to be sent to the development
-mailing list.
-
-@node Indices
-@unnumbered Indices
-
-@menu
-* Function Index::
-* Variable Index::
-* Keystroke Index::
-* Concept Index::
-@end menu
-
-@node Function Index
-@unnumberedsec Function index
-
-@printindex fn
-
-@node Variable Index
-@unnumberedsec Variable index
-
-@printindex vr
-
-@node Keystroke Index
-@unnumberedsec Keystroke index
-
-@printindex ky
-
-@node Concept Index
-@unnumberedsec Concept index
-
-@printindex cp
-
-@bye
diff --git a/elpa/kubed-0.5.0.signed b/elpa/kubed-0.5.0.signed
new file mode 100644 (file)
index 0000000..6bef68e
--- /dev/null
@@ -0,0 +1 @@
+Good signature from 645357D2883A0966 GNU ELPA Signing Agent (2023) <elpasignNOSPAMelpa.gnu.org> (trust undefined) created at 2025-06-11T23:05:01+0200 using EDDSA
\ No newline at end of file
diff --git a/elpa/kubed-0.5.0/.elpaignore b/elpa/kubed-0.5.0/.elpaignore
new file mode 100644 (file)
index 0000000..afa5a63
--- /dev/null
@@ -0,0 +1,5 @@
+.dir-locals.el
+README.md
+kubed.png
+explain-and-patch.png
+pod-context-menu.png
diff --git a/elpa/kubed-0.5.0/LICENSE b/elpa/kubed-0.5.0/LICENSE
new file mode 100644 (file)
index 0000000..cfd527c
--- /dev/null
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2024-2025 Eshel Yaron
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/elpa/kubed-0.5.0/NEWS.org b/elpa/kubed-0.5.0/NEWS.org
new file mode 100644 (file)
index 0000000..c8dd79a
--- /dev/null
@@ -0,0 +1,156 @@
+#+title:                 Kubed NEWS -- history of user-visible changes
+#+author:                Eshel Yaron
+#+email:                 meNOSPAMeshelyaron.com
+#+language:              en
+#+options:               ':t toc:nil num:nil ^:{}
+
+This file contains the release notes for Kubed, a rich Emacs interface
+for Kubernetes.
+
+For further details, see the Kubed manual:
+[[https://eshelyaron.com/kubed.html][https://eshelyaron.com/kubed.html]].
+
+* Version 0.5.0 on 2025-06-11
+
+** DaemonSets support
+
+Kubed now provides commands for working with DaemonSets by default.
+Remember that you can always configure support for additional resource
+types with the ~kubed-define-resource~ macro!
+
+** Fix Tramp integration for context names with non-alphanumeric characters
+
+This version fixes an issue in the Kubed integration with Tramp, which
+caused it to fail for ~kubectl~ contexts whose name includes ":" and
+most other non-alphanumeric characters.
+
+See bug report at https://lists.sr.ht/~eshel/kubed-devel/%3C87ldqz70a6.fsfNOSPAMgmail.com%3E
+
+* Version 0.4.3 on 2025-01-21
+
+This is a maintenance release, it includes minor improvements and one
+important bug fix:
+
+** Fix 'kubed-list-delete-marked' in non-default context
+
+Marking resources with ~d~ and deleting them with ~x~ now works also
+in resource tables of resources in non-default contexts or namespaces.
+
+* Version 0.4.2 on 2024-10-22
+
+** New user option 'kubed-list-mode-line-format'
+
+This user option lets you customize the indicator that Kubed shows in
+the mode line of resource table buffers when update is in progress.
+
+** Fix Tramp method autoload issue
+
+This version arranges for the Kubed Tramp integration to be loaded
+earlier, which circumvents the "Method ‘kubedv1’ is not known" error
+that some users have experienced.
+
+* Version 0.4.1 on 2024-09-23
+
+** New command and transient menu for scaling deployments
+
+You can now scale Kubernetes deployment with Kubed, directly with
+~kubed-scale-deployment~, from the deployments table buffer, or via
+the new transient menu ~kubed-transient-scale-deployment~.
+
+** New commands and transient menu for managing Kubernetes API proxies
+
+You can now use Kubed to create proxy servers that give access to the
+Kubernetes API server.  The commands ~kubed-proxy~ and
+~kubed-stop-proxy~ start and stop proxy servers, respectively.  The
+new transient menu ~kubed-transient-proxy~ lets specify options when
+starting a proxy, such as the local port to use.
+
+* Version 0.4.0 on 2024-08-23
+
+** ~kubed-list-update~ is now bound to ~g~ in resource table buffers.
+
+Previously, this command was bound to the slightly less convenient
+capital ~G~.  This shadows the default binding of ~revert-buffer~,
+which you can still invoke via ~C-x x g~.
+
+** Introduce resource type specific bindings in resource table help transients.
+
+The help transient menu that you get with ~?~ in resource table
+buffers now includes type-specific bindings, such as the ~F~ key for
+forwarding a local port to a pod in the Kubed pods buffer.
+
+** New transient menu ~kubed-transient-logs~ for showing container logs.
+
+** Improved Tramp integration.
+
+Kubed now uses a bespoke Tramp method to open Dired and Shell buffers
+inside Kubernetes pods.  The main advantage of this method is the
+ability to work with multiple ~kubectl~ contexts simultaneously.  This
+method requires Tramp 2.7 or later, Kubed will complain if you try to
+start remote Dired or Shell with an earlier Tramp version.
+
+* Version 0.3.2 on 2024-08-15
+
+** Improved support for multiple contexts and namespaces
+
+Each buffer now has a local context and namespace, which acts as the
+default/current context and namespace when you invoke Kubed commands
+from that buffer.  See new manual section "Context and Namespace" for
+more details.
+
+** New filter operators ~<~ and ~>~ in resource tables.
+
+These operators let you filter line with columns that are less than or
+greater than a given value.
+
+** New command for applying changes to displayed resource.
+
+You can now edit displayed resource YAML buffers after you select a
+resource with ~RET~ in the table buffer, and apply your changes to the
+live resource with ~C-c C-c~.
+
+* Version 0.3.1 on 2024-08-06
+
+** New command for fitting column width to content in resource tables.
+
+** New transient menu showing help in resource table buffers.
+
+* Version 0.3.0 on 2024-08-05
+
+** New command for copying name of resource at point to kill ring.
+
+** New commands for running ~kubectl~ command on resource at point.
+
+** Support bookmarking resource list and resource details buffers.
+
+** New command for jumping from resource details buffer to list buffer.
+
+** Fix installation on Doom Emacs.
+
+** New transient menu for displaying resources.
+
+** Support multiple resource list buffers with different namespaces or contexts.
+
+* Version 0.2.0 on 2024-08-02
+
+** Ensure compatibility with Emacs 29.
+
+** Add right-click context menus in resource tables.
+
+** New menu-bar "Kubernetes" menu.
+
+** New commands for restarting and watching deployments.
+
+** Add filtering capability to all resource tables.
+
+** New cron job commands: suspend, resume, and start job now.
+
+** New commands for patching resources.
+
+** New useful columns in services table and deployments table.
+
+** Use multi-column layout in transient menus.
+
+* Version 0.1.0 on 2024-07-28
+
+Initial release.
diff --git a/elpa/kubed-0.5.0/assets/kubed-deployment-prefix-map.png b/elpa/kubed-0.5.0/assets/kubed-deployment-prefix-map.png
new file mode 100644 (file)
index 0000000..19551b1
Binary files /dev/null and b/elpa/kubed-0.5.0/assets/kubed-deployment-prefix-map.png differ
diff --git a/elpa/kubed-0.5.0/assets/kubed-list-transient.png b/elpa/kubed-0.5.0/assets/kubed-list-transient.png
new file mode 100644 (file)
index 0000000..c0fdb28
Binary files /dev/null and b/elpa/kubed-0.5.0/assets/kubed-list-transient.png differ
diff --git a/elpa/kubed-0.5.0/assets/kubed-overview.png b/elpa/kubed-0.5.0/assets/kubed-overview.png
new file mode 100644 (file)
index 0000000..b74db91
Binary files /dev/null and b/elpa/kubed-0.5.0/assets/kubed-overview.png differ
diff --git a/elpa/kubed-0.5.0/assets/kubed-prefix-map.png b/elpa/kubed-0.5.0/assets/kubed-prefix-map.png
new file mode 100644 (file)
index 0000000..0f0d609
Binary files /dev/null and b/elpa/kubed-0.5.0/assets/kubed-prefix-map.png differ
diff --git a/elpa/kubed-0.5.0/assets/kubed-replace-diff.png b/elpa/kubed-0.5.0/assets/kubed-replace-diff.png
new file mode 100644 (file)
index 0000000..6e6d07a
Binary files /dev/null and b/elpa/kubed-0.5.0/assets/kubed-replace-diff.png differ
diff --git a/elpa/kubed-0.5.0/assets/kubed-scale-deployments.png b/elpa/kubed-0.5.0/assets/kubed-scale-deployments.png
new file mode 100644 (file)
index 0000000..3f51ecd
Binary files /dev/null and b/elpa/kubed-0.5.0/assets/kubed-scale-deployments.png differ
diff --git a/elpa/kubed-0.5.0/assets/kubed-transient-exec.png b/elpa/kubed-0.5.0/assets/kubed-transient-exec.png
new file mode 100644 (file)
index 0000000..5f412e8
Binary files /dev/null and b/elpa/kubed-0.5.0/assets/kubed-transient-exec.png differ
diff --git a/elpa/kubed-0.5.0/assets/kubed-transient.png b/elpa/kubed-0.5.0/assets/kubed-transient.png
new file mode 100644 (file)
index 0000000..97fa375
Binary files /dev/null and b/elpa/kubed-0.5.0/assets/kubed-transient.png differ
diff --git a/elpa/kubed-0.5.0/cobra.el b/elpa/kubed-0.5.0/cobra.el
new file mode 100644 (file)
index 0000000..c7d5ffb
--- /dev/null
@@ -0,0 +1,143 @@
+;;; cobra.el --- Complete Cobra command lines   -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024-2025  Free Software Foundation, Inc.
+
+;; Author: Eshel Yaron <meNOSPAMeshelyaron.com>
+;; Keywords: tools
+
+;;; Commentary:
+
+;; Cobra is a popular Golang framework for CLI programs.  This library
+;; defines function `cobra-read-command-line', which helps you read a
+;; command line for a program that uses Cobra, with completion.
+;; Prominent examples of Cobra programs are `kubectl' and `docker'.
+
+;;; Code:
+
+(defvar cobra--cache nil)
+
+(defun cobra-completion-table (executable s p a)
+  "Completion table for command lines that invoke EXECUTABLE.
+
+Perform completion action A on string S with predicate P."
+  (let ((start 0))
+    (while (string-match "[[:space:]=]" s start)
+      (setq start (match-end 0)))
+    (if (eq a 'metadata)
+        `(metadata
+          (category . cobra-command-line)
+          (affixation-function
+           . ,(lambda (cands)
+                (let ((max (seq-max
+                            (cons 0 (mapcar #'string-width cands)))))
+                  (mapcar
+                   (lambda (cand)
+                     (list
+                      cand ""
+                      (if-let
+                          ((desc (get-text-property
+                                  0 'cobra-argument-description
+                                  cand)))
+                          (concat
+                           (make-string (1+ (- max (string-width cand))) ?\s)
+                           (propertize desc 'face 'completions-annotations))
+                        "")))
+                   cands)))))
+      (let* ((lines
+              (cdr
+               (if (string= s (car cobra--cache))
+                   ;; Cache hit.
+                   cobra--cache
+                 (setq
+                  cobra--cache
+                  (cons s
+                        (apply #'process-lines-ignore-status
+                               executable "__complete"
+                               (let ((args (cdr (split-string-and-unquote s))))
+                                 (if (string-suffix-p " " s)
+                                     ;; Restore omitted empty argument.
+                                     (nconc args '(""))
+                                   args))))))))
+             (code nil)
+             (comps (seq-take-while
+                     (lambda (line)
+                       (not (and (string-match "^:\\([0-9]+\\)$" line)
+                                 (setq code (string-to-number
+                                             (match-string 1 line))))))
+                     lines)))
+        ;; `code' encodes "completion directives", as follows:
+        ;; #b000001: An error occurred, ignore completions.
+        ;; #b000010: Don't add space after completion.  (TODO.)
+        ;; #b000100: Don't fall back to file completion.
+        ;; #b001000: Completions are really file extension filters.
+        ;; #b010000: Complete directory names.
+        ;; #b100000: Preserve completions order.
+        (when (and code (zerop (logand 1 code)))
+          ;; Error bit in unset, proceed.
+          (if (= #b100 (logand #b100 code))
+              ;; No file name completion.
+              (if (eq (car-safe a) 'boundaries)
+                  `(boundaries
+                    ,start . ,(and (string-match "[[:space:]=]" (cdr a))
+                                   (match-beginning 0)))
+                (let ((table
+                       (mapcar
+                        ;; Annotate completion candidates.
+                        (lambda (comp)
+                          (pcase (split-string comp "\t" t)
+                            (`(,c ,d . ,_)
+                             (propertize
+                              c 'cobra-argument-description
+                              ;; Only keep first sentence.
+                              (car (split-string d "\\." t))))
+                            (`(,c . ,_)  c)))
+                        comps)))
+                  (if a (complete-with-action a table (substring s start) p)
+                    ;; `try-completion'.
+                    (let ((comp (complete-with-action a table (substring s start) p)))
+                      (if (stringp comp) (concat (substring s 0 start) comp) comp)))))
+            ;; File name completion.
+            (setq p
+                  (cond
+                   ((= #b1000 (logand #b1000 code))
+                    ;; `comps' are valid extensions.
+                    (lambda (f)
+                      (or (file-directory-p f)
+                          (when (string-match "\\.[^.]*\\'" f)
+                            (member (substring f (1+ (match-beginning 0)))
+                                    comps)))))
+                   ((= #b10000 (logand #b10000 code))
+                    ;; Directory name completion.
+                    #'file-directory-p)))
+            (if (eq (car-safe a) 'boundaries)
+                ;; Find nested boundaries.
+                (let* ((suf (cdr a))
+                       (bounds (completion-boundaries
+                                (substring s start) #'completion-file-name-table p
+                                (substring suf 0 (string-match "[[:space:]=]" suf)))))
+                  `(boundaries ,(+ (car bounds) start) . ,(cdr bounds)))
+              (if a (complete-with-action a #'completion-file-name-table
+                                          (substring s start) p)
+                (let ((comp (complete-with-action a #'completion-file-name-table
+                                                  (substring s start) p)))
+                  (if (stringp comp) (concat (substring s 0 start) comp) comp))))))))))
+
+;;;###autoload
+(defun cobra-read-command-line (prompt initial &optional hist)
+  "Prompt with PROMPT for a command line starting with INITIAL.
+
+Optional argument HIST is the name of the history list variable to use,
+if it is nil or omitted, it defaults to `shell-command-history'."
+  (let ((exec (car (split-string-and-unquote (car (ensure-list initial))))))
+    (minibuffer-with-setup-hook
+        (:append (lambda ()
+                   (let ((map (make-sparse-keymap)))
+                     ;; Ensure SPC is self-inserting.
+                     (keymap-unset map "SPC")
+                     (use-local-map
+                      (make-composed-keymap map (current-local-map))))))
+      (completing-read prompt (apply-partially #'cobra-completion-table exec)
+                       nil nil initial (or hist 'shell-command-history)))))
+
+(provide 'cobra)
+;;; cobra.el ends here
diff --git a/elpa/kubed-0.5.0/dir b/elpa/kubed-0.5.0/dir
new file mode 100644 (file)
index 0000000..c2a3104
--- /dev/null
@@ -0,0 +1,18 @@
+This is the file .../info/dir, which contains the
+topmost node of the Info hierarchy, called (dir)Top.
+The first time you invoke Info you start off looking at this node.
+\1f
+File: dir,     Node: Top       This is the top of the INFO tree
+
+  This (the Directory node) gives a menu of major topics.
+  Typing "q" exits, "H" lists all Info commands, "d" returns here,
+  "h" gives a primer for first-timers,
+  "mEmacs<Return>" visits the Emacs manual, etc.
+
+  In Emacs, you can click mouse button 2 on a menu item or cross reference
+  to select it.
+
+* Menu:
+
+Emacs
+* Kubed: (kubed).               Kubernetes, Emacs, done!
diff --git a/elpa/kubed-0.5.0/kubed-autoloads.el b/elpa/kubed-0.5.0/kubed-autoloads.el
new file mode 100644 (file)
index 0000000..e727490
--- /dev/null
@@ -0,0 +1,509 @@
+;;; kubed-autoloads.el --- automatically extracted autoloads (do not edit)   -*- lexical-binding: t -*-
+;; Generated by the `loaddefs-generate' function.
+
+;; This file is part of GNU Emacs.
+
+;;; Code:
+
+(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
+
+
+\f
+;;; Generated autoloads from cobra.el
+
+(autoload 'cobra-read-command-line "cobra" "\
+Prompt with PROMPT for a command line starting with INITIAL.
+
+Optional argument HIST is the name of the history list variable to use,
+if it is nil or omitted, it defaults to `shell-command-history'.
+
+(fn PROMPT INITIAL &optional HIST)")
+(register-definition-prefixes "cobra" '("cobra-"))
+
+\f
+;;; Generated autoloads from kubed.el
+
+(autoload 'kubed-display-resource "kubed" "\
+Display Kubernetes RESOURCE of type TYPE in CONTEXT.
+
+For namespaced resource types, NAMESPACE is the namespace of RESOURCE.
+
+Interactively, use the current context and namespace by default, and
+prompt for TYPE and RESOURCE.  With a prefix argument \\[universal-argument],
+prompt for NAMESPACE.  With a double prefix argument \\[universal-argument] \\[universal-argument],
+prompt for CONTEXT as well.
+
+(fn TYPE RESOURCE CONTEXT &optional NAMESPACE)" t)
+(autoload 'kubed-display-resource-handle-bookmark "kubed" "\
+Display Kubernetes resource according to BOOKMARK.
+
+(fn BOOKMARK)")
+(autoload 'kubed-list-handle-bookmark "kubed" "\
+Display Kubernetes resource according to BOOKMARK.
+
+(fn BOOKMARK)")
+(autoload 'kubed-delete-resources "kubed" "\
+Delete Kubernetes RESOURCES of type TYPE in context CONTEXT.
+
+For namespaced resource types, NAMESPACE is the namespace of RESOURCE.
+
+Interactively, use the current context and namespace by default, and
+prompt for TYPE and RESOURCES.  With a prefix argument \\[universal-argument],
+prompt for NAMESPACE.  With a double prefix argument \\[universal-argument] \\[universal-argument],
+prompt for CONTEXT as well.
+
+(fn TYPE RESOURCES CONTEXT &optional NAMESPACE)" t)
+(autoload 'kubed-edit-resource "kubed" "\
+Edit Kubernetes RESOURCE of type TYPE in context CONTEXT.
+
+For namespaced resource types, NAMESPACE is the namespace of RESOURCE.
+
+Interactively, use the current context and namespace by default, and
+prompt for TYPE and RESOURCES.  With a prefix argument \\[universal-argument],
+prompt for NAMESPACE.  With a double prefix argument \\[universal-argument] \\[universal-argument],
+prompt for CONTEXT as well.
+
+(fn TYPE RESOURCE CONTEXT &optional NAMESPACE)" t)
+(autoload 'kubed-define-resource "kubed" "\
+Define Kubernetes RESOURCE with associated PROPERTIES and COMMANDS.
+
+RESOURCE is a symbol corresponding to a Kubernetes resource type, such
+as `pod' or `service'.  This macro defines the following commands for
+interacting with Kubernetes RESOURCEs:
+
+- `kubed-display-RESOURCE': prompt for a RESOURCE and display its
+  description in YAML format.  See also `kubed-yaml-setup-hook'.
+- `kubed-edit-RESOURCE': prompt for a RESOURCE and edit it.
+- `kubed-delete-RESOURCE': prompt for a RESOURCE and delete it.
+- `kubed-list-RESOURCEs': display a buffer listing all RESOURCEs in the
+  current namespace.  The RESOURCEs list buffer uses a dedicated major
+  mode, `kubed-RESOURCEs-mode', which is also defined by this macro.
+- `kubed-create-RESOURCE': create a RESOURCE from a YAML or a JSON file.
+- `kubed-explain-RESOURCEs': show buffer with help about RESOURCEs.
+
+This macro also defines a prefix keymap, `kubed-RESOURCE-prefix-map',
+with bindings for the above commands.
+
+PROPERTIES is a list of lists (PROP JSON-PATH WIDTH SORT FORMAT . ATTRS)
+that specify properties of RESOURCEs.  PROP is the name of the property,
+as a symbol; JSON-PATH is a JSONPath expression that evaluates to the
+value of PROP when applied to the JSON representation of a RESOURCE.
+WIDTH, SORT, FORMAT and ATTRS are optional and can be omitted.  WIDTH is
+used as the default width of the column corresponding to PROP in
+RESOURCEs list buffers; SORT is sort predicate, a function that takes
+two values of PROP as strings and returns non-nil if the first should
+sort before the second; FORMAT is a function that takes a value of PROP
+and formats it.  If you provide a FORMAT function and a SORT function,
+then the SORT function gets the formatted values (the output of the
+FORMAT function), not the original values.  If you want to sort based on
+the unformatted original values, you can store them as text properties
+in your FORMAT function and access them in your SORT function.
+
+ATTRS is a plist of additional attributes of the PROP column, see
+`tabulated-list-format' for available attributes.
+
+For example, if PROPERTIES is (phase \".status.phase\" 10) that means
+that RESOURCE has a `phase' property at JSONPath \".status.phase\" whose
+values are typically 10 columns wide.  The first property in PROPERTIES
+is used to annotate completion candidates when prompting for a RESOURCE.
+
+COMMANDS is a list of elements (COMMAND KEYS DOC-PREFIX . BODY) that
+define commands for RESOURCE list buffers.  COMMAND is a symbol
+specifying the suffix of the command name, the full name of the command
+is `kubed-RESOURCEs-COMMAND' (for example, `kubed-pods-shell'); KEYS is
+either a string that specifies a key sequence to bind to the command in
+`kubed-RESOURCEs-mode-map', or nil if the command should not be bound;
+DOC-PREFIX is a string used to construct the docstring of the command,
+this macro appends the string \" Kubernetes RESOURCE at point.\" to it
+to obtain the final docstring; lastly, BODY is the body the command.
+Within BODY, the variable RESOURCE is let-bound to the name of the
+RESOURCE at point.  For example, if RESOURCE is `pod', the following
+COMMANDS element defines a command `kubed-pods-frob' and binds it to the
+key \"f\" in `kubed-pods-mode-map':
+
+  (frob \"f\" \"Frobnicate\"
+        (message \"Preparing...\")
+        (frobnicate-pod pod)
+        (message \"Done.\"))
+
+By default, this macro assumes that RESOURCE is namespaced.  To define a
+namespaceless resource type, put `:namespaced nil' before COMMANDS:
+
+  (kubed-define-resource global-thingy (PROP1 PROP2 ...) :namespaced nil
+    CMD1
+    CMD2
+    ...)
+
+Other keyword arguments that go between PROPERTIES and COMMANDS are:
+
+- `:create (ARGLIST DOCSTRING INTERACTIVE BODY...)': specialize the
+  resource creation command, `kubed-create-RESOURCE'.  ARGLIST,
+  DOCSTRING, INTERACTIVE and BODY have the same meaning as in `defun'.
+- `:prefix ((KEY LABEL DEFINITION)...)': additional keybinding for the
+  prefix keymap `kubed-RESOURCE-prefix-map' and the
+  `kubed-RESOURCE-menu-map' menu.  Each element (KEY LABEL DEFINITION)
+  says to bind KEY to DEFINITION in `kubed-RESOURCE-menu-map', and to
+  add DEFINITION to `kubed-RESOURCE-menu-map' with the label LABEL.
+- `:plural PLURAL': specify plural form of RESOURCE, as a symbol.  If
+  you omit this keyword argument, the plural form defaults to RESOURCE
+  followed by \"s\".
+- `:logs t': generate `kubed-logs-for-RESOURCE' command.
+- `:suffixes (SUFFIX...)': add type-specific transient suffixes to
+  `kubed-list-transient'.
+
+(fn RESOURCE &optional PROPERTIES &rest COMMANDS)" nil t)
+(function-put 'kubed-define-resource 'lisp-indent-function 2)
+ (autoload 'kubed-display-pod "kubed" nil t)
+ (autoload 'kubed-edit-pod "kubed" nil t)
+ (autoload 'kubed-delete-pods "kubed" nil t)
+ (autoload 'kubed-list-pods "kubed" nil t)
+ (autoload 'kubed-create-pod "kubed" nil t)
+ (autoload 'kubed-logs-for-pod "kubed" nil t)
+ (autoload 'kubed-pod-prefix-map "kubed" nil t 'keymap)
+ (autoload 'kubed-display-namespace "kubed" nil t)
+ (autoload 'kubed-edit-namespace "kubed" nil t)
+ (autoload 'kubed-delete-namespaces "kubed" nil t)
+ (autoload 'kubed-list-namespaces "kubed" nil t)
+ (autoload 'kubed-create-namespace "kubed" nil t)
+ (autoload 'kubed-namespace-prefix-map "kubed" nil t 'keymap)
+ (autoload 'kubed-display-persistentvolume "kubed" nil t)
+ (autoload 'kubed-edit-persistentvolume "kubed" nil t)
+ (autoload 'kubed-delete-persistentvolumes "kubed" nil t)
+ (autoload 'kubed-list-persistentvolumes "kubed" nil t)
+ (autoload 'kubed-create-persistentvolume "kubed" nil t)
+ (autoload 'kubed-persistentvolume-prefix-map "kubed" nil t 'keymap)
+ (autoload 'kubed-display-service "kubed" nil t)
+ (autoload 'kubed-edit-service "kubed" nil t)
+ (autoload 'kubed-delete-services "kubed" nil t)
+ (autoload 'kubed-list-services "kubed" nil t)
+ (autoload 'kubed-create-service "kubed" nil t)
+ (autoload 'kubed-logs-for-service "kubed" nil t)
+ (autoload 'kubed-service-prefix-map "kubed" nil t 'keymap)
+ (autoload 'kubed-display-secret "kubed" nil t)
+ (autoload 'kubed-edit-secret "kubed" nil t)
+ (autoload 'kubed-delete-secrets "kubed" nil t)
+ (autoload 'kubed-list-secrets "kubed" nil t)
+ (autoload 'kubed-create-secret "kubed" nil t)
+ (autoload 'kubed-secret-prefix-map "kubed" nil t 'keymap)
+ (autoload 'kubed-display-job "kubed" nil t)
+ (autoload 'kubed-edit-job "kubed" nil t)
+ (autoload 'kubed-delete-jobs "kubed" nil t)
+ (autoload 'kubed-list-jobs "kubed" nil t)
+ (autoload 'kubed-create-job "kubed" nil t)
+ (autoload 'kubed-logs-for-job "kubed" nil t)
+ (autoload 'kubed-job-prefix-map "kubed" nil t 'keymap)
+(autoload 'kubed-watch-deployment-status "kubed" "\
+Show and update status of Kubernetes deployment DEP in a dedicate buffer.
+
+Optional argument CONTEXT is the `kubectl' context to use, defaulting to
+the current context; NAMESPACE is the namespace of DEP, defaulting to
+the current namespace.  CB is an optional callback function to call with
+no arguments when the deployment ends.
+
+Interactively, prompt for DEP.  With a prefix argument, prompt for
+NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
+
+(fn DEP &optional CONTEXT NAMESPACE CB)" t)
+(autoload 'kubed-scale-deployment "kubed" "\
+Scale deployment DEP in namespace NAMESPACE via CONTEXT to REPS replicas.
+
+Optional argument CONTEXT is the `kubectl' context to use, defaulting to
+the current context; NAMESPACE is the namespace of DEP, defaulting to
+the current namespace.
+
+Interactively, prompt for DEP.  With a prefix argument, prompt for
+NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
+
+(fn DEP REPS &optional CONTEXT NAMESPACE)" t)
+(autoload 'kubed-restart-deployment "kubed" "\
+Restart Kubernetes deployment DEP in namespace NAMESPACE via CONTEXT.
+
+Optional argument CONTEXT is the `kubectl' context to use, defaulting to
+the current context; NAMESPACE is the namespace of DEP, defaulting to
+the current namespace.  CB is an optional callback function to call with
+no arguments when the deployment ends.
+
+Interactively, prompt for DEP.  With a prefix argument, prompt for
+NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
+
+(fn DEP &optional CONTEXT NAMESPACE)" t)
+ (autoload 'kubed-display-deployment "kubed" nil t)
+ (autoload 'kubed-edit-deployment "kubed" nil t)
+ (autoload 'kubed-delete-deployments "kubed" nil t)
+ (autoload 'kubed-list-deployments "kubed" nil t)
+ (autoload 'kubed-create-deployment "kubed" nil t)
+ (autoload 'kubed-logs-for-deployment "kubed" nil t)
+ (autoload 'kubed-deployment-prefix-map "kubed" nil t 'keymap)
+ (autoload 'kubed-display-replicaset "kubed" nil t)
+ (autoload 'kubed-edit-replicaset "kubed" nil t)
+ (autoload 'kubed-delete-replicasets "kubed" nil t)
+ (autoload 'kubed-list-replicasets "kubed" nil t)
+ (autoload 'kubed-create-replicaset "kubed" nil t)
+ (autoload 'kubed-logs-for-replicaset "kubed" nil t)
+ (autoload 'kubed-replicaset-prefix-map "kubed" nil t 'keymap)
+ (autoload 'kubed-display-daemonset "kubed" nil t)
+ (autoload 'kubed-edit-daemonset "kubed" nil t)
+ (autoload 'kubed-delete-daemonsets "kubed" nil t)
+ (autoload 'kubed-list-daemonsets "kubed" nil t)
+ (autoload 'kubed-create-daemonset "kubed" nil t)
+ (autoload 'kubed-logs-for-daemonset "kubed" nil t)
+ (autoload 'kubed-daemonset-prefix-map "kubed" nil t 'keymap)
+ (autoload 'kubed-display-statefulset "kubed" nil t)
+ (autoload 'kubed-edit-statefulset "kubed" nil t)
+ (autoload 'kubed-delete-statefulsets "kubed" nil t)
+ (autoload 'kubed-list-statefulsets "kubed" nil t)
+ (autoload 'kubed-create-statefulset "kubed" nil t)
+ (autoload 'kubed-logs-for-statefulset "kubed" nil t)
+ (autoload 'kubed-statefulset-prefix-map "kubed" nil t 'keymap)
+ (autoload 'kubed-display-cronjob "kubed" nil t)
+ (autoload 'kubed-edit-cronjob "kubed" nil t)
+ (autoload 'kubed-delete-cronjobs "kubed" nil t)
+ (autoload 'kubed-list-cronjobs "kubed" nil t)
+ (autoload 'kubed-create-cronjob "kubed" nil t)
+ (autoload 'kubed-cronjob-prefix-map "kubed" nil t 'keymap)
+ (autoload 'kubed-display-ingressclass "kubed" nil t)
+ (autoload 'kubed-edit-ingressclass "kubed" nil t)
+ (autoload 'kubed-delete-ingressclasses "kubed" nil t)
+ (autoload 'kubed-list-ingressclasss "kubed" nil t)
+ (autoload 'kubed-create-ingressclass "kubed" nil t)
+ (autoload 'kubed-ingressclass-prefix-map "kubed" nil t 'keymap)
+ (autoload 'kubed-display-ingress "kubed" nil t)
+ (autoload 'kubed-edit-ingress "kubed" nil t)
+ (autoload 'kubed-delete-ingresses "kubed" nil t)
+ (autoload 'kubed-list-ingresss "kubed" nil t)
+ (autoload 'kubed-create-ingress "kubed" nil t)
+ (autoload 'kubed-ingress-prefix-map "kubed" nil t 'keymap)
+(autoload 'kubed-use-context "kubed" "\
+Set current Kubernetes context to CONTEXT.
+
+(fn CONTEXT)" t)
+(autoload 'kubed-rename-context "kubed" "\
+Rename Kubernetes context OLD to NEW.
+
+(fn OLD NEW)" t)
+(autoload 'kubed-display-config "kubed" "\
+Display current Kubernetes client settings in a YAML buffer." t)
+(autoload 'kubed-set-namespace "kubed" "\
+Set default Kubernetes namespace in CONTEXT to NAMESPACE.
+
+Interactively, prompt for NAMESPACE and use the current context.  With a
+prefix argument, prompt for CONTEXT as well.
+
+(fn NAMESPACE &optional CONTEXT)" t)
+(autoload 'kubed-apply "kubed" "\
+Apply CONFIG to Kubernetes resource of kind KIND via CONTEXT.
+
+(fn CONFIG &optional KIND CONTEXT)" t)
+(autoload 'kubed-create "kubed" "\
+Create resource of kind KIND with definition DEFINITION via CONTEXT.
+
+(fn DEFINITION &optional KIND CONTEXT)" t)
+(autoload 'kubed-run "kubed" "\
+Run container IMAGE in a new Kubernetes POD.
+
+Optional argument CONTEXT is the `kubectl' context to use, defaulting to
+the current context.  NAMESPACE is the namespace in which to create POD,
+defaulting to the current namespace.  PORT is the port to expose,
+defaulting to none.  If ATTACH is non-nil, then attach to the created
+image with a `comint-mode' buffer, and pop to that buffer.  Non-nil
+STDIN says to keep the standard input of the container open; non-nil TTY
+says to allocate a TTY for the container; and non-nil RM says to remove
+the container after it exits.  ENVS is a list of strings \"VAR=VAL\"
+which specify environment variables VAR and values VAL to give them in
+the created container.  ARGS are command line arguments for the
+container command.  If COMMAND is non-nil, ARGS consist of a complete
+command line, that overrides the container command instead of just
+providing it with arguments.
+
+Interactively, prompt for POD and IMAGE.  With a prefix argument, prompt
+for NAMESPACE; with a double prefix argument, also prompt for CONTEXT.
+
+(fn POD IMAGE &optional CONTEXT NAMESPACE PORT ATTACH STDIN TTY RM ENVS COMMAND ARGS)" t)
+(autoload 'kubed-logs "kubed" "\
+Show logs for container CONTAINER in Kubernetes RESOURCE of type TYPE.
+
+Optional argument CONTEXT is the `kubectl' context to use; NAMESPACE is
+the namespace for RESOURCE; CONTAINER is the name of the container in
+RESOURCE to show logs for, or t which specifies all relevant containers.
+
+With a prefix argument, prompt for NAMESPACE; with a double prefix
+argument, also prompt for CONTEXT.
+
+(fn TYPE RESOURCE &optional CONTEXT NAMESPACE CONTAINER FOLLOW LIMIT PREFIX SINCE TAIL TIMESTAMPS)" t)
+(autoload 'kubed-forward-port-to-pod "kubed" "\
+Forward LOCAL-PORT to REMOTE-PORT of Kubernetes pod POD.
+
+(fn POD LOCAL-PORT REMOTE-PORT CONTEXT NAMESPACE)" t)
+(autoload 'kubed-attach "kubed" "\
+Attach to running process in CONTAINER in Kubernetes POD.
+
+Optional argument NAMESPACE is the namespace in which to look for POD.
+Non-nil STDIN says to connect local standard input to remote process.
+Non-nil TTY says to use a TTY for standard input.
+
+Interactively, prompt for POD; if there are multiple pod containers,
+prompt for CONTAINER as well.  With a prefix argument, prompt for
+NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
+STDIN and TTY are t interactively.
+
+(fn POD &optional CONTAINER CONTEXT NAMESPACE STDIN TTY)" t)
+(autoload 'kubed-diff "kubed" "\
+Display difference between Kubernetes resource DEFINITION and current state.
+
+DEFINITION is either a file name or a buffer.  Interactively, prompt for
+a YAML or JSON file name to use as DEFINITION.
+
+Optional argument CONTEXT is the `kubectl' context to use, defaulting to
+the current context; non-nil INCLUDE-MANAGED (interactively, the prefix
+argument) says to include managed fields in the comparison.
+
+(fn DEFINITION &optional INCLUDE-MANAGED CONTEXT)" t)
+(autoload 'kubed-exec "kubed" "\
+Execute COMMAND with ARGS in CONTAINER in Kubernetes POD.
+
+Optional argument NAMESPACE is the namespace in which to look for POD.
+Non-nil STDIN says to connect local standard input to remote process.
+Non-nil TTY says to use a TTY for standard input.
+
+Interactively, prompt for POD; if there are multiple pod containers,
+prompt for CONTAINER as well.  With a prefix argument, prompt for
+NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
+STDIN and TTY are t interactively.
+
+(fn POD COMMAND &optional CONTAINER CONTEXT NAMESPACE STDIN TTY ARGS)" t)
+(autoload 'kubed-patch "kubed" "\
+Patch Kubernetes resource NAME of TYPE with patch PATCH.
+
+Optional argument NAMESPACE is the namespace in which to look for NAME.
+STRATEGY is the patch type to use, one of \"json\", \"merge\" and
+\"strategic\", defaulting to \"strategic\".
+
+Interactively, prompt for TYPE, NAME and PATCH.  With a prefix argument,
+prompt for NAMESPACE too.  With a double prefix argument, also prompt
+for CONTEXT.
+
+(fn TYPE NAME PATCH &optional CONTEXT NAMESPACE STRATEGY)" t)
+(autoload 'kubed-proxy "kubed" "\
+Start a web server on localhost proxying the Kubernetes API server.
+
+ADDR and PORT are the local address and port to bind the proxy server
+to.  They default to 127.0.0.1 and 8001, respectively.  API-PREFIX is a
+prefix under which to proxy the Kubernetes API.  WWW-DIR is a local
+directory to serve under WWW-PREFIX, which defaults to \"/static/\".
+Lastly, CONTEXT is the the `kubectl' context to use, defaulting to the
+local context.
+
+(fn &optional ADDR PORT API-PREFIX WWW-DIR WWW-PREFIX CONTEXT)" t)
+(autoload 'kubed-stop-proxy "kubed" "\
+Stop local proxy for context CONTEXT, defaulting to the local context.
+
+(fn &optional CONTEXT)" t)
+(autoload 'kubed-explain "kubed" "\
+Show help buffer with explanation about Kubernetes resource FIELD.
+
+(fn FIELD)" t)
+(autoload 'kubed-kubectl-command "kubed" "\
+Execute `kubectl' COMMAND.
+
+This function calls `shell-command' (which see) to do the work.
+
+Interactively, prompt for COMMAND with completion for `kubectl' arguments.
+
+(fn COMMAND)" t)
+ (autoload 'kubed-prefix-map "kubed" nil t 'keymap)
+(defvar kubed-menu-bar-mode nil "\
+Non-nil if Kubed-Menu-Bar mode is enabled.
+See the `kubed-menu-bar-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `kubed-menu-bar-mode'.")
+(custom-autoload 'kubed-menu-bar-mode "kubed" nil)
+(autoload 'kubed-menu-bar-mode "kubed" "\
+Add \"Kubernetes\" menu to your menu bar.
+
+This is a global minor mode.  If called interactively, toggle the
+`Kubed-Menu-Bar mode' mode.  If the prefix argument is positive, enable
+the mode, and if it is zero or negative, disable the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'.  Enable the
+mode if ARG is nil, omitted, or is a positive number.  Disable the mode
+if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate `(default-value \\='kubed-menu-bar-mode)'.
+
+The mode's hook is called both when the mode is enabled and when it is
+disabled.
+
+(fn &optional ARG)" t)
+(register-definition-prefixes "kubed" '("kubed-"))
+
+\f
+;;; Generated autoloads from kubed-common.el
+
+(register-definition-prefixes "kubed-common" '("kubed-"))
+
+\f
+;;; Generated autoloads from kubed-tramp.el
+
+(autoload 'kubed-tramp-context "kubed-tramp" "\
+Extract `kubectl' context from Kubed Tramp remote file name FILE-NAME.
+
+(fn FILE-NAME)")
+(autoload 'kubed-tramp-namespace "kubed-tramp" "\
+Extract Kubernetes namespace from Kubed Tramp remote file name FILE-NAME.
+
+(fn FILE-NAME)")
+(autoload 'kubed-tramp-assert-support "kubed-tramp" "\
+Check if Kubed Tramp support is available, throw `user-error' if not.")
+(autoload 'kubed-tramp-enable "kubed-tramp" "\
+Enable Kubed integration with Tramp.")
+ (with-eval-after-load 'tramp (kubed-tramp-enable))
+(register-definition-prefixes "kubed-tramp" '("kubed-tramp--"))
+
+\f
+;;; Generated autoloads from kubed-transient.el
+
+ (autoload 'kubed-transient "kubed-transient" nil t)
+ (autoload 'kubed-transient-logs-for-pod "kubed-transient" nil t)
+ (autoload 'kubed-transient-logs-for-deployment "kubed-transient" nil t)
+ (autoload 'kubed-transient-logs-for-service "kubed-transient" nil t)
+ (autoload 'kubed-transient-logs-for-job "kubed-transient" nil t)
+ (autoload 'kubed-transient-logs-for-replicaset "kubed-transient" nil t)
+ (autoload 'kubed-transient-logs-for-daemonset "kubed-transient" nil t)
+ (autoload 'kubed-transient-logs-for-statefulset "kubed-transient" nil t)
+ (autoload 'kubed-transient-logs "kubed-transient" nil t)
+ (autoload 'kubed-transient-scale-deployment "kubed-transient" nil t)
+ (autoload 'kubed-transient-proxy "kubed-transient" nil t)
+ (autoload 'kubed-transient-rollout "kubed-transient" nil t)
+ (autoload 'kubed-transient-attach "kubed-transient" nil t)
+ (autoload 'kubed-transient-diff "kubed-transient" nil t)
+ (autoload 'kubed-transient-exec "kubed-transient" nil t)
+ (autoload 'kubed-transient-run "kubed-transient" nil t)
+ (autoload 'kubed-transient-apply "kubed-transient" nil t)
+ (autoload 'kubed-transient-patch "kubed-transient" nil t)
+ (autoload 'kubed-transient-create "kubed-transient" nil t)
+ (autoload 'kubed-transient-display "kubed-transient" nil t)
+ (autoload 'kubed-transient-edit "kubed-transient" nil t)
+ (autoload 'kubed-transient-delete "kubed-transient" nil t)
+ (autoload 'kubed-transient-create-cronjob "kubed-transient" nil t)
+ (autoload 'kubed-transient-create-ingress "kubed-transient" nil t)
+ (autoload 'kubed-transient-create-deployment "kubed-transient" nil t)
+ (autoload 'kubed-transient-create-job "kubed-transient" nil t)
+ (autoload 'kubed-list-transient "kubed-transient" nil t)
+(register-definition-prefixes "kubed-transient" '("kubed-transient-"))
+\f
+;;; End of scraped data
+
+(provide 'kubed-autoloads)
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; no-native-compile: t
+;; coding: utf-8-emacs-unix
+;; End:
+
+;;; kubed-autoloads.el ends here
diff --git a/elpa/kubed-0.5.0/kubed-common.el b/elpa/kubed-0.5.0/kubed-common.el
new file mode 100644 (file)
index 0000000..f7cb240
--- /dev/null
@@ -0,0 +1,25 @@
+;;; kubed-common.el --- Common definitons for Kubed   -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024-2025  Free Software Foundation, Inc.
+
+;; Author: Eshel Yaron <meNOSPAMeshelyaron.com>
+;; Keywords: tools
+
+;;; Commentary:
+
+;; This library provides definitions that both `kubed' and `kubed-tramp'
+;; require.
+
+;;; Code:
+
+(defvar kubed-tramp-method "kubedv2"    ;Versioned, for compatibility.
+  ;; (find-file "/kubedv2:CONTEXT%NAMESPACE%POD%CONTAINER:/some/file")
+  "Name of the Kubed Tramp method.")
+
+(defcustom kubed-kubectl-program "kubectl"
+  "Name of `kubectl' executable to use for interacting with Kubernetes."
+  :type 'string
+  :group 'kubed)
+
+(provide 'kubed-common)
+;;; kubed-tramp.el ends here
diff --git a/elpa/kubed-0.5.0/kubed-pkg.el b/elpa/kubed-0.5.0/kubed-pkg.el
new file mode 100644 (file)
index 0000000..9717f71
--- /dev/null
@@ -0,0 +1,2 @@
+;; Generated package description from kubed.el  -*- mode: lisp-data; no-byte-compile: t -*-
+(define-package "kubed" "0.5.0" "Kubernetes, Emacs, done!" '((emacs "29.1")) :commit "e8a6f9b0dc25d44f3783036962d6c08eacbdbd23" :authors '(("Eshel Yaron" . "meNOSPAMeshelyaron.com")) :maintainer '("Eshel Yaron" . "~eshel/kubed-devel@lists.sr.ht") :keywords '("tools" "kubernetes" "containers") :url "https://eshelyaron.com/kubed.html")
diff --git a/elpa/kubed-0.5.0/kubed-tramp.el b/elpa/kubed-0.5.0/kubed-tramp.el
new file mode 100644 (file)
index 0000000..9e6fbac
--- /dev/null
@@ -0,0 +1,150 @@
+;;; kubed-tramp.el --- Kubed Tramp integration   -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024-2025  Free Software Foundation, Inc.
+
+;; Author: Eshel Yaron <meNOSPAMeshelyaron.com>
+;; Keywords: tools
+
+;;; Commentary:
+
+;; This library provides Tramp integration for Kubed.  This is similar
+;; to the built-in "kubernetes" Tramp method from tramp-container.el,
+;; except that the Kubed method always requires the container name and
+;; Kubernetes namespace to be specified, as well a `kubectl' context.
+;; In other words, the filename syntax of this method is fully explicit.
+;; An explicit syntax is useful when juggling between different contexts
+;; and namespaces with Kubed; on the other hand, for finding a remote
+;; file with C-x C-f, the concise syntax of the built-in "kubernetes"
+;; method is probably more convenient.
+
+;;; Code:
+
+(require 'kubed-common)
+(require 'tramp)
+
+(defun kubed-tramp--unhex (x)
+  ;; Simplified version of `url-unhex'.
+  (if (> x ?9) (+ 10 (- x ?A)) (- x ?0)))
+
+(defun kubed-tramp--decode-context-name (str)
+  ;; Adopted from `url-unhex-string'.
+  (let ((tmp "") (case-fold-search nil))
+    (while (string-match "[.][0-9A-F][0-9A-F]" str)
+      (let* ((start (match-beginning 0))
+            (ch1 (kubed-tramp--unhex (elt str (+ start 1))))
+            (code (+ (* 16 ch1)
+                     (kubed-tramp--unhex (elt str (+ start 2))))))
+       (setq tmp (concat tmp (substring str 0 start) (byte-to-string code))
+             str (substring str (match-end 0)))))
+    (concat tmp str)))
+
+(defun kubed-tramp--v2-context (vec)
+  "Extract the context name from a kubernetes host name in VEC."
+  (or (when-let ((host (and vec (tramp-file-name-host vec))))
+        (shell-quote-argument
+         (decode-coding-string
+         (kubed-tramp--decode-context-name (nth 0 (split-string host "%")))
+         'utf-8)))
+      ""))
+
+(defun kubed-tramp--context (vec)
+  "Extract the context name from a kubernetes host name in VEC."
+  (or (when-let ((host (and vec (tramp-file-name-host vec))))
+        (nth 0 (split-string host "%")))
+      ""))
+
+(defun kubed-tramp--namespace (vec)
+  "Extract the namespace from a kubernetes host name in VEC."
+  (or (when-let ((host (and vec (tramp-file-name-host vec))))
+        (nth 1 (split-string host "%")))
+      ""))
+
+(defun kubed-tramp--pod (vec)
+  "Extract the pod name from a kubernetes host name in VEC."
+  (or (when-let ((host (and vec (tramp-file-name-host vec))))
+        (nth 2 (split-string host "%")))
+      ""))
+
+(defun kubed-tramp--container (vec)
+  "Extract the container name from a kubernetes host name in VEC."
+  (or (when-let ((host (and vec (tramp-file-name-host vec))))
+        (nth 3 (split-string host "%")))
+      ""))
+
+;;;###autoload
+(defun kubed-tramp-context (file-name)
+  "Extract `kubectl' context from Kubed Tramp remote file name FILE-NAME."
+  ;; TODO: Dispatch based on method version.  The following is intended
+  ;; for v2, although it also works for v1 in most cases.
+  (decode-coding-string
+   (kubed-tramp--decode-context-name
+    (nth 0 (split-string
+            (tramp-file-name-host (tramp-dissect-file-name file-name))
+            "%")))
+   'utf-8))
+
+;;;###autoload
+(defun kubed-tramp-namespace (file-name)
+  "Extract Kubernetes namespace from Kubed Tramp remote file name FILE-NAME."
+  (nth 1 (split-string
+          (tramp-file-name-host (tramp-dissect-file-name file-name)) "%")))
+
+;;;###autoload
+(defun kubed-tramp-assert-support ()
+  "Check if Kubed Tramp support is available, throw `user-error' if not."
+  (unless (assoc kubed-tramp-method tramp-methods)
+    (user-error "Kubed Tramp support requires Tramp version 2.7 or later")))
+
+;;;###autoload
+(defun kubed-tramp-enable ()
+  "Enable Kubed integration with Tramp."
+  (when (boundp 'tramp-extra-expand-args) ; Tramp 2.7+
+
+    (let ((params `((tramp-login-program ,kubed-kubectl-program)
+                    (tramp-login-args (("exec")
+                                       ("--context" "%x")
+                                       ("--namespace" "%y")
+                                       ("-c" "%a")
+                                       ("%h")
+                                       ("-it")
+                                       ("--")
+                                      ("%l")))
+                    (tramp-direct-async (,tramp-default-remote-shell "-c"))
+                    (tramp-remote-shell ,tramp-default-remote-shell)
+                    (tramp-remote-shell-login ("-l"))
+                    (tramp-remote-shell-args ("-i" "-c")))))
+
+      ;; Old version.
+      (setf (alist-get "kubedv1" tramp-methods nil nil #'string=) params)
+
+      (connection-local-set-profile-variables
+       'kubed-tramp-connection-local-default-profile
+       '((tramp-extra-expand-args
+          ?a (kubed-tramp--container  (car tramp-current-connection))
+          ?h (kubed-tramp--pod        (car tramp-current-connection))
+          ?x (kubed-tramp--context    (car tramp-current-connection))
+          ?y (kubed-tramp--namespace  (car tramp-current-connection)))))
+
+      (connection-local-set-profiles
+       '(:application tramp :protocol "kubedv1")
+       'kubed-tramp-connection-local-default-profile)
+
+      ;; New version.
+      (setf (alist-get kubed-tramp-method tramp-methods nil nil #'string=) params)
+
+      (connection-local-set-profile-variables
+       'kubed-tramp-v2-connection-local-default-profile
+       '((tramp-extra-expand-args
+          ?a (kubed-tramp--container  (car tramp-current-connection))
+          ?h (kubed-tramp--pod        (car tramp-current-connection))
+          ?x (kubed-tramp--v2-context (car tramp-current-connection))
+          ?y (kubed-tramp--namespace  (car tramp-current-connection)))))
+
+      (connection-local-set-profiles
+       `(:application tramp :protocol ,kubed-tramp-method)
+       'kubed-tramp-v2-connection-local-default-profile))))
+
+;;;###autoload (with-eval-after-load 'tramp (kubed-tramp-enable))
+
+(provide 'kubed-tramp)
+;;; kubed-tramp.el ends here
diff --git a/elpa/kubed-0.5.0/kubed-transient.el b/elpa/kubed-0.5.0/kubed-transient.el
new file mode 100644 (file)
index 0000000..faf861c
--- /dev/null
@@ -0,0 +1,588 @@
+;;; kubed-transient.el --- Kubernetes transient menus   -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024-2025  Free Software Foundation, Inc.
+
+;; Author: Eshel Yaron <meNOSPAMeshelyaron.com>
+;; Keywords: tools
+
+;;; Commentary:
+
+;; This library extends Kubed with transient menus for various
+;; Kubernetes operations.
+
+;;; Code:
+
+(require 'kubed)
+(require 'transient)
+
+(defun kubed-transient-read-date (prompt default _history)
+  "Prompt with PROMPT for a date, defaulting to DEFAULT.
+
+Return an RFC3339 string representation of the selected date."
+  (require 'org)
+  (when (fboundp 'org-read-date)
+    (format-time-string "%Y-%m-%dT%H:%M:%S%:z"
+                        (org-read-date 'with-time t nil prompt default))))
+
+(defun kubed-transient-read-context (prompt _initial-input _history)
+  "Prompt with PROMPT for Kubernetes context."
+  (kubed-read-context prompt (kubed-local-context)))
+
+(defun kubed-transient-read-namespace (prompt _initial-input _history)
+  "Prompt with PROMPT for Kubernetes namespace."
+  (let ((context (or (seq-some (lambda (s)
+                                 (and (cl-typep s 'transient-infix)
+                                      (equal (oref s argument) "--context=")
+                                      (oref s value)))
+                               transient--suffixes)
+                     (kubed-local-context))))
+    (kubed-read-namespace prompt (kubed--namespace context) nil context)))
+
+(defun kubed-transient-read-ingressclass (prompt _initial-input _history)
+  "Prompt with PROMPT for Kubernetes ingress class."
+  (kubed-read-ingressclass prompt))
+
+(defun kubed-transient-read-service-and-port (prompt _initial-input _history)
+  "Prompt with PROMPT for Kubernetes service and port number."
+  (let ((service (kubed-read-service prompt)))
+    (concat service ":" (number-to-string (read-number "Port number: ")))))
+
+(defun kubed-transient-read-resource-definition-file-name
+    (_prompt _initial-input _history)
+  "Read and return Kubernetes resource definition file name."
+  (kubed-read-resource-definition-file-name))
+
+;;;###autoload (autoload 'kubed-transient "kubed-transient" nil t)
+(transient-define-prefix kubed-transient ()
+  "Perform Kubernetes operation."
+  ["Kubernetes"
+   [ :pad-keys t
+     ("RET" "Display" kubed-transient-display)
+     ("+" "Create"  kubed-transient-create)
+     ("*" "Apply"   kubed-transient-apply)
+     ("D" "Delete"  kubed-transient-delete)]
+   [("e" "Edit"    kubed-transient-edit)
+    ("r" "Run"     kubed-transient-run)
+    ("a" "Attach"  kubed-transient-attach)
+    ("X" "Exec"    kubed-transient-exec)]
+   [("l" "Logs"    kubed-transient-logs)
+    ("d" "Diff"    kubed-transient-diff)
+    ("P" "Patch"   kubed-transient-patch)
+    ("R" "Rollout" kubed-transient-rollout)]
+   [("$" "Scale" kubed-transient-scale-deployment)
+    (":" "Proxy" kubed-transient-proxy)
+    ("E" "Explain" kubed-explain)
+    ("!" "Command line" kubed-kubectl-command)]])
+
+(defmacro kubed-transient-logs-for-resource (resource &optional plural)
+  "Define transient menu for showing logs for Kubernetes RESOURCE.
+
+Optional argument PLURAL is the plural form of RESOURCE.  If nil, it
+defaults to \"RESOURCEs\"."
+  (let ((name (intern (concat "kubed-transient-logs-for-" resource))))
+    `(transient-define-prefix ,name (&optional value)
+       ,(format "Show logs for a Kubernetes %s." resource)
+       [,(format "Kubernetes Logs for %s\n" (capitalize resource))
+        ["Actions"
+         ("l" "Show Logs" ,(intern (concat "kubed-logs-for-" resource)))
+         ("!" "Command line" kubed-kubectl-command)]
+        ["Options"
+         ("-n" "Namespace" "--namespace="
+          :prompt "Namespace" :reader kubed-transient-read-namespace)
+         ("-C" "Context" "--context="
+          :prompt "Context" :reader kubed-transient-read-context)
+         ("-b" "Limit bytes" "--limit-bytes="
+          :prompt "Bytes limit: " :reader transient-read-number-N+)
+         ("-t" "Limit lines" "--tail="
+          :prompt "Lines limit: " :reader transient-read-number-N+)
+         ("-S" "Since time" "--since-time="
+          :prompt "Since time: " :reader kubed-transient-read-date)]
+        ["Switches"
+         ("-A" "All containers" "--all-containers")
+         ("-f" "Stream logs" "--follow")
+         ("-P" "Add pod and container" "--prefix")
+         ("-T" "Add timestamps" "--timestamps")]]
+       (interactive
+        (list (kubed-transient-args 'kubed-transient-logs)))
+       (transient-setup ',name nil nil
+                        :value value
+                        :scope '("logs" ,(concat (or plural
+                                                     (concat resource "s"))
+                                                 "/"))))))
+
+;;;###autoload (autoload 'kubed-transient-logs-for-pod "kubed-transient" nil t)
+(kubed-transient-logs-for-resource "pod")
+
+;;;###autoload (autoload 'kubed-transient-logs-for-deployment "kubed-transient" nil t)
+(kubed-transient-logs-for-resource "deployment")
+
+;;;###autoload (autoload 'kubed-transient-logs-for-service "kubed-transient" nil t)
+(kubed-transient-logs-for-resource "service")
+
+;;;###autoload (autoload 'kubed-transient-logs-for-job "kubed-transient" nil t)
+(kubed-transient-logs-for-resource "job")
+
+;;;###autoload (autoload 'kubed-transient-logs-for-replicaset "kubed-transient" nil t)
+(kubed-transient-logs-for-resource "replicaset")
+
+;;;###autoload (autoload 'kubed-transient-logs-for-daemonset "kubed-transient" nil t)
+(kubed-transient-logs-for-resource "daemonset")
+
+;;;###autoload (autoload 'kubed-transient-logs-for-statefulset "kubed-transient" nil t)
+(kubed-transient-logs-for-resource "statefulset")
+
+;;;###autoload (autoload 'kubed-transient-logs "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-logs ()
+  "Show logs for containers running in Kubernetes."
+  ["Kubernetes Logs\n"
+   ["Kinds"
+    ("p" "Pod" kubed-transient-logs-for-pod)
+    ("d" "Deployment" kubed-transient-logs-for-deployment)
+    ("j" "Job" kubed-transient-logs-for-job)
+    ("s" "Service" kubed-transient-logs-for-service)
+    ("l" "Any type" kubed-logs)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)
+    ("-b" "Limit bytes" "--limit-bytes="
+     :prompt "Bytes limit: " :reader transient-read-number-N+)
+    ("-t" "Limit lines" "--tail="
+     :prompt "Lines limit: " :reader transient-read-number-N+)
+    ("-S" "Since time" "--since-time="
+     :prompt "Since time: " :reader kubed-transient-read-date)]
+   ["Switches"
+    ("-A" "All containers" "--all-containers")
+    ("-f" "Stream logs" "--follow")
+    ("-P" "Add pod and container" "--prefix")
+    ("-T" "Add timestamps" "--timestamps")]]
+  (interactive)
+  (transient-setup 'kubed-transient-logs nil nil
+                   :scope '("logs")))
+
+;;;###autoload (autoload 'kubed-transient-scale-deployment "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-scale-deployment ()
+  "Scale Kubernetes deployments."
+  ["Kubernetes Scale Deployment\n"
+   ["Action"
+    ("$" "Scale" kubed-scale-deployment)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)
+    ("-r" "Replicas" "--replicas="
+     :prompt "Number of replicas: " :reader transient-read-number-N+)]]
+  (interactive)
+  (transient-setup 'kubed-transient-scale-deployment nil nil
+                   :scope '("scale" "deployment")))
+
+;;;###autoload (autoload 'kubed-transient-proxy "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-proxy ()
+  "Create a proxy between localhost and the Kubernetes API server."
+  ["Kubernetes Proxy\n"
+   ["Action"
+    (":" "Start proxy" kubed-proxy)
+    ("|" "Stop proxy" kubed-stop-proxy)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)
+    ("-a" "Address" "--address="
+     :prompt "Local proxy address: ")
+    ("-p" "Port" "--port="
+     :prompt "Local proxy port: " :reader transient-read-number-N0)
+    ("-w" "WWW directory" "--www="
+     :prompt "Local WWW directory: " :reader transient-read-existing-directory)
+    ("-P" "WWW prefix" "--www-prefix="
+     :prompt "WWW prefix: ")
+    ("-A" "API prefix" "--api-prefix="
+     :prompt "API prefix: ")]]
+  (interactive)
+  (transient-setup 'kubed-transient-proxy nil nil
+                   :scope '("proxy")))
+
+;;;###autoload (autoload 'kubed-transient-rollout "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-rollout ()
+  "Manage Kubernetes deployments."
+  ["Kubernetes Rollout\n"
+   ["Actions"
+    ("W" "Watch"   kubed-watch-deployment-status)
+    ("R" "Restart" kubed-restart-deployment)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)]]
+  (interactive)
+  (transient-setup 'kubed-transient-rollout nil nil
+                   :scope '("rollout")))
+
+;;;###autoload (autoload 'kubed-transient-attach "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-attach ()
+  "Attach to running process in container in Kubernetes pod."
+  ["Kubernetes Attach\n"
+   ["Actions"
+    ("a" "Attach" kubed-attach)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Switches"
+    ("-i" "Open stdin" "--stdin")
+    ("-t" "Allocate TTY" "--tty")]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)]]
+  (interactive)
+  (transient-setup 'kubed-transient-attach nil nil
+                   :value '("--stdin" "--tty")
+                   :scope '("attach")))
+
+;;;###autoload (autoload 'kubed-transient-diff "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-diff ()
+  "Display difference between Kubernetes resource definition and current state."
+  ["Kubernetes Diff\n"
+   ["Actions"
+    ("d" "Diff" kubed-diff)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Switches"
+    ("-M" "Include managed fields" "--show-managed-fields")]
+   ["Options"
+    ("-f" "Definition file" "--filename="
+     :reader kubed-transient-read-resource-definition-file-name)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)]]
+  (interactive)
+  (transient-setup 'kubed-transient-diff nil nil
+                   :scope '("diff")))
+
+;;;###autoload (autoload 'kubed-transient-exec "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-exec ()
+  "Execute command in Kubernetes pod."
+  ["Kubernetes Exec\n"
+   ["Actions"
+    ("X" "Execute" kubed-exec)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Switches"
+    ("-i" "Open stdin" "--stdin")
+    ("-t" "Allocate TTY" "--tty")]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)
+    ("--" "Command" "-- ="
+     :prompt "Command: ")]]
+  (interactive)
+  (transient-setup 'kubed-transient-exec nil nil
+                   :value '("--stdin" "--tty")
+                   :scope '("exec")))
+
+;;;###autoload (autoload 'kubed-transient-run "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-run ()
+  "Run container image in a Kubernetes pod."
+  ["Kubernetes Run\n"
+   ["Actions"
+    ("r" "Run" kubed-run)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Switches"
+    ("-A" "Attach" "--attach")
+    ("-i" "Open stdin" "--stdin")
+    ("-t" "Allocate TTY" "--tty")
+    ("-R" "Remove after exit" "--rm")
+    ("-c" "Override container command" "--command")]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)
+    ("-I" "Image" "--image="
+     :prompt "Image to deploy: ")
+    ("-p" "Port" "--port="
+     :prompt "Port to expose: " :reader transient-read-number-N+)
+    ("-E" "Env vars" "--env="
+     :prompt "Set environment VAR=VAL: "
+     :multi-value repeat)
+    ("--" "Arguments" "-- ="
+     :prompt "Arguments for container command: ")]]
+  (interactive)
+  (transient-setup 'kubed-transient-run nil nil
+                   :scope '("run")))
+
+;;;###autoload (autoload 'kubed-transient-apply "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-apply ()
+  "Apply configuration to Kubernetes resource."
+  ["Kubernetes Apply\n"
+   ["Actions"
+    ("*" "Apply" kubed-apply)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-f" "Definition file" "--filename="
+     :reader kubed-transient-read-resource-definition-file-name)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)]]
+  (interactive)
+  (transient-setup 'kubed-transient-apply nil nil
+                   :scope '("apply")))
+
+;;;###autoload (autoload 'kubed-transient-patch "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-patch ()
+  "Apply patch to Kubernetes resource."
+  ["Kubernetes Patch\n"
+   ["Actions"
+    ("P" "Patch" kubed-patch)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)
+    ("-t" "Patch type" "--type="
+     :prompt "Patch type: "
+     :choices ("strategic" "merge" "json"))]]
+  (interactive)
+  (transient-setup 'kubed-transient-patch nil nil
+                   :scope '("patch")))
+
+;;;###autoload (autoload 'kubed-transient-create "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-create ()
+  "Create Kubernetes resource."
+  ["Kubernetes Create\n"
+   ["Kinds"
+    ("p" "Pod" kubed-create-pod)
+    ("d" "Deployment" kubed-transient-create-deployment)
+    ("j" "Job" kubed-transient-create-job)
+    ("c" "CronJob" kubed-transient-create-cronjob)
+    ("s" "Service" kubed-create-service)]
+   ["More"
+    :pad-keys t
+    ("S" "Secret" kubed-create-secret)
+    ("N" "Namespace" kubed-create-namespace)
+    ("i" "Ingress" kubed-transient-create-ingress)
+    ("+" "Any type" kubed-create)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-f" "Definition file" "--filename="
+     :reader kubed-transient-read-resource-definition-file-name)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)]]
+  (interactive)
+  (transient-setup 'kubed-transient-create nil nil
+                   :scope '("create")))
+
+;;;###autoload (autoload 'kubed-transient-display "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-display ()
+  "Display Kubernetes resource."
+  ["Kubernetes Display\n"
+   ["Kinds"
+    ("p" "Pod" kubed-display-pod)
+    ("d" "Deployment" kubed-display-deployment)
+    ("j" "Job" kubed-display-job)
+    ("c" "CronJob" kubed-display-cronjob)
+    ("s" "Service" kubed-display-service)]
+   ["More"
+    :pad-keys t
+    ("S" "Secret" kubed-display-secret)
+    ("N" "Namespace" kubed-display-namespace)
+    ("i" "Ingress" kubed-display-ingress)
+    ("RET" "Any type" kubed-display-resource)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)]]
+  (interactive)
+  (transient-setup 'kubed-transient-display nil nil
+                   :scope '("get")))
+
+;;;###autoload (autoload 'kubed-transient-edit "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-edit ()
+  "Edit Kubernetes resource."
+  ["Kubernetes Edit\n"
+   ["Kinds"
+    ("p" "Pod" kubed-edit-pod)
+    ("d" "Deployment" kubed-edit-deployment)
+    ("j" "Job" kubed-edit-job)
+    ("c" "CronJob" kubed-edit-cronjob)
+    ("s" "Service" kubed-edit-service)]
+   ["More"
+    :pad-keys t
+    ("S" "Secret" kubed-edit-secret)
+    ("N" "Namespace" kubed-edit-namespace)
+    ("i" "Ingress" kubed-edit-ingress)
+    ("RET" "Any type" kubed-edit-resource)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)]]
+  (interactive)
+  (transient-setup 'kubed-transient-edit nil nil
+                   :scope '("edit")))
+
+;;;###autoload (autoload 'kubed-transient-delete "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-delete ()
+  "Delete Kubernetes resource."
+  ["Kubernetes Delete\n"
+   ["Kinds"
+    ("p" "Pod" kubed-delete-pods)
+    ("d" "Deployment" kubed-delete-deployments)
+    ("j" "Job" kubed-delete-jobs)
+    ("c" "CronJob" kubed-delete-cronjobs)
+    ("s" "Service" kubed-delete-services)]
+   ["More"
+    :pad-keys t
+    ("S" "Secret" kubed-delete-secrets)
+    ("N" "Namespace" kubed-delete-namespaces)
+    ("i" "Ingress" kubed-delete-ingresses)
+    ("D" "Any type" kubed-delete-resources)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)]]
+  (interactive)
+  (transient-setup 'kubed-transient-delete nil nil
+                   :scope '("delete")))
+
+;;;###autoload (autoload 'kubed-transient-create-cronjob "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-create-cronjob ()
+  "Create Kubernetes cronjob."
+  ["Kubernetes Create CronJob\n"
+   ["Actions"
+    ("+" "Create" kubed-create-cronjob)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)
+    ("-I" "Image" "--image="
+     :prompt "Image to run: ")
+    ("-S" "Schedule" "--schedule="
+     :prompt "Cron schedule: ")
+    ("--" "Command" "-- ="
+     :prompt "Command: ")]]
+  (interactive)
+  (transient-setup 'kubed-transient-create-cronjob nil nil
+                   :scope '("create" "cronjob")))
+
+;;;###autoload (autoload 'kubed-transient-create-ingress "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-create-ingress ()
+  "Create Kubernetes ingress."
+  ["Kubernetes Create Ingress\n"
+   ["Actions"
+    ("+" "Create" kubed-create-ingress)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)
+    ("-c" "Class" "--class="
+     :prompt "Class" :reader kubed-transient-read-ingressclass)
+    ("-d" "Default backend service" "--default-backend="
+     :prompt "Default backend service"
+     :reader kubed-transient-read-service-and-port)
+    ("-a" "Annotation" "--annotation="
+     :prompt "Ingress annotations: "
+     :multi-value repeat)
+    ("-r" "Rule" "--rule="
+     :prompt "Ingress rule: ")]]
+  (interactive)
+  (transient-setup 'kubed-transient-create-ingress nil nil
+                   :scope '("create" "ingress")))
+
+;;;###autoload (autoload 'kubed-transient-create-deployment "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-create-deployment ()
+  "Create Kubernetes deployment."
+  ["Kubernetes Create Deployment\n"
+   ["Actions"
+    ("+" "Create" kubed-create-deployment)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)
+    ("-r" "Replicas" "--replicas="
+     :prompt "Number of replicas: " :reader transient-read-number-N+)
+    ("-I" "Image" "--image="
+     :prompt "Images to deploy: "
+     :multi-value repeat)
+    ("-p" "Port" "--port="
+     :prompt "Port to expose: " :reader transient-read-number-N+)
+    ("--" "Command" "-- ="
+     :prompt "Command: ")]]
+  (interactive)
+  (transient-setup 'kubed-transient-create-deployment nil nil
+                   :scope '("create" "deployment")))
+
+;;;###autoload (autoload 'kubed-transient-create-job "kubed-transient" nil t)
+(transient-define-prefix kubed-transient-create-job ()
+  "Create Kubernetes job."
+  ["Kubernetes Create Job\n"
+   ["Actions"
+    ("+" "Create" kubed-create-job)
+    ("c" "Create from cronjob" kubed-create-job-from-cronjob)
+    ("!" "Command line" kubed-kubectl-command)]
+   ["Options"
+    ("-n" "Namespace" "--namespace="
+     :prompt "Namespace" :reader kubed-transient-read-namespace)
+    ("-C" "Context" "--context="
+     :prompt "Context" :reader kubed-transient-read-context)
+    ("-I" "Image" "--image="
+     :prompt "Image to run: ")
+    ("--" "Command" "-- ="
+     :prompt "Command: ")]]
+  (interactive)
+  (transient-setup 'kubed-transient-create-job nil nil
+                   :scope '("create" "job")))
+
+;;;###autoload (autoload 'kubed-list-transient "kubed-transient" nil t)
+(transient-define-prefix kubed-list-transient ()
+  "Help for Kubernetes resource list buffers."
+  ;; TODO: Add a type-specific group with `:setup-children'.
+  ["Kubernetes Resources:"
+   ["Select"
+    :pad-keys t
+    ("RET" "Select" kubed-list-select-resource)
+    ("C-o" "Display" kubed-list-display-resource :transient t)
+    ("e" "Edit" kubed-list-edit :transient t)
+    ("w" "Copy name" kubed-list-copy-as-kill :transient t)
+    ("!" "Command line" kubed-list-kubectl-command :transient t)]
+   ["Delete"
+    ("D" "Delete" kubed-list-delete :transient t)
+    ("d" "Mark" kubed-list-mark-for-deletion :transient t)
+    ("u" "Unmark" kubed-list-unmark :transient t)
+    ("x" "Delete marked" kubed-list-delete-marked :transient t)
+    ("+" "Create" kubed-list-create :transient t)]
+   ["Table"
+    ("|" "Fit column" kubed-list-fit-column-width-to-content :transient t)
+    ("}" "Widen column" tabulated-list-widen-current-column :transient t)
+    ("{" "Narrow column" tabulated-list-narrow-current-column :transient t)
+    ("S" "Sort" tabulated-list-sort :transient t)
+    ("/" "Filter" kubed-list-set-filter :transient t)]
+   ["Movement"
+    :pad-keys t
+    ("n" "Next line" next-line :transient t)
+    ("p" "Previous line" previous-line :transient t)
+    ("TAB" "Next column" kubed-list-next-column :transient t)
+    ("S-TAB" "Previous column" kubed-list-previous-column :transient t)
+    ("g" "Update" kubed-list-update :transient t)]]
+  ["Type Specific"
+   :class transient-columns
+   :setup-children
+   (lambda (_)
+     (transient-parse-suffixes 'kubed-list-transient
+                               kubed-list-transient-extra-suffixes))])
+
+(provide 'kubed-transient)
+;;; kubed-transient.el ends here
diff --git a/elpa/kubed-0.5.0/kubed.el b/elpa/kubed-0.5.0/kubed.el
new file mode 100644 (file)
index 0000000..f28a5e3
--- /dev/null
@@ -0,0 +1,3582 @@
+;;; kubed.el --- Kubernetes, Emacs, done!   -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024-2025  Free Software Foundation, Inc.
+
+;; Author: Eshel Yaron <meNOSPAMeshelyaron.com>
+;; Maintainer: Eshel Yaron <~eshel/kubed-develNOSPAMlists.sr.ht>
+;; Keywords: tools kubernetes containers
+;; URL: https://eshelyaron.com/kubed.html
+;; Package-Version: 0.5.0
+;; Package-Requires: ((emacs "29.1"))
+
+;;; Commentary:
+
+;; This library defines commands for interacting with Kubernetes
+;; resources, such as Kubernetes pods, services, deployments, and more.
+;;
+;; Use `kubed-display-pod' to display a Kubernetes pod,
+;; `kubed-edit-pod' to edit it, `kubed-delete-pods' to delete it, and
+;; `kubed-list-pods' to see a menu of all pods.  You can create new pods
+;; from YAML or JSON files with `kubed-create-pod'.
+;;
+;; Similar commands are defined for other types of resources as well.
+;;
+;; This library interacts with Kubernetes via `kubectl', and uses the
+;; current `kubectl' context and namespace by default.  To change your
+;; current context or namespace, use commands `kubed-use-context' and
+;; `kubed-set-namespace' respectively; you can also interact with
+;; resources in other namespaces without changing your default
+;; namespace, for example you can call `kubed-list-pods' with a prefix
+;; argument to choose another namespace for listing pods.  The prefix
+;; keymap `kubed-prefix-map' gives you quick access to these and other
+;; useful commands, you may want to bind it globally to a convenient key
+;; with `keymap-global-set':
+;;
+;;   (keymap-global-set "C-c k" 'kubed-prefix-map)
+;;
+;; In addition, the command `kubed-transient' lets you explore various
+;; Kubernetes operations with a transient menu interface.  You may also
+;; want to enable `kubed-menu-bar-mode', which add a "Kubernetes" menu
+;; to your menu-bar with many useful entries.
+;;
+;; If you want to work with more or different types of Kubernetes
+;; resources, use the macro `kubed-define-resource'.  This macro defines
+;; some common functions and commands that'll get you started with ease.
+;;
+;; For more information, see the Kubed manual at (info "(kubed)Top"), or
+;; online at https://eshelyaron.com/kubed.html
+
+;;; Code:
+
+(require 'kubed-common)
+
+(defgroup kubed nil
+  "Kubernetes interface."
+  :group 'tools)
+
+(defcustom kubed-default-context-and-namespace nil
+  "Default `kubectl' context and Kubernetes namespace.
+
+This is either a cons cell (CONTEXT . NAMESPACE), or nil.  If nil, Kubed
+initializes this option to a non-nil value next time Kubed consults it."
+  :type '(choice (const :tag "Initialize from `kubectl' on first use" nil)
+                 (cons :tag "Context and namespace"
+                       (string :tag "Context")
+                       (string :tag "Namespace"))))
+
+(defcustom kubed-yaml-setup-hook '(yaml-ts-mode view-mode)
+  "List of functions to call in Kubernetes resource description YAML buffers.
+
+The first function in the list should normally be the major mode to use,
+by default it is `yaml-ts-mode'."
+  :type 'hook)
+
+(defcustom kubed-logs-setup-hook '(view-mode)
+  "List of functions to call when setting up Kubernetes pod logs buffers."
+  :type 'hook)
+
+(defcustom kubed-name-column '("Name" 48 t)
+  "Specification of resource name column in Kubernetes resource list buffers."
+  :type '(list string natnum boolean))
+
+(defvar kubed--data nil)
+
+(defun kubed--alist (type context namespace)
+  "Return information about resources in CONTEXT of type TYPE in NAMESPACE."
+  (alist-get namespace
+             (alist-get type
+                        (alist-get context
+                                   kubed--data nil nil #'string=)
+                        nil nil #'string=)
+             nil nil #'equal))
+
+(gv-define-setter kubed--alist (value type context namespace)
+  `(setf (alist-get ,namespace
+                    (alist-get ,type
+                               (alist-get ,context
+                                          kubed--data nil nil #'string=)
+                               nil nil #'string=)
+                    nil nil #'equal)
+         ,value))
+
+(defvar kubed--columns nil)
+
+(defun kubed-update (type context &optional namespace)
+  "Update list of resources of type TYPE in CONTEXT and NAMESPACE."
+  (when (process-live-p (alist-get 'process (kubed--alist type context namespace)))
+    (user-error "Update in progress"))
+  (let* ((out (get-buffer-create (format " *kubed-get-%s*"        type)))
+         (err (get-buffer-create (format " *kubed-get-%s-stderr*" type)))
+         (columns (alist-get type kubed--columns nil nil #'string=)))
+    (with-current-buffer out (erase-buffer))
+    (setf (alist-get 'process (kubed--alist type context namespace))
+          (make-process
+           :name (format "*kubed-get-%s*" type)
+           :buffer out
+           :stderr err
+           :command (append
+                     (list kubed-kubectl-program "get" type
+                           "--context" context
+                           (format "--output=custom-columns=%s"
+                                   (mapconcat #'car columns ",")))
+                     (when namespace (list "--namespace" namespace)))
+           :sentinel
+           (lambda (_proc status)
+             (cond
+              ((string= status "finished\n")
+               (let (new offsets eol)
+                 (with-current-buffer out
+                   (goto-char (point-min))
+                   (setq eol (pos-eol))
+                   (while (re-search-forward "[^ ]+" eol t)
+                     (push (1- (match-beginning 0)) offsets))
+                   (setq offsets (nreverse offsets))
+                   (forward-char 1)
+                   (while (not (eobp))
+                     (let ((cols nil)
+                           (beg (car offsets))
+                           (ends (append (cdr offsets)
+                                         (list (- (pos-eol) (point))))))
+                       (dolist (column columns)
+                         (let ((str (string-trim (buffer-substring
+                                                  (+ (point) beg)
+                                                  (+ (point) (car ends))))))
+                           (push (if-let ((f (cdr column))) (funcall f str) str)
+                                 cols)
+                           (setq beg (pop ends))))
+                       (push (nreverse cols) new))
+                     (forward-line 1)))
+                 (setf (kubed--alist type context namespace)
+                       (list (cons 'resources
+                                   (mapcar (lambda (c) (list (car c) (apply #'vector c)))
+                                           new))))
+                 (let ((bufs nil))
+                   (dolist (buf (buffer-list))
+                     (and (equal (buffer-local-value 'kubed-list-type buf) type)
+                          (equal (buffer-local-value 'kubed-list-context buf) context)
+                          (equal (buffer-local-value 'kubed-list-namespace buf) namespace)
+                          (with-current-buffer buf
+                            (when (derived-mode-p 'kubed-list-mode)
+                              (revert-buffer)
+                              (when-let ((win (get-buffer-window)))
+                                (set-window-point win (point))
+                                (push buf bufs))))))
+                   (walk-windows
+                    (lambda (win)
+                      (let ((buf (window-buffer win)))
+                        (when (memq buf bufs)
+                          (set-window-point
+                           win (with-current-buffer buf (point))))))))
+                 (message (format "Updated Kubernetes %S." type))))
+              ((string= status "exited abnormally with code 1\n")
+               (with-current-buffer err
+                 (goto-char (point-max))
+                 (insert "\n" status))
+               (display-buffer err))))))))
+
+(defvar-local kubed-display-resource-info nil
+  "Information about Kubernetes resource that current buffer displays.
+
+The value is a list (TYPE NAME CONTEXT NAMESPACE), where TYPE is the
+type of the resource, NAME is the name of the resource, CONTEXT is the
+`kubectl' context to use for accessing the resource, and NAMESPACE is
+the namespace of the resource, or nil if TYPE is not namespaced.")
+
+(put 'kubed-display-resource-info 'permanent-local t)
+
+(defun kubed-display-resource-revert (&optional _ _)
+  "Clear and populate current Kubernetes resource buffer."
+  (seq-let (type name context namespace)
+      kubed-display-resource-info
+    (let ((inhibit-read-only t)
+          (target (current-buffer)))
+      (buffer-disable-undo)
+      (with-temp-buffer
+        (unless (zerop
+                 (apply
+                  #'call-process
+                  kubed-kubectl-program nil t nil "get"
+                  type "--output=yaml" name
+                  (append (when namespace (list "-n" namespace))
+                          (when context (list "--context" context)))))
+          (error "Failed to display Kubernetes resource `%s'" name))
+        (let ((source (current-buffer)))
+          (with-current-buffer target
+            (replace-buffer-contents source)
+            (set-buffer-modified-p nil)
+            (buffer-enable-undo)))))))
+
+(defun kubed-display-resource-in-buffer
+    (buffer type resource &optional context namespace)
+  "Display Kubernetes RESOURCE of type TYPE in BUFFER."
+  (let ((info (list type resource context namespace)))
+    (with-current-buffer (get-buffer-create buffer)
+      (setq-local kubed-display-resource-info info)
+      (kubed-display-resource-revert)
+      (goto-char (point-min))
+      (run-hooks 'kubed-yaml-setup-hook)
+      (kubed-display-resource-mode)
+      (current-buffer))))
+
+(defun kubed-display-resource-short-description
+    (type resource context namespace)
+  "Return short string to use as a label for RESOURCE of type TYPE."
+  (concat type "/" resource
+          (when namespace (concat "@" namespace))
+          (when context   (concat "[" context "]"))))
+
+(defun kubed-namespaced-p (type &optional context)
+  "Return non-nil if TYPE is a namespaced resource type in context CONTEXT."
+  (member type (kubed-api-resources context t)))
+
+(defun kubed--namespace (context &optional prompt-p)
+  "Return Kubernetes namespace for CONTEXT.
+
+Non-nil optional argument PROMPT-P says to prompt for a namespace."
+  (let ((ns (if (equal context (kubed-local-context))
+                (kubed-local-namespace)
+              (kubed-current-namespace context))))
+    ;; If CONTEXT is another context that has no configured namespace,
+    ;; then NS is nil and we must prompt.
+    (unless ns (setq prompt-p t))
+    (if prompt-p
+        (kubed-read-namespace "Namespace" ns nil context)
+      ns)))
+
+;;;###autoload
+(defun kubed-display-resource
+    (type resource context &optional namespace)
+  "Display Kubernetes RESOURCE of type TYPE in CONTEXT.
+
+For namespaced resource types, NAMESPACE is the namespace of RESOURCE.
+
+Interactively, use the current context and namespace by default, and
+prompt for TYPE and RESOURCE.  With a prefix argument \
+\\[universal-argument],
+prompt for NAMESPACE.  With a double prefix argument \
+\\[universal-argument] \\[universal-argument],
+prompt for CONTEXT as well."
+  (interactive
+   (let ((type nil) (context nil) (namespace nil))
+     (dolist (arg (kubed-transient-args 'kubed-transient-display))
+       (cond
+        ((string-match "--namespace=\\(.+\\)" arg)
+         (setq namespace (match-string 1 arg)))
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (unless type
+       (setq type (kubed-read-resource-type "Type of resource to display"
+                                            nil context)))
+     (when (and (null namespace) (kubed-namespaced-p type context))
+       (setq namespace (kubed--namespace context current-prefix-arg)))
+     (list type (kubed-read-resource-name type "Display" nil nil
+                                          context namespace)
+           context namespace)))
+  (display-buffer
+   (kubed-display-resource-in-buffer
+    (concat "*Kubed "
+            (kubed-display-resource-short-description
+             type resource context namespace)
+            "*")
+    type resource context namespace)))
+
+(declare-function bookmark-prop-get                 "bookmark")
+(declare-function bookmark-get-front-context-string "bookmark")
+(declare-function bookmark-get-rear-context-string  "bookmark")
+(declare-function bookmark-make-record-default      "bookmark")
+
+;;;###autoload
+(defun kubed-display-resource-handle-bookmark (bookmark)
+  "Display Kubernetes resource according to BOOKMARK."
+  (require 'bookmark)
+  (seq-let (type name context namespace)
+      (bookmark-prop-get bookmark 'resource)
+    (set-buffer
+     (kubed-display-resource-in-buffer
+      (concat "*Kubed "
+              (kubed-display-resource-short-description
+               type name context namespace)
+              "*")
+      type name context namespace))
+    (when-let ((str (bookmark-get-front-context-string bookmark))
+               ((search-forward str (point-max) t)))
+      (goto-char (match-beginning 0)))
+    (when-let ((str (bookmark-get-rear-context-string bookmark))
+               ((search-backward str (point-min) t)))
+      (goto-char (match-end 0)))))
+
+(put 'kubed-display-resource-handle-bookmark 'bookmark-handler-type "KubedResource")
+
+(defun kubed-display-resource-make-bookmark ()
+  "Return bookmark pointing to currently displayed Kubernetes resource."
+  (require 'bookmark)
+  (seq-let (type name context namespace) kubed-display-resource-info
+    (cons
+     (kubed-display-resource-short-description type name context namespace)
+     (append
+      (list
+       (cons 'handler #'kubed-display-resource-handle-bookmark)
+       (cons 'resource kubed-display-resource-info))
+      (bookmark-make-record-default t)))))
+
+(defun kubed-display-resource-jump-to-list ()
+  "Jump to line in resources list that corresponds to the displayed resource."
+  (interactive)
+  (seq-let (type name context namespace) kubed-display-resource-info
+    (apply (intern (concat "kubed-list-" type)) context
+           (when namespace (list namespace)))
+    (kubed-list-go-to-line name)))
+
+(defun kubed-display-resource-diff ()
+  "Show diff of current buffer with current state of the displayed resource."
+  (interactive)
+  (kubed-diff (current-buffer) nil (nth 2 kubed-display-resource-info)))
+
+(defun kubed-display-resource-replace ()
+  "Replace displayed Kubernetes resource with current buffer contents."
+  (interactive)
+  (let (choice)
+    (while (= ?d (setq choice
+                       (car (read-multiple-choice
+                             "Replace resource with changes in current buffer?"
+                             '((?y "yes") (?n "no") (?d "diff"))))))
+      (kubed-display-resource-diff))
+    (when (= ?y choice)
+      (let ((err-buf (get-buffer-create " *kubed-replace*")))
+        (with-current-buffer err-buf (erase-buffer))
+        (unless (zerop (call-process-region nil nil kubed-kubectl-program
+                                            nil err-buf nil "replace" "-f" "-"))
+          (display-buffer err-buf)
+          (user-error "`kubectl replace' failed!")))
+      (message "Replaced Kubernetes resource with changes in current buffer.")
+      (revert-buffer))))
+
+(defun kubed-display-resource-p (_symbol buffer)
+  "Return non-nil if `kubed-display-resource-mode' is enabled in BUFFER.
+
+The first argument, SYMBOL, is ignored.  You can use this function as
+the `completion-predicate' property of commands that you define that
+should only be available in buffers that display Kubernetes resources."
+  (buffer-local-value 'kubed-display-resource-mode buffer))
+
+(dolist (cmd '(kubed-display-resource-jump-to-list
+               kubed-display-resource-diff
+               kubed-display-resource-replace))
+  (put cmd 'completion-predicate #'kubed-display-resource-p))
+
+(defvar-keymap kubed-display-resource-mode-map
+  :doc "Keymap buffers that display Kubernetes resource."
+  "C-c C-j" #'kubed-display-resource-jump-to-list
+  "C-c C-=" #'kubed-display-resource-diff
+  "C-c C-c" #'kubed-display-resource-replace)
+
+(define-minor-mode kubed-display-resource-mode
+  "Minor mode for buffers that display a Kubernetes resource."
+  :interactive nil
+  :lighter " Kubed"
+  (when kubed-display-resource-mode
+    (setq-local
+     revert-buffer-function        #'kubed-display-resource-revert
+     bookmark-make-record-function #'kubed-display-resource-make-bookmark)))
+
+(defun kubed-list-filter-lt-operator (v s)
+  "Return non-nil if S is less than V as a number or as a string."
+  (let ((l (string-to-number s)) (r (string-to-number v)))
+    (if (= l r) (string< s v) (< l r))))
+
+(defun kubed-list-filter-gt-operator (v s)
+  "Return non-nil if S is greater than V as a number or as a string."
+  (let ((l (string-to-number s)) (r (string-to-number v)))
+    (if (= l r) (string> s v) (> l r))))
+
+(defcustom kubed-list-filter-operator-alist
+  '((= . string=)
+    (~ . string-match-p)
+    (< . kubed-list-filter-lt-operator)
+    (> . kubed-list-filter-gt-operator))
+  "Association list of filter operators and functions that implement them.
+
+Elements of the list are cons cells (OP . FN), where OP is a symbol that
+is used as a filter operator and FN is a function that implements OP.
+FN takes two arguments, a string STR and a parameter VAL.  FN should
+return non-nil if STR and VAL are related according to OP: to determine
+if a line in which column COL is STR satisfies the filter (OP COL VAL),
+Kubed checks if the form (FN VAL STR) evaluates to non-nil."
+  :type '(alist :key-type (symbol :tag "Operator") :value-type function))
+
+(defun kubed-list-interpret-atomic-filter (atom)
+  "Return function that implements atomic filter ATOM."
+  (if (eq (car-safe atom) 'quote)
+      (let ((p (kubed-list-interpret-atomic-filter (cadr atom))))
+        (lambda (x) (not (funcall p x))))
+    (let* ((column-number (tabulated-list--column-number (symbol-name (nth 1 atom))))
+           (value (nth 2 atom))
+           (value (if (stringp value) value (prin1-to-string value)))
+           (op (alist-get (car atom) kubed-list-filter-operator-alist)))
+      (unless op (user-error "Unknown filter operator `%S'" (car atom)))
+      (lambda (x) (funcall op value (aref (cadr x) column-number))))))
+
+(defvar-local kubed-list-filter nil "Filter in effect in the current buffer.")
+
+(defun kubed-list-interpret-filter (&optional filter)
+  "Return function that implements FILTER.
+
+If FILTER is omitted or nil, it defaults to `kubed-list-filter'."
+  (let ((conjunction (or filter kubed-list-filter)))
+    (if (listp (car conjunction))
+        (let ((conjuncts
+               (mapcar (lambda (disjunction)
+                         (if (listp (car disjunction))
+                             (let ((disjuncts
+                                    (mapcar #'kubed-list-interpret-atomic-filter
+                                            disjunction)))
+                               (lambda (entry)
+                                 (catch 'keep-it
+                                   (dolist (pred disjuncts)
+                                     (when (funcall pred entry)
+                                       (throw 'keep-it t)))
+                                   nil)))
+                           ;; Single atomic disjunct.
+                           (kubed-list-interpret-atomic-filter disjunction)))
+                       (or conjunction kubed-list-filter))))
+          (lambda (entry)
+            (catch 'keep-it
+              (dolist (pred conjuncts)
+                (unless (funcall pred entry)
+                  (throw 'keep-it nil)))
+              t)))
+      ;; Single atomic conjunct.
+      (kubed-list-interpret-atomic-filter conjunction))))
+
+(defun kubed-list-validate-atomic-filter (atom)
+  "Return string explaining why ATOM is invalid, or nil if it is valid."
+  (unless (consp atom)
+    (throw 'validation-error
+           (format (substitute-quotes
+                    "Invalid atomic filter `%S', must be a list")
+                   atom)))
+  (if (eq (car-safe atom) 'quote)
+      (kubed-list-validate-atomic-filter (cadr atom))
+    (unless (length= atom 3)
+      (throw 'validation-error
+             (format (substitute-quotes
+                      "Invalid atomic filter `%S', must have three elements")
+                     atom)))
+    (unless (assq (car atom) kubed-list-filter-operator-alist)
+      (throw 'validation-error
+             (format (substitute-quotes
+                      "No operator `%S' in `kubed-list-filter-operator-alist'")
+                     (car atom))))
+    (unless (ignore-errors
+              (tabulated-list--column-number (symbol-name (nth 1 atom))))
+      (throw 'validation-error (format (substitute-quotes
+                                        "Invalid column name `%S'")
+                                       (nth 1 atom))))))
+
+(defun kubed-list-validate-filter (filter)
+  "Return string explaining why FILTER is invalid, or nil if it is valid."
+  (catch 'validation-error
+    (if (listp (car-safe filter))
+        (dolist (disjunction filter)
+          (if (and (consp disjunction) (listp (car disjunction)))
+              (dolist (disjunct disjunction)
+                (kubed-list-validate-atomic-filter disjunct))
+            (kubed-list-validate-atomic-filter disjunction)))
+      (kubed-list-validate-atomic-filter filter))))
+
+(defvar-local kubed-list-filter-history-variable nil
+  "History list variable to use for filter history in the current buffer.")
+
+(defvar-local kubed--list-read-filter-target-buffer nil
+  "Resource list buffer for which this minibuffer is reading a filter.")
+
+(defvar-local kubed-list-type nil)
+(defvar-local kubed-list-context nil)
+(defvar-local kubed-list-namespace nil)
+
+(defvar-local kubed-list-transient-extra-suffixes nil
+  "List of transient suffixes for the type of resources in current buffer.")
+
+(defun kubed-list-go-to-line (id)
+  "Go to beginning of table line with ID."
+  (let ((pos nil))
+    (save-excursion
+      ;; Wait for refresh to finish, if currently underway.
+      (while (process-live-p
+              (alist-get 'process (kubed--alist kubed-list-type
+                                                kubed-list-context
+                                                kubed-list-namespace)))
+        (accept-process-output
+         (alist-get 'process (kubed--alist kubed-list-type
+                                           kubed-list-context
+                                           kubed-list-namespace))
+         1))
+      (goto-char (point-min))
+      (while (not (or pos (eobp)))
+        (if (equal id (tabulated-list-get-id))
+            (setq pos (point))
+          (forward-line))))
+    (goto-char pos)))
+
+(defun kubed-list-try-read-filter ()
+  "Try to read a resource list filter in the minibuffer.
+
+Exit the minibuffer if successful, else report the error and move point
+to the location of the error.  If point is not already at the location
+of the error, push a mark before moving point."
+  (interactive "" minibuffer-mode)
+  (let* ((prompt-end (minibuffer-prompt-end))
+         (contents (minibuffer-contents))
+         (error-point nil) (error-message nil) (form nil) (inval nil))
+    (with-temp-buffer
+      (condition-case err
+          (progn
+            ;; FIXME: There is a small edge case here that could get
+            ;; better treatment: when `contents' ends with " ?", it
+            ;; espaces the terminating closing parenthesis and leads us
+            ;; to incorrectly report the input as incomplete.
+            (insert "(" contents ")")
+            (goto-char (point-min))
+            (setq form (read (current-buffer))))
+        (error (setq error-point (+ prompt-end (1- (point)))
+                     error-message err))))
+    (cond
+     (error-point
+      (unless (= (point) error-point) (push-mark))
+      (goto-char error-point)
+      (minibuffer-message (error-message-string error-message)))
+     ((setq inval (with-current-buffer kubed--list-read-filter-target-buffer
+                    (kubed-list-validate-filter form)))
+      (minibuffer-message inval))
+     (t (exit-minibuffer)))))
+
+(defvar-keymap kubed-list-read-filter-map
+  :parent minibuffer-local-map
+  "TAB" #'completion-at-point
+  "M-?" #'completion-help-at-point
+  "<remap> <exit-minibuffer>" #'kubed-list-try-read-filter)
+
+(defun kubed-list-read-filter (prompt)
+  "Prompt with PROMPT for a filter for the current buffer."
+  (let* ((buf (current-buffer))
+         (cols (seq-map #'car tabulated-list-format))
+         (vals (let ((tmp nil))
+                 (dolist (ent (alist-get 'resources
+                                         (kubed--alist kubed-list-type
+                                                       kubed-list-context
+                                                       kubed-list-namespace)))
+                   (let ((i 0))
+                     (dolist (col cols)
+                       (push (aref (cadr ent) i)
+                             (alist-get col tmp nil nil #'string=))
+                       (setq i (1+ i)))))
+                 (mapcar #'delete-dups tmp)))
+         (filter
+          (minibuffer-with-setup-hook
+              (lambda ()
+                (set-syntax-table emacs-lisp-mode-syntax-table)
+                (setq-local kubed--list-read-filter-target-buffer buf)
+                (add-hook
+                 'completion-at-point-functions
+                 (lambda ()
+                   (let ((cont (buffer-substring
+                                (minibuffer-prompt-end) (point)))
+                         (bounds (or (bounds-of-thing-at-point 'symbol)
+                                     (cons (point) (point)))))
+                     (with-temp-buffer
+                       (set-syntax-table emacs-lisp-mode-syntax-table)
+                       (insert "(" cont)
+                       (when-let ((fn-argi (elisp--fnsym-in-current-sexp))
+                                  (argi (cadr fn-argi)))
+                         (if (= argi 0)
+                             ;; Complete operators.
+                             (list
+                              (car bounds) (cdr bounds)
+                              (mapcar #'car kubed-list-filter-operator-alist))
+                           (when (car fn-argi)
+                             (cond
+                              ((= argi 1)
+                               ;; Complete column names.
+                               (list (car bounds) (cdr bounds) cols))
+                              ((= argi 2)
+                               ;; Complete column values.
+                               (when-let ((beg (nth 1 (syntax-ppss)))
+                                          ;; Grab preceding symbol.
+                                          (col (save-excursion
+                                                 (goto-char beg)
+                                                 (forward-char 1)
+                                                 (forward-sexp 2)
+                                                 (thing-at-point 'symbol))))
+                                 (list (car bounds) (cdr bounds)
+                                       (alist-get col vals
+                                                  nil nil #'string=)))))))))))
+                 nil t))
+            (read-from-minibuffer
+             (format-prompt prompt "disable")
+             (mapconcat #'prin1-to-string kubed-list-filter " ")
+             kubed-list-read-filter-map nil
+             kubed-list-filter-history-variable ""))))
+    (car (ignore-errors (read-from-string (format "(%s)" filter))))))
+
+(defun kubed-list-set-filter (filter)
+  "Set the filter of the current buffer to FILTER.
+
+FILTER determines which resources to keep.  FILTER can be an atomic
+filter, which is a list (OP COL VAL), where OP is an operator defined in
+`kubed-list-filter-operator-alist' (which see), COL is a symbol whose
+name is a column name, and VAL is a string or an object whose printed
+representation is compared to the value of the column COL according to
+OP.  For example, the atomic filter (= Name foobar) keeps only resources
+whose name is \"foobar\".  (= Name \"foobar\") does exactly the same.
+To negate an atomic filter, quote it.  E.g. use \\='(~ Namespace kube)
+to hide all resources in namespaces whose name contains \"kube\".
+
+FILTER can also be a list of sub-filters (SUB1 SUB2 ...) where each
+sub-filter is either an atomic filter or a list of atomic filters.  If a
+sub-filter is a list of atomic filters, then that sub-filter denotes the
+disjunction of those atomic filters.  FILTER denotes the conjunction of
+the sub-filters.  In particular, FILTER nil denotes the empty
+conjunction which is always true (keeps all resources).
+
+More examples:
+
+- `((= Name foobar) (~ Namespace kube))': keep only resources named
+  \"foobar\" in namespaces that contain \"kube\".
+- `(((= Name foobar) (~ Namespace kube)))': keep resources that are
+  either named \"foobar\" or in a namespace that contains \"kube\".
+- `(((= Name foobar) (~ Namespace kube)) \\='(~ Starttime 2024-07))':
+  keep only resources that are either named \"foobar\" or in a namespace
+  that contains \"kube\", and were not started during July 2024.
+
+Interactively, prompt for FILTER sans the outermost set of parenthesis.
+For example, enter \"= Name foobar\" in the minibuffer to specify the
+atomic FILTER (= Name foobar).
+
+See also Info node \"(kubed) List Filter\"."
+  (interactive (list (kubed-list-read-filter "Set filter")) kubed-list-mode)
+  (when-let ((validation-error (kubed-list-validate-filter filter)))
+    (user-error validation-error))
+  (setq-local kubed-list-filter filter)
+  (revert-buffer))
+
+(defun kubed-list-mark-for-deletion ()
+  "Mark Kubernetes resource at point for deletion."
+  (interactive "" kubed-list-mode)
+  (tabulated-list-put-tag (propertize "D" 'help-echo "Marked for deletion") t))
+
+(defun kubed-list-unmark ()
+  "Remove mark from Kubernetes resource at point."
+  (interactive "" kubed-list-mode)
+  (tabulated-list-put-tag " " t))
+
+(defun kubed-list-previous-column (&optional n)
+  "Move backward N columns.
+
+Interactively, N is the numeric value of the prefix argument, defaulting
+to 1."
+  (interactive "p" kubed-list-mode)
+  (kubed-list-next-column (- n)))
+
+(defun kubed-list-next-column (&optional n)
+  "Move forward N columns.
+
+Interactively, N is the numeric value of the prefix argument, defaulting
+to 1."
+  (interactive "p" kubed-list-mode)
+  (let ((next (point))
+        (times (abs (or n 1)))
+        (dir-fn (if (< 0 n)
+                    #'next-single-property-change
+                  #'previous-single-property-change)))
+    (dotimes (_ times)
+      (setq next (funcall dir-fn next 'tabulated-list-column-name))
+      (when (equal (char-after next) ?\n)
+        ;; At line boundary, go to first/last column of next line.
+        (setq next (funcall dir-fn next 'tabulated-list-column-name)))
+      (unless next (user-error "End of table")))
+    (goto-char next)))
+
+(defun kubed-list-copy-as-kill (click)
+  "Copy name of Kubernetes resource at CLICK into the kill ring."
+  (interactive (list last-nonmenu-event) kubed-list-mode)
+  (if-let ((ent (tabulated-list-get-entry (mouse-set-point click)))
+           (new (aref ent 0)))
+      (progn
+        (kill-new new)
+        (message "Copied resource name `%s'" new))
+    (user-error "No Kubernetes resource at point")))
+
+(defun kubed-list-context-menu (menu click)
+  "Extend MENU with common actions on Kubernetes resource at CLICK."
+  (when (tabulated-list-get-entry (posn-point (event-start click)))
+    (define-key menu [kubed-list-select-resource]
+                '(menu-item "Select" kubed-list-select-resource))
+    (define-key menu [kubed-list-display-resource]
+                '(menu-item "Display" kubed-list-display-resource))
+    (define-key menu [kubed-list-delete]
+                '(menu-item "Delete" kubed-list-delete))
+    (define-key menu [kubed-list-patch]
+                '(menu-item "Patch" kubed-list-patch))
+    (define-key menu [kubed-list-edit]
+                '(menu-item "Edit" kubed-list-edit))
+    (define-key menu [kubed-list-kubectl-command]
+                '(menu-item "Execute `kubectl' command" kubed-list-kubectl-command))
+    (define-key menu [kubed-list-copy-as-kill]
+                '(menu-item "Copy name" kubed-list-copy-as-kill)))
+  menu)
+
+(defun kubed-list-update (&optional quiet)
+  "Update list of Kubernetes resources.
+
+If optional argument QUIET is non-nil, do not emit a message when
+starting to update.  Display a message when the update is done
+regardless of QUIET."
+  (interactive "" kubed-list-mode)
+  (kubed-update kubed-list-type kubed-list-context kubed-list-namespace)
+  (force-mode-line-update)
+  (unless quiet (minibuffer-message (format "Updating Kubernetes %S..." kubed-list-type))))
+
+(defun kubed-list-delete-marked ()
+  "Delete marked Kubernetes resources."
+  (interactive "" kubed-list-mode)
+  (let (delete-list)
+    (save-excursion
+      (goto-char (point-min))
+      (while (not (eobp))
+        (when (eq (char-after) ?D)
+          (push (tabulated-list-get-id) delete-list))
+        (forward-line)))
+    (if delete-list
+        (when (y-or-n-p (format "Delete %d marked Kubernetes resources?"
+                                (length delete-list)))
+          (save-excursion
+            (goto-char (point-min))
+            (while (not (eobp))
+              (when (member (tabulated-list-get-id) delete-list)
+                (tabulated-list-put-tag
+                 (propertize "K" 'help-echo "Deletion in progress")))
+              (forward-line)))
+          (let ((errb (generate-new-buffer " *kubed-list-delete-marked-stderr*"))
+                (buf (current-buffer)))
+            (make-process
+             :name "*kubed-list-delete-marked*"
+             :stderr errb
+             :command (cons kubed-kubectl-program
+                            (append
+                             (when kubed-list-context
+                               (list "--context" kubed-list-context))
+                             (when kubed-list-namespace
+                               (list "--namespace" kubed-list-namespace))
+                             (list "delete" kubed-list-type)
+                             delete-list))
+             :sentinel (lambda (_proc status)
+                         (cond
+                          ((string= status "finished\n")
+                           (message (format "Deleted %d marked Kubernetes resources."
+                                            (length delete-list)))
+                           (when (buffer-live-p buf)
+                             (with-current-buffer buf
+                               (kubed-list-update t))))
+                          ((string= status "exited abnormally with code 1\n")
+                           (with-current-buffer errb
+                             (goto-char (point-max))
+                             (insert "\n" status))
+                           (display-buffer errb)))))))
+      (user-error "No Kubernetes resources marked for deletion"))))
+
+(defun kubed-list-display-resource (click)
+  "Display Kubernetes resource at CLICK in another window."
+  (interactive (list last-nonmenu-event) kubed-list-mode)
+  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
+      (kubed-display-resource
+       kubed-list-type resource kubed-list-context kubed-list-namespace)
+    (user-error "No Kubernetes resource at point")))
+
+(defun kubed-list-select-resource (click)
+  "Display Kubernetes resource at CLICK in current window."
+  (interactive (list last-nonmenu-event) kubed-list-mode)
+  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
+      (switch-to-buffer
+       (kubed-display-resource-in-buffer
+        (concat "*Kubed "
+                (kubed-display-resource-short-description
+                 kubed-list-type resource kubed-list-context kubed-list-namespace)
+                "*")
+        kubed-list-type resource kubed-list-context kubed-list-namespace))
+    (user-error "No Kubernetes resource at point")))
+
+(defun kubed-list-select-resource-other-window (click)
+  "Display Kubernetes resource at CLICK in other window and select that window."
+  (interactive (list last-nonmenu-event) kubed-list-mode)
+  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
+      (switch-to-buffer-other-window
+       (kubed-display-resource-in-buffer
+        (concat "*Kubed "
+                (kubed-display-resource-short-description
+                 kubed-list-type resource kubed-list-context kubed-list-namespace)
+                "*")
+        kubed-list-type resource kubed-list-context kubed-list-namespace))
+    (user-error "No Kubernetes resource at point")))
+
+(defun kubed-list-delete (click)
+  "Delete Kubernetes resource at CLICK."
+  (interactive (list last-nonmenu-event) kubed-list-mode)
+  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
+      (when (y-or-n-p (format "Delete `%s'?" resource))
+        (kubed-delete-resources kubed-list-type (list resource)
+                                kubed-list-context kubed-list-namespace))
+    (user-error "No Kubernetes resource at point")))
+
+(defun kubed-list-patch (click)
+  "Patch Kubernetes resource at CLICK."
+  (interactive (list last-nonmenu-event) kubed-list-mode)
+  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
+      (kubed-patch kubed-list-type resource
+                   (kubed-read-patch) kubed-list-context kubed-list-namespace)
+    (user-error "No Kubernetes resource at point")))
+
+(defun kubed-list-edit (click)
+  "Edit Kubernetes resource at CLICK."
+  (interactive (list last-nonmenu-event) kubed-list-mode)
+  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
+      (kubed-edit-resource kubed-list-type resource
+                           kubed-list-context kubed-list-namespace)
+    (user-error "No Kubernetes resource at point")))
+
+(defun kubed-list-kubectl-command (click)
+  "Use Kubernetes resource at CLICK as argument for `kubectl' command."
+  (interactive (list last-nonmenu-event) kubed-list-mode)
+  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
+      (kubed-kubectl-command
+       (kubed-read-kubectl-command
+        "Execute command: "
+        (cons (concat
+               " "
+               (when kubed-list-namespace (concat "-n " kubed-list-namespace " "))
+               (when kubed-list-context (concat "--context " kubed-list-context " "))
+               kubed-list-type " " resource)
+              ;; Put point after "kubectl ".
+              0)))
+    (user-error "No Kubernetes resource at point")))
+
+(defun kubed-list-logs (click)
+  "Show logs for Kubernetes resource at CLICK."
+  (interactive (list last-nonmenu-event) kubed-list-mode)
+  (if-let ((resource (tabulated-list-get-id (mouse-set-point click))))
+      (kubed-logs kubed-list-type resource kubed-list-context kubed-list-namespace
+                  t t nil t)
+    (user-error "No Kubernetes resource at point")))
+
+(defun kubed-list-create (definition &optional kind)
+  "Create Kubernetes resource of kind KIND from definition file DEFINITION."
+  (interactive (list (kubed-read-resource-definition-file-name)) kubed-list-mode)
+  (kubed-create definition kind kubed-list-context)
+  (kubed-list-update t))
+
+(defun kubed-list-column-number-at-point ()
+  "Return table column number at point."
+  (let ((start (current-column))
+        (nb-cols (1- (length tabulated-list-format)))
+        (col-nb 0)
+        (total-width tabulated-list-padding)
+        (found nil))
+    (while (and (not found) (< col-nb nb-cols))
+      (if (>= start
+              (setq total-width
+                    (+ total-width
+                       (cadr (aref tabulated-list-format col-nb))
+                       (or (plist-get (nthcdr 3 (aref tabulated-list-format
+                                                      col-nb))
+                                      :pad-right)
+                           1))))
+          (setq col-nb (1+ col-nb))
+        (setq found t)))
+    col-nb))
+
+(defun kubed-list-fit-column-width-to-content (n)
+  "Fit width of Nth table column to its content.
+
+If N is negative, fit all columns.  Interactively, N is the column
+number at point, or the numeric prefix argument if you provide one."
+  (interactive
+   (list (if current-prefix-arg
+             (prefix-numeric-value current-prefix-arg)
+           (kubed-list-column-number-at-point)))
+   kubed-list-mode)
+  (if (< n 0)
+      ;; Fit all columns.
+      (let* ((num-cols (length tabulated-list-format))
+             (widths (apply #'vector (seq-map
+                                      ;; +2 to make room for sorting icon.
+                                      (lambda (col) (+ 2 (length (car col))))
+                                      tabulated-list-format))))
+        (save-excursion
+          (goto-char (point-min))
+          (while-let ((entry (tabulated-list-get-entry)))
+            (dotimes (i num-cols)
+              (aset widths i (max (aref widths i) (length (aref entry i)))))
+            (forward-line)))
+        (setq tabulated-list-format (copy-tree tabulated-list-format t))
+        (dotimes (i num-cols)
+          (setf (cadr (aref tabulated-list-format i))
+                (1+ (aref widths i)))))
+    ;; Fit Nth column.
+    (let* ((width (+ 2 (length (car (aref tabulated-list-format n))))))
+      (save-excursion
+        (goto-char (point-min))
+        (while-let ((entry (tabulated-list-get-entry)))
+          (setq width (max width (length (aref entry n))))
+          (forward-line)))
+      (setq tabulated-list-format (copy-tree tabulated-list-format t))
+      (setf (cadr (aref tabulated-list-format n)) (1+ width))))
+  (tabulated-list-print t)
+  (tabulated-list-init-header))
+
+(declare-function kubed-list-transient                 "kubed-transient" ())
+(declare-function kubed-transient-logs-for-pod         "kubed-transient" (val))
+(declare-function kubed-transient-logs-for-deployment  "kubed-transient" (val))
+(declare-function kubed-transient-logs-for-statefulset "kubed-transient" (val))
+(declare-function kubed-transient-logs-for-replicaset  "kubed-transient" (val))
+(declare-function kubed-transient-logs-for-daemonset   "kubed-transient" (val))
+(declare-function kubed-transient-logs-for-job         "kubed-transient" (val))
+(declare-function kubed-transient-logs-for-service     "kubed-transient" (val))
+
+(defvar-keymap kubed-list-mode-map
+  :doc "Common keymap for Kubernetes resource list buffers."
+  "RET" #'kubed-list-select-resource
+  "o" #'kubed-list-select-resource-other-window
+  "C-o" #'kubed-list-display-resource
+  "D" #'kubed-list-delete
+  "P" #'kubed-list-patch
+  "x" #'kubed-list-delete-marked
+  "e" #'kubed-list-edit
+  "!" #'kubed-list-kubectl-command
+  "g" #'kubed-list-update
+  "/" #'kubed-list-set-filter
+  "|" #'kubed-list-fit-column-width-to-content
+  "d" #'kubed-list-mark-for-deletion
+  "u" #'kubed-list-unmark
+  "w" #'kubed-list-copy-as-kill
+  "C-i" #'kubed-list-next-column
+  "TAB" #'kubed-list-next-column
+  "C-S-i" #'kubed-list-previous-column
+  "S-TAB" #'kubed-list-previous-column
+  "<backtab>" #'kubed-list-previous-column
+  "+" #'kubed-list-create
+  "?" #'kubed-list-transient)
+
+(defun kubed-list-entries ()
+  "`tabulated-list-entries' function for `kubed-list-mode'."
+  (let ((pred (kubed-list-interpret-filter))
+        (ents nil))
+    (dolist (ent (alist-get 'resources (kubed--alist kubed-list-type
+                                                     kubed-list-context
+                                                     kubed-list-namespace)))
+      (when (funcall pred ent) (push ent ents)))
+    (reverse ents)))
+
+;;;###autoload
+(defun kubed-list-handle-bookmark (bookmark)
+  "Display Kubernetes resource according to BOOKMARK."
+  (require 'bookmark)
+  (let* ((type (bookmark-prop-get bookmark 'type))
+         (context (bookmark-prop-get bookmark 'context))
+         (namespace (bookmark-prop-get bookmark 'namespace))
+         (current (bookmark-prop-get bookmark 'current))
+         (buff-fn (intern (format "kubed-%s-buffer" type)))
+         (buff (apply buff-fn context (when namespace (list namespace)))))
+    (set-buffer buff)
+    (when current (kubed-list-go-to-line current))))
+
+(put 'kubed-list-handle-bookmark 'bookmark-handler-type "KubedList")
+
+(defun kubed-list-make-bookmark ()
+  "Return bookmark pointing to currently displayed Kubernetes resource."
+  (require 'bookmark)
+  (cons
+   (concat kubed-list-type
+           (when kubed-list-namespace (concat "@" kubed-list-namespace))
+           (when kubed-list-context   (concat "[" kubed-list-context "]")))
+   (append
+    (list
+     (cons 'handler #'kubed-list-handle-bookmark)
+     (cons 'filter kubed-list-filter)
+     (cons 'type kubed-list-type)
+     (cons 'context kubed-list-context)
+     (cons 'current (tabulated-list-get-id))
+     (cons 'namespace kubed-list-namespace)))))
+
+(defun kubed-list-revert (&rest _)
+  "Revert the current Kubernetes resources list buffer.
+
+This is the `revert-buffer-function' for `kubed-list-mode' and its
+derivatives.  This function does not fetch new data from Kubernetes, it
+only (re)displays the existing data."
+  (let (marks)
+    (save-excursion
+      (goto-char (point-min))
+      (while (not (eobp))
+        (unless (eq (char-after) ?\s)
+          (push (cons (tabulated-list-get-id)
+                      ;; Preserve mark text properties.
+                      (buffer-substring (point) (1+ (point))))
+                marks))
+        (forward-line)))
+    (tabulated-list-revert)
+    (save-excursion
+      (goto-char (point-min))
+      (while (not (eobp))
+        (let ((id (tabulated-list-get-id)))
+          (when-let ((mark (alist-get id marks nil nil #'equal)))
+            (tabulated-list-put-tag mark)))
+        (forward-line)))))
+
+(define-derived-mode kubed-list-mode tabulated-list-mode "Kubernetes Resources"
+  "Major mode for listing Kubernetes resources.
+
+Modes for specific resource types, such as `kubed-pods-mode', use this
+mode as their parent."
+  :interactive nil
+  (setq-local truncate-string-ellipsis (propertize ">" 'face 'shadow)
+              tabulated-list-entries #'kubed-list-entries
+              bookmark-make-record-function #'kubed-list-make-bookmark
+              revert-buffer-function #'kubed-list-revert)
+  (add-hook 'context-menu-functions #'kubed-list-context-menu nil t))
+
+;;;###autoload
+(defun kubed-delete-resources (type resources context &optional namespace)
+  "Delete Kubernetes RESOURCES of type TYPE in context CONTEXT.
+
+For namespaced resource types, NAMESPACE is the namespace of RESOURCE.
+
+Interactively, use the current context and namespace by default, and
+prompt for TYPE and RESOURCES.  With a prefix argument \
+\\[universal-argument],
+prompt for NAMESPACE.  With a double prefix argument \
+\\[universal-argument] \\[universal-argument],
+prompt for CONTEXT as well."
+  (interactive
+   (let ((type nil) (context nil) (namespace nil))
+     (dolist (arg (kubed-transient-args 'kubed-transient-delete))
+       (cond
+        ((string-match "--namespace=\\(.+\\)" arg)
+         (setq namespace (match-string 1 arg)))
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (unless type
+       (setq type (kubed-read-resource-type "Type of resource to delete"
+                                            nil context)))
+     (when (and (null namespace) (kubed-namespaced-p type context))
+       (setq namespace (kubed--namespace context current-prefix-arg)))
+     (list type (kubed-read-resource-name type "Delete" nil t
+                                          context namespace)
+           context namespace)))
+  (unless resources (user-error "You didn't specify %s to delete" type))
+  (message (format "Deleting Kubernetes %s `%s'..."
+                   type (string-join resources "', `")))
+  (if (zerop (apply #'call-process
+                    kubed-kubectl-program nil nil nil
+                    "delete" type
+                    (append (when namespace (list "-n" namespace))
+                            (when context (list "--context" context))
+                            resources)))
+      (message (format "Deleting Kubernetes %s `%s'...  Done."
+                       type (string-join resources "', `")))
+    (error (format "Failed to delete Kubernetes %s `%s'"
+                   type (string-join resources "', `")))))
+
+;;;###autoload
+(defun kubed-edit-resource (type resource context &optional namespace)
+  "Edit Kubernetes RESOURCE of type TYPE in context CONTEXT.
+
+For namespaced resource types, NAMESPACE is the namespace of RESOURCE.
+
+Interactively, use the current context and namespace by default, and
+prompt for TYPE and RESOURCES.  With a prefix argument \
+\\[universal-argument],
+prompt for NAMESPACE.  With a double prefix argument \
+\\[universal-argument] \\[universal-argument],
+prompt for CONTEXT as well."
+  (interactive
+   (let ((type nil) (context nil) (namespace nil))
+     (dolist (arg (kubed-transient-args 'kubed-transient-edit))
+       (cond
+        ((string-match "--namespace=\\(.+\\)" arg)
+         (setq namespace (match-string 1 arg)))
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (unless type
+       (setq type (kubed-read-resource-type "Type of resource to edit"
+                                            nil context)))
+     (when (and (null namespace) (kubed-namespaced-p type context))
+       (setq namespace (kubed--namespace context current-prefix-arg)))
+     (list type (kubed-read-resource-name type "Edit" nil nil
+                                          context namespace)
+           context namespace)))
+  (unless (bound-and-true-p server-process) (server-start))
+  (let ((process-environment
+         (cons (if (boundp 'emacsclient-program-name)
+                   (concat "KUBE_EDITOR=" emacsclient-program-name)
+                 "KUBE_EDITOR=emacsclient")
+               process-environment)))
+    (apply #'start-process
+           (format "*kubed-%S-edit*" type) nil
+           kubed-kubectl-program "edit" type resource
+           (append
+            (when namespace (list "-n" namespace))
+            (when context (list "--context" context))))))
+
+(defcustom kubed-list-mode-line-format
+  '(:eval (cond
+           ((process-live-p
+             (alist-get 'process
+                        (kubed--alist kubed-list-type
+                                      kubed-list-context
+                                      kubed-list-namespace)))
+            (propertize "[...]" 'help-echo "Updating..."))
+           (kubed-list-filter
+            (propertize
+             (concat "[" (mapconcat #'prin1-to-string kubed-list-filter " ") "]")
+             'help-echo "Current filter"))))
+  "Mode line construct for indicating status of Kubernetes resources list."
+  :type 'sexp
+  :risky t)
+
+;;;###autoload
+(defmacro kubed-define-resource (resource &optional properties &rest commands)
+  "Define Kubernetes RESOURCE with associated PROPERTIES and COMMANDS.
+
+RESOURCE is a symbol corresponding to a Kubernetes resource type, such
+as `pod' or `service'.  This macro defines the following commands for
+interacting with Kubernetes RESOURCEs:
+
+- `kubed-display-RESOURCE': prompt for a RESOURCE and display its
+  description in YAML format.  See also `kubed-yaml-setup-hook'.
+- `kubed-edit-RESOURCE': prompt for a RESOURCE and edit it.
+- `kubed-delete-RESOURCE': prompt for a RESOURCE and delete it.
+- `kubed-list-RESOURCEs': display a buffer listing all RESOURCEs in the
+  current namespace.  The RESOURCEs list buffer uses a dedicated major
+  mode, `kubed-RESOURCEs-mode', which is also defined by this macro.
+- `kubed-create-RESOURCE': create a RESOURCE from a YAML or a JSON file.
+- `kubed-explain-RESOURCEs': show buffer with help about RESOURCEs.
+
+This macro also defines a prefix keymap, `kubed-RESOURCE-prefix-map',
+with bindings for the above commands.
+
+PROPERTIES is a list of lists (PROP JSON-PATH WIDTH SORT FORMAT . ATTRS)
+that specify properties of RESOURCEs.  PROP is the name of the property,
+as a symbol; JSON-PATH is a JSONPath expression that evaluates to the
+value of PROP when applied to the JSON representation of a RESOURCE.
+WIDTH, SORT, FORMAT and ATTRS are optional and can be omitted.  WIDTH is
+used as the default width of the column corresponding to PROP in
+RESOURCEs list buffers; SORT is sort predicate, a function that takes
+two values of PROP as strings and returns non-nil if the first should
+sort before the second; FORMAT is a function that takes a value of PROP
+and formats it.  If you provide a FORMAT function and a SORT function,
+then the SORT function gets the formatted values (the output of the
+FORMAT function), not the original values.  If you want to sort based on
+the unformatted original values, you can store them as text properties
+in your FORMAT function and access them in your SORT function.
+
+ATTRS is a plist of additional attributes of the PROP column, see
+`tabulated-list-format' for available attributes.
+
+For example, if PROPERTIES is (phase \".status.phase\" 10) that means
+that RESOURCE has a `phase' property at JSONPath \".status.phase\" whose
+values are typically 10 columns wide.  The first property in PROPERTIES
+is used to annotate completion candidates when prompting for a RESOURCE.
+
+COMMANDS is a list of elements (COMMAND KEYS DOC-PREFIX . BODY) that
+define commands for RESOURCE list buffers.  COMMAND is a symbol
+specifying the suffix of the command name, the full name of the command
+is `kubed-RESOURCEs-COMMAND' (for example, `kubed-pods-shell'); KEYS is
+either a string that specifies a key sequence to bind to the command in
+`kubed-RESOURCEs-mode-map', or nil if the command should not be bound;
+DOC-PREFIX is a string used to construct the docstring of the command,
+this macro appends the string \" Kubernetes RESOURCE at point.\" to it
+to obtain the final docstring; lastly, BODY is the body the command.
+Within BODY, the variable RESOURCE is let-bound to the name of the
+RESOURCE at point.  For example, if RESOURCE is `pod', the following
+COMMANDS element defines a command `kubed-pods-frob' and binds it to the
+key \"f\" in `kubed-pods-mode-map':
+
+  (frob \"f\" \"Frobnicate\"
+        (message \"Preparing...\")
+        (frobnicate-pod pod)
+        (message \"Done.\"))
+
+By default, this macro assumes that RESOURCE is namespaced.  To define a
+namespaceless resource type, put `:namespaced nil' before COMMANDS:
+
+  (kubed-define-resource global-thingy (PROP1 PROP2 ...) :namespaced nil
+    CMD1
+    CMD2
+    ...)
+
+Other keyword arguments that go between PROPERTIES and COMMANDS are:
+
+- `:create (ARGLIST DOCSTRING INTERACTIVE BODY...)': specialize the
+  resource creation command, `kubed-create-RESOURCE'.  ARGLIST,
+  DOCSTRING, INTERACTIVE and BODY have the same meaning as in `defun'.
+- `:prefix ((KEY LABEL DEFINITION)...)': additional keybinding for the
+  prefix keymap `kubed-RESOURCE-prefix-map' and the
+  `kubed-RESOURCE-menu-map' menu.  Each element (KEY LABEL DEFINITION)
+  says to bind KEY to DEFINITION in `kubed-RESOURCE-menu-map', and to
+  add DEFINITION to `kubed-RESOURCE-menu-map' with the label LABEL.
+- `:plural PLURAL': specify plural form of RESOURCE, as a symbol.  If
+  you omit this keyword argument, the plural form defaults to RESOURCE
+  followed by \"s\".
+- `:logs t': generate `kubed-logs-for-RESOURCE' command.
+- `:suffixes (SUFFIX...)': add type-specific transient suffixes to
+  `kubed-list-transient'."
+  (declare (indent 2))
+  (let ((plrl-var (intern (format "%Ss"                         resource)))
+        (read-fun (intern (format "kubed-read-%S"               resource)))
+        (dsp-name (intern (format "kubed-display-%S"            resource)))
+        (edt-name (intern (format "kubed-edit-%S"               resource)))
+        (crt-name (intern (format "kubed-create-%S"             resource)))
+        (map-name (intern (format "kubed-%S-prefix-map"         resource)))
+        (menu-map (intern (format "kubed-%S-menu-map"           resource)))
+        (logs-cmd (intern (format "kubed-logs-for-%S"           resource)))
+        (logs-trs (intern (format "kubed-transient-logs-for-%S" resource)))
+        (namespaced t) (logs nil)
+        (keyword nil)
+        frmt-var buff-fun list-cmd expl-cmd dlt-name mod-name
+        ctxt-fun crt-spec prf-keys hist-var trs-cols)
+
+    ;; Process keyword arguments.
+    (while (keywordp (car commands))
+      (setq keyword (pop commands))
+      (cond
+       ((eq keyword :namespaced) (setq namespaced (pop commands)))
+       ((eq keyword :logs)       (setq logs       (pop commands)))
+       ((eq keyword :create)     (setq crt-spec   (pop commands)))
+       ((eq keyword :prefix)     (setq prf-keys   (pop commands)))
+       ((eq keyword :plural)     (setq plrl-var   (pop commands)))
+       ((eq keyword :suffixes)   (setq trs-cols   (pop commands)))
+       ;; FIXME: Add error for unknown keywords.
+       (t (pop commands))))
+
+    (setq frmt-var (intern (format "kubed-%S-columns"       plrl-var))
+          hist-var (intern (format "kubed-%S-history"       plrl-var))
+          buff-fun (intern (format "kubed-%S-buffer"        plrl-var))
+          list-cmd (intern (format "kubed-list-%S"          plrl-var))
+          expl-cmd (intern (format "kubed-explain-%S"       plrl-var))
+          dlt-name (intern (format "kubed-delete-%S"        plrl-var))
+          mod-name (intern (format "kubed-%S-mode"          plrl-var))
+          ctxt-fun (intern (format "kubed-%S-context-menu"  plrl-var)))
+
+    (when logs (push `("L" "Show Logs" ,logs-cmd) prf-keys))
+
+    ;; Generate code.
+    `(progn
+       (setf (alist-get ,(symbol-name plrl-var) kubed--columns nil nil #'string=)
+             (list
+              '("NAME:.metadata.name")
+              ,@(mapcar (lambda (p)
+                          `(cons ,(concat (upcase (symbol-name (car p)))
+                                          ":"
+                                          (cadr p))
+                                 ,(nth 4 p)))
+                        properties)))
+
+       (defvar ,hist-var nil
+         ,(format "History list for `%S'." read-fun))
+
+       (defun ,read-fun (prompt &optional default multi context
+                                . ,(when namespaced '(namespace)))
+         ,(format "Prompt with PROMPT for a Kubernetes %S name.
+
+Optional argument DEFAULT is the minibuffer default argument.
+
+Non-nil optional argument MULTI says to read and return a list
+of %S, instead of just one." resource plrl-var)
+         (kubed-read-resource-name ,(symbol-name plrl-var) prompt default multi context . ,(when namespaced '(namespace))))
+
+       (defun ,dsp-name (,resource &optional context . ,(when namespaced '(namespace)))
+         ,(if namespaced
+              (format "Display Kubernetes %S %s in CONTEXT and NAMESPACE.
+
+Interactively, use the current context and namespace by default.  With a
+prefix argument \\[universal-argument], prompt for NAMESPACE.  With a
+double prefix argument \\[universal-argument] \\[universal-argument], \
+prompt for CONTEXT as well." resource (upcase (symbol-name resource)))
+            (format "Display Kubernetes %S %s in context CONTEXT.
+
+Interactively, use the current context.  With a prefix argument
+\\[universal-argument], prompt for CONTEXT." resource (upcase (symbol-name resource))))
+         (interactive
+          ,(if namespaced
+               `(let ((context nil) (namespace nil))
+                  (dolist (arg (kubed-transient-args 'kubed-transient-display))
+                    (cond
+                     ((string-match "--namespace=\\(.+\\)" arg)
+                      (setq namespace (match-string 1 arg)))
+                     ((string-match "--context=\\(.+\\)" arg)
+                      (setq context (match-string 1 arg)))))
+                  (unless context
+                    (setq context
+                          (let ((cxt (kubed-local-context)))
+                            (if (equal current-prefix-arg '(16))
+                                (kubed-read-context "Context" cxt)
+                              cxt))))
+                  (unless namespace
+                    (setq namespace (kubed--namespace context current-prefix-arg)))
+                  (list (,read-fun "Display" nil nil context namespace) context namespace))
+             `(let ((context nil))
+                (dolist (arg (kubed-transient-args 'kubed-transient-display))
+                  (cond
+                   ((string-match "--context=\\(.+\\)" arg)
+                    (setq context (match-string 1 arg)))))
+                (unless context
+                  (setq context
+                        (let ((cxt (kubed-local-context)))
+                          (if current-prefix-arg
+                              (kubed-read-context "Context" cxt)
+                            cxt))))
+                (list (,read-fun "Display" nil nil context) context))))
+         (let ((context (or context (kubed-local-context))))
+           (kubed-display-resource
+            ,(symbol-name plrl-var) ,resource context
+            . ,(when namespaced '((or namespace (kubed--namespace context)))))))
+
+       (defun ,edt-name (,resource &optional context . ,(when namespaced '(namespace)))
+         ,(if namespaced
+              (format "Edit Kubernetes %S %s in CONTEXT and NAMESPACE.
+
+Interactively, use the current context and namespace by default.  With a
+prefix argument \\[universal-argument], prompt for NAMESPACE.  With a
+double prefix argument \\[universal-argument] \\[universal-argument], \
+prompt for CONTEXT as well." resource (upcase (symbol-name resource)))
+            (format "Edit Kubernetes %S %s in context CONTEXT.
+
+Interactively, use the current context.  With a prefix argument
+\\[universal-argument], prompt for CONTEXT." resource (upcase (symbol-name resource))))
+         (interactive
+          ,(if namespaced
+               `(let ((context nil) (namespace nil))
+                  (dolist (arg (kubed-transient-args 'kubed-transient-edit))
+                    (cond
+                     ((string-match "--namespace=\\(.+\\)" arg)
+                      (setq namespace (match-string 1 arg)))
+                     ((string-match "--context=\\(.+\\)" arg)
+                      (setq context (match-string 1 arg)))))
+                  (unless context
+                    (setq context
+                          (let ((cxt (kubed-local-context)))
+                            (if (equal current-prefix-arg '(16))
+                                (kubed-read-context "Context" cxt)
+                              cxt))))
+                  (unless namespace
+                    (setq namespace (kubed--namespace context current-prefix-arg)))
+                  (list (,read-fun "Edit" nil nil context namespace) context namespace))
+             `(let ((context nil))
+                (dolist (arg (kubed-transient-args 'kubed-transient-edit))
+                  (cond
+                   ((string-match "--context=\\(.+\\)" arg)
+                    (setq context (match-string 1 arg)))))
+                (unless context
+                  (setq context
+                        (let ((cxt (kubed-local-context)))
+                          (if current-prefix-arg
+                              (kubed-read-context "Context" cxt)
+                            cxt))))
+                (list (,read-fun "Edit" nil nil context) context))))
+         (let ((context (or context (kubed-local-context))))
+           (kubed-edit-resource
+            ,(symbol-name plrl-var) ,resource context
+            . ,(when namespaced '((or namespace (kubed--namespace context)))))))
+
+       (defun ,dlt-name (,plrl-var &optional context
+                                   . ,(when namespaced '(namespace)))
+         ,(if namespaced
+              (format "Delete Kubernetes %S %s in CONTEXT and NAMESPACE.
+
+Interactively, use the current context and namespace by default.  With a
+prefix argument \\[universal-argument], prompt for NAMESPACE.  With a
+double prefix argument \\[universal-argument] \\[universal-argument], \
+prompt for CONTEXT as well." plrl-var (upcase (symbol-name plrl-var)))
+            (format "Delete Kubernetes %S %s in context CONTEXT.
+
+Interactively, use the current context.  With a prefix argument
+\\[universal-argument], prompt for CONTEXT." plrl-var (upcase (symbol-name plrl-var))))
+         (interactive
+          ,(if namespaced
+               `(let ((context nil) (namespace nil))
+                  (dolist (arg (kubed-transient-args 'kubed-transient-delete))
+                    (cond
+                     ((string-match "--namespace=\\(.+\\)" arg)
+                      (setq namespace (match-string 1 arg)))
+                     ((string-match "--context=\\(.+\\)" arg)
+                      (setq context (match-string 1 arg)))))
+                  (unless context
+                    (setq context
+                          (let ((cxt (kubed-local-context)))
+                            (if (equal current-prefix-arg '(16))
+                                (kubed-read-context "Context" cxt)
+                              cxt))))
+                  (unless namespace
+                    (setq namespace (kubed--namespace context current-prefix-arg)))
+                  (list (,read-fun "Delete" nil t context namespace) context namespace))
+             `(let ((context nil))
+                (dolist (arg (kubed-transient-args 'kubed-transient-delete))
+                  (cond
+                   ((string-match "--context=\\(.+\\)" arg)
+                    (setq context (match-string 1 arg)))))
+                (unless context
+                  (setq context
+                        (let ((cxt (kubed-local-context)))
+                          (if current-prefix-arg
+                              (kubed-read-context "Context" cxt)
+                            cxt))))
+                (list (,read-fun "Delete" nil t context) context))))
+         (unless ,plrl-var
+           (user-error ,(format "You didn't specify %S to delete" plrl-var)))
+         (let ((context (or context (kubed-local-context))))
+           (kubed-delete-resources
+            ,(symbol-name plrl-var) ,plrl-var context
+            . ,(when namespaced '((or namespace (kubed--namespace context)))))))
+
+       ,(if crt-spec `(defun ,crt-name . ,crt-spec)
+          `(defun ,crt-name (definition &optional context)
+             ,(format "Create Kubernetes %s from file DEFINITION in CONTEXT.
+
+Interactively, prompt for DEFINITION and use the current context.  With
+a prefix argument \\[universal-argument], prompt for CONTEXT too."
+                      (symbol-name resource))
+             (interactive
+              (let ((context nil))
+                (dolist (arg (kubed-transient-args 'kubed-transient-create))
+                  (cond
+                   ((string-match "--context=\\(.+\\)" arg)
+                    (setq context (match-string 1 arg)))))
+                (unless context
+                  (setq context
+                        (let ((cxt (kubed-local-context)))
+                          (if current-prefix-arg
+                              (kubed-read-context "Context" cxt)
+                            cxt))))
+                (list (kubed-read-resource-definition-file-name ,(symbol-name resource))
+                      context)))
+             (kubed-create definition ,(symbol-name resource) context)
+             (kubed-update ,(symbol-name plrl-var) context)))
+
+       ,@(when logs
+           `((defun ,logs-cmd
+                 ( ,resource &optional context namespace
+                   container follow limit prefix since tail timestamps)
+               ,(format "Show logs for Kubernetes %S %s."
+                        resource (upcase (symbol-name resource)))
+               (interactive
+                (let ( ,resource context namespace
+                       container follow limit prefix since tail timestamps)
+                  (dolist (arg (kubed-transient-args
+                                ',logs-trs))
+                    (cond
+                     ((string-match "--namespace=\\(.+\\)" arg)
+                      (setq namespace (match-string 1 arg)))
+                     ((string-match "--context=\\(.+\\)" arg)
+                      (setq context (match-string 1 arg)))
+                     ((string-match "--limit-bytes=\\(.+\\)" arg)
+                      (setq limit (string-to-number (match-string 1 arg))))
+                     ((string-match "--tail=\\(.+\\)" arg)
+                      (setq tail (string-to-number (match-string 1 arg))))
+                     ((string-match "--since-time=\\(.+\\)" arg)
+                      (setq since (match-string 1 arg)))
+                     ((equal "--all-containers" arg) (setq container t))
+                     ((equal "--follow" arg) (setq follow t))
+                     ((equal "--prefix" arg) (setq prefix t))
+                     ((equal "--timestamps" arg) (setq timestamps t))))
+                  (unless context
+                    (setq context
+                          (let ((cxt (kubed-local-context)))
+                            (if (equal current-prefix-arg '(16))
+                                (kubed-read-context "Context" cxt)
+                              cxt))))
+                  (unless namespace
+                    (setq namespace (kubed--namespace context current-prefix-arg)))
+                  (setq ,resource (,read-fun "Show logs for"
+                                             (and (equal context kubed-list-context)
+                                                  (equal namespace kubed-list-namespace)
+                                                  (equal ,(symbol-name plrl-var) kubed-list-type)
+                                                  (tabulated-list-get-id (mouse-set-point last-nonmenu-event)))
+                                             nil context namespace))
+                  (list ,resource context namespace
+                        ,(if (eq resource 'pod)
+                             '(or container
+                                  (kubed-read-container pod "Container" t
+                                                        context namespace))
+                           'container)
+                        follow limit prefix since tail timestamps)))
+               (kubed-logs ,(symbol-name plrl-var) ,resource context namespace container
+                           follow limit prefix since tail timestamps))))
+
+       ,@(let ((click-var (gensym "click")))
+           (mapcar
+            (pcase-lambda (`(,suffix ,_key ,desc . ,body))
+              `(defun ,(intern (format "kubed-%S-%S" plrl-var suffix)) (,click-var)
+                 ,(format "%s Kubernetes %S at point." desc resource)
+                 (interactive (list last-nonmenu-event) ,mod-name)
+                 (if-let ((,resource (tabulated-list-get-id (mouse-set-point ,click-var))))
+                     (progn ,@body)
+                   (user-error ,(format "No Kubernetes %S at point" resource)))))
+            commands))
+
+       (defvar-keymap ,(intern (format "kubed-%S-mode-map" plrl-var))
+         :doc ,(format "Keymap for `%S" mod-name)
+         "+" #',crt-name
+         ,@(when logs
+             `("l" #'kubed-list-logs
+               "L" #',logs-trs))
+         ,@(mapcan
+            (pcase-lambda (`(,suffix ,key ,_desc . ,_body))
+              (when key
+                (list key `#',(intern (format "kubed-%S-%S" plrl-var suffix)))))
+            commands))
+
+       (defvar ,frmt-var
+         ',(let ((i 0)
+                 (res nil))
+             (dolist (p properties)
+               (setq i (1+ i))
+               (push
+                (append
+                 (list (capitalize (symbol-name (car p)))
+                       (caddr p)
+                       (if-let ((sorter (cadddr p)))
+                           `(lambda (l r)
+                              (funcall ,sorter (aref (cadr l) ,i) (aref (cadr r) ,i)))
+                         t))
+                 (nthcdr 5 p))
+                res))
+             (reverse res)))
+
+       (defun ,ctxt-fun (menu . ,(if commands '(click) '(_click)))
+         ,@(when commands
+             `((when (tabulated-list-get-entry (posn-point (event-start click)))
+                 ,@(mapcar
+                    (pcase-lambda (`(,suffix ,_key ,desc . ,_body))
+                      `(define-key
+                        menu [,(intern (format "kubed-%S-%S" plrl-var suffix))]
+                        (list 'menu-item ,(format "%s this %S" desc resource)
+                              #',(intern (format "kubed-%S-%S" plrl-var suffix)))))
+                    (reverse commands)))))
+         menu)
+
+       (define-derived-mode ,mod-name kubed-list-mode
+         '(,(format "Kubernetes %s" (capitalize (symbol-name plrl-var)))
+           kubed-list-mode-line-format)
+         ,(format "Major mode for listing Kubernetes %S." plrl-var)
+         :interactive nil
+         (setq kubed-list-filter-history-variable
+               ',(intern (format "kubed-%S-filter-history" plrl-var))
+               kubed-list-type ,(symbol-name plrl-var)
+               ,@(when trs-cols
+                   `(kubed-list-transient-extra-suffixes ',trs-cols))
+               tabulated-list-padding 2
+               tabulated-list-format (apply #'vector (cons kubed-name-column ,frmt-var)))
+         (add-hook 'context-menu-functions #',ctxt-fun nil t)
+         (tabulated-list-init-header))
+
+       (defun ,buff-fun (context . ,(when namespaced '(namespace)))
+         (let ((buf-name (format ,(format "*Kubed %S%%s*" plrl-var)
+                                 ,(if namespaced
+                                      `(concat "@" namespace "[" context "]")
+                                    `(concat "[" context "]")))))
+           (if-let ((buf (get-buffer buf-name))) buf
+             (with-current-buffer (get-buffer-create buf-name)
+               (,mod-name)
+               (setq kubed-list-context context
+                     ,@(when namespaced
+                         '(kubed-list-namespace namespace)))
+               (kubed-list-update)
+               (tabulated-list-print)
+               (current-buffer)))))
+
+       (defun ,list-cmd (context . ,(when namespaced '(namespace)))
+         ,(if namespaced
+              (format "List Kubernetes %S in context CONTEXT and namespace NAMESPACE.
+
+Interactively, use the current context and namespace by default.  With a
+prefix argument \\[universal-argument], prompt for NAMESPACE.  With a
+double prefix argument \\[universal-argument] \\[universal-argument], \
+prompt for CONTEXT as well." plrl-var)
+            (format "List Kubernetes %S in context CONTEXT.
+
+Interactively, use the current context.  With a prefix argument
+\\[universal-argument], prompt for CONTEXT." plrl-var))
+         (interactive
+          (let* ((context (kubed-local-context))
+                 (context (if (equal current-prefix-arg
+                                     ,(if namespaced ''(16) ''(4)))
+                              (kubed-read-context "Context" context)
+                            context)))
+            (list context
+                  . ,(when namespaced '((kubed--namespace context current-prefix-arg))))))
+         (pop-to-buffer (,buff-fun context . ,(when namespaced '(namespace)))))
+
+       (defun ,expl-cmd ()
+         ,(format "Show help buffer with explanation about Kubernetes %S." plrl-var)
+         (interactive)
+         (kubed-explain ,(symbol-name plrl-var)))
+
+       (defvar-keymap ,map-name
+         :doc ,(format "Prefix keymap for Kubed %S commands." resource)
+         :prefix ',map-name
+         "l" #',list-cmd
+         "+" #',crt-name
+         "e" #',edt-name
+         "d" #',dlt-name
+         "RET" #',dsp-name
+         "E" #',expl-cmd
+         ,@(mapcan
+            (pcase-lambda (`(,key ,_label ,cmd))
+              (list key `#',cmd))
+            prf-keys))
+
+       (defvar-keymap ,menu-map
+         :doc ,(format "Keymap with Kubernetes %S related menu entries." resource)
+         :prefix ',menu-map
+         "<list>"    '("List"           . ,list-cmd)
+         "<create>"  '("Create"         . ,crt-name)
+         "<edit>"    '("Edit"           . ,edt-name)
+         "<delete>"  '("Delete"         . ,dlt-name)
+         "<display>" '("Display"        . ,dsp-name)
+         "<explain>" '("Explain Fields" . ,expl-cmd)
+         ,@(mapcan
+            (pcase-lambda (`(,key ,label ,cmd))
+              (list key `'(,label . ,cmd)))
+            prf-keys)))))
+
+(setf
+ ;; Teach Imenu about `kubed-define-resource'.
+ (alist-get "KubedResource" lisp-imenu-generic-expression nil nil #'equal)
+ (list (concat "^\\s-*(kubed-define-resource\\s-+\\("
+               lisp-mode-symbol-regexp
+               "\\)")
+       1))
+
+(defconst kubed--hex-encoding-table
+  (let ((vec (make-vector 256 nil)))
+    (dotimes (byte 256) (aset vec byte (format ".%02X" byte))) vec))
+
+(defconst kubed--hex-allowed-chars-table
+  (let ((vec (make-vector 256 nil)))
+    (dolist (byte '( ?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z
+                     ?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z
+                     ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9
+                     ?- ?_))
+      (ignore-errors (aset vec byte t)))
+    vec))
+
+(defun kubed--encode-context-name (str)
+  ;; Adopted from `url-hexify-string'.
+  (mapconcat (lambda (byte)
+              (if (aref kubed--hex-allowed-chars-table byte)
+                  (char-to-string byte)
+                (aref kubed--hex-encoding-table byte)))
+            (if (multibyte-string-p str)
+                (encode-coding-string str 'utf-8)
+              str)))
+
+(defun kubed-remote-file-name (context namespace pod &optional file-name)
+  "Return remote FILE-NAME for POD in NAMESPACE and CONTEXT."
+  (concat "/" kubed-tramp-method ":"
+          (kubed--encode-context-name context) "%" namespace "%" pod
+          "%" (kubed-read-container pod "Container" t context namespace)
+          ":" file-name))
+
+(declare-function kubed-tramp-context          "kubed-tramp" (file-name))
+(declare-function kubed-tramp-namespace        "kubed-tramp" (file-name))
+(declare-function kubed-tramp-assert-support   "kubed-tramp" ())
+
+;;;###autoload (autoload 'kubed-display-pod "kubed" nil t)
+;;;###autoload (autoload 'kubed-edit-pod "kubed" nil t)
+;;;###autoload (autoload 'kubed-delete-pods "kubed" nil t)
+;;;###autoload (autoload 'kubed-list-pods "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-pod "kubed" nil t)
+;;;###autoload (autoload 'kubed-logs-for-pod "kubed" nil t)
+;;;###autoload (autoload 'kubed-pod-prefix-map "kubed" nil t 'keymap)
+(kubed-define-resource pod
+    ((phase ".status.phase" 10
+            nil                         ; sorting function
+            (lambda (ph)
+              (if-let ((face (pcase ph
+                               ;; TODO: Define/derive bespoke faces.
+                               ("Pending"   'warning)
+                               ("Running"   'success)
+                               ("Succeeded" 'shadow)
+                               ("Failed"    'error))))
+                  (propertize ph 'face face)
+                ph)))
+     (ready ".status.containerStatuses[?(.ready==true)].name" 6
+            (lambda (l r) (< (string-to-number l) (string-to-number r)))
+            (lambda (cs)
+              (if (string= cs "<none>") "0"
+                (number-to-string (1+ (seq-count (lambda (c) (= c ?,)) cs)))))
+            :right-align t)
+     (total ".status.containerStatuses[*].name" 6
+            (lambda (l r) (< (string-to-number l) (string-to-number r)))
+            (lambda (cs)
+              (if (string= cs "<none>") "0"
+                (number-to-string (1+ (seq-count (lambda (c) (= c ?,)) cs)))))
+            :right-align t)
+     (starttime ".status.startTime" 20))
+  :logs t
+  :prefix (("A" "Attach"       kubed-attach)
+           ("X" "Execute"      kubed-exec)
+           ("F" "Forward Port" kubed-forward-port-to-pod))
+  :suffixes ([ ("L" "Logs" kubed-transient-logs-for-pod)
+               ("X" "Exec" kubed-pods-exec)
+               ("a" "Attach" kubed-pods-attach)]
+             [ :pad-keys t
+               ("C-d" "Dired" kubed-pods-dired)
+               ("s" "Shell" kubed-pods-shell)
+               ("F" "Forward port" kubed-pods-forward-port)])
+  (dired "C-d" "Start Dired in"
+         (kubed-tramp-assert-support)
+         (dired (kubed-remote-file-name
+                 kubed-list-context kubed-list-namespace pod)))
+  (shell "s" "Start shell in"
+         (kubed-tramp-assert-support)
+         (let* ((default-directory (kubed-remote-file-name
+                                    kubed-list-context kubed-list-namespace pod)))
+           (shell
+            (concat "*Kubed Shell "
+                    (kubed-display-resource-short-description
+                     "pods" pod kubed-list-context kubed-list-namespace)
+                    "*"))))
+  (attach "a" "Attach to remote process running on"
+          (kubed-attach pod (kubed-read-container pod "Container" t
+                                                  kubed-list-context
+                                                  kubed-list-namespace)
+                        kubed-list-context kubed-list-namespace t t))
+  (exec "X" "Execute command in"
+        (let ((container (kubed-read-container pod "Container" t
+                                               kubed-list-context
+                                               kubed-list-namespace))
+              (cmd-args (split-string-and-unquote
+                         (read-string "Execute command: "))))
+          (kubed-exec pod (car cmd-args) container kubed-list-context
+                      kubed-list-namespace t t (cdr cmd-args))))
+  (forward-port "F" "Forward local network port to remote port of"
+                (let ((local-port (read-number "Forward local port: ")))
+                  (kubed-forward-port-to-pod
+                   pod local-port
+                   (read-number (format "Forward local port %d to remote port: "
+                                        local-port))
+                   kubed-list-context
+                   kubed-list-namespace))))
+
+;;;###autoload (autoload 'kubed-display-namespace "kubed" nil t)
+;;;###autoload (autoload 'kubed-edit-namespace "kubed" nil t)
+;;;###autoload (autoload 'kubed-delete-namespaces "kubed" nil t)
+;;;###autoload (autoload 'kubed-list-namespaces "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-namespace "kubed" nil t)
+;;;###autoload (autoload 'kubed-namespace-prefix-map "kubed" nil t 'keymap)
+(kubed-define-resource namespace
+    ((phase ".status.phase" 10
+            nil                         ; sorting function
+            (lambda (ph)
+              (if-let ((face (pcase ph
+                               ;; TODO: Define/derive bespoke faces.
+                               ("Active"      'success)
+                               ("Terminating" 'shadow))))
+                  (propertize ph 'face face)
+                ph)))
+     (creationtimestamp ".metadata.creationTimestamp" 20))
+  :namespaced nil
+  :prefix (("S" "Set" kubed-set-namespace))
+  :create
+  ((name &optional context)
+   "Create Kubernetes namespace NAME in CONTEXT.
+
+Interactively, prompt for NAME and use the current context by default.
+With a prefix argument, prompt for CONTEXT instead."
+   (interactive
+    (let ((context nil))
+      (dolist (arg (kubed-transient-args 'kubed-transient-create))
+        (cond
+         ((string-match "--context=\\(.+\\)" arg)
+          (setq context (match-string 1 arg)))))
+      (unless context
+        (setq context
+              (let ((cxt (kubed-local-context)))
+                (if current-prefix-arg
+                    (kubed-read-context "Context" cxt)
+                  cxt))))
+      (list (read-string "Create namespace with name: ") context)))
+   (unless (zerop
+            (apply #'call-process
+                   kubed-kubectl-program nil nil nil
+                   "create" "namespace" name
+                   (when context (list "--context" context))))
+     (user-error "Failed to create Kubernetes namespace with name `%s'" name))
+   (kubed-update "namespaces" (or context (kubed-local-context)))
+   (message "Created Kubernetes namespace with name `%s'." name))
+  (set "s" "Set current namespace to"
+       (save-excursion
+         (goto-char (point-min))
+         (while (not (eobp))
+           (when (eq (char-after) ?*)
+             (tabulated-list-put-tag " "))
+           (forward-line)))
+       (kubed-set-namespace namespace kubed-list-context)
+       (tabulated-list-put-tag
+        (propertize "*" 'help-echo "Current namespace"))))
+
+;;;###autoload (autoload 'kubed-display-persistentvolume "kubed" nil t)
+;;;###autoload (autoload 'kubed-edit-persistentvolume "kubed" nil t)
+;;;###autoload (autoload 'kubed-delete-persistentvolumes "kubed" nil t)
+;;;###autoload (autoload 'kubed-list-persistentvolumes "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-persistentvolume "kubed" nil t)
+;;;###autoload (autoload 'kubed-persistentvolume-prefix-map "kubed" nil t 'keymap)
+(kubed-define-resource persistentvolume () :namespaced nil)
+
+;;;###autoload (autoload 'kubed-display-service "kubed" nil t)
+;;;###autoload (autoload 'kubed-edit-service "kubed" nil t)
+;;;###autoload (autoload 'kubed-delete-services "kubed" nil t)
+;;;###autoload (autoload 'kubed-list-services "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-service "kubed" nil t)
+;;;###autoload (autoload 'kubed-logs-for-service "kubed" nil t)
+;;;###autoload (autoload 'kubed-service-prefix-map "kubed" nil t 'keymap)
+(kubed-define-resource service
+    ((type ".spec.type" 12)
+     (clusterip ".spec.clusterIP" 16)
+     (externalip ".spec.externalIPs[*]" 16)
+     (ports ".spec.ports[*].port" 6)
+     (creationtimestamp ".metadata.creationTimestamp" 20))
+  :logs t)
+
+;;;###autoload (autoload 'kubed-display-secret "kubed" nil t)
+;;;###autoload (autoload 'kubed-edit-secret "kubed" nil t)
+;;;###autoload (autoload 'kubed-delete-secrets "kubed" nil t)
+;;;###autoload (autoload 'kubed-list-secrets "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-secret "kubed" nil t)
+;;;###autoload (autoload 'kubed-secret-prefix-map "kubed" nil t 'keymap)
+(kubed-define-resource secret
+    ((type ".type" 32) (creationtimestamp ".metadata.creationTimestamp" 20)))
+
+(defun kubed-create-job-from-cronjob (name cronjob &optional context namespace)
+  "Create Kubernetes job with name NAME from cronjob CRONJOB.
+
+Optional argument CONTEXT is the `kubectl' context to use, defaulting to
+the current context; NAMESPACE is the namespace to use for the job,
+defaulting to the current namespace."
+  (interactive
+   (let ((name (read-string "Create job with name: "))
+         (context nil) (namespace nil))
+     (dolist (arg (kubed-transient-args 'kubed-transient-create-job))
+       (cond
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))
+        ((string-match "--namespace=\\(.+\\)" arg)
+         (setq namespace (match-string 1 arg)))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (unless namespace
+       (setq namespace (kubed--namespace context current-prefix-arg)))
+     (list name
+           (kubed-read-cronjob
+            (format "Create job `%s' from cronjob" name) nil nil context namespace)
+           context namespace)))
+  (let* ((context (or context (kubed-local-context)))
+         (namespace (or namespace (kubed--namespace context))))
+    (unless (zerop
+             (call-process
+              kubed-kubectl-program nil nil nil
+              "create" "job" name "--from" (concat "cronjob/" cronjob)
+              "-n" namespace "--context" context))
+      (user-error "Failed to create Kubernetes job `%s'" name))
+    (kubed-update "jobs" context namespace)
+    (message "Created Kubernetes job `%s'." name)))
+
+;;;###autoload (autoload 'kubed-display-job "kubed" nil t)
+;;;###autoload (autoload 'kubed-edit-job "kubed" nil t)
+;;;###autoload (autoload 'kubed-delete-jobs "kubed" nil t)
+;;;###autoload (autoload 'kubed-list-jobs "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-job "kubed" nil t)
+;;;###autoload (autoload 'kubed-logs-for-job "kubed" nil t)
+;;;###autoload (autoload 'kubed-job-prefix-map "kubed" nil t 'keymap)
+(kubed-define-resource job
+    ((status ".status.conditions[0].type" 10) (starttime ".status.startTime" 20))
+  :prefix (("c" "Create from Cron" kubed-create-job-from-cronjob))
+  :logs t
+  :create
+  ((name image &optional context namespace command)
+   "Create Kubernetes job with name NAME executing COMMAND in IMAGE.
+
+Optional argument CONTEXT is the `kubectl' context to use, defaulting to
+the current context; NAMESPACE is the namespace to use for the job,
+defaulting to the current namespace."
+   (interactive
+    (let ((name (read-string "Create job with name: "))
+          (image nil) (context nil) (namespace nil) (command nil))
+      (dolist (arg (kubed-transient-args 'kubed-transient-create-job))
+        (cond
+         ((string-match "--image=\\(.+\\)" arg)
+          (setq image (match-string 1 arg)))
+         ((string-match "--context=\\(.+\\)" arg)
+          (setq context (match-string 1 arg)))
+         ((string-match "--namespace=\\(.+\\)" arg)
+          (setq namespace (match-string 1 arg)))
+         ((string-match "-- =\\(.+\\)" arg)
+          (setq command (split-string-and-unquote (match-string 1 arg))))))
+      (unless context
+        (setq context
+              (let ((cxt (kubed-local-context)))
+                (if (equal current-prefix-arg '(16))
+                    (kubed-read-context "Context" cxt)
+                  cxt))))
+      (unless namespace
+        (setq namespace (kubed--namespace context current-prefix-arg)))
+      (unless image
+        (setq image (kubed-read-container-image "Image to run in job")))
+      (list name image context namespace command)))
+   (unless (zerop
+            (apply #'call-process
+                   kubed-kubectl-program nil nil nil
+                   "create" "job" name "--image" image
+                   (append
+                    (when namespace (list "-n" namespace))
+                    (when context (list "--context" context))
+                    (when command (cons "--" command)))))
+     (user-error "Failed to create Kubernetes job `%s'" name))
+   (message "Created Kubernetes job `%s'." name)))
+
+;;;###autoload
+(defun kubed-watch-deployment-status (dep &optional context namespace cb)
+  "Show and update status of Kubernetes deployment DEP in a dedicate buffer.
+
+Optional argument CONTEXT is the `kubectl' context to use, defaulting to
+the current context; NAMESPACE is the namespace of DEP, defaulting to
+the current namespace.  CB is an optional callback function to call with
+no arguments when the deployment ends.
+
+Interactively, prompt for DEP.  With a prefix argument, prompt for
+NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT."
+  (interactive
+   (let (context namespace)
+     (dolist (arg (kubed-transient-args 'kubed-transient-rollout))
+       (cond
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))
+        ((string-match "--namespace=\\(.+\\)" arg)
+         (setq namespace (match-string 1 arg)))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (unless namespace
+       (setq namespace (kubed--namespace context current-prefix-arg)))
+     (list (kubed-read-deployment "Watch deployment status" nil nil
+                                  context namespace)
+           context namespace)))
+  (let* ((buf (get-buffer-create "*kubed-deployment-status*"))
+         (context (or context (kubed-local-context)))
+         (namespace (or namespace (kubed--namespace context))))
+    (with-current-buffer buf (erase-buffer))
+    (make-process
+     :name "*kubed-watch-deployment-status*"
+     :buffer buf
+     :command (list kubed-kubectl-program "rollout" "status"
+                    "deployment" dep "-n" namespace "--context" context)
+     :sentinel (when cb
+                 (lambda (_proc status)
+                   (when (member status '("finished\n"
+                                          "exited abnormally with code 1\n"))
+                     (funcall cb)))))
+    (display-buffer buf)))
+
+(defcustom kubed-restart-deployment-watch-status t
+  "Whether to pop up a progress buffer when restarting Kubernetes deployments."
+  :type 'boolean)
+
+;;;###autoload
+(defun kubed-scale-deployment (dep reps &optional context namespace)
+  "Scale deployment DEP in namespace NAMESPACE via CONTEXT to REPS replicas.
+
+Optional argument CONTEXT is the `kubectl' context to use, defaulting to
+the current context; NAMESPACE is the namespace of DEP, defaulting to
+the current namespace.
+
+Interactively, prompt for DEP.  With a prefix argument, prompt for
+NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT."
+  (interactive
+   (let (reps context namespace)
+     (dolist (arg (kubed-transient-args 'kubed-transient-rollout))
+       (cond
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))
+        ((string-match "--namespace=\\(.+\\)" arg)
+         (setq namespace (match-string 1 arg)))
+        ((string-match "--replicas=\\(.+\\)" arg)
+         (setq reps (string-to-number (match-string 1 arg))))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (unless namespace
+       (setq namespace (kubed--namespace context current-prefix-arg)))
+     (list (kubed-read-deployment "Scale deployment" nil nil context namespace)
+           (or reps (read-number "Number of replicas: ")) context namespace)))
+  (let* ((context (or context (kubed-local-context)))
+         (namespace (or namespace (kubed--namespace context))))
+    (unless (zerop
+             (apply #'call-process
+                    kubed-kubectl-program nil nil nil
+                    "scale" "deployment" dep
+                    "--replicas" (number-to-string reps)
+                    (append
+                     (when namespace (list "-n" namespace))
+                     (when context (list "--context" context)))))
+      (user-error "Failed to scale Kubernetes deployment `%s'" dep))
+    (message "Scaled Kubernetes deployment `%s' to %d replicas." dep reps)))
+
+;;;###autoload
+(defun kubed-restart-deployment (dep &optional context namespace)
+  "Restart Kubernetes deployment DEP in namespace NAMESPACE via CONTEXT.
+
+Optional argument CONTEXT is the `kubectl' context to use, defaulting to
+the current context; NAMESPACE is the namespace of DEP, defaulting to
+the current namespace.  CB is an optional callback function to call with
+no arguments when the deployment ends.
+
+Interactively, prompt for DEP.  With a prefix argument, prompt for
+NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT."
+  (interactive
+   (let (context namespace)
+     (dolist (arg (kubed-transient-args 'kubed-transient-rollout))
+       (cond
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))
+        ((string-match "--namespace=\\(.+\\)" arg)
+         (setq namespace (match-string 1 arg)))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (unless namespace
+       (setq namespace (kubed--namespace context current-prefix-arg)))
+     (list (kubed-read-deployment "Restart deployment" nil nil
+                                  context namespace)
+           context namespace)))
+  (let* ((context (or context (kubed-local-context)))
+         (namespace (or namespace (kubed--namespace context))))
+    (unless (zerop
+             (apply #'call-process
+                    kubed-kubectl-program nil nil nil
+                    "rollout" "restart" "deployment" dep
+                    (append
+                     (when namespace (list "-n" namespace))
+                     (when context (list "--context" context)))))
+      (user-error "Failed to restart Kubernetes deployment `%s'" dep))
+    (message "Restarting Kubernetes deployment `%s'." dep)
+    (when kubed-restart-deployment-watch-status
+      (kubed-watch-deployment-status
+       dep context namespace
+       (lambda ()
+         (kubed-update "deployments" context namespace))))))
+
+;;;###autoload (autoload 'kubed-display-deployment "kubed" nil t)
+;;;###autoload (autoload 'kubed-edit-deployment "kubed" nil t)
+;;;###autoload (autoload 'kubed-delete-deployments "kubed" nil t)
+;;;###autoload (autoload 'kubed-list-deployments "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-deployment "kubed" nil t)
+;;;###autoload (autoload 'kubed-logs-for-deployment "kubed" nil t)
+;;;###autoload (autoload 'kubed-deployment-prefix-map "kubed" nil t 'keymap)
+(kubed-define-resource deployment
+    (( ready ".status.readyReplicas" 6
+       (lambda (l r) (< (string-to-number l) (string-to-number r)))
+       (lambda (s) (if (string= s "<none>") "0" s))
+       :right-align t)
+     ( updated ".status.updatedReplicas" 8
+       (lambda (l r) (< (string-to-number l) (string-to-number r)))
+       (lambda (s) (if (string= s "<none>") "0" s))
+       :right-align t)
+     ( available ".status.availableReplicas" 10
+       (lambda (l r) (< (string-to-number l) (string-to-number r)))
+       (lambda (s) (if (string= s "<none>") "0" s))
+       :right-align t)
+     ( reps ".status.replicas" 4
+       (lambda (l r) (< (string-to-number l) (string-to-number r)))
+       nil                              ; formatting function
+       :right-align t)
+     ( creationtimestamp ".metadata.creationTimestamp" 20))
+  :prefix (("R" "Restart" kubed-restart-deployment)
+           ("W" "Watch"   kubed-watch-deployment-status)
+           ("$" "Scale"   kubed-scale-deployment))
+  :logs t
+  :suffixes ([("L" "Logs" kubed-transient-logs-for-deployment)
+              ("W" "Watch" kubed-deployments-watch)
+              ("R" "Restart" kubed-deployments-restart)
+              ("$" "Scale" kubed-deployments-scale)])
+  :create
+  ((name images &optional context namespace replicas port command)
+   "Deploy IMAGES to Kubernetes in deployment with name NAME.
+
+Optional argument NAMESPACE is the namespace to use for the deployment,
+defaulting to the current namespace, REPLICAS in the number of replicas
+to create for each image, PORT is the port to expose, and COMMAND is an
+optional command to run in the images."
+   (interactive
+    (let ((name (read-string "Create deployment with name: "))
+          (images nil) (replicas nil) (port nil) (command nil)
+          (context nil) (namespace nil))
+      (dolist (arg (kubed-transient-args 'kubed-transient-create-deployment))
+        (cond
+         ((string-match "--replicas=\\(.+\\)" arg)
+          (setq replicas (string-to-number (match-string 1 arg))))
+         ((string-match "--image=\\(.+\\)" arg)
+          (push (match-string 1 arg) images))
+         ((string-match "--port=\\(.+\\)" arg)
+          (setq port (string-to-number (match-string 1 arg))))
+         ((string-match "--namespace=\\(.+\\)" arg)
+          (setq namespace (match-string 1 arg)))
+         ((string-match "--context=\\(.+\\)" arg)
+          (setq context (match-string 1 arg)))
+         ((string-match "-- =\\(.+\\)" arg)
+          (setq command (split-string-and-unquote (match-string 1 arg))))))
+      (unless images
+        (setq images (kubed-read-container-image "Images to deploy" nil t)))
+      (unless context
+        (setq context
+              (let ((cxt (kubed-local-context)))
+                (if (equal current-prefix-arg '(16))
+                    (kubed-read-context "Context" cxt)
+                  cxt))))
+      (unless namespace
+        (setq namespace (kubed--namespace context current-prefix-arg)))
+      (list name images context namespace replicas port command)))
+   (let* ((context (or context (kubed-local-context)))
+          (namespace (or namespace (kubed--namespace context))))
+     (unless (zerop
+              (apply #'call-process
+                     kubed-kubectl-program nil nil nil
+                     "create" "deployment" name
+                     (append
+                      (mapcar (lambda (image) (concat "--image=" image)) images)
+                      (when namespace (list (concat "--namespace=" namespace)))
+                      (when context (list (concat "--context=" context)))
+                      (when replicas (list (format "--replicas=%d" replicas)))
+                      (when port (list (format "--port=%d" port)))
+                      (when command (cons "--" command)))))
+       (user-error "Failed to create Kubernetes deployment `%s'" name))
+     (message "Created Kubernetes deployment `%s'." name)
+     (kubed-update "deployments" context namespace)))
+  (restart "R" "Restart"
+           (kubed-restart-deployment deployment kubed-list-context kubed-list-namespace)
+           (unless kubed-restart-deployment-watch-status
+             (message "Deployment restarting")
+             (kubed-list-update t)))
+  (watch "W" "Watch" (kubed-watch-deployment-status
+                      deployment kubed-list-context kubed-list-namespace))
+  (scale "$" "Scale" (kubed-scale-deployment
+                      deployment (if current-prefix-arg
+                                     (prefix-numeric-value current-prefix-arg)
+                                   (read-number "Number of replicas: "))
+                      kubed-list-context kubed-list-namespace)))
+
+;;;###autoload (autoload 'kubed-display-replicaset "kubed" nil t)
+;;;###autoload (autoload 'kubed-edit-replicaset "kubed" nil t)
+;;;###autoload (autoload 'kubed-delete-replicasets "kubed" nil t)
+;;;###autoload (autoload 'kubed-list-replicasets "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-replicaset "kubed" nil t)
+;;;###autoload (autoload 'kubed-logs-for-replicaset "kubed" nil t)
+;;;###autoload (autoload 'kubed-replicaset-prefix-map "kubed" nil t 'keymap)
+(kubed-define-resource replicaset
+    ((reps ".status.replicas" 4
+           (lambda (l r) (< (string-to-number l) (string-to-number r)))
+           nil                          ; formatting function
+           :right-align t)
+     (ownerkind ".metadata.ownerReferences[0].kind" 12)
+     (ownername ".metadata.ownerReferences[0].name" 16)
+     (creationtimestamp ".metadata.creationTimestamp" 20))
+  :logs t)
+
+;;;###autoload (autoload 'kubed-display-daemonset "kubed" nil t)
+;;;###autoload (autoload 'kubed-edit-daemonset "kubed" nil t)
+;;;###autoload (autoload 'kubed-delete-daemonsets "kubed" nil t)
+;;;###autoload (autoload 'kubed-list-daemonsets "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-daemonset "kubed" nil t)
+;;;###autoload (autoload 'kubed-logs-for-daemonset "kubed" nil t)
+;;;###autoload (autoload 'kubed-daemonset-prefix-map "kubed" nil t 'keymap)
+(kubed-define-resource daemonset
+    ((desired ".status.desiredNumberScheduled" 8
+              (lambda (l r) (< (string-to-number l) (string-to-number r)))
+              nil                          ; formatting function
+              :right-align t)
+     (current ".status.currentNumberScheduled" 8
+              (lambda (l r) (< (string-to-number l) (string-to-number r)))
+              nil                          ; formatting function
+              :right-align t)
+     (ready ".status.numberReady" 6
+              (lambda (l r) (< (string-to-number l) (string-to-number r)))
+              nil                          ; formatting function
+              :right-align t)
+     (updated ".status.updatedNumberScheduled" 8
+            (lambda (l r) (< (string-to-number l) (string-to-number r)))
+            nil                          ; formatting function
+            :right-align t)
+     (available ".status.numberAvailable" 10
+              (lambda (l r) (< (string-to-number l) (string-to-number r)))
+              nil                          ; formatting function
+              :right-align t)
+     (creationtimestamp ".metadata.creationTimestamp" 20))
+  :logs t)
+
+;;;###autoload (autoload 'kubed-display-statefulset "kubed" nil t)
+;;;###autoload (autoload 'kubed-edit-statefulset "kubed" nil t)
+;;;###autoload (autoload 'kubed-delete-statefulsets "kubed" nil t)
+;;;###autoload (autoload 'kubed-list-statefulsets "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-statefulset "kubed" nil t)
+;;;###autoload (autoload 'kubed-logs-for-statefulset "kubed" nil t)
+;;;###autoload (autoload 'kubed-statefulset-prefix-map "kubed" nil t 'keymap)
+(kubed-define-resource statefulset
+    ((reps ".status.replicas" 4
+           (lambda (l r) (< (string-to-number l) (string-to-number r)))
+           nil                          ; formatting function
+           :right-align t)
+     (ownerkind ".metadata.ownerReferences[0].kind" 12)
+     (ownername ".metadata.ownerReferences[0].name" 16)
+     (creationtimestamp ".metadata.creationTimestamp" 20))
+  :logs t)
+
+(defun kubed-cronjob-suspended-p (cj &optional context ns)
+  "Return non-nil if cronjob CJ in CONTEXT and namespace NS is suspended."
+  (equal (car (apply #'process-lines
+                     kubed-kubectl-program
+                     "get" "cronjobs" cj
+                     "-o" "custom-columns=SUSPENDED:.spec.suspend" "--no-headers"
+                     (append
+                      (when ns (list "-n" ns))
+                      (when context (list "--context" context)))))
+         "true"))
+
+;;;###autoload (autoload 'kubed-display-cronjob "kubed" nil t)
+;;;###autoload (autoload 'kubed-edit-cronjob "kubed" nil t)
+;;;###autoload (autoload 'kubed-delete-cronjobs "kubed" nil t)
+;;;###autoload (autoload 'kubed-list-cronjobs "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-cronjob "kubed" nil t)
+;;;###autoload (autoload 'kubed-cronjob-prefix-map "kubed" nil t 'keymap)
+(kubed-define-resource cronjob
+    ((schedule ".spec.schedule" 20)
+     (suspend ".spec.suspend" 20)
+     (lastschedule ".status.lastScheduleTime" 20)
+     (lastsuccess ".status.lastSuccessfulTime" 20)
+     (activejob ".status.active[0].name" 36))
+  :create
+  ((name image schedule &optional context namespace command)
+   "Schedule IMAGE to run in a cronjob with name NAME according to SCHEDULE.
+
+Optional argument NAMESPACE is the namespace to use for the cronjob,
+defaulting to the current namespace.  COMMAND is a list of strings that
+represent a program followed by its arguments, if it non-nil then it
+overrides the default command IMAGE runs."
+   (interactive
+    (let ((name (read-string "Create cronjob with name: "))
+          (image nil)
+          (schedule nil)
+          (command nil)
+          (context nil)
+          (namespace nil))
+      (dolist (arg (kubed-transient-args 'kubed-transient-create-cronjob))
+        (cond
+         ((string-match "--image=\\(.+\\)" arg)
+          (setq image (match-string 1 arg)))
+         ((string-match "--schedule=\\(.+\\)" arg)
+          (setq schedule (match-string 1 arg)))
+         ((string-match "--namespace=\\(.+\\)" arg)
+          (setq namespace (match-string 1 arg)))
+         ((string-match "--context=\\(.+\\)" arg)
+          (setq context (match-string 1 arg)))
+         ((string-match "-- =\\(.+\\)" arg)
+          (setq command (split-string-and-unquote (match-string 1 arg))))))
+      (unless context
+        (setq context
+              (let ((cxt (kubed-local-context)))
+                (if (equal current-prefix-arg '(16))
+                    (kubed-read-context "Context" cxt)
+                  cxt))))
+      (unless namespace
+        (setq namespace (kubed--namespace context current-prefix-arg)))
+      (unless image
+        (setq image (kubed-read-container-image "Image to run")))
+      (unless schedule
+        (setq schedule (read-string "Cron schedule: " "* * * * *")))
+      (list name image schedule context namespace command)))
+   (unless (zerop
+            (apply #'call-process
+                   kubed-kubectl-program nil nil nil
+                   "create" "cronjob" name
+                   "--image" image "--schedule" schedule
+                   (append
+                    (when context (list "--context" context))
+                    (when namespace (list "--namespace" namespace))
+                    (when command (cons "--" command)))))
+     (user-error "Failed to create Kubernetes cronjob `%s'" name))
+   (message "Created Kubernetes cronjob `%s'." name))
+  ;; Commands in *kubed-cronjobs* buffer.
+  ( toggle-suspension "T" "Toggle suspension of"
+    (kubed-patch "cronjobs" cronjob
+                 (format
+                  "{\"spec\": {\"suspend\": %s}}"
+                  (if (kubed-cronjob-suspended-p
+                       cronjob kubed-list-context kubed-list-namespace)
+                      "false" "true"))
+                 kubed-list-context kubed-list-namespace))
+  ( create-job "j" "Create job from"
+    (kubed-create-job-from-cronjob
+     (read-string "Create job with name: ") cronjob
+     kubed-list-context kubed-list-namespace)))
+
+;;;###autoload (autoload 'kubed-display-ingressclass "kubed" nil t)
+;;;###autoload (autoload 'kubed-edit-ingressclass "kubed" nil t)
+;;;###autoload (autoload 'kubed-delete-ingressclasses "kubed" nil t)
+;;;###autoload (autoload 'kubed-list-ingressclasss "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-ingressclass "kubed" nil t)
+;;;###autoload (autoload 'kubed-ingressclass-prefix-map "kubed" nil t 'keymap)
+(kubed-define-resource ingressclass
+    ((controller ".spec.controller" 32)
+     (creationtimestamp ".metadata.creationTimestamp" 20))
+  :namespaced nil
+  :plural ingressclasses)
+
+;;;###autoload (autoload 'kubed-display-ingress "kubed" nil t)
+;;;###autoload (autoload 'kubed-edit-ingress "kubed" nil t)
+;;;###autoload (autoload 'kubed-delete-ingresses "kubed" nil t)
+;;;###autoload (autoload 'kubed-list-ingresss "kubed" nil t)
+;;;###autoload (autoload 'kubed-create-ingress "kubed" nil t)
+;;;###autoload (autoload 'kubed-ingress-prefix-map "kubed" nil t 'keymap)
+(kubed-define-resource ingress
+    ((class ".spec.ingressClassName" 8)
+     (creationtimestamp ".metadata.creationTimestamp" 20))
+  :plural ingresses
+  :create
+  ((name rules &optional context namespace class default-backend annotations)
+   "Create Kubernetes ingress with name NAME and rules RULES.
+
+Optional argument NAMESPACE is the namespace to use for the ingress,
+defaulting to the current namespace.  CLASS is the ingress class,
+ANNOTATIONS are a list of annotations for the created ingress, and
+DEFAULT-BACKEND is the service to use as a backend for unhandled URLs."
+   (interactive
+    (let ((name (read-string "Create ingress with name: "))
+          (rules nil)
+          (context nil)
+          (namespace nil)
+          (class nil)
+          (annotations nil)
+          (default-backend nil))
+      (dolist (arg (kubed-transient-args 'kubed-transient-create-ingress))
+        (cond
+         ((string-match "--rule=\\(.+\\)" arg)
+          (push (match-string 1 arg) rules))
+         ((string-match "--context=\\(.+\\)" arg)
+          (setq context (match-string 1 arg)))
+         ((string-match "--namespace=\\(.+\\)" arg)
+          (setq namespace (match-string 1 arg)))
+         ((string-match "--class=\\(.+\\)" arg)
+          (setq class (match-string 1 arg)))
+         ((string-match "--default-backend=\\(.+\\)" arg)
+          (setq default-backend (match-string 1 arg)))
+         ((string-match "--annotation=\\(.+\\)" arg)
+          (push (match-string 1 arg) annotations))))
+      (unless context
+        (setq context
+              (let ((cxt (kubed-local-context)))
+                (if (equal current-prefix-arg '(16))
+                    (kubed-read-context "Context" cxt)
+                  cxt))))
+      (unless namespace
+        (setq namespace (kubed--namespace context current-prefix-arg)))
+      (unless rules (setq rules (kubed-read-ingress-rules)))
+      (list name rules context namespace class default-backend annotations)))
+   (unless (zerop
+            (apply #'call-process
+                   kubed-kubectl-program nil nil nil
+                   "create" "ingress" name
+                   (append
+                    (mapcan (lambda (rule) (list "--rule" rule)) rules)
+                    (when namespace (list "--namespace" namespace))
+                    (when context (list "--context" context))
+                    (when class (list "--class" class))
+                    (when default-backend
+                      (list "--default-backend" default-backend))
+                    (mapcan (lambda (ann) (list "--annotation" ann))
+                            annotations))))
+     (user-error "Failed to create Kubernetes ingress `%s'" name))
+   (message "Created Kubernetes ingress `%s'." name)))
+
+;; TODO: Events may be numerous.  Need to only get a few.
+;; ;;;###autoload (autoload 'kubed-list-events "kubed" nil t)
+;; ;;;###autoload (autoload 'kubed-event-prefix-map "kubed" nil t 'keymap)
+;; (kubed-define-resource event
+;;     ((last ".lastTimestamp" 20)
+;;      (type ".type" 10)
+;;      (reason ".reason" 20)
+;;      (objectkind ".involvedObject.kind" 12)
+;;      (objectname ".involvedObject.name" 16)
+;;      (message ".message" 36)))
+
+(defun kubed-contexts ()
+  "Return list of Kubernetes contexts."
+  (process-lines kubed-kubectl-program "config" "get-contexts" "-o" "name"))
+
+(defun kubed-current-context ()
+  "Return current Kubernetes context."
+  (car (process-lines kubed-kubectl-program "config" "current-context")))
+
+(defun kubed-read-default-namespace-non-empty (context)
+  "Prompt for a default namespace for CONTEXT, refusing empty input."
+  (let ((ns (kubed-read-namespace
+             (format "Default namespace for context `%s'" context)
+             nil nil context)))
+    (when (string-empty-p ns)
+      (user-error "You didn't specify a default namespace"))
+    ns))
+
+(defun kubed-default-context-and-namespace ()
+  "Return default context and namespace as a cons cell (CONTEXT . NAMESPACE)."
+  (or kubed-default-context-and-namespace
+      (setq kubed-default-context-and-namespace
+            (let ((context (kubed-current-context)))
+              (cons context
+                    (or (kubed-current-namespace context)
+                        (kubed-read-default-namespace-non-empty context)))))))
+
+(defun kubed-default-context ()
+  "Return default `kubectl' context."
+  (car (kubed-default-context-and-namespace)))
+
+(defun kubed-default-namespace ()
+  "Return default Kubernetes namespace in the default context."
+  (cdr (kubed-default-context-and-namespace)))
+
+(defun kubed-remote-file-name-p (file-name)
+  "Check whether FILE-NAME is a Kubed Tramp remote file name."
+  ;; We use this function to heuristically check file names without
+  ;; loading `kubed-tramp' (which in turn loads `tramp').
+  (string-match-p "[/|]kubedv[0-9]+:" file-name))
+
+(defun kubed-local-context ()
+  "Return Kubernetes context local to the current buffer."
+  (or kubed-list-context
+      (nth 2 kubed-display-resource-info)
+      (and (kubed-remote-file-name-p default-directory)
+           (kubed-tramp-context default-directory))
+      (kubed-default-context)))
+
+(defvar kubed-context-history nil
+  "History list for `kubed-read-context'.")
+
+(defun kubed-read-context (prompt &optional default)
+  "Prompt with PROMPT for a Kubernetes context.
+
+Optional argument DEFAULT is the minibuffer default argument."
+  (completing-read (format-prompt prompt default)
+                   (kubed-contexts)
+                   nil 'confirm nil 'kubed-context-history default))
+
+;;;###autoload
+(defun kubed-use-context (context)
+  "Set current Kubernetes context to CONTEXT."
+  (interactive
+   (list (kubed-read-context "Use context" (kubed-local-context))))
+  (unless (zerop
+           (call-process
+            kubed-kubectl-program nil nil nil
+            "config" "use-context" context))
+    (user-error "Failed to use Kubernetes context `%s'" context))
+  (message "Now using Kubernetes context `%s'." context))
+
+;;;###autoload
+(defun kubed-rename-context (old new)
+  "Rename Kubernetes context OLD to NEW."
+  (interactive
+   (let ((old (kubed-read-context "Rename context" (kubed-local-context))))
+     (list old (read-string (format-prompt "Rename context to" old)
+                            nil 'kubed-context-history old))))
+  (unless (zerop
+           (call-process
+            kubed-kubectl-program nil nil nil
+            "config" "rename-context" old new))
+    (user-error "Failed to rename Kubernetes context `%s' to `%s'" old new))
+  (message "Renamed Kubernetes context `%s' to `%s'." old new))
+
+;;;###autoload
+(defun kubed-display-config ()
+  "Display current Kubernetes client settings in a YAML buffer."
+  (interactive)
+  (let* ((buf (get-buffer-create "*kubed-config*"))
+         (fun (lambda (&optional _ _)
+                (let ((inhibit-read-only t)
+                      (target (current-buffer)))
+                  (buffer-disable-undo)
+                  (with-temp-buffer
+                    (unless (zerop
+                             (call-process
+                              kubed-kubectl-program nil t nil "config" "view"))
+                      (error "`kubectl config view' failed"))
+                    (let ((source (current-buffer)))
+                      (with-current-buffer target
+                        (replace-buffer-contents source)
+                        (set-buffer-modified-p nil)
+                        (buffer-enable-undo))))))))
+    (with-current-buffer buf
+      (funcall fun)
+      (goto-char (point-min))
+      (run-hooks 'kubed-yaml-setup-hook)
+      (setq-local revert-buffer-function fun))
+    (display-buffer buf)))
+
+(defun kubed-current-namespace (&optional context)
+  "Return current Kubernetes namespace for context CONTEXT.
+
+If no namespace is configured for CONTEXT, return nil."
+  (or (car (process-lines
+            kubed-kubectl-program
+            "config" "view" "-o"
+            (format "jsonpath={.contexts[?(.name==\"%s\")].context.namespace}"
+                    (or context (kubed-current-context)))))))
+
+(defun kubed-local-namespace ()
+  "Return Kubernetes namespace in CONTEXT local to the current buffer."
+  (or kubed-list-namespace
+      (nth 3 kubed-display-resource-info)
+      (and (kubed-remote-file-name-p default-directory)
+           (kubed-tramp-namespace default-directory))
+      (kubed-default-namespace)))
+
+(defun kubed-local-context-and-namespace ()
+  "Return (CONTEXT . NAMESPACE) pair local to the current buffer."
+  (or (when-let ((context kubed-list-context))
+        (cons context
+              (or kubed-list-namespace
+                  (kubed-current-namespace context))))
+      (when-let ((context (nth 2 kubed-display-resource-info)))
+        (cons context
+              (or (nth 3 kubed-display-resource-info)
+                  (kubed-current-namespace context))))
+      (when-let ((context (and (kubed-remote-file-name-p default-directory)
+                               (kubed-tramp-context default-directory))))
+        (cons context (kubed-tramp-namespace default-directory)))
+      (kubed-default-context-and-namespace)))
+
+;;;###autoload
+(defun kubed-set-namespace (namespace &optional context)
+  "Set default Kubernetes namespace in CONTEXT to NAMESPACE.
+
+Interactively, prompt for NAMESPACE and use the current context.  With a
+prefix argument, prompt for CONTEXT as well."
+  (interactive
+   (let* ((context (kubed-local-context))
+          (context (if current-prefix-arg
+                       (kubed-read-context "Context" context)
+                     context)))
+     (list (kubed-read-namespace "Set namespace" (kubed--namespace context)
+                                 nil context)
+           context)))
+  (unless (zerop
+           (call-process
+            kubed-kubectl-program nil nil nil
+            "config" "set-context" (or context "--current")
+            "--namespace" namespace))
+    (user-error "Failed to set Kubernetes namespace to `%s'" namespace))
+  (message "Default Kubernetes namespace%s is now `%s'."
+           (if context
+               (substitute-quotes (concat " for context `" context "'"))
+             "")
+           namespace))
+
+(defcustom kubed-read-resource-definition-filter-files-by-kind t
+  "Whether to filter file completion candidates by their Kubernetes \"kind\".
+
+If this is non-nil, `kubed-read-resource-definition-file-name' only
+suggests files with the right \"kind\" as completion candidates when you
+call it with non-nil KIND argument.  This is useful because you get more
+relevant completions, but it may become slow in directories with many
+large JSON and YAML files, in which case you can set this option to nil."
+  :type 'boolean)
+
+(defun kubed-read-resource-definition-file-name (&optional kind)
+  "Prompt for Kubernetes resource definition file name.
+
+Optional argument KIND is the kind of resource the file should define.
+If `kubed-read-resource-definition-filter-files-by-kind' is non-nil,
+this function suggests only files that define resources of kind KIND as
+completion candidates."
+  (read-file-name
+   (format "%s definition file: " (or kind "Resource")) nil nil t nil
+   (if (and kind kubed-read-resource-definition-filter-files-by-kind
+            (executable-find "grep"))
+       (let ((cache (make-hash-table :test 'equal)))
+         (lambda (f)
+           (or (file-directory-p f)
+               (when-let ((ext (and (string-match "\\.[^.]*\\'" f)
+                                    (substring f (1+ (match-beginning 0))))))
+                 (or (and (member ext '("yaml" "yml"))
+                          (pcase (gethash (expand-file-name f) cache 'noval)
+                            ('noval
+                             (puthash (expand-file-name f)
+                                      (zerop (call-process
+                                              "grep" f nil nil "-i"
+                                              (format "^kind: %s$" kind)))
+                                      cache))
+                            (val val)))
+                     (and (equal ext "json")
+                          (pcase (gethash (expand-file-name f) cache 'noval)
+                            ('noval
+                             (puthash (expand-file-name f)
+                                      (zerop (call-process
+                                              "grep" f nil nil "-i"
+                                              (format "^kind: %s$" kind)))
+                                      cache))
+                            (val val))))))))
+     (lambda (f)
+       (or (file-directory-p f)
+           (when (string-match "\\.[^.]*\\'" f)
+             (member (substring f (1+ (match-beginning 0)))
+                     '("yaml" "yml" "json"))))))))
+
+;;;###autoload
+(defun kubed-apply (config &optional kind context)
+  "Apply CONFIG to Kubernetes resource of kind KIND via CONTEXT."
+  (interactive
+   (let ((config nil) (context nil))
+     (dolist (arg (kubed-transient-args 'kubed-transient-apply))
+       (cond
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))
+        ((string-match "--filename=\\(.+\\)" arg)
+         (setq config (match-string 1 arg)))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if current-prefix-arg
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (unless config
+       (setq config (kubed-read-resource-definition-file-name)))
+     (list config nil context)))
+  (let ((kind (or kind "resource"))
+        (context (or context (kubed-local-context))))
+    (message "Applying Kubernetes %s configuration `%s'..." kind config)
+    (call-process kubed-kubectl-program nil nil nil
+                  "apply" "-f" (expand-file-name config) "--context" context)
+    (message "Applying Kubernetes %s configuration `%s'... Done." kind config)))
+
+;;;###autoload
+(defun kubed-create (definition &optional kind context)
+  "Create resource of kind KIND with definition DEFINITION via CONTEXT."
+  (interactive
+   (let ((definition nil) (context nil))
+     (dolist (arg (kubed-transient-args 'kubed-transient-create))
+       (cond
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))
+        ((string-match "--filename=\\(.+\\)" arg)
+         (setq definition (match-string 1 arg)))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if current-prefix-arg
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (unless definition
+       (setq definition (kubed-read-resource-definition-file-name)))
+     (list definition nil context)))
+  (let ((kind (or kind "resource")))
+    (message "Creating Kubernetes %s with definition `%s'..." kind definition)
+    (message "Creating Kubernetes %s with definition `%s'... Done.  New %s name is `%s'."
+             kind definition kind
+             (car (apply #'process-lines kubed-kubectl-program
+                         "create" "-f" (expand-file-name definition)
+                         "-o" "jsonpath={.metadata.name}"
+                         (when context (list "--context" context)))))))
+
+;;;###autoload
+(defun kubed-run
+    ( pod image
+      &optional context namespace port attach stdin tty rm envs command args)
+  "Run container IMAGE in a new Kubernetes POD.
+
+Optional argument CONTEXT is the `kubectl' context to use, defaulting to
+the current context.  NAMESPACE is the namespace in which to create POD,
+defaulting to the current namespace.  PORT is the port to expose,
+defaulting to none.  If ATTACH is non-nil, then attach to the created
+image with a `comint-mode' buffer, and pop to that buffer.  Non-nil
+STDIN says to keep the standard input of the container open; non-nil TTY
+says to allocate a TTY for the container; and non-nil RM says to remove
+the container after it exits.  ENVS is a list of strings \"VAR=VAL\"
+which specify environment variables VAR and values VAL to give them in
+the created container.  ARGS are command line arguments for the
+container command.  If COMMAND is non-nil, ARGS consist of a complete
+command line, that overrides the container command instead of just
+providing it with arguments.
+
+Interactively, prompt for POD and IMAGE.  With a prefix argument, prompt
+for NAMESPACE; with a double prefix argument, also prompt for CONTEXT."
+  (interactive
+   (let ((pod nil) (image nil) (port nil) (context nil) (namespace nil)
+         (attach nil) (stdin nil) (tty nil) (rm nil) (envs nil)
+         (command nil) (args nil))
+     (dolist (arg (kubed-transient-args 'kubed-transient-run))
+       (cond
+        ((string-match "--image=\\(.+\\)" arg)
+         (setq image (match-string 1 arg)))
+        ((string-match "--port=\\(.+\\)" arg)
+         (setq port (string-to-number (match-string 1 arg))))
+        ((string-match "--namespace=\\(.+\\)" arg)
+         (setq namespace (match-string 1 arg)))
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))
+        ((equal "--attach" arg) (setq attach t))
+        ((equal "--stdin" arg) (setq stdin t))
+        ((equal "--tty" arg) (setq tty t))
+        ((equal "--rm" arg) (setq rm t))
+        ((equal "--command" arg) (setq command t))
+        ((string-match "--env=\\(.+\\)" arg)
+         (push (match-string 1 arg) envs))
+        ((string-match "-- =\\(.+\\)" arg)
+         (setq args (split-string-and-unquote (match-string 1 arg))))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (unless namespace
+       (setq namespace (kubed--namespace context current-prefix-arg)))
+     (setq pod (read-string "Run image in pod with name: "))
+     (unless image
+       (setq image (read-string "Image to run: " nil 'kubed-container-image-history)))
+     (list pod image context namespace port attach stdin tty rm envs command args)))
+  (if attach
+      (pop-to-buffer
+       (apply #'make-comint "kubed-run" kubed-kubectl-program nil
+              "run" pod (concat "--image=" image) "--attach"
+              (append
+               (mapcar (lambda (env) (concat "--env=" env))
+                       (cons "TERM=dumb" envs))
+               (when namespace (list (concat "--namespace=" namespace)))
+               (when stdin '("-i"))
+               (when tty '("-t"))
+               (when rm '("--rm"))
+               (when port (list (format "--port=%d" port)))
+               (when command '("--command"))
+               (when args (cons "--" args)))))
+    (unless (zerop
+             (apply #'call-process
+                    kubed-kubectl-program nil nil nil
+                    "run" pod (concat "--image=" image)
+                    (append
+                     (mapcar (lambda (env) (concat "--env=" env)) envs)
+                     (when namespace (list (concat "--namespace=" namespace)))
+                     (when context (list (concat "--context=" context)))
+                     (when stdin '("-i"))
+                     (cond
+                      (attach '("--attach"))
+                      (stdin  '("--attach=false")))
+                     (when tty '("-t"))
+                     (when rm '("--rm"))
+                     (when port (list (format "--port=%d" port)))
+                     (when command '("--command"))
+                     (when args (cons "--" args)))))
+      (user-error "Failed to run image `%s'" image))
+    (message "Image `%s' is now running in pod `%s'." image pod)))
+
+(defun kubed-pod-containers (pod &optional context namespace)
+  "Return list of containers in Kubernetes pod POD in NAMESPACE in CONTEXT."
+  (string-split
+   (car (apply #'process-lines
+               kubed-kubectl-program "get"
+               "pod" pod "-o" "jsonpath={.spec.containers[*].name}"
+               (append
+                (when namespace (list "--namespace" namespace))
+                (when context (list "--context" context)))))
+   " "))
+
+(defun kubed-pod-default-container (pod &optional context namespace)
+  "Return default container of Kubernetes pod POD in NAMESPACE in CONTEXT."
+  (car (apply #'process-lines
+              kubed-kubectl-program
+              "get" "pod" pod "-o"
+              "jsonpath={.metadata.annotations.kubectl\\.kubernetes\\.io/default-container}"
+              (append
+               (when namespace (list "--namespace" namespace))
+               (when context (list "--context" context))))))
+
+(defun kubed-read-container
+    (pod prompt &optional guess context namespace)
+  "Prompt with PROMPT for a container in POD and return its name.
+
+Non-nil optional argument GUESS says to try and guess which container to
+use without prompting: if the pod has a
+\"kubectl.kubernetes.id/default-container\" annotation, use the
+container that this annotation specifes; if there's just one container,
+use it; otherwise, fall back to prompting."
+  (let ((default (kubed-pod-default-container pod context namespace))
+        (all 'unset))
+    (or
+     ;; There's a default container, so that's our guess.
+     (and guess default)
+     ;; No default, but we're allowed to guess, so check if there's just
+     ;; one container, and if so that's our guess.
+     (and guess (setq all (kubed-pod-containers pod context namespace))
+          (null (cdr all))
+          (car all))
+     ;; No guessing, prompt.
+     (completing-read (format-prompt prompt default)
+                      (completion-table-dynamic
+                       (lambda (_)
+                         (if (eq all 'unset)
+                             (setq all (kubed-pod-containers pod context namespace))
+                           all)))
+                      nil t nil nil default))))
+
+;;;###autoload
+(defun kubed-logs
+    ( type resource &optional context namespace
+      container follow limit prefix since tail timestamps)
+  "Show logs for container CONTAINER in Kubernetes RESOURCE of type TYPE.
+
+Optional argument CONTEXT is the `kubectl' context to use; NAMESPACE is
+the namespace for RESOURCE; CONTAINER is the name of the container in
+RESOURCE to show logs for, or t which specifies all relevant containers.
+
+With a prefix argument, prompt for NAMESPACE; with a double prefix
+argument, also prompt for CONTEXT."
+  (interactive
+   (let ( type resource context namespace
+          container follow limit prefix since tail timestamps)
+     (dolist (arg (kubed-transient-args 'kubed-transient-logs))
+       (cond
+        ((string-match "--namespace=\\(.+\\)" arg)
+         (setq namespace (match-string 1 arg)))
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))
+        ((string-match "--limit-bytes=\\(.+\\)" arg)
+         (setq limit (string-to-number (match-string 1 arg))))
+        ((string-match "--tail=\\(.+\\)" arg)
+         (setq tail (string-to-number (match-string 1 arg))))
+        ((string-match "--since-time=\\(.+\\)" arg)
+         (setq since (match-string 1 arg)))
+        ((equal "--all-containers" arg) (setq container t))
+        ((equal "--follow" arg) (setq follow t))
+        ((equal "--prefix" arg) (setq prefix t))
+        ((equal "--timestamps" arg) (setq timestamps t))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (setq type (kubed-read-resource-type "Type of resource to display"
+                                          nil context))
+     (unless namespace
+       (setq namespace (kubed--namespace context current-prefix-arg)))
+     (setq resource (kubed-read-resource-name type "Show logs for" nil nil
+                                              context namespace))
+     (list type resource context namespace
+           (or container
+               (and (string= type "pods")
+                    (kubed-read-container resource "Container" t
+                                          context namespace)))
+           follow limit prefix since tail timestamps)))
+  (let* ((context (or context (kubed-local-context)))
+         (namespace (or namespace (kubed--namespace context)))
+         (buf (generate-new-buffer
+               (format "*kubed-logs %s/%s%s in %s[%s]*"
+                       type resource
+                       (cond
+                        ((stringp container) (concat "[" container "]"))
+                        (container "[all containers]")
+                        (t ""))
+                       namespace context))))
+    (with-current-buffer buf (run-hooks 'kubed-logs-setup-hook))
+    (apply #'start-process "*kubed-logs*" buf
+           kubed-kubectl-program "logs" (concat type "/" resource)
+           "--context" context "-n" namespace
+           (append
+            (cond
+             ((stringp container) (list "-c" container))
+             (container '("--all-containers")))
+            (when follow '("--follow"))
+            (when prefix '("--prefix"))
+            (when timestamps '("--timestamps"))
+            (when since (list "--since-time" since))
+            (when tail (list "--tail" (number-to-string tail)))
+            (when limit (list "--limit-bytes" (number-to-string limit)))))
+    (display-buffer buf)))
+
+(defvar kubed-port-forward-process-alist nil
+  "Alist of current port-forwarding descriptors and corresponding processes.")
+
+(defun kubed-port-forward-process-alist (&optional _ignored)
+  "Update and return value of variable `kubed-port-forward-process-alist'."
+  (setq kubed-port-forward-process-alist
+        (seq-filter (lambda (pair)
+                      (process-live-p (cdr pair)))
+                    kubed-port-forward-process-alist)))
+
+;;;###autoload
+(defun kubed-forward-port-to-pod
+    (pod local-port remote-port context namespace)
+  "Forward LOCAL-PORT to REMOTE-PORT of Kubernetes pod POD."
+  (interactive
+   (let* ((c (kubed-local-context))
+          (c (if (equal current-prefix-arg '(16))
+                 (kubed-read-context "Context" c)
+               c))
+          (n (kubed--namespace c current-prefix-arg))
+          (n (if current-prefix-arg
+                 (kubed-read-namespace "Namespace" n nil c)
+               n))
+          (p (kubed-read-pod "Forward port to pod" nil nil c n))
+          (l (read-number "Local port: "))
+          (r (read-number "Remote port: ")))
+     (list p l r c n)))
+  (message "Forwarding local port %d to remote port %d of pod `%s' in namespace `%s'..."
+           local-port remote-port pod namespace)
+  (push
+   (cons
+    (format "%s %d:%d in %s[%s]" pod local-port remote-port namespace context)
+    (apply #'start-process
+           "*kubed-port-forward*" nil
+           kubed-kubectl-program "port-forward"
+           pod (format "%d:%d" local-port remote-port)
+           (append
+            (when namespace (list "-n" namespace))
+            (when context (list "--context" context)))))
+   kubed-port-forward-process-alist))
+
+(defun kubed-stop-port-forward (descriptor)
+  "Stop Kubernetes port-forwarding with descriptor DESCRIPTOR.
+
+DESCRIPTOR is a string that says which port-forwarding process to stop,
+it has the format \"POD LOCAL-PORT:REMOTE-PORT in NAMESPACE[CONTEXT]\",
+where POD is the name of the pod that is the target of the
+port-forwarding, LOCAL-PORT is the local port that is being forwarded,
+REMOTE-PORT is the correspoding remote port of POD, NAMESPACE is the
+namespace of POD and CONTEXT is the `kubectl' context.
+
+Interactively, prompt for DESCRIPTOR with completion.  If there is only
+one port-forwarding process, stop that process without prompting."
+  (interactive
+   (list
+    (cond
+     ((cdr (kubed-port-forward-process-alist))
+      (completing-read "Stop port-forwarding: "
+                       (completion-table-dynamic
+                        #'kubed-port-forward-process-alist)
+                       nil t))
+     ((caar kubed-port-forward-process-alist))
+     (t (user-error "No port-forwarding to Kubernetes in progress")))))
+  (if-let ((pair (assoc descriptor kubed-port-forward-process-alist)))
+      (delete-process (cdr pair))
+    (error "No port-forwarding for %s" descriptor))
+  (message "Stopped port-forwarding for %s" descriptor))
+
+(defvar kubed-container-image-history nil
+  "Minibuffer history for `kubed-read-container-image'.")
+
+(defun kubed-read-container-image (prompt &optional default multi)
+  "Prompt with PROMPT for names of container images.
+
+Optional argument DEFAULT is the minibuffer default argument.  Non-nil
+optional argument MULTI says to read multiple image names and return
+them as list."
+  (funcall (if multi #'completing-read-multiple #'completing-read)
+           (format-prompt prompt default) nil nil nil nil
+           'kubed-container-images-history default))
+
+(defvar kubed-ingress-rule-history nil
+  "Minibuffer history for `kubed-read-ingress-rules'.")
+
+(defun kubed-read-ingress-rules ()
+  "Prompt with PROMPT for Kubernetes ingress rules."
+  (let ((rules (list (read-string "Ingress rule: "
+                                  nil 'kubed-ingress-rule-history))))
+    (while (not
+            (string-empty-p
+             (car (push (read-string (format-prompt "Additional rules" "done")
+                                     nil 'kubed-ingress-rule-history)
+                        rules)))))
+    (nreverse (cdr rules))))
+
+(defvar transient-current-command)
+
+(defun kubed-transient-args (&optional prefix)
+  "Return current arguments from transient PREFIX.
+
+If PREFIX nil, it defaults to the value of `transient-current-command'."
+  (when-let ((prefix (or prefix (bound-and-true-p transient-current-command))))
+    (and (featurep 'kubed-transient)
+         (fboundp 'transient-args)
+         (transient-args prefix))))
+
+;;;###autoload
+(defun kubed-attach (pod &optional container context namespace stdin tty)
+  "Attach to running process in CONTAINER in Kubernetes POD.
+
+Optional argument NAMESPACE is the namespace in which to look for POD.
+Non-nil STDIN says to connect local standard input to remote process.
+Non-nil TTY says to use a TTY for standard input.
+
+Interactively, prompt for POD; if there are multiple pod containers,
+prompt for CONTAINER as well.  With a prefix argument, prompt for
+NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
+STDIN and TTY are t interactively."
+  (interactive
+   (let ((context nil) (namespace nil) (stdin t) (tty t))
+     (dolist (arg (kubed-transient-args 'kubed-transient-attach))
+       (cond
+        ((string-match "--namespace=\\(.+\\)" arg)
+         (setq namespace (match-string 1 arg)))
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))
+        ((equal "--stdin" arg) (setq stdin t))
+        ((equal "--tty" arg) (setq tty t))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (unless namespace
+       (setq namespace (kubed--namespace context current-prefix-arg)))
+     (let* ((p (kubed-read-pod "Exec on pod" nil nil context namespace))
+            (c (kubed-read-container p "Container" t context namespace)))
+       (list p c context namespace stdin tty))))
+  (pop-to-buffer
+   (apply #'make-comint "kubed-attach" kubed-kubectl-program nil
+          "attach" pod
+          (append
+           (when namespace (list "-n" namespace))
+           (when context (list "--context" context))
+           (when container (list "-c" container))
+           (when stdin '("-i"))
+           (when tty   '("-t"))))))
+
+;;;###autoload
+(defun kubed-diff (definition &optional include-managed context)
+  "Display difference between Kubernetes resource DEFINITION and current state.
+
+DEFINITION is either a file name or a buffer.  Interactively, prompt for
+a YAML or JSON file name to use as DEFINITION.
+
+Optional argument CONTEXT is the `kubectl' context to use, defaulting to
+the current context; non-nil INCLUDE-MANAGED (interactively, the prefix
+argument) says to include managed fields in the comparison."
+  (interactive
+   (let ((definition nil) (context nil) (include-managed nil))
+     (dolist (arg (kubed-transient-args 'kubed-transient-diff))
+       (cond
+        ((string-match "--filename=\\(.+\\)" arg)
+         (setq definition (match-string 1 arg)))
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))
+        ((equal "--show-managed-fields" arg) (setq include-managed t))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (list (or definition (kubed-read-resource-definition-file-name))
+           (or include-managed current-prefix-arg)
+           context)))
+  (let ((buf (get-buffer-create "*kubed-diff*"))
+        (args (cons "diff"
+                    (append
+                     (when context (list "--context" context))
+                     (when include-managed
+                       (list "--show-managed-fields" "true"))
+                     (list "-f" (if (bufferp definition) "-"
+                                  (expand-file-name definition)))))))
+    (with-current-buffer buf
+      (setq buffer-read-only nil)
+      (delete-region (point-min) (point-max))
+      (fundamental-mode)
+      (if (bufferp definition)
+          (with-current-buffer definition
+            (apply #'call-process-region nil nil kubed-kubectl-program
+                   nil buf nil args))
+        (apply #'call-process kubed-kubectl-program
+               nil t nil args))
+      (setq buffer-read-only t)
+      (diff-mode)
+      (goto-char (point-min)))
+    (display-buffer buf)))
+
+;;;###autoload
+(defun kubed-exec
+    (pod command &optional container context namespace stdin tty args)
+  "Execute COMMAND with ARGS in CONTAINER in Kubernetes POD.
+
+Optional argument NAMESPACE is the namespace in which to look for POD.
+Non-nil STDIN says to connect local standard input to remote process.
+Non-nil TTY says to use a TTY for standard input.
+
+Interactively, prompt for POD; if there are multiple pod containers,
+prompt for CONTAINER as well.  With a prefix argument, prompt for
+NAMESPACE too.  With a double prefix argument, also prompt for CONTEXT.
+STDIN and TTY are t interactively."
+  (interactive
+   (let ((context nil) (namespace nil) (stdin t) (tty t) (command nil) (args nil))
+     (dolist (arg (kubed-transient-args 'kubed-transient-exec))
+       (cond
+        ((string-match "--namespace=\\(.+\\)" arg)
+         (setq namespace (match-string 1 arg)))
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))
+        ((equal "--stdin" arg) (setq stdin t))
+        ((equal "--tty" arg) (setq tty t))
+        ((string-match "-- =\\(.+\\)" arg)
+         (setq args    (split-string-and-unquote (match-string 1 arg))
+               command (car args)
+               args    (cdr args)))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (unless namespace
+       (setq namespace (kubed--namespace context current-prefix-arg)))
+     (unless command
+       (setq args    (split-string-and-unquote
+                      (read-string "Execute command: "))
+             command (car args)
+             args    (cdr args)))
+     (let* ((p (kubed-read-pod "Exec on pod" nil nil context namespace))
+            (c (kubed-read-container p "Container" t context namespace)))
+       (list p command c context namespace stdin tty args))))
+  (pop-to-buffer
+   (apply #'make-comint "kubed-exec" kubed-kubectl-program nil
+          "exec" pod
+          (append
+           (when namespace (list "-n" namespace))
+           (when context (list "--context" context))
+           (when container (list "-c" container))
+           (when stdin '("-i"))
+           (when tty '("-t"))
+           (list "--" command)
+           args))))
+
+(defvar kubed-patch-history nil
+  "Minibuffer history for `kubed-read-patch'.")
+
+(defun kubed-read-patch ()
+  "Prompt for a Kubernetes resource patch in JSON or YAML format."
+  (read-string "Patch (JSON or YAML): " nil 'kubed-patch-history))
+
+;;;###autoload
+(defun kubed-patch (type name patch &optional context namespace strategy)
+  "Patch Kubernetes resource NAME of TYPE with patch PATCH.
+
+Optional argument NAMESPACE is the namespace in which to look for NAME.
+STRATEGY is the patch type to use, one of \"json\", \"merge\" and
+\"strategic\", defaulting to \"strategic\".
+
+Interactively, prompt for TYPE, NAME and PATCH.  With a prefix argument,
+prompt for NAMESPACE too.  With a double prefix argument, also prompt
+for CONTEXT."
+  (interactive
+   (let ((type nil) (context nil) (namespace nil) (strategy nil))
+     (dolist (arg (kubed-transient-args 'kubed-transient-patch))
+       (cond
+        ((string-match "--namespace=\\(.+\\)" arg)
+         (setq namespace (match-string 1 arg)))
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))
+        ((string-match "--type=\\(.+\\)" arg)
+         (setq strategy (match-string 1 arg)))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (unless namespace
+       (setq namespace (kubed--namespace context current-prefix-arg)))
+     (list (kubed-read-resource-type "Resource type to patch" nil context)
+           (kubed-read-resource-name type "Resource to patch" nil nil context namespace)
+           (kubed-read-patch) context namespace strategy)))
+  (message "Applying patch to `%s'..." name)
+  (unless (zerop
+           (apply #'call-process
+                  kubed-kubectl-program nil nil nil
+                  "patch" type name "-p" patch
+                  (append
+                   (when namespace (list "-n" namespace))
+                   (when context (list "--context" context))
+                   (when strategy (list "--type" strategy)))))
+    (user-error "Patching `%s' failed" name))
+  (message "Applying patch to `%s'...  Done." name))
+
+(defvar kubed--proxy-alist nil
+  "Alist associating `kubectl' context names and their proxy processes.")
+
+;;;###autoload
+(defun kubed-proxy
+    (&optional addr port api-prefix www-dir www-prefix context)
+  "Start a web server on localhost proxying the Kubernetes API server.
+
+ADDR and PORT are the local address and port to bind the proxy server
+to.  They default to 127.0.0.1 and 8001, respectively.  API-PREFIX is a
+prefix under which to proxy the Kubernetes API.  WWW-DIR is a local
+directory to serve under WWW-PREFIX, which defaults to \"/static/\".
+Lastly, CONTEXT is the the `kubectl' context to use, defaulting to the
+local context."
+  (interactive
+   (let ((addr nil) (port nil)
+         (api-prefix nil) (www-dir nil) (www-prefix nil)
+         (context nil))
+     (dolist (arg (kubed-transient-args 'kubed-transient-proxy))
+       (cond
+        ((string-match "--address=\\(.+\\)" arg)
+         (setq addr (match-string 1 arg)))
+        ((string-match "--port=\\(.+\\)" arg)
+         (setq port (string-to-number (match-string 1 arg))))
+        ((string-match "--api-prefix=\\(.+\\)" arg)
+         (setq api-prefix (match-string 1 arg)))
+        ((string-match "--www-dir=\\(.+\\)" arg)
+         (setq www-dir (match-string 1 arg)))
+        ((string-match "--www-prefix=\\(.+\\)" arg)
+         (setq www-prefix (match-string 1 arg)))
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (list addr port api-prefix www-dir www-prefix context)))
+  (let ((context (or context (kubed-local-context))))
+    (when-let ((proc (alist-get context kubed--proxy-alist
+                                nil nil #'string=))
+               ((process-live-p proc)))
+      (if (y-or-n-p (concat "Proxy already running for context `" context
+                            "'.  Stop it and start new proxy?"))
+          (kill-process proc)
+        (user-error "Proxy already running for context `%s'" context))
+      (message "Stopped proxy for context `%s'." context))
+    (setf (alist-get context kubed--proxy-alist nil nil #'string=)
+          (apply #'start-process (format "*kubed-proxy[%s]*" context) nil
+                 kubed-kubectl-program "proxy"
+                 "--context" context
+                 (append
+                  (when addr (list "--address" addr))
+                  (when port (list "--port" (number-to-string port)))
+                  (when api-prefix (list "--api-prefix" api-prefix))
+                  (when www-dir (list "--www-dir" www-dir))
+                  (when www-prefix (list "--www-prefix" www-prefix)))))
+    (message "Started proxy for context `%s'." context)))
+
+;;;###autoload
+(defun kubed-stop-proxy (&optional context)
+  "Stop local proxy for context CONTEXT, defaulting to the local context."
+  (interactive
+   (let ((context nil))
+     (dolist (arg (kubed-transient-args 'kubed-transient-proxy))
+       (cond
+        ((string-match "--context=\\(.+\\)" arg)
+         (setq context (match-string 1 arg)))))
+     (unless context
+       (setq context
+             (let ((cxt (kubed-local-context)))
+               (if (equal current-prefix-arg '(16))
+                   (kubed-read-context "Context" cxt)
+                 cxt))))
+     (list context)))
+  (let ((context (or context (kubed-local-context))))
+    (if-let ((proc (alist-get context kubed--proxy-alist
+                              nil nil #'string=))
+             ((process-live-p proc)))
+        (kill-process proc)
+      (user-error "No proxy running for context `%s'" context))
+    (message "Stopped proxy for context `%s'." context)))
+
+(with-eval-after-load 'help-mode
+  ;; Wait for `help-mode' to define `help-xref'.  It's always loaded by
+  ;; the time we actually need it in `kubed-explain'.
+  (define-button-type 'kubed-explain
+    :supertype 'help-xref
+    'help-function 'kubed-explain
+    'help-echo "mouse-2, RET: explain"))
+
+(defvar kubed-resource-field-history nil
+  "Minibuffer history for `kubed-read-resource-field'.")
+
+(defun kubed-api-resources (&optional context only-namespaced)
+  "Return list of resource types in the context CONTEXT.
+
+Non-nil optional argument ONLY-NAMESPACED says to return only namespaced
+resource types."
+  (mapcar
+   (lambda (line)
+     (car (split-string line)))
+   (apply #'process-lines
+          kubed-kubectl-program
+          "api-resources" "--no-headers"
+          (append
+           (when only-namespaced '("--namespaced=true"))
+           (when context (list (concat "--context=" context)))))))
+
+(defun kubed-resource-names (type context &optional namespace)
+  "Return list of Kubernetes resources of type TYPE in NAMESPACE via CONTEXT."
+  (unless (kubed--alist type context namespace)
+    (let ((proc (kubed-update type context namespace)))
+      (while (process-live-p proc)
+        (accept-process-output proc 1))))
+  (mapcar #'car (alist-get 'resources (kubed--alist type context namespace))))
+
+(defun kubed-read-resource-name (type prompt &optional default multi context namespace)
+  "Prompt with PROMPT for Kubernetes resource name of type TYPE.
+
+Optional argument DEFAULT is the minibuffer default argument; non-nil
+MULTI says to read multiple names and return them as a list; CONTEXT is
+the `kubectl' context to use, defaulting to the local context; and
+NAMESPACE is the namespace to use, or nil if TYPE is non-namespaced."
+  (funcall
+   (if multi #'completing-read-multiple #'completing-read)
+   (format-prompt prompt default)
+   (let ((table 'unset))
+     (lambda (s p a)
+       (if (eq a 'metadata)
+           `(metadata (category . ,(intern (concat "kubernetes-" type))))
+         (when (eq table 'unset)
+           (setq table (kubed-resource-names
+                        type (or context (kubed-local-context)) namespace)))
+         (complete-with-action a table s p))))
+   nil 'confirm nil (intern (concat "kubed-" type "-history")) default))
+
+(defun kubed-read-resource-type (prompt &optional default context)
+  "Prompt with PROMPT for Kubernetes resource type in context CONTEXT.
+
+Optional argument DEFAULT is the minibuffer default argument."
+  (completing-read
+   (format-prompt prompt default)
+   (kubed-api-resources context)
+   nil 'confirm nil nil default))
+
+(defun kubed-read-resource-field (prompt &optional default context)
+  "Prompt with PROMPT for Kubernetes resource type or field name.
+
+Optional argument DEFAULT is the minibuffer default argument, and
+CONTEXT is the `kubectl' context to use."
+  (completing-read
+   (format-prompt prompt default)
+   (lambda (s p a)
+     (unless (eq a 'metadata)
+       (let ((start 0))
+         (while (string-match "\\." s start)
+           (setq start (match-end 0)))
+         (if (eq (car-safe a) 'boundaries)
+             `(boundaries ,start . ,(and (string-match "\\." (cdr a))
+                                         (match-beginning 0)))
+           (let ((table
+                  (if (zerop start)
+                      ;; Complete resource type.
+                      (kubed-api-resources context)
+                    ;; Complete (sub-)field name.
+                    (with-temp-buffer
+                      (call-process
+                       kubed-kubectl-program nil t nil
+                       "explain" (substring s 0 start))
+                      (goto-char (point-min))
+                      (let ((res nil))
+                        (while (re-search-forward
+                                (rx line-start (+ " ") (group-n 1 (* alnum)) "\t")
+                                nil t)
+                          (push (match-string 1) res))
+                        res)))))
+             (if a (complete-with-action a table (substring s start) p)
+               ;; `try-completion'.
+               (let ((comp (complete-with-action a table (substring s start) p)))
+                 (if (stringp comp) (concat (substring s 0 start) comp) comp))))))))
+   nil 'confirm nil 'kubed-resource-field-history default))
+
+;;;###autoload
+(defun kubed-explain (field)
+  "Show help buffer with explanation about Kubernetes resource FIELD."
+  (interactive
+   (list (kubed-read-resource-field "Explain type or field")))
+  (let ((help-buffer-under-preparation t))
+    (help-setup-xref (list #'kubed-explain field)
+                     (called-interactively-p 'interactive))
+    (with-help-window (help-buffer)
+      (with-current-buffer (help-buffer)
+        (insert (substitute-quotes
+                 (concat "`kubed explain " field "' says:\n\n")))
+        (save-excursion
+          ;; Add button that goes to parent.
+          (goto-char (point-min))
+          (when (re-search-forward (rx " "
+                                       (group-n 1 (* graph))
+                                       "."
+                                       (+ (not (any ?.)))
+                                       line-end)
+                                   nil t)
+            (help-xref-button 1 'kubed-explain (match-string 1))))
+
+        (call-process kubed-kubectl-program nil t nil "explain" field)
+        ;; Buttonize references to other fields.
+        (goto-char (point-min))
+        (while (re-search-forward (rx line-start
+                                      (+ " ")
+                                      (group-n 1 (* alnum))
+                                      "\t")
+                                  nil t)
+          (help-xref-button 1 'kubed-explain
+                            (concat field "." (match-string 1))))))))
+
+(defvar kubed-kubectl-command-history nil
+  "Minibuffer history for `kubed-kubectl-command'.")
+
+(declare-function cobra-read-command-line "cobra"
+                  (prompt initial &optional hist))
+
+(defun kubed-read-kubectl-command (prompt &optional initial)
+  "Prompt with PROMPT for a `kubectl' command line.
+
+Optional argument INITIAL added to the initial minibuffer input
+following the value of `kubed-kubectl-program' and a space character."
+  (let ((init (if (consp initial)
+                  (cons    (concat kubed-kubectl-program " " (car initial))
+                        (+ (length kubed-kubectl-program) 1  (cdr initial)))
+                (concat kubed-kubectl-program " " initial))))
+    (cobra-read-command-line prompt init 'kubed-kubectl-command-history)))
+
+;;;###autoload
+(defun kubed-kubectl-command (command)
+  "Execute `kubectl' COMMAND.
+
+This function calls `shell-command' (which see) to do the work.
+
+Interactively, prompt for COMMAND with completion for `kubectl' arguments."
+  (interactive
+   (list (kubed-read-kubectl-command
+          "Command: "
+          (let* ((args (kubed-transient-args))
+                 (prefix (and (fboundp 'transient-prefix-object)
+                              (transient-prefix-object)))
+                 (scope (and prefix (fboundp 'eieio-oref)
+                             (eieio-oref prefix 'scope))))
+            (when (or args scope)
+              (concat (string-join (append scope args) " ") " "))))))
+  (shell-command command))
+
+;;;###autoload (autoload 'kubed-prefix-map "kubed" nil t 'keymap)
+(defvar-keymap kubed-prefix-map
+  :doc "Prefix keymap for Kubed commands."
+  :prefix 'kubed-prefix-map
+  "p" 'kubed-pod-prefix-map
+  "N" 'kubed-namespace-prefix-map
+  "s" 'kubed-service-prefix-map
+  "S" 'kubed-secret-prefix-map
+  "j" 'kubed-job-prefix-map
+  "d" 'kubed-deployment-prefix-map
+  "i" 'kubed-ingress-prefix-map
+  "c" 'kubed-cronjob-prefix-map
+  "C" #'kubed-use-context
+  "+" #'kubed-create
+  "*" #'kubed-apply
+  "R" #'kubed-run
+  "=" #'kubed-diff
+  "E" #'kubed-explain
+  "P" #'kubed-patch
+  ":" #'kubed-proxy
+  "RET" #'kubed-display-resource
+  "!" #'kubed-kubectl-command)
+
+(defvar-keymap kubed-menu-map
+  :doc "Keymap with Kubed menu entries."
+  :prefix 'kubed-menu-map
+  "<namespace>"        '("Namespaces..."         . kubed-namespace-menu-map)
+  "<pod>"              '("Pods..."               . kubed-pod-menu-map)
+  "<persistentvolume>" '("Persistent Volumes..." . kubed-persistentvolume-menu-map)
+  "<service>"          '("Services..."           . kubed-service-menu-map)
+  "<secret>"           '("Secrets..."            . kubed-secret-menu-map)
+  "<job>"              '("Jobs..."               . kubed-job-menu-map)
+  "<deployment>"       '("Deployments..."        . kubed-deployment-menu-map)
+  "<replicaset>"       '("Replica Sets..."       . kubed-replicaset-menu-map)
+  "<daemonset>"        '("Daemon Sets..."        . kubed-daemonset-menu-map)
+  "<statefulset>"      '("Stateful Sets..."      . kubed-statefulset-menu-map)
+  "<cronjob>"          '("Cron Jobs..."          . kubed-cronjob-menu-map)
+  "<ingressclass>"     '("Ingress Classes..."    . kubed-ingressclass-menu-map)
+  "<ingress>"          '("Ingresses..."          . kubed-ingress-menu-map)
+  "<proxy>"            '("Proxy Kubernetes API"  . kubed-proxy)
+  "<patch>"            '("Patch Resource"        . kubed-patch)
+  "<diff>"             '("Diff Config with Live" . kubed-diff)
+  "<kubectl-command>"  '("Invoke kubectl"        . kubed-kubectl-command)
+  "<explain>"          '("Explain Type or Field" . kubed-explain)
+  "<use-context>"      '("Set Current Context"   . kubed-use-context)
+  "<run>"              '("Run Image"             . kubed-run)
+  "<apply>"            '("Apply Config"          . kubed-apply)
+  "<create>"           '("Create Resource"       . kubed-create)
+  "<display>"          '("Display Resource"      . kubed-display-resource))
+
+;;;###autoload
+(define-minor-mode kubed-menu-bar-mode
+  "Add \"Kubernetes\" menu to your menu bar."
+  :global t
+  (if kubed-menu-bar-mode
+      (keymap-set-after (current-global-map)
+        "<menu-bar> <kubed>" '("Kubernetes" . kubed-menu-map))
+    (keymap-global-unset "<menu-bar> <kubed>")))
+
+(defvar reporter-prompt-for-summary-p)
+
+(defun kubed-submit-bug-report ()
+  "Report a Kubed issue to the maintainers via email."
+  (interactive)
+  (require 'reporter)
+  (let ((reporter-prompt-for-summary-p t))
+    (reporter-submit-bug-report
+     "Kubed Development <~eshel/kubed-develNOSPAMlists.sr.ht>"
+     (format "Kubed")
+     '(kubed-kubectl-program)
+     nil nil
+     (propertize " "
+                 'display
+                 (propertize
+                  "Insert your bug report below.
+If possible, specify where you got Emacs, kubectl and Kubed,
+and include a recipe for reproducing your issue.
+[This line and the above text are not included in your report.]"
+                  'face 'italic)))))
+
+(provide 'kubed)
+;;; kubed.el ends here
diff --git a/elpa/kubed-0.5.0/kubed.info b/elpa/kubed-0.5.0/kubed.info
new file mode 100644 (file)
index 0000000..afd891e
Binary files /dev/null and b/elpa/kubed-0.5.0/kubed.info differ
diff --git a/elpa/kubed-0.5.0/kubed.texi b/elpa/kubed-0.5.0/kubed.texi
new file mode 100644 (file)
index 0000000..86e6e1c
--- /dev/null
@@ -0,0 +1,817 @@
+\input texinfo    @c -*- texinfo -*-
+@c %**start of header
+@setfilename kubed.info
+@settitle Kubed: Kubernetes, Emacs, done!
+@documentencoding UTF-8
+@documentlanguage en
+@set MAINTAINERSITE @uref{https://eshelyaron.com,maintainer webpage}
+@set MAINTAINER Eshel Yaron
+@set MAINTAINEREMAIL @email{meNOSPAMeshelyaron.com}
+@set MAINTAINERCONTACT @uref{mailto:meNOSPAMeshelyaron.com,contact the maintainer}
+@c %**end of header
+
+@copying
+This manual is for Kubed 0.5.0, a rich Emacs interface for Kubernetes.
+
+Copyright @copyright{} 2024-2025 Eshel Yaron.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+@end quotation
+@end copying
+
+@dircategory Emacs
+@direntry
+* Kubed: (kubed).       Kubernetes, Emacs, done!
+@end direntry
+
+@finalout
+@titlepage
+@title Kubed: Kubernetes, Emacs, done!
+@author Eshel Yaron (@email{me@@eshelyaron.com})
+@end titlepage
+
+@contents
+
+@ifnottex
+@node Top
+@top Kubed: Kubernetes, Emacs, done!
+
+This manual is for Kubed 0.5.0, a rich Emacs interface for Kubernetes.
+
+@end ifnottex
+
+@menu
+* Overview::                    Introduction to Kubed
+* Getting Started::             First steps with Kubed
+* Usage::                       Using Kubed to interact with Kubernetes
+* Extending Kubed::             Adding support for your custom resources
+* Contributing::                Get involved in Kubed development
+* Indices::
+@end menu
+
+@node Overview
+@chapter Overview
+
+@cindex Kubed
+@cindex kubed
+Kubed is a rich Kubernetes interface within Emacs.  It helps you work
+with your Kubernetes clusters and deployments with the full power of
+@command{kubectl}, and with the comfort and confidence of an intuitive
+interactive interface.
+
+@float
+@ifset split
+@image{../../assets/kubed-overview,,,Image: Four different kinds of Kubed buffers in Emacs,.png}
+@end ifset
+@ifclear split
+@image{assets/kubed-overview,,,Image: Four different kinds of Kubed buffers in Emacs,.png}
+@end ifclear
+@caption{Pods, logs, shells, YAMLs, all in one integrated interface}
+@end float
+
+You can use Kubed to:
+
+@itemize
+@item
+Browse and manage Kubernetes workloads
+@item
+Connect to pods and edit files or execute commands
+@item
+Create new resources, edit and delete them
+@item
+Work with multiple clusters
+@item
+Get help about various Kubernetes objects
+@item
+@dots{}
+@end itemize
+
+These features and others are documented in the rest of this manual,
+along with many options that Kubed provides for you to customize its
+behavior.
+
+@node Getting Started
+@chapter Getting Started
+
+@cindex installation
+
+Get Kubed from GNU ELPA with @kbd{M-x package-install}, or use your
+favorite Emacs package manager to install Kubed from Git.  You can
+clone the Kubed Git repository from any of the following locations:
+
+@itemize
+@item
+@url{https://git.sr.ht/~eshel/kubed}
+@item
+@url{https://github.com/eshelyaron/kubed.git}
+@item
+@url{git://git.eshelyaron.com/kubed.git}
+@end itemize
+
+@cindex requirements
+To get started with Kubed, all you need is @command{kubectl} and Emacs.
+
+Kubed tries to find @command{kubectl} in the directories listed in the
+Emacs variable @code{exec-path}.  When Emacs is started from a shell, it
+initializes @code{exec-path} from the shell's @env{PATH} environment
+variable which normally includes the location of @command{kubectl} in
+common @command{kubectl} installations.  If Emacs doesn't find the
+@command{kubectl} executable via @code{exec-path}, you can tell Kubed
+where to find it by customizing @code{kubed-kubectl-program}.
+
+@defopt kubed-kubectl-program
+Name of @command{kubectl} executable file to use.
+@end defopt
+
+@node Usage
+@chapter Usage
+
+Kubed comes with a large number of Emacs command for interacting with
+Kubernetes.  Some commands perform one action on one resource, while
+others show you a menu with many resources and let you interact with any
+number of them.  Some commands are specific to one type of resources,
+while others act on resources of any type.  There are different ways to
+use Kubed, depending on your use case.
+
+The two most important entry points for Kubed are
+@code{kubed-prefix-map} and @code{kubed-transient}:
+
+@anchor{Definition of kubed-prefix-map}
+@cindex global prefix keymap
+@cindex prefix keymap, global commands
+@cindex keymap, for global commands
+@defvr Keymap kubed-prefix-map
+Keymap with bindings for many useful Kubed commands.
+@end defvr
+
+The prefix keymap @code{kubed-prefix-map} gives you quick access to the
+main Kubed commands.  You may want to bind it to a convenient key in
+your global keymap, for example:
+
+@lisp
+(keymap-global-set "C-c k" 'kubed-prefix-map)
+@end lisp
+
+With this binding in place, you can create a new Kubernetes resource
+with @kbd{C-c k +} and attach to a running pod with @kbd{C-c k p a}.
+The @kbd{C-c k} binding is just a suggestion of course, feel free to
+pick any key sequence you like.
+
+@float
+
+@ifset split
+@image{../../assets/kubed-prefix-map,,,Image: Emacs which-key popup for kubed-prefix-map keymap,.png}
+@end ifset
+@ifclear split
+@image{assets/kubed-prefix-map,,,Image: Emacs which-key popup for kubed-prefix-map keymap,.png}
+@end ifclear
+
+@ifset split
+@image{../../assets/kubed-deployment-prefix-map,,,Image: Emacs which-key popup for kubed-deployment-prefix-map,.png}
+@end ifset
+@ifclear split
+@image{assets/kubed-deployment-prefix-map,,,Image: Emacs which-key popup for kubed-deployment-prefix-map,.png}
+@end ifclear
+
+@caption{Use @code{kubed-prefix-map} for quick access to the main Kubed commands}
+@end float
+
+You can also access all of the commands in @code{kubed-prefix-map} via
+the menu-bar @samp{Kubernetes} menu---to add this menu to your
+menu-bar, enable the global minor mode @code{kubed-menu-bar-mode}:
+
+@anchor{Definition of kubed-menu-bar-mode}
+@deffn {Minor Mode} kubed-menu-bar-mode
+Add @samp{Kubernetes} menu to your menu bar.
+@end deffn
+
+The other important entry point that Kubed provides for exploring and
+performing different Kubernetes operations is @code{kubed-transient}:
+
+@deffn Command kubed-transient
+Open the main Kubed transient menu.
+@end deffn
+
+This command pops up the Kubed transient menu, which gives you
+interactive guidance for invoking Kubed commands.
+@xref{Top,,,transient}.
+
+The following sections describe in detail the various Kubed commands.
+
+@menu
+* Display Resource::
+* Browse Resources::
+* Context and Namespace::
+* Transient Menus::
+* Scale Deployment::
+@end menu
+
+@node Display Resource
+@section Display Resource
+
+You can view the YAML description of any resource in your Kubernetes
+cluster.  In Kubed, this is referred to as @dfn{displaying} the given
+resource.  The following commands display a Kubernetes resource:
+
+@deffn Command kubed-display-resource
+Display a Kubernetes resource.
+@end deffn
+
+@deffn Command kubed-display-pod
+@deffnx Command kubed-display-deployment
+@deffnx Command kubed-display-namespace
+@deffnx Command kubed-display-@var{foo}
+Display Kubernetes resource of a given type.
+@end deffn
+
+Command @code{kubed-display-resource} can display any Kubernetes
+resource.  It prompts you to select a resource type and a resource
+name, and displays that resource in a dedicated buffer.  By default,
+this command assumes you want to display a resource that is in the
+current namespace, but if you invoke @code{kubed-display-resource}
+with a prefix argument (@kbd{C-u}) and choose a namespaced resource
+type, then it also lets you select the namespace of the resource.
+With a double prefix argument, it lets you select which
+@command{kubectl} context to use too.  @xref{Context and Namespace}.
+
+If you have @code{kubed-prefix-map} bound to @kbd{C-c k}, you can
+invoke @code{kubed-display-resource} with @kbd{C-c k @key{RET}}.  This
+command is also available from the menu-bar ``Kubernetes'' menu
+(@pxref{Definition of kubed-menu-bar-mode}), and from the transient
+``Kubernetes Display'' menu (@pxref{Transient Menus}).
+
+You can also display the resource at point in resources list buffers
+by simply typing @kbd{@key{RET}}.  @xref{Browse Resources}.
+
+Kubed also provides a dedicated @code{kubed-display-@var{foo}} command
+for each supported resource type @var{foo}.  These commands are just
+like @code{kubed-display-resource}, except that they do not prompt you
+for a type, since they are type-specific.  For example,
+@code{kubed-display-pod} only prompts you for a pod name, and then
+displays it like @code{kubed-display-resource} does.
+
+You can invoke these commands by adding a type-specific key before
+@kbd{@key{RET}} in @kbd{C-c k @key{RET}}: @kbd{C-c k p @key{RET}}
+invokes @code{kubed-display-pod}, @kbd{C-c k d @key{RET}} invokes
+@code{kubed-display-deployment}, and so on.
+
+When Kubed prepares a buffer for displaying a resource, it runs the
+hook @code{kubed-yaml-setup-hook} right after populating the buffer
+with the YAML description of the resource:
+
+@defopt kubed-yaml-setup-hook
+List of functions to call, in order, to prepare YAML buffers.  The
+first function on this hook is normally the major mode you want to use
+for YAML buffers that display Kubernetes resources.  By default, this
+is the list @code{(yaml-ts-mode view-mode)}.
+@end defopt
+
+In addition, Kubed enables a bespoke minor mode
+@code{kubed-display-resource-mode} in buffers that display Kubernetes
+resources:
+
+@deffn {Minor Mode} kubed-display-resource-mode
+Minor mode for buffers that display a Kubernetes resource.
+@end deffn
+
+@noindent
+This minor mode does the following:
+
+@itemize
+@item
+It shows the word @samp{Kubed} in the mode line, so you know you're
+seeing a rendered Kubernetes resource, rather than any old YAML file.
+@item
+It allows you to @emph{bookmark} the resource your viewing and your
+position in its YAML description with the regular Emacs bookmarks
+commands (@pxref{Bookmarks,,,emacs}), namely @kbd{C-x r m}.
+@item
+@kindex C-c C-j
+@findex kubed-display-resource-jump-to-list
+It binds the key sequence @kbd{C-c C-j} to command
+@code{kubed-display-resource-jump-to-list}, which pops up the
+resources list buffer for the type of the displayed resource, and
+takes you to the line corresponding to it.
+@item
+@kindex C-c C-c
+@findex kubed-display-resource-replace
+@kindex C-c C-=
+@findex kubed-display-resource-diff
+@kindex C-x C-q
+@findex read-only-mode
+It binds @kbd{C-c C-c} to command
+@code{kubed-display-resource-replace}, which lets you apply any
+changes that you make in the YAML buffer back to the resource.  When
+you hit @kbd{C-c C-c}, Kubed asks you for confirmation before
+proceeding; you can reply with @kbd{d} (@samp{diff}) to show a diff
+between the current state of the resource and the current buffer
+contents.  You can also display this diff anytime with @kbd{C-c C-=}.
+Note that by default Kubed displays resources in read-only buffers, so
+you may need to hit @kbd{C-x C-q} (@code{read-only-mode}) before
+making changes in the buffer.
+@item
+@kindex C-x x g
+@findex revert-buffer
+@findex revert-buffer-quick
+It lets you repopulate the buffer with updated information about the
+resource with @kbd{C-x x g} (@code{revert-buffer-quick}) and
+@w{@kbd{M-x revert-buffer}}.  This is also useful if you edit the
+resource and want to restart from a clean slate.
+@end itemize
+
+@float
+@ifset split
+@image{../../assets/kubed-replace-diff,,,Image: Displaying and editing YAML of Kubernetes pod with Kubed,.png}
+@end ifset
+@ifclear split
+@image{assets/kubed-replace-diff,,,Image: Displaying and editing YAML of Kubernetes pod with Kubed,.png}
+@end ifclear
+@caption{Type @kbd{C-x C-q} in a resource YAML buffer to edit it, @kbd{C-c C-c} to apply}
+@end float
+
+@node Browse Resources
+@section Browse Resources
+
+Kubed gives you an interactive list of resources for each type, that
+you access with the @code{kubed-list-@var{resource}s} commands, such
+as @code{kubed-list-pods}.
+
+These commands are bound to @kbd{l} in Kubed's type-specific prefix
+keymaps, most of which are accessible via the global
+@code{kubed-prefix-map} by default (@pxref{Definition of
+kubed-prefix-map}).  So if you've bound @code{kubed-prefix-map} to
+@kbd{C-c k}, you can pop up the pods list with @kbd{C-c k p l}, the
+deployments list with @kbd{C-c k d l}, the jobs list with @w{@kbd{C-c
+k j l}}, etc.  Normally, Kubed shows the list of resources in the
+current namespace, but if you invoke these commands with a prefix
+argument (say, @kbd{C-u C-c k p l}), they first prompt you to select a
+namespace, and then show resources in the namespace you selected.
+
+The list of @var{resource}s in shown a buffer called @w{@file{*Kubed
+@var{resource}s@@@var{namespace}[@var{context}]*}}, where
+@var{context} is a @command{kubectl} context, and @var{namespace} is a
+namespace in @var{context}.  For example, Kubed shows the list of pods
+in namespace @samp{default} for context @samp{minikube} in buffer
+@file{*Kubed pos@@default[minikube]}.  For non-namespaced resources,
+the @w{@samp{@@@var{namespace}}} part is omitted.
+
+Each resource type has its own major mode for list buffers with
+type-specific commands and operations, but they are all also derived
+from a shared parent mode.  The pods list uses the
+@code{kubed-pods-mode} (@samp{Kubernetes Pods}) major mode, the list
+of Kubernetes deployments uses @code{kubed-deployments-mode}, and so
+on.
+
+@float
+@ifset split
+@image{../../assets/kubed-list-transient,,,Image: Kubed pods list buffer with the help transient menu visible,.png}
+@end ifset
+@ifclear split
+@image{assets/kubed-list-transient,,,Image: Kubed pods list buffer with the help transient menu visible,.png}
+@end ifclear
+@caption{Browse your pods, deployments, and other resources with Kubed list buffers}
+@end float
+
+The common parent major mode is @code{kubed-list-mode}:
+
+@deffn {Major Mode} kubed-list-mode
+Major mode for listing generic Kubernetes resources.
+@end deffn
+
+This mode provides the following commands for all type-specific
+derived modes:
+
+@table @kbd
+@kindex @key{?}
+@findex kubed-list-transient
+@item @key{?}
+Show help in transient menu (@code{kubed-list-transient}).
+@kindex @key{RET}
+@findex kubed-list-select-resource
+@item @key{RET}
+Display the resource at point in the current window
+(@code{kubed-list-select-resource}).
+@kindex o
+@findex kubed-list-select-resource-other-window
+@item o
+Display the resource at point in another window and select that window
+(@code{kubed-list-select-resource-other-window}).
+@kindex C-o
+@findex kubed-list-display-resource
+@item C-o
+Display the resource at point in another window without selecting it
+(@code{kubed-list-display-resource}).
+@kindex D
+@findex kubed-list-delete
+@item D
+Delete the resource at point (@code{kubed-list-delete}).
+@kindex e
+@findex kubed-list-edit
+@item e
+Edit the resource at point (@code{kubed-list-edit}).
+@kindex P
+@findex kubed-list-patch
+@item P
+Patch the resource at point (@code{kubed-list-patch}).
+@kindex g
+@findex kubed-list-update
+@item g
+Update the resources list by fetching new information from Kubernetes
+(@code{kubed-list-update}).
+@kindex /
+@findex kubed-list-set-filter
+@item /
+Filter the current list of resources (@code{kubed-list-set-filter}).
+@xref{List Filter}.
+@kindex d
+@findex kubed-list-mark-for-deletion
+@item d
+Mark the resource at point for deletion
+(@code{kubed-list-mark-for-deletion}).  Resources marked for deletion
+have a @samp{D} in the beginning of their line.
+@kindex x
+@findex kubed-list-delete-marked
+@item x
+Delete marked resources (@code{kubed-list-delete-marked}).
+@kindex u
+@findex kubed-list-unmark
+@item u
+Unmark from resource at point (@code{kubed-list-unmark}).
+@kindex w
+@findex kubed-list-copy-as-kill
+@item w
+Copy name of resource at point into the kill ring
+(@code{kubed-list-copy-as-kill}).
+@kindex n
+@findex next-line
+@item n
+Move point to the next line (@code{next-line}).
+@kindex p
+@findex previous-line
+@item p
+Move point to the previous line (@code{previous-line}).
+@kindex @key{TAB}
+@findex kubed-list-next-column
+@item @key{TAB}
+Move point to the next column.  If point is already at the last
+column, move to the first column of the next line instead
+(@code{kubed-list-next-column}).
+@kindex S-@key{TAB}
+@findex kubed-list-previous-column
+@item S-@key{TAB}
+Move point to the previous column.  If point is already at the first
+column, move to the last column of the previous line instead
+(@code{kubed-list-previous-column}).
+@kindex S
+@findex tabulated-list-sort
+@item S
+Sort lines by the column at point (@code{tabulated-list-sort}).
+@kindex |
+@findex kubed-list-fit-column-width-to-content
+@item |
+Fit width of column at point to its content
+(@code{kubed-list-fit-column-width-to-content}).  With non-negative
+prefix argument @var{n} (for example, @kbd{0 |}), fit @var{n}th
+column.  With negative prefix argument (@kbd{- |}), fit all columns.
+@kindex @{
+@findex tabulated-list-narrow-current-column
+@item @{
+Narrow the column at point
+(@code{tabulated-list-narrow-current-column}).
+@kindex @}
+@findex tabulated-list-widen-current-column
+@item @}
+Widen the column at point
+(@code{tabulated-list-widen-current-column}).
+@end table
+
+In addition, you can bookmark any Kubed resources list buffer with the
+usual @kbd{C-x r m}.  @xref{Bookmarks,,,emacs}.
+
+Note that @code{kubed-list-mode} (and its type-specific derivatives)
+bind the @kbd{g} key, which is commonly bound to @code{revert-buffer},
+to @code{kubed-list-update}.  The difference between these commands is
+that @code{revert-buffer} only refreshes the list display, without
+fetching updated data from Kubernetes.  You can still invoke
+@code{revert-buffer} with @kbd{C-x x g} or @kbd{M-x}, if you need it.
+
+@vindex kubed-list-mode-line-format
+Whenever Kubed is fetching data from Kubernetes to update a resources
+list buffer, the mode line of that list buffer shows the @samp{[...]}
+indicator.  You can set user option @code{kubed-list-mode-line-format}
+to customize this indicator.
+
+@menu
+* List Filter::
+@end menu
+
+@node List Filter
+@subsection Filtering Resource Lists
+
+In all Kubernetes resource list buffers, you can use @kbd{/}
+(@code{kubed-list-set-filter}) to @dfn{filter} the list of resources.
+This command sets the filter of the current buffer, which specifies
+conditions on resources (lines).  Resources that don't satisfy the
+conditions are hidden, so you can focus on those that do.
+
+Filters can be simple (@dfn{atomic filters}) or complex (@dfn{composed
+filters}).  In the simple case, you enter a filter in the minibuffer
+in the format @w{@samp{@var{op} @var{col} @var{val}}}, where @var{op}
+is a comparison operator, one of @samp{=}, @samp{~}, @samp{<} and
+@samp{>}; @var{col} is a column name; and @var{val} is a value to
+compare to values of @var{col} with @var{op}.
+
+If @var{op} is @samp{=}, it says to keep only lines whose @var{col}
+equals @var{val}.  If @var{op} is @samp{~}, it says to keep lines
+whose @var{col} matches the @var{val} as a regular expression.
+@samp{<} and @samp{>} compare column values to numeric values.  For
+example, the filter @samp{= Name foobar} keeps only resources whose
+name is @samp{foobar}.  To include whitespace in @var{val}, wrap
+@var{val} in double quotes: @samp{= Name "foo bar"}.
+
+The possible values of @var{op} and their meanings are defined in
+@code{kubed-list-filter-operator-alist}, which is a user option you
+can use to add or change the meaning of filter operators:
+
+@defopt kubed-list-filter-operator-alist
+Association list of filter operators and corresponding Emacs Lisp
+functions.  See the documentation string of this option for specifics.
+@end defopt
+
+You can use more refined filters by composing simple filters.  To add
+another filter that resources must satisfy, wrap your two filters in
+parentheses and put them next to each other:
+
+@lisp
+(= Name foobar) (~ Namespace kube)
+@end lisp
+
+@noindent
+This filter keeps only resources whose name is @samp{foobar} in
+namespaces that include @samp{kube} as a substring, it expresses the
+conjunction of the two simple filters.
+
+To negate a simple filter, put a single quote ahead of it, like so:
+
+@lisp
+(= Name foobar) '(~ Namespace kube)
+@end lisp
+
+@noindent
+This matches resources named @samp{foobar} in namespaces that do
+@emph{not} contain @samp{kube}.
+
+To specify a disjunction of simple filters (and negated simple
+filters), add another level of nesting:
+
+@lisp
+((= Name spam) (= Name foobar)) '(~ Namespace kube)
+@end lisp
+
+@noindent
+This filter matches resources named either @samp{spam} or
+@samp{foobar}, in namespaces that do not contain @samp{kube}.
+
+While entering a filter in the minibuffer, @kbd{@key{TAB}} completion
+is available for column names and values.  To clear the filter, just
+exit the minibuffer with an empty input.
+
+@node Context and Namespace
+@section Context and Namespace
+
+Kubed uses @command{kubectl} to interact with Kubernetes clusters, and
+you can use multiple @command{kubectl} @dfn{contexts} in Kubed to work
+with different Kubernetes clusters in parallel.  Within each context,
+Kubed lets you work in multiple @dfn{namespaces} too.  In general,
+each buffer has its own @dfn{local context} and @dfn{local namespace},
+and Kubed commands use these local context and namespace by default.
+This is similar to how different buffers have different values of
+@code{default-directory} (@pxref{File Names,,,emacs}), and how that
+affects commands that interact with the filesystem.
+
+For Kubed buffers that display a Kubernetes resource (@pxref{Display
+Resource}) or a list of resources (@pxref{Browse Resources}), the
+buffer-local context and namespace are the context and namespace of
+the resources the buffer displays.  For non-Kubed buffers, the user
+option @code{kubed-default-context-and-namespace} determines the
+default local context and namespace.
+
+@defopt kubed-default-context-and-namespace
+Default @command{kubectl} context and Kubernetes namespace for Kubed
+commands.  The value of this option is either a cons cell
+@w{@code{(@var{context} . @var{namespace})}} or @code{nil}.  If it is
+@code{nil}, Kubed initializes this option to a cons cell with the
+current @command{kubectl} context and namespace for that context on
+the first time Kubed consults this option.
+@end defopt
+
+As mentioned above, most Kubed commands use the local context and
+namespace by default---it is also conventional for Kubed commands to
+let you choose a different namespace if you invoke them with a prefix
+argument (@kbd{C-u}), and to also let you choose a different context
+if you invoke them with a double prefix argument (@kbd{C-u C-u}).
+
+The following functions return the local context and namespace for
+buffer in which you call them:
+
+@defun kubed-local-context
+Return the local @command{kubectl} context for the current buffer.
+@end defun
+
+@defun kubed-local-namespace
+Return the local Kubernetes namespace for the current buffer.
+@end defun
+
+@defun kubed-local-context-and-namespace
+Return the local context and namespace for the current buffer as a
+cons cell @w{@code{(@var{context} . @var{namespace})}}.
+@end defun
+
+@node Transient Menus
+@section Transient Menus
+
+Kubed provides a set of keyboard-driven @dfn{transient menus}
+(@pxref{Top,,,transient}) that you can use to explore and invoke
+various commands.  Transient menus show you available commands along
+with their key bindings, which helps you use many different commands
+without the need to remember the key bindings for all them.
+Additionally, the transient menus allow you to specify options and
+switches for the commands you invoke, which may not be available when
+invoking these commands directly.  For example, while you can invoke
+command @code{kubed-logs} directly to view logs from a container
+running in Kubernetes, the ``Kubernetes Logs'' transient menu which
+you open with @code{kubed-transient-logs} lets you set a maximum
+number of logs to retrieve, among other knobs and handles.
+
+@float
+
+@ifset split
+@image{../../assets/kubed-transient,,,Image: The Kubed main transient menu,.png}
+@end ifset
+@ifclear split
+@image{assets/kubed-transient,,,Image: The Kubed main transient menu,.png}
+@end ifclear
+
+@ifset split
+@image{../../assets/kubed-transient-exec,,,Image: The Kubed Exec transient menu,.png}
+@end ifset
+@ifclear split
+@image{assets/kubed-transient-exec,,,Image: The Kubed Exec transient menu,.png}
+@end ifclear
+
+@caption{Explore Kubed commands with transient menus}
+@end float
+
+Command @code{kubed-transient} opens the Kubed ``root'' transient
+menu, which is a dispatch that lets you access different transient
+menus, such as the aforementioned ``Kubernetes Logs'' transient menu.
+It's a good idea to bind @code{kubed-transient} to a convenient key,
+either in the global keymap or under @code{kubed-prefix-map}:
+
+@lisp
+(keymap-global-set "s-k" #'kubed-transient)
+(keymap-set kubed-prefix-map "k" #'kubed-transient)
+@end lisp
+
+In Kubed resource list buffers, type @kbd{?} to pop up a transient
+menu with commands that are specific to the type of resources the
+buffer displays.  @xref{Browse Resources}.
+
+@node Scale Deployment
+@section Scale Deployment
+
+You can use Kubed to @dfn{scale} Kubernetes a deployment, which means
+setting the size of the deployment in terms of the number of replicas
+it governs.
+
+@deffn Command kubed-scale-deployment
+Scale a Kubernetes deployment.
+@end deffn
+
+@code{kubed-scale-deployment} is bound to @kbd{$} in the
+@code{kubed-deployment-prefix-map}, so if you have
+@code{kubed-prefix-map} bound to @kbd{C-c k} then you can invoke it
+with @kbd{C-c k d $}.  @xref{Definition of kubed-prefix-map}.  This
+command prompts you for a deployment and then lets you select a new
+number of replicas for that deployment.  By default you are prompted
+for deployment in the local context and namespace (@pxref{Context and
+Namespace}); with a prefix argument, you can specify a different
+namespace; with a double prefix argument (@kbd{C-u C-u}), you can
+specify a different context too.
+
+In the deployments list buffer, you can scale the deployment at point
+by simply typing @kbd{$}.  @xref{Browse Resources}.
+
+@float
+@ifset split
+@image{../../assets/kubed-scale-deployments,,,Image: Help transient menu in Kubed deployments list buffer,.png}
+@end ifset
+@ifclear split
+@image{assets/kubed-scale-deployments,,,Image: Help transient menu in Kubed deployments list buffer,.png}
+@end ifclear
+@caption{Scale deployments with @kbd{$} in the deployments list buffer}
+@end float
+
+Lastly, you can scale deployments using the transient menu
+@code{kubed-transient-scale-deployment}, which is available from the
+main Kubed transient by pressing @kbd{$}.  @xref{Transient Menus}.
+
+@node Extending Kubed
+@chapter Extending Kubed
+
+Kubed has built-in support for many common types of Kubernetes
+resources.  ``Support'' for a resource type in Kubed just means
+providing common commands for working with resources of that type,
+such as a command for showing the interactive list of these resources,
+like @code{kubed-list-pods} for Kubernetes pods.  In Kubed, the macro
+@code{kubed-define-resource} is used to define these common commands
+and add support for more resource types:
+
+@deffn Macro kubed-define-resource resource &optional properties &rest [ keyword argument ]@dots{} commands
+Define commands for @var{resource}.
+@end deffn
+
+Say you want to add support for your Kubernetes service accounts.
+With @code{kubed-define-resource}, all you need to do is to add the
+following line to your Emacs initialization file:
+
+@lisp
+(kubed-define-resource serviceaccount)
+@end lisp
+
+This line defines the following commands for you:
+
+@itemize
+@item
+@code{kubed-display-serviceaccount}
+@item
+@code{kubed-list-serviceaccounts}
+@item
+@code{kubed-edit-serviceaccount}
+@item
+@code{kubed-delete-serviceaccount}
+@item
+@code{kubed-create-serviceaccount}
+@item
+@code{kubed-explain-serviceaccounts}
+@end itemize
+
+See the documentation string of @code{kubed-define-resource}
+(@w{@kbd{C-h f}}) for details about the optional arguments of this
+macro: the @var{properties} argument which lets you specify what Kubed
+should show in the resource list buffer and the @code{commands} argument
+which lets you associate additional commands with your resource type.
+
+@node Contributing
+@chapter Contributing
+
+We highly appreciate all contributions, including bug reports,
+patches, improvement suggestions, and general feedback!
+
+The best way to get in touch with the Kubed maintainers is via
+@uref{https://lists.sr.ht/~eshel/kubed-devel, the Kubed mailing list}.
+
+@deffn Command kubed-submit-bug-report
+Report a bug in Kubed to the maintainers via mail.
+@end deffn
+
+You can use the command @kbd{M-x kubed-submit-bug-report} to easily
+contact the Kubed maintainers from within Emacs.  This command opens a
+new buffer with a message template ready to be sent to the development
+mailing list.
+
+@node Indices
+@unnumbered Indices
+
+@menu
+* Function Index::
+* Variable Index::
+* Keystroke Index::
+* Concept Index::
+@end menu
+
+@node Function Index
+@unnumberedsec Function index
+
+@printindex fn
+
+@node Variable Index
+@unnumberedsec Variable index
+
+@printindex vr
+
+@node Keystroke Index
+@unnumberedsec Keystroke index
+
+@printindex ky
+
+@node Concept Index
+@unnumberedsec Concept index
+
+@printindex cp
+
+@bye