├── .gitignore ├── .travis.yml ├── Example.hs ├── LICENSE ├── README.md ├── Setup.hs ├── print.cabal ├── src └── Print.hs └── stack.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | *.sw[po] 2 | .stack-work 3 | dist 4 | .cabal-sandbox 5 | cabal.sandbox.config 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # NB: don't set `language: haskell` here 2 | language: c 3 | 4 | # See also https://github.com/hvr/multi-ghc-travis for more information 5 | 6 | # The following lines enable several GHC versions and/or HP versions 7 | # to be tested; often it's enough to test only against the last 8 | # release of a major GHC version. Setting HPVER implictly sets 9 | # GHCVER. Omit lines with versions you don't need/want testing for. 10 | env: 11 | - CABALVER=1.22 GHCVER=7.10.1 12 | - CABALVER=1.22 GHCVER=7.10.2 13 | - CABALVER=1.22 GHCVER=7.10.3 14 | - CABALVER=1.24 GHCVER=8.0.1 15 | 16 | # Note: the distinction between `before_install` and `install` is not 17 | # important. 18 | before_install: 19 | - case "$HPVER" in 20 | "") ;; 21 | 22 | "2014.2.0.0") 23 | export CABALVER=1.18 ; 24 | export GHCVER=7.8.3 ; 25 | echo "constraints:async==2.0.1.5,attoparsec==0.10.4.0,case-insensitive==1.1.0.3,fgl==5.5.0.1,GLUT==2.5.1.1,GLURaw==1.4.0.1,haskell-src==1.0.1.6,hashable==1.2.2.0,html==1.0.1.2,HTTP==4000.2.10,HUnit==1.2.5.2,mtl==2.1.3.1,network==2.4.2.3,OpenGL==2.9.2.0,OpenGLRaw==1.5.0.0,parallel==3.2.0.4,parsec==3.1.5,primitive==0.5.2.1,QuickCheck==2.6,random==1.0.1.1,regex-base==0.93.2,regex-compat==0.95.1,regex-posix==0.95.2,split==0.2.2,stm==2.4.2,syb==0.4.1,text==1.1.0.0,transformers==0.3.0.0,unordered-containers==0.2.4.0,vector==0.10.9.1,xhtml==3000.2.1,zlib==0.5.4.1" > cabal.config ;; 26 | 27 | "2013.2.0.0") 28 | export CABALVER=1.16 ; 29 | export GHCVER=7.6.3 ; 30 | echo "constraints:async==2.0.1.4,attoparsec==0.10.4.0,case-insensitive==1.0.0.1,cgi==3001.1.7.5,fgl==5.4.2.4,GLUT==2.4.0.0,GLURaw==1.3.0.0,haskell-src==1.0.1.5,hashable==1.1.2.5,html==1.0.1.2,HTTP==4000.2.8,HUnit==1.2.5.2,mtl==2.1.2,network==2.4.1.2,OpenGL==2.8.0.0,OpenGLRaw==1.3.0.0,parallel==3.2.0.3,parsec==3.1.3,QuickCheck==2.6,random==1.0.1.1,regex-base==0.93.2,regex-compat==0.95.1,regex-posix==0.95.2,split==0.2.2,stm==2.4.2,syb==0.4.0,text==0.11.3.1,transformers==0.3.0.0,unordered-containers==0.2.3.0,vector==0.10.0.1,xhtml==3000.2.1,zlib==0.5.4.1" > cabal.config ;; 31 | 32 | "2012.4.0.0") 33 | export CABALVER=1.16 ; 34 | export GHCVER=7.6.2 ; 35 | echo "constraints:async==2.0.1.3,cgi==3001.1.7.4,fgl==5.4.2.4,GLUT==2.1.2.1,haskell-src==1.0.1.5,html==1.0.1.2,HTTP==4000.2.5,HUnit==1.2.5.1,mtl==2.1.2,network==2.3.1.0,OpenGL==2.2.3.1,parallel==3.2.0.3,parsec==3.1.3,QuickCheck==2.5.1.1,random==1.0.1.1,regex-base==0.93.2,regex-compat==0.95.1,regex-posix==0.95.2,split==0.2.1.1,stm==2.4,syb==0.3.7,text==0.11.2.3,transformers==0.3.0.0,vector==0.10.0.1,xhtml==3000.2.1,zlib==0.5.4.0" > cabal.config ;; 36 | 37 | "2012.2.0.0") 38 | export CABALVER=1.16 ; 39 | export GHCVER=7.4.1 ; 40 | echo "constraints:cgi==3001.1.7.4,fgl==5.4.2.4,GLUT==2.1.2.1,haskell-src==1.0.1.5,html==1.0.1.2,HTTP==4000.2.3,HUnit==1.2.4.2,mtl==2.1.1,network==2.3.0.13,OpenGL==2.2.3.1,parallel==3.2.0.2,parsec==3.1.2,QuickCheck==2.4.2,random==1.0.1.1,regex-base==0.93.2,regex-compat==0.95.1,regex-posix==0.95.1,stm==2.3,syb==0.3.6.1,text==0.11.2.0,transformers==0.3.0.0,xhtml==3000.2.1,zlib==0.5.3.3" > cabal.config ;; 41 | 42 | "2011.4.0.0") 43 | export CABALVER=1.16 ; 44 | export GHCVER=7.0.4 ; 45 | echo "constraints:cgi==3001.1.7.4,fgl==5.4.2.4,GLUT==2.1.2.1,haskell-src==1.0.1.4,html==1.0.1.2,HUnit==1.2.4.2,network==2.3.0.5,OpenGL==2.2.3.0,parallel==3.1.0.1,parsec==3.1.1,QuickCheck==2.4.1.1,regex-base==0.93.2,regex-compat==0.95.1,regex-posix==0.95.1,stm==2.2.0.1,syb==0.3.3,xhtml==3000.2.0.4,zlib==0.5.3.1,HTTP==4000.1.2,deepseq==1.1.0.2" > cabal.config ;; 46 | 47 | *) 48 | export GHCVER=unknown ; 49 | echo "unknown/invalid Haskell Platform requested" ; 50 | exit 1 ;; 51 | 52 | esac 53 | 54 | - travis_retry sudo add-apt-repository -y ppa:hvr/ghc 55 | - travis_retry sudo apt-get update 56 | - travis_retry sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER 57 | - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH 58 | 59 | install: 60 | - cabal --version 61 | - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]" 62 | - travis_retry cabal update 63 | - cabal install --only-dependencies --enable-tests --enable-benchmarks 64 | 65 | # Here starts the actual work to be performed for the package under 66 | # test; any command which exits with a non-zero exit code causes the 67 | # build to fail. 68 | script: 69 | - if [ -f configure.ac ]; then autoreconf -i; fi 70 | # -v2 provides useful information for debugging 71 | - cabal configure --enable-tests --enable-benchmarks -v2 72 | 73 | # this builds all libraries and executables 74 | # (including tests/benchmarks) 75 | - cabal build 76 | 77 | # tests that a source-distribution can be generated 78 | - cabal sdist 79 | 80 | # check that the generated source-distribution can be built & installed 81 | - SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz && 82 | (cd dist && cabal install --force-reinstalls "$SRC_TGZ") 83 | 84 | # EOF 85 | -------------------------------------------------------------------------------- /Example.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | {-# LANGUAGE DeriveAnyClass #-} 3 | {-# LANGUAGE OverloadedStrings #-} 4 | {-# LANGUAGE ExtendedDefaultRules #-} 5 | {-# LANGUAGE NoImplicitPrelude #-} 6 | 7 | module Main where 8 | 9 | import Print 10 | import Protolude hiding (Show, show, print) 11 | 12 | data Animal 13 | = Dog 14 | | Cat 15 | deriving (Generic, Show) 16 | 17 | data T1 18 | = T1 Int Bool 19 | deriving (Generic, Show) 20 | 21 | data T2 22 | = T2 Int Bool 23 | | T3 { x :: Bool, y :: Int } 24 | deriving (Generic, Show) 25 | 26 | data B a = B 27 | { first :: Int 28 | , second :: a 29 | } deriving (Generic, Show) 30 | 31 | data I a b = a :. b 32 | deriving (Generic, Show) 33 | 34 | main :: IO () 35 | main = do 36 | print [Cat, Dog] 37 | print [0 :: Int,5..100] 38 | print (T1 42 False) 39 | print (T2 1 True, B 1 (T3 False 3)) 40 | print (B 3 [Cat, Dog]) 41 | print (show (0.5 :: Double) == show ((1/2) :: Double)) 42 | print ("継続は力なり" :: Text) 43 | print ("To be or not to be.\nThat is the question." :: Text) 44 | putStrLn (show (3.1415926535 :: Double)) 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2017, Stephen Diehl 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to 5 | deal in the Software without restriction, including without limitation the 6 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | sell copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Print 2 | ===== 3 | 4 | [![Build Status](https://travis-ci.org/sdiehl/print.svg?branch=master)](https://travis-ci.org/sdiehl/print) 5 | 6 | Simple printing with Text. This is a prototype, not production code. 7 | 8 | ```haskell 9 | base >= 4.6 && <4.10, 10 | text >= 1.2 && <1.3, 11 | text-format >= 0.3 && <0.4 12 | ``` 13 | 14 | ### Functions 15 | 16 | Replaces the Prelude function ``show``: 17 | 18 | ```haskell 19 | show :: Show a => a -> String 20 | ``` 21 | 22 | ... with a new one that uses Text. 23 | 24 | ```haskell 25 | show :: Show a => a -> Text 26 | ``` 27 | 28 | ### Instances 29 | 30 | A Text-based Show replacement can be derived with GHC's new 31 | ``-XDeriveAnyClass``. 32 | 33 | ```haskell 34 | {-# LANGUAGE DeriveAnyClass #-} 35 | 36 | data Animal 37 | = Dog 38 | | Cat 39 | deriving (Generic, Print.Show) 40 | ``` 41 | 42 | ### GHCi 43 | 44 | GHCI's default printing mechanism can be overloaded by adding the following to 45 | your ``.ghci`` file. Anything typed at the console will then use the modern 46 | ``print`` function instead of the Prelude. 47 | 48 | ```haskell 49 | import Print 50 | :set -interactive-print=Print.print 51 | ``` 52 | 53 | ### Building 54 | 55 | **Stack (Recommended)** 56 | 57 | ```bash 58 | $ stack build 59 | $ stack repl print:exe:Example 60 | ``` 61 | 62 | **Cabal** 63 | 64 | ```bash 65 | $ cabal sandbox init 66 | $ cabal install --only-dependencies 67 | $ cabal build 68 | $ cabal repl exe:Example 69 | ``` 70 | -------------------------------------------------------------------------------- /Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /print.cabal: -------------------------------------------------------------------------------- 1 | name: print 2 | version: 0.1.5 3 | synopsis: Simple printing for Text. 4 | description: Simple printing for Text and automatic deriving of Text Show. 5 | homepage: https://github.com/sdiehl/print 6 | license: MIT 7 | license-file: LICENSE 8 | author: Stephen Diehl 9 | maintainer: stephen.m.diehl@gmail.com 10 | copyright: 2016-2017 Stephen Diehl 11 | category: Prelude 12 | build-type: Simple 13 | cabal-version: >=1.10 14 | tested-with: 15 | GHC == 7.6.1, 16 | GHC == 7.6.2, 17 | GHC == 7.6.3, 18 | GHC == 7.8.1, 19 | GHC == 7.8.2, 20 | GHC == 7.8.3, 21 | GHC == 7.8.4, 22 | GHC == 7.10.1, 23 | GHC == 7.10.2, 24 | GHC == 7.10.3, 25 | GHC == 8.0.1 26 | Bug-Reports: https://github.com/sdiehl/print/issues 27 | 28 | description: 29 | Simple printing for Text. 30 | Source-Repository headl 31 | type: git 32 | location: git@github.com:sdiehl/print.git 33 | 34 | library 35 | exposed-modules: 36 | Print 37 | 38 | default-extensions: 39 | NoImplicitPrelude 40 | OverloadedStrings 41 | ExtendedDefaultRules 42 | FlexibleContexts 43 | FlexibleInstances 44 | 45 | ghc-options: 46 | -fwarn-implicit-prelude 47 | -fwarn-incomplete-patterns 48 | -fwarn-unused-imports 49 | 50 | build-depends: 51 | base >= 4.6 && <5.0, 52 | text >= 1.2 && <1.3, 53 | text-format >= 0.3 && <0.4 54 | 55 | hs-source-dirs: src 56 | default-language: Haskell2010 57 | 58 | executable Example 59 | default-language: Haskell2010 60 | main-is: Example.hs 61 | default-extensions: 62 | NoImplicitPrelude 63 | build-depends: 64 | base >= 4.6 && <5.0, 65 | text >= 1.2 && <1.3, 66 | text-format >= 0.3 && <0.4, 67 | print -any, 68 | 69 | -- doesn't require this, just for example 70 | protolude >= 0.1.5 71 | -------------------------------------------------------------------------------- /src/Print.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TypeOperators #-} 2 | {-# LANGUAGE FlexibleContexts #-} 3 | {-# LANGUAGE FlexibleInstances #-} 4 | {-# LANGUAGE DefaultSignatures #-} 5 | {-# LANGUAGE OverloadedStrings #-} 6 | {-# LANGUAGE ExtendedDefaultRules #-} 7 | 8 | module Print ( 9 | Show(showsPrec, show), 10 | ShowS, 11 | showChar, 12 | showText, 13 | showList, 14 | showList__, 15 | showParen, 16 | shows, 17 | 18 | con0, 19 | con1, 20 | 21 | print, 22 | ) where 23 | 24 | import Data.Int 25 | import Data.Word 26 | import Data.Char 27 | import Data.Maybe 28 | import Data.Monoid 29 | import Data.Either 30 | import Data.Function 31 | import Data.Foldable 32 | 33 | import Data.Text.Lazy (Text) 34 | import qualified Data.Text as T 35 | import qualified Data.Text.Lazy as TL 36 | import qualified Data.Text.Lazy.IO as TL 37 | 38 | import Data.Text.Buildable (build) 39 | import qualified Data.Text.Lazy.Builder as TB 40 | 41 | import GHC.Num 42 | import GHC.Exts hiding (build) 43 | import GHC.Base hiding (build) 44 | import GHC.Generics 45 | 46 | default (Text) 47 | 48 | 49 | type ShowS = TB.Builder -> TB.Builder 50 | 51 | data PType = Rec | Pref | Inf Text 52 | 53 | appPrec, appPrec1 :: Int 54 | appPrec = 10 55 | appPrec1 = 11 56 | 57 | showText :: Text -> ShowS 58 | showText = (<>) . TB.fromLazyText 59 | {-# INLINABLE showText #-} 60 | 61 | -- For compatability with GHC.Generics 62 | showString :: String -> ShowS 63 | showString s = (TB.fromString s <>) 64 | {-# INLINABLE showString #-} 65 | 66 | showChar :: Char -> ShowS 67 | showChar c = (TB.singleton c <>) 68 | {-# INLINABLE showChar #-} 69 | 70 | showSpace :: ShowS 71 | showSpace = showChar ' ' 72 | 73 | showParen :: Bool -> ShowS -> ShowS 74 | showParen True p = showChar '(' . p . showChar ')' 75 | showParen False p = p 76 | 77 | showBraces :: ShowS -> ShowS 78 | showBraces p = showChar '{' . p . showChar '}' 79 | 80 | showQuotes :: ShowS -> ShowS 81 | showQuotes p = showChar '"' . p . showChar '"' 82 | 83 | showList__ :: (a -> ShowS) -> [a] -> ShowS 84 | showList__ _ [] s = "[]" <> s 85 | showList__ showx (x:xs) s = "[" <> showx x (showl xs) 86 | where 87 | showl [] = "]" <> s 88 | showl (y:ys) = "," <> showx y (showl ys) 89 | 90 | showList :: Show a => [a] -> TB.Builder -> TB.Builder 91 | showList = showList__ shows 92 | 93 | shows :: (Show a) => a -> ShowS 94 | shows = showsPrec 0 95 | {-# INLINABLE shows #-} 96 | 97 | class Show a where 98 | showsPrec :: Int -> a -> ShowS 99 | show :: a -> TL.Text 100 | 101 | default showsPrec 102 | :: (Generic a, GShow (Rep a)) 103 | => Int -> a -> ShowS 104 | showsPrec i x = gshowsPrec Pref i (from x) 105 | 106 | show x = TB.toLazyText (shows x "") 107 | 108 | class GShow f where 109 | gshowsPrec :: PType -> Int -> f a -> ShowS 110 | basic :: f a -> Bool 111 | basic _ = False 112 | 113 | instance GShow U1 where 114 | gshowsPrec _ _ _ = id 115 | basic _ = True 116 | 117 | instance Show c => GShow (K1 i c) where 118 | gshowsPrec _ i (K1 fp) = showsPrec i fp 119 | 120 | instance (GShow f, Constructor c) => GShow (M1 C c f) where 121 | gshowsPrec t i c@(M1 fp) 122 | | conIsRecord c = 123 | showString (conName c) 124 | . showChar ' ' 125 | . showBraces (gshowsPrec Rec i fp) 126 | 127 | | otherwise = case conFixity c of 128 | Prefix -> showParen (i > appPrec && not (basic fp)) $ 129 | showString (conName c) 130 | . if basic fp then id else showChar ' ' 131 | . gshowsPrec t appPrec1 fp 132 | 133 | Infix _ m -> showParen (i > m) $ 134 | showBraces (gshowsPrec t m fp) 135 | 136 | instance (GShow f, Selector c) => GShow (M1 S c f) where 137 | gshowsPrec t i c@(M1 fp) = case t of 138 | Pref -> gshowsPrec t i fp 139 | Inf _ -> gshowsPrec t i fp 140 | Rec -> 141 | showString (selName c) 142 | . showText " = " 143 | . gshowsPrec t i fp 144 | 145 | instance (GShow f) => GShow (M1 D c f) where 146 | gshowsPrec t i (M1 fp) = gshowsPrec t i fp 147 | 148 | instance (GShow f, GShow g) => GShow (f :+: g) where 149 | gshowsPrec t i (L1 fp) = gshowsPrec t i fp 150 | gshowsPrec t i (R1 fp) = gshowsPrec t i fp 151 | 152 | instance (GShow a, GShow b) => GShow (a :*: b) where 153 | gshowsPrec t@Rec n (a :*: b) = 154 | gshowsPrec t n a 155 | . showText ", " 156 | . gshowsPrec t n b 157 | 158 | gshowsPrec t@Pref n (a :*: b) = 159 | gshowsPrec t (n+1) a 160 | . showChar ' ' 161 | . gshowsPrec t (n+1) b 162 | 163 | gshowsPrec t@(Inf s) n (a :*: b) = 164 | gshowsPrec t n a 165 | . showText s 166 | . gshowsPrec t n b 167 | 168 | -- Buildable instances 169 | 170 | instance Show Int where 171 | showsPrec _ n f = build n <> f 172 | 173 | instance Show Int8 where 174 | showsPrec _ n f = build n <> f 175 | 176 | instance Show Int16 where 177 | showsPrec _ n f = build n <> f 178 | 179 | instance Show Int32 where 180 | showsPrec _ n f = build n <> f 181 | 182 | instance Show Int64 where 183 | showsPrec _ n f = build n <> f 184 | 185 | instance Show Integer where 186 | showsPrec _ n f = build n <> f 187 | 188 | instance Show Word where 189 | showsPrec _ n f = build n <> f 190 | 191 | instance Show Word16 where 192 | showsPrec _ n f = build n <> f 193 | 194 | instance Show Word32 where 195 | showsPrec _ n f = build n <> f 196 | 197 | instance Show Word64 where 198 | showsPrec _ n f = build n <> f 199 | 200 | instance Show Float where 201 | showsPrec _ n f = build n <> f 202 | 203 | instance Show Double where 204 | showsPrec _ n f = build n <> f 205 | 206 | instance Show T.Text where 207 | showsPrec _ n f = build n <> f 208 | 209 | instance Show TL.Text where 210 | showsPrec _ n f = build n <> f 211 | 212 | instance Show TB.Builder where 213 | showsPrec _ n f = build n <> f 214 | 215 | instance Show Char where 216 | showsPrec _ '\'' = showText "'\\''" 217 | showsPrec _ c = showChar '\'' . showChar c . showChar '\'' 218 | 219 | instance Show a => Show [a] where 220 | showsPrec _ = showList 221 | 222 | con0 :: Text -> ShowS 223 | con0 = showText 224 | {-# INLINE con0 #-} 225 | 226 | con1 :: Show a => Text -> Int -> a -> ShowS 227 | con1 con p x = 228 | showParen (p > appPrec) $ 229 | showText con . 230 | showsPrec appPrec1 x 231 | {-# INLINE con1 #-} 232 | 233 | instance Show () where 234 | showsPrec _ () = showText "()" 235 | 236 | instance Show Bool where 237 | showsPrec _ True = showText "True" 238 | showsPrec _ False = showText "False" 239 | 240 | instance Show Ordering where 241 | showsPrec _ LT = showText "LT" 242 | showsPrec _ EQ = showText "EQ" 243 | showsPrec _ GT = showText "GT" 244 | 245 | instance Show a => Show (Maybe a) where 246 | showsPrec _ Nothing s = con0 "Nothing" s 247 | showsPrec p (Just x) s = con1 "Just " p x s 248 | 249 | instance (Show a, Show b) => Show (Either a b) where 250 | showsPrec p (Left x) s = con1 "Left " p x s 251 | showsPrec p (Right x) s = con1 "Right " p x s 252 | 253 | instance (Show a, Show b) => Show (a,b) where 254 | showsPrec _ (a,b) = showTuple [shows a, shows b] 255 | 256 | instance (Show a, Show b, Show c) => Show (a,b,c) where 257 | showsPrec _ (a,b,c) = showTuple [shows a, shows b, shows c] 258 | 259 | instance (Show a, Show b, Show c, Show d) => Show (a,b,c,d) where 260 | showsPrec _ (a,b,c,d) = showTuple [shows a, shows b, shows c, shows d] 261 | 262 | showTuple :: [ShowS] -> ShowS 263 | showTuple ss = 264 | showChar '(' 265 | . foldr1 (\s r -> s . showChar ',' . r) ss 266 | . showChar ')' 267 | 268 | print :: Show a => a -> IO () 269 | print = TL.putStrLn . show 270 | -------------------------------------------------------------------------------- /stack.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-7.14 2 | packages: 3 | - '.' 4 | extra-deps: [] 5 | flags: {} 6 | extra-package-dbs: [] 7 | --------------------------------------------------------------------------------