├── .envrc ├── .gitignore ├── .vscode └── extensions.json ├── src ├── SyntaxHighlight │ ├── Language │ │ ├── Type.elm │ │ ├── NoLang.elm │ │ ├── Xml.elm │ │ ├── Helpers.elm │ │ ├── Json.elm │ │ ├── Nix.elm │ │ ├── Python.elm │ │ ├── Kotlin.elm │ │ ├── Sql.elm │ │ ├── Go.elm │ │ ├── Javascript.elm │ │ └── Elm.elm │ ├── Theme.elm │ ├── Theme │ │ ├── GitHub.elm │ │ ├── OneDark.elm │ │ ├── Monokai.elm │ │ └── Type.elm │ ├── Line.elm │ ├── Line │ │ └── Helpers.elm │ ├── Style.elm │ └── View.elm └── SyntaxHighlight.elm ├── demo ├── index.html ├── README.md ├── elm.json └── themes-page │ ├── elm.json │ ├── make-themes.js │ ├── Main.elm │ └── themes-template.html ├── elm.json ├── flake.lock ├── tests └── Language │ ├── Go.elm │ ├── Nix.elm │ ├── Sql.elm │ ├── NoLang.elm │ ├── Kotlin.elm │ ├── Python.elm │ ├── Json.elm │ ├── Xml.elm │ ├── Javascript.elm │ ├── Elm.elm │ └── Css.elm ├── CONTRIBUTING.md ├── README.md ├── CHANGELOG.md ├── .github └── workflows │ └── test-build-deploy.yml ├── flake.nix ├── themes.md └── LICENSE /.envrc: -------------------------------------------------------------------------------- 1 | use flake -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | elm-stuff 2 | .DS_Store 3 | .idea 4 | demo/elm-themes.js 5 | demo/themes.html 6 | demo/build 7 | elm.js 8 | node_modules 9 | .direnv 10 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "mkhl.direnv", 4 | "jnoortheen.nix-ide", 5 | "elmtooling.elm-ls-vscode" 6 | ] 7 | } -------------------------------------------------------------------------------- /src/SyntaxHighlight/Language/Type.elm: -------------------------------------------------------------------------------- 1 | module SyntaxHighlight.Language.Type exposing (Syntax(..), Token) 2 | 3 | 4 | type alias Token a = 5 | ( Syntax a, String ) 6 | 7 | 8 | type Syntax a 9 | = Normal 10 | | Comment 11 | | LineBreak 12 | | C a 13 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Elm Syntax Highlight 8 | 9 | 10 | 11 |

Loading...

