From 9968d31fb5fe819b374943a576d35de908d5eb79 Mon Sep 17 00:00:00 2001 From: Clinton Mead Date: Thu, 11 Jun 2026 11:59:28 +1000 Subject: [PATCH 1/2] Add OsString module This exposes the library interface under the type OsString, which is actually a platform independent interface, instead of exposing WindowsString and PosixString directly in the interface --- .gitignore | 3 + path/default.nix | 2 +- .../System/OsString/Compat/Include.hs | 81 ++++++++++++++----- .../System/OsString/Compat/OsString.hs | 19 +++++ path/path.cabal | 10 ++- path/src/OsPath/Include.hs | 8 +- path/src/OsPath/Internal/Include.hs | 20 +++-- path/src/OsPath/Internal/OsPathWrapper.hs | 13 +++ path/src/OsPath/Internal/OsString.hs | 17 ++++ path/src/OsPath/OsString.hs | 17 ++++ 10 files changed, 159 insertions(+), 31 deletions(-) create mode 100644 path/os-string-compat/System/OsString/Compat/OsString.hs create mode 100644 path/src/OsPath/Internal/OsPathWrapper.hs create mode 100644 path/src/OsPath/Internal/OsString.hs create mode 100644 path/src/OsPath/OsString.hs diff --git a/.gitignore b/.gitignore index d6c3007..77013df 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ cabal.project.local cabal.sandbox.config dist-*/ dist/ +.direnv +.pre-commit-config.yaml +result diff --git a/path/default.nix b/path/default.nix index b3d10ac..3613425 100644 --- a/path/default.nix +++ b/path/default.nix @@ -4,7 +4,7 @@ }: mkDerivation { pname = "path"; - version = "0.9.6"; + version = "0.9.7"; src = ./.; libraryHaskellDepends = [ aeson base deepseq exceptions filepath hashable template-haskell diff --git a/path/os-string-compat/System/OsString/Compat/Include.hs b/path/os-string-compat/System/OsString/Compat/Include.hs index 9828f71..82c1451 100644 --- a/path/os-string-compat/System/OsString/Compat/Include.hs +++ b/path/os-string-compat/System/OsString/Compat/Include.hs @@ -6,6 +6,7 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TypeSynonymInstances #-} {-# OPTIONS_GHC -Wno-deprecations #-} {-# OPTIONS_GHC -Wno-orphans #-} @@ -18,42 +19,62 @@ #endif #endif -module System.OsString.Compat.PLATFORM_NAME +#ifndef MODULE_NAME +#define MODULE_NAME System.OsString.Compat.PLATFORM_NAME +#endif + +module MODULE_NAME #if USE_os_string ( PLATFORM_STRING(..) , PLATFORM_CHAR(..) , module OsString +#ifdef ALTERNATE_OSSTRING_PSTR + , pstr +#endif ) #else ( PLATFORM_STRING(..) , PLATFORM_CHAR(..) +#ifndef ALTERNATE_OSSTRING_PSTR , OsString.pstr - , System.OsString.Compat.PLATFORM_NAME.all - , System.OsString.Compat.PLATFORM_NAME.any - , System.OsString.Compat.PLATFORM_NAME.break - , System.OsString.Compat.PLATFORM_NAME.breakEnd - , System.OsString.Compat.PLATFORM_NAME.dropWhileEnd - , System.OsString.Compat.PLATFORM_NAME.empty - , System.OsString.Compat.PLATFORM_NAME.init - , System.OsString.Compat.PLATFORM_NAME.isInfixOf - , System.OsString.Compat.PLATFORM_NAME.isPrefixOf - , System.OsString.Compat.PLATFORM_NAME.isSuffixOf - , System.OsString.Compat.PLATFORM_NAME.length - , System.OsString.Compat.PLATFORM_NAME.map - , System.OsString.Compat.PLATFORM_NAME.null - , System.OsString.Compat.PLATFORM_NAME.replicate - , System.OsString.Compat.PLATFORM_NAME.singleton - , System.OsString.Compat.PLATFORM_NAME.span - , System.OsString.Compat.PLATFORM_NAME.spanEnd - , System.OsString.Compat.PLATFORM_NAME.stripPrefix - , System.OsString.Compat.PLATFORM_NAME.uncons +#else + , pstr +#endif + , MODULE_NAME.all + , MODULE_NAME.any + , MODULE_NAME.break + , MODULE_NAME.breakEnd + , MODULE_NAME.dropWhileEnd + , MODULE_NAME.empty + , MODULE_NAME.init + , MODULE_NAME.isInfixOf + , MODULE_NAME.isPrefixOf + , MODULE_NAME.isSuffixOf + , MODULE_NAME.length + , MODULE_NAME.map + , MODULE_NAME.null + , MODULE_NAME.replicate + , MODULE_NAME.singleton + , MODULE_NAME.span + , MODULE_NAME.spanEnd + , MODULE_NAME.stripPrefix + , MODULE_NAME.uncons ) #endif where import Data.Data (Data) +#ifdef EXTRA_DATA_DERIVATION +import System.OsString.Internal.Types (PLATFORM_STRING(..), PLATFORM_CHAR(..), EXTRA_DATA_DERIVATION) +#else import System.OsString.Internal.Types (PLATFORM_STRING(..), PLATFORM_CHAR(..)) -import System.OsString.PLATFORM_NAME as OsString +#endif + +#ifndef OSSTRING_MODULE +#define OSSTRING_MODULE System.OsString.PLATFORM_NAME +#endif + +import OSSTRING_MODULE as OsString #if !USE_os_string import Data.Coerce (coerce) @@ -65,9 +86,27 @@ import qualified System.OsPath.Data.ByteString.Short as BSP #endif #endif +#ifdef EXPOSE_CONSTRUCTOR_MODULE +import qualified EXPOSE_CONSTRUCTOR_MODULE +#endif + +#ifdef ALTERNATE_OSSTRING_PSTR +import Language.Haskell.TH.Quote (QuasiQuoter) +#endif + +#ifdef EXTRA_DATA_DERIVATION +deriving instance Data EXTRA_DATA_DERIVATION +#endif + deriving instance Data PLATFORM_STRING +#ifdef ALTERNATE_OSSTRING_PSTR +pstr :: QuasiQuoter +pstr = ALTERNATE_OSSTRING_PSTR +#endif + #if !USE_os_string + all :: (PLATFORM_CHAR -> Bool) -> PLATFORM_STRING -> Bool all = coerce BSP.all diff --git a/path/os-string-compat/System/OsString/Compat/OsString.hs b/path/os-string-compat/System/OsString/Compat/OsString.hs new file mode 100644 index 0000000..74ecb9f --- /dev/null +++ b/path/os-string-compat/System/OsString/Compat/OsString.hs @@ -0,0 +1,19 @@ +{-# LANGUAGE CPP #-} + +#define PLATFORM_NAME OsString +#define OSSTRING_MODULE System.OsString +#define PLATFORM_STRING OsString +#define PLATFORM_CHAR OsChar +#define MODULE_NAME System.OsString.Compat.OsString +#define EXPOSE_CONSTRUCTOR_MODULE System.OsString.Internal.Types +#define EXTRA_DATA_DERIVATION PlatformString + +#if defined(mingw32_HOST_OS) || defined(__MINGW32__) +#define IS_WINDOWS 1 +#else +#define IS_WINDOWS 0 +#endif + +#define ALTERNATE_OSSTRING_PSTR OsString.osstr + +#include "Include.hs" diff --git a/path/path.cabal b/path/path.cabal index 2e247d9..d96bb3a 100644 --- a/path/path.cabal +++ b/path/path.cabal @@ -1,6 +1,6 @@ cabal-version: 3.0 name: path -version: 0.9.6 +version: 0.9.7 synopsis: Support for well-typed paths description: Support for well-typed paths. license: BSD-3-Clause @@ -66,9 +66,13 @@ library , OsPath , OsPath.Posix , OsPath.Windows + , OsPath.OsString , OsPath.Internal , OsPath.Internal.Posix , OsPath.Internal.Windows + , OsPath.Internal.OsString + + other-modules: OsPath.Internal.OsPathWrapper build-depends: aeson >= 1.0.0.0 , base >= 4.12 && < 5 @@ -92,9 +96,11 @@ library os-string-compat exposed-modules: System.OsString.Compat.Posix , System.OsString.Compat.Windows + , System.OsString.Compat.OsString build-depends: base >= 4.12 && < 5 - + , template-haskell + if flag(os-string) build-depends: os-string >= 2.0.0 else diff --git a/path/src/OsPath/Include.hs b/path/src/OsPath/Include.hs index 6f8dea8..d473262 100644 --- a/path/src/OsPath/Include.hs +++ b/path/src/OsPath/Include.hs @@ -115,8 +115,12 @@ import GHC.Generics (Generic) import Language.Haskell.TH (Exp, Q) import Language.Haskell.TH.Syntax (lift) import Language.Haskell.TH.Quote (QuasiQuoter(..)) -import System.OsPath.PLATFORM_NAME (PLATFORM_PATH) -import qualified System.OsPath.PLATFORM_NAME as OsPath + +#ifndef OSPATH_MODULE +#define OSPATH_MODULE System.OsPath.PLATFORM_NAME +#endif +import OSPATH_MODULE (PLATFORM_PATH) +import qualified OSPATH_MODULE as OsPath import OsPath.Internal.PLATFORM_NAME import System.OsString.Compat.PLATFORM_NAME (PLATFORM_STRING) diff --git a/path/src/OsPath/Internal/Include.hs b/path/src/OsPath/Internal/Include.hs index 18d280e..14f32e4 100644 --- a/path/src/OsPath/Internal/Include.hs +++ b/path/src/OsPath/Internal/Include.hs @@ -13,7 +13,10 @@ -- | Internal types and functions. -module OsPath.Internal.PLATFORM_NAME +#ifndef MODULE_NAME +#define MODULE_NAME OsPath.Internal.PLATFORM_NAME +#endif +module MODULE_NAME ( -- * The Path type Path(..) , toOsPath @@ -49,11 +52,18 @@ import GHC.Generics (Generic) import Data.Data import Data.Hashable import qualified Language.Haskell.TH.Syntax as TH -import System.OsPath.PLATFORM_NAME (PLATFORM_PATH) -import qualified System.OsPath.PLATFORM_NAME as OsPath -import System.OsString.Compat.PLATFORM_NAME (PLATFORM_STRING) -import qualified System.OsString.Compat.PLATFORM_NAME as OsString +#ifndef OSPATH_MODULE +#define OSPATH_MODULE System.OsPath.PLATFORM_NAME +#endif +import OSPATH_MODULE (PLATFORM_PATH) +import qualified OSPATH_MODULE as OsPath + +#ifndef OSSTRING_COMPAT_MODULE +#define OSSTRING_COMPAT_MODULE System.OsString.Compat.PLATFORM_NAME +#endif +import OSSTRING_COMPAT_MODULE (PLATFORM_STRING) +import qualified OSSTRING_COMPAT_MODULE as OsString -- | Path of some base and type. -- diff --git a/path/src/OsPath/Internal/OsPathWrapper.hs b/path/src/OsPath/Internal/OsPathWrapper.hs new file mode 100644 index 0000000..d472e4a --- /dev/null +++ b/path/src/OsPath/Internal/OsPathWrapper.hs @@ -0,0 +1,13 @@ +{- +Include.hs expects the quasiquoter to be named 'pstr', however despite the fact that both +System.OsPath.Posix and System.OsPath.Windows export a quasiquoter named 'pstr', +System.OsPath names it 'osp'. So we just re-export with a different name. +-} +module OsPath.Internal.OsPathWrapper (module System.OsPath, pstr) where + +import System.OsPath hiding (osp) +import qualified System.OsPath +import Language.Haskell.TH.Quote (QuasiQuoter) + +pstr :: QuasiQuoter +pstr = System.OsPath.osp diff --git a/path/src/OsPath/Internal/OsString.hs b/path/src/OsPath/Internal/OsString.hs new file mode 100644 index 0000000..e86faa4 --- /dev/null +++ b/path/src/OsPath/Internal/OsString.hs @@ -0,0 +1,17 @@ +{-# LANGUAGE CPP #-} + +#define MODULE_NAME OsPath.Internal.OsString +#define PLATFORM_NAME OsString +#define OSPATH_MODULE OsPath.Internal.OsPathWrapper +#define OSSTRING_MODULE System.OsString +#define PLATFORM_PATH OsPath +#define PLATFORM_PATH_SINGLE 'OsPath' +#define PLATFORM_STRING OsString + +#if defined(mingw32_HOST_OS) || defined(__MINGW32__) +#define IS_WINDOWS 1 +#else +#define IS_WINDOWS 0 +#endif + +#include "Include.hs" diff --git a/path/src/OsPath/OsString.hs b/path/src/OsPath/OsString.hs new file mode 100644 index 0000000..5e6f9ca --- /dev/null +++ b/path/src/OsPath/OsString.hs @@ -0,0 +1,17 @@ +{-# LANGUAGE CPP #-} + +#define PLATFORM_NAME OsString +#define PLATFORM_PATH OsPath +#define PLATFORM_PATH_SINGLE 'OsPath' +#define PLATFORM_STRING OsString +#define OSPATH_MODULE System.OsPath + +#if defined(mingw32_HOST_OS) || defined(__MINGW32__) +#define IS_WINDOWS 1 +#define PLATFORM_UTF_CODEC UTF16-LE +#else +#define IS_WINDOWS 0 +#define PLATFORM_UTF_CODEC UTF8 +#endif + +#include "Include.hs" From 93fe0ca740433513221707d075a9219efc7bb26c Mon Sep 17 00:00:00 2001 From: Clinton Mead Date: Fri, 12 Jun 2026 08:22:43 +1000 Subject: [PATCH 2/2] Consistently define and re-export ptr This is so we can we can produce platform strings when required for functions in this library in the same way for all modules in this library, easing migration between the modules --- path/src/OsPath/Include.hs | 9 ++++++++- path/src/OsPath/OsString.hs | 1 + path/src/Path/Include.hs | 11 +++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/path/src/OsPath/Include.hs b/path/src/OsPath/Include.hs index d473262..f696e56 100644 --- a/path/src/OsPath/Include.hs +++ b/path/src/OsPath/Include.hs @@ -99,6 +99,13 @@ module OsPath.PLATFORM_NAME ,(<.>) ,setFileExtension ,(-<.>) + + -- * Platform string quasiquoter + -- | A number of functions in this library take as an argument a "platform string" + -- which in this module is PLATFORM_STRING_SINGLE + -- Irregardless of the module you're using from this library, + -- 'pstr' will produce the appropriate "platform string". + , pstr ) where @@ -123,7 +130,7 @@ import OSPATH_MODULE (PLATFORM_PATH) import qualified OSPATH_MODULE as OsPath import OsPath.Internal.PLATFORM_NAME -import System.OsString.Compat.PLATFORM_NAME (PLATFORM_STRING) +import System.OsString.Compat.PLATFORM_NAME (PLATFORM_STRING, pstr) import qualified System.OsString.Compat.PLATFORM_NAME as OsString -------------------------------------------------------------------------------- diff --git a/path/src/OsPath/OsString.hs b/path/src/OsPath/OsString.hs index 5e6f9ca..e86d78d 100644 --- a/path/src/OsPath/OsString.hs +++ b/path/src/OsPath/OsString.hs @@ -4,6 +4,7 @@ #define PLATFORM_PATH OsPath #define PLATFORM_PATH_SINGLE 'OsPath' #define PLATFORM_STRING OsString +#define PLATFORM_STRING_SINGLE 'OsString' #define OSPATH_MODULE System.OsPath #if defined(mingw32_HOST_OS) || defined(__MINGW32__) diff --git a/path/src/Path/Include.hs b/path/src/Path/Include.hs index 7069ec4..fed8980 100644 --- a/path/src/Path/Include.hs +++ b/path/src/Path/Include.hs @@ -96,6 +96,8 @@ module Path.PLATFORM_NAME ,(<.>) ,setFileExtension ,(-<.>) + -- * Platform string quasiquoter + ,pstr ) where @@ -185,6 +187,15 @@ fromJSONKeyWith f = {-# INLINE fromJSONKeyWith #-} +-- | A number of functions in this library take as an argument a "platform string" +-- which in this module is just 'FilePath', which is just a 'String'. +-- This means this quosiquoter basically does nothing, you could just write the raw string. +-- But if you move to one of the OsPath style modules, if you use the '[pstr|blah|]' quasiquoter, +-- it will continue to work and produce the appropriate "platform string" for that module, +-- whereas using a raw string literal will break. +pstr :: QuasiQuoter +pstr = qq lift + -- | Exceptions that can occur during path operations. -- -- @since 0.6.0