Added some more sort features to my "data" commands
Including a nifty ability to sort lines by a user-definable column. Oh, and the ability to run a `jq` command on a JSON buffer to whittle it down, which seems to be very data-centric.
This commit is contained in:
parent
4a6a3c87b1
commit
a00b70c54a
2 changed files with 135 additions and 14 deletions
71
ha-data.org
71
ha-data.org
|
@ -49,11 +49,14 @@ These functions focus on the data in the buffer as a series of lines:
|
|||
#+begin_src emacs-lisp
|
||||
(ha-leader
|
||||
"d l" '(:ignore t :which-key "on lines")
|
||||
"d l f" '("flush lines" . flush-lines)
|
||||
"d l k" '("keep lines" . keep-lines)
|
||||
"d l s" '("sort lines" . ha-sort-lines)
|
||||
"d l u" '("unique lines" . delete-duplicate-lines)
|
||||
"d l b" '("flush blanks" . flush-blank-lines))
|
||||
"d l d" '("flush lines" . flush-lines)
|
||||
"d l k" '("keep lines" . keep-lines)
|
||||
"d l s" '("sort lines" . ha-sort-lines)
|
||||
"d l f" '("sort fields" . ha-sort-fields)
|
||||
"d l n" '("sort field num" . ha-sort-fields-numerically)
|
||||
"d l r" '("reverse lines" . ha-reverse-lines)
|
||||
"d l u" '("unique lines" . delete-duplicate-lines)
|
||||
"d l b" '("flush blanks" . flush-blank-lines))
|
||||
#+end_src
|
||||
|
||||
One issue I have is [[help:keep-lines][keep-lines]] operate on the lines /starting with the point/, not on the entire buffer. Let’s fix that:
|
||||
|
@ -69,16 +72,20 @@ One issue I have is [[help:keep-lines][keep-lines]] operate on the lines /starti
|
|||
(advice-add 'flush-lines :around #'call-function-at-buffer-beginning)
|
||||
#+end_src
|
||||
|
||||
The [[help:sort-lines][sort-lines]] is useful, but insists on an /active/ region. Let’s made a data-focused version:
|
||||
The [[help:sort-lines][sort-lines]] is useful, but insists on an /active/ region. Let’s make a collection of data-focused versions that work on both a region (if it is active) or the entire buffer, regardless of the position of the cursor.
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-sort-lines (prefix)
|
||||
"Sort the lines in a buffer or region (if active).
|
||||
If PREFIX given, sort in reverse order."
|
||||
(interactive "P")
|
||||
(save-excursion
|
||||
(if (region-active-p)
|
||||
(sort-lines prefix (region-beginning) (region-end))
|
||||
(sort-lines prefix (point-min) (point-max)))))
|
||||
(dolist (tuple '((ha-sort-lines sort-lines)
|
||||
(ha-sort-fields sort-fields)
|
||||
(ha-sort-fields-numerically sort-numeric-fields)))
|
||||
(cl-destructuring-bind (func orig-func) tuple
|
||||
(eval `(defun ,func (prefix)
|
||||
,(format "Call `%s' with all lines in a buffer or region (if active).
|
||||
Passes PREFIX to the function." orig-func)
|
||||
(interactive "P")
|
||||
(save-excursion
|
||||
(if (region-active-p)
|
||||
(,orig-func prefix (region-beginning) (region-end))
|
||||
(,orig-func prefix (point-min) (point-max))))))))
|
||||
#+end_src
|
||||
|
||||
Getting rid of blank lines seems somewhat useful:
|
||||
|
@ -95,6 +102,8 @@ These functions focus on the data in the buffer as a table consisting of columns
|
|||
#+begin_src emacs-lisp
|
||||
(ha-leader
|
||||
"d t" '(:ignore t :which-key "on tables")
|
||||
"d t f" '("sort by columns" . ha-sort-fields)
|
||||
"d t n" '("sort by columns numerically" . ha-sort-fields-numerically)
|
||||
"d t k" '("keep columns" . keep-columns)
|
||||
"d t f" '("flush columns" . flush-columns))
|
||||
#+end_src
|
||||
|
@ -215,6 +224,40 @@ Does this work?
|
|||
(should (equal (numbers-to-number-list "1, 2 3") '(1 2 3)))
|
||||
(should (equal (numbers-to-number-list "1, 4-7 9") '(1 4 5 6 7 9))))
|
||||
#+end_src
|
||||
|
||||
The [[help:sort-fields][sort-fields]] function does a good job if the table is space separated, but if we separate by some other character(s), it doesn’t work. Can we write a function that does this? Here we make a /helper/ to some regular expression for the [[help:sort-regexp-fields][sort-regexp-fields]] function.
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-sort-table-by-column (separator field)
|
||||
"Sort the active region or entire buffer by column, FIELD.
|
||||
Columns are denoted by a regular expression, SEPARATOR, which
|
||||
could be a single character. For instance, given a buffer:
|
||||
|
||||
d, a, c, b
|
||||
x, y
|
||||
e, f, g
|
||||
i, m, a, o
|
||||
|
||||
Calling this function with a `,' separator, and `2' for the
|
||||
column, would result in:
|
||||
|
||||
d, a, c, b
|
||||
e, f, g
|
||||
i, m, a, o
|
||||
x, y"
|
||||
(interactive "sSeparator: \nnSorting field: ")
|
||||
;; Create a regular expression of grouped fields, separated
|
||||
;; by the separator sequence, for commas, this would be e.g.
|
||||
;; \\(.*\\),\\(.*\\),\\(.*\\),\\(.*\\)
|
||||
(let* ((rx-list (mapconcat (lambda (x) (rx (group (zero-or-more any))))
|
||||
(number-sequence 1 field)
|
||||
separator))
|
||||
;; Prepend the beginning of line to the regular expression:
|
||||
(regexp (concat (rx bol) rx-list))
|
||||
(start (if (region-active-p) (region-beginning) (point-min)))
|
||||
(end (if (region-active-p) (region-end) (point-max))))
|
||||
(save-excursion
|
||||
(sort-regexp-fields nil regexp (format "\\%d" field) start end))))
|
||||
#+end_src
|
||||
* Buffer-Oriented Functions
|
||||
If there is no specific function, but you can think of a shell command that will work, then
|
||||
#+begin_src emacs-lisp
|
||||
|
|
|
@ -849,6 +849,84 @@ So many configuration files to track:
|
|||
#+end_src
|
||||
** JSON
|
||||
While interested in the [[https://github.com/emacs-tree-sitter/tree-sitter-langs][tree-sitter]] extensions for JSON, e.g. =json-ts-mode=, that comes with Emacs 29, I’ll deal with what is bundled now.
|
||||
|
||||
However, what about taking a buffer of JSON data, and whittling it down with [[https://jqlang.github.io/jq/][jq]]?
|
||||
#+begin_src emacs-lisp
|
||||
(defun ha-json-buffer-to-jq (query)
|
||||
"Runs JSON buffer with QUERY through an external `jq' program.
|
||||
Attempts to find the first JSON object in the buffer, and limits
|
||||
the data to that region. The `jq' program is the first found in
|
||||
the standard path."
|
||||
(interactive "sjq Query: ")
|
||||
(let (s e)
|
||||
(save-excursion
|
||||
(if (region-active-p)
|
||||
(setq s (region-beginning)
|
||||
e (region-end))
|
||||
(goto-char (point-min))
|
||||
(unless (looking-at "{")
|
||||
(re-search-forward "{")
|
||||
(goto-char (match-beginning 0)))
|
||||
(setq s (point))
|
||||
(evil-jump-item)
|
||||
(setq e (1+ (point))))
|
||||
;; (narrow-to-region s e)
|
||||
(shell-command-on-region s e (concat "jq " query) nil t "*jq errors*"))))
|
||||
|
||||
(ha-local-leader :keymaps '(js-json-mode-map json-ts-mode-map)
|
||||
"j" 'ha-json-buffer-to-jq)
|
||||
#+end_src
|
||||
|
||||
This means, that some data like:
|
||||
#+begin_src json :tangle no
|
||||
{
|
||||
"common_id": "GMC|F2BADC23|64D52BF7|awardlateengine",
|
||||
"data": {
|
||||
"name": "Create And Wait for Service Image",
|
||||
"description": "Creates a new Service Image using IMaaS",
|
||||
"long_description": "This job creates a new yawxway service image with name yawxway-howard.abrams-test and docker-dev-artifactory.workday.com/dev/yawxway-service:latest docker url in development folder",
|
||||
"job_id": "5e077245-0f4a-4dc9-b473-ce3ec0b811ba",
|
||||
"state": "success",
|
||||
"progress": "100",
|
||||
"timeout": {
|
||||
"seconds": 300,
|
||||
"strategy": "real_time",
|
||||
"elapsed": 1291.8504
|
||||
},
|
||||
"started_at": "2023-08-10T16:20:49Z",
|
||||
"finished_at": "2023-08-10T16:42:20Z",
|
||||
"links": [
|
||||
{
|
||||
"rel": "child-4aa5978c-4537-4aa9-9568-041ad97c2374",
|
||||
"href": "https://eng501.garmet.howardism.org/api/jobs/4aa5978c-4537-4aa9-9568-041ad97c2374"
|
||||
},
|
||||
{
|
||||
"rel": "project",
|
||||
"href": "https://eng501.garmet.howardism.org/api/projects/8abe0f6e-161e-4423-ab27-d4fb0d5cfd0c"
|
||||
},
|
||||
{
|
||||
"rel": "details",
|
||||
"href": "https://eng501.garmet.howardism.org/api/jobs/5e077245-0f4a-4dc9-b473-ce3ec0b811ba/details"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"foobar", "birdie"
|
||||
],
|
||||
"progress_comment": null,
|
||||
"children": [
|
||||
{
|
||||
"id": "4aa5978c-4537-4aa9-9568-041ad97c2374"
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": "SUCCESS"
|
||||
}
|
||||
#+end_src
|
||||
|
||||
I can type, ~, j~ and then type =.data.timeout.seconds= and end up with:
|
||||
#+begin_src json
|
||||
300
|
||||
#+end_src
|
||||
** Markdown
|
||||
All the READMEs and other documentation use [[https://jblevins.org/projects/markdown-mode/][markdown-mode]].
|
||||
#+begin_src emacs-lisp
|
||||
|
|
Loading…
Reference in a new issue