skylighting-format-typst (empty) → 0.1
raw patch · 4 files changed
+183/−0 lines, 4 filesdep +basedep +containersdep +skylighting-core
Dependencies added: base, containers, skylighting-core, text
Files
- LICENSE +30/−0
- README.md +5/−0
- skylighting-format-typst.cabal +36/−0
- src/Skylighting/Format/Typst.hs +112/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2016-2018, John MacFarlane.+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * The names of the contributors may not be used to endorse or+ promote products derived from this software without specific+ prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,5 @@+# skylighting-format-typst++This package provides functions to render syntax-highlighting+as typst.+
+ skylighting-format-typst.cabal view
@@ -0,0 +1,36 @@+name: skylighting-format-typst+version: 0.1+synopsis: Typst formatter for skylighting syntax highlighting library+description: This module allows tokens produced by skylighting-core+ to be rendered as Typst.+homepage: https://github.com/jgm/skylighting+license: BSD3+license-file: LICENSE+author: John MacFarlane+maintainer: jgm@berkeley.edu+copyright: (C) 2024 John MacFarlane+category: Text+build-type: Simple+extra-source-files: README.md++cabal-version: >=1.10++source-repository head+ type: git+ location: https://github.com/jgm/skylighting.git++library+ exposed-modules: Skylighting.Format.Typst+ other-extensions: CPP+ build-depends: base >= 4.8 && < 5.0,+ skylighting-core,+ text,+ containers+ hs-source-dirs: src+ ghc-prof-options: -fprof-auto-exported+ default-language: Haskell2010+ ghc-options: -Wall+ if impl(ghc >= 8.4)+ ghc-options: -fhide-source-paths+ if impl(ghc >= 8.10)+ ghc-options: -Wunused-packages
+ src/Skylighting/Format/Typst.hs view
@@ -0,0 +1,112 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+module Skylighting.Format.Typst (+ formatTypstInline+ , formatTypstBlock+ , styleToTypst+ ) where++import Control.Monad (mplus)+import Data.List (sort)+import qualified Data.Map as Map+import Data.Text (Text)+import qualified Data.Text as Text+import Skylighting.Types+import qualified Data.Map as M+import Data.Maybe (fromMaybe)+#if !MIN_VERSION_base(4,11,0)+import Data.Semigroup+#endif++-- | Formats tokens as Typst using custom commands inside+-- @|@ characters. Assumes that @|@ is defined as a short verbatim+-- command by the macros produced by 'styleToTypst'.+-- A @KeywordTok@ is rendered using @\\KeywordTok{..}@, and so on.+formatTypstInline :: FormatOptions -> [SourceLine] -> Text+formatTypstInline _opts = Text.intercalate newline . map sourceLineToTypst++newline :: Text+newline = "#EndLine()\n"++sourceLineToTypst :: SourceLine -> Text+sourceLineToTypst = mconcat . map tokenToTypst++tokenToTypst :: Token -> Text+tokenToTypst (toktype, txt) =+ "#" <> Text.pack (show toktype) <> "(" <> doubleQuoted txt <> ");"++doubleQuoted :: Text -> Text+doubleQuoted t = "\"" <> escape t <> "\""+ where+ escape = Text.concatMap escapeChar+ escapeChar '\\' = "\\\\"+ escapeChar '"' = "\\\""+ escapeChar c = Text.singleton c++-- Typst++-- | Format tokens as a Typst @Highlighting@ environment inside a+-- Skylighting block that can be styled. @Skylighting@ is+-- defined by the macros produced by 'styleToTypst'.+formatTypstBlock :: FormatOptions -> [SourceLine] -> Text+formatTypstBlock opts ls =+ "#Skylighting(" <>+ (if numberLines opts+ then "number: true, start: " <> Text.pack (show (startNumber opts)) <> ", "+ else "") <>+ "(" <> -- an array+ Text.intercalate "\n" (map (\ln -> "[" <> formatTypstInline opts [ln] <> "],") ls)+ <> "));"++-- | Converts a 'Style' to a set of Typst macro definitions,+-- which should be placed in the document's preamble.+styleToTypst :: Style -> Text+styleToTypst f =+ Text.unlines $+ [ "/* Function definitions for syntax highlighting generated by skylighting: */"+ , "#let EndLine() = raw(\"\\n\")"+ , "#let Skylighting(fill: none, number: false, start: 1, sourcelines) = {"+ , " let blocks = []"+ , " let lnum = start - 1"+ , " let bgcolor = " <> maybe "none" toTypstColor (backgroundColor f)+ , " for ln in sourcelines {"+ , " if number {"+ , " lnum = lnum + 1"+ , " blocks = blocks + box(width: if start + sourcelines.len() > 999 { 30pt } else { 24pt }, text(" <> lineNumberFill <> "[ #lnum ]))"+ , " }"+ , " blocks = blocks + ln + EndLine()"+ , " }"+ , " block(fill: bgcolor, blocks)"+ , "}"+ ] <>+ sort (map (macrodef (defaultColor f) (Map.toList (tokenStyles f)))+ (enumFromTo KeywordTok NormalTok))+ where+ toTypstColor c = "rgb(" <> Text.pack (show (fromColor c :: String)) <> ")"+ lineNumberFill = case lineNumberColor f of+ Nothing -> ""+ Just c -> "fill: " <> toTypstColor c <> ", "++macrodef :: Maybe Color -> [(TokenType, TokenStyle)] -> TokenType -> Text+macrodef defaultcol tokstyles' tokt =+ "#let " <> Text.pack (show tokt) <> "(s) = " <> (ul . bg . textstyle) ("raw(s)")+ where tokstyles = M.fromList tokstyles'+ tokf = fromMaybe defStyle $ M.lookup tokt tokstyles+ ul x = if tokenUnderline tokf+ then "underline(" <> x <> ")"+ else x+ bg x = case tokenBackground tokf of+ Nothing -> x+ Just _c -> x -- TODO?+ textstyle x = "text(" <> bf <> it <> co <> x <> ")"+ it = if tokenItalic tokf+ then "style: \"italic\","+ else ""+ bf = if tokenBold tokf+ then "weight: \"bold\","+ else ""+ co = case tokenColor tokf `mplus` defaultcol of+ Just c -> "fill: rgb(" <>+ Text.pack (show (fromColor c :: String)) <> "),"+ Nothing -> ""