1144 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			EmacsLisp
		
	
	
	
	
	
		
		
			
		
	
	
			1144 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			EmacsLisp
		
	
	
	
	
	
|   | ;; $Id: scribble.el,v 1.49 2015/11/03 17:54:56 user Exp $ | ||
|  | 
 | ||
|  | (defconst scribble-mode-title   "Racket Scribble Emacs Mode") | ||
|  | (defconst scribble-mode-version "0.6") | ||
|  | (defconst scribble-mode-date    "2016-02-19") | ||
|  | (defconst scribble-mode-web     "http://www.neilvandyke.org/scribble-emacs/") | ||
|  | 
 | ||
|  | (defconst scribble-mode-legal-notices | ||
|  |   "Copyright (c) 2011, 2013, 2015, 2016 Neil Van Dyke.  This program is Free
 | ||
|  | Software; you can redistribute it and/or modify it under the terms of the GNU | ||
|  | Lesser General Public License as published by the Free Software Foundation; | ||
|  | either version 3 of the License (LGPL 3), or (at your option) any later | ||
|  | version. This program is distributed in the hope that it will be useful, but | ||
|  | without any warranty; without even the implied warranty of merchantability or | ||
|  | fitness for a particular purpose.  See http://www.gnu.org/licenses/ for | ||
|  | details.  For other licenses and consulting, please contact the author.")
 | ||
|  | 
 | ||
|  | ;; TODO: !!! 2016-02-19 Recover documentation from old PLaneT package. | ||
|  | 
 | ||
|  | ;; Note: Changes to above info must be reflected in "scribble-emacs.scrbl" | ||
|  | ;; and "info.rkt". | ||
|  | 
 | ||
|  | ;;-------------------------------------------------------------------- Requires | ||
|  | 
 | ||
|  | (require 'eldoc) | ||
|  | 
 | ||
|  | ;;---------------------------------------------------------------------- Custom | ||
|  | 
 | ||
|  | (defgroup scribble | ||
|  |   nil | ||
|  |   "Racket Scribble Emacs Mode" | ||
|  |   :group 'wp | ||
|  |   :prefix "scribble-") | ||
|  | 
 | ||
|  | (defface scribble-comment-face | ||
|  |   '((t :foreground "cyan")) | ||
|  |   "Face for Comments in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-at-keyword-face | ||
|  |   '((t :weight bold :foreground "gray50")) | ||
|  |   "Face for `@'-and-name in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-square-bracket-face | ||
|  |   '((t :weight bold :foreground "#c48080")) | ||
|  |   "Face for square brackets in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-curly-brace-face | ||
|  |   '((t :weight bold :foreground "#c48080")) | ||
|  |   "Face for curly braces in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-title-face | ||
|  |   '((t :family "DejaVu Serif" :height 2.0736 :slant italic)) | ||
|  |   "Face for titles in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-section-heading-face | ||
|  |   '((t :family "DejaVu Serif" :height 2.0736 :weight bold)) | ||
|  |   "Face for section headings in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-subsection-heading-face | ||
|  |   '((t :family "DejaVu Serif" :height 1.728 :weight bold)) | ||
|  |   "Face for subsection headings in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-subsubsection-heading-face | ||
|  |   '((t :family "DejaVu Serif" :height 1.44 :weight bold)) | ||
|  |   "Face for subsubsection headings in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-sub*section-heading-face | ||
|  |   '((t :family "DejaVu Serif" :height 1.2 :weight bold)) | ||
|  |   "Face for deep-subsection headings in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-bold-face | ||
|  |   '((t  :weight bold)) | ||
|  |   "Face for @bold in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-emph-face | ||
|  |   '((t  :slant italic)) | ||
|  |   "Face for @emph in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-tt-face | ||
|  |   '((t  :family "DejaVu Sans Mono")) | ||
|  |   "Face for @tt in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-link-text-face | ||
|  |   '((t :underline t :foreground "blue")) | ||
|  |   "Face for link text in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-planet-face | ||
|  |   '((t)) | ||
|  |   "Face for @PLaneT in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-racket-result-face | ||
|  |   '((t :foreground "blue3")) | ||
|  |   "Face for Racket results in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-racket-value-face | ||
|  |   '((t :foreground "green2")) | ||
|  |   "Face for Racket values in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-bnf-nonterm-face | ||
|  |   '((t :slant italic)) | ||
|  |   "Face for @nonterm in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-racket-litchar-face | ||
|  |   '((t :foreground "#aaaa00" | ||
|  |        :background "#f4f4f4" | ||
|  |        :slant      normal | ||
|  |        :weight     normal)) | ||
|  |   "Face for @litchar in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | ;; Quickref Faces: | ||
|  | 
 | ||
|  | ;; (defface scribble-quickref-default-face | ||
|  | ;;   '((t :family     "DejaVu Sans" | ||
|  | ;;        :foreground "#000000" | ||
|  | ;;        :background "#e8e8ff" | ||
|  | ;;        :weight     normal | ||
|  | ;;        :slant      normal)) | ||
|  | ;;   "Face for Quickref in Scribble mode." | ||
|  | ;;   :group 'scribble) | ||
|  | 
 | ||
|  | ;; (defface scribble-quickref-meta-face | ||
|  | ;;   '((t :inherit    scribble-quickref-default-face | ||
|  | ;;        :foreground "#000000")) | ||
|  | ;;   "Face for Quickref !!! in Scribble mode." | ||
|  | ;;   :group 'scribble) | ||
|  | 
 | ||
|  | ;; (defface scribble-quickref-literal-face | ||
|  | ;;   '((t :family     "DejaVu Sans Mono" | ||
|  | ;;        :inherit    scribble-quickref-default-face | ||
|  | ;;        :foreground "red4" | ||
|  | ;;        :weight     bold)) | ||
|  | ;;   "Face for Quickref !!! in Scribble mode." | ||
|  | ;;   :group 'scribble) | ||
|  | 
 | ||
|  | ;; (defface scribble-quickref-value-face | ||
|  | ;;   '((t :family     "DejaVu Sans Mono" | ||
|  | ;;        :inherit    scribble-quickref-default-face | ||
|  | ;;        :foreground "green4")) | ||
|  | ;;   "Face for Quickref !!! in Scribble mode." | ||
|  | ;;   :group 'scribble) | ||
|  | 
 | ||
|  | ;; (defface scribble-quickref-at-face | ||
|  | ;;   '((t :inherit    scribble-quickref-literal-face)) | ||
|  | ;;   "Face for Quickref !!! in Scribble mode." | ||
|  | ;;   :group 'scribble) | ||
|  | 
 | ||
|  | ;; (defface scribble-quickref-keyword-face | ||
|  | ;;   '((t :family     "DejaVu Sans" | ||
|  | ;;        :inherit    scribble-quickref-literal-face)) | ||
|  | ;;   "Face for Quickref !!! in Scribble mode." | ||
|  | ;;   :group 'scribble) | ||
|  | 
 | ||
