diff --git a/cover/private/html/assets/main.css b/cover/private/html/assets/main.css index de25e68..86ac5cf 100644 --- a/cover/private/html/assets/main.css +++ b/cover/private/html/assets/main.css @@ -38,7 +38,7 @@ td a, td a:visited { color: #07A; } -tr.stripe { +tr.stripe, :target { background-color: #F5F5EC; } @@ -59,6 +59,16 @@ div.line-numbers { text-align: right; } +.line-numbers a { + color: black; + text-decoration: none; +} + +.line-numbers a:hover { + color: blue; + text-decoration: underline; +} + div.file-lines { display: table-cell; } diff --git a/cover/private/html/html.rkt b/cover/private/html/html.rkt index 43f2fba..336c3e5 100644 --- a/cover/private/html/html.rkt +++ b/cover/private/html/html.rkt @@ -210,33 +210,36 @@ (define (div:line-numbers line-count) `(div ([class "line-numbers"]) ,@(for/list ([num (in-range 1 (add1 line-count))]) - `(div () ,(number->string num))))) + (let ([str-num (number->string num)]) + `(div () (a ([href ,(string-append "#" str-num)]) ,str-num)))))) (module+ test (check-equal? (div:line-numbers 5) `(div ([class "line-numbers"]) - ,@(build-list 5 (λ (n) `(div () ,(number->string (add1 n)))))))) + ,@(build-list 5 (λ (n) `(div () (a ([href ,(format "#~a" (add1 n))]) + ,(number->string (add1 n))))))))) ;; [List String] Covered? -> Xexpr (define (div:file-lines file-lines covered?) - (define-values (line-divs _) - (for/fold ([lines '()] [pos 1]) ([line (in-list file-lines)]) - (values (cons (div:file-line line pos covered?) lines) - (add1 (+ pos (string-length line)))))) + (define-values (line-divs _1 _2) + (for/fold ([lines '()] [pos 1] [line-number 1]) ([line (in-list file-lines)]) + (values (cons (div:file-line line pos covered? line-number) lines) + (add1 (+ pos (string-length line))) + (add1 line-number)))) `(div ([class "file-lines"]) ,@(reverse line-divs))) (module+ test (define lines '("hello world" "goodbye")) (check-equal? (div:file-lines lines mock-covered?) `(div ([class "file-lines"]) - ,(div:file-line (first lines) 1 mock-covered?) - ,(div:file-line (second lines) 12 mock-covered?)))) + ,(div:file-line (first lines) 1 mock-covered? 1) + ,(div:file-line (second lines) 12 mock-covered? 2)))) ;; String Nat Covered? -> Xexpr ;; Build a single line into an Xexpr -(define (div:file-line line pos covered?) - (cond [(zero? (string-length line)) '(br ())] +(define (div:file-line line pos covered? line-number) + (cond [(zero? (string-length line)) `(br ([id ,(number->string line-number)]))] [else (define (build-span str type) `(span ([class ,(symbol->string type)]) ,str)) (define (add-expr cover-type expr cover-exprs) @@ -255,12 +258,13 @@ [else (define new-expr (add-expr current-cover-type expr/acc covered-exp)) (values new-expr (string c) (covered? (+ pos offset)))]))) - `(div ([class "line"]) ,@(reverse (add-expr coverage-type acc/str xexpr)))])) + `(div ([class "line"] [id ,(number->string line-number)]) + ,@(reverse (add-expr coverage-type acc/str xexpr)))])) (module+ test - (check-equal? (div:file-line "" 1 mock-covered?) '(br ())) - (check-equal? (div:file-line "hello world" 1 mock-covered?) - '(div ([class "line"]) (span ([class "covered"]) "hello") + (check-equal? (div:file-line "" 1 mock-covered? 999) '(br ([id "999"]))) + (check-equal? (div:file-line "hello world" 1 mock-covered? 2) + '(div ([class "line"] [id "2"]) (span ([class "covered"]) "hello") nbsp (span ([class "uncovered"]) "world"))))