diff --git a/frog/enhance-body.rkt b/frog/enhance-body.rkt index 24cf6db0..ab124c21 100644 --- a/frog/enhance-body.rkt +++ b/frog/enhance-body.rkt @@ -34,19 +34,28 @@ @racket[find-executable-path], so the default @racket["python"] will work if the version of Python that Pygments wants is on the path.} + (define (highlight brush texts hl-lines) + (match brush + [(pregexp "\\s*brush:\\s*(.+?)\\s*$" (list _ lang)) + `(div ([class ,(str "brush: " lang)]) + ,@(pygmentize (apply string-append texts) lang + #:python-executable python-executable + #:line-numbers? line-numbers? + #:css-class css-class + #:hl-lines hl-lines))] + [_ `(pre ,@texts)])) + (let recur ([xs x-expressions]) (for/list ([x xs]) (match x [(or `(pre ([class ,brush]) (code () ,(? string? texts) ...)) `(pre ([class ,brush]) ,(? string? texts) ...)) - (match brush - [(pregexp "\\s*brush:\\s*(.+?)\\s*$" (list _ lang)) - `(div ([class ,(str "brush: " lang)]) - ,@(pygmentize (apply string-append texts) lang - #:python-executable python-executable - #:line-numbers? line-numbers? - #:css-class css-class))] - [_ `(pre ,@texts)])] + (highlight brush texts '())] + [(or `(pre ([class ,brush] [data-hl-lines ,hl-lines]) + (code () ,(? string? texts) ...)) + `(pre ([class ,brush] [data-hl-lines ,hl-lines]) + ,(? string? texts) ...)) + (highlight brush texts (map string->number (string-split hl-lines " ")))] ;; Check child elements, too. For example as in issue #217 ;; could be (ol () (li () (pre () ___))). [(list* (? symbol? tag) (? list? attributes) elements) @@ -126,7 +135,19 @@ [(`((pre . ,_) (div . ,_) ,_ ... ;varies: line numbers? - (div ([class "brush: racket"]) . ,_)) + (div ([class "brush: racket"]) . ,_) + ,_ ...) + `(span ([class ,(and c (not "c1") (not "hll"))]) . ,xs)) + (if code? + `(span ([class ,c]) ,@(->racket-doc-links xs)) + x)] + ;; This is the case where the line is highlighted. + [(`((span ([class "hll"]) . ,_) + (pre . ,_) + (div . ,_) + ,_ ... ;varies: line numbers? + (div ([class "brush: racket"]) . ,_) + ,_ ...) `(span ([class ,(and c (not "c1"))]) . ,xs)) (if code? `(span ([class ,c]) ,@(->racket-doc-links xs)) diff --git a/frog/frog.scrbl b/frog/frog.scrbl index 0ce1e0e3..1d90a2bf 100644 --- a/frog/frog.scrbl +++ b/frog/frog.scrbl @@ -413,19 +413,24 @@ Scribble non-post page} for more information. @defmodule[frog/scribble] -@defproc[(pygment-code [#:lang lang string?][str string?] ...) paragraph?]{ +@defproc[(pygment-code [#:lang lang string?][#:hl-lines hl-lines list? '()][str string?] ...) paragraph?]{ In Scribble source files of course you can use @racket[codeblock], @racket[racketblock], and friends to write code blocks for languages that have DrRacket style syntax-coloring parsers. For other languages, you can emit a @tt{
} block with a language
 tag (as happens with @secref["markdown-code-blocks"]) so that it can
-be highlighted by Pygments.
+be highlighted by Pygments. You can also additionally supply lines to be
+highlighted via @racket[#:hl-lines].
 
 Example usage:
 @pre|{
 @(require frog/scribble)
-@pygment-code[#:lang "js"]{function foo() {return 1;}}
+@pygment-code[#:lang "js" #:hl-lines '(1 2)]{
+  function foo() {
+    return 1;
+  }
+}
 }|
 }
 
diff --git a/frog/private/enhance-body/syntax-highlight/pipe.py b/frog/private/enhance-body/syntax-highlight/pipe.py
index 034c21e6..3b78f30c 100644
--- a/frog/private/enhance-body/syntax-highlight/pipe.py
+++ b/frog/private/enhance-body/syntax-highlight/pipe.py
@@ -2,6 +2,7 @@
 # continuously. Input format is:
 #
 #     
+#     
 #     
 #     ...
 #     __END__
@@ -28,12 +29,9 @@
 parser.add_option('--cssclass', default="source", dest="cssclass")
 (options, _) = parser.parse_args()
 
-formatter = HtmlFormatter(linenos=options.linenos,
-                          cssclass=options.cssclass,
-                          encoding="utf-8")
-
 lexer = ""
 code = ""
+lines_to_highlight = ""
 py_version = sys.version_info.major
 sys.stdout.write("ready\n")
 sys.stdout.flush()
@@ -47,6 +45,10 @@
         break
     elif line == '__END__':
         # Lex input finished. Lex it.
+        formatter = HtmlFormatter(linenos=options.linenos,
+                          cssclass=options.cssclass,
+                          encoding="utf-8",
+                          hl_lines=lines_to_highlight)
         if py_version >= 3:
           sys.stdout.write(highlight(code, lexer, formatter).decode("utf-8"))
         else:
@@ -55,12 +57,17 @@
         sys.stdout.flush()
         lexer = ""
         code = ""
+        lines_to_highlight = ""
     elif lexer == "":
         # Starting another lex. First line is the lexer name.
         try:
             lexer = get_lexer_by_name(line, encoding="guess")
         except ClassNotFound:
             lexer = get_lexer_by_name("text", encoding="guess")
+    elif lines_to_highlight == "":
+        # Starting another lex. Second line is list of lines to highlight,
+        # formatted as string of whitespace-separated integers
+        lines_to_highlight = [int(str) for str in line.split()]
     else:
         # Accumulate more code
         # Use `line_raw`: Do want trailing space, \n, \r
diff --git a/frog/private/enhance-body/syntax-highlight/pygments.rkt b/frog/private/enhance-body/syntax-highlight/pygments.rkt
index bd36d2fc..c9c6c147 100644
--- a/frog/private/enhance-body/syntax-highlight/pygments.rkt
+++ b/frog/private/enhance-body/syntax-highlight/pygments.rkt
@@ -1,6 +1,7 @@
 #lang racket/base
 
 (require racket/format
+         racket/string
          racket/function
          racket/match
          racket/port
@@ -66,13 +67,15 @@
 (define (pygmentize code lang
                     #:python-executable python-executable
                     #:line-numbers? line-numbers?
-                    #:css-class css-class)
+                    #:css-class css-class
+                    #:hl-lines [hl-lines '()])
   (define (default code)
     `((pre () (code () ,code))))
   (unless (running?)
     (start python-executable line-numbers? css-class))
   (cond [(running?)
          (displayln lang pyg-out)
+         (displayln (string-join (map number->string hl-lines) " ") pyg-out)
          (displayln code pyg-out)
          (displayln "__END__" pyg-out)
          (let loop ([s ""])
diff --git a/frog/scribble.rkt b/frog/scribble.rkt
index 8c60c998..e4766553 100644
--- a/frog/scribble.rkt
+++ b/frog/scribble.rkt
@@ -1,6 +1,7 @@
 #lang racket/base
 
-(require (only-in scribble/core style)
+(require racket/string
+         (only-in scribble/core style)
          (only-in scribble/manual para)
          (only-in scribble/html-properties attributes alt-tag)
          (only-in scribble/base literal))
@@ -17,8 +18,12 @@
 ;;
 ;; @pygment-code[#:lang "js"]{function foo() {return 1;}}
 ;;
-(define (pygment-code #:lang lang . xs)
-  (para #:style (style "brush:"
-                       (list (attributes `([class . ,lang]))
-                             (alt-tag "pre")))
+(define (pygment-code #:lang lang #:hl-lines [hl-lines '()] . xs)
+  (para #:style
+        (style "brush:"
+               (list (attributes
+                      `([class . ,lang]
+                        [data-hl-lines . ,(string-join (map number->string hl-lines)
+                                                       " ")]))
+                     (alt-tag "pre")))
         (apply literal xs)))