README.org
June 30, 2025 ยท View on GitHub
-
What is it? =jq-mode= is an emacs major mode for editing [[https://github.com/stedolan/jq][jq]]-scripts.
-
Getting started [[https://melpa.org/#/jq-mode][file:https://melpa.org/packages/jq-mode-badge.svg]] [[https://stable.melpa.org/#/jq-mode][file:https://stable.melpa.org/packages/jq-mode-badge.svg]]
- Download jq-mode.el and put it in a directory somewhere.
- Add the following to your .emacs file
#+BEGIN_SRC emacs-lisp (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)) #+END_SRC
Now jq-mode will load whenever you visit a file whose name ends with .jq. Alternatively, run =M-x jq-mode= in an existing buffer containing jq commands.
-
Interactive mode =jq-mode= can also be used interactively in a JSON buffer. If you add the following to your .emacs file
#+BEGIN_SRC emacs-lisp (with-eval-after-load "json-mode" (define-key json-mode-map (kbd "C-c C-j") #'jq-interactively)) #+END_SRC
or you can call =M-x jq-interactively=. =jq-interactively= runs the expression that is written in the minibuffer iteratively over the JSON buffer. Press =C-g= to abort, =C-j= for newline, =RET= commits any changes.
** Use yq for yaml
It is possible to use [[https://github.com/kislyuk/yq][yq]] to process yaml with the interactive mode instead:
#+BEGIN_SRC emacs-lisp (setq jq-interactive-command "yq" jq-interactive-font-lock-mode #'yaml-mode jq-interactive-default-options "--yaml-roundtrip") #+END_SRC
-
Org babel
=jq-mode= provides =ob-jq= for working with literate programming in Org mode.
Add =jq= under =org-babel-load-languages= in your .emacs file
#+BEGIN_SRC emacs-lisp (org-babel-do-load-languages 'org-babel-load-languages '((jq . t))) #+END_SRC
** Why should I write jq expressions in org documents?
Writing =jq= expressions in org documents is a huge usability improvment over writing them on the command line.
- Being in a proper editor makes it easier to write multiline expressions.
- Iteration is very fast.
- Related =jq= expressions can be organized together into a [[https://en.wikipedia.org/wiki/Notebook_interface][computational notebook]].
- In contrast, command line =jq= expressions tend to be ephemeral.
** jq specific header arguments
=ob-jq= provides some additional header arguments:
- =:compact= :: Add =-c= to =jq= arguments list suppressing pretty printing
** Examples
*** Using ob-jq with a file as input
- =:in-file= is used to set the input filename. In this example [[https://pastebin.com/UKtNrGGt][apartments.json]] is used.
- =:cmd-line= can be used to pass =jq= extra command line parameters.
- =:wrap= can be used to wrap the result in another org block. In this example, it's a src block that contains JSON.
#+begin_src org ,#+begin_src jq :in-file apartments.json :cmd-line "-r" :wrap src json [ .[] | select(.addr_prefecture == "Aichi") ] | sort_by(.monthly_cost) | .[] | { link, monthly_cost } ,#+end_src
,#+RESULTS: ,#+begin_src json { "link": "https://realestate.co.jp/en/rent/view/1095206", "monthly_cost": 157200 } { "link": "https://realestate.co.jp/en/rent/view/1095222", "monthly_cost": 163200 } ,#+end_src #+end_src
*** Using ob-jq with JSON data from an inert block
- If you want to include the JSON in the org document, give it a =#+name:=.
- Then use =:stdin= to feed it into a jq src block like this.
#+begin_src org ,#+name: inert ,#+begin_example { "name": "gg" } ,#+end_example
,#+begin_src jq :stdin inert .name ,#+end_src
,#+RESULTS: : "gg" #+end_src
*** Using ob-jq with the output of another block
- It works just like passing in an inert block. Just give it a =#+name:= and pass it in via =:stdin=.
#+begin_src org ,#+name: btcusd ,#+begin_src sh :results output :wrap src json curl --silent 'https://www.bitstamp.net/api/v2/ohlc/btcusd/?start=1359936000&limit=3&step=60' ,#+end_src
,#+RESULTS: btcusd ,#+begin_src json {"data": {"pair": "BTC/USD", "ohlc": [{"timestamp": "1359936000", "open": "20.29", "high": "20.29", "low": "20.29", "close": "20.29", "volume": "0.00000000"}, {"timestamp": "1359936060", "open": "20.29", "high": "20.29", "low": "20.29", "close": "20.29", "volume": "0.00000000"}, {"timestamp": "1359936120", "open": "20.29", "high": "20.29", "low": "20.29", "close": "20.29", "volume": "0.00000000"}]}} ,#+end_src
,#+begin_src jq :stdin btcusd :wrap src json .data.ohlc | .[] | { close, timestamp: .timestamp | tonumber | strftime("%Y-%m-%dT%H:%M:%S") } ,#+end_src
,#+RESULTS: ,#+begin_src json { "close": "20.29", "timestamp": "2013-02-04T00:00:00" } { "close": "20.29", "timestamp": "2013-02-04T00:01:00" } { "close": "20.29", "timestamp": "2013-02-04T00:02:00" } ,#+end_src #+end_src
- Bugs and Enhancements If you have a problem or would like to see it get better in a specific way, feel free to drop an issue in [[https://github.com/ljos/jq-mode/issues][the issue tracker]]. Enjoy!