22
$\begingroup$

Recently, we had a nice question which brought up an issue that I believe is a bug. In the tutorial Defining Output Formats, there is an example at the end which doesn't make sense:

This specifies the TeXForm for the symbol x.

Format[x, TeXForm] := "{\\bf x}"

The output format for x that you specified is now used whenever the TeX form is needed.

TeXForm[1 + x^2] 
(* x^2+1 *)

The given output is wrong and should instead be something like {\bf x}^2+1. Therefore, I tested this with my colleague on all versions available to us and the output below shows, that it only worked back in version 4.2.

Is there a simple reason why Format does not work as advertised?

Version 4.2

Format[x,TeXForm]:="{\\bf x}";
TeXForm[1+x^2]
(* 1 + {{\bf x}}^2 *)

Version 5.1

Format[x,TeXForm]:="{\\bf x}";
TeXForm[1+x^2]
(* x^2+1 *)

Version 6.0

Format[x, TeXForm] := "{\\bf x}";
TeXForm[1 + x^2]
(* x^2+1 *)

Version 7.0

Format[x, TeXForm] := "{\\bf x}";
TeXForm[1 + x^2]
(* x^2+1 *)

Version 8.0

Format[x, TeXForm] := "{\\bf x}";
TeXForm[1 + x^2]
(* x^2+1 *)

Version 9.0

Format[x, TeXForm] := "{\\bf x}";
TeXForm[1 + x^2]
(* x^2+1 *)
$\endgroup$
  • $\begingroup$ From Mathematica's help: Format[s]:=rhs defines a symbol s to print like rhs. $\endgroup$ – Gregory Rut May 7 '14 at 9:41
  • 1
    $\begingroup$ @GregoryRut How does that answer the question? $\endgroup$ – Sjoerd C. de Vries May 7 '14 at 10:50
  • 2
    $\begingroup$ @RolfMertig it works with any $BoxForms, which are StandardForm and TraditionalForm. These are called by TeXForm on its argument, and the latter then displays as the $\TeX$ corresponding to the resulting boxes. It isn't the most elegant approach, I admit, but without knowledge of how the TeXForm display is obtained internally (probably the the FE sees it and produces some special boxes?), this hijacking seems to be the best we can do. $\endgroup$ – Oleksandr R. May 7 '14 at 13:00
  • 1
    $\begingroup$ @chuy I have already reported it as bug. $\endgroup$ – halirutan May 7 '14 at 17:10
  • 2
    $\begingroup$ Note: the Format rule is applied in TeXForm[x]. It is possible that a format is applied in TeXForm only when it matches the whole expression. $\endgroup$ – Michael E2 May 9 '14 at 12:37
13
$\begingroup$

What Format does

Role of Format, as I understand it, is to set appropriate transformation rules. One can check those rules using FormatValues function:

Format[x, TeXForm] = "{\\bf x}";
FormatValues[x] // FullForm
(* List[RuleDelayed[HoldPattern[Format[x, TeXForm]], "{\\bf x}"]] *)

One can also see those rules by inspecting symbol for which rules where set:

