i started trying to use OsString + OsChar and immediately ran into this issue using osp is really annoying but tolerable this is more than double the overhead
unsafeFromChar :: Char → OsChar
maybe define a short function alias och (also funny if you’re german)
unsafeFromChar isn’t equivalent to osp + head, if i give it a invalid literal i will get a compile time error, unsafeFromChar will just fail silently as it truncates the bytes. I guess if i give osp the empty string then it also fails at runtime but it atleast will raise an exception
I can certainly add such a quasiquoter if you find it useful.
Feel free to create a PR. The osstr quasiquoter is here for an example: os-string/System/OsString/Internal.hs at 0cc9aded7e582c508fb4246700aaecf7956d9877 · haskell/os-string · GitHub
fromText . Data.Text.singleton will do it for you, using fromText.
I added OsChar conversions to Witch: Add `OsChar` conversions by tfausak · Pull Request #158 · tfausak/witch · GitHub
Normally you could use liftedFrom to check values at compile time, like $$(liftedInto @OsChar ‘x’). But unfortunately that won’t work because of a missing Lift instance: Allow lifting `OsChar` · Issue #44 · haskell/os-string · GitHub
Also note that going through OsString probably won’t do what you want for non-ASCII characters. For example:
ghci> uncons [osstr|λ|]
Just (206,"\187")
You would get '\206’ (U+00CE, LATIN CAPITAL LETTER I WITH CIRCUMFLEX) rather than '\955’ (U+03BB, GREEK SMALL LETTER LAMDA).
Yes, it’s not clear to me whether OP really wants OsChar, because it’s not a representation of a unicode codepoint anyway.
So osp/osstr is the right thing for that.
What exactly are you trying to achieve @eldritch-cookie ?
I was making a small script that would remove all blank characters before a newline. i was unable to find a robust way to identify binary files so i decided to whitelist extensions.
I have a list of extensions without the dot and i needed to get a OsChar for the dot to use cons on each extension.
With a fresh mind i reconsidered my options and had a second look over filepath and found isExtensionOf which does exactly what i wanted, i also could use the Semigroup typeclass combined with isSuffixOf to implement that. ![]()
Keep in mind that OsChar is actually more or less a byte in an encoded byte sequence. You could argue it should have been named OsWord to avoid confusion.
There are cases where extracting an OsChar and pattern matching on it makes sense, e.g. notably with the filepath separator /, because it is encoding agnostic. But in other cases you may get nonsensical results if you expect OsChar to correspond to unicode code points or graphemes even. On windows (UTF-16) you may hit a surrogate or on a utf-8 unix system you may hit a multi byte unicode sequence.
Using unsafeFromChar :: Char -> OsChar and then pack :: [OsChar] -> OsString essentially truncates your unicode to the extended ascii range. You could now treat it as valid latin1, but it’s unclear if that makes any sense.
If you need proper semantic search, you need to decode first (e.g. to String or Text) and decide what the source encoding is.
The filepath extension char is a bit on the fence here: posix standard doesn’t specify a byte for it, but I believe it’s more or less convention that 0x2E (anywhere in a byte sequence) denotes a filepath extension.
If we look at UTF-8 then it becomes apparent that we can’t accidentally have 0x2E in a multibyte unicode sequence. All bytes in a multibyte unicode sequence always start in the range greater than 0x80 (so above the ascii range). That’s why the encoding is ascii compatible. You can’t get an accidental / or ..
I don’t think that holds for all encodings, but the OS API won’t really care whether your string has a funny encoding. The filepath separator is a fixed byte.
I’d stick with isExtensionOf here. OsChar isn’t really a Unicode character anyway—it’s closer to a unit of the underlying OS string encoding. For filepath extensions, working at the OsString/filepath level is usually cleaner and avoids encoding-related surprises.