[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/plz-see bdcc265ce9 01/10: Initial commit
From: |
ELPA Syncer |
Subject: |
[elpa] externals/plz-see bdcc265ce9 01/10: Initial commit |
Date: |
Wed, 1 Nov 2023 18:58:45 -0400 (EDT) |
branch: externals/plz-see
commit bdcc265ce99601bdb411b2b00fb2d778429d7c3b
Author: Augusto Stoffel <arstoffel@gmail.com>
Commit: Augusto Stoffel <arstoffel@gmail.com>
Initial commit
---
plzi.el | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 240 insertions(+)
diff --git a/plzi.el b/plzi.el
new file mode 100644
index 0000000000..818a61ccc7
--- /dev/null
+++ b/plzi.el
@@ -0,0 +1,240 @@
+;;; plzi.el --- Interactive HTTP client -*- lexical-binding: t;
-*-
+
+;; Copyright (C) 2023 Augusto Stoffel
+
+;; Author: Augusto Stoffel <arstoffel@gmail.com>
+;; Keywords: comm, network, http
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'json)
+(require 'plz)
+
+;;; User options and variables
+
+(defgroup plzi nil
+ "Interactive HTTP client."
+ :group 'plz
+ :link '(url-link "https://github.com/astoff/plzi.el"))
+
+(defcustom plzi-base-url nil
+ "Prefix to add to the URL argument of `plzi', if relative.
+Here \"relative\" means, paradoxically, that the URL in question
+starts with '/'."
+ :local t
+ :type '(choice string (const :tag "None" nil))
+ :safe #'stringp)
+
+(defcustom plzi-base-headers nil
+ "List of headers to add to all requests.
+Entries of this alist are ignored if the same header is given
+explicitly in the HEADERS argument of `plzi'."
+ :local t
+ :type '(alist :key-type string :value-type string)
+ :safe #'listp)
+
+(defcustom plzi-keep-buffers 10
+ "How many response buffers to keep.
+If nil, never delete old response buffers."
+ :type '(choice natnum (const :tag "Keep all" nil)))
+
+(defcustom plzi-display-action nil
+ "The ACTION argument `plzi' passes to `display-buffer'."
+ :type 'sexp)
+
+(defcustom plzi-header-line-format
+ (let ((headers '(plzi-header-line-status
+ plzi-header-line-content-type
+ plzi-header-line-content-length
+ plzi-header-line-show-headers)))
+ (dolist (sym headers)
+ (put sym 'risky-local-variable t))
+ (cons "" headers))
+ "Header line format for plzi result buffers."
+ :type 'sexp)
+
+(defcustom plzi-headers-buffer nil
+ "Buffer used to display request headers.
+This can be nil to add the headers to the response buffer itself,
+or a buffer name to use a separate buffer."
+ :type 'sexp)
+
+(defface plzi-header '((t :inherit font-lock-comment-face))
+ "Face added by `plzi-insert-headers' to response headers.")
+
+(defcustom plzi-content-type-alist
+ `(("\\`text/html" . html-mode)
+ ("\\`\\(application\\|text\\)/xml" . xml-mode)
+ ("\\`application/xhtml\\+xml" . xml-mode)
+ ("\\`application/json" . ,(lambda ()
+ (json-pretty-print-buffer)
+ (js-json-mode)))
+ ("\\`application/javascript" . js-mode)
+ ("\\`application/css" . css-mode)
+ ("\\`text/plain" . text-mode)
+ ("\\`application/pdf" . doc-view-mode)
+ ("\\`image/" . image-mode))
+ "Alist mapping content types to rendering functions."
+ :type '(alist :key-type regexp
+ :value-type function))
+
+(defvar-local plzi-response nil
+ "Store the `plz-response' object in a plzi buffer.")
+
+(defvar plzi--buffers '(0 . nil)
+ "List of buffers generated by `plzi'.
+The car is the number of buffers created so far.")
+
+;;; Response buffer header line
+
+(defvar plzi-header-line-status
+ '(:eval
+ (setq-local plzi-header-line-status
+ (format "HTTP/%s %s"
+ (plz-response-version plzi-response)
+ (let ((status (plz-response-status plzi-response)))
+ (propertize (number-to-string status)
+ 'face (if (<= 200 status 299) 'success
'error)))))))
+
+(defvar plzi-header-line-content-type
+ '(:eval
+ (setq-local plzi-header-line-content-type
+ (format " | %s"
+ (alist-get 'content-type
+ (plz-response-headers plzi-response))))))
+
+(defvar plzi-header-line-content-length
+ '(:eval
+ (setq-local plzi-header-line-content-length
+ (format " | %s bytes"
+ (alist-get 'content-length
+ (plz-response-headers plzi-response))))))
+
+(defvar plzi-header-line-show-headers
+ '(:eval
+ (setq-local plzi-header-line-show
+ (format " | %s"
+ (buttonize "show headers"
+ (lambda (buffer)
+ (with-selected-window (get-buffer-window
buffer)
+ (plzi-insert-headers)))
+ (current-buffer))))))
+
+;;; Response buffer construction
+
+(defun plzi--prepare-buffer (response)
+ (let* ((buffer (generate-new-buffer
+ (format "*plzi-%s*" (cl-incf (car plzi--buffers)))))
+ (error (and (plz-error-p response) response))
+ (response (if error (plz-error-response error) response))
+ (headers (plz-response-headers response))
+ (mode (alist-get (alist-get 'content-type headers)
+ plzi-content-type-alist
+ nil nil #'string-match-p))
+ (body (plz-response-body response)))
+ (with-current-buffer buffer
+ (save-excursion
+ (insert body)
+ (when mode (funcall mode)))
+ (setq-local plzi-response response)
+ (setq header-line-format plzi-header-line-format)
+ (push buffer (cdr plzi--buffers))
+ (when-let ((oldbufs (and plzi-keep-buffers
+ (seq-drop (cdr plzi--buffers)
+ (1- plzi-keep-buffers)))))
+ (dolist (b (cdr oldbufs))
+ (kill-buffer b))
+ (setf (cdr oldbufs) nil))
+ buffer)))
+
+(defun plzi--continue (as continue)
+ (lambda (response)
+ (if-let ((curl-error (and (plz-error-p response)
+ (plz-error-curl-error response))))
+ (message "curl error %s: %s" (car curl-error) (cdr curl-error))
+ (let ((buffer (plzi--prepare-buffer response)))
+ (display-buffer buffer plzi-display-action)
+ (when continue
+ (funcall continue
+ (pcase-exhaustive as
+ ('response response)
+ ('buffer buffer)
+ ((or 'binary 'string 'file `(file ,_))
+ (user-error "plzi does not accept :as %s" as))
+ ((pred functionp)
+ (with-temp-buffer
+ (insert (plz-response-body response))
+ (goto-char (point-min))
+ (funcall as))))))))))
+
+;;; User commands
+
+(defun plzi-kill-old-buffers (n)
+ "Kill all but the N most recent plzi buffers.
+Interactively, N is the prefix argument."
+ (interactive "p")
+ (let ((buffers (seq-drop plzi--buffers n)))
+ (dolist (buffer (cdr buffers))
+ (kill-buffer buffer))
+ (setf (cdr buffers) nil)))
+
+(defun plzi-insert-headers ()
+ "Insert response headers into `plzi-headers-buffer'."
+ (interactive)
+ (let ((headers (plz-response-headers plzi-response))
+ (hbuffer (when plzi-headers-buffer
+ (get-buffer-create plzi-headers-buffer))))
+ (with-current-buffer (or hbuffer (current-buffer))
+ (let ((inhibit-read-only t))
+ (save-excursion
+ (goto-char (point-min))
+ (pcase-dolist (`(,k . ,v) headers)
+ (insert (format "%s: %s\n" k v)))
+ (insert ?\n)
+ (add-text-properties (point-min) (point)
+ '(face plzi-header
+ font-lock-face plzi-header
+ fontified t)))))
+ (if hbuffer
+ (display-buffer hbuffer)
+ (setq-local plzi-header-line-show-headers nil))))
+
+;;;###autoload
+(cl-defun plzi (method
+ url
+ &rest rest
+ &key headers then else as
+ &allow-other-keys)
+ (interactive `(get ,(read-from-minibuffer "Make GET request: ")))
+ (when (and plzi-base-url
+ (string-prefix-p "/" url))
+ (setq url (concat plzi-base-url url)))
+ (dolist (h plzi-base-headers)
+ (unless (assoc (car h) headers)
+ (push h headers)))
+ (apply #'plz method url
+ :headers headers
+ :as 'response
+ :then (plzi--continue as then)
+ :else (plzi--continue as else)
+ rest))
+
+(provide 'plzi)
+;;; plzi.el ends here
- [elpa] branch externals/plz-see created (now c55e6aa297), ELPA Syncer, 2023/11/01
- [elpa] externals/plz-see bdcc265ce9 01/10: Initial commit,
ELPA Syncer <=
- [elpa] externals/plz-see 0dc77f9f69 04/10: Add readme and docstrings, ELPA Syncer, 2023/11/01
- [elpa] externals/plz-see f0198fd494 05/10: Add screenshot, ELPA Syncer, 2023/11/01
- [elpa] externals/plz-see 08ab7e7923 08/10: Expand docstring, ELPA Syncer, 2023/11/01
- [elpa] externals/plz-see f82b7530bb 02/10: Handle missing content-type and content-length correctly, ELPA Syncer, 2023/11/01
- [elpa] externals/plz-see 4d788655b6 03/10: Rename package, ELPA Syncer, 2023/11/01
- [elpa] externals/plz-see c55e6aa297 10/10: Version 0.1, ELPA Syncer, 2023/11/01
- [elpa] externals/plz-see 9b45fb544f 06/10: Address comments from emacs-devel, ELPA Syncer, 2023/11/01
- [elpa] externals/plz-see 939c39fbf2 07/10: Add completion predicate for command, ELPA Syncer, 2023/11/01
- [elpa] externals/plz-see e144d38654 09/10: Don't make base URL and headers variables buffer-local by default, ELPA Syncer, 2023/11/01