Skip to content

Commit

Permalink
Improve tidy-requires
Browse files Browse the repository at this point in the history
Motivated by jackfirth/resyntax#432, as well
as inspired by racket-review's use of syntax classes.

Define syntax classes closely following the require grammar. Use them
to drive the matching and simplification, producing attribute values
that are `sortable` structs, from which we reconstruct the syntax.

Because the macro-debugger-lib drop analysis works in terms of <module
phase> tuples, the root-module-path syntax class is the locus -- it
may produce #f instead of a `sortable` to indicate elision. This can
percolate up through other specs, since they all build directly or
transitively on root-module-path.

Simplify gratuitous specs either reducing to the simpler equivalent
spec or eliding entirely. e.g. (only-in m) => m or (combine-in) => #f.

No longer "explode" multi-in forms when denormalizing and attempt to
recover them when normalizing. Instead: Preserve multi-in forms,
modifying only for drops. In simple cases like (multi-in a b (c d)),
we can modify the multi-in form itself. In the general case -- any
Cartesian product -- we must wrap in a subtract-in spec.

Change require tidying to work on full file syntax; requires are
tidied in all modules. The racket-{trim base}-requires add/drop
required modules only in the file's root module, because the
macro-debugger lib's analysis only works for that module. As a result
of this change, the front end no longer needs to gather and supply a
list of require forms. Instead it always just supplies a file path.
The back end commands return a list of textual changes -- inserts,
deletes, and replaces -- for the front end to make to the buffer. This
seems like a cleaner and more appropriate division of labor.

Improve some doc strings in substance, and prefer active to passive
voice.
  • Loading branch information
greghendershott committed Jan 13, 2025
1 parent f2645aa commit 135fefe
Show file tree
Hide file tree
Showing 5 changed files with 925 additions and 634 deletions.
120 changes: 57 additions & 63 deletions doc/racket-mode.texi
Original file line number Diff line number Diff line change
Expand Up @@ -1069,37 +1069,24 @@ Unfold (show) all test submodules.

@kbd{M-x} @code{racket-tidy-requires}

Make a single ``require'' form, modules sorted, one per line.
Make a single, sorted ``require'' form.

The scope of this command is the innermost module around point,
including the outermost module for a file using a ``#lang'' line.
All require forms within that module are combined into a single
form. Within that form:
The scope of this command is the innermost module around point --
whether an explicit submodule form or the outermost module for a
file that has a ``#lang'' line.

@itemize
@item
A single subform is used for each phase level, sorted in this
Merge all require forms within that module to one form.

Use a single require-spec for each phase-level, sorted in this
order: for-syntax, for-template, for-label, for-meta, and
plain (phase 0).

@itemize
@item
Within each level subform, the modules are sorted:

@itemize
@item
Collection path modules -- sorted alphabetically.

@item
Subforms such as only-in.
Within each phase-level, sort require-specs by module name.

@item
Quoted relative requires -- sorted alphabetically.
@end itemize
@end itemize
@end itemize
Format at most one module per line.

At most one required module is listed per line.
Simplify gratuitous require-specs. For example reduce (only-in m)
to m and elide (combine-in).

See also: @ref{racket-trim-requires} and @ref{racket-base-requires}.

Expand All @@ -1108,16 +1095,28 @@ See also: @ref{racket-trim-requires} and @ref{racket-base-requires}.

@kbd{M-x} @code{racket-trim-requires}

Like @ref{racket-tidy-requires} but also deletes unnecessary requires.
Like @ref{racket-tidy-requires} but also delete unnecessary requires.

Use macro-debugger/analysis/check-requires to analyze.

The analysis:

@itemize
@item
Needs the @code{macro-debugger-lib} package.

Note: This only works when the source file can be fully expanded
with no errors.
@item
Only works when the source file can be fully expanded with no
@end itemize
errors.

Note: This only works for requires at the top level of a source
file using #lang. It does NOT work for require forms inside
module forms. Furthermore, it is not smart about module+ or
module* forms -- it might delete top level requires that are
actually needed by such submodules.
@itemize
@item
Only works for requires at the top level of a source file using
@end itemize
#lang -- not for requires inside submodule forms. Furthermore, it
is not smart about module+ or module* forms -- it might delete
outer requires that are actually needed by such submodules.

See also: @ref{racket-base-requires}.

Expand All @@ -1128,24 +1127,16 @@ See also: @ref{racket-base-requires}.

Change from ``#lang racket'' to ``#lang racket/base''.

Adds explicit requires for imports that are provided by
``racket'' but not by ``racket/base''.

This is a recommended optimization for Racket applications.
Avoiding loading all of ``racket'' can reduce load time and
memory footprint.
Using ``racket/base'' is a recommended optimization for Racket
applications. Loading all of ``racket'' is slower and uses more
memory.

Also, as does @ref{racket-trim-requires}, this removes unneeded
modules and tidies everything into a single, sorted require form.
Add explicit requires for imports that are provided by ``racket''
but not by ``racket/base''.

Note: This only works when the source file can be fully expanded
with no errors.

Note: This only works for requires at the top level of a source
file using #lang. It does NOT work for require forms inside
module forms. Furthermore, it is not smart about module+ or
module* forms -- it might delete top level requires that are
actually needed by such submodules.
Also do the equivalent of @ref{racket-trim-requires} and
@code{nil}. See those commands for additional notes
and caveats.

Note: Currently this only helps change ``#lang racket'' to
``#lang racket/base''. It does not help with other similar
Expand All @@ -1162,28 +1153,31 @@ Add a require for an identifier.
Useful when you know the name of an export but don't remember
from what module it is exported.

At the prompt:
1 At the prompt, you may:

@itemize
@item
Use @kbd{<XF86Forward>} or @kbd{<next>} or @kbd{M-n} to load the identifier at point.
You may also need to @kbd{C-e} or @kbd{<end>} to see candidates.

Or type anything.
@end itemize
You might also need to @kbd{C-e} or @kbd{<end>} to see candidates.

After you choose:
@itemize
@item
Or, type anything.

The identifier you chose is inserted at point if not already
there.
@item
After you choose, this command will:

A ``require'' form is inserted, followed by doing a
@ref{racket-tidy-requires}.
@item
Insert the identifier at point if not already there.

When more than one module supplies an identifer with the same
name, the first is used -- for example ``racket/base'' instead of
``racket''.
@item
Insert a ``require'' form and do @ref{racket-tidy-requires}.
@end itemize

Caveat: This works in terms of identifiers that are documented.
The mechanism is similar to that used for Racket's ``Search
Manuals'' feature. Today there exists no system-wide database of
Caveat: This works only for identifiers that are documented. The
mechanism is similar to that used for Racket's ``Search Manuals''
feature. Today there exists no system-wide database of
identifiers that are exported but not documented.

@node racket-indent-line
Expand Down
Loading

0 comments on commit 135fefe

Please sign in to comment.