    {-# LANGUAGE OverloadedStrings #-}
    {-|
    Module      : HsLua.Module.Path
    Copyright   : © 2021-2024 Albert Krewinkel
    License     : MIT
    Maintainer  : Albert Krewinkel <tarleb@hslua.org>

    Lua module to work with file paths.
    -}
    module HsLua.Module.Path (
      -- * Module
        documentedModule

      -- * Fields
      , separator
      , search_path_separator

      -- * Path manipulation
      , add_extension
      , combine
      , directory
      , filename
      , is_absolute
      , is_relative
      , join
      , make_relative
      , normalize
      , split
      , split_extension
      , split_search_path
      , treat_strings_as_paths
      )
    where

    import Data.Text (Text)
    import Data.Version (Version, makeVersion)
    import HsLua.Core
      ( LuaError, getglobal, getmetatable, nth, pop, rawset, remove, top )
    import HsLua.Marshalling
      ( Peeker, peekList, peekString, pushList, pushName, pushString )
    import HsLua.Packaging

    import qualified Data.Text as T
    import qualified System.FilePath as Path

    -- | The @path@ module specification.
    documentedModule :: LuaError e => Module e
    documentedModule :: forall e. LuaError e => Module e
    documentedModule = Module
      { moduleName :: Name
    moduleName = Name
    "path"
      , moduleDescription :: Text
    moduleDescription = Text
    "Module for file path manipulations."
      , moduleFields :: [Field e]
    moduleFields = [Field e]
    forall e. [Field e]
    fields
      , moduleFunctions :: [DocumentedFunction e]
    moduleFunctions = [DocumentedFunction e]
    forall e. LuaError e => [DocumentedFunction e]
    functions
      , moduleOperations :: [(Operation, DocumentedFunction e)]
    moduleOperations = []
      , moduleTypeInitializers :: [LuaE e Name]
    moduleTypeInitializers = []
      }

    --
    -- Fields
    --

    -- | Exported fields.
    fields :: [Field e]
    fields :: forall e. [Field e]
    fields =
      [ Field e
    forall e. Field e
    separator
      , Field e
    forall e. Field e
    search_path_separator
      ]

    -- | Wrapper for @'Path.pathSeparator'@.
    separator :: Field e
    separator :: forall e. Field e
    separator = Field
      { fieldName :: Text
    fieldName = Text
    "separator"
      , fieldType :: TypeSpec
    fieldType = TypeSpec
    "string"
      , fieldDescription :: Text
    fieldDescription = Text
    "The character that separates directories."
      , fieldPushValue :: LuaE e ()
    fieldPushValue = FilePath -> LuaE e ()
    forall e. FilePath -> LuaE e ()
    pushString [Char
    Path.pathSeparator]
      }

    -- | Wrapper for @'Path.searchPathSeparator'@.
    search_path_separator :: Field e
    search_path_separator :: forall e. Field e
    search_path_separator = Field
      { fieldName :: Text
    fieldName = Text
    "search_path_separator"
      , fieldType :: TypeSpec
    fieldType = TypeSpec
    "string"
      , fieldDescription :: Text
    fieldDescription = Text
    "The character that is used to separate the entries in "
                        Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    "the `PATH` environment variable."
      , fieldPushValue :: LuaE e ()
    fieldPushValue = FilePath -> LuaE e ()
    forall e. FilePath -> LuaE e ()
    pushString [Char
    Path.searchPathSeparator]
      }

    --
    -- Functions
    --

    functions :: LuaError e => [DocumentedFunction e]
    functions :: forall e. LuaError e => [DocumentedFunction e]
    functions =
      [ DocumentedFunction e
    forall e. DocumentedFunction e
    directory
      , DocumentedFunction e
    forall e. DocumentedFunction e
    filename
      , DocumentedFunction e
    forall e. DocumentedFunction e
    is_absolute
      , DocumentedFunction e
    forall e. DocumentedFunction e
    is_relative
      , DocumentedFunction e
    forall e. LuaError e => DocumentedFunction e
    join
      , DocumentedFunction e
    forall e. DocumentedFunction e
    make_relative
      , DocumentedFunction e
    forall e. DocumentedFunction e
    normalize
      , DocumentedFunction e
    forall e. LuaError e => DocumentedFunction e
    split
      , DocumentedFunction e
    forall e. DocumentedFunction e
    split_extension
      , DocumentedFunction e
    forall e. LuaError e => DocumentedFunction e
    split_search_path
      , DocumentedFunction e
    forall e. LuaError e => DocumentedFunction e
    treat_strings_as_paths
      ]

    -- | See @Path.takeDirectory@
    directory :: DocumentedFunction e
    directory :: forall e. DocumentedFunction e
    directory = Name
    -> (FilePath -> LuaE e FilePath)
    -> HsFnPrecursor e (FilePath -> LuaE e FilePath)
    forall a e. Name -> a -> HsFnPrecursor e a
    defun Name
    "directory"
      ### liftPure Path.takeDirectory
      HsFnPrecursor e (FilePath -> LuaE e FilePath)
    -> Parameter e FilePath -> HsFnPrecursor e (LuaE e FilePath)
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Parameter e FilePath
    forall e. Parameter e FilePath
    filepathParam
      HsFnPrecursor e (LuaE e FilePath)
    -> FunctionResults e FilePath -> DocumentedFunction e
    forall e a.
    HsFnPrecursor e (LuaE e a)
    -> FunctionResults e a -> DocumentedFunction e
    =#> Text -> FunctionResults e FilePath
    forall e. Text -> FunctionResults e FilePath
    filepathResult Text
    "The filepath up to the last directory separator."
      #? ("Gets the directory name, i.e., removes the last directory " <>
          "separator and everything after from the given path.")
      DocumentedFunction e -> Version -> DocumentedFunction e
    forall e. DocumentedFunction e -> Version -> DocumentedFunction e
    `since` Version
    initialVersion

    -- | See @Path.takeFilename@
    filename :: DocumentedFunction e
    filename :: forall e. DocumentedFunction e
    filename = Name
    -> (FilePath -> LuaE e FilePath)
    -> HsFnPrecursor e (FilePath -> LuaE e FilePath)
    forall a e. Name -> a -> HsFnPrecursor e a
    defun Name
    "filename"
      ### liftPure Path.takeFileName
      HsFnPrecursor e (FilePath -> LuaE e FilePath)
    -> Parameter e FilePath -> HsFnPrecursor e (LuaE e FilePath)
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Parameter e FilePath
    forall e. Parameter e FilePath
    filepathParam
      HsFnPrecursor e (LuaE e FilePath)
    -> FunctionResults e FilePath -> DocumentedFunction e
    forall e a.
    HsFnPrecursor e (LuaE e a)
    -> FunctionResults e a -> DocumentedFunction e
    =#> Text -> FunctionResults e FilePath
    forall e. Text -> FunctionResults e FilePath
    filepathResult Text
    "File name part of the input path."
      #? "Get the file name."
      DocumentedFunction e -> Version -> DocumentedFunction e
    forall e. DocumentedFunction e -> Version -> DocumentedFunction e
    `since` Version
    initialVersion

    -- | See @Path.isAbsolute@
    is_absolute :: DocumentedFunction e
    is_absolute :: forall e. DocumentedFunction e
    is_absolute = Name
    -> (FilePath -> LuaE e Bool)
    -> HsFnPrecursor e (FilePath -> LuaE e Bool)
    forall a e. Name -> a -> HsFnPrecursor e a
    defun Name
    "is_absolute"
      ### liftPure Path.isAbsolute
      HsFnPrecursor e (FilePath -> LuaE e Bool)
    -> Parameter e FilePath -> HsFnPrecursor e (LuaE e Bool)
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Parameter e FilePath
    forall e. Parameter e FilePath
    filepathParam
      HsFnPrecursor e (LuaE e Bool)
    -> FunctionResults e Bool -> DocumentedFunction e
    forall e a.
    HsFnPrecursor e (LuaE e a)
    -> FunctionResults e a -> DocumentedFunction e
    =#> Text -> FunctionResults e Bool
    forall e. Text -> FunctionResults e Bool
    boolResult (Text
    "`true` iff `filepath` is an absolute path, " Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <>
                      Text
    "`false` otherwise.")
      #? "Checks whether a path is absolute, i.e. not fixed to a root."
      DocumentedFunction e -> Version -> DocumentedFunction e
    forall e. DocumentedFunction e -> Version -> DocumentedFunction e
    `since` Version
    initialVersion

    -- | See @Path.isRelative@
    is_relative :: DocumentedFunction e
    is_relative :: forall e. DocumentedFunction e
    is_relative = Name
    -> (FilePath -> LuaE e Bool)
    -> HsFnPrecursor e (FilePath -> LuaE e Bool)
    forall a e. Name -> a -> HsFnPrecursor e a
    defun Name
    "is_relative"
      ### liftPure Path.isRelative
      HsFnPrecursor e (FilePath -> LuaE e Bool)
    -> Parameter e FilePath -> HsFnPrecursor e (LuaE e Bool)
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Parameter e FilePath
    forall e. Parameter e FilePath
    filepathParam
      HsFnPrecursor e (LuaE e Bool)
    -> FunctionResults e Bool -> DocumentedFunction e
    forall e a.
    HsFnPrecursor e (LuaE e a)
    -> FunctionResults e a -> DocumentedFunction e
    =#> Text -> FunctionResults e Bool
    forall e. Text -> FunctionResults e Bool
    boolResult (Text
    "`true` iff `filepath` is a relative path, " Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <>
                      Text
    "`false` otherwise.")
      #? "Checks whether a path is relative or fixed to a root."
      DocumentedFunction e -> Version -> DocumentedFunction e
    forall e. DocumentedFunction e -> Version -> DocumentedFunction e
    `since` Version
    initialVersion

    -- | See @Path.joinPath@
    join :: LuaError e => DocumentedFunction e
    join :: forall e. LuaError e => DocumentedFunction e
    join = Name
    -> ([FilePath] -> LuaE e FilePath)
    -> HsFnPrecursor e ([FilePath] -> LuaE e FilePath)
    forall a e. Name -> a -> HsFnPrecursor e a
    defun Name
    "join"
      ### liftPure Path.joinPath
      HsFnPrecursor e ([FilePath] -> LuaE e FilePath)
    -> Parameter e [FilePath] -> HsFnPrecursor e (LuaE e FilePath)
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Peeker e [FilePath]
    -> TypeSpec -> Text -> Text -> Parameter e [FilePath]
    forall e a. Peeker e a -> TypeSpec -> Text -> Text -> Parameter e a
    parameter (Peeker e FilePath -> Peeker e [FilePath]
    forall a e. LuaError e => Peeker e a -> Peeker e [a]
    peekList Peeker e FilePath
    forall e. Peeker e FilePath
    peekFilePath) TypeSpec
    "{string,...}"
             Text
    "filepaths" Text
    "path components"
      HsFnPrecursor e (LuaE e FilePath)
    -> FunctionResults e FilePath -> DocumentedFunction e
    forall e a.
    HsFnPrecursor e (LuaE e a)
    -> FunctionResults e a -> DocumentedFunction e
    =#> Text -> FunctionResults e FilePath
    forall e. Text -> FunctionResults e FilePath
    filepathResult Text
    "The joined path."
      #? "Join path elements back together by the directory separator."
      DocumentedFunction e -> Version -> DocumentedFunction e
    forall e. DocumentedFunction e -> Version -> DocumentedFunction e
    `since` Version
    initialVersion

    make_relative :: DocumentedFunction e
    make_relative :: forall e. DocumentedFunction e
    make_relative = Name
    -> (FilePath -> FilePath -> Maybe Bool -> LuaE e FilePath)
    -> HsFnPrecursor
         e (FilePath -> FilePath -> Maybe Bool -> LuaE e FilePath)
    forall a e. Name -> a -> HsFnPrecursor e a
    defun Name
    "make_relative"
      ### liftPure3 makeRelative
      HsFnPrecursor
      e (FilePath -> FilePath -> Maybe Bool -> LuaE e FilePath)
    -> Parameter e FilePath
    -> HsFnPrecursor e (FilePath -> Maybe Bool -> LuaE e FilePath)
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Peeker e FilePath
    -> TypeSpec -> Text -> Text -> Parameter e FilePath
    forall e a. Peeker e a -> TypeSpec -> Text -> Text -> Parameter e a
    parameter
            Peeker e FilePath
    forall e. Peeker e FilePath
    peekFilePath
            TypeSpec
    "string"
            Text
    "path"
            Text
    "path to be made relative"
      HsFnPrecursor e (FilePath -> Maybe Bool -> LuaE e FilePath)
    -> Parameter e FilePath
    -> HsFnPrecursor e (Maybe Bool -> LuaE e FilePath)
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Peeker e FilePath
    -> TypeSpec -> Text -> Text -> Parameter e FilePath
    forall e a. Peeker e a -> TypeSpec -> Text -> Text -> Parameter e a
    parameter
            Peeker e FilePath
    forall e. Peeker e FilePath
    peekFilePath
            TypeSpec
    "string"
            Text
    "root"
            Text
    "root path"
      HsFnPrecursor e (Maybe Bool -> LuaE e FilePath)
    -> Parameter e (Maybe Bool) -> HsFnPrecursor e (LuaE e FilePath)
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Parameter e Bool -> Parameter e (Maybe Bool)
    forall e a. Parameter e a -> Parameter e (Maybe a)
    opt (Text -> Text -> Parameter e Bool
    forall e. Text -> Text -> Parameter e Bool
    boolParam Text
    "unsafe" Text
    "whether to allow `..` in the result.")
      HsFnPrecursor e (LuaE e FilePath)
    -> FunctionResults e FilePath -> DocumentedFunction e
    forall e a.
    HsFnPrecursor e (LuaE e a)
    -> FunctionResults e a -> DocumentedFunction e
    =#> Text -> FunctionResults e FilePath
    forall e. Text -> FunctionResults e FilePath
    filepathResult Text
    "contracted filename"
      #? mconcat
         [ "Contract a filename, based on a relative path. Note that the "
         , "resulting path will never introduce `..` paths, as the "
         , "presence of symlinks means `../b` may not reach `a/b` if it "
         , "starts from `a/c`. For a worked example see "
         , "[this blog post](http://neilmitchell.blogspot.co.uk"
         , "/2015/10/filepaths-are-subtle-symlinks-are-hard.html)."
         ]
      DocumentedFunction e -> Version -> DocumentedFunction e
    forall e. DocumentedFunction e -> Version -> DocumentedFunction e
    `since` Version
    initialVersion

    -- | See @Path.normalise@
    normalize :: DocumentedFunction e
    normalize :: forall e. DocumentedFunction e
    normalize = Name
    -> (FilePath -> LuaE e FilePath)
    -> HsFnPrecursor e (FilePath -> LuaE e FilePath)
    forall a e. Name -> a -> HsFnPrecursor e a
    defun Name
    "normalize"
      ### liftPure Path.normalise
      HsFnPrecursor e (FilePath -> LuaE e FilePath)
    -> Parameter e FilePath -> HsFnPrecursor e (LuaE e FilePath)
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Parameter e FilePath
    forall e. Parameter e FilePath
    filepathParam
      HsFnPrecursor e (LuaE e FilePath)
    -> FunctionResults e FilePath -> DocumentedFunction e
    forall e a.
    HsFnPrecursor e (LuaE e a)
    -> FunctionResults e a -> DocumentedFunction e
    =#> Text -> FunctionResults e FilePath
    forall e. Text -> FunctionResults e FilePath
    filepathResult Text
    "The normalized path."
      #? T.unlines
         [ "Normalizes a path."
         , ""
         , " - `//` makes sense only as part of a (Windows) network drive;"
         , "   elsewhere, multiple slashes are reduced to a single"
         , "   `path.separator` (platform dependent)."
         , " - `/` becomes `path.separator` (platform dependent)."
         , " - `./` is removed."
         , " - an empty path becomes `.`"
         ]
      DocumentedFunction e -> Version -> DocumentedFunction e
    forall e. DocumentedFunction e -> Version -> DocumentedFunction e
    `since` Version
    initialVersion

    -- | See @Path.splitDirectories@.
    --
    -- Note that this does /not/ wrap @'Path.splitPath'@, as that function
    -- adds trailing slashes to each directory, which is often inconvenient.
    split :: LuaError e => DocumentedFunction e
    split :: forall e. LuaError e => DocumentedFunction e
    split = Name
    -> (FilePath -> LuaE e [FilePath])
    -> HsFnPrecursor e (FilePath -> LuaE e [FilePath])
    forall a e. Name -> a -> HsFnPrecursor e a
    defun Name
    "split"
      ### liftPure Path.splitDirectories
      HsFnPrecursor e (FilePath -> LuaE e [FilePath])
    -> Parameter e FilePath -> HsFnPrecursor e (LuaE e [FilePath])
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Parameter e FilePath
    forall e. Parameter e FilePath
    filepathParam
      HsFnPrecursor e (LuaE e [FilePath])
    -> FunctionResults e [FilePath] -> DocumentedFunction e
    forall e a.
    HsFnPrecursor e (LuaE e a)
    -> FunctionResults e a -> DocumentedFunction e
    =#> Text -> FunctionResults e [FilePath]
    forall e. LuaError e => Text -> FunctionResults e [FilePath]
    filepathListResult Text
    "List of all path components."
      #? "Splits a path by the directory separator."
      DocumentedFunction e -> Version -> DocumentedFunction e
    forall e. DocumentedFunction e -> Version -> DocumentedFunction e
    `since` Version
    initialVersion

    -- | See @Path.splitExtension@
    split_extension :: DocumentedFunction e
    split_extension :: forall e. DocumentedFunction e
    split_extension = Name
    -> (FilePath -> LuaE e (FilePath, FilePath))
    -> HsFnPrecursor e (FilePath -> LuaE e (FilePath, FilePath))
    forall a e. Name -> a -> HsFnPrecursor e a
    defun Name
    "split_extension"
      ### liftPure Path.splitExtension
      HsFnPrecursor e (FilePath -> LuaE e (FilePath, FilePath))
    -> Parameter e FilePath
    -> HsFnPrecursor e (LuaE e (FilePath, FilePath))
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Parameter e FilePath
    forall e. Parameter e FilePath
    filepathParam
      HsFnPrecursor e (LuaE e (FilePath, FilePath))
    -> FunctionResults e (FilePath, FilePath) -> DocumentedFunction e
    forall e a.
    HsFnPrecursor e (LuaE e a)
    -> FunctionResults e a -> DocumentedFunction e
    =#> (Pusher e (FilePath, FilePath)
    -> TypeSpec -> Text -> FunctionResults e (FilePath, FilePath)
    forall e a. Pusher e a -> TypeSpec -> Text -> FunctionResults e a
    functionResult (FilePath -> LuaE e ()
    forall e. FilePath -> LuaE e ()
    pushString (FilePath -> LuaE e ())
    -> ((FilePath, FilePath) -> FilePath)
    -> Pusher e (FilePath, FilePath)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (FilePath, FilePath) -> FilePath
    forall a b. (a, b) -> a
    fst) TypeSpec
    "string" Text
    "filepath without extension"
           FunctionResults e (FilePath, FilePath)
    -> FunctionResults e (FilePath, FilePath)
    -> FunctionResults e (FilePath, FilePath)
    forall a. [a] -> [a] -> [a]
    ++
           Pusher e (FilePath, FilePath)
    -> TypeSpec -> Text -> FunctionResults e (FilePath, FilePath)
    forall e a. Pusher e a -> TypeSpec -> Text -> FunctionResults e a
    functionResult (FilePath -> LuaE e ()
    forall e. FilePath -> LuaE e ()
    pushString (FilePath -> LuaE e ())
    -> ((FilePath, FilePath) -> FilePath)
    -> Pusher e (FilePath, FilePath)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (FilePath, FilePath) -> FilePath
    forall a b. (a, b) -> b
    snd) TypeSpec
    "string" Text
    "extension or empty string")
      #? ("Splits the last extension from a file path and returns the parts. "
          <> "The extension, if present, includes the leading separator; "
          <> "if the path has no extension, then the empty string is returned "
          <> "as the extension.")
      DocumentedFunction e -> Version -> DocumentedFunction e
    forall e. DocumentedFunction e -> Version -> DocumentedFunction e
    `since` Version
    initialVersion

    -- | Wraps function @'Path.splitSearchPath'@.
    split_search_path :: LuaError e => DocumentedFunction e
    split_search_path :: forall e. LuaError e => DocumentedFunction e
    split_search_path = Name
    -> (FilePath -> LuaE e [FilePath])
    -> HsFnPrecursor e (FilePath -> LuaE e [FilePath])
    forall a e. Name -> a -> HsFnPrecursor e a
    defun Name
    "split_search_path"
      ### liftPure Path.splitSearchPath
      HsFnPrecursor e (FilePath -> LuaE e [FilePath])
    -> Parameter e FilePath -> HsFnPrecursor e (LuaE e [FilePath])
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Parameter
          { parameterPeeker :: Peeker e FilePath
    parameterPeeker = Peeker e FilePath
    forall e. Peeker e FilePath
    peekString
          , parameterDoc :: ParameterDoc
    parameterDoc = ParameterDoc
            { parameterName :: Text
    parameterName = Text
    "search_path"
            , parameterType :: TypeSpec
    parameterType = TypeSpec
    "string"
            , parameterDescription :: Text
    parameterDescription = Text
    "platform-specific search path"
            , parameterIsOptional :: Bool
    parameterIsOptional = Bool
    False
            }
          }
      HsFnPrecursor e (LuaE e [FilePath])
    -> FunctionResults e [FilePath] -> DocumentedFunction e
    forall e a.
    HsFnPrecursor e (LuaE e a)
    -> FunctionResults e a -> DocumentedFunction e
    =#> Text -> FunctionResults e [FilePath]
    forall e. LuaError e => Text -> FunctionResults e [FilePath]
    filepathListResult Text
    "list of directories in search path"
      #? ("Takes a string and splits it on the `search_path_separator` "
          <> "character. Blank items are ignored on Windows, "
          <> "and converted to `.` on Posix. "
          <> "On Windows path elements are stripped of quotes.")
      DocumentedFunction e -> Version -> DocumentedFunction e
    forall e. DocumentedFunction e -> Version -> DocumentedFunction e
    `since` Version
    initialVersion

    -- | Join two paths with a directory separator. Wraps @'Path.combine'@.
    combine :: DocumentedFunction e
    combine :: forall e. DocumentedFunction e
    combine = Name
    -> (FilePath -> FilePath -> LuaE e FilePath)
    -> HsFnPrecursor e (FilePath -> FilePath -> LuaE e FilePath)
    forall a e. Name -> a -> HsFnPrecursor e a
    defun Name
    "combine"
      ### liftPure2 Path.combine
      HsFnPrecursor e (FilePath -> FilePath -> LuaE e FilePath)
    -> Parameter e FilePath
    -> HsFnPrecursor e (FilePath -> LuaE e FilePath)
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Parameter e FilePath
    forall e. Parameter e FilePath
    filepathParam
      HsFnPrecursor e (FilePath -> LuaE e FilePath)
    -> Parameter e FilePath -> HsFnPrecursor e (LuaE e FilePath)
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Parameter e FilePath
    forall e. Parameter e FilePath
    filepathParam
      HsFnPrecursor e (LuaE e FilePath)
    -> FunctionResults e FilePath -> DocumentedFunction e
    forall e a.
    HsFnPrecursor e (LuaE e a)
    -> FunctionResults e a -> DocumentedFunction e
    =#> Text -> FunctionResults e FilePath
    forall e. Text -> FunctionResults e FilePath
    filepathResult Text
    "combined paths"
      #? "Combine two paths with a path separator."

    -- | Adds an extension to a file path. Wraps @'Path.addExtension'@.
    add_extension :: DocumentedFunction e
    add_extension :: forall e. DocumentedFunction e
    add_extension = Name
    -> (FilePath -> FilePath -> LuaE e FilePath)
    -> HsFnPrecursor e (FilePath -> FilePath -> LuaE e FilePath)
    forall a e. Name -> a -> HsFnPrecursor e a
    defun Name
    "add_extension"
      ### liftPure2 Path.addExtension
      HsFnPrecursor e (FilePath -> FilePath -> LuaE e FilePath)
    -> Parameter e FilePath
    -> HsFnPrecursor e (FilePath -> LuaE e FilePath)
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Parameter e FilePath
    forall e. Parameter e FilePath
    filepathParam
      HsFnPrecursor e (FilePath -> LuaE e FilePath)
    -> Parameter e FilePath -> HsFnPrecursor e (LuaE e FilePath)
    forall e a b.
    HsFnPrecursor e (a -> b) -> Parameter e a -> HsFnPrecursor e b
    <#> Parameter
          { parameterPeeker :: Peeker e FilePath
    parameterPeeker = Peeker e FilePath
    forall e. Peeker e FilePath
    peekString
          , parameterDoc :: ParameterDoc
    parameterDoc = ParameterDoc
            { parameterName :: Text
    parameterName = Text
    "extension"
            , parameterType :: TypeSpec
    parameterType = TypeSpec
    "string"
            , parameterDescription :: Text
    parameterDescription = Text
    "an extension, with or without separator dot"
            , parameterIsOptional :: Bool
    parameterIsOptional = Bool
    False
            }
          }
      HsFnPrecursor e (LuaE e FilePath)
    -> FunctionResults e FilePath -> DocumentedFunction e
    forall e a.
    HsFnPrecursor e (LuaE e a)
    -> FunctionResults e a -> DocumentedFunction e
    =#> Text -> FunctionResults e FilePath
    forall e. Text -> FunctionResults e FilePath
    filepathResult Text
    "filepath with extension"
      #? "Adds an extension, even if there is already one."
      DocumentedFunction e -> Version -> DocumentedFunction e
    forall e. DocumentedFunction e -> Version -> DocumentedFunction e
    `since` Version
    initialVersion

    stringAugmentationFunctions :: LuaError e => [DocumentedFunction e]
    stringAugmentationFunctions :: forall e. LuaError e => [DocumentedFunction e]
    stringAugmentationFunctions =
      [ DocumentedFunction e
    forall e. DocumentedFunction e
    directory
      , DocumentedFunction e
    forall e. DocumentedFunction e
    filename
      , DocumentedFunction e
    forall e. DocumentedFunction e
    is_absolute
      , DocumentedFunction e
    forall e. DocumentedFunction e
    is_relative
      , DocumentedFunction e
    forall e. DocumentedFunction e
    normalize
      , DocumentedFunction e
    forall e. LuaError e => DocumentedFunction e
    split
      , DocumentedFunction e
    forall e. DocumentedFunction e
    split_extension
      , DocumentedFunction e
    forall e. LuaError e => DocumentedFunction e
    split_search_path
      ]

    treat_strings_as_paths :: LuaError e => DocumentedFunction e
    treat_strings_as_paths :: forall e. LuaError e => DocumentedFunction e
    treat_strings_as_paths = Name -> LuaE e () -> HsFnPrecursor e (LuaE e ())
    forall a e. Name -> a -> HsFnPrecursor e a
    defun Name
    "treat_strings_as_paths"
      ### do let addFunction fn = do
                     pushName (functionName fn)
                     pushDocumentedFunction fn
                     rawset (nth 3)
             -- for some reason we can't just dump all functions into the
             -- string metatable, but have to use the string module for
             -- non-metamethods.
             pushString "" *> getmetatable top *> remove (nth 2)
             mapM_ addFunction
               [setName "__add" add_extension, setName "__div" combine]
             pop 1  -- string metatable

             _ <- getglobal "string"
             mapM_ addFunction stringAugmentationFunctions
             pop 1 -- string module
      HsFnPrecursor e (LuaE e ())
    -> FunctionResults e () -> DocumentedFunction e
    forall e a.
    HsFnPrecursor e (LuaE e a)
    -> FunctionResults e a -> DocumentedFunction e
    =#> []
      #? ("Augment the string module such that strings can be used as "
          <> "path objects.")
      DocumentedFunction e -> Version -> DocumentedFunction e
    forall e. DocumentedFunction e -> Version -> DocumentedFunction e
    `since` Version
    initialVersion

    --
    -- Parameters
    --

    -- | Retrieves a file path from the stack.
    peekFilePath :: Peeker e FilePath
    peekFilePath :: forall e. Peeker e FilePath
    peekFilePath = Peeker e FilePath
    forall e. Peeker e FilePath
    peekString

    -- | Filepath function parameter.
    filepathParam :: Parameter e FilePath
    filepathParam :: forall e. Parameter e FilePath
    filepathParam = Peeker e FilePath
    -> TypeSpec -> Text -> Text -> Parameter e FilePath
    forall e a. Peeker e a -> TypeSpec -> Text -> Text -> Parameter e a
    parameter Peeker e FilePath
    forall e. Peeker e FilePath
    peekFilePath TypeSpec
    "string" Text
    "filepath" Text
    "path"

    -- | Result of a function returning a file path.
    filepathResult :: Text -- ^ Description
                   -> FunctionResults e FilePath
    filepathResult :: forall e. Text -> FunctionResults e FilePath
    filepathResult = Text -> FunctionResults e FilePath
    forall e. Text -> FunctionResults e FilePath
    stringResult

    -- | List of filepaths function result.
    filepathListResult :: LuaError e
                       => Text -- ^ Description
                       -> FunctionResults e [FilePath]
    filepathListResult :: forall e. LuaError e => Text -> FunctionResults e [FilePath]
    filepathListResult = Pusher e [FilePath]
    -> TypeSpec -> Text -> FunctionResults e [FilePath]
    forall e a. Pusher e a -> TypeSpec -> Text -> FunctionResults e a
    functionResult (Pusher e FilePath -> Pusher e [FilePath]
    forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
    pushList Pusher e FilePath
    forall e. FilePath -> LuaE e ()
    pushString) TypeSpec
    "{string,...}"

    --
    -- Helpers
    --

    -- | Alternative version of @'Path.makeRelative'@, which introduces @..@
    -- paths if desired.
    makeRelative :: FilePath      -- ^ path to be made relative
                 -> FilePath      -- ^ root directory from which to start
                 -> Maybe Bool    -- ^ whether to use unsafe relative paths.
                 -> FilePath
    makeRelative :: FilePath -> FilePath -> Maybe Bool -> FilePath
    makeRelative FilePath
    path FilePath
    root (Just Bool
    True)
     | FilePath -> FilePath -> Bool
    Path.equalFilePath FilePath
    root FilePath
    path = FilePath
    "."
     | FilePath -> FilePath
    Path.takeDrive FilePath
    root FilePath -> FilePath -> Bool
    forall a. Eq a => a -> a -> Bool
    /= FilePath -> FilePath
    Path.takeDrive FilePath
    path = FilePath
    path
     | Bool
    otherwise =
       let toParts :: FilePath -> [FilePath]
    toParts = FilePath -> [FilePath]
    Path.splitDirectories (FilePath -> [FilePath])
    -> (FilePath -> FilePath) -> FilePath -> [FilePath]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . FilePath -> FilePath
    Path.normalise
           go :: [FilePath] -> [FilePath] -> FilePath
    go (FilePath
    pp:[FilePath]
    pps) (FilePath
    rp:[FilePath]
    rps)
             | FilePath
    pp FilePath -> FilePath -> Bool
    forall a. Eq a => a -> a -> Bool
    == FilePath
    rp = [FilePath] -> [FilePath] -> FilePath
    go [FilePath]
    pps [FilePath]
    rps
           go [FilePath]
    pps [FilePath]
    rps
             = [FilePath] -> FilePath
    Path.joinPath ([FilePath] -> FilePath) -> [FilePath] -> FilePath
    forall a b. (a -> b) -> a -> b
    $ Int -> FilePath -> [FilePath]
    forall a. Int -> a -> [a]
    replicate ([FilePath] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [FilePath]
    rps) FilePath
    ".." [FilePath] -> [FilePath] -> [FilePath]
    forall a. [a] -> [a] -> [a]
    ++ [FilePath]
    pps
       in [FilePath] -> [FilePath] -> FilePath
    go (FilePath -> [FilePath]
    toParts FilePath
    path) (FilePath -> [FilePath]
    toParts FilePath
    root)
    makeRelative FilePath
    path FilePath
    root Maybe Bool
    _unsafe = FilePath -> FilePath -> FilePath
    Path.makeRelative FilePath
    root FilePath
    path

    -- | First published version of this library.
    initialVersion :: Version
    initialVersion :: Version
    initialVersion = [Int] -> Version
    makeVersion [Int
    0,Int
    1,Int
    0]