Skip to content

Commit

Permalink
Improve racket-describe-search
Browse files Browse the repository at this point in the history
- Use exported-index-desc* and index-desc structs when available from
a sufficiently new scribble-lib. Among other things, these enable
better "kind" descriptions, and add the concept of "language
families".

- Replace the racket-describe-search-mode "disambiguation" buffer with
a completing-read that shows search metadata as completion
annotations. (The buffers were an annoying intermediate step, and
tended to remain around as litter.)

- Change dynamic-require wrappers.

- Now that we make an affixation-function in four places, add a
racket--make-affix helper.

- Change the Racket package status "manual" to "installed", for a
package that wasn't installed just as a dependency. In testing
describe-racket-package using the new racket--make-affix, I found
"manual" to be ambiguous (it implies "documentation" as well as
"manually installed vs. automatically installed as a dependency").
Furthermore "installed" matches the term used by Emacs' list-packages
and describe-package.
greghendershott committed Oct 25, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 1203449 commit 5ecbb45
Showing 21 changed files with 584 additions and 345 deletions.
2 changes: 2 additions & 0 deletions doc/generate.el
Original file line number Diff line number Diff line change
@@ -216,6 +216,8 @@
racket-pretty-print
racket-repl-command-file
"Other variables"
racket-doc-index-directory
racket-doc-index-predicate-function
racket-indent-curly-as-sequence
racket-indent-sequence-depth
racket-pretty-lambda
39 changes: 24 additions & 15 deletions doc/racket-mode.texi
Original file line number Diff line number Diff line change
@@ -243,6 +243,8 @@ REPL variables
Other variables
* racket-doc-index-directory::
* racket-doc-index-predicate-function::
* racket-indent-curly-as-sequence::
* racket-indent-sequence-depth::
* racket-pretty-lambda::
@@ -2144,21 +2146,6 @@ the Racket ``Search Manuals'' page.

Search installed documentation; view using @code{racket-describe-mode}.

Always prompts you to enter a symbol, defaulting to the symbol at
point if any.

@itemize
@item
If just one module exports the name, you go directly to a
Racket Describe buffer with its documentation.

@item
If multiple modules export the name, you go first to a
``disambiguation'' buffer similar to the Racket ``Search
Manuals'' web page. You may press RET on any item to get a
Racket Describe buffer for that module's version of the thing.
@end itemize

@node Run
@section Run

@@ -3581,6 +3568,8 @@ Name of the file used by @ref{racket-repl}.
@section Other variables

@menu
* racket-doc-index-directory::
* racket-doc-index-predicate-function::
* racket-indent-curly-as-sequence::
* racket-indent-sequence-depth::
* racket-pretty-lambda::
@@ -3591,6 +3580,26 @@ Name of the file used by @ref{racket-repl}.
* racket-sexp-comment-fade::
@end menu

@node racket-doc-index-directory
@subsection racket-doc-index-directory

Directory for @ref{racket-describe-search} doc index files.

@node racket-doc-index-predicate-function
@subsection racket-doc-index-predicate-function

A function used by @ref{racket-describe-search} to filter results.

The default value, the @code{always} function, filters nothing.

The function is given four string arguments -- TERM, WHAT,
FROM-LIBS, and FAMILIES -- and should return whether to include
the item in the list of completion candidates. An example that
limits candidates to the ``Rhombus'' family:

(lambda (@math{_term} _what _from-libs families)
(string-equal families ``Rhombus'')

@node racket-indent-curly-as-sequence
@subsection racket-indent-curly-as-sequence

92 changes: 92 additions & 0 deletions racket-complete.el
Original file line number Diff line number Diff line change
@@ -89,6 +89,98 @@ displaying inappropriate annotations."
(_
(complete-with-action action completions prefix predicate)))))

