'\n' is not working in `print` for customized string literals

I define a @c_str macro for colored strings:

using Rematch: @match

function color_string(str::AbstractString, color::AbstractChar)
    env = @match color begin
        'b' => "\033[34m"
        'r' => "\033[31m"
        'g' => "\033[32m"
        'm' => "\033[35m"
        _ => throw(ArgumentError("unknown color flag: $color"))
    end
    return env * str * "\033[0m\033[0m"
end

macro c_str(str, color = 'g')
    @assert(length(color) == 1)
    return color_string(str, first(color))
end # macro c_str

However, print a c_str with '\n' inside does not print new lines anymore:

julia> print(c"new line\n"r)
new line\n
julia> print(c"\nnew line\n"r)
\nnew line\n
julia>

Can it be solved?

Also, string interpolation is not working:

julia> a = 1
1

julia> c" $a "
"\e[32m \$a \e[0m\e[0m"

For custom string literals, you get the raw string without processing of escape characters or interpolations. It’s up to you to implement those extra behaviors if desired:

julia> macro blah_str(str)
           for c in str
               println(repr(c))
           end
       end
@blah_str (macro with 1 method)

julia> blah"\n$x"
'\\'
'n'
'$'
'x'

Doing something like Meta.parse('"' * replace(str, '"' => "\\\"") * '"') inside the macro and processing the resulting string or AST can be a convenient way to recover the usual interpolation support.

2 Likes

This seems inconsistent with the documentation however. From Metaprogramming · The Julia Language viz:

Like string literals, command literals can also be prefixed by an identifier to form what are called non-standard command literals. These command literals are parsed as calls to specially-named macros. For example, the syntax customliteral`` is parsed as @custom_cmd "literal" . Julia itself does not contain any non-standard command literals, but packages can make use of this syntax. Aside from the different syntax and the _cmd suffix instead of the _str suffix, non-standard command literals behave exactly like non-standard string literals.

But

macro blah_str(str)
    return quote
        @eval $str
    end
end

v = 1
@blah_str "$v" # => "1"
blah"$v" # => "\$v"

So they don’t seem to be parsed the same as each other (similarly for commands).

This is julia v1.7.1

The point here is that x"blah" and x`blah` are parsed the same (other than having different sufficies @x_str vs @x_cmd.)

However @x_str "str" and x"str" are not the same if str contains escape sequences; the manual doesn’t really discuss this case for nonstandard string literals. I don’t think the manual is inconsistent here but it is incomplete.