summaryrefslogtreecommitdiff
path: root/.config
diff options
context:
space:
mode:
Diffstat (limited to '.config')
-rw-r--r--.config/emacs/site-lisp/live-jq.el101
1 files changed, 101 insertions, 0 deletions
diff --git a/.config/emacs/site-lisp/live-jq.el b/.config/emacs/site-lisp/live-jq.el
new file mode 100644
index 0000000..f8a0a7f
--- /dev/null
+++ b/.config/emacs/site-lisp/live-jq.el
@@ -0,0 +1,101 @@
+;; TODO: ‘defcustom’ this
+(defvar live-jq-major-mode
+ (cond ((fboundp #'json-ts-mode) #'json-ts-mode)
+ ((fboundp #'json-mode) #'json-mode))
+ "TODO")
+
+(defvar live-jq--input-buffer nil
+ "The buffer containing the original JSON data.")
+
+(defvar live-jq--preview-buffer "*JQ Preview*"
+ "The buffer showing the live jq results.")
+
+(defvar live-jq--last-query "")
+
+(defun live-jq--get-json-input ()
+ "Return the contents of the input buffer as a string."
+ (with-current-buffer live-jq--input-buffer
+ (buffer-substring-no-properties (point-min) (point-max))))
+
+(defun live-jq--run-jq (query)
+ "Run jq QUERY on the input buffer's content and return result string or nil on error."
+ (let ((json-input (live-jq--get-json-input)))
+ (with-temp-buffer
+ (insert json-input)
+ (let ((exit-code (call-process-region
+ (point-min) (point-max)
+ "jq" :delete t nil "--tab" query)))
+ (when (zerop exit-code)
+ (buffer-string))))))
+
+(defun live-jq--render-jq-preview (query)
+ "Update preview buffer with the result or error of jq QUERY."
+ (let* ((preview-buffer (get-buffer-create live-jq--preview-buffer))
+ (json-input (live-jq--get-json-input))
+ (inhibit-read-only t))
+ (with-current-buffer preview-buffer
+ (erase-buffer)
+ (condition-case err
+ (with-temp-buffer
+ (insert json-input)
+ (let ((exit-code (call-process-region
+ (point-min) (point-max)
+ "jq" nil preview-buffer nil "--tab" query)))
+ (when (not (zerop exit-code))
+ (erase-buffer)
+ (insert "%s\n%s"
+ (propertize (format "jq error (exit %d): %s" exit-code query)
+ 'face 'error)
+ json-input))))
+ (error
+ (insert "%s\n%s"
+ (propertize (format "Error: %s" err) 'face 'error)
+ input-json)))
+ (goto-char (point-min))
+ (when live-jq-major-mode
+ (funcall live-jq-major-mode))))
+ (display-buffer live-jq--preview-buffer))
+
+(defun live-jq--minibuffer-update ()
+ "Update preview as user types."
+ (let ((query (minibuffer-contents)))
+ (unless (equal query live-jq--last-query)
+ (setq live-jq--last-query query)
+ (live-jq--render-jq-preview query))))
+
+;;;###autoload
+(defun live-jq ()
+ "Prompt for a jq query, show live results, and replace buffer on confirmation."
+ (interactive)
+ (unless (executable-find "jq")
+ (user-error "`jq' not found in PATH."))
+
+ (setq live-jq--input-buffer (current-buffer))
+ (setq live-jq--last-query "")
+
+ ;; Clean up preview buffer if user cancels with C-g
+ (let ((minibuffer-setup-hook
+ (list (lambda ()
+ ;; Add post-command-hook for live preview
+ (add-hook 'post-command-hook #'live-jq--minibuffer-update nil t)
+ ;; Add abort cleanup
+ (add-hook 'minibuffer-exit-hook
+ (lambda ()
+ (when (get-buffer live-jq--preview-buffer)
+ (kill-buffer live-jq--preview-buffer)))
+ nil t)))))
+ (let ((query (read-from-minibuffer (format-prompt "Query" nil))))
+ (unwind-protect
+ (let ((result (live-jq--run-jq query)))
+ (if result
+ (with-current-buffer live-jq--input-buffer
+ (let ((inhibit-read-only t))
+ (erase-buffer)
+ (insert result))
+ (message "jq applied."))
+ (user-error "Invalid jq query: see *jq-preview* for details")))
+ ;; Cleanup preview buffer after any outcome
+ (when (get-buffer live-jq--preview-buffer)
+ (kill-buffer live-jq--preview-buffer))))))
+
+(provide 'live-jq)