2022-01-27 21:50:07 +03:00
|
|
|
module Shiki exposing (Highlighted, ShikiToken, decoder, view)
|
2021-07-16 21:26:53 +03:00
|
|
|
|
|
|
|
import Html exposing (Html)
|
|
|
|
import Html.Attributes as Attr exposing (class)
|
2022-01-27 05:56:15 +03:00
|
|
|
import Json.Decode as Decode exposing (Decoder)
|
|
|
|
import Json.Decode.Extra
|
2021-07-16 21:26:53 +03:00
|
|
|
|
|
|
|
|
|
|
|
type alias ShikiToken =
|
|
|
|
{ content : String
|
2021-07-17 21:41:50 +03:00
|
|
|
, color : Maybe String
|
2021-07-16 21:26:53 +03:00
|
|
|
, fontStyle : Maybe ( String, String )
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type alias Highlighted =
|
|
|
|
{ lines : List (List ShikiToken)
|
2021-07-17 21:41:50 +03:00
|
|
|
, fg : String
|
2021-07-16 21:26:53 +03:00
|
|
|
, bg : String
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
decoder : Decoder Highlighted
|
|
|
|
decoder =
|
2021-07-17 21:41:50 +03:00
|
|
|
Decode.map3 Highlighted
|
2021-07-16 21:26:53 +03:00
|
|
|
(Decode.field "tokens" (Decode.list (Decode.list shikiTokenDecoder)))
|
2021-07-17 21:41:50 +03:00
|
|
|
(Decode.field "fg" Decode.string)
|
2021-07-16 21:26:53 +03:00
|
|
|
(Decode.field "bg" Decode.string)
|
|
|
|
|
|
|
|
|
|
|
|
shikiTokenDecoder : Decode.Decoder ShikiToken
|
|
|
|
shikiTokenDecoder =
|
|
|
|
Decode.map3 ShikiToken
|
|
|
|
(Decode.field "content" Decode.string)
|
2022-01-27 05:56:15 +03:00
|
|
|
(Json.Decode.Extra.optionalField "color" Decode.string)
|
|
|
|
(Json.Decode.Extra.optionalField "fontStyle" fontStyleDecoder |> Decode.map (Maybe.andThen identity))
|
2021-07-16 21:26:53 +03:00
|
|
|
|
|
|
|
|
|
|
|
fontStyleDecoder : Decoder (Maybe ( String, String ))
|
|
|
|
fontStyleDecoder =
|
|
|
|
Decode.int
|
|
|
|
|> Decode.map
|
|
|
|
(\styleNumber ->
|
|
|
|
case styleNumber of
|
|
|
|
1 ->
|
|
|
|
Just ( "font-style", "italic" )
|
|
|
|
|
|
|
|
2 ->
|
|
|
|
Just ( "font-style", "bold" )
|
|
|
|
|
|
|
|
4 ->
|
|
|
|
Just ( "font-style", "underline" )
|
|
|
|
|
|
|
|
_ ->
|
|
|
|
Nothing
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
{-| <https://github.com/shikijs/shiki/blob/2a31dc50f4fbdb9a63990ccd15e08cccc9c1566a/packages/shiki/src/renderer.ts#L16>
|
|
|
|
-}
|
|
|
|
view : List (Html.Attribute msg) -> Highlighted -> Html msg
|
|
|
|
view attrs highlighted =
|
|
|
|
highlighted.lines
|
|
|
|
|> List.indexedMap
|
|
|
|
(\lineIndex line ->
|
|
|
|
let
|
|
|
|
isLastLine =
|
|
|
|
List.length highlighted.lines == (lineIndex + 1)
|
|
|
|
in
|
|
|
|
Html.span [ class "line" ]
|
|
|
|
((line
|
|
|
|
|> List.map
|
|
|
|
(\token ->
|
|
|
|
Html.span
|
2021-07-17 21:41:50 +03:00
|
|
|
[ Attr.style "color" (token.color |> Maybe.withDefault highlighted.fg)
|
2021-07-16 21:26:53 +03:00
|
|
|
, token.fontStyle
|
|
|
|
|> Maybe.map
|
|
|
|
(\( key, value ) ->
|
|
|
|
Attr.style key value
|
|
|
|
)
|
|
|
|
|> Maybe.withDefault (Attr.title "")
|
|
|
|
]
|
|
|
|
[ Html.text token.content ]
|
|
|
|
)
|
|
|
|
)
|
|
|
|
++ [ if isLastLine then
|
|
|
|
Html.text ""
|
|
|
|
|
|
|
|
else
|
|
|
|
Html.text "\n"
|
|
|
|
]
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|> Html.code []
|
|
|
|
|> List.singleton
|
|
|
|
|> Html.pre
|
|
|
|
([ Attr.style "background-color" highlighted.bg
|
|
|
|
, Attr.style "white-space" "pre-wrap"
|
|
|
|
, Attr.style "overflow-wrap" "break-word"
|
|
|
|
]
|
|
|
|
++ attrs
|
|
|
|
)
|