From 3883b65cd55646d977ddb71f04755bfeece3bf28 Mon Sep 17 00:00:00 2001 From: Sorawee Porncharoenwase Date: Thu, 8 Nov 2018 11:59:11 -0800 Subject: [PATCH 1/3] Add an ability to highlight lines for Scribble's Pygments This backports https://github.com/mbutterick/pollen/commit/3972173eacd5a158591a6b86c50bc96ad4d0fc3f --- frog/enhance-body.rkt | 25 +++++++++++++------ frog/frog.scrbl | 11 +++++--- .../enhance-body/syntax-highlight/pipe.py | 15 ++++++++--- .../syntax-highlight/pygments.rkt | 5 +++- frog/scribble.rkt | 15 +++++++---- 5 files changed, 50 insertions(+), 21 deletions(-) diff --git a/frog/enhance-body.rkt b/frog/enhance-body.rkt index 24cf6db0..0cb96468 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) 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)))

From 45140482ce5c000daf88ecd392113425f8541d68 Mon Sep 17 00:00:00 2001
From: Sorawee Porncharoenwase 
Date: Thu, 8 Nov 2018 19:02:05 -0800
Subject: [PATCH 2/3] Make it hl-lines integrate with add-racket-doc-links
 nicely

---
 frog/enhance-body.rkt | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/frog/enhance-body.rkt b/frog/enhance-body.rkt
index 0cb96468..c3d8419a 100644
--- a/frog/enhance-body.rkt
+++ b/frog/enhance-body.rkt
@@ -136,6 +136,16 @@
                         (div . ,_)
                         ,_ ...          ;varies: line numbers?
                         (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))

From 7fb834d02863dedda1ee3874c3cd0e8cce403817 Mon Sep 17 00:00:00 2001
From: Sorawee Porncharoenwase 
Date: Fri, 9 Nov 2018 04:18:08 -0800
Subject: [PATCH 3/3] Allow non-top level matching, fixes
 greghendershott/frog#239

---
 frog/enhance-body.rkt | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/frog/enhance-body.rkt b/frog/enhance-body.rkt
index c3d8419a..ab124c21 100644
--- a/frog/enhance-body.rkt
+++ b/frog/enhance-body.rkt
@@ -135,7 +135,8 @@
                     [(`((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))
@@ -145,7 +146,8 @@
                         (pre . ,_)
                         (div . ,_)
                         ,_ ...          ;varies: line numbers?
-                        (div ([class "brush: racket"]) . ,_))
+                        (div ([class "brush: racket"]) . ,_)
+                        ,_ ...)
                       `(span ([class ,(and c (not "c1"))]) . ,xs))
                      (if code?
                          `(span ([class ,c]) ,@(->racket-doc-links xs))