17 Commits
Author SHA1 Message Date
paul 9a4c1f17b7 Bump version to 0.5 2023-03-24 13:08:11 +01:00
paul 3d104ef50c Add allNames function 2023-03-24 13:06:17 +01:00
paul 976fbada7e Add text/plain rendering for /text 2023-03-24 12:59:34 +01:00
paul 0d59ded2ec Add newline after text table 2023-03-24 12:54:55 +01:00
paul ab667742da Bump version to 0.4 2023-03-24 12:53:38 +01:00
paul 647b5c2ad1 Rename /bytes to /utf8 2023-03-17 02:22:13 +01:00
paul 57173d14dd Limit number of returned codepoints 2023-03-17 02:19:15 +01:00
paul fde68ee833 Bump version to 0.3 2023-03-16 03:21:16 +01:00
paul 610c819483 Add some instructions for the Nix setup 2023-03-16 03:15:55 +01:00
paul 3fd4177cd4 Move common html code to its own function 2023-03-12 20:53:43 +01:00
paul 9881b44fa2 Add HTML version of /codepoints 2023-03-12 20:50:33 +01:00
paul 36f9bb390d Bump version 2023-03-10 18:51:13 +01:00
paul f5fd1089b1 Add /text endpoint 2023-03-10 18:46:34 +01:00
paul 5bdf69ef91 Regenerate hie.yaml 2023-03-10 18:33:05 +01:00
paul da2540c3fa Add docker image derivation 2023-03-09 02:51:12 +01:00
paul d5cd8905bb Reduce files copied into build 2023-03-09 02:22:34 +01:00
paul 66ad565cba Add nix derivation 2023-03-09 01:39:45 +01:00
10 changed files with 173 additions and 38 deletions
+1
View File
@@ -1,3 +1,4 @@
.stack-work/ .stack-work/
.vscode/ .vscode/
*.swp *.swp
result
+20
View File
@@ -1 +1,21 @@
# utoy # utoy
## Building the executable
```
$ $(nix-build utoy.nix)/bin/utoy
```
## Building the Docker image
```
$ docker load < $(nix-build nix/docker-image.nix)
```
## Development Shell
Includes Stack, `haskell-language-server`, `gen-hie` etc.
```
$ nix-shell
```
+94 -30
View File
@@ -61,28 +61,35 @@ app :: Application
app = serve (Proxy :: Proxy API) server app = serve (Proxy :: Proxy API) server
type API = type API =
"bytes" :> Capture "bytes" Text :> Get '[PlainText, HTML] BytesModel "utf8" :> Capture "bytes" Text :> Get '[PlainText, HTML] Utf8Model
:<|> "codepoints" :> Capture "codepoints" Text :> Get '[PlainText] CodepointsModel :<|> "codepoints" :> Capture "codepoints" Text :> Get '[PlainText, HTML] CodepointsModel
:<|> "text" :> Capture "text" Text :> Get '[PlainText, HTML] TextModel
server :: Server API server :: Server API
server = server =
bytesR :<|> codepointsR utf8R :<|> codepointsR :<|> textR
where where
bytesR bytesP = do utf8R bytesP = do
bytes <- Parsers.parseHexBytes bytesP `orThrow` const err400 bytes <- Parsers.parseHexBytes bytesP `orThrow` const err400
pure $ BytesModel $ Decode.decodeUtf8 bytes pure $ mkUtf8Model bytes
codepointsR codepointsP = do codepointsR codepointsP = do
codepoints' <- Parsers.parseCodepoints codepointsP `orThrow` const err400 codepoints' <- Parsers.parseCodepoints codepointsP `orThrow` const err400
pure $ mkCodepointsModel codepoints' pure $ mkCodepointsModel codepoints'
textR textP = do
pure $ TextModel textP
-- /bytes/<bytes> -- /bytes/<bytes>
newtype BytesModel = BytesModel newtype Utf8Model = Utf8Model
{ codepoints :: [([Word8], Either String Char)] { codepoints :: [([Word8], Either String Char)]
} }
instance MimeRender PlainText BytesModel where mkUtf8Model :: [Word8] -> Utf8Model
mkUtf8Model = Utf8Model . Decode.decodeUtf8
instance MimeRender PlainText Utf8Model where
mimeRender _ model = renderText $ mimeRender _ model = renderText $
Table.render " " $ concat Table.render " " $ concat
[ [ [ Table.cl $ Text.pack $ unwords $ map showByteHex bytes [ [ [ Table.cl $ Text.pack $ unwords $ map showByteHex bytes
@@ -95,7 +102,7 @@ instance MimeRender PlainText BytesModel where
Right c -> Right c ->
[ Text.pack [c] [ Text.pack [c]
, Text.pack $ printf "U+%04X" c , Text.pack $ printf "U+%04X" c
, Text.pack $ intercalate ", " $ maybeToList (UnicodeNames.name c) ++ map (++ "*") (UnicodeNames.nameAliases c) , Text.pack $ intercalate ", " $ allNames c
, Text.pack $ fromMaybe "" $ blockName c , Text.pack $ fromMaybe "" $ blockName c
] ]
) )
@@ -103,25 +110,19 @@ instance MimeRender PlainText BytesModel where
| (bytes, eiC) <- model.codepoints | (bytes, eiC) <- model.codepoints
] ]
instance MimeRender HTML BytesModel where instance MimeRender HTML Utf8Model where
mimeRender _ model = renderHtml $ H.docTypeHtml $ do mimeRender _ model = renderHtml $ documentWithBody $ do
H.head $ do H.table $ for_ model.codepoints $ \(bytes, eiC) -> do
H.meta ! A.charset "utf-8" H.tr $ do
H.title "utoy" H.td $ H.pre $ H.toHtml $ unlines $ map unwords [map showByteHex bytes, map showByteBin bytes]
H.style $ H.toHtml $ Encoding.decodeUtf8 $(embedFile "utoy.css") case eiC of
H.body $ do Left err ->
H.table $ for_ model.codepoints $ \(bytes, eiC) -> do H.td ! A.colspan "4" $ H.toHtml $ "Decoding error: " ++ err
H.tr $ do Right c -> do
H.td $ H.pre $ H.toHtml $ unlines $ map unwords [map showByteHex bytes, map showByteBin bytes] H.td $ H.input ! A.class_ "charbox" ! A.value (H.toValue [c])
case eiC of H.td $ H.code $ printfHtml "U+%04X" c
Left err -> H.td $ H.code $ H.toHtml $ intercalate ", " $ allNames c
H.td ! A.colspan "4" $ H.toHtml $ "Decoding error: " ++ err H.td $ H.code $ H.toHtml $ fromMaybe "" $ blockName c
Right c -> do
H.td $ do
H.input ! A.value (H.toValue [c]) ! A.style "text-align: center; width: 2em; font-size: 1em;"
H.td $ H.code $ printfHtml "U+%04X" c
H.td $ H.code $ H.toHtml $ intercalate ", " $ maybeToList (UnicodeNames.name c) ++ map (++ "*") (UnicodeNames.nameAliases c)
H.td $ H.toHtml $ fromMaybe "" $ blockName c
-- /codepoints/<codepoints> -- /codepoints/<codepoints>
@@ -130,7 +131,14 @@ newtype CodepointsModel = CodepointsModel
} }
mkCodepointsModel :: [(Word, Word)] -> CodepointsModel mkCodepointsModel :: [(Word, Word)] -> CodepointsModel
mkCodepointsModel = CodepointsModel . map go . concatMap (uncurry enumFromTo) mkCodepointsModel =
CodepointsModel
-- Limit number of returned codepoints. Otherwise it's
-- too easy to provoke massive response bodies with requests like
-- /codepoints/0-99999999
. take 100000
. map go
. concatMap (uncurry enumFromTo)
where where
go codepoint = (codepoint, toChar codepoint) go codepoint = (codepoint, toChar codepoint)
@@ -151,13 +159,54 @@ instance MimeRender PlainText CodepointsModel where
Right c -> Right c ->
[ Text.pack [c] [ Text.pack [c]
, Text.pack $ printf "U+%04X" c , Text.pack $ printf "U+%04X" c
, Text.pack $ intercalate ", " $ maybeToList (UnicodeNames.name c) ++ map (++ "*") (UnicodeNames.nameAliases c) , Text.pack $ intercalate ", " $ allNames c
, Text.pack $ fromMaybe "" $ blockName c , Text.pack $ fromMaybe "" $ blockName c
] ]
) )
| (codepoint, eiC) <- model.codepoints | (codepoint, eiC) <- model.codepoints
] ]
instance MimeRender HTML CodepointsModel where
mimeRender _ model = renderHtml $ documentWithBody $ do
H.table $ for_ model.codepoints $ \(codepoint, eiC) ->
H.tr $ do
H.td $ H.code $ H.toHtml $ Text.pack $ printf "0x%X" codepoint
case eiC of
Left err -> do
H.td ! A.colspan "4" $ H.code $ H.toHtml $ "Decoding error: " <> Text.pack err
Right c -> do
H.td $ H.input ! A.class_ "charbox" ! A.value (H.toValue [c])
H.td $ H.code $ printfHtml "U+%04X" c
H.td $ H.code $ H.toHtml $ intercalate ", " $ allNames c
H.td $ H.code $ H.toHtml $ fromMaybe "" $ blockName c
-- /text/<text>
newtype TextModel = TextModel
{ text :: Text
}
instance MimeRender HTML TextModel where
mimeRender _ model = renderHtml $ documentWithBody $ do
H.table $ for_ (Text.unpack model.text) $ \c -> do
H.tr $ do
H.td $ H.input ! A.class_ "charbox" ! A.value (H.toValue [c])
H.td $ H.code $ printfHtml "U+%04X" c
H.td $ H.code $ H.toHtml $ intercalate ", " $ allNames c
H.td $ H.code $ H.toHtml $ fromMaybe "" $ blockName c
instance MimeRender PlainText TextModel where
mimeRender _ model = renderText $ Table.render " "
[ map (Table.cl)
[ Text.pack [c]
, Text.pack $ printf "U+%04X" c
, Text.pack $ intercalate ", " $ allNames c
, Text.pack $ fromMaybe "" $ blockName c
]
| c <- Text.unpack model.text
]
-- Utilities -- Utilities
renderText :: Text -> BL.ByteString renderText :: Text -> BL.ByteString
@@ -167,7 +216,13 @@ showByteHex :: Word8 -> String
showByteHex = printf " %02X" showByteHex = printf " %02X"
showByteBin :: Word8 -> String showByteBin :: Word8 -> String
showByteBin = printf "%8b" showByteBin = printf "%08b"
-- | Retrieve name and aliases (suffixed with @*@) of a 'Char'.
allNames :: Char -> [String]
allNames c =
maybeToList (UnicodeNames.name c)
++ map (++ "*") (UnicodeNames.nameAliases c)
blockName :: Char -> Maybe String blockName :: Char -> Maybe String
blockName c = UnicodeBlocks.blockName . UnicodeBlocks.blockDefinition <$> UnicodeBlocks.block c blockName c = UnicodeBlocks.blockName . UnicodeBlocks.blockDefinition <$> UnicodeBlocks.block c
@@ -179,6 +234,15 @@ orThrow (Right val) _ = pure val
printfHtml :: PrintfArg a => String -> a -> H.Html printfHtml :: PrintfArg a => String -> a -> H.Html
printfHtml fmt = (H.toHtml :: String -> H.Html) . printf fmt printfHtml fmt = (H.toHtml :: String -> H.Html) . printf fmt
documentWithBody :: H.Html -> H.Html
documentWithBody body =
H.docTypeHtml $ do
H.head $ do
H.meta ! A.charset "utf-8"
H.title "utoy"
H.style $ H.toHtml $ Encoding.decodeUtf8 $(embedFile "static/utoy.css")
H.body body
-- HTML routes -- HTML routes
data HTML data HTML
+1 -1
View File
@@ -4,7 +4,7 @@ cradle:
component: "utoy:lib" component: "utoy:lib"
- path: "./app/Main.hs" - path: "./app/Main.hs"
component: "utoy:exe:utoy-exe" component: "utoy:exe:utoy"
- path: "./test" - path: "./test"
component: "utoy:test:utoy-test" component: "utoy:test:utoy-test"
+9
View File
@@ -0,0 +1,9 @@
let
pkgs = import ./pkgs.nix {};
utoy = import ../utoy.nix;
in
pkgs.dockerTools.buildImage {
name = "git.pbrinkmeier.de/paul/utoy";
tag = utoy.version;
config.Cmd = [ "${utoy}/bin/utoy" ];
}
+3 -3
View File
@@ -1,7 +1,7 @@
# Adapted from new-template.hsfiles # Adapted from new-template.hsfiles
name: utoy name: utoy
version: 0.1.0.0 version: 0.5
git: "https://git.pbrinkmeier.de/paul/utoy" git: "https://git.pbrinkmeier.de/paul/utoy"
license: MIT license: MIT
author: "Paul Brinkmeier" author: "Paul Brinkmeier"
@@ -10,7 +10,7 @@ copyright: "2023 Paul Brinkmeier"
extra-source-files: extra-source-files:
- README.md - README.md
- utoy.css - static/utoy.css
dependencies: dependencies:
- base >= 4.7 && < 5 - base >= 4.7 && < 5
@@ -32,7 +32,7 @@ library:
source-dirs: src source-dirs: src
executables: executables:
utoy-exe: utoy:
main: Main.hs main: Main.hs
source-dirs: app source-dirs: app
ghc-options: ghc-options:
+1 -1
View File
@@ -17,7 +17,7 @@ cr :: Text -> Cell
cr = C AlignRight cr = C AlignRight
render :: Text -> [[Cell]] -> Text render :: Text -> [[Cell]] -> Text
render delim cells = Text.intercalate "\n" $ map showRow cells render delim cells = Text.unlines $ map showRow cells
where where
showRow = Text.intercalate delim . map showCell . zipLongest columnWidths showRow = Text.intercalate delim . map showCell . zipLongest columnWidths
+6
View File
@@ -19,3 +19,9 @@ pre, code {
pre { pre {
margin: 0; font-size: 0.5em; margin: 0; font-size: 0.5em;
} }
.charbox {
text-align: center;
width: 2em;
font-size: 1em;
}
+3 -3
View File
@@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack -- see: https://github.com/sol/hpack
name: utoy name: utoy
version: 0.1.0.0 version: 0.5
author: Paul Brinkmeier author: Paul Brinkmeier
maintainer: hallo@pbrinkmeier.de maintainer: hallo@pbrinkmeier.de
copyright: 2023 Paul Brinkmeier copyright: 2023 Paul Brinkmeier
@@ -14,7 +14,7 @@ license-file: LICENSE
build-type: Simple build-type: Simple
extra-source-files: extra-source-files:
README.md README.md
utoy.css static/utoy.css
source-repository head source-repository head
type: git type: git
@@ -36,7 +36,7 @@ library
, text , text
default-language: Haskell2010 default-language: Haskell2010
executable utoy-exe executable utoy
main-is: Main.hs main-is: Main.hs
hs-source-dirs: hs-source-dirs:
app app
+35
View File
@@ -0,0 +1,35 @@
let
pkgs = import ./nix/pkgs.nix {};
settings = import ./nix/settings.nix;
haskellDeps = import ./nix/haskell-deps.nix;
haskellPackages = pkgs.haskell.packages."${settings.ghc}";
utoy =
{ mkDerivation }:
mkDerivation {
version = "0.5";
pname = "utoy";
license = pkgs.lib.licenses.mit;
src =
let
buildFiles = [
./LICENSE
./utoy.cabal
./Setup.hs
./app
./src
./static
./test
];
in
pkgs.lib.sources.cleanSourceWith {
src = ./.;
filter = path: _type: pkgs.lib.any (prefix: pkgs.lib.hasPrefix (toString prefix) path) buildFiles;
};
libraryHaskellDepends = haskellDeps haskellPackages;
};
in
pkgs.haskell.lib.justStaticExecutables
(haskellPackages.callPackage utoy {})