I will assume that you want the normal TraditionalForm
typesetting in a notebook to be unaffected, and only want to see the TeXForm
of FresnelC
, CosIntegral
and other targeted functions changed. Also, I assume you don't want to have to use a new function, like myTeXForm
, but would rather just use TeXForm
as you usually do.
TeXForm works by first converting an expression into TraditionalForm
boxes, and then converting those boxes into a TeX string. So, one possibility is to do as @QuantumDot suggests, and modify the functions that convert the boxes to a TeX string. However, I prefer avoiding the creation of the wrong boxes. Another possibility is to do as @b3m2a1 suggests, but then both the TeXForm
and normal TraditionalForm
typesetting will be affected.
Instead, I would modify the expression to boxes internal function so that it creates the desired boxes. This can be done by having this function set a global variable, say $TeX
, to True
. Then, when the expression is converted to boxes, a conditioned FormatValue can be used to create the TraditionalForm
boxes you want.
Initial
It will be convenient to make use of the function Initial
from my answer to How can one manually change the rule ordering:
Initial /: Verbatim[TagSetDelayed][Initial[sym_], lhs_, rhs_] := With[
{
new = Block[{sym},
TagSetDelayed[sym, lhs, rhs];
First @ Language`ExtendedDefinition[sym, "ExcludedContexts" -> {}]
],
protect=Unprotect[sym]
},
sym;
Replace[new,
Rule[values_, n:Except[{}]] :> (values[sym] = Prepend[values[sym],n]),
{2}
];
Protect@protect;
]
This function creates a new *Value, and prepends it to the existing *Values. It also forces autoloading of any necessary packages (.mx) files that will populate the *Values of the function before the new *Value is added.
Convert`TeX`ExpressionToTeX
The internal function I will modify is Convert`TeX`ExpressionToTeX
:
Initial[Convert`TeX`ExpressionToTeX] /:
Convert`TeX`ExpressionToTeX[e__] /; !TrueQ@$TeX := Block[
{$TeX = True},
Convert`TeX`ExpressionToTeX[e]
]
Note that when $TeX
is not True, the above DownValue will set $TeX
to True, and then use the old DownValue.
FormatValues
The new TraditionalForm FormatValues are:
Initial[FresnelC] /: MakeBoxes[FresnelC[a_], TraditionalForm] /; $TeX :=
MakeBoxes[Defer[FresnelC][a], TraditionalForm]
Initial[CosIntegral] /: MakeBoxes[CosIntegral[a_], TraditionalForm] /; $TeX :=
MakeBoxes[Defer[CosIntegral][a], TraditionalForm]
Note the use of the $TeX
condition. Also, note the use of Defer[FresnelC]
on the RHS so that no recursion errors occur. Finally, I like using Defer[FresnelC]
instead of something like HoldForm[FresnelC]
because the boxes that are produced are simpler. Compare:
MakeBoxes[Defer[FresnelC], TraditionalForm]
MakeBoxes[HoldForm[FresnelC], TraditionalForm]
"FresnelC"
TagBox["FresnelC", HoldForm]
Results
Here we see the new TeXForm
formatting in action:
ToString[{FresnelC[a], CosIntegral[b]}, TeXForm]
"\{\text{FresnelC}(a),\text{CosIntegral}(b)\}"
And here we see the normal TraditionalForm
typesetting is still in place:
{FresnelC[a], CosIntegral[b]} //TraditionalForm
{C(a),Ci(b)}
Update
To address the question in the comments, defining:
System`Convert`TeXFormDump`maketex[s_String] /; !StringMatchQ[s, "\""~~___~~"\""] && SyntaxQ[s, TeXForm] := Replace[
s,
{
n_ /; StringMatchQ[n, NumberString] :> n,
w_?wordQ :> "\\operatorname{"<>w<>"}"
}
]
wordQ[s_String] := Length @ StringSplit[s, WordBoundary] == 1
should make operators use \operatorname instead of \text.
Convert`TeX`BoxesToTeX
$\endgroup$