12 | 13 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /demo/README.md: -------------------------------------------------------------------------------- 1 | # Elm Syntax Highlight demo 2 | 3 | All commands must be run in this folder (`demo`). 4 | 5 | ## Development 6 | 7 | ```sh 8 | elm reactor 9 | ``` 10 | 11 | Open your browser at http://localhost:8000/ and navigate to `src/Main.elm`. 12 | 13 | 14 | ## Run standalone 15 | 16 | Remove `"../src"` at the `source-directories` entry in `elm.json` file and install the package running: 17 | 18 | ```sh 19 | elm install pablohirafuji/elm-syntax-highlight 20 | ``` 21 | -------------------------------------------------------------------------------- /elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "package", 3 | "name": "pablohirafuji/elm-syntax-highlight", 4 | "summary": "Syntax highlighting in Elm", 5 | "license": "Apache-2.0", 6 | "version": "3.7.1", 7 | "exposed-modules": [ 8 | "SyntaxHighlight" 9 | ], 10 | "elm-version": "0.19.0 <= v < 0.20.0", 11 | "dependencies": { 12 | "elm/core": "1.0.0 <= v < 2.0.0", 13 | "elm/html": "1.0.0 <= v < 2.0.0", 14 | "elm/parser": "1.1.0 <= v < 2.0.0", 15 | "elm/regex": "1.0.0 <= v < 2.0.0" 16 | }, 17 | "test-dependencies": { 18 | "elm-explorations/test": "2.2.0 <= v < 3.0.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1741181794, 6 | "narHash": "sha256-KaY79mvudbMfufn3FW2Yzx/hiF848gj5y1rMjS/U8fA=", 7 | "owner": "NixOS", 8 | "repo": "nixpkgs", 9 | "rev": "bb1b98cea759f3739d88b1a6a0d379d61aaf5573", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "NixOS", 14 | "ref": "release-24.11", 15 | "repo": "nixpkgs", 16 | "type": "github" 17 | } 18 | }, 19 | "root": { 20 | "inputs": { 21 | "nixpkgs": "nixpkgs" 22 | } 23 | } 24 | }, 25 | "root": "root", 26 | "version": 7 27 | } 28 | -------------------------------------------------------------------------------- /demo/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src", 5 | "../src" 6 | ], 7 | "elm-version": "0.19.1", 8 | "dependencies": { 9 | "direct": { 10 | "elm/browser": "1.0.2", 11 | "elm/core": "1.0.5", 12 | "elm/html": "1.0.0", 13 | "elm/json": "1.1.3", 14 | "elm/parser": "1.1.0", 15 | "elm/regex": "1.0.0", 16 | "elm/time": "1.0.0" 17 | }, 18 | "indirect": { 19 | "elm/url": "1.0.0", 20 | "elm/virtual-dom": "1.0.3" 21 | } 22 | }, 23 | "test-dependencies": { 24 | "direct": {}, 25 | "indirect": {} 26 | } 27 | } -------------------------------------------------------------------------------- /demo/themes-page/elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | ".", 5 | "../../src" 6 | ], 7 | "elm-version": "0.19.1", 8 | "dependencies": { 9 | "direct": { 10 | "elm/browser": "1.0.0", 11 | "elm/core": "1.0.0", 12 | "elm/html": "1.0.0", 13 | "elm/json": "1.0.0", 14 | "elm/parser": "1.1.0", 15 | "elm/regex": "1.0.0", 16 | "elm/time": "1.0.0" 17 | }, 18 | "indirect": { 19 | "elm/url": "1.0.0", 20 | "elm/virtual-dom": "1.0.2" 21 | } 22 | }, 23 | "test-dependencies": { 24 | "direct": {}, 25 | "indirect": {} 26 | } 27 | } -------------------------------------------------------------------------------- /src/SyntaxHighlight/Theme.elm: -------------------------------------------------------------------------------- 1 | module SyntaxHighlight.Theme exposing 2 | ( all 3 | , gitHub 4 | , monokai 5 | , oneDark 6 | ) 7 | 8 | import SyntaxHighlight.Theme.GitHub as GitHub 9 | import SyntaxHighlight.Theme.Monokai as Monokai 10 | import SyntaxHighlight.Theme.OneDark as OneDark 11 | 12 | 13 | 14 | -- Add all themes name and code here to show in the Demo and Themes page 15 | 16 | 17 | all : List ( String, String ) 18 | all = 19 | [ ( "Monokai", monokai ) 20 | , ( "GitHub", gitHub ) 21 | , ( "One Dark", oneDark ) 22 | ] 23 | 24 | 25 | monokai : String 26 | monokai = 27 | Monokai.css 28 | 29 | 30 | gitHub : String 31 | gitHub = 32 | GitHub.css 33 | 34 | 35 | oneDark : String 36 | oneDark = 37 | OneDark.css 38 | -------------------------------------------------------------------------------- /demo/themes-page/make-themes.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | var path = require("path"); 3 | var templateFile = fs.readFileSync(path.resolve(__dirname + "/themes-template.html")); 4 | var templateStr = templateFile.toString(); 5 | 6 | 7 | var elm = require("./elm-themes").Elm.Main.init(); 8 | elm.ports.themesList.subscribe(function(themeList) { 9 | var themeListHtml = "" 10 | themeList.forEach(function(element, index, array) { 11 | themeListHtml += "
  • " + element.name + "
    " + element.content + "
  • " 12 | }); 13 | 14 | var themesHtml = templateStr.replace("${themeList}", themeListHtml) 15 | 16 | fs.writeFile("./themes.html", themesHtml, function(err) { 17 | if (err) { return console.log(err); } 18 | }); 19 | }); -------------------------------------------------------------------------------- /tests/Language/Go.elm: -------------------------------------------------------------------------------- 1 | module Language.Go exposing (suite) 2 | 3 | import Expect exposing (Expectation, equal, equalLists, onFail) 4 | import Fuzz exposing (string) 5 | import Parser 6 | import Result exposing (Result(..)) 7 | import SyntaxHighlight.Language.Go as Go exposing (Syntax(..), toRevTokens) 8 | import Test exposing (..) 9 | 10 | 11 | suite : Test 12 | suite = 13 | describe "Go Language Test Suite" 14 | [ fuzz string "Fuzz string" <| 15 | \fuzzStr -> 16 | Parser.run Go.toRevTokens fuzzStr 17 | |> Result.map 18 | (List.reverse 19 | >> List.map Tuple.second 20 | >> String.concat 21 | ) 22 | |> equal (Ok fuzzStr) 23 | |> onFail ("Resulting error string: \"" ++ fuzzStr ++ "\"") 24 | ] 25 | -------------------------------------------------------------------------------- /tests/Language/Nix.elm: -------------------------------------------------------------------------------- 1 | module Language.Nix exposing (suite) 2 | 3 | import Expect exposing (Expectation, equal, equalLists, onFail) 4 | import Fuzz exposing (string) 5 | import Parser 6 | import Result exposing (Result(..)) 7 | import SyntaxHighlight.Language.Nix as Nix exposing (Syntax(..), toRevTokens) 8 | import Test exposing (..) 9 | 10 | 11 | suite : Test 12 | suite = 13 | describe "Nix Language Test Suite" 14 | [ fuzz string "Fuzz string" <| 15 | \fuzzStr -> 16 | Parser.run Nix.toRevTokens fuzzStr 17 | |> Result.map 18 | (List.reverse 19 | >> List.map Tuple.second 20 | >> String.concat 21 | ) 22 | |> equal (Ok fuzzStr) 23 | |> onFail ("Resulting error string: \"" ++ fuzzStr ++ "\"") 24 | ] 25 | -------------------------------------------------------------------------------- /tests/Language/Sql.elm: -------------------------------------------------------------------------------- 1 | module Language.Sql exposing (suite) 2 | 3 | import Expect exposing (Expectation, equal, equalLists, onFail) 4 | import Fuzz exposing (string) 5 | import Parser 6 | import Result exposing (Result(..)) 7 | import SyntaxHighlight.Language.Sql as Sql exposing (Syntax(..), toRevTokens) 8 | import Test exposing (..) 9 | 10 | 11 | suite : Test 12 | suite = 13 | describe "SQL Language Test Suite" 14 | [ fuzz string "Fuzz string" <| 15 | \fuzzStr -> 16 | Parser.run Sql.toRevTokens fuzzStr 17 | |> Result.map 18 | (List.reverse 19 | >> List.map Tuple.second 20 | >> String.concat 21 | ) 22 | |> equal (Ok fuzzStr) 23 | |> onFail ("Resulting error string: \"" ++ fuzzStr ++ "\"") 24 | ] 25 | -------------------------------------------------------------------------------- /tests/Language/NoLang.elm: -------------------------------------------------------------------------------- 1 | module Language.NoLang exposing (suite) 2 | 3 | import Expect exposing (equal, onFail) 4 | import Fuzz exposing (string) 5 | import Parser 6 | import Result exposing (Result(..)) 7 | import SyntaxHighlight.Language.NoLang as NoLang exposing (Syntax(..), toRevTokens) 8 | import Test exposing (Test, describe, fuzz) 9 | 10 | 11 | suite : Test 12 | suite = 13 | describe "NoLang Language Test Suite" 14 | [ fuzz string "Fuzz string" <| 15 | \fuzzStr -> 16 | Parser.run NoLang.toRevTokens fuzzStr 17 | |> Result.map 18 | (List.reverse 19 | >> List.map Tuple.second 20 | >> String.concat 21 | ) 22 | |> equal (Ok fuzzStr) 23 | |> onFail ("Resulting error string: \"" ++ fuzzStr ++ "\"") 24 | ] 25 | -------------------------------------------------------------------------------- /tests/Language/Kotlin.elm: -------------------------------------------------------------------------------- 1 | module Language.Kotlin exposing (suite) 2 | 3 | import Expect exposing (Expectation, equal, equalLists, onFail) 4 | import Fuzz exposing (string) 5 | import Parser 6 | import Result exposing (Result(..)) 7 | import SyntaxHighlight.Language.Kotlin as Kotlin exposing (Syntax(..), toRevTokens) 8 | import Test exposing (..) 9 | 10 | 11 | suite : Test 12 | suite = 13 | describe "Kotlin Language Test Suite" 14 | [ fuzz string "Fuzz string" <| 15 | \fuzzStr -> 16 | Parser.run Kotlin.toRevTokens fuzzStr 17 | |> Result.map 18 | (List.reverse 19 | >> List.map Tuple.second 20 | >> String.concat 21 | ) 22 | |> equal (Ok fuzzStr) 23 | |> onFail ("Resulting error string: \"" ++ fuzzStr ++ "\"") 24 | ] 25 | -------------------------------------------------------------------------------- /tests/Language/Python.elm: -------------------------------------------------------------------------------- 1 | module Language.Python exposing (suite) 2 | 3 | import Expect exposing (Expectation, equal, equalLists, onFail) 4 | import Fuzz exposing (string) 5 | import Parser 6 | import Result exposing (Result(..)) 7 | import SyntaxHighlight.Language.Python as Python exposing (Syntax(..), toRevTokens) 8 | import Test exposing (..) 9 | 10 | 11 | suite : Test 12 | suite = 13 | describe "Python Language Test Suite" 14 | [ fuzz string "Fuzz string" <| 15 | \fuzzStr -> 16 | Parser.run Python.toRevTokens fuzzStr 17 | |> Result.map 18 | (List.reverse 19 | >> List.map Tuple.second 20 | >> String.concat 21 | ) 22 | |> equal (Ok fuzzStr) 23 | |> onFail ("Resulting error string: \"" ++ fuzzStr ++ "\"") 24 | ] 25 | -------------------------------------------------------------------------------- /src/SyntaxHighlight/Theme/GitHub.elm: -------------------------------------------------------------------------------- 1 | module SyntaxHighlight.Theme.GitHub exposing (css, theme) 2 | 3 | import SyntaxHighlight.Style exposing (Color(..), RequiredStyles, backgroundColor, noEmphasis, textColor) 4 | import SyntaxHighlight.Theme.Type exposing (Theme, toCss) 5 | 6 | 7 | 8 | -- GitHub inspired theme 9 | 10 | 11 | css : String 12 | css = 13 | toCss theme 14 | 15 | 16 | theme : Theme 17 | theme = 18 | { requiredStyles = requiredStyles 19 | , customStyles = [] 20 | } 21 | 22 | 23 | requiredStyles : RequiredStyles 24 | requiredStyles = 25 | { default = noEmphasis (Hex "#24292e") (Hex "#ffffff") 26 | , highlight = backgroundColor (Hex "#fffbdd") 27 | , addition = backgroundColor (Hex "#eaffea") 28 | , deletion = backgroundColor (Hex "#ffecec") 29 | , comment = textColor (Hex "#969896") 30 | , style1 = textColor (Hex "#005cc5") 31 | , style2 = textColor (Hex "#df5000") 32 | , style3 = textColor (Hex "#d73a49") 33 | , style4 = textColor (Hex "#0086b3") 34 | , style5 = textColor (Hex "#63a35c") 35 | , style6 = textColor (Hex "#005cc5") 36 | , style7 = textColor (Hex "#795da3") 37 | } 38 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Running the demo 2 | 3 | ```shell 4 | cd demo 5 | elm reactor 6 | ``` 7 | 8 | Demo will be available at http://localhost:8000/index.html 9 | 10 | 11 | # Creating a Theme 12 | 13 | TODO 14 | 15 | # Creating a Language 16 | 17 | In the big picture, the process looks like this: 18 | 19 | - Create a type for your language syntax. 20 | - Make a parsing function that return a reverse list of `SyntaxHighlight.Language.Type.Token a`, with your created syntax type being the `a`. 21 | - The `Normal`, `LineBreak` and `Comment` types are already defined in `SyntaxHighlight.Language.Type.Syntax`. You must parse all line breaks and give each one the `LineBreak` syntax. 22 | - There is a bunch of helpers in `SyntaxHighlight.Language.Helpers`, but you are free to not use it. 23 | - Make a `syntaxToStyle` function that take your created syntax type and return a tuple containing a `SyntaxHighlight.Style.Required` and a string unique for this syntax. The required style will be used when no specific style is defined for the syntax in the chosen theme. 24 | - Use the `SyntaxHighlight.Line.Helpers.toLines` to transform your reversed tokens and `syntaxToStyle` function into a `List Line`. 25 | - Expose this function in the file `SyntaxHighlight.elm`. 26 | - Add the language in `SyntaxHighlight.Theme.Type.Syntax`. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Elm Syntax Highlight 2 | 3 | Syntax highlighting in Elm. [Demo](https://pablohirafuji.github.io/elm-syntax-highlight/). 4 | 5 | ## Language support 6 | 7 | - Elm 8 | - Javascript 9 | - Xml 10 | - Css 11 | - Python (Thanks [@brandly](https://github.com/brandly)!) 12 | - SQL (Thanks [@oschmid](https://github.com/oschmid)!) 13 | - JSON 14 | - Nix (Thanks [@anddani](https://github.com/anddani)!) 15 | - Kotlin (Thanks [@anddani](https://github.com/anddani)!) 16 | - Go (Thanks [@ahmedakef](https://github.com/ahmedakef)!) 17 | 18 | And there is a `noLang` generic option for when the language is unknown (Thanks [@Anton-4](https://github.com/Anton-4)!). 19 | 20 | ## Themes 21 | 22 | You can define the theme either by copying and pasting the theme styles into your `.css` file or using the `useTheme` helper. 23 | 24 | ### Copying and pasting the theme 25 | 26 | All themes and required styles can be found [here](https://pablohirafuji.github.io/elm-syntax-highlight/themes.html). 27 | 28 | ### Using `useTheme` helper 29 | 30 | Place the `useTheme` function with your chosen theme anywhere on your view. 31 | 32 | ```elm 33 | import SyntaxHighlight exposing (useTheme, monokai, elm, toBlockHtml) 34 | 35 | view : Model -> Html msg 36 | view model = 37 | div [] 38 | [ useTheme monokai 39 | , elm model.elmCode 40 | |> Result.map (toBlockHtml (Just 1)) 41 | |> Result.withDefault 42 | (pre [] [ code [] [ text model.elmCode ]]) 43 | ] 44 | ``` 45 | 46 | ## Thanks 47 | 48 | Thank you Evan for bringing joy to the frontend. 49 | -------------------------------------------------------------------------------- /src/SyntaxHighlight/Theme/OneDark.elm: -------------------------------------------------------------------------------- 1 | module SyntaxHighlight.Theme.OneDark exposing (css, theme) 2 | 3 | import SyntaxHighlight.Style exposing (Color(..), RequiredStyles, backgroundColor, italic, noEmphasis, textColor) 4 | import SyntaxHighlight.Theme.Type exposing (Theme, toCss) 5 | 6 | 7 | 8 | {- 9 | Author: Baransu (https://github.com/Baransu) 10 | Atom One Dark inspired theme 11 | https://github.com/atom/one-dark-syntax 12 | 13 | base: #282c34 14 | mono-1: #abb2bf 15 | mono-2: #818896 16 | mono-3: #5c6370 17 | hue-1: #56b6c2 18 | hue-2: #61aeee 19 | hue-3: #c678dd 20 | hue-4: #98c379 21 | hue-5: #e06c75 22 | hue-5-2: #be5046 23 | hue-6: #d19a66 24 | hue-6-2: #e6c07b 25 | -} 26 | 27 | 28 | css : String 29 | css = 30 | toCss theme 31 | 32 | 33 | theme : Theme 34 | theme = 35 | { requiredStyles = requiredStyles 36 | , customStyles = [] 37 | } 38 | 39 | 40 | requiredStyles : RequiredStyles 41 | requiredStyles = 42 | { default = noEmphasis (Hex "#abb2bf") (Hex "#282c34") 43 | , highlight = backgroundColor (Rgba 229 231 235 0.1) 44 | , addition = backgroundColor (Rgba 40 124 82 0.4) 45 | , deletion = backgroundColor (Rgba 136 64 67 0.4) 46 | , comment = textColor (Hex "#5c6370") |> italic 47 | , style1 = textColor (Hex "#d19a66") 48 | , style2 = textColor (Hex "#98c379") 49 | , style3 = textColor (Hex "#c678dd") 50 | , style4 = textColor (Hex "#c678dd") 51 | , style5 = textColor (Hex "#61aeee") 52 | , style6 = textColor (Hex "#d19a66") 53 | , style7 = textColor (Hex "#abb2bf") 54 | } 55 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ### 3.7.0 4 | 5 | Add Go language support (#28). Thanks @ahmedakef! 6 | 7 | ### 3.6.0 8 | 9 | Add Kotlin language support (#27). Thanks @anddani! 10 | 11 | ### 3.5.0 12 | 13 | Add Nix language support (#23). Thanks @anddani! 14 | 15 | ### 3.4.1 16 | 17 | Fix JSON support for numbers in exponential notation (#17). Thanks @jackgene! 18 | 19 | ### 3.4.0 20 | 21 | Add `noLang` for unknown language with generic styling (#13). Thanks @Anton-4! 22 | 23 | ### 3.3.0 24 | 25 | Add `toCustom` function (#12). Thanks @BrianHicks for the idea! 26 | 27 | ### 3.2.0 28 | 29 | Add Json support (#11). 30 | 31 | ### 3.1.1 32 | 33 | Fix Xml declarations (#10). 34 | 35 | ### 3.1.0 36 | 37 | Add SQL support. Thanks @oschmid! 38 | 39 | ### 3.0.0 40 | 41 | Update to 0.19. 42 | 43 | ### 2.1.0 44 | 45 | Add Python support. Thanks @brandly! 46 | 47 | ### 2.0.0 48 | 49 | - Modified how themes are made. Now it has a lot more flexibility 50 | while mantaining consistency with future languages. Thanks @Baransu 51 | for pointing it out! 52 | - Removed `Line` exposition. It was exposed to allow custom output 53 | formats (e.g.: console), but I think it makes sense to concentrate 54 | these outputs in this package. 55 | - Added pure string html output. 56 | - Added console output. 57 | 58 | ### 1.1.0 59 | 60 | - Add CSS language support, with `SyntaxHighlight.css` 61 | - Add One Dark theme, with `SyntaxHighlight.oneDark`. Thanks @Baransu! 62 | 63 | ### 1.0.0 64 | 65 | Package published with the following languages: 66 | 67 | - Elm 68 | - Javascript 69 | - Xml 70 | 71 | With `monokai` and `github` themes. 72 | -------------------------------------------------------------------------------- /.github/workflows/test-build-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Test, Build, Deploy and Publish 2 | on: 3 | push: 4 | branches: 5 | - master 6 | permissions: 7 | contents: write 8 | jobs: 9 | build-and-deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v4 14 | with: 15 | fetch-depth: 1 16 | 17 | - uses: nixbuild/nix-quick-install-action@v30 18 | - run: nix build --version 19 | 20 | - uses: actions/cache@v4 21 | id: elm-cache 22 | with: 23 | path: ~/.elm 24 | key: ${{ runner.os }}-elm--home-${{ hashFiles('**/elm.json') }} 25 | 26 | - uses: nix-community/cache-nix-action@v6 27 | with: 28 | # restore and save a cache using this key 29 | primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} 30 | # if there's no cache hit, restore a cache by this prefix 31 | restore-prefixes-first-match: nix-${{ runner.os }}- 32 | # collect garbage until Nix store size (in bytes) is at most this number 33 | # before trying to save a new cache 34 | # 1 GB = 1073741824 B 35 | gc-max-store-size-linux: 1073741824 36 | 37 | - name: Test 38 | run: nix develop --command elm-test 39 | 40 | - name: Build demo 41 | run: nix develop --command build-demo 42 | 43 | - name: Build themes page 44 | run: nix develop --command build-themes 45 | 46 | - name: Deploy demo 47 | uses: JamesIves/github-pages-deploy-action@v4 48 | with: 49 | branch: gh-pages 50 | folder: demo/build 51 | clean: true 52 | -------------------------------------------------------------------------------- /demo/themes-page/Main.elm: -------------------------------------------------------------------------------- 1 | port module Main exposing (Msg, ThemeModel, init, main, requiredStyles, themesList, update) 2 | 3 | import SyntaxHighlight as SH 4 | import SyntaxHighlight.Theme as Theme 5 | 6 | 7 | main : Program () () Msg 8 | main = 9 | Platform.worker 10 | { init = \_ -> init 11 | , update = update 12 | , subscriptions = \_ -> Sub.none 13 | } 14 | 15 | 16 | 17 | -- TYPES 18 | 19 | 20 | type alias Msg = 21 | () 22 | 23 | 24 | type alias ThemeModel = 25 | { name : String 26 | , content : String 27 | } 28 | 29 | 30 | init : ( (), Cmd Msg ) 31 | init = 32 | ( () 33 | , themesList 34 | (List.map 35 | (\( name, content ) -> 36 | ThemeModel 37 | name 38 | (SH.css (String.trim content) 39 | |> Result.map (SH.toStaticBlockHtml (Just 1)) 40 | |> Result.withDefault (String.trim content) 41 | ) 42 | ) 43 | (requiredStyles :: Theme.all) 44 | ) 45 | ) 46 | 47 | 48 | requiredStyles : ( String, String ) 49 | requiredStyles = 50 | ( "Required Styles", """pre.elmsh { 51 | padding: 10px; 52 | margin: 0; 53 | text-align: left; 54 | overflow: auto; 55 | } 56 | code.elmsh { 57 | padding: 0; 58 | } 59 | .elmsh-line:before { 60 | content: attr(data-elmsh-lc); 61 | display: inline-block; 62 | text-align: right; 63 | width: 40px; 64 | padding: 0 20px 0 0; 65 | opacity: 0.3; 66 | }""" ) 67 | 68 | 69 | update : Msg -> () -> ( (), Cmd Msg ) 70 | update msg model = 71 | ( model, Cmd.none ) 72 | 73 | 74 | port themesList : List ThemeModel -> Cmd msg 75 | -------------------------------------------------------------------------------- /src/SyntaxHighlight/Line.elm: -------------------------------------------------------------------------------- 1 | module SyntaxHighlight.Line exposing 2 | ( Line, Fragment, Highlight(..) 3 | , highlightLines 4 | ) 5 | 6 | {-| A parsed highlighted line. 7 | 8 | @docs Line, Fragment, Highlight 9 | 10 | 11 | ## Helpers 12 | 13 | @docs highlightLines 14 | 15 | -} 16 | 17 | import SyntaxHighlight.Style as Style 18 | 19 | 20 | {-| A line holds information about its fragments and if is highlighted in any way. 21 | -} 22 | type alias Line = 23 | { fragments : List Fragment 24 | , highlight : Maybe Highlight 25 | } 26 | 27 | 28 | {-| A fragment holds information about the text being styled, the style and additional class to be applied. 29 | -} 30 | type alias Fragment = 31 | { text : String 32 | , requiredStyle : Style.Required 33 | , additionalClass : String 34 | } 35 | 36 | 37 | type Highlight 38 | = Normal 39 | | Add 40 | | Del 41 | 42 | 43 | highlightLines : Maybe Highlight -> Int -> Int -> List Line -> List Line 44 | highlightLines maybeHighlight start end lines = 45 | let 46 | length = 47 | List.length lines 48 | 49 | start_ = 50 | if start < 0 then 51 | length + start 52 | 53 | else 54 | start 55 | 56 | end_ = 57 | if end < 0 then 58 | length + end 59 | 60 | else 61 | end 62 | in 63 | List.indexedMap (highlightLinesHelp maybeHighlight start_ end_) lines 64 | 65 | 66 | highlightLinesHelp : Maybe Highlight -> Int -> Int -> Int -> Line -> Line 67 | highlightLinesHelp maybeHighlight start end index line = 68 | if index >= start && index < end then 69 | { line | highlight = maybeHighlight } 70 | 71 | else 72 | line 73 | -------------------------------------------------------------------------------- /src/SyntaxHighlight/Theme/Monokai.elm: -------------------------------------------------------------------------------- 1 | module SyntaxHighlight.Theme.Monokai exposing (css, theme) 2 | 3 | import SyntaxHighlight.Language.Css as Css 4 | import SyntaxHighlight.Language.Elm as Elm 5 | import SyntaxHighlight.Language.Javascript as JS 6 | import SyntaxHighlight.Style exposing (Color(..), RequiredStyles, backgroundColor, bold, italic, noEmphasis, textColor) 7 | import SyntaxHighlight.Theme.Type as Type exposing (Syntax(..), Theme, toCss) 8 | 9 | 10 | 11 | -- Monokai inspired theme 12 | 13 | 14 | css : String 15 | css = 16 | toCss theme 17 | 18 | 19 | theme : Theme 20 | theme = 21 | { requiredStyles = requiredStyles 22 | , customStyles = 23 | [ ( [ Elm Elm.TypeSignature 24 | , Javascript JS.DeclarationKeyword 25 | , Css Css.Property 26 | ] 27 | , textColor (Hex "#66d9ef") |> italic 28 | ) 29 | , ( [ Javascript JS.ClassExtends ] 30 | , textColor (Hex "#a6e22e") |> italic 31 | ) 32 | , ( [ Css (Css.AtRule Css.Identifier) ] 33 | , textColor (Hex "#f92672") |> bold 34 | ) 35 | ] 36 | } 37 | 38 | 39 | requiredStyles : RequiredStyles 40 | requiredStyles = 41 | { default = noEmphasis (Hex "#f8f8f2") (Hex "#23241f") 42 | , highlight = backgroundColor (Hex "#343434") 43 | , addition = backgroundColor (Hex "#003800") 44 | , deletion = backgroundColor (Hex "#380000") 45 | , comment = textColor (Hex "#75715e") 46 | , style1 = textColor (Hex "#ae81ff") 47 | , style2 = textColor (Hex "#e6db74") 48 | , style3 = textColor (Hex "#f92672") 49 | , style4 = textColor (Hex "#66d9ef") 50 | , style5 = textColor (Hex "#a6e22e") 51 | , style6 = textColor (Hex "#ae81ff") 52 | , style7 = textColor (Hex "#fd971f") 53 | } 54 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Development environment"; 3 | 4 | inputs.nixpkgs.url = "github:NixOS/nixpkgs/release-24.11"; 5 | 6 | outputs = { self, nixpkgs }: 7 | let 8 | supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; 9 | forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f { 10 | pkgs = import nixpkgs { inherit system; }; 11 | }); 12 | in 13 | { 14 | devShells = forEachSupportedSystem ({ pkgs }: { 15 | default = pkgs.mkShell { 16 | packages = 17 | (with pkgs.elmPackages; [ 18 | elm 19 | elm-test 20 | elm-format 21 | ]) ++ (with pkgs; [ 22 | nil 23 | nixpkgs-fmt 24 | nodejs_20 25 | nodePackages.uglify-js 26 | 27 | (writeScriptBin "run-demo" '' 28 | cd demo 29 | elm reactor 30 | '') 31 | 32 | (writeScriptBin "build-demo" '' 33 | cd demo 34 | elm make src/Main.elm --optimize --output build/index.js 35 | cp -f index.html build/index.html 36 | uglifyjs build/index.js --compress "pure_funcs=[F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9],pure_getters,keep_fargs=false,unsafe_comps,unsafe" | uglifyjs --mangle --output build/index.js 37 | '') 38 | 39 | (writeScriptBin "build-themes" '' 40 | cd demo/themes-page 41 | elm make Main.elm --output elm-themes.js 42 | node make-themes.js 43 | rm elm-themes.js 44 | cd .. 45 | mv -f themes-page/themes.html build 46 | '') 47 | 48 | ]); 49 | }; 50 | }); 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /src/SyntaxHighlight/Language/NoLang.elm: -------------------------------------------------------------------------------- 1 | module SyntaxHighlight.Language.NoLang exposing 2 | ( Syntax(..) 3 | , syntaxToStyle 4 | -- Exposed for testing 5 | 6 | , toLines 7 | , toRevTokens 8 | ) 9 | 10 | import Parser exposing (DeadEnd, Parser, Step(..), chompIf, getChompedString, loop, map, oneOf, succeed, symbol) 11 | import SyntaxHighlight.Language.Helpers exposing (chompIfThenWhile, isSpace) 12 | import SyntaxHighlight.Language.Type as T 13 | import SyntaxHighlight.Line exposing (Line) 14 | import SyntaxHighlight.Line.Helpers as Line 15 | import SyntaxHighlight.Style as Style exposing (Required(..)) 16 | 17 | 18 | type alias Token = 19 | T.Token Syntax 20 | 21 | 22 | type Syntax 23 | = String 24 | 25 | 26 | syntaxToStyle : Syntax -> ( Style.Required, String ) 27 | syntaxToStyle syntax = 28 | case syntax of 29 | String -> 30 | ( Default, "nolang" ) 31 | 32 | 33 | toLines : String -> Result (List DeadEnd) (List Line) 34 | toLines = 35 | Parser.run toRevTokens 36 | >> Result.map (Line.toLines syntaxToStyle) 37 | 38 | 39 | toRevTokens : Parser (List Token) 40 | toRevTokens = 41 | loop [] mainLoop 42 | 43 | 44 | mainLoop : List Token -> Parser (Step (List Token) (List Token)) 45 | mainLoop revTokens = 46 | oneOf 47 | [ whitespace 48 | |> map (\n -> Loop (n :: revTokens)) 49 | , chompIf (always True) 50 | |> getChompedString 51 | |> map (\b -> Loop (( T.Normal, b ) :: revTokens)) 52 | , succeed (Done revTokens) 53 | ] 54 | 55 | 56 | 57 | -- Helpers 58 | 59 | 60 | whitespace : Parser Token 61 | whitespace = 62 | oneOf 63 | [ space 64 | , lineBreak 65 | ] 66 | 67 | 68 | space : Parser Token 69 | space = 70 | chompIfThenWhile isSpace 71 | |> getChompedString 72 | |> map (\b -> ( T.Normal, b )) 73 | 74 | 75 | lineBreak : Parser Token 76 | lineBreak = 77 | symbol "\n" 78 | |> map (\_ -> ( T.LineBreak, "\n" )) 79 | -------------------------------------------------------------------------------- /src/SyntaxHighlight/Line/Helpers.elm: -------------------------------------------------------------------------------- 1 | module SyntaxHighlight.Line.Helpers exposing (toLines) 2 | 3 | import SyntaxHighlight.Language.Type as T exposing (Syntax(..), Token) 4 | import SyntaxHighlight.Line exposing (Fragment, Line) 5 | import SyntaxHighlight.Style as Style exposing (Required(..)) 6 | 7 | 8 | toLines : (a -> ( Required, String )) -> List (Token a) -> List Line 9 | toLines toStyle revTokens = 10 | List.foldl (toLinesHelp toStyle) ( [], [], Nothing ) revTokens 11 | |> (\( lines, frags, _ ) -> newLine frags :: lines) 12 | 13 | 14 | toLinesHelp : (a -> ( Required, String )) -> Token a -> ( List Line, List Fragment, Maybe (Syntax a) ) -> ( List Line, List Fragment, Maybe (Syntax a) ) 15 | toLinesHelp toStyle ( syntax, text ) ( lines, fragments, maybeLastSyntax ) = 16 | if syntax == LineBreak then 17 | ( newLine fragments :: lines 18 | , [ toFragment toStyle ( syntax, text ) ] 19 | , Nothing 20 | ) 21 | 22 | else if Just syntax == maybeLastSyntax then 23 | -- Concat same syntax sequence to reduce html elements. 24 | case fragments of 25 | headFrag :: tailFrags -> 26 | ( lines 27 | , { headFrag | text = text ++ headFrag.text } 28 | :: tailFrags 29 | , maybeLastSyntax 30 | ) 31 | 32 | _ -> 33 | ( lines 34 | , toFragment toStyle ( syntax, text ) :: fragments 35 | , maybeLastSyntax 36 | ) 37 | 38 | else 39 | ( lines 40 | , toFragment toStyle ( syntax, text ) :: fragments 41 | , Just syntax 42 | ) 43 | 44 | 45 | toFragment : (a -> ( Required, String )) -> Token a -> Fragment 46 | toFragment toStyle ( syntax, text ) = 47 | case syntax of 48 | Normal -> 49 | { text = text 50 | , requiredStyle = Default 51 | , additionalClass = "" 52 | } 53 | 54 | T.Comment -> 55 | { text = text 56 | , requiredStyle = Style.Comment 57 | , additionalClass = "" 58 | } 59 | 60 | LineBreak -> 61 | { text = text 62 | , requiredStyle = Default 63 | , additionalClass = "" 64 | } 65 | 66 | C c -> 67 | let 68 | ( requiredStyle, additionalClass ) = 69 | toStyle c 70 | in 71 | { text = text 72 | , requiredStyle = requiredStyle 73 | , additionalClass = additionalClass 74 | } 75 | 76 | 77 | newLine : List Fragment -> Line 78 | newLine fragments = 79 | { fragments = fragments 80 | , highlight = Nothing 81 | } 82 | -------------------------------------------------------------------------------- /demo/themes-page/themes-template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Elm Syntax Highlight Themes 8 | 132 | 133 | 134 | 135 |

    Elm Syntax Highlight Themes

    136 |

    Package / GitHub / Demo

    137 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /tests/Language/Json.elm: -------------------------------------------------------------------------------- 1 | module Language.Json exposing (suite) 2 | 3 | import Expect exposing (Expectation, equal, equalLists, onFail) 4 | import Fuzz exposing (string) 5 | import Parser 6 | import Result exposing (Result(..)) 7 | import SyntaxHighlight.Language.Json as Json exposing (Syntax(..), toRevTokens) 8 | import SyntaxHighlight.Language.Type as T exposing (Syntax(..)) 9 | import Test exposing (..) 10 | 11 | 12 | suite : Test 13 | suite = 14 | describe "JSON Language Test Suite" 15 | [ numberTest "integer zero" "0" 16 | , numberTest "decimal zero" "0.0" 17 | , numberTest "life, the universe, everything" "42" 18 | , numberTest "negative value" "-1" 19 | , numberTest "negative decimal" "-1.2345" 20 | , numberTest "Euler's number" "2.71828" 21 | , numberTest "Avogadro's number exponent (E) notation" "6.0221409E23" 22 | , numberTest "Avogadro's number exponent (e) notation" "6.0221409e23" 23 | , numberTest "Avogadro's number exponent (E+) notation" "6.0221409E+23" 24 | , numberTest "Avogadro's number exponent (e+) notation" "6.0221409e+23" 25 | , numberTest "Gauss' constant exponent (E) notation" "8.346268E-1" 26 | , numberTest "Gauss' constant exponent (e) notation" "8.346268e-1" 27 | , fuzz string "Fuzz string" <| 28 | \fuzzStr -> 29 | Parser.run Json.toRevTokens fuzzStr 30 | |> Result.map 31 | (List.reverse 32 | >> List.map Tuple.second 33 | >> String.concat 34 | ) 35 | |> equal (Ok fuzzStr) 36 | |> onFail ("Resulting error string: \"" ++ fuzzStr ++ "\"") 37 | ] 38 | 39 | 40 | numberTest : String -> String -> Test 41 | numberTest testName testStr = 42 | describe ("Number :" ++ testName) 43 | [ equalTest "number" 44 | ( "{\"number\": " ++ testStr ++ "}" ) 45 | ( Ok [(C Object,"{"),(C ObjectKey,"\""),(C ObjectKey,"number"),(C ObjectKey,"\""),(C Object,":"),(Normal," "),(C Number,testStr),(C Object,"}")]) 46 | ] 47 | 48 | 49 | equalTest : String -> String -> Result (List Parser.DeadEnd) (List ( T.Syntax Json.Syntax, String )) -> Test 50 | equalTest testName testStr testResult = 51 | describe testName 52 | [ test "Syntax equality" <| 53 | \() -> 54 | Parser.run Json.toRevTokens testStr 55 | |> Result.map List.reverse 56 | |> equal testResult 57 | , test "String equality" <| 58 | \() -> 59 | Parser.run Json.toRevTokens testStr 60 | |> Result.map 61 | (List.reverse 62 | >> List.map Tuple.second 63 | >> String.concat 64 | ) 65 | |> equal (Ok testStr) 66 | ] 67 | -------------------------------------------------------------------------------- /src/SyntaxHighlight/Theme/Type.elm: -------------------------------------------------------------------------------- 1 | module SyntaxHighlight.Theme.Type exposing (Syntax(..), Theme, syntaxToSelector, syntaxesToSelectors, toCss) 2 | 3 | import SyntaxHighlight.Language.Css as Css 4 | import SyntaxHighlight.Language.Elm as Elm 5 | import SyntaxHighlight.Language.Javascript as Javascript 6 | import SyntaxHighlight.Language.Nix as Nix 7 | import SyntaxHighlight.Language.NoLang as NoLang 8 | import SyntaxHighlight.Language.Python as Python 9 | import SyntaxHighlight.Language.Sql as Sql 10 | import SyntaxHighlight.Language.Xml as Xml 11 | import SyntaxHighlight.Style as Style exposing (RequiredStyles, Style) 12 | 13 | 14 | type alias Theme = 15 | { requiredStyles : RequiredStyles 16 | , customStyles : List ( List Syntax, Style ) 17 | } 18 | 19 | 20 | type Syntax 21 | = Elm Elm.Syntax 22 | | Xml Xml.Syntax 23 | | Javascript Javascript.Syntax 24 | | Css Css.Syntax 25 | | Python Python.Syntax 26 | | Sql Sql.Syntax 27 | | Nix Nix.Syntax 28 | | NoLang NoLang.Syntax 29 | 30 | 31 | toCss : Theme -> String 32 | toCss { requiredStyles, customStyles } = 33 | [ ( ".elmsh", requiredStyles.default ) 34 | , ( ".elmsh-hl", requiredStyles.highlight ) 35 | , ( ".elmsh-add", requiredStyles.addition ) 36 | , ( ".elmsh-del", requiredStyles.deletion ) 37 | , ( ".elmsh-comm", requiredStyles.comment ) 38 | , ( ".elmsh1", requiredStyles.style1 ) 39 | , ( ".elmsh2", requiredStyles.style2 ) 40 | , ( ".elmsh3", requiredStyles.style3 ) 41 | , ( ".elmsh4", requiredStyles.style4 ) 42 | , ( ".elmsh5", requiredStyles.style5 ) 43 | , ( ".elmsh6", requiredStyles.style6 ) 44 | , ( ".elmsh7", requiredStyles.style7 ) 45 | ] 46 | ++ List.map (Tuple.mapFirst syntaxesToSelectors) customStyles 47 | |> Style.toCss 48 | 49 | 50 | syntaxesToSelectors : List Syntax -> String 51 | syntaxesToSelectors syntaxes = 52 | List.map syntaxToSelector syntaxes 53 | |> List.map ((++) ".elmsh-") 54 | |> List.intersperse ", " 55 | |> String.concat 56 | 57 | 58 | syntaxToSelector : Syntax -> String 59 | syntaxToSelector syntax = 60 | case syntax of 61 | Elm elmSyntax -> 62 | Elm.syntaxToStyle elmSyntax 63 | |> Tuple.second 64 | 65 | Xml xmlSyntax -> 66 | Xml.syntaxToStyle xmlSyntax 67 | |> Tuple.second 68 | 69 | Javascript jsSyntax -> 70 | Javascript.syntaxToStyle jsSyntax 71 | |> Tuple.second 72 | 73 | Css cssSyntax -> 74 | Css.syntaxToStyle cssSyntax 75 | |> Tuple.second 76 | 77 | Python pythonSyntax -> 78 | Python.syntaxToStyle pythonSyntax 79 | |> Tuple.second 80 | 81 | Sql sqlSyntax -> 82 | Sql.syntaxToStyle sqlSyntax 83 | |> Tuple.second 84 | 85 | Nix nixSyntax -> 86 | Nix.syntaxToStyle nixSyntax 87 | |> Tuple.second 88 | 89 | NoLang noLangSyntax -> 90 | NoLang.syntaxToStyle noLangSyntax 91 | |> Tuple.second 92 | -------------------------------------------------------------------------------- /themes.md: -------------------------------------------------------------------------------- 1 | # Themes 2 | 3 | - [Required Styles](https://github.com/pablohirafuji/elm-syntax-highlight/blob/master/themes.md#required-styles) 4 | - [Monokai](https://github.com/pablohirafuji/elm-syntax-highlight/blob/master/themes.md#monokai) 5 | - [GitHub](https://github.com/pablohirafuji/elm-syntax-highlight/blob/master/themes.md#github) 6 | - [One Dark](https://github.com/pablohirafuji/elm-syntax-highlight/blob/master/themes.md#one-dark) 7 | 8 | ## Required styles 9 | 10 | ```css 11 | pre.elmsh { 12 | padding: 10px; 13 | margin: 0; 14 | text-align: left; 15 | overflow: auto; 16 | } 17 | code.elmsh { 18 | padding: 0; 19 | } 20 | .elmsh-line:before { 21 | content: attr(data-elmsh-lc); 22 | display: inline-block; 23 | text-align: right; 24 | width: 40px; 25 | padding: 0 20px 0 0; 26 | opacity: 0.3; 27 | } 28 | ``` 29 | 30 | ## Monokai 31 | 32 | ```css 33 | .elmsh { 34 | background: #23241f; 35 | color: #f8f8f2; 36 | } 37 | 38 | .elmsh-hl { 39 | background: #0e0f0d; 40 | } 41 | 42 | .elmsh-add { 43 | background: #003800; 44 | } 45 | 46 | .elmsh-del { 47 | background: #380000; 48 | } 49 | 50 | .elmsh-strong { 51 | font-weight: bold; 52 | } 53 | 54 | .elmsh-emphasis { 55 | font-style: italic; 56 | } 57 | 58 | .elmsh1 { 59 | color: #75715e; 60 | } 61 | .elmsh2 { 62 | color: #e6db74; 63 | } 64 | 65 | .elmsh3 { 66 | color: #f92672; 67 | } 68 | 69 | .elmsh4 { 70 | color: #66d9ef; 71 | } 72 | 73 | .elmsh5 { 74 | color: #a6e22e; 75 | } 76 | 77 | .elmsh6 { 78 | color: #ae81ff; 79 | } 80 | 81 | .elmsh7 { 82 | color: #fd971f; 83 | } 84 | ``` 85 | 86 | ## GitHub 87 | 88 | ```css 89 | .elmsh { 90 | background: white; 91 | color: #24292e; 92 | } 93 | 94 | .elmsh-hl { 95 | background: #fffbdd; 96 | } 97 | 98 | .elmsh-add { 99 | background: #eaffea; 100 | } 101 | 102 | .elmsh-del { 103 | background: #ffecec; 104 | } 105 | 106 | .elmsh-strong { 107 | font-weight: bold; 108 | } 109 | 110 | .elmsh-emphasis { 111 | font-style: italic; 112 | } 113 | 114 | .elmsh1 { 115 | color: #969896; 116 | } 117 | .elmsh2 { 118 | color: #df5000; 119 | } 120 | 121 | .elmsh3 { 122 | color: #d73a49; 123 | } 124 | 125 | .elmsh4 { 126 | color: #0086b3; 127 | } 128 | 129 | .elmsh5 { 130 | color: #63a35c; 131 | } 132 | 133 | .elmsh6 { 134 | color: #005cc5; 135 | } 136 | 137 | .elmsh7 { 138 | color: #795da3; 139 | } 140 | ``` 141 | 142 | ## One Dark 143 | 144 | ```css 145 | .elmsh { 146 | background: #282c34; 147 | color: #abb2bf; 148 | } 149 | 150 | .elmsh-hl { 151 | background: rgba(229,231,235, 0.1); 152 | } 153 | 154 | .elmsh-add { 155 | background: rgba(40,124,82, 0.4); 156 | } 157 | 158 | .elmsh-del { 159 | background: rgba(136,64,67, 0.4); 160 | } 161 | 162 | .elmsh-strong { 163 | font-weight: bold; 164 | } 165 | 166 | .elmsh-emphasis { 167 | font-style: italic; 168 | } 169 | 170 | .elmsh1 { 171 | color: #5c6370; 172 | font-style: italic 173 | } 174 | .elmsh2 { 175 | color: #98c379; 176 | } 177 | 178 | .elmsh3 { 179 | color: #c678dd; 180 | } 181 | 182 | .elmsh4 { 183 | color: #c678dd; 184 | } 185 | 186 | .elmsh5 { 187 | color: #61aeee; 188 | } 189 | 190 | .elmsh6 { 191 | color: #c678dd; 192 | } 193 | 194 | .elmsh7 { 195 | color: #abb2bf; 196 | } 197 | ``` 198 | -------------------------------------------------------------------------------- /tests/Language/Xml.elm: -------------------------------------------------------------------------------- 1 | module Language.Xml exposing (suite) 2 | 3 | import Expect exposing (Expectation, equal, onFail) 4 | import Fuzz exposing (string) 5 | import Parser 6 | import Result exposing (Result(..)) 7 | import SyntaxHighlight.Language.Type as T exposing (Syntax(..)) 8 | import SyntaxHighlight.Language.Xml as Xml exposing (Syntax(..), toRevTokens) 9 | import Test exposing (..) 10 | 11 | 12 | suite : Test 13 | suite = 14 | describe "Xml Language Test Suite" 15 | [ equalTest "Element" "

    Hero

    " <| 16 | Ok 17 | [ ( Normal, "<" ) 18 | , ( C Tag, "p" ) 19 | , ( Normal, " " ) 20 | , ( C Attribute, "class" ) 21 | , ( Normal, "=" ) 22 | , ( C AttributeValue, "\"" ) 23 | , ( C AttributeValue, "hero" ) 24 | , ( C AttributeValue, "\"" ) 25 | , ( Normal, ">Hero" ) 26 | , ( Normal, "" ) 29 | ] 30 | , equalTest "Comment" "