--- /dev/null
+#+TITLE: Orientation in JSON documents with Emacs and Tree-sitter
+#+SUBTITLE: Adventures with the new Tree-sitter based Emacs mode for JSON
+#+DESCRIPTION: A post by Eshel Yaron about his adventures with the new Tree-sitter based Emacs mode for JSON
+#+KEYWORDS: emacs,lisp,treesitter
+#+DATE: 2023-05-17
+
+@@html:<div class="metadata">@@Created on [{{{date}}}], last updated [{{{modification-time(%Y-%m-%d, t)}}}]@@html:</div>@@
+
+I often find myself opening a large JSON document, usually a sample from a
+larger dataset I'm analyzing, in order to figure out where in that JSON some
+interesting fields are buried. In most cases, I have some idea of what these
+fields should contain, so I can locate them quite easily by searching with
+Emacs's [[note:isearch][Isearch]] for some string that I expect to find there.
+
+If I end up somewhere in the middle of a large JSON document, the challenge then
+becomes determining the path from the root of the document to the position of my
+cursor. [[note:emacs][Emacs]] has a built-in function ~json-path-to-position~ in =json.el= that
+parses the buffer as a JSON document and returns the path to a given position,
+but since I've recently started using the new Tree-sitter based JSON major mode
+~json-ts-mode~, I figured it'd be a nice exercise to implement a
+~json-path-at-point~ command that leverages Tree-sitter's knowledge of the
+buffer's parse tree, and doesn't require =json.el=.
+
+There it is, I give you ~esy/json-path-at-point~:
+
+#+begin_src emacs-lisp
+ (defun esy/json-path-to-position (pos)
+ "Return the JSON path from the document's root to the element at POS.
+
+ The path is represented as a list of strings and integers,
+ corresponding to the object keys and array indices that lead from
+ the root to the element at POS."
+ (named-let loop ((node (treesit-node-at pos)) (acc nil))
+ (if-let ((parent (treesit-parent-until
+ node
+ (lambda (n)
+ (member (treesit-node-type n)
+ '("pair" "array"))))))
+ (loop parent
+ (cons
+ (pcase (treesit-node-type parent)
+ ("pair"
+ (treesit-node-text
+ (treesit-node-child (treesit-node-child parent 0) 1) t))
+ ("array"
+ (named-let check ((i 1))
+ (if (< pos (treesit-node-end (treesit-node-child parent i)))
+ (/ (1- i) 2)
+ (check (+ i 2))))))
+ acc))
+ acc)))
+
+ (defun esy/json-path-at-point (point &optional kill)
+ "Display the JSON path at POINT. When KILL is non-nil, kill it too.
+
+ Interactively, POINT is point and KILL is the prefix argument."
+ (interactive "d\nP" json-ts-mode)
+ (let ((path (mapconcat (lambda (o) (format "%s" o))
+ (esy/json-path-to-position point)
+ ".")))
+ (if kill
+ (progn (kill-new path) (message "Copied: %s" path))
+ (message path))
+ path))
+#+end_src
+
+As an example of its usage, consider the following JSON:
+
+#+begin_src json-ts
+ {
+ "foo" : [
+ {
+ "bar" : "baz"
+ },
+ {
+ "one" : "two"
+ }
+ ]
+ }
+#+end_src
+
+With point on "baz", typing ~M-x esy/json-path-at-point~ displays ~foo.0.bar~ in
+the echo area. With a prefix argument (~C-u~), it copies the path to the kill
+ring as well so I can, for instance, later copy it into some script I'm writing.
--- /dev/null
+#+TITLE: Extending Emacs's Dictionary Library
+#+SUBTITLE: Introducing new customization options in the Emacs package dictionary.el
+#+DESCRIPTION: A post from Eshel Yaron introducing new customization options in the Emacs package dictionary.el
+#+KEYWORDS: emacs,lisp,dictionary
+#+DATE: 2023-05-26
+
+@@html:<div class="metadata">@@Created on [{{{date}}}], last updated [{{{modification-time(%Y-%m-%d, t)}}}]@@html:</div>@@
+
+Yesterday [2023-05-26] [[note:eli-zaretskii][Eli Zaretskii]] applied a patch that I've submitted to the
+Emacs =master= branch which introduces new customization options to Emacs's
+=dictionary.el= library.
+
+=dictionary.el= is a library that lets Emacs query [[https://www.rfc-editor.org/rfc/rfc2229.html][RFC2229]] dictionary servers
+for word definitions, and display these definitions to the user upon request.
+This package was initially written by [[note:torsten-hilbrich][Torsten Hilbrich]] to support both [[note:emacs][GNU Emacs]]
+and XEmacs, and was added as a library to Emacs core in version 28.
+
+I've started using =dictionary.el= slightly over a month ago after reading
+[[note:bozhidar-batsov][Bozhidar Batsov]]'s post [[https://emacsredux.com/blog/2023/04/11/looking-up-words-in-a-dictionary/][Looking Up Words in a Dictionary]]. Beforehand, I've been
+using the ~define-word~ package by [[note:oleh-krehel][Oleh Krehel]] which achieves a similar goal of
+obtaining and displaying word definitions, but instead of querying RFC2229
+dictionary servers like =dictionary.el= does, ~define-word~ performs HTTP
+requests to web-based dictionary services and parses their HTML responses.
+~define-word~ served me pretty well, but since =dictionary.el= is built into
+Emacs I thought I'd give it a try. Another notable difference between these
+packages is that ~define-word~ displays word definitions as transient messages
+in the echo area, while =dictionary.el= pops up a dedicated =*Dictionary*=
+buffer.
+
+My first impression of =dictionary.el= was quite positive. I consult the
+dictionary quite often, and I liked how =dictionary.el= puts the definition in a
+buffer that stays visible while I write rather than a message that disappears on
+my first keystroke. But then there were also some quirks. First, I found that
+whenever =dictionary.el= displays a definition in the =*Dictionary*= buffer, it
+also selects that buffer. That's inconvenient when I'm in the middle of writing
+a sentence and just want to quickly glance at a word's definition to make sure
+I'm using it correctly. This is similar in nature to consulting a function's
+definition or docstring when writing code, it should be a frictionless process.
+Having to switch windows from the =*Dictionary*= buffer back to whatever buffer
+I was in the middle of editing means unnecessary friction, especially if I have
+multiple open windows to navigate between.
+
+I can imagine that at this point you're thinking "well, this is Emacs after all,
+can't you customize it not to switch buffers or something?", and no, I couldn't
+really. But now you can. More on that later though, for now let me rant just a
+bit longer.
+
+The other problem I came across when trying to adopt =dictionary.el= was its
+"cool" feature of restoring the window configuration you had while searching the
+dictionary when you quit the =*Dictionary*= buffer. The way this works is that
+=dictionary.el= saves the current window configuration when creating the
+=*Dictionary*= buffer, and binds ~q~ to the command ~dictionary-close~ which,
+among other things, tries to restore the saved window configuration. This is,
+in my view, plain harmful. I can understand the idea behind it --
+=dictionary.el= wants to let you quit the =*Dictionary*= buffer, so it needs to
+do something with the window it inhabits. It doesn't want to make an arbitrary
+decision for the user so it takes the seemingly safe choice of reverting to how
+things were when the buffer was created. The intention is admirable, but the
+implementation is unfortunately shortsighted. The problem is that a lot of time
+can pass between the moment you perform a dictionary search and the moment you
+quit the =*Dictionary*= buffer, and in that time you may have moved on to
+working on something else entirely. Perhaps you've even set up a perfect window
+configuration that shows you exactly the right context for the task at hand.
+And then you quit the =*Dictionary*= window. And your carefully crafted context
+is gone, nowhere to be found. You're left looking at a bunch of random buffers
+that happened to be open when you looked up "palaver" or some other word you've
+read on [[https://protesilaos.com/codelog/2023-05-11-accessibility-software-freedom/][Prot's blog]].
+
+This behavior basically assumes that you quit the =*Dictionary*= window right
+after performing a search, without doing anything else with Emacs in the
+meantime. In all other cases--it's a footgun. What =dictionary.el= should have
+done instead, is to bind ~q~ to ~quit-window~ as is the case in ~special-mode~
+and its derivatives. This command is specifically designed for getting the
+current buffer out of view: paraphrasing from the docstring, it "deletes the
+window or shows some other buffer in it". And it's standard Emacs stuff,
+tweakable via standard Emacs mechanisms.
+
+This brings me to my subtler, broader issue with =dictionary.el=, which is that
+it doesn't make good use of existing Emacs facilities, and instead it tries to
+reinvent the wheel in too many places for my taste. Maybe it's because it was
+originally supposed to also support XEmacs which had some differences compared
+to GNU Emacs, I'm really not sure. The result is a library that's harder for me
+as a user to customize and extend.
+
+In face of this dissatisfaction, I decided to write my own dictionary lookup
+package for Emacs. I've put together a minimal yet powerful RFC2229 dictionary
+client package for Emacs in less than 300 lines of Elisp, including headers and
+docstrings. I called it /Dict/, because it was shorter than =dictionary.el=.
+
+I've [[https://lists.gnu.org/archive/html/emacs-devel/2023-05/msg00318.html][proposed my Dict package for inclusion in GNU ELPA]] over the =emacs-devel=
+mailing list earlier this month, noting that I wouldn't mind trying to modify
+the built-in =dictionary.el= instead of adding this new package, if the Emacs
+maintainers would be open for that kind of change. Eli [[https://lists.gnu.org/archive/html/emacs-devel/2023-05/msg00319.html][responded]] that
+augmenting =dictionary.el= would indeed be preferable, which led after some more
+back and forth to the patch this post is really all about.
+
+My patch adds a few new user options to =dictionary.el= that affect the behavior
+of the ~dictionary-search~ command. The most influential new option is
+~dictionary-display-definition-function~. It controls how ~dictionary-search~
+displays dictionary definitions, by specifying a function that responsible for
+taking a definition and displaying it. We now also have a new function called
+~dictionary-display-definition-in-help-buffer~ that you can use as the value of
+~dictionary-display-definition-function~ to have definitions appear in the
+standard Emacs =*Help*= buffer. The way I see it, the =*Help*= buffer is ideal
+for this task as it is the same interface I use for viewing transient reference
+information in Emacs--such as variables' docstrings or active keybindings--all
+the time. In the =*Help*= buffer we can click on references to other dictionary
+definitions to display them instead, just like we do with references to Elisp
+functions. We can than press ~l~ to go back and ~r~ to go forward, and ~q~
+naturally invokes ~quit-window~ rather than a bespoke
+window-quitting-and-restoring command. Other notable new options are
+~dictionary-read-word-function~ and ~dictionary-read-dictionary-function~ that
+control how ~dictionary-search~ prompts you for a word and a dictionary to
+search in, respectively.
+
+On Eli's advice, I've also added a more high-level user option called
+~dictionary-search-interface~ that uses the ~:set~ property of ~defcustom~ to
+modify the values of all three aforementioned options together when you set it.
+The idea is that this option acts as a bundle that users can customize once
+instead of configuring several separate options. If you customize
+~dictionary-search-interface~ to the symbol ~help~, it makes the
+~dictionary-search~ command behave similarly to the corresponding command from
+my short-lived Dict package. Crucially, definitions are displayed in a =*Help*=
+buffer. It also enables completion when prompting for a word to search for
+based on matching dictionary definitions and improves the default word choice.
+
+With this patch in place, my settings for =dictionary.el= are now as follows:
+
+#+begin_src emacs-lisp
+ (setopt dictionary-search-interface 'help
+ dictionary-default-strategy "prefix"
+ dictionary-default-dictionary "gcide"
+ dictionary-server "dict.org")
+
+ (keymap-global-set "M-#" #'dictionary-search)
+#+end_src
+
+If you also use the =dict.org= dictionary server, I strongly suggest setting
+~dictionary-default-strategy~ (which designates the word-matching strategy to
+use) to something other than the default ~"."~. Otherwise, the dictionary
+server uses a matching strategy of its choosing, and this server's default
+choice was [[https://lists.gnu.org/archive/html/emacs-devel/2023-05/msg00611.html][reported]] to misbehave for some words. As you can see above, I
+currently use the ~"prefix"~ matching strategy. Other strategies I've found
+useful are ~"substring"~ for matching words that contain the string we're
+searching for, and ~"re"~ for regular expression matching. There's also
+~"soundex"~ for matching words that sound similar to the input string, which is
+helpful when I'm not totally sure how to spell the word I have in mind.