?x
(* Global`x *)
(* x/:Format[x,TeXForm]={\bf x} *)

So Format alone correctly assigns proper transformation rules. It's TeXForm that is not using them as it should.


What TeXForm does

There are two problems with how TeXForm works.

Problem 1: When formatting rules are used, what we have set as RHS of Format is not used verbatim, but converted to $\TeX$.

As it's noted in comment by @MichaelE2, if we pass expression with defined rules directly to TeXForm

TeXForm[x]
(* \text{$\{\backslash \backslash $bf x$\}$} *)

transformation rules are used, but string "{\\bf x}" is converted to $\TeX$.

Problem 2: Formatting rules are not used for subexpressions of expression passed to TeXForm.

TeXForm[1 + x^2]
(* x^2+1 *)

How TeXForm works under the hood is described in answers to question mentioned by OP.

As stated in Properties & Relations section of Format documentation MakeBoxes use formatting rules added by Format. MakeBoxes is used by TeXForm, but as noted in comment by @RolfMertig and explained in comment by @OleksandrR. TeXForm is not one of $BoxForms and internally TeXForm converts expression to boxes in TraditionalForm. So formatting rules for TeXForm are just not used anywhere.


How to work around TeXForm problems

Problem 1

To deal with it we can define a wrapper that, when converted to $\TeX$, will return its content verbatim:

TeXVerbatim::usage = "TeXVerbatim[\"str\"] converted to TeX gives verbatim \"str\"."

Let's use System`Convert`TeXFormDump`maketex to force appropriate $\TeX$ conversion:

System`Convert`TeXFormDump`maketex[
    RowBox[{
        "TeXVerbatim",
        "(" | "[", 
        arg_String?(StringMatchQ[#, "\"" ~~ ___ ~~ "\""] &), 
        ")" | "]"
    }]
] :=
    ToExpression[arg]

This is the only place where we'll use this internal function and only "box pattern" we need to write by hand. Let's check that it works:

TeXVerbatim["\\macro $1+1$ \\command[a=b]{c}"] // TeXForm
(* \macro $1+1$ \command[a=b]{c} *)

Now use it in Format:

Format[x, TeXForm] := TeXVerbatim["{\\bf x}"]
TeXForm[x]
(* {\bf x} *)

Problem 2

First let's define function that applies relevant rules to given expression:

ApplyTeXFormFormat::usage =
    "ApplyTeXFormFormat[expr] returns expr with all subexpressions that \
    have custom TeX formating rules replaced with their TeX form."

ApplyTeXFormFormat[expr_] :=
    expr /.
        Flatten[
            Cases[
                (* Get formating rules, *)
                FormatValues[#]
                ,
                (* take only rules defined for TeXFormat *)
                HoldPattern[HoldPattern[HoldPattern][Format[x_, TeXForm]] :> xTeX_] :>
                    (* and change them to replacement rules for bare transformed expression. *)
                    (HoldPattern[x] :> xTeX)
            ] & /@
                (* Perform above for all symbols found in expr. *)
                DeleteDuplicates[
                    Cases[expr, _Symbol, {0, Infinity}, Heads -> True]]
                ]
        ]

Since those rules transform expression and not low level boxes they could be used anywhere before MakeBoxes is called on expression passed to TeXForm.

We can either define own function that will apply transformation rules and convert expression to $\TeX$:

TeXFormAll::usage =
    "TeXFormAll[expr] prints TeX version of expr with custom formating \
    applied to each subexpression."

TeXFormAll[expr_] := TeXForm[ApplyTeXFormFormat[expr]]

TeXFormAll[1 + x^2]
(* {\bf x}^2+1 *)

or redefine built in Convert`TeX`ExpressionToTeX function so that TeXForm will work as expected:

Unprotect[Convert`TeX`ExpressionToTeX];

Convert`TeX`ExpressionToTeX[expr_, opts___?OptionQ] :=
    Convert`TeX`BoxesToTeX[
        ToBoxes[ApplyTeXFormFormat[expr], TraditionalForm],
        opts,
        "BoxRules" -> System`Convert`TeXFormDump`$GreekWords
     ]

Protect[Convert`TeX`ExpressionToTeX];

TeXForm[1 + x^2]
(* {\bf x}^2+1 *)

Package

I've created a package implementing above concepts together with some additional functions to customize TeX output. It is available on GitHub.

Its example usage could be:

Get["https://raw.githubusercontent.com/jkuczm/MathematicaTeXUtilities/master/TeXUtilities/TeXUtilities.m"]
Get["https://raw.githubusercontent.com/jkuczm/MathematicaTeXUtilities/master/TeXUtilities/FormatTeXFormPatch.m"]


Format[something, TeXForm] = TeXVerbatim["\\macro $1+1$ \\command[a=b]{c}"];

Format[f[x__], TeXForm] := TeXDelimited["\\left(", x, "\\right)", "DelimSeparator" -> ""]

Format[g[x__], TeXForm] := TeXCommand["g", {{a -> b}, x}]

Format[h[x__], TeXForm] := TeXEnvironment["myEnv", x]

h[
    f[1 + alpha],
    5 - g[3, g[2]],
    something
] // TeXForm
(*
\begin{myEnv}
\left(\alpha +1\right)
5-\g[a=b]{3}{\g[a=b]{2}}
\macro $1+1$ \command[a=b]{c}
\end{myEnv}
*)
$\endgroup$
  • $\begingroup$ Thank you for the detective work! $\endgroup$ – masterxilo Sep 17 '16 at 19:58
