calamity-commands: A library for declaring, parsing, and invoking text-input based commands

[ library, mit, utils ] [ Propose Tags ]
Versions [RSS] 0.1.0.0, 0.1.1.0, 0.1.2.0, 0.1.3.0, 0.2.0.0, 0.3.0.0, 0.4.0.0
Change log ChangeLog.md
Dependencies base (>=4.13 && <5), megaparsec (>=8 && <10), optics (>=0.4.1 && <0.5), polysemy (>=1.5 && <2), polysemy-plugin (>=0.3 && <0.5), text (>=1.2 && <2.1), text-show (>=3.8 && <4), unordered-containers (>=0.2 && <0.3) [details]
License MIT
Copyright 2020 Ben Simms
Author Ben Simms
Maintainer ben@bensimms.moe
Category Utils
Home page https://github.com/simmsb/calamity
Bug tracker https://github.com/simmsb/calamity/issues
Source repo head: git clone https://github.com/simmsb/calamity
Uploaded by nitros12 at 2022-05-30T01:49:49Z
Distributions NixOS:0.4.0.0
Downloads 728 total (27 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user
Build status unknown [no reports yet]

Readme for calamity-commands-0.4.0.0

[back to package description]

Calamity Commands

Hackage Build Status License Hackage-Deps Discord Invite

Calamity Commands is a Haskell library for constructing text-based commands, it uses Polysemy as the core library for handling effects, allowing you to pick and choose how to handle certain features of the library.

Docs

You can find documentation on hackage at: https://hackage.haskell.org/package/calamity-commands

Examples

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedLabels #-}

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}

{-# LANGUAGE TypeOperators #-}

module Main where

import Polysemy
import CalamityCommands.Commands
import CalamityCommands.Commands.Help
import CalamityCommands.Commands.Context
import CalamityCommands.Commands.ParsePrefix
import Data.Functor.Identity
import qualified Data.Text as T
import qualified Data.Text.IO as T

-- Make a command handler, we don't actually use the context and therefore this
-- handler is generic over the context used
h' :: CommandContext Identity c (Either T.Text Int) => CommandHandler Identity c (Either T.Text Int)
h' = runIdentity . runFinal $ do
  (h, _) <- buildCommands $ do
        command @'[Int, Int] "add" $ \ctx a b -> pure $ Right (a + b)
        command @'[Int, Int] "mul" $ \ctx a b -> pure $ Right (a * b)
        helpCommand (pure . Left)
  pure h

-- To use the commands we need to provide the interpreters for
-- 'ConstructContext' and 'ParsePrefix', the default provided ones are being
-- used here: 'useBasicContext' which makes @ctx ~ 'BasicContext'@, and
-- @'useConstantPrefix' "!"@ which treats any input starting with @!@ as a
-- command.
--
--
-- The 'processCommands' function can then be used to parse and invoke commands,
-- since commands are generic over the monad they run in we use @'runIdentity' .
-- 'runFinal' . 'embedToFinal'@ to have the commands interpreted purely.
--
--
-- This function 'r' takes an input string such as "!add 1 2", and then looks up
-- the invoked command and runs it, returning the result.
r :: T.Text -> Maybe (Either
                       (CmdInvokeFailReason (BasicContext Identity (Either T.Text Int)))
                       (BasicContext Identity (Either T.Text Int), Either T.Text Int))
r = runIdentity . runFinal . embedToFinal . useBasicContext . useConstantPrefix "!" . processCommands h'

-- Then to display the result of processing the command nicely, we can use a
-- something like this function, which prints the result of a command if one was
-- invoked successfully, and prints the error nicely if not.
rm :: T.Text -> IO ()
rm s = case r s of
            Just (Right (_, Right r)) ->
              print r

            Just (Right (_, Left h)) ->
              T.putStrLn h

            Just (Left (CommandInvokeError _ (ParseError t r))) ->
              T.putStrLn ("Parsing parameter " <> t <> " failed with reason: " <> r)

            _ -> pure ()