|  | ;; (defface scribble-quickref-form-name-face | ||
|  | ;;   '((t :inherit scribble-quickref-default-face | ||
|  | ;;        :foreground "blue4" | ||
|  | ;;        :weight  bold)) | ||
|  | ;;   "Face for Quickref !!! in Scribble mode." | ||
|  | ;;   :group 'scribble) | ||
|  | 
 | ||
|  | ;; (defface scribble-quickref-type-face | ||
|  | ;;   '((t :inherit    scribble-quickref-default-face | ||
|  | ;;        :foreground "blue")) ;!!! | ||
|  | ;;   "Face for Quickref !!! in Scribble mode." | ||
|  | ;;   :group 'scribble) | ||
|  | 
 | ||
|  | ;; (defface scribble-quickref-arg-face | ||
|  | ;;   '((t :inherit    scribble-quickref-default-face | ||
|  | ;;        :slant      italic | ||
|  | ;;        :foreground "blue2")) | ||
|  | ;;   "Face for Quickref !!! in Scribble mode." | ||
|  | ;;   :group 'scribble) | ||
|  | 
 | ||
|  | ;; ElDoc Faces: | ||
|  | 
 | ||
|  | (defface scribble-eldoc-default-face | ||
|  |   '((t :family     "DejaVu Sans" | ||
|  |        :foreground "#000000" | ||
|  |        :background "#fffff0" | ||
|  |        :weight     normal | ||
|  |        :slant      normal)) | ||
|  |   "Face for ElDoc in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-eldoc-literal-face | ||
|  |   '((t :inherit    scribble-eldoc-default-face)) | ||
|  |   "Face for ElDoc literals in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-eldoc-meta-face | ||
|  |   '((t :inherit    scribble-eldoc-default-face | ||
|  |        :foreground "#4040ff")) | ||
|  |   "Face for ElDoc metasyntactic symbols in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | (defface scribble-eldoc-nonterminal-face | ||
|  |   '((t :inherit scribble-eldoc-default-face | ||
|  |        :slant   italic)) | ||
|  |   "Face for ElDoc nonterminals in Scribble mode." | ||
|  |   :group 'scribble) | ||
|  | 
 | ||
|  | ;;---------------------------------------------------- Customization Procedures | ||
|  | 
 | ||
