packages feed

gibberish-3.0.0.0: src/Data/Gibberish/Utils.hs

module Data.Gibberish.Utils
  ( numeralConversions,
    symbolConversions,
    update1,
    updateR,
    findIndices,
    textTraverse,
    toQwertyKey,
    qwertyKeys,
  ) where

import Control.Monad.Random (MonadRandom (), fromList)
import Data.Map (Map ())
import Data.Map qualified as Map
import Data.Ratio (denominator, numerator)
import Data.Text (Text ())
import Data.Text qualified as Text

-- | A mapping from letters to numbers that look like them
numeralConversions :: Map Char [Char]
numeralConversions =
  Map.fromList
    [ ('o', ['0']),
      ('l', ['1']),
      ('z', ['2']),
      ('e', ['3']),
      ('a', ['4']),
      ('s', ['5']),
      ('g', ['6', '9']),
      ('t', ['7']),
      ('b', ['8'])
    ]

-- | A mapping from letters to symbols that look like them
symbolConversions :: Map Char [Char]
symbolConversions =
  Map.fromList
    [ ('a', ['@']),
      ('l', ['!']),
      ('s', ['$'])
    ]

update1 :: Monad m => (Char -> m Char) -> Text -> Int -> m Text
update1 f t pos =
  case Text.splitAt pos t of
    (prefix, suffix) ->
      case Text.uncons suffix of
        Nothing -> pure t
        Just (ch, suffix') -> do
          ch' <- f ch
          pure $ prefix `Text.append` (ch' `Text.cons` suffix')

updateR :: MonadRandom m => (Char -> m Char) -> Rational -> Text -> m Text
updateR f prob = textTraverse updateR'
  where
    updateR' ch = do
      ch' <- f ch
      fromList
        [ (ch, toRational $ denominator prob),
          (ch', toRational $ numerator prob)
        ]

-- | /O(n)/ The 'findIndices' function extends 'findIndex', by returning the
-- indices of all elements satisfying the predicate, in ascending order.
findIndices :: (Char -> Bool) -> Text -> [Int]
findIndices p = loop 0
  where
    loop !n !qs = case Text.findIndex p qs of
      Just !i ->
        let !j = n + i
        in j : loop (j + 1) (Text.drop (i + 1) qs)
      Nothing -> []
{-# INLINE [1] findIndices #-}

textTraverse :: Monad m => (Char -> m Char) -> Text -> m Text
textTraverse f = Text.foldr folder (pure Text.empty)
  where
    folder c accum = do
      accum' <- accum
      c' <- f c
      pure $ Text.cons c' accum'

-- | Transform a letter-type character to something that's easy to type on a
-- QWERTY keyboard
toQwertyKey :: Char -> Char
toQwertyKey 'à' = 'a'
toQwertyKey 'á' = 'a'
toQwertyKey 'â' = 'a'
toQwertyKey 'ä' = 'a'
toQwertyKey 'å' = 'a'
toQwertyKey 'ç' = 'c'
toQwertyKey 'è' = 'e'
toQwertyKey 'é' = 'e'
toQwertyKey 'ê' = 'e'
toQwertyKey 'ë' = 'e'
toQwertyKey 'í' = 'i'
toQwertyKey 'ï' = 'i'
toQwertyKey 'ñ' = 'n'
toQwertyKey 'ó' = 'o'
toQwertyKey 'ô' = 'o'
toQwertyKey 'ö' = 'o'
toQwertyKey 'û' = 'u'
toQwertyKey 'ü' = 'u'
toQwertyKey 'ú' = 'u'
toQwertyKey c = c

-- | All the characters that are easy to type on a QWERTY keyboard
qwertyKeys :: [Char]
qwertyKeys =
  "1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,./!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:'\"ZXCVBNM<>?"