10
$\begingroup$

If someone is after an easy workaround, then here it is: First, you have to initialise the TeX conversion system by simply calling something like TeXForm[1] when you are working on a fresh Kernel.

After that it is simply

System`Convert`TeXFormDump`maketex["x"] = "{\\bf x}";
TeXForm[x^2 + 1]
(* {\bf x}^2+1 *)

For a detailed explanation, please see here.

Note that this only works around the issue and doesn't explain, why it is not working as described.

$\endgroup$
5
$\begingroup$

This is not an answer, but a comment to halirutans answer that is to big for a comment.

It's important to stress that, if we want special TeXForm for an expression, argument given to System`Convert`TeXFormDump`maketex should be low level box representation of that expression in TraditionalForm.

For symbol it's just string with symbols name:

TeXForm[1](* initialise *)

System`Convert`TeXFormDump`maketex["x"] = "\\text{special TeXForm of x}";
TeXForm[1 + x]
(* \text{special TeXForm of x}+1 *)

For complicated expressions we can use MakeBoxes:

System`Convert`TeXFormDump`maketex[MakeBoxes[f[a, b], TraditionalForm]] = "\\f[a]{b}";
TeXForm[1 + f[a, b]]
(* \f[a]{b}+1 *)

But if one wants special TeXForm of any expression matching given pattern, it's more complicated.

System`Convert`TeXFormDump`maketex[MakeBoxes[g[a_], TraditionalForm]] := "\\g{" <> a <> "}"
TeXForm[g[a + 1]]
(* g(a+1) *)

Above does not work because boxes representing an "expression pattern":

MakeBoxes[g[a_], TraditionalForm] // FullForm
(* RowBox[List["g", "(", "a_", ")"]] *)

are something different than "box pattern" matching boxes representing any expression matching said "expression pattern". For simple pattern like the one above it's easy to write appropriate "box pattern" by hand:

System`Convert`TeXFormDump`maketex[RowBox[{"g", "(", a_, ")"}]] :=
    "\\g{" <> System`Convert`TeXFormDump`MakeTeX[a] <> "}"
    (* Note the use of MakeTeX with capital letters on RHS
       it's needed to properly use "BoxRules",
       that can be passed as an option to Convert`TeX`BoxesToTeX *)

TeXForm[g[a + 1]]
(* \g{a+1} *)

but for more complicated patterns it's very cumbersome.

Code samples tested in version 9.0.1.0 on Linux.

$\endgroup$
5
$\begingroup$

To have a self-contained answer, I am repeating some of what the other answers have mentioned. For the TLDR folks, I've included all of the relevant code at the end of this answer.

TeXForm design

The way TeXForm works is as follows:

  1. Apply any TeXForm formatting rules that match the entire expression. If one does, then return the result. Otherwise:
  2. Convert the resulting expression into TraditionalForm boxes.
  3. Recursively transform the resulting TraditionalForm boxes into a TeXForm string.

Format issue

The heart of the problem then is that during step 1, the TeXForm definitions defined using Format are only applied once, and to the entire expression. This behavior is different from other Format definitions, which apply definitions recursively, because of the two-step process that TeXForm uses. To fix this, there are two possibilities:

  1. Use a ReplaceRepeated strategy on the expression, that replaces parts at all levels (improve step 1).
  2. Convert the TeXForm format rules into MakeBoxes rules (improve step 2).

Possibility 1 is used by @jkuczm in his TeXUtilities package. I prefer possibility 2, so I will provide code to use this possibility.

Why I don't like possibility 1

The reason I don't like using possibility 1 is because the code needs to search the expression to figure out which Format rules should be used when doing the expression replacement. And, since a Format rule can include a symbol on the RHS that also needs to be converted, the conversion of the expression really needs to be done again, including the search for all symbols that might need replacement in the new expression. Here is an example. Suppose we have the following Format rules:

Format[foo[x_], TeXForm] := bar[x, foo2[x]]
Format[foo2[x_], TeXForm] := bar2[x]

and we want to convert the expression:

foo[x] + Sin[x]

into TeXForm. In order to know which Format rules to use, we need to examine the expression, upon which we figure out that only foo needs to be replaced. So, if we replace it, we end up with:

bar[x, foo2[x]] + Sin[x]

Notice that we now have an expression with foo2. So, we need to repeat the above process, and we figure out that now only foo2 needs to be replaced. So, we again replace, ending up with:

bar[x, bar2[x]] + Sin[x]

At this point, there are no more Format rules to apply, so we can go ahead and create the boxes corresponding to the above expression.

Now, with possibility 2, all we need to do is to define the MakeBoxes rules corresponding to the Format statements, and then applying MakeBoxes to the expression will automatically use these new MakeBoxes rules as needed. No need to repeatedly search the expression for symbols and perform replacements.

Converting Format -> MakeBoxes

One issue with converting Format rules into MakeBoxes rules is that TeXForm uses TraditionalForm, and we don't want the TeXForm specific MakeBoxes rules to be used during normal TraditionalForm formatting. To avoid this, I will introduce a global variable (I've given it the name $TeX), and set this variable to True when the expression is converted to TraditionalForm boxes. Then, the code to convert Format rules into MakeBoxes rules can include a $TeX condition in the MakeBoxes rule, so that it only fires when the TeXForm string is being created.

Modifying built-in symbols

I will be modifying built-in symbols, and you should be aware that there are risks associated with doing this.

Since I will be changing DownValues/UpValues of built-in symbols, it will be very convenient to make use of the Initial wrapper that I introduced in 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]
    ],
    protect = Unprotect[sym]
    },

    sym;
    Replace[new,
        Rule[values_, n:Except[{}]] :> (
            values[sym] = DeleteDuplicates@Join[n, values[sym]]
        ),
        {2}
    ];
    Protect@protect;
]

The basic idea is that using something like:

Initial[FresnelC] /: 
    MakeBoxes[FresnelC[x_], TraditionalForm] :=
    MakeBoxes[Defer[FresnelC][x], TraditionalForm]

will not only create the new FormatValues, it will try to put this new format value at the beginning, so that it fires before any built - in format rules for the input:

FormatValues[FresnelC] //InputForm

{HoldPattern[MakeBoxes[FresnelC[x_], TraditionalForm]] :> MakeBoxes[Defer[FresnelC][x], TraditionalForm], HoldPattern[MakeBoxes[FresnelC[BoxForm`a\$_], TraditionalForm] /; BoxForm`sufficientVersionQ[6.1]] :> TemplateBox[{MakeBoxes[BoxForm`a\$, TraditionalForm]}, "FresnelC"]}

