Skip to content

Commit

Permalink
Enhance macro expansion stepper hiding; closes #697
Browse files Browse the repository at this point in the history
- Add customization variable racket-expand-hiding, which is an Emacs
Lisp equivalent of macro-debugger/model/hiding-policies. Allows the
same level of macro hiding customization as in DrRacket.

- Use macro-debugger stepper for expressions, too:

  - Simplifies back end implementation.

  - Allows racket-expand-hiding policy to affect expression expansion,
  too.

- Unless overridden by a command prefix, show the racket-expand-hiding
name and value in the buffer, and button-ize the former to be
customize-variable.

- Add a racket-stepper-refresh command, so after someone customizes
the hiding policy they can just hit "g" to use the new value.
  • Loading branch information
greghendershott committed Jan 28, 2024
1 parent 3536288 commit 3ce25d8
Show file tree
Hide file tree
Showing 7 changed files with 289 additions and 206 deletions.
1 change: 1 addition & 0 deletions doc/generate.el
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@
racket-xp-highlight-unused-regexp
racket-xp-add-binding-faces
racket-documentation-search-location
racket-expand-hiding
"Hash lang variables"
racket-hash-lang-token-face-alist
racket-hash-lang-pairs
Expand Down
22 changes: 20 additions & 2 deletions doc/racket-mode.texi
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ General variables
* racket-xp-highlight-unused-regexp::
* racket-xp-add-binding-faces::
* racket-documentation-search-location::
* racket-expand-hiding::
Hash lang variables
Expand Down Expand Up @@ -2781,6 +2782,8 @@ Used by the commands @ref{racket-expand-file},
@multitable {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}
@item Key
@tab Binding
@item @kbd{g}
@tab @code{racket-stepper-refresh}
@item @kbd{k}
@tab @code{racket-stepper-previous-item}
@item @kbd{p}
Expand Down Expand Up @@ -2816,8 +2819,8 @@ If the file is non-trivial and/or is not compiled to a .zo
bytecode file, then it might take many seconds before the
original form is displayed and you can start stepping.

With @kbd{C-u} also expands syntax from racket/base
-- which can result in very many expansion steps.
With @kbd{C-u} behaves as if @ref{racket-expand-hiding}
were 'disabled.

@node racket-expand-region
@subsection racket-expand-region
Expand All @@ -2829,6 +2832,9 @@ Expand the active region using @ref{racket-stepper-mode}.
Uses Racket's @code{expand-once} in the namespace from the most recent
@ref{racket-run}.

With @kbd{C-u} behaves as if @ref{racket-expand-hiding}
were 'disabled.

@node racket-expand-definition
@subsection racket-expand-definition

Expand All @@ -2839,6 +2845,9 @@ Expand the definition around point using @ref{racket-stepper-mode}.
Uses Racket's @code{expand-once} in the namespace from the most recent
@ref{racket-run}.

With @kbd{C-u} behaves as if @ref{racket-expand-hiding}
were 'disabled.

@node racket-expand-last-sexp
@subsection racket-expand-last-sexp

Expand All @@ -2849,6 +2858,9 @@ Expand the sexp before point using @ref{racket-stepper-mode}.
Uses Racket's @code{expand-once} in the namespace from the most recent
@ref{racket-run}.

With @kbd{C-u} behaves as if @ref{racket-expand-hiding}
were 'disabled.

@node Other
@section Other

Expand Down Expand Up @@ -2982,6 +2994,7 @@ Delete the ``compiled'' directories made by @ref{racket-mode-start-faster}.
* racket-xp-highlight-unused-regexp::
* racket-xp-add-binding-faces::
* racket-documentation-search-location::
* racket-expand-hiding::
@end menu

@node racket-program
Expand Down Expand Up @@ -3140,6 +3153,11 @@ after applying @code{url-hexify-string}. Apart from ``%s'', the
string should be a properly encoded URL@.
@end itemize

@node racket-expand-hiding
@subsection racket-expand-hiding

The macro hiding policy for commands like @ref{racket-expand-file}.

@node Hash lang variables
@section Hash lang variables

Expand Down
39 changes: 39 additions & 0 deletions racket-custom.el
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,45 @@ ignore POS. Examples: `racket-show-echo-area' and
:risky t
:group 'racket-other)

(defcustom racket-expand-hiding 'standard
"The macro hiding policy for commands like `racket-expand-file'."
:tag "Racket Expand Hiding"
:type '(choice
(const :tag "Disable" disable)
(const :tag "Standard" standard)
(list :tag "Custom" :value (t t t t nil)
(boolean :tag "Hide racket syntax")
(boolean :tag "Hide library syntax")
(boolean :tag "Hide contracts")
(boolean :tag "Hide phase>0")
(repeat
:tag "More rules (see macro-debugger/model/hiding-policies \"Entry\" and \"Condition\")"
(list (choice (const :tag "show-if" show-if)
(const :tag "hide-if" hide-if))
(choice (const :tag "lexical" (lexical))
(const :tag "unbound" (unbound))
(const :tag "from-kernel-module" (from-kernel-module))
(list :tag "from-def-module"
(const from-def-module)
(choice :tag "module path" string symbol))
(list :tag "from-nom-module"
(const from-nom-module)
(choice :tag "module path" string symbol))
(list :tag "from-collection"
(const from-collection)
(repeat :tag "collection-string" string))
(list :tag "symbol=?"
(const symbol=?)
(symbol))
(list :tag "symbol-like"
(const symbol-like)
(string :tag "racket regexp"))
(list :tag "phase>=?"
(const phase>=?)
(natnum :tag "natural number"))
(sexp :tag "sexp"))))))
:group 'racket-other)

