zkry / yaml-pro

Edit YAML in Emacs like a pro
GNU General Public License v3.0
139 stars 9 forks source link

yaml-pro-jump to jump to path under point? #67

Closed ardrabczyk closed 1 month ago

ardrabczyk commented 2 months ago

I want for example to jump to paths referenced using $ref: in OpenAPI like here https://github.com/rootless-containers/rootlesskit/blob/264f23eb1063623da6974a3f322a12af6d7cc8d4/pkg/api/openapi.yaml#L19. I don't know Emacs Lisp that well, is it possible to achieve that?

zkry commented 1 month ago

Hey! So the use case you mentioned being specific to OpenAPI, I haven't thought about including something concerning it into this package (though it's definitely a possibility). yaml-pro does have a useful function to help you navigate the YAML document structure. The following is a function I came up with to do what you want:

(defun yaml-navigate-to-ref ()
  "Navigate to thing pointed to by $ref."
  (let* (;; First we use a treesitter query to get the key: value pair
         ;; (i.e. block_mapping_pair) we're at.
         (mapping-node (treesit-thing-at-point "block_mapping_pair" 'nested))
         ;; Next we issue a query on the node we retrieved on the previous step to
         ;; extract what the $ref is pointing to.  This query also makes sure that
         ;; we are indeed looking at the value on a "$ref": keyed item.
         (capture (treesit-query-capture
                   mapping-node
                   '(key: ((flow_node) @ref (:match "$ref" @ref))

                          value: (flow_node) @val)))
         ;; Since the node we got back was a quoted string, let's strip the
         ;; quotes at the beginning/end.
         (ref-item (string-trim (treesit-node-text (alist-get 'val capture))
                                "['\" \n\r\t]+"
                                "['\" \n\r\t]+")))
    ;; I'm not sure all the patterns you want to support, but let's
    ;; just suppose that if the string starts with a "#" it means we
    ;; are looking for something in the file we're in.  With some
    ;; modifications you can have it look into other files.
    (when (eql (aref ref-item 0) ?#)
      ;;
      (let* ((path (string-split (string-trim-left ref-item "#/") "/")))
        ;; yaml-pro has a convenience function to navigate into
        ;; a certain path yaml-pro-ts-jump-to-definition
        ;; So for example:
        ;;
        ;; students:
        ;;   Lars:
        ;;     grade: 100
        ;;
        ;; We can run (yaml-pro-ts-jump-to-definition "students" "Lars" "grade")
        ;; to navigate to the grade text
        (apply #'yaml-pro-ts-jump-to-definition path)))))

Definitely let me know if you have any questions regarding the Elisp here or if there's something else you'd want this function to do!

ardrabczyk commented 1 month ago

It works, thank you so much! You're the best!

zkry commented 1 month ago

Awesome! Definitely let me know if you have any other questions!