|  | (defun scribble-customize () | ||
|  |   (interactive) | ||
|  |   (customize-group 'scribble)) | ||
|  | 
 | ||
|  | ;; TODO: Implement making any non-face changes take effect. | ||
|  | 
 | ||
|  | ;;-------------------------------------------------------------- Scribble Forms | ||
|  | 
 | ||
|  | (defsubst scribble-get-form-name (form) (aref form 0)) | ||
|  | (defsubst scribble-get-form-args (form) (aref form 1)) | ||
|  | (defsubst scribble-get-form-type (form) (aref form 2)) | ||
|  | (defsubst scribble-get-form-face (form) (aref form 3)) | ||
|  | 
 | ||
|  | ;; TODO: Maybe make types be strings. | ||
|  | 
 | ||
|  | (defsubst scribble-get-formarg-kind    (arg) (aref arg 0)) | ||
|  | (defsubst scribble-get-formarg-name    (arg) (aref arg 1)) | ||
|  | (defsubst scribble-get-formarg-type    (arg) (aref arg 2)) | ||
|  | (defsubst scribble-get-formarg-default (arg) (aref arg 3)) | ||
|  | 
 | ||
|  | ;; Note: The information is from Racket 5.0.2 Scribble documentation. | ||
|  | 
 | ||
|  | (defconst scribble-style-form-type | ||
|  |   '(or/c style? f string? symbol? (listof symbol?))) | ||
|  | 
 | ||
|  | (defconst scribble-optional-style-form-arg | ||
|  |   `[k style ,scribble-style-form-type "#f"]) | ||
|  | 
 | ||
|  | (defconst scribble-optional-underline?-form-arg | ||
|  |   `[k underline? any/c "#t"]) | ||
|  | 
 | ||
|  | (defconst scribble-optional-tag-form-arg | ||
|  |   `[k tag (or/c false/c string? (listof string?)) "#f"]) | ||
|  | 
 | ||
|  | (defconst scribble-heading-form-args | ||
|  |   `(,scribble-optional-tag-form-arg | ||
|  |     [k tag-prefix (or/c false/c string? module-path?) "#f"] | ||
|  |     ,scribble-optional-style-form-arg)) | ||
|  | 
 | ||
|  | ;; TODO: Support more than just "scribble/base". | ||
|  | 
 | ||
|  | (defconst scribble-base-forms | ||
|  |   `( | ||
|  |     ;; scribble/base | ||
|  |     ;; file:///usr/local/racket-5.0.2/share/racket/doc/scribble/base.html | ||
|  | 
 | ||
|  |     [title (,@scribble-heading-form-args | ||
|  |             [k version (or/c string? false/c) "#f"] | ||
|  |             [p -       pre-content?           -] | ||
|  |             ...) | ||
|  |            title-decl? | ||
|  |            scribble-title-face] | ||
|  |     [section       (,@scribble-heading-form-args | ||
|  |                     [p - pre-content? -] | ||
|  |                     ...) | ||
|  |                    part-start? | ||
|  |                    scribble-section-heading-face] | ||
|  |     [subsection    (,@scribble-heading-form-args | ||
|  |                     [p - pre-content? -] | ||
|  |                     ...) | ||
|  |                    part-start? | ||
|  |                    scribble-subsection-heading-face] | ||
|  |     [subsubsection (,@scribble-heading-form-args | ||
|  |                     [p - pre-content? -] | ||
|  |                     ...) | ||
|  |                    part-start? | ||
|  |                    scribble-subsubsection-heading-face] | ||
|  |     [sub*section   (,@scribble-heading-form-args | ||
|  |                     [p - pre-content? -] | ||
|  |                     ...) | ||
|  |                    part-start? | ||
|  |                    scribble-sub*section-heading-face] | ||
|  |     [author ([p - content? -]) | ||
|  |             block? | ||
|  |             nil] | ||
|  |     [author+email ([p author     elem    -] | ||
|  |                    [p email      string? -] | ||
|  |                    [k obfuscate? any/c   "#f"]) | ||
|  |                   element? | ||
|  |                   nil] | ||
|  |     [para (,scribble-optional-style-form-arg | ||
|  |            [p - pre-content? -] | ||
|  |            ...) | ||
|  |           paragraph? | ||
|  |           nil] | ||
|  |     [nested (,scribble-optional-style-form-arg | ||
|  |              [p - pre-flow? -] | ||
|  |              ...) | ||
|  |             nested-flow? | ||
|  |             nil] | ||
|  |     [centered ([p - pre-flow? -] | ||
|  |                ...) | ||
|  |               nested-flow? | ||
|  |               nil] | ||
|  |     [margin-note ([p - pre-flow? -] | ||
|  |                   ...) | ||
|  |                  block? | ||
|  |                  nil] | ||
|  |     [margin-note* ([p - pre-content? -] | ||
|  |                    ...) | ||
|  |                   element? | ||
|  |                   nil] | ||
|  |     [itemlist ([p - item? -] | ||
|  |                ... | ||
|  |                ,scribble-optional-style-form-arg) | ||
|  |               itemization? | ||
|  |               nil] | ||
|  |     [item ([p - pre-flow? -] | ||
|  |            ...) | ||
|  |           item? | ||
|  |           nil] | ||
|  |     [tabular ([p cells (listof (listof (or/c block? content? 'cont))) -] | ||
|  |               ,scribble-optional-style-form-arg) | ||
|  |              table? | ||
|  |              nil] | ||
|  |     [verbatim ([p indent exact-nonnegative-integer? "0"] | ||
|  |                [p -      string?                    -] | ||
|  |                ...) | ||
|  |               block? | ||
|  |               nil] | ||
|  |     [elem ([p - pre-content? -] | ||
|  |            ... | ||
|  |            ,scribble-optional-style-form-arg) | ||
|  |           element? | ||
|  |           nil] | ||
|  |     [italic ([p - pre-content? -] | ||
|  |              ...) | ||
|  |             element? | ||
|  |             nil] | ||
|  |     [bold ([p - pre-content? -] | ||
|  |            ...) | ||
|  |           element? | ||
|  |           scribble-bold-face] | ||
|  |     [code ([p - pre-content? -] | ||
|  |            ...) | ||
|  |           element? | ||
|  |           nil] | ||
|  |     [codeblock ([p - pre-content? -] | ||
|  |                 ...) | ||
|  |                element? | ||
|  |                nil] | ||
|  |     [tt ([p - pre-content? -] | ||
|  |          ...)  | ||
|  |         element? | ||
|  |         scribble-tt-face] | ||
|  |     [subscript ([p - pre-content? -] | ||
|  |                 ...)  | ||
|  |                element? | ||
|  |                nil] | ||
|  |     [superscript ([p - pre-content? -] | ||
|  |                   ...)  | ||
|  |                  element? | ||
|  |                  nil] | ||
|  |     [smaller ([p - pre-content? -] | ||
|  |               ...)  | ||
|  |              element? | ||
|  |              nil] | ||
|  |     [larger ([p - pre-content? -] | ||
|  |              ...)  | ||
|  |             element? | ||
|  |             nil] | ||
|  |     [emph ([p - pre-content? -] | ||
|  |            ...)  | ||
|  |           element? | ||
|  |           scribble-emph-face] | ||
|  |     [linebreak () | ||
|  |                element? | ||
|  |                nil] | ||
|  |     [hspace ([p - exact-nonnegative-integer? -]) | ||
|  |             element? | ||
|  |             nil] | ||
|  |     [literal ([p - string? -] | ||
|  |               ...)  | ||
|  |              element? | ||
|  |              nil] | ||
|  |     [image | ||
|  |      ([p path     (or/c path-string? (cons/c 'collects (listof bytes?))) -] | ||
|  |       [k scale    real?                "1.0"] | ||
|  |       [k suffixes (listof (rx "^[.]")) "null"] | ||
|  |       [p -        pre-content?         -] | ||
|  |       ...) | ||
|  |      element? | ||
|  |      nil] | ||
|  |     [hyperlink ([p url string?      -] | ||
|  |                 [p -   pre-content? -] | ||
|  |                 ... | ||
|  |                 ,scribble-optional-underline?-form-arg | ||
|  |                 [k style | ||
|  |                    (or/c style? string? symbol? false/c) | ||
|  |                    "(if underline? #f \"plainlink\")"]) | ||
|  |                element? | ||
|  |                scribble-link-text-face] | ||
|  |     [url ([p dest string? -]) | ||
|  |          element? | ||
|  |          nil] | ||
|  |     [secref ([p tag          string                          -] | ||
|  |              [k doc          (or/c module-path? false/c)     "#f"] | ||
|  |              [k tag-prefixes (or/c (listof string?) false/c) "#f"] | ||
|  |              ,scribble-optional-underline?-form-arg) | ||
|  |             element? | ||
|  |             scribble-link-text-face] | ||
|  |     [seclink ([p tag          string?                         -] | ||
|  |               [k doc          (or/c module-path? false/c)     "#f"] | ||
|  |               [k tag-prefixes (or/c (listof string?) false/c) "#f"] | ||
|  |               ,scribble-optional-underline?-form-arg | ||
|  |               [p -            pre-content?                    -] | ||
|  |               ...) | ||
|  |              element? | ||
|  |              scribble-link-text-face] | ||
|  |     [other-doc ([p module-path module-path? -] | ||
|  |                 ,scribble-optional-underline?-form-arg) | ||
|  |                element? | ||
|  |                nil] | ||
|  |     [elemtag ([p t (or/c tag? string?) -] | ||
|  |               [p - pre-content?        -] | ||
|  |               ...) | ||
|  |              element? | ||
|  |              nil] | ||
|  |     [elemref ([p t (or/c tag? string?) -] | ||
|  |               [p - pre-content?        -] | ||
|  |               ... | ||
|  |               ,scribble-optional-underline?-form-arg) | ||
|  |              element? | ||
|  |              nil] | ||
|  |     [index ([p words (or/c string? (listof string?)) -] | ||
|  |             [p -     pre-content?                    -] | ||
|  |             ...) | ||
|  |            index-element? | ||
|  |            nil] | ||
|  |     [index* ([p words         (listof string?) -] | ||
|  |              [p word-contents (listof list?)   -] | ||
|  |              [p -             pre-content?     -] | ||
|  |              ...) | ||
|  |             index-element? | ||
|  |             nil] | ||
|  |     [as-index ([p - pre-content? -] | ||
|  |                ...) | ||
|  |               index-element? | ||
|  |               nil] | ||
|  |     [section-index ([p word string? -] | ||
|  |                     ...) | ||
|  |                    part-index-decl? | ||
|  |                    nil] | ||
|  |     [index-section ([k tag (or/c false/c string?) "\"doc-index\""] | ||
|  |                     ,scribble-optional-tag-form-arg) | ||
|  |                    part? | ||
|  |                    nil] | ||
|  |     [table-of-contents () | ||
|  |                        delayed-block? | ||
|  |                        nil] | ||
|  |     [local-table-of-contents (,scribble-optional-style-form-arg) | ||
|  |                              delayed-block? | ||
|  |                              nil])) | ||
|  | 
 | ||
|  | (defconst scribble-manual-forms | ||
|  |   `( | ||
|  | 
 | ||
|  |     [racketblock  ([p - datum? -] ...) any/c nil] | ||
|  |     [RACKETBLOCK  ([p - datum? -] ...) any/c nil] | ||
|  |     [racketblock0 ([p - datum? -] ...) any/c nil] | ||
|  |     [RACKETBLOCK0 ([p - datum? -] ...) any/c nil] | ||
|  | 
 | ||
|  |     [racketresultblock  ([p - datum? -] ...) any/c nil] | ||
|  |     [RACKETRESULTBLOCK  ([p - datum? -] ...) any/c nil] | ||
|  |     [racketresultblock0 ([p - datum? -] ...) any/c nil] | ||
|  |     [RACKETRESULTBLOCK0 ([p - datum? -] ...) any/c nil] | ||
|  | 
 | ||
|  |     [racketinput ([p - datum? -] ...) any/c nil] | ||
|  |     [RACKETINPUT ([p - datum? -] ...) any/c nil] | ||
|  |      | ||
|  |     [racketmod ([k file string? "#f"] | ||
|  |                 [p -    datum?  -] | ||
|  |                 ...) | ||
|  |                any/c | ||
|  |                nil] | ||
|  | 
 | ||
|  |     [racket ([p - datum? -] ...) any/c nil] | ||
|  |     [RACKET ([p - datum? -] ...) any/c nil] | ||
|  | 
 | ||
|  |     ;; TODO: For "racketresult" and "racketid", maybe override body faces. | ||
|  |     [racketresult ([p - datum? -] ...) any/c scribble-racket-result-face] | ||
|  |     [racketid     ([p - datum? -] ...) any/c nil] | ||
|  | 
 | ||
|  |     [racketmodlink ([p - datum?            -] | ||
|  |                     [p - pre-content-expr? -] | ||
|  |                     ...) | ||
|  |                    any/c | ||
|  |                    nil] | ||
|  | 
 | ||
|  |     [litchar ([p - string? -] ...) element? scribble-racket-litchar-face] | ||
|  | 
 | ||
|  |     [racketfont        ([p - pre-content? -] ...) element? nil] | ||
|  |     [racketvalfont     ([p - pre-content? -] ...) element? scribble-racket-value-face] | ||
|  |     [racketresultfont  ([p - pre-content? -] ...) element? scribble-racket-result-face] | ||
|  |     [racketidfont      ([p - pre-content? -] ...) element? nil] | ||
|  |     [racketvarfont     ([p - pre-content? -] ...) element? nil] | ||
|  |     [racketkeywordfont ([p - pre-content? -] ...) element? nil] | ||
|  |     [racketparenfont   ([p - pre-content? -] ...) element? nil] | ||
|  |     [racketmetafont    ([p - pre-content? -] ...) element? nil] | ||
|  |     [racketerror       ([p - pre-content? -] ...) element? nil] | ||
|  |     [racketmodfont     ([p - pre-content? -] ...) element? nil] | ||
|  |     [racketoutputfont  ([p - pre-content? -] ...) element? nil] | ||
|  |     ;; TODO: Define faces for some of the above? | ||
|  | 
 | ||
|  |     ;; TODO: We could use overlays to make "@procedure" content have | ||
|  |     ;; "#<procedure:" and ">". | ||
|  |     [procedure         ([p - pre-content? -] ...) element? nil] | ||
|  | 
 | ||
|  |     [var  ([p - datum? -] ...) element? nil] | ||
|  |     [svar ([p - datum? -] ...) element? nil] | ||
|  |      | ||
|  |     ;; TODO: Possibly add support for all the "scheme" backword-compatibility | ||
|  |     ;; identifiers. | ||
|  | 
 | ||
|  |     ;; TODO: !!! CONTINUE ADDING AFTER | ||
|  |     ;; file:///usr/local/racket-5.0.2/share/racket/doc/scribble/scribble_manual_code.html | ||
|  | 
 | ||
|  |     )) | ||
|  | 
 | ||
|  | (defconst scribble-bnf-forms | ||
|  |   `([BNF ([p - (cons element? (listof element?)) -] ...) table? nil] | ||
|  | 
 | ||
|  |     [nonterm   ([p - pre-content? -] ...) element? scribble-bnf-nonterm-face] | ||
|  |     [BNF-seq   ([p - element?     -] ...) element? nil] | ||
|  |     [BNF-group ([p - pre-content? -] ...) element? nil] | ||
|  | 
 | ||
|  |     [optional   ([p - pre-content? -] ...) element? nil] | ||
|  |     [kleenestar ([p - pre-content? -] ...) element? nil] | ||
|  |     [kleeneplus ([p - pre-content? -] ...) element? nil] | ||
|  | 
 | ||
|  |     [kleenerange ([p n any/c        -] | ||
|  |                   [p m any/c        -] | ||
|  |                   [p - pre-content? -] | ||
|  |                   ...) | ||
|  |                  element? | ||
|  |                  nil] | ||
|  | 
 | ||
|  |     [BNF-alt ([p - element? -] ...) element? nil] | ||
|  |     [BNF-etc ([p - string? -]) void scribble-comment-face])) | ||
|  | 
 | ||
|  | (defconst scribble-forms | ||
|  |   `(,@scribble-base-forms | ||
|  |     ,@scribble-manual-forms | ||
|  |     ,@scribble-bnf-forms)) | ||
|  | 
 | ||
|  | (defconst scribble-name-string-to-form-hash | ||
|  |   (let ((ht (make-hash-table :test 'equal))) | ||
|  |     (mapc (lambda (form) | ||
|  |             (puthash (symbol-name (scribble-get-form-name form)) form ht)) | ||
|  |           scribble-forms) | ||
|  |     ht)) | ||
|  | 
 | ||
|  | (defun scribble-minus-to-nil (x) | ||
|  |   (if (eq x '-) nil x)) | ||
|  | 
 | ||
|  | (defun scribble-form-type-to-racket (type) | ||
|  |   ;; TODO: translate true, false, rx, quote.  Or convert types to strings. | ||
|  |   (format "%s" type)) | ||
|  | 
 | ||
|  | ;;---------------------------------------------------------------- Syntax Table | ||
|  | 
 | ||
|  | (defvar scribble-mode-syntax-table | ||
|  |   (let ((st (make-syntax-table))) | ||
|  |      | ||
|  |     (modify-syntax-entry ?   " " st) | ||
|  |     (modify-syntax-entry ?\t " " st) | ||
|  |     (modify-syntax-entry ?\f " " st) | ||
|  |     (modify-syntax-entry ?\n ">" st) | ||
|  |      | ||
|  |     (modify-syntax-entry ?\" "." st) | ||
|  |      | ||
|  |     (modify-syntax-entry ?\@ "_ 1" st) | ||
|  |     (modify-syntax-entry ?\# "_ 1" st) | ||
|  |     (modify-syntax-entry ?\: "_ 1" st) | ||
|  |     (modify-syntax-entry ?\; ". 2" st) | ||
|  |      | ||
|  |     (modify-syntax-entry ?\( "()" st) | ||
|  |     (modify-syntax-entry ?\) ")(" st) | ||
|  |     (modify-syntax-entry ?\[ "(]" st) | ||
|  |     (modify-syntax-entry ?\] ")[" st) | ||
|  |     (modify-syntax-entry ?\{ "(}" st) | ||
|  |     (modify-syntax-entry ?\} "){" st) | ||
|  |      | ||
|  |     st)) | ||
|  | 
 | ||
|  | ;;------------------------------------------------------------- Forms Reference | ||
|  | 
 | ||
|  | ;; (defun scribble-forms-reference () | ||
|  | ;;   (interactive) | ||
|  | ;;   (scribble-buffer-display | ||
|  | ;;    "*Scribble Forms Reference*" | ||
|  | ;;    (function | ||
|  | ;;     (lambda () | ||
|  | ;;       (mapc (lambda (form) | ||
|  | ;;               (insert (scribble-form-quickref-text form) "\n\n")) | ||
|  | ;;             scribble-forms))))) | ||
|  | 
 | ||
|  | ;;------------------------------------------------------------------- Mode Menu | ||
|  | 
 | ||
|  | (defvar scribble-mode-menu | ||
|  |   (let ((km (make-sparse-keymap "Scribble"))) | ||
|  | 
 | ||
|  |     (define-key km [scribble-about] | ||
|  |       '(menu-item "About Scribble Emacs Mode..." scribble-about | ||
|  |                   :help "See information about Scribble Emacs mode")) | ||
|  | 
 | ||
|  |     (define-key km [scribble-browse-mode-web] | ||
|  |       '(menu-item "Browse Scribble Emacs Mode Web..." scribble-browse-mode-web | ||
|  |                   :help "Browse Web pages for Scribble Emacs mode")) | ||
|  | 
 | ||
|  |     ;; TODO: Browse/search scribble docs. | ||
|  | 
 | ||
|  |     (define-key km [scribble-separator-2] | ||
|  |       `(menu-item "--")) | ||
|  | 
 | ||
|  |     ;; TODO: Experiment with this.  Use local variable "scribble-modules" to | ||
|  |     ;; specify in files, and update it programmatically from this interface. | ||
|  |     ;; Can also have operation that scans "#lang" and "@(require" to determine | ||
|  |     ;; or update this variable.  Unfortunately can't use "-*-" line because | ||
|  |     ;; Emacs currently (GNU 23.2) doesn't support it occuring after the "#lang" | ||
|  |     ;; line. | ||
|  |     (define-key km [scribble-forms-bnf] | ||
|  |       '(menu-item "scribble/bnf" nil | ||
|  |                   :enable nil | ||
|  |                   :button (:toggle . t) | ||
|  |                   :help "!!!")) | ||
|  |     (define-key km [scribble-forms-manual] | ||
|  |       '(menu-item "scribble/manual" nil | ||
|  |                   :enable nil | ||
|  |                   :button (:toggle . nil) | ||
|  |                   :help "!!!")) | ||
|  |     (define-key km [scribble-forms-base] | ||
|  |       '(menu-item "scribble/base" nil | ||
|  |                   :enable nil | ||
|  |                   :button (:toggle . t) | ||
|  |                   :help "!!!")) | ||
|  | 
 | ||
|  |     ;; (define-key km [scribble-forms-reference] | ||
|  |     ;;   '(menu-item "Forms Reference..." scribble-forms-reference | ||
|  |     ;;               :help "Show a reference of Scribble forms")) | ||
|  | 
 | ||
|  |     (define-key km [scribble-separator-1] | ||
|  |       `(menu-item "--")) | ||
|  | 
 | ||
|  |     (define-key km [scribble-customize] | ||
|  |       '(menu-item "Customize..." scribble-customize | ||
|  |                   :help "Set Emacs customization options for Scribble")) | ||
|  |     ;; TODO: Perhaps wrapping "completion-at-point" with another procedure | ||
|  |     ;; that does "call-interactively" will work. | ||
|  |     ;; | ||
|  |     ;; (define-key km [scribble-completion-at-point] | ||
|  |     ;;   `(menu-item "Completion at Point" 'completion-at-point)) | ||
|  | 
 | ||
|  |     km)) | ||
|  | 
 | ||
|  | ;;---------------------------------------------------------------------- Keymap | ||
|  | 
 | ||
|  | (defvar scribble-mode-map  | ||
|  |   (let ((km (make-sparse-keymap))) | ||
|  |     (define-key km (kbd "M-TAB") 'completion-at-point) | ||
|  |     (define-key km [menu-bar Scribble] (cons "Scribble" scribble-mode-menu)) | ||
|  |     km)) | ||
|  | 
 | ||
|  | ;;------------------------------------------------------------------- Font-Lock | ||
|  | 
 | ||
|  | ;; TODO: Should probably switch to using something other than font-lock, like | ||
|  | ;; handwritten fuzzy parser. | ||
|  | 
 | ||
|  | (defvar scribble-font-lock-keywords | ||
|  |   `( | ||
|  |      ,@(mapcar (lambda (face-to-namerxs-pair) | ||
|  |                  (let ((face (car face-to-namerxs-pair))) | ||
|  |                    `(,(concat "\\("     ; < 1 at-name | ||
|  |                               "@" | ||
|  |                               (let ((names (cdr face-to-namerxs-pair))) | ||
|  |                                 (if (cdr names) | ||
|  |                                     (regexp-opt names) | ||
|  |                                   (car names))) | ||
|  |                               "\\)"       ; > 1 at-name | ||
|  |                               "\\b" | ||
|  |                               "\\(?:"     ; < opt-squares | ||
|  |                               "\\(\\[\\)" ; = 2 open-square | ||
|  |                               "[^]]*"     ; | ||
|  |                               "\\(\\]\\)" ; = 3 close-square | ||
|  |                               "\\)?"      ; > opt-squares | ||
|  |                               "\\(?:"     ; < opt-curlies | ||
|  |                               "\\({\\)"   ; ; = 4 open-curly | ||
|  |                               (if face "\\(" "") | ||
|  |                               "[^}]*"   ; | ||
|  |                               (if face "\\)" "") | ||
|  |                               "\\(}\\)" ; = 5,6 close-curly | ||
|  |                               "\\)?"    ; > opt-curlies | ||
|  |                               ) | ||
|  |                      (1 'scribble-at-keyword-face) | ||
|  |                      (2 'scribble-square-bracket-face nil t) | ||
|  |                      (3 'scribble-square-bracket-face nil t) | ||
|  |                      (4 'scribble-curly-brace-face    nil t) | ||
|  |                      ,@(if face | ||
|  |                            `((5 (quote ,face) nil t)) | ||
|  |                          '()) | ||
|  |                      (,(if face 6 5) 'scribble-curly-brace-face nil t)))) | ||
|  |                (let ((face-to-namerxs-alist '())) | ||
|  |                  (mapc (lambda (form) | ||
|  |                          (let* ((namerx (regexp-quote | ||
|  |                                          (symbol-name (scribble-get-form-name | ||
|  |                                                        form)))) | ||
|  |                                 (face (scribble-get-form-face form)) | ||
|  |                                 (pair (assq face face-to-namerxs-alist))) | ||
|  |                            (if pair | ||
|  |                                (setcdr pair (cons namerx (cdr pair))) | ||
|  |                              (setq face-to-namerxs-alist | ||
|  |                                    `((,face . (,namerx)) | ||
|  |                                      ,@face-to-namerxs-alist))))) | ||
|  |                        scribble-forms) | ||
|  |                  face-to-namerxs-alist)) | ||
|  |      | ||
|  |     ("\\(@\\)\\(PLaneT\\)" | ||
|  |      (1 'scribble-at-keyword-face) | ||
|  |      (2 'scribble-planet-face)) | ||
|  |      | ||
|  |     ;; TODO: Is this right? | ||
|  |     ;; | ||
|  |     ;; ("\\(@\\)@" | ||
|  |     ;;  (1 'scribble-at-keyword-face)) | ||
|  |      | ||
|  |     ("\\(@#reader\\)[ ]+\\([^\r\n]+\\)" | ||
|  |      (1 'scribble-at-keyword-face) | ||
|  |      (2 'scribble-at-keyword-face)) | ||
|  |      | ||
|  |     ("\\`\\(#lang\\)[ ]+\\([^\r\n]+\\)" | ||
|  |      (1 'scribble-at-keyword-face) | ||
|  |      (2 'scribble-at-keyword-face)))) | ||
|  | 
 | ||
|  | (defvar scribble-font-lock-defaults | ||
|  |   `(scribble-font-lock-keywords nil)) | ||
|  | 
 | ||
|  | ;;----------------------------------------------------------------------- Imenu | ||
|  | 
 | ||
|  | (defvar scribble-imenu-generic-expression | ||
|  |   '((nil | ||
|  |      "@\\(?:sub\\(?:sub\\)?\\)?section\\(?:\\[[^]]*\\]\\)?{\\([^}]*\\)" | ||
|  |      1))) | ||
|  | 
 | ||
|  | ;; TODO: Use one of the lower-level ways of doing this. | ||
|  | 
 | ||
|  | ;;------------------------------------------------------------------ Characters | ||
|  | 
 | ||
|  | (defconst scribble-right-arrow-char 8594) | ||
|  | 
 | ||
|  | ;;-------------------------------------------------------------------- Quickref | ||
|  | 
 | ||
|  | ;; TODO: !!! this needs work since eldoc was forked out of this. | ||
|  | ;;  | ||
|  | ;; (defun scribble-form-type-to-quickref (type) | ||
|  | ;;   (propertize (scribble-form-type-to-racket type) | ||
|  | ;;               'face 'scribble-quickref-type-face)) | ||
|  | ;;  | ||
|  | ;; (defconst scribble-quickref-dotdotdot  | ||
|  | ;;   (propertize "..." 'face 'scribble-quickref-meta-face)) | ||
|  | ;;  | ||
|  | ;; (defconst scribble-quickref-space | ||
|  | ;;   (propertize " " 'face 'scribble-quickref-default-face)) | ||
|  | ;;  | ||
|  | ;; (defconst scribble-quickref-open-paren | ||
|  | ;;   (propertize "(" 'face 'scribble-quickref-literal-face)) | ||
|  | ;;  | ||
|  | ;; (defconst scribble-quickref-close-paren | ||
|  | ;;   (propertize ")" 'face 'scribble-quickref-literal-face)) | ||
|  | ;;  | ||
|  | ;; (defconst scribble-quickref-open-optional | ||
|  | ;;   (propertize "[" 'face 'scribble-quickref-meta-face)) | ||
|  | ;;  | ||
|  | ;; (defconst scribble-quickref-close-optional | ||
|  | ;;   (propertize "]" 'face 'scribble-quickref-meta-face)) | ||
|  | ;;  | ||
|  | ;; (defconst scribble-quickref-space-colon-space | ||
|  | ;;   (concat scribble-quickref-space | ||
|  | ;;           (propertize ":" 'face 'scribble-quickref-meta-face) | ||
|  | ;;           scribble-quickref-space)) | ||
|  | ;;  | ||
|  | ;; (defconst scribble-quickref-space-equal-space | ||
|  | ;;   (concat scribble-quickref-space | ||
|  | ;;           (propertize "=" 'face 'scribble-quickref-meta-face) | ||
|  | ;;           scribble-quickref-space)) | ||
|  | ;;  | ||
|  | ;; (defun scribble-form-arg-to-quickref (arg) | ||
|  | ;;   (if (eq arg '...) | ||
|  | ;;       scribble-quickref-dotdotdot | ||
|  | ;;     (let* ((fmt      '()) | ||
|  | ;;            (kind     (scribble-get-formarg-kind arg)) | ||
|  | ;;            (name     (scribble-minus-to-nil | ||
|  | ;;                       (scribble-get-formarg-name arg))) | ||
|  | ;;            (type     (scribble-get-formarg-type arg)) | ||
|  | ;;            (default  (scribble-minus-to-nil | ||
|  | ;;                       (scribble-get-formarg-default arg))) | ||
|  | ;;            (name-str (if name (symbol-name name) nil)) | ||
|  | ;;            (type-str (scribble-form-type-to-racket type)) | ||
|  | ;;            (type-ps  (propertize type-str | ||
|  | ;;                                  'face 'scribble-quickref-type-face))) | ||
|  | ;;       (cond ((eq kind 'p) | ||
|  | ;;              (setq fmt | ||
|  | ;;                    (if name-str | ||
|  | ;;                        `(,type-ps | ||
|  | ;;                          ,scribble-quickref-space-colon-space | ||
|  | ;;                          ,(propertize name-str  | ||
|  | ;;                                       'face | ||
|  | ;;                                       'scribble-quickref-arg-face)) | ||
|  | ;;                      `(,type-ps)))) | ||
|  | ;;             ((eq kind 'k) | ||
|  | ;;              (or name-str | ||
|  | ;;                  (error "formarg kind k must have name in %s" arg)) | ||
|  | ;;              (setq fmt | ||
|  | ;;                    `(,type-ps | ||
|  | ;;                      ,scribble-quickref-space-colon-space | ||
|  | ;;                      ,(propertize (concat "#:" name-str) | ||
|  | ;;                                   'face 'scribble-quickref-keyword-face)))) | ||
|  | ;;             (t (error "invalid formarg kind in %s" arg))) | ||
|  | ;;       (apply 'concat | ||
|  | ;;              (if default | ||
|  | ;;                  (reverse | ||
|  | ;;                   `(,(propertize default 'face 'scribble-quickref-value-face) | ||
|  | ;;                     ,scribble-quickref-space-equal-space | ||
|  | ;;                     ,@fmt)) | ||
|  | ;;                (reverse fmt)))))) | ||
|  | ;;  | ||
|  | ;; (defun scribble-form-quickref-text (form) | ||
|  | ;;   ;; TODO: !!! working on this | ||
|  | ;;   (let* ((at (propertize "@" 'face 'scribble-quickref-at-face)) | ||
|  | ;;          (space-arrow-space | ||
|  | ;;           (concat scribble-quickref-space | ||
|  | ;;                   (propertize (string scribble-right-arrow-char) | ||
|  | ;;                               'face | ||
|  | ;;                               'scribble-quickref-meta-face) | ||
|  | ;;                   scribble-quickref-space))) | ||
|  | ;;   (apply | ||
|  | ;;    'concat | ||
|  | ;;    `(,at | ||
|  | ;;      ,(propertize (symbol-name (scribble-get-form-name form)) | ||
|  | ;;                   'face 'scribble-quickref-form-name-face) | ||
|  | ;;      ,@(let ((args (scribble-get-form-args form))) | ||
|  | ;;          (if args | ||
|  | ;;              (let ((fmt '())) | ||
|  | ;;                (mapc (lambda (arg) | ||
|  | ;;                        (setq fmt `(,(scribble-form-arg-to-quickref arg) | ||
|  | ;;                                    ,scribble-quickref-space | ||
|  | ;;                                    ,@fmt))) | ||
|  | ;;                      args) | ||
|  | ;;                (reverse fmt)) | ||
|  | ;;            '())) | ||
|  | ;;      ,closeparen-space-arrow-space | ||
|  | ;;      ,(scribble-form-type-to-quickref (scribble-get-form-type form)))))) | ||
|  | 
 | ||
|  | ;;------------------------------------------------------------------------ ElDoc | ||
|  | 
 | ||
|  | (defconst scribble-eldoc-dotdotdot  | ||
|  |   (propertize "..." 'face 'scribble-eldoc-meta-face)) | ||
|  | 
 | ||
|  | (defconst scribble-eldoc-space | ||
|  |   (propertize " " 'face 'scribble-eldoc-default-face)) | ||
|  | 
 | ||
|  | (defconst scribble-eldoc-open-paren | ||
|  |   (propertize "(" 'face 'scribble-eldoc-literal-face)) | ||
|  | 
 | ||
|  | (defconst scribble-eldoc-close-paren | ||
|  |   (propertize ")" 'face 'scribble-eldoc-literal-face)) | ||
|  | 
 | ||
|  | (defconst scribble-eldoc-open-optional | ||
|  |   (propertize "[" 'face 'scribble-eldoc-meta-face)) | ||
|  | 
 | ||
|  | (defconst scribble-eldoc-close-optional | ||
|  |   (propertize "]" 'face 'scribble-eldoc-meta-face)) | ||
|  | 
 | ||
|  | (defconst scribble-eldoc-closeparen-space-arrow-space | ||
|  |   (concat scribble-eldoc-close-paren | ||
|  |           scribble-eldoc-space | ||
|  |           (propertize (string scribble-right-arrow-char) | ||
|  |                       'face | ||
|  |                       'scribble-eldoc-meta-face) | ||
|  |           scribble-eldoc-space)) | ||
|  | 
 | ||
|  | (defun scribble-form-arg-to-eldoc (arg) | ||
|  |   (if (eq arg '...) | ||
|  |       scribble-eldoc-dotdotdot | ||
|  |     (let* ((kind     (scribble-get-formarg-kind arg)) | ||
|  |            (name     (scribble-minus-to-nil (scribble-get-formarg-name arg))) | ||
|  |            (name-str (if name (symbol-name name) nil)) | ||
|  |            (id-ps | ||
|  |             (cond ((eq kind 'p) | ||
|  |                    (propertize (or name-str | ||
|  |                                    (scribble-form-type-to-racket | ||
|  |                                     (scribble-get-formarg-type arg))) | ||
|  |                                'face | ||
|  |                                'scribble-eldoc-nonterminal-face)) | ||
|  |                   ((eq kind 'k) | ||
|  |                    (propertize | ||
|  |                     (concat "#:" | ||
|  |                             (or name-str | ||
|  |                                 (error "formarg kind k must have name in %s" | ||
|  |                                        arg))) | ||
|  |                     'face 'scribble-eldoc-literal-face)) | ||
|  |                   (t (error "invalid formarg kind in %s" arg))))) | ||
|  |       (if (eq '- (scribble-get-formarg-default arg)) | ||
|  |           id-ps | ||
|  |         (concat scribble-eldoc-open-optional | ||
|  |                 id-ps | ||
|  |                 scribble-eldoc-close-optional))))) | ||
|  | 
 | ||
|  | (defun scribble-make-form-eldoc-message (form) | ||
|  |   (apply | ||
|  |    'concat | ||
|  |    `(,scribble-eldoc-open-paren | ||
|  |      ,(propertize (symbol-name (scribble-get-form-name form)) | ||
|  |                   'face 'scribble-eldoc-literal-face) | ||
|  |      ,@(let ((args (scribble-get-form-args form))) | ||
|  |          (if args | ||
|  |              (let ((fmt '())) | ||
|  |                (mapc (lambda (arg) | ||
|  |                        (setq fmt `(,(scribble-form-arg-to-eldoc arg) | ||
|  |                                    ,scribble-eldoc-space | ||
|  |                                    ,@fmt))) | ||
|  |                      args) | ||
|  |                (reverse fmt)) | ||
|  |            '())) | ||
|  |      ,scribble-eldoc-closeparen-space-arrow-space | ||
|  |      ,(propertize (scribble-form-type-to-racket (scribble-get-form-type form)) | ||
|  |                   'face | ||
|  |                   'scribble-eldoc-nonterminal-face)))) | ||
|  | 
 | ||
|  | (defconst scribble-name-to-eldoc-message-hash | ||
|  |   (let ((ht (make-hash-table :test 'equal))) | ||
|  |     (mapc (lambda (form) | ||
|  |             (puthash (symbol-name (scribble-get-form-name form)) | ||
|  |                      (scribble-make-form-eldoc-message form) | ||
|  |                      ht)) | ||
|  |           scribble-forms) | ||
|  |     ht)) | ||
|  | 
 | ||
|  | (defun scribble-get-form-eldoc-message (form) | ||
|  |   (scribble-make-form-eldoc-message form)) | ||
|  | 
 | ||
|  | (defun scribble-eldoc-documentation-function () | ||
|  |   ;; TODO: Implement this properly, figuring out which form we're in.  Might | ||
|  |   ;; wait until we implement better fontification, using the same parsing | ||
|  |   ;; mechanism. | ||
|  |   ;; | ||
|  |   ;; TODO: !!! Maybe look for "@"-name under point, and if that fails, then | ||
|  |   ;; up-sexp, and then look for an @-name to left of point (or left-sexp if | ||
|  |   ;; there is a square-bracket to left of point. | ||
|  |   (let ((word (let ((c (char-after (point)))) | ||
|  |                 (and c | ||
|  |                      (memq (char-syntax c) '(?w ?_)) | ||
|  |                      (current-word))))) | ||
|  |     (and (> (length word) 0) | ||
|  |          (equal ?@ (aref word 0)) | ||
|  |          (gethash (substring word 1) | ||
|  |                   scribble-name-to-eldoc-message-hash | ||
|  |                   nil)))) | ||
|  | 
 | ||
|  | ;;------------------------------------------------------------------ Completion | ||
|  | 
 | ||
|  | (defun scribble-build-completion-table () | ||
|  |   (sort (let ((kw-seen-hash (make-hash-table :test 'eq)) | ||
|  |               (result       '("Felleisen"))) | ||
|  |           (mapc (lambda (form) | ||
|  |                   (setq result (cons (symbol-name (scribble-get-form-name form)) | ||
|  |                                      result)) | ||
|  |                   (mapc (lambda (arg) | ||
|  |                           (and (vectorp arg) | ||
|  |                                (eq 'k (scribble-get-formarg-kind arg)) | ||
|  |                                (let ((sym (scribble-get-formarg-name arg))) | ||
|  |                                  (or (gethash sym kw-seen-hash) | ||
|  |                                      (progn (puthash sym t kw-seen-hash) | ||
|  |                                             (setq result | ||
|  |                                                   (cons (concat | ||
|  |                                                          "#:" | ||
|  |                                                          (symbol-name sym)) | ||
|  |                                                         result))))))) | ||
|  |                         (scribble-get-form-args form))) | ||
|  |                 scribble-forms) | ||
|  |           result) | ||
|  |         'string<)) | ||
|  | 
 | ||
|  | (defconst scribble-completion-table (scribble-build-completion-table)) | ||
|  | 
 | ||
|  | (defconst scribble-completion-at-point-tail  | ||
|  |   (list scribble-completion-table | ||
|  |         ;; :annotation-function 'scribble-completion-annotate-function | ||
|  |         )) | ||
|  | 
 | ||
|  | (defun scribble-completion-at-point-function () | ||
|  |   (let* ((end (point)) | ||
|  |          (start (let ((c (char-before end))) | ||
|  |                   (if (and c (memq (char-syntax c) '(?w ?_))) | ||
|  |                       (save-excursion | ||
|  |                         (backward-sexp 1) | ||
|  |                         (and (eq ?\@ (char-after (point))) | ||
|  |                              (forward-char 1)) | ||
|  |                         (point)) | ||
|  |                     end)))) | ||
|  |     `(,start ,end ,@scribble-completion-at-point-tail))) | ||
|  | 
 | ||
|  | ;;-------------------------------------------------------------- Buffer Display | ||
|  | 
 | ||
|  | (defun scribble-buffer-display (name proc) | ||
|  |   (save-excursion | ||
|  |     (set-buffer (get-buffer-create name)) | ||
|  |     (toggle-read-only 0) | ||
|  |     (buffer-disable-undo) | ||
|  |     (goto-char (point-min)) | ||
|  |     (delete-region (point-min) (point-max)) | ||
|  |     (funcall proc) | ||
|  |     (buffer-enable-undo) | ||
|  |     (set-buffer-modified-p nil) | ||
|  |     (toggle-read-only 1) | ||
|  |     (goto-char (point-min)) | ||
|  |     ;; TODO: Maybe make "q" restore window config. | ||
|  |     (local-set-key "q" 'scribble-quit-buffer-display) | ||
|  |     (pop-to-buffer (current-buffer)) | ||
|  |     (message "Press \"q\" to quit the \"%s\" buffer." name))) | ||
|  | 
 | ||
|  | (defun scribble-quit-buffer-display () | ||
|  |   (interactive) | ||
|  |   (let ((buf (current-buffer))) | ||
|  |     (condition-case nil | ||
|  |         (delete-window) | ||
|  |       (error nil)) | ||
|  |     (kill-buffer buf))) | ||
|  | 
 | ||
|  | ;;---------------------------------------------------------------- Web Browsing | ||
|  | 
 | ||
|  | (defun scribble-browse-mode-web () | ||
|  |   (interactive) | ||
|  |   (browse-url scribble-mode-web)) | ||
|  | 
 | ||
|  | ;; TODO: Add browsing to Scribble documentation.  First try to find URLs to | ||
|  | ;; their existing documentation (based "~/.racket" and on dir of "racket" | ||
|  | ;; command).  Fall back to public Web version. | ||
|  | 
 | ||
|  | ;;----------------------------------------------------------------------- About | ||
|  | 
 | ||
|  | (defun scribble-about () | ||
|  |   (interactive) | ||
|  |   (scribble-buffer-display | ||
|  |    "*About Scribble Mode*" | ||
|  |    (function  | ||
|  |     (lambda () | ||
|  |       (insert (propertize scribble-mode-title 'face 'bold) | ||
|  |               "\n\n" | ||
|  |               "Version " | ||
|  |               (propertize scribble-mode-version 'face 'bold) | ||
|  |               "\n\n" | ||
|  |               (propertize scribble-mode-web 'face 'bold) | ||
|  |               "\n\n" | ||
|  |               scribble-mode-legal-notices | ||
|  |               "\n"))))) | ||
|  | 
 | ||
|  | ;;--------------------------------------------------------------- Mode Function | ||
|  | 
 | ||
|  | ;;;###autoload | ||
|  | (defun scribble-mode () | ||
|  |   "!!! `\[COMMAND]', `\{KEYMAP}', and `\<KEYMAP>'" | ||
|  |   (interactive) | ||
|  | 
 | ||
|  |   (kill-all-local-variables) | ||
|  | 
 | ||
|  |   (use-local-map scribble-mode-map) | ||
|  | 
 | ||
|  |   (set-syntax-table scribble-mode-syntax-table) | ||
|  |    | ||
|  |   (setq fill-column 79) | ||
|  | 
 | ||
|  |   ;; Comments: | ||
|  |   (set (make-local-variable 'comment-start)      "@;") | ||
|  |   (set (make-local-variable 'comment-end)        "") | ||
|  |   (set (make-local-variable 'comment-padding)    1) | ||
|  |   (set (make-local-variable 'comment-multi-line) nil) | ||
|  |   (set (make-local-variable 'comment-start-skip) | ||
|  |        "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\);+ *") | ||
|  | 
 | ||
|  |   ;; TODO: comment-indent-function | ||
|  | 
 | ||
|  |   ;; TODO: indent-line-function  | ||
|  | 
 | ||
|  |   ;; TODO: abbrev | ||
|  | 
 | ||
|  |   ;; Font-Lock: | ||
|  |   (set (make-local-variable 'font-lock-defaults) scribble-font-lock-defaults) | ||
|  | 
 | ||
|  |   ;; Imenu: | ||
|  |   (set (make-local-variable 'imenu-generic-expression) | ||
|  |        scribble-imenu-generic-expression) | ||
|  |   (set (make-local-variable 'imenu-case-fold-search) nil) | ||
|  |   (imenu-add-to-menubar "Imenu") | ||
|  |    | ||
|  |   ;; ElDoc: | ||
|  |   (set (make-local-variable 'eldoc-documentation-function) | ||
|  |        'scribble-eldoc-documentation-function) | ||
|  |   (turn-on-eldoc-mode) | ||
|  | 
 | ||
|  |   ;; Completion: | ||
|  |   (set (make-local-variable 'completion-at-point-functions) | ||
|  |        (list 'scribble-completion-at-point-function)) | ||
|  | 
 | ||
|  |   ;; Mode Identification: | ||
|  |   (setq mode-name "Scribble") | ||
|  |   (setq major-mode 'scribble-mode) | ||
|  | 
 | ||
|  |   ;; Hooks: | ||
|  |   (run-mode-hooks 'scribble-mode-hook)) | ||
|  | 
 | ||
|  | ;;------------------------------------------------------------------- Auto-Mode | ||
|  | 
 | ||
|  | ;;;###autoload | ||
|  | (mapc (lambda (pair) | ||
|  |         (or (assoc (car pair) auto-mode-alist) | ||
|  |             (push pair auto-mode-alist))) | ||
|  |       '(("\\.scrbl\\'" . scribble-mode))) | ||
|  | 
 | ||
|  | ;;--------------------------------------------------------------------- Provide | ||
|  | 
 | ||
|  | (provide 'scribble) | ||
|  | 
 | ||
|  | ;;; scribble.el ends here |