dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

commit 9834552cb29958c7b3d0d7e74d5ce71ed197b2ce
parent a9df54930de3f5056bb96ac7183ee9f80d06bb49
Author: Lukas Henkel <lh@entf.net>
Date:   Fri, 22 Apr 2022 21:06:42 +0200

Add jq-mode

Diffstat:
Aelpa/jq-mode-0.5.0/jq-mode-autoloads.el | 44++++++++++++++++++++++++++++++++++++++++++++
Aelpa/jq-mode-0.5.0/jq-mode-pkg.el | 10++++++++++
Aelpa/jq-mode-0.5.0/jq-mode.el | 321+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/jq-mode-0.5.0/ob-jq.el | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minit.el | 5++++-
5 files changed, 534 insertions(+), 1 deletion(-)

diff --git a/elpa/jq-mode-0.5.0/jq-mode-autoloads.el b/elpa/jq-mode-0.5.0/jq-mode-autoloads.el @@ -0,0 +1,44 @@ +;;; jq-mode-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*- +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "jq-mode" "jq-mode.el" (0 0 0 0)) +;;; Generated autoloads from jq-mode.el + +(autoload 'jq-mode "jq-mode" "\ +Major mode for jq scripts. +\\{jq-mode-map} + +\(fn)" t nil) + +(autoload 'jq-interactively "jq-mode" "\ +Runs jq interactively on a json buffer. + +\(fn BEG END)" t nil) + +(register-definition-prefixes "jq-mode" '("jq-")) + +;;;*** + +;;;### (autoloads nil "ob-jq" "ob-jq.el" (0 0 0 0)) +;;; Generated autoloads from ob-jq.el + +(register-definition-prefixes "ob-jq" '("org-babel-")) + +;;;*** + +;;;### (autoloads nil nil ("jq-mode-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8-emacs-unix +;; End: +;;; jq-mode-autoloads.el ends here diff --git a/elpa/jq-mode-0.5.0/jq-mode-pkg.el b/elpa/jq-mode-0.5.0/jq-mode-pkg.el @@ -0,0 +1,10 @@ +(define-package "jq-mode" "0.5.0" "Edit jq scripts." + '((emacs "25.1")) + :commit "3bda2d1085d5ac28fc6e7e8093ca7e74d3719f56" :authors + '(("Bjarte Johansen <Bjarte dot Johansen at gmail dot com>")) + :maintainer + '("Bjarte Johansen <Bjarte dot Johansen at gmail dot com>") + :url "https://github.com/ljos/jq-mode") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/jq-mode-0.5.0/jq-mode.el b/elpa/jq-mode-0.5.0/jq-mode.el @@ -0,0 +1,321 @@ +;;; jq-mode.el --- Edit jq scripts. -*- lexical-binding: t; -*- + +;; Copyright (C) 2015--2018 Bjarte Johansen + +;; Author: Bjarte Johansen <Bjarte dot Johansen at gmail dot com> +;; Homepage: https://github.com/ljos/jq-mode +;; Package-Requires: ((emacs "25.1")) +;; Version: 0.4.1 + +;; This file is not part of GNU Emacs. + +;; 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 jq-mode. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Mode for editing jq queries. + +;;; Usage: + +;; Add to your Emacs config: + +;; (add-to-list 'load-path "/path/to/jq-mode-dir") +;; (autoload 'jq-mode "jq-mode.el" +;; "Major mode for editing jq files" t) +;; (add-to-list 'auto-mode-alist '("\\.jq\\'" . jq-mode)) + +;;; Code: +(defgroup jq nil + "Major mode for editing jq queries." + :group 'languages) + +(defcustom jq-indent-offset 2 + "*Indentation offset for `jq-mode'." + :group 'jq + :type 'integer) + +(defconst jq--keywords + '("as" + "break" + "catch" + "def" + "elif" "else" "end" + "foreach" + "if" "import" "include" + "label" + "module" + "reduce" + "then" "try") + "The keywords used in jq.") + +(defun jq-indent-line () + "Indent current line as a jq-script." + (interactive) + (let ((indent-column 0)) + (save-mark-and-excursion + (if (> 0 (forward-line -1)) + (setq indent-column (current-indentation)) + (end-of-line) + (or (search-backward ";" (line-beginning-position) t) + (back-to-indentation)) + (skip-chars-forward "[:space:]" (line-end-position)) + (cond ((looking-at-p "#.*$") + (setq indent-column (current-indentation))) + ((looking-at-p + (concat (regexp-opt (remove "end" jq--keywords)) "\\b")) + (setq indent-column (+ indent-column jq-indent-offset)))))) + (save-mark-and-excursion + (back-to-indentation) + (save-mark-and-excursion + (let ((extra (if (looking-at-p ")\\|}\\|\\]") 0 1))) + (ignore-errors + (up-list -1) + (when (looking-at-p "(\\|{\\|\\[") + (setq indent-column (+ extra (current-column))))))) + (when (looking-at-p "|") + (setq indent-column (+ indent-column jq-indent-offset))) + (end-of-line) + (delete-horizontal-space) + (indent-line-to indent-column))) + (when (let ((search-spaces-regexp t)) + (string-match-p "^ *$" + (buffer-substring-no-properties + (line-beginning-position) + (point)))) + (skip-chars-forward "[:space:]" (line-end-position)))) + +(defconst jq--builtins + '("IN" "INDEX" + "JOIN" + "acos" "acosh" "add" "all" "any" "arrays" "ascii_downcase" "ascii_upcase" + "asin" "asinh" "atan" "atan2" "atanh" + "booleans" "bsearch" "builtins" + "capture" "cbrt" "ceil" "combinations" "contains" "copysign" "cos" "cosh" + "debug" "del" "delpaths" "drem" + "empty" "endswith" "env" "erf" "erfc" "error" "exp" "exp10" "exp2" + "explode" "expm1" + "fabs" "fdim" "finites" "first" "flatten" "floor" "fma" "fmax" "fmin" + "fmod" "format" "frexp" "from_entries" "fromdate" "fromdateiso8601" + "fromjson" "fromstream" + "gamma" "get_jq_origin" "get_prog_origin" "get_search_list" "getpath" + "gmtime" "group_by" "gsub" + "halt" "halt_error" "has" "hypot" + "implode" "in" "index" "indices" "infinite" "input" "input_filename" + "input_line_number" "inputs" "inside" "isempty" "isfinite" "isinfinite" + "isnan" "isnormal" "iterables" + "j0" "j1" "jn" "join" + "keys" "keys_unsorted" + "last" "ldexp" "leaf_paths" "length" "lgamma" "lgamma_r" "limit" + "localtime" "log" "log10" "log1p" "log2" "logb" "ltrimstr" + "map" "map_values" "match" "max" "max_by" "min" "min_by" "mktime" "modf" + "modulemeta" + "nan" "nearbyint" "nextafter" "nexttoward" "normals" "not" "now" "nth" + "nulls" "numbers" + "objects" + "path" "paths" "pow" "pow10" + "range" "recurse" "recurse_down" "remainder" "repeat" "reverse" "rindex" + "rint" "round" "rtrimstr" + "scalars" "scalars_or_empty" "scalb" "scalbln" "scan" "select" "setpath" + "significand" "sin" "sinh" "sort" "sort_by" "split" "splits" "sqrt" + "startswith" "stderr" "strflocaltime" "strftime" "strings" "strptime" "sub" + "tan" "tanh" "test" "tgamma" "to_entries" "todate" "todateiso8601" "tojson" + "tonumber" "tostream" "tostring" "transpose" "trunc" "truncate_stream" + "type" + "unique" "unique_by" "until" "utf8bytelength" + "values" + "walk" "while" "with_entries" + "y0" "y1" "yn") + "All builtin functions in jq.") + + +(defconst jq--escapings + '("text" "json" "html" "uri" "csv" "tsv" "sh" "base64") + "Jq escaping directives.") + +(defconst jq-font-lock-keywords + `( ;; Variables + ("\\$\\w+" 0 font-lock-variable-name-face) + ;; Format strings and escaping + (,(concat "@" (regexp-opt jq--escapings) "\\b") . font-lock-type-face) + ;; Keywords + ,(concat "\\b" (regexp-opt jq--keywords) "\\b") + ;; Functions + ("\\bdef\\s-*\\([_[:alnum:]]+\\)\\s-*\(" (1 font-lock-function-name-face)))) + +(defvar jq-mode-map + (let ((map (make-sparse-keymap))) + map) + "Keymap for `jq-mode'.") + +(defvar jq-mode-syntax-table + (let ((syntax-table (make-syntax-table))) + ;; Strings + (modify-syntax-entry ?\" "\"\"" syntax-table) + + ;; Comments + (modify-syntax-entry ?# "<" syntax-table) + (modify-syntax-entry ?\n ">" syntax-table) + syntax-table) + "Syntax table for `jq-mode.'") + +(defun jq-completion-at-point () + (when-let ((bnds (bounds-of-thing-at-point 'symbol))) + (unless (eq ?$ (char-before (car bnds))) ; Ignore variables + (list (car bnds) (cdr bnds) jq--builtins)))) + +(defvar company-keywords-alist) +(with-eval-after-load 'company-keywords + (add-to-list 'company-keywords-alist + `(jq-mode . ,(append jq--keywords + jq--builtins)))) + +;;;###autoload +(define-derived-mode jq-mode prog-mode "jq" + "Major mode for jq scripts. +\\{jq-mode-map}" + :group 'jq + (setq-local indent-line-function #'jq-indent-line) + (setq-local font-lock-defaults '(jq-font-lock-keywords)) + (setq-local comment-start "# ") + (add-hook 'completion-at-point-functions #'jq-completion-at-point nil t)) + +;;; jq-interactively +(defgroup jq-interactive nil + "Major mode for editing json with jq." + :group 'languages) + +(defcustom jq-interactive-command "jq" + "Command to use for calling jq." + :group 'jq-interactive + :type 'string) + +(defcustom jq-interactive-default-options "" + "Command line options to pass to jq." + :group 'jq-interactive + :type 'string) + +(defcustom jq-interactive-default-prompt "jq: " + "Default prompt to use in minibuffer." + :group 'jq-interactive + :type 'string) + +(defvar jq-interactive-history nil) + +(defvar jq-interactive--last-minibuffer-contents "") +(defvar jq-interactive--positions nil) +(defvar jq-interactive--buffer nil) +(defvar jq-interactive--overlay nil) + +(defun jq-interactive--run-command () + (with-temp-buffer + (let ((output (current-buffer))) + (with-current-buffer jq-interactive--buffer + (call-process-region + (point-min) + (point-max) + shell-file-name + nil + output + nil + shell-command-switch + (format "%s %s %s" + jq-interactive-command + jq-interactive-default-options + (shell-quote-argument + jq-interactive--last-minibuffer-contents)))) + (ignore-errors + (json-mode) + (font-lock-fontify-region (point-min) (point-max))) + (buffer-string)))) + +(defun jq-interactive--feedback () + (save-mark-and-excursion + (let ((font-lock-defaults '(jq-font-lock-keywords))) + (font-lock-fontify-region (point) (point-max)))) + (with-current-buffer jq-interactive--buffer + (overlay-put jq-interactive--overlay + 'after-string + (jq-interactive--run-command)))) + +(defun jq-interactive--minibuffer-setup () + (setq-local font-lock-defaults '(jq-font-lock-keywords))) + +(defun jq-interactive--quit () + (remove-hook 'after-change-functions #'jq-interactive--update) + (remove-hook 'minibuffer-setup-hook #'jq-interactive--minibuffer-setup) + (delete-overlay jq-interactive--overlay)) + +(defun jq-interactive--update (_beg _end _len) + (unless (> (minibuffer-depth) 1) + (let ((contents (minibuffer-contents-no-properties))) + (unless (or (not (minibufferp)) + (and (string= "" contents) + (equal last-command 'previous-history-element)) + (string= contents jq-interactive--last-minibuffer-contents)) + (setq jq-interactive--last-minibuffer-contents contents) + (jq-interactive--feedback))))) + +(defun jq-interactive-indent-line () + "Indents a jq expression in the jq-interactive mini-buffer." + (interactive) + (jq-indent-line) + (save-mark-and-excursion + (beginning-of-line) + (insert-char ?\s (length jq-interactive-default-prompt))) + (skip-chars-forward "[:space:]")) + +(defvar jq-interactive-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map minibuffer-local-map) + (define-key map (kbd "<tab>") #'jq-interactive-indent-line) + (define-key map (kbd "C-j") #'electric-newline-and-maybe-indent) + map) + "Keymap for `jq-interactively'.") + +;;;###autoload +(defun jq-interactively (beg end) + "Runs jq interactively on a json buffer." + (interactive + (if (region-active-p) + (list (region-beginning) + (region-end)) + (list (point-min) + (point-max)))) + (unwind-protect + (progn + (setq jq-interactive--overlay (make-overlay beg end)) + (overlay-put jq-interactive--overlay 'invisible t) + (setq jq-interactive--positions (cons beg end)) + (setq jq-interactive--buffer (current-buffer)) + (setq jq-interactive--last-minibuffer-contents "") + (jq-interactive--feedback) + (add-hook 'after-change-functions #'jq-interactive--update) + (add-hook 'minibuffer-setup-hook #'jq-interactive--minibuffer-setup) + (save-mark-and-excursion + (deactivate-mark) + (read-from-minibuffer + jq-interactive-default-prompt + nil + jq-interactive-map + nil + jq-interactive-history)) + (goto-char beg) + (delete-region beg end) + (insert (plist-get (overlay-properties jq-interactive--overlay) + 'after-string))) + (jq-interactive--quit))) + +(provide 'jq-mode) + +;;; jq-mode.el ends here diff --git a/elpa/jq-mode-0.5.0/ob-jq.el b/elpa/jq-mode-0.5.0/ob-jq.el @@ -0,0 +1,155 @@ +;;; ob-jq.el --- org-babel functions for jq scripts -*- lexical-binding: t; -*- + +;; Copyright (C) 2015 Bjarte Johansen + +;; Author: Bjarte Johansen +;; Keywords: literate programming, reproducible research +;; Homepage: http://www.github.com/ljos/jq-mode +;; Version: 0.1.0 + +;;; License: + +;; 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, 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 jq-mode. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Provides a way to evaluate jq scripts in org-mode. + +;;; Usage: + +;; Add to your Emacs config: + +;; (org-babel-do-load-languages +;; 'org-babel-load-languages +;; '((jq . t))) + +;;; Code: +(require 'ob) +(require 'jq-mode) +(require 'json) + +(defvar org-babel-jq-command "jq" + "Name of the jq executable command.") + +(defvar org-babel-tangle-lang-exts) +(add-to-list 'org-babel-tangle-lang-exts '("jq" . "jq")) + +(defconst org-babel-header-args:jq + '( + (:in-file . :any) + (:cmd-line . :any) + (:compact . ((yes no))) + ) + "Jq specific header arguments.") + +(defvar org-babel-default-header-args:jq '( + (:results . "output") + (:compact . "no") + ) + "Default arguments for evaluating a jq source block.") + +(defun org-babel-jq-table-to-json (data) + "Convert org table to JSON. + +First line specifies the keys." + (let* ((header (car data)) + (data (cdr data))) + (while (eq (car data) 'hline) + (setq data (cdr data))) + (json-encode + (mapcar + (lambda (row) (cl-mapcar 'cons header row)) + data)))) + +(defun org-babel-jq-args (params) + "Return an --arg argument for each PARAMS :var" + (let ((vars (org-babel--get-vars params))) + (and vars + (mapconcat + (lambda (var) + (format "--arg %s %S" (car var) (cdr var))) + vars + " ")))) + +(defun org-babel-execute:jq (body params) + "Execute a block of jq code with org-babel. This function is +called by `org-babel-execute-src-block'" + (message "executing jq source code block") + (let* ((result-params (cdr (assq :result-params params))) + (compact (equal "yes" (cdr (assq :compact params)))) + (cmd-line (cdr (assq :cmd-line params))) + (vars (org-babel-jq-args params)) + (in-file (cdr (assq :in-file params))) + (code-file (let ((file (org-babel-temp-file "jq-"))) + (with-temp-file file + (insert body) + file))) + (stdin (let ((stdin (cdr (assq :stdin params)))) + (when stdin + (let ((tmp (org-babel-temp-file "jq-stdin-")) + (res (org-babel-ref-resolve stdin))) + (with-temp-file tmp + (insert + (cond + ((listp res) (org-babel-jq-table-to-json res)) + (t res))) + tmp))))) + (cmd (mapconcat #'identity + (remq nil + (list org-babel-jq-command + (format "--from-file \"%s\"" code-file) + (when compact "--compact-output") + cmd-line + vars + in-file)) + " "))) + (org-babel-reassemble-table + (let ((results + (cond + (stdin (with-temp-buffer + (call-process-shell-command cmd stdin (current-buffer)) + (buffer-string))) + (t (org-babel-eval cmd ""))))) + (when results + (org-babel-result-cond result-params + results + (let ((data (json-read-from-string results))) + ;; If we have an array we might have a table + (if (and (vectorp data) + (> (length data) 0)) + (cond + ;; If the first element is a vector then just "unpack" + ;; the vector of vectors + ((vectorp (aref data 0)) + (mapcar (lambda (row) (append row nil)) data)) + ;; If the first element is a list we will assume we + ;; have an array of objects, so generate the colnames + ;; accordingly + ((consp (aref data 0)) + (let ((colnames (mapcar 'car (aref data 0)))) + (unless (assq :colnames params) + (push `(:colnames . ,colnames) params)) + (mapcar (lambda (row) (mapcar 'cdr row)) data))) + ;; For a vector of scalars just return it as an + ;; array, it will make a single-row table + (t (list (append data nil)))) + ;; If we have an object then just output it as string + results))))) + (org-babel-pick-name (cdr (assq :colname-names params)) + (cdr (assq :colnames params))) + (org-babel-pick-name (cdr (assq :rowname-names params)) + (cdr (assq :rownames params)))))) + +(provide 'ob-jq) +;;; ob-jq.el ends here diff --git a/init.el b/init.el @@ -147,6 +147,9 @@ (lh/define-keys elfeed-search-mode-map (("G" . elfeed-update)) elfeed) +(lh/define-keys json-mode-map + (("C-c C-j" . jq-interactively)) + json-mode) (defun corfu-insert-with-return () (interactive) @@ -232,7 +235,7 @@ ("melpa-stable" . "https://stable.melpa.org/packages/") ("melpa" . "https://melpa.org/packages/"))) '(package-selected-packages - '(multiple-cursors ob-restclient restclient vterm deadgrep helpful pdf-tools paredit-menu paredit corfu sly eglot aggressive-indent project nov nhexl-mode elfeed magit yaml-mode json-mode lua-mode go-mode geiser-guile geiser org-roam org-contrib org ace-window expand-region consult marginalia uuidgen request diminish which-key)) + '(jq-mode multiple-cursors ob-restclient restclient vterm deadgrep helpful pdf-tools paredit-menu paredit corfu sly eglot aggressive-indent project nov nhexl-mode elfeed magit yaml-mode json-mode lua-mode go-mode geiser-guile geiser org-roam org-contrib org ace-window expand-region consult marginalia uuidgen request diminish which-key)) '(pcomplete-ignore-case t t) '(pixel-scroll-precision-mode t) '(read-buffer-completion-ignore-case t)