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)))