summaryrefslogtreecommitdiff
path: root/.config/emacs/modules
diff options
context:
space:
mode:
Diffstat (limited to '.config/emacs/modules')
-rw-r--r--.config/emacs/modules/mm-editing.el41
-rw-r--r--.config/emacs/modules/mm-humanwave.el136
-rw-r--r--.config/emacs/modules/mm-treesit.el5
3 files changed, 179 insertions, 3 deletions
diff --git a/.config/emacs/modules/mm-editing.el b/.config/emacs/modules/mm-editing.el
index 0b9971f..4c5e8be 100644
--- a/.config/emacs/modules/mm-editing.el
+++ b/.config/emacs/modules/mm-editing.el
@@ -56,6 +56,7 @@
(go-ts-mode . (:extras go-ts-mode-indent-offset))
(gsp-ts-mode . (:width 2 :extras gsp-ts-mode-indent-rules))
(helpful-mode . (:width 8)) ; GNU code uses 8-column tabs
+ (json-ts-mode . (:extras json-ts-mode-indent-offset))
(latex-mode . (:width 2))
(lisp-data-mode . (:spaces t))
(lisp-interaction-mode . (:spaces t))
@@ -319,6 +320,36 @@ is as described by `emmet-expand-line'."
(emmet-self-closing-tag-style ""))
+;;; JQ Manipulation in JSON Mode
+
+(defun mm-jq-filter (query &optional beg end)
+ "TODO"
+ (interactive
+ (list
+ (read-string (format-prompt "Query" nil))
+ (when (use-region-p) (region-beginning))
+ (when (use-region-p) (region-end))))
+ (let* ((beg (or beg (point-min)))
+ (end (or end (point-max)))
+ (temp-buffer (generate-new-buffer "* jq temp*"))
+ (exit-code (call-process-region beg end "jq" nil temp-buffer nil
+ "--tab" query))
+ (output (with-current-buffer temp-buffer (buffer-string))))
+ (if (zerop exit-code)
+ (atomic-change-group
+ (delete-region beg end)
+ (insert output)
+ (indent-region beg (point)))
+ (message "%s" output))
+ (kill-buffer temp-buffer)))
+
+(use-package json-ts-mode
+ :bind ( :map json-ts-mode-map
+ ("C-|" . #'mm-jq-filter))
+ :config
+ (require 'live-jq))
+
+
;;; Number Formatting
(use-package number-format-mode
@@ -363,6 +394,12 @@ is as described by `emmet-expand-line'."
;;; Add Missing Extensions
(dolist (pattern '("\\.tmac\\'" "\\.mom\\'"))
- (add-to-list 'auto-mode-alist (cons pattern 'nroff-mode)))
+ (add-to-list 'auto-mode-alist (cons pattern #'nroff-mode)))
+
+
+;;; Subword Navigation
+
+(use-package subword
+ :hook prog-mode)
-(provide 'mm-editing) \ No newline at end of file
+(provide 'mm-editing)
diff --git a/.config/emacs/modules/mm-humanwave.el b/.config/emacs/modules/mm-humanwave.el
new file mode 100644
index 0000000..40bde27
--- /dev/null
+++ b/.config/emacs/modules/mm-humanwave.el
@@ -0,0 +1,136 @@
+;;; mm-humanwave.el --- Humanwave extras -*- lexical-binding: t; -*-
+
+
+;;; Query the Backend
+
+(defvar mm--humanwave-query-history nil
+ "History for endpoints given to `mm-humanwave-query'.")
+
+(defun mm-humanwave-query (endpoint &optional method)
+ "Query and display the result of an HTTP reqiest on ENDPOINT.
+If METHOD is nil, a GET request is performed."
+ (interactive
+ (let* ((query (read-string (format-prompt "Query" nil)
+ (car-safe mm--humanwave-query-history)
+ 'mm--humanwave-query-history))
+ (parts (string-split (string-trim query) " " :omit-nulls)))
+ (when (length> parts 2)
+ (user-error "Queries must be of the form `METHOD ENDPOINT' or `ENDPOINT'."))
+ (nreverse parts)))
+ (let* ((project-root (project-root (project-current :maybe-prompt)))
+ (qry-path (expand-file-name "qry" project-root))
+ extras)
+ (unless (file-executable-p qry-path)
+ (user-error "No `qry' executable found in the project root"))
+ (let ((output-buffer (get-buffer-create "*Query Response*")))
+ (with-current-buffer output-buffer
+ (delete-region (point-min) (point-max))
+ (call-process qry-path nil t nil
+ (string-trim endpoint) "-X" (or method "GET"))
+ (unless (eq major-mode 'json-ts-mode)
+ (json-ts-mode))
+ (goto-char (point-min)))
+ (display-buffer output-buffer))))
+
+(keymap-set project-prefix-map "q" #'mm-humanwave-query)
+
+
+;;; IMenu Support for Handlers
+
+(defvar mm-humanwave-handler--regexp
+ (rx bol
+ (* blank)
+ (or "if" "elif")
+ (* blank)
+ (or "topic" "schedule")
+ (* blank)
+ "=="
+ (* blank)
+ (or (seq ?\' (* (not ?\')) ?\')
+ (seq ?\" (* (not ?\")) ?\"))
+ (* blank)
+ ?:
+ (* blank)
+ eol))
+
+(defun mm-humanwave-handler-topic-imenu-index ()
+ (let ((tree-index (when (fboundp 'treesit-simple-imenu--generic-function)
+ (treesit-simple-imenu--generic-function
+ treesit-simple-imenu-settings)))
+ (topic-index '()))
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward mm-humanwave-handler--regexp nil :noerror)
+ (let ((label (match-string 0))
+ (pos (match-beginning 0)))
+ (push (cons (format "Topic: %s" (string-trim label)) pos) topic-index))))
+ (append (nreverse topic-index) tree-index)))
+
+(defun mm-humanwave-handler-topic-imenu-setup ()
+ "Setup custom imenu index for `python-ts-mode'."
+ (when (and (string-match-p "handlers?" (or (buffer-file-name) ""))
+ (derived-mode-p #'python-ts-mode))
+ (setq-local imenu-create-index-function
+ #'mm-humanwave-handler-topic-imenu-index)))
+
+(add-hook 'after-change-major-mode-hook
+ #'mm-humanwave-handler-topic-imenu-setup)
+
+
+;;; Insert Imports in Vue
+
+
+(defun mm-humanwave-insert-vue-import-path (base-directory target-file)
+ "Insert an import directive at POINT.
+The import directive imports TARGET-FILE relative from BASE-DIRECTORY.
+When called interactively BASE-DIRECTORY is the directory of the current
+open Vue file and TARGET-FILE is a file in the current project that is
+queried interactively.
+
+When called interactively the prefix argument can be used to emulate the
+behaviour of the INCLUDE-ALL-P argument to `mm-project-read-file-name'."
+ (interactive
+ (list
+ default-directory
+ (mm-humanwave-project-read-file-name current-prefix-arg)))
+ (let ((path (file-name-sans-extension
+ (file-relative-name target-file base-directory))))
+ (insert "import ")
+ (save-excursion
+ (insert (format " from '%s';" path)))))
+
+(defun mm-humanwave-project-read-file-name (&optional include-all-p)
+ "Prompt for a project file.
+This function is similar to `project-find-file', but it returns the path
+to the selected file instead of opening it.
+
+When called interactively the selected file is printed to the minibuffer,
+otherwise it is returned.
+
+The prefix argument INCLUDE-ALL-P is the same as the INCLUDE-ALL argument
+to the `project-find-file' command."
+ (interactive "P")
+ (let* ((project (project-current :maybe-prompt))
+ (root (project-root project))
+ (files (if include-all-p
+ (let ((vc-ignores (mapcar
+ (lambda (dir) (concat dir "/"))
+ vc-directory-exclusion-list)))
+ (project--files-in-directory root vc-ignores))
+ (project-files project)))
+ (canditates (mapcar (lambda (f) (file-relative-name f root))
+ files))
+ (table (lambda (string predicate action)
+ (if (eq action 'metadata)
+ '(metadata (category . file))
+ (complete-with-action action canditates string predicate))))
+ (default-directory root)
+ (choice (completing-read (format-prompt "Find project file" nil)
+ table nil :require-match)))
+ (let ((path (expand-file-name choice root)))
+ (if (called-interactively-p 'any)
+ (message "%s" path)
+ path))))
+
+
+(provide 'mm-humanwave)
diff --git a/.config/emacs/modules/mm-treesit.el b/.config/emacs/modules/mm-treesit.el
index 1d4defa..bd146ce 100644
--- a/.config/emacs/modules/mm-treesit.el
+++ b/.config/emacs/modules/mm-treesit.el
@@ -35,6 +35,8 @@
"https://github.com/tree-sitter/tree-sitter-java")
(javascript
"https://github.com/tree-sitter/tree-sitter-javascript")
+ (json
+ "https://github.com/tree-sitter/tree-sitter-json")
(markdown
"https://github.com/tree-sitter-grammars/tree-sitter-markdown"
"split_parser" "tree-sitter-markdown/src")
@@ -116,6 +118,7 @@ The parsers are taken from `treesit-language-source-alist'."
(defvar mm-treesit-language-file-name-alist
'((go . "\\.go\\'")
(gomod . "/go\\.mod\\'")
+ (json . "\\.json\\'")
(tsx . "\\.tsx\\'")
(typescript . "\\.ts\\'"))
"Alist mapping languages to their associated file-names.
@@ -219,4 +222,4 @@ back to regular `expreg-expand'."
:commands (mm-expreg-expand mm-expreg-expand-dwim)
:bind ("M-SPC" . mm-expreg-expand-dwim))
-(provide 'mm-treesit) \ No newline at end of file
+(provide 'mm-treesit)