;;; Faces

(defgroup racket-faces nil
Expand Down
136 changes: 83 additions & 53 deletions racket-stepper.el
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@
;; Need to define this before racket-stepper-mode
(defvar racket-stepper-mode-map
(racket--easy-keymap-define
'((("C-m") racket-stepper-step)
(("n" "j") racket-stepper-next-item)
(("p" "k") racket-stepper-previous-item))))
`((("C-m") ,#'racket-stepper-step)
(("n" "j") ,#'racket-stepper-next-item)
(("p" "k") ,#'racket-stepper-previous-item)
("g" ,#'racket-stepper-refresh))))

(easy-menu-define racket-stepper-mode-menu racket-stepper-mode-map
"Menu for Racket stepper mode."
'("Racket"
["Step" racket-stepper-step]
["Next" racket-stepper-next-item]
["Previous" racket-stepper-previous-item]))
`("Racket"
["Step" ,#'racket-stepper-step]
["Next" ,#'racket-stepper-next-item]
["Previous" ,#'racket-stepper-previous-item]
["Refresh" ,#'racket-stepper-refresh]))

(defconst racket-stepper-font-lock-keywords
(eval-when-compile
Expand Down Expand Up @@ -59,7 +61,7 @@ Used by the commands `racket-expand-file',

;;; commands

(defun racket-expand-file (&optional into-base)
(defun racket-expand-file (&optional no-hiding)
"Expand the `racket-mode' buffer's file in `racket-stepper-mode'.
Uses the `macro-debugger` package to do the expansion.
Expand All @@ -71,75 +73,87 @@ If the file is non-trivial and/or is not compiled to a .zo
bytecode file, then it might take many seconds before the
original form is displayed and you can start stepping.
With \\[universal-argument] also expands syntax from racket/base
-- which can result in very many expansion steps."
With \\[universal-argument] behaves as if `racket-expand-hiding'
were \\='disabled."
(interactive "P")
(racket--assert-edit-mode)
(racket--save-if-changed)
(racket-stepper--start 'file (racket--buffer-file-name) into-base))
(racket-stepper--start nil no-hiding))

(defun racket-expand-region (start end &optional into-base)
(defun racket-expand-region (&optional no-hiding)
"Expand the active region using `racket-stepper-mode'.
Uses Racket's `expand-once` in the namespace from the most recent
`racket-run'."
(interactive "rP")
`racket-run'.
With \\[universal-argument] behaves as if `racket-expand-hiding'
were \\='disabled."
(interactive "P")
(unless (region-active-p)
(user-error "No region"))
(racket--assert-sexp-edit-mode)
(racket-stepper--expand-text into-base
(racket--assert-edit-mode)
(racket-stepper--expand-text no-hiding
(lambda ()
(cons start end))))
(cons (region-beginning)
(region-end)))))

(defun racket-expand-definition (&optional into-base)
(defun racket-expand-definition (&optional no-hiding)
"Expand the definition around point using `racket-stepper-mode'.
Uses Racket's `expand-once` in the namespace from the most recent
`racket-run'."
`racket-run'.
With \\[universal-argument] behaves as if `racket-expand-hiding'
were \\='disabled."
(interactive "P")
(racket--assert-sexp-edit-mode)
(racket-stepper--expand-text into-base
(racket-stepper--expand-text no-hiding
(lambda ()
(save-excursion
(cons (progn (beginning-of-defun) (point))
(progn (end-of-defun) (point)))))))

(defun racket-expand-last-sexp (&optional into-base)
(defun racket-expand-last-sexp (&optional no-hiding)
"Expand the sexp before point using `racket-stepper-mode'.
Uses Racket's `expand-once` in the namespace from the most recent
`racket-run'."
`racket-run'.
With \\[universal-argument] behaves as if `racket-expand-hiding'
were \\='disabled."
(interactive "P")
(racket--assert-sexp-edit-mode)
(racket-stepper--expand-text into-base
(racket-stepper--expand-text no-hiding
(lambda ()
(save-excursion
(cons (progn (backward-sexp) (point))
(progn (forward-sexp) (point)))))))

(defun racket-stepper--expand-text (prefix get-region)
(defun racket-stepper--expand-text (no-hiding get-region)
(pcase (funcall get-region)
(`(,beg . ,end)
(racket-stepper--start 'expr
(buffer-substring-no-properties beg end)
prefix))))

(defvar racket--stepper-repl-session-id nil
"The REPL session used when stepping.
(racket-stepper--start (buffer-substring-no-properties beg end)
no-hiding))))

May be nil for \"file\" stepping, but must be valid for \"expr\"
stepping.")
;; When starting, save the essential parameters in these vars, to
;; support a refresh command.
(defvar racket--stepper-repl-session-id nil)
(defvar racket--stepper-path nil)
(defvar racket--stepper-expr nil)
(defvar racket--stepper-no-hiding nil)

(defun racket-stepper--start (which str into-base)
(defun racket-stepper--start (expression-str no-hiding)
"Ensure buffer and issue initial command.
WHICH should be \"expr\" or \"file\".
STR should be the expression or pathname.
INTO-BASE is treated as a raw command prefix arg and converted to boolp."
STR should be the expression or nil for file expansion."
(racket--assert-edit-mode)
(setq racket--stepper-repl-session-id (racket--repl-session-id))
(unless (or racket--stepper-repl-session-id
(eq which 'file))
(error "Only works when the edit buffer has a REPL buffer, and, you should racket-run first"))
(unless (or (not expression-str)
racket--stepper-repl-session-id)
(error "Expression expansion only works when the edit buffer has a REPL buffer, and, you already did a racket-run"))
(setq racket--stepper-path (racket-file-name-front-to-back (racket--buffer-file-name)))
(setq racket--stepper-expr expression-str)
(setq racket--stepper-no-hiding no-hiding)
;; Create buffer if necessary
(let ((name (racket--stepper-buffer-name)))
(unless (get-buffer name)
Expand All @@ -148,35 +162,51 @@ INTO-BASE is treated as a raw command prefix arg and converted to boolp."
;; Give it a window if necessary
(unless (get-buffer-window name)
(pop-to-buffer (get-buffer name)))
;; Select the stepper window and insert
;; Select the stepper window and start.
(select-window (get-buffer-window name))
(let ((inhibit-read-only t))
(delete-region (point-min) (point-max))
(insert "Starting macro expansion stepper... please wait...\n"))
(racket--cmd/async racket--stepper-repl-session-id
`(macro-stepper (,which . ,(if (eq which 'file)
(racket-file-name-front-to-back str)
str))
,(and into-base t))
#'racket-stepper--insert)))

(defun racket-stepper--insert (nothing-or-steps)
(if (eq nothing-or-steps 'nothing)
(racket-stepper-refresh)))

(defun racket-stepper-refresh ()
(interactive)
(let ((inhibit-read-only t))
(delete-region (point-min) (point-max))
(insert "Starting macro expansion stepper... please wait...\n"))
(racket--cmd/async racket--stepper-repl-session-id
`(macro-stepper ,racket--stepper-path
,racket--stepper-expr
,(if racket--stepper-no-hiding
'disable
racket-expand-hiding))
#'racket-stepper--insert))

(defun racket-stepper--insert (steps)
(if (null steps)
(message "Nothing to expand")
(with-current-buffer (racket--stepper-buffer-name)
(let ((inhibit-read-only t))
(goto-char (point-max))
(dolist (step nothing-or-steps)
(dolist (step steps)
(pcase step
(`(original . ,text)
(delete-region (point-min) (point-max))
(if racket--stepper-no-hiding
(insert "macro hiding disabled by command prefix")
(insert-text-button "racket-expand-hiding"
'action #'racket-stepper-customize-hiding)
(insert ": ")
(princ (if racket--stepper-no-hiding 'disable racket-expand-hiding)
(current-buffer)))
(insert "\n\n")
(insert "Original\n" text "\n" "\n"))
(`(final . ,text) (insert "Final\n" text "\n"))
(`(,label . ,diff) (insert label "\n" diff "\n"))))
(racket-stepper-previous-item)
(when (equal (selected-window) (get-buffer-window (current-buffer)))
(recenter))))))

(defun racket-stepper-customize-hiding (_btn)
(customize-variable 'racket-expand-hiding))

(defun racket-stepper-step (prefix)
(interactive "P")
(racket--cmd/async racket--stepper-repl-session-id
Expand Down
2 changes: 1 addition & 1 deletion racket/command-server.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@
[`(no-op) #t]
[`(logger ,v) (channel-put logger-command-channel v)]
[`(check-syntax ,path-str ,code) (check-syntax path-str code)]
[`(macro-stepper ,str ,into-base?) (macro-stepper str into-base?)]
[`(macro-stepper ,path ,str ,pol) (macro-stepper path str pol)]
[`(macro-stepper/next ,what) (macro-stepper/next what)]
[`(module-names) (module-names)]
[`(requires/tidy ,reqs) (requires/tidy reqs)]
Expand Down

0 comments on commit 3ce25d8

Please sign in to comment.