Here's a method that's really no different from the standard ones except it's generalized for copying cells and, theoretically, for Windows and Unix.
We'll use RunProcess
because this exists now, and tweak the ProcessEnvironment
to make it work for Mac:
FrontEnd`unicodeCopy[s_String,
enc : _String | Automatic : Automatic,
lang : _String | Automatic : Automatic
] :=
With[{
encoding = Replace[enc, Automatic :> $CharacterEncoding],
language = Replace[lang, Automatic :> $Language]
},
If[#["ExitCode"] =!= 0,
FrontEnd`unicodeCopy::copyerr = "error in copy process:\n ``";
Message[FrontEnd`unicodeCopy::copyerr, #["StandardError"]];,
#["StandardOuput"];
] &@
RunProcess[
Switch[$OperatingSystem,
"Windows",
"clip",
"MacOSX",
"pbcopy",
"Unix",
{"xsel", "-b"}
],
All,
ExportString[s,
"String",
CharacterEncoding -> encoding
],
ProcessEnvironment -> <|
"LANG" ->
Replace[ToLowerCase@language,
"english" -> "en_US"
] <> "." <>
Replace[encoding, {
"UTF8" -> "UTF-8",
"Unicode" -> "UTF-16"
}],
"PATH" -> Environment["PATH"]
|>
]
];
(I'm using FrontEnd`
for when I dump to "MenuSetup.tr"
, just so it looks consistent)
Now we'll define a bunch of junk to generalize to make it work across an NB:
$unicodeTR =
FrontEnd`FindFileOnPath["UnicodeCharacters.tr",
"PrivatePathsTextResources"] // FrontEndExecute;
$unicodeReplacements = #[[2]] ->
ToExpression[
"\"" <> StringReplace[#[[1]], {"x" -> ":",
StartOfString ~~ "0" -> "\\"}] <> "\""] & /@
Rest[
StringSplit@StringSplit[Import[$unicodeTR, "String"], "\n"]
];
FrontEnd`UnicodeCopy[c : {__Cell}] :=
Replace[
MathLink`CallFrontEnd[
ExportPacket[Cell[CellGroupData[c]], "InputText"]
], {
{s_String, __} :>
FrontEnd`unicodeCopy@
StringReplace[s,$unicodeReplacements]
}];
FrontEnd`UnicodeCopy[c_Cell] :=
Replace[
MathLink`CallFrontEnd[
ExportPacket[c, "InputText"]
], {
{s_String, __} :>
FrontEnd`unicodeCopy@
StringReplace[s,$unicodeReplacements]
}];
FrontEnd`UnicodeCopy[b_BoxData | _TextData] :=
FrontEnd`UnicodeCopy@Cell[b];
FrontEnd`UnicodeCopy[b_RowBox] :=
FrontEnd`UnicodeCopy@Cell[BoxData@b];
FrontEnd`UnicodeCopy[
nb : _NotebookObject | _FrontEnd`NotebookObject | \
_FrontEnd`SelectedNotebook | _FrontEnd`InputNotebook | \
_FrontEnd`ButtonNotebook | _FrontEnd`EvaluationNotebook | \
_FrontEnd`MessagesNotebook | _FrontEnd`HelpBrowserNotebook | \
_FrontEnd`ClipboardNotebook
] :=
FrontEnd`UnicodeCopy[Evaluate@NotebookRead@nb];
FrontEnd`UnicodeCopy[
nb : _InputNotebook | _EvaluationNotebook | _ClipboardNotebook | \
_ButtonNotebook | _MessagesNotebook | _HelpBrowserNotebook] :=
FrontEnd`UnicodeCopy@Evaluate@nb;
FrontEnd`UnicodeCopy[Optional[Automatic, Automatic]] :=
FrontEnd`UnicodeCopy@InputNotebook[];
FrontEnd`UnicodeCopy[s_String] :=
FrontEnd`unicodeCopy[s];
FrontEnd`UnicodeCopy[e_] :=
FrontEnd`UnicodeCopy[Evaluate@ToString[Unevaluated[e], InputForm]];
FrontEnd`UnicodeCopy~SetAttributes~HoldFirst
Then I'll add this to my MenuSetup using the framework I wrote up here and whose up-to-date implementation lives here
FEMenuSetupAdd[
{"Edit", "Copy As", 5},
"Unicode" -> KernelExecute[ToExpression["FrontEnd`UnicodeCopy[]"]],
MenuEvaluator -> Automatic,
System`MenuKey["C", System`Modifiers -> {"Control"}]
]
This now lives under the "Copy As"
menu:
And it can be used by function:
FrontEnd`UnicodeCopy["asdasd\[Alpha]\[Beta]\[Gamma]"]
asdasdαβγ
FrontEnd`UnicodeCopy[Cell["asdasd\[Alpha]\[Beta]\[Gamma]"]]
asdasdαβγ
Or by Control-C:
FrontEnd`UnicodeCopy[Cell["asdasdαβγ"]]
(fixed, now, by doing a more selective replacement from UnicodeCharacters.tr
)
One issue here is that I was a bit over zealous with some replacements when copying from cells and boxes (has to do with what comes out of the ExportPacket
):
(Command-C): "asdasd\\[Alpha]\\[Beta]\\[Gamma]"
(Control-C): "asdasd\α\β\γ"
And just to include the original example:
\[Alpha]\[Beta] +
Mod[\[Delta]\[CapitalPsi], 2\[InvisibleTimes]\[Rho]^2]
becomes:
αβ +
Mod[δΨ, 2ρ^2]
(note how, unfortunately, the added spacing from the cell copy is preserved)