Notice how the new MakeBoxes rule is first.

Convert`TeX`ExpressionToTeX

The first change is to modify the function Convert`TeX`ExpressionToTeX so that it sets the global variable $TeX to True before creating TraditionalForm boxes:

Initial[Convert`TeX`ExpressionToTeX] /: 
    Convert`TeX`ExpressionToTeX[e__] /; !TrueQ@$TeX := Block[
	{$TeX = True},
        Convert`TeX`ExpressionToTeX[e]
    ]

By design, $TeX will only get a value when it is blocked. This means that !TrueQ@$TeX will initially be True, and then after $TeX is blocked True, the condition will be false. The normal Convert`TeX`ExpressionToTeX code converts the expression into boxes using MakeBoxes[.., TraditionalForm].

Modifying Format

TagSetDelayed Format

The next step is to modify Format so that it creates a $TeX conditioned TraditionalForm MakeBoxes rule instead of a TeXForm Format rule. Before I do that, let's see what kind of FormatValues TeXForm typically creates:

foo /: Format[foo, TeXForm] := bar
FormatValues[foo] //FullForm

List[RuleDelayed[HoldPattern[Format[foo,TeXForm]],bar]]

Instead of the above, I want to create a TraditionalForm MakeBoxes rules. The following code does this:

Initial[Format] /: TagSetDelayed[sym_Symbol, Verbatim[Format][x_, TeXForm], rhs_] := With[
    {fmt = TraditionalForm},

    Initial[sym] /: MakeBoxes[x, fmt] /; $TeX := MakeBoxes[rhs, fmt]
]

Let's try the above Format again:

Clear[foo];
foo /: Format[foo, TeXForm] := bar

FormatValues[foo]

{HoldPattern[MakeBoxes[foo, TraditionalForm] /; $TeX] :> MakeBoxes[bar, TraditionalForm]}