(defun racket--make-affix (specs &optional prop)
"Make an affixation-function to show completion annotations.
For more information about affixation-function completion
metadata, see Info node `(elisp)Programmed Completion'.
PROP is the symbol name of a text property that must be attached
to each of the completion candidate strings. The value of the
property is a list of strings -- each string is a suffix column
value to show as an annotation. The list length must be the same
for all candidate strings. The property name defaults to
\\='racket-affix.
SPECS is a vector of specs for each column -- one for the
completion candidate string, plus the length of the list of
suffix columns. Each spec may be an integer, which is a minimum
width, or [WIDTH FACE]. Note: The width is N/A for the last
suffix column. The face is N/A for the first column, which shows
the candidate string. For suffix columns, the face defaults to
completions-anntoations. An explicit nil value in the spec means
not to add a face, because the string is already propertized with
one.
The affixation-function arranges for each suffix column to be
aligned, considering the minimum width and the maximum width of
the previous column.
When a candidate string ends with text made invisible by a
\\='display \"\" property -- as is done by
`racket--doc-index-make-alist' -- that text is ignored for
purposes of calculating widths."
;; Note: Below we use `cl-loop' because `seq-do-indexed' and
;; `seq-map-indexed' are unavailable in Emacs 25.
(let ((min-widths (cl-loop
for spec across specs
collect (pcase spec
(`[,width ,_face] width)
((and (pred numberp) width) width)
(_ 0))))
(suffix-faces (cl-loop for spec across (seq-drop specs 1)
collect (pcase spec
(`[,_width ,face] face)
(_ 'completions-annotations))))
(prop (or prop 'racket-affix)))
(lambda (strs)
(let* ((max-widths (apply #'vector min-widths))
(rows
(cl-loop
for str in strs
collect
(let ((visible-str
(substring str
0
(text-property-any 0 (length str)
'display ""
str)))
(suffixes (get-text-property 0 prop str)))
;; Mutate `max-widths'.
(cl-loop
for col in (cons visible-str suffixes)
for ix from 0
do (aset max-widths ix
(max (aref max-widths ix)
(1+ (length col)))))
(cons str suffixes))))
(suffix-offsets
(let ((offset 0))
(cl-loop
for max-width across max-widths
collect
(setq offset (+ offset max-width))))))
(cl-loop
for row in rows
collect
(pcase-let*
((`(,str . ,suffixes) row)
(suffixes-str
(cl-loop
for suffix in suffixes
for offset in suffix-offsets
for face in suffix-faces
concat
(concat
(propertize " "
'display
`(space :align-to ,offset))
(if face
(propertize (or suffix "")
'face face)
(or suffix ""))))))
(list str "" suffixes-str)))))))

(provide 'racket-complete)

;; racket-complete.el ends here
35 changes: 35 additions & 0 deletions racket-custom.el
Original file line number Diff line number Diff line change
@@ -222,6 +222,28 @@ Scribble text, use the face `racket-hash-lang-text'."
:type '(alist :key-type symbol :value-type face)
:safe #'listp)

(defcustom racket-doc-index-directory
(locate-user-emacs-file (file-name-as-directory "racket-mode"))
"Directory for `racket-describe-search' doc index files."
:type 'file)

(defcustom racket-doc-index-predicate-function
'always
"A function used by `racket-describe-search' to filter results.
The default value, the `always' function, filters nothing.
The function is given four string arguments -- TERM, WHAT,
FROM-LIBS, and FAMILIES -- and should return whether to include
the item in the list of completion candidates. An example that
limits candidates to the \"Rhombus\" family:
(lambda (_term _what _from-libs families)
(string-equal families \"Rhombus\")
"
:type 'function
:risky t)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; racket-repl group

@@ -595,6 +617,7 @@ ignore POS. Examples: `racket-show-echo-area' and
:group 'racket)

(defmacro defface-racket (id facespec docstr)
(declare (indent defun))
`(progn
(defconst ,id ',id)
(defface ,id
@@ -803,6 +826,18 @@ See the variable `racket-browse-url-function'.")
'((t (:inherit default)))
"Face `racket-hash-lang-mode' uses for text tokens.")

(defface-racket racket-describe-search-kind
'((t (:inherit font-lock-type-face)))
"Face `racket-describe-search' uses for kinds.")

(defface-racket racket-describe-search-from-libs
'((t (:inherit font-lock-string-face)))
"Face `racket-describe-search' uses for library modules.")

(defface-racket racket-describe-search-lang-fams
'((t (:inherit font-lock-doc-face)))
"Face `racket-describe-search' uses for language families.")

(provide 'racket-custom)

;;; racket-custom.el ends here
Loading

0 comments on commit 5ecbb45

Please sign in to comment.