lsp-bjolang/emacs/bjolang-lsp.el

84 lines
3.2 KiB
EmacsLisp
Raw Normal View History

;;; bjolang-lsp.el --- Commands for the parts of BjolangLsp that LSP has no request for -*- lexical-binding: t; -*-
;;; Commentary:
;; Macro expansion: `bjo-expand-macro' shows the expansion of the macro call
;; at point all the way down, and `bjo-expand-macro-1' one step of it, in a
;; buffer of their own. With a prefix argument they keep the names hygiene
;; made, such as `tmp__37', which is what tells a template's name from the
;; caller's of the same spelling.
;;
;; The expansion is the compiler's, from its last check of the buffer; a
;; change not yet checked is checked first. `loop', `seql', `->' and the
;; other forms the parser turns into code itself are not macros, and have
;; no expansion to show.
;;; Code:
(require 'lsp-mode)
(defvar bjo-mode-map)
(defvar bjo-mode-hook)
(declare-function bjo-mode "bjomode")
(defun bjo--field (result key)
"The field KEY, a string, of RESULT as `lsp-mode' decoded it.
A hash table or a plist, as `lsp-use-plists' says, which can differ from
how this file was compiled."
(if (hash-table-p result)
(gethash key result)
(plist-get result (intern (concat ":" key)))))
(defun bjo--expand-macro (full hygienic)
"Show the expansion of the macro call at point.
FULL expands the macro calls in the expansion too; HYGIENIC keeps the
names hygiene made."
(let* ((params (append (lsp--text-document-position-params)
(list :full (if full t :json-false)
:hygienic (if hygienic t :json-false))))
(result (lsp-request "bjolang/expandMacro" params)))
(if (null result)
(message "No macro call at point.")
(let ((macro (bjo--field result "macro"))
(text (bjo--field result "text"))
(buffer (get-buffer-create "*bjo expansion*")))
(with-current-buffer buffer
(let ((inhibit-read-only t)
;; The expansion is not a file, and must not start a server.
(bjo-mode-hook nil))
(erase-buffer)
(bjo-mode)
(insert (format ";; (%s ...), %s%s\n\n"
macro
(if full "expanded all the way" "one step")
(if hygienic ", with hygiene's names" ""))
text
"\n")
(font-lock-ensure)
(goto-char (point-min)))
;; Read only, and `q' to leave, without binding `q' in the mode's
;; own map, which every Bjolang buffer shares.
(view-mode 1))
(display-buffer buffer)))))
(defun bjo-expand-macro (&optional hygienic)
"Show the macro call at point expanded all the way down.
With a prefix argument HYGIENIC, keep the names hygiene made."
(interactive "P")
(bjo--expand-macro t hygienic))
(defun bjo-expand-macro-1 (&optional hygienic)
"Show one step of the expansion of the macro call at point.
With a prefix argument HYGIENIC, keep the names hygiene made."
(interactive "P")
(bjo--expand-macro nil hygienic))
;; As SLIME binds its macroexpanders.
(with-eval-after-load 'bjo-mode
(define-key bjo-mode-map (kbd "C-c C-m") #'bjo-expand-macro-1)
(define-key bjo-mode-map (kbd "C-c M-m") #'bjo-expand-macro))
(provide 'bjolang-lsp)
;;; bjolang-lsp.el ends here