Notice that there is no TeXForm rule any more, only a $TeX conditioned MakeBoxes rule. Also, the FormatValues is attached to foo, and not to MakeBoxes. This is exactly what we want. Modifying Format to do this is easy when TagSetDelayed is used, since the relevant tag symbol (needed for the MakeBoxes rule) is given in the input.

SetDelayed Format

A typical Format statement doesn't bother including the tag, so it would be nice to have this version work as well. Here is one way to do that:

Initial[Format] /: SetDelayed[Verbatim[Format][x_, TeXForm], rhs_] := With[
    {s = getTagSymbol[Format[x, TeXForm]], fmt = TraditionalForm},
    Replace[s,
        HoldForm[tag_] :> (
            Initial[tag] /: MakeBoxes[x, fmt] /; $TeX := MakeBoxes[rhs, fmt]
        )
    ]
]

SetAttributes[getTagSymbol, HoldFirst]

getTagSymbol[Format[x_, TeXForm]] := Module[{dummy, t},
    extractTag[Hold[Message[Format::tag, HoldForm@Format, _, tag_], False]] := t = tag;
    Internal`HandlerBlock[{Message, extractTag},
        Quiet[dummy[1] /: Format[x, TeXForm] := 1]
    ];
    t
]

The above code uses getTagSymbol to figure out what the correct tag is for a given Format LHS. It does this by using a dummy Module variable as the tag, so that the Format rule will issue an error message telling us what the tag symbol should be. For instance:

dummy /: Format[x, InputForm] := 2

Format::tag: Rule for Format of x can only be attached to x.

$Failed

The Internal`HandlerBlock code intercepts this Message to figure out what the tag symbol is, and a Quiet is used because we are intentionally creating an error. A couple examples of getTagSymbol in action:

getTagSymbol[Format[x, TeXForm]]
getTagSymbol[Format[s_String, TeXForm]]
getTagSymbol[Format[foo[bar_], TeXForm]]

HoldForm[x]

HoldForm[String]

HoldForm[foo]

Finally, here is an example of an ordinary Format statement:

Format[foo2, TeXForm] := bar2
FormatValues[foo2]

{HoldPattern[MakeBoxes[foo2, TraditionalForm] /; $TeX] :> MakeBoxes[bar2, TraditionalForm]}

Again, there is no Format rule, and the MakeBoxes rule has the $TeX condition as desired. With the above rules, we now get:

ToString[foo + foo2, TeXForm]

"\text{bar}+\text{bar2}"

The above code is sufficient for effectively making the TeXForm Format rules act recursively.

Examples

Example 1

My first example will be similar to the OP example, except that I won't use a string RHS. Instead, I will define:

Format[x, TeXForm] := Style["x", FontWeight->"Bold"]

Then, the TeXForm for a few examples are (I use CellPrint so that all examples print, to avoid the issue discussed in (138916)):

CellPrint@TextCell[ToString[#, TeXForm], "Output"]& /@ {x, x+1, Sin[x^2+1]};

\pmb{\text{x}}

\pmb{\text{x}}+1

\sin \left(\pmb{\text{x}}^2+1\right)

And this is what they look like when using MathJax:

$\pmb{\text{x}}$

$\pmb{\text{x}}+1$

$\sin \left(\pmb{\text{x}}^2+1\right)$

Example 2

This example comes from question (153876):

Format[FresnelC[x_], TeXForm] := Defer[FresnelC][x]
Format[CosIntegral[x_], TeXForm] := Defer[CosIntegral][x]

Then, nested functions do the right thing:

HoldForm[1+FresnelC[1+FresnelC[CosIntegral[z]]]] //TeXForm

1+\text{FresnelC}(1+\text{FresnelC}(\text{CosIntegral}(z)))

OP Example

Finally, let's look at the OP Example:

Format[x, TeXForm] := "{\\bf x}"

x //TeXForm

\text{$\{\backslash \backslash $bf x$\}$}

What happened here? Without my Format changes, the Format statement will match x, and then return "{\b x}", short-circuiting the MakeBoxes/BoxesToTeX code. On the other hand, my Format changes mean that there are no Format statements to match, they have all been turned into MakeBoxes rules. So, there is no short-circuit, and the BoxesToTeX code applies its rules to the boxes to produce the output you see. It is the same thing as doing:

"{\\bf x}" //TeXForm

\text{$\{\backslash \backslash $bf x$\}$}

I think this treatment of strings is rather suboptimal.

I think the way to proceed here is to change how the BoxesToTeX code deals with strings. MakeBoxes produces 2 kinds of strings. For example:

MakeBoxes[x] //FullForm
MakeBoxes["x"] //FullForm

"x"

"\"x\""

Basically, strings get converted into "quoted" strings, and everything else gets converted into "unquoted" strings. Currently, the BoxesToTeX code treats both kinds of strings equivalently. For example:

Convert`TeX`BoxesToTeX["\"{\\\\bf x}\""]
Convert`TeX`BoxesToTeX["{\\\\bf x}"]

"\text{\$\{\backslash \backslash \$bf x\$\}\$}"

"\text{\$\{\backslash \backslash \$bf x\$\}\$}"

So, one idea is to leave the conversions of "quoted strings" as they are, but to change the conversions of "unquoted strings". This way anybody who relies on the current behavior of TeXForm[string] will see that behavior maintained (although I suspect that nobody relies on the current behavior, and the best thing to do is to eliminate this string conversion behavior entirely).

The following code only changes the conversion of unquoted strings that are syntactically valid TeX:

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

Note that numbers are left alone, single word strings (corresponding to operators) are wrapped in \operatorname, and other strings are just left alone (since they pass the TeXForm SyntaxQ check).

Finally, the Format rule needs to be changed slightly because we want the TraditionalForm boxes to not have quotes:

Format[x, TeXForm] := "{\\bf x}"

Block[{$TeX=True}, MakeBoxes[x, TraditionalForm]] //InputForm

"\"{\\bf x}\""

Since the RHS of the Format statement is a string, the corresponding boxes are a quoted string. To make the corresponding boxes an unquoted string (so that the new string TeX code is used), we need to use RawBoxes:

Format[x, TeXForm] := RawBoxes @ "{\\bf x}"

Block[{$TeX=True}, MakeBoxes[x, TraditionalForm]] //InputForm

"{\bf x}"

Now, the OP example should work:

x^2+1 //TeXForm

{\bf x}^2+1

Code

Here is the relevant code in a single code block:

Initial /: Verbatim[TagSetDelayed][Initial[sym_], lhs_, rhs_] := With[
    {
    new = Block[{sym},
        TagSetDelayed[sym, lhs, rhs];
        First @ Language`ExtendedDefinition[sym]
    ],
    protect = Unprotect[sym]
    },

    sym;
    Replace[new,
        Rule[values_, n:Except[{}]] :> (
            values[sym] = DeleteDuplicates@Join[n, values[sym]]
        ),
        {2}
    ];
    Protect@protect;
]

Initial[Convert`TeX`ExpressionToTeX] /: 
    Convert`TeX`ExpressionToTeX[e__] /; !TrueQ@$TeX := Block[
	{$TeX = True},
        Convert`TeX`ExpressionToTeX[e]
    ]

Initial[Format] /: TagSetDelayed[sym_Symbol, Verbatim[Format][x_, TeXForm], rhs_] := With[
    {fmt = TraditionalForm},

    Initial[sym] /: MakeBoxes[x, fmt] /; $TeX := MakeBoxes[rhs, fmt]
]

Initial[Format] /: SetDelayed[Verbatim[Format][x_, TeXForm], rhs_] := With[
    {s = getTagSymbol[Format[x, TeXForm]], fmt = TraditionalForm},
    Replace[s,
        HoldForm[tag_] :> (
            Initial[tag] /: MakeBoxes[x, fmt] /; $TeX := MakeBoxes[rhs, fmt]
        )
    ]
]

SetAttributes[getTagSymbol, HoldFirst]

getTagSymbol[Format[x_, TeXForm]] := Module[{dummy, t},
    extractTag[Hold[Message[Format::tag, HoldForm@Format, _, tag_], False]] := t = tag;
    Internal`HandlerBlock[{Message, extractTag},
        Quiet[dummy[1] /: Format[x, TeXForm] := 1]
    ];
    t
]

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

And, here again is the OP example:

(* OP example *)
Format[x, TeXForm] := RawBoxes @ "{\\bf x}"
x^2 + 1 //TeXForm

{\bf x}^2+1

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.