mirror of
https://github.com/WolframResearch/WolframLanguageForJupyter.git
synced 2025-04-16 11:46:05 +00:00
Merge pull request #46 from WolframResearch/feature/add-hooks-and-improve-multi-expression-input-handling
Make common idioms for setting a persistent format type for output effective
This commit is contained in:
commit
75fc9c238d
@ -27,14 +27,14 @@ If[
|
||||
files
|
||||
*************************************)
|
||||
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "Initialization.wl"}]]; (* loopState *)
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "Initialization.wl"}]]; (* loopState, applyHook, $canUseFrontEnd *)
|
||||
|
||||
(************************************
|
||||
wrapper for interacting
|
||||
with the cloud
|
||||
*************************************)
|
||||
|
||||
(* Interact is wrapper, open to the user, for asking that the result of the evaluation
|
||||
(* Interact is a wrapper, open to the user, for asking that the result of the evaluation
|
||||
be displayed as an embedded cloud object that can be interacted with *)
|
||||
(* set Interact to not evaluate its arguments *)
|
||||
SetAttributes[Interact, HoldAll];
|
||||
@ -46,6 +46,24 @@ If[
|
||||
(* begin the private context for WolframLanguageForJupyter *)
|
||||
Begin["`Private`"];
|
||||
|
||||
(************************************
|
||||
helper utilities for
|
||||
diagnosing and removing
|
||||
command wrappers
|
||||
(e.g., Interact[])
|
||||
*************************************)
|
||||
|
||||
(* check if expr is wrapped with Interact *)
|
||||
interactQ[expr___] := MatchQ[expr, Hold[Interact[___]]];
|
||||
SetAttributes[interactQ, HoldAll];
|
||||
|
||||
(* remove any Interact wrappers,
|
||||
apply $Pre,
|
||||
and bring in the Front End for the evaluation of expr *)
|
||||
uninteract[Interact[expr_]] := UsingFrontEnd[applyHook[$Pre, expr]];
|
||||
uninteract[expr_] := UsingFrontEnd[applyHook[$Pre, expr]];
|
||||
SetAttributes[uninteract, HoldAll];
|
||||
|
||||
(************************************
|
||||
version of Print that
|
||||
sends output to Jupyter
|
||||
@ -78,21 +96,143 @@ If[
|
||||
more easily intercept
|
||||
*************************************)
|
||||
|
||||
Unprotect[Throw];
|
||||
Throw[value_] :=
|
||||
Throw[
|
||||
value,
|
||||
WolframLanguageForJupyter`Private`$ThrowLabel
|
||||
];
|
||||
Protect[Throw];
|
||||
Unprotect[Throw];
|
||||
Throw[value_] :=
|
||||
Throw[
|
||||
value,
|
||||
WolframLanguageForJupyter`Private`$ThrowLabel
|
||||
];
|
||||
Protect[Throw];
|
||||
|
||||
Unprotect[Catch];
|
||||
Catch[expr_] :=
|
||||
Catch[
|
||||
expr,
|
||||
WolframLanguageForJupyter`Private`$ThrowLabel
|
||||
];
|
||||
Protect[Catch];
|
||||
Unprotect[Catch];
|
||||
Catch[expr_] :=
|
||||
Catch[
|
||||
expr,
|
||||
WolframLanguageForJupyter`Private`$ThrowLabel
|
||||
];
|
||||
Protect[Catch];
|
||||
|
||||
(************************************
|
||||
utilities for splitting
|
||||
input by Wolfram Language
|
||||
expression
|
||||
*************************************)
|
||||
|
||||
(* start parsing the input, and return an Association for keeping track of said parse *)
|
||||
startParsingInput[codeStr_] :=
|
||||
Module[
|
||||
{
|
||||
(* an Association for keeping track of the parse containing:
|
||||
"LinesLeft" - the lines of input left to be processed,
|
||||
"ExpressionsParsed" - the number of expressions parsed out so far,
|
||||
"ExpressionString" - an expression string generated by a pass of the parser,
|
||||
"SyntaxError" - a flag for if the expression string contains a syntax error,
|
||||
"ParseDone" - a flag for if the parse is done *)
|
||||
parseTrackerInit
|
||||
},
|
||||
|
||||
(* initialize parseTrackerInit *)
|
||||
parseTrackerInit = Association[];
|
||||
|
||||
(* add the annotated lines left, and the defaults *)
|
||||
AssociateTo[
|
||||
parseTrackerInit,
|
||||
{
|
||||
"LinesLeft" -> StringSplit[StringJoin[" ", codeStr], "\r\n" | "\n"],
|
||||
"ExpressionsParsed" -> 0,
|
||||
"ExpressionString" -> " ",
|
||||
"SyntaxError" -> False,
|
||||
"ParseDone" -> False
|
||||
}
|
||||
];
|
||||
|
||||
(* return the parse tracker *)
|
||||
Return[parseTrackerInit];
|
||||
];
|
||||
|
||||
(* parse out an expression *)
|
||||
parseIntoExpr[tracker_] :=
|
||||
Module[
|
||||
{
|
||||
(* the parse tracker to be updated with the results of this parse *)
|
||||
newTracker,
|
||||
|
||||
(* for storing the lines of input left to be processed, annotated with their line numbers *)
|
||||
annotatedLinesLeft,
|
||||
|
||||
(* for storing the current line position when moving through annotatedLinesLeft *)
|
||||
linePos,
|
||||
|
||||
(* for storing the result *)
|
||||
result,
|
||||
|
||||
(* for storing the concatenation of some lines of input *)
|
||||
exprStr
|
||||
},
|
||||
|
||||
(* initialize the parse tracker to be updated *)
|
||||
newTracker = tracker;
|
||||
|
||||
(* if there are no lines of input left to be processed,
|
||||
set newTracker["ParseDone"] to True and return the updated tracker *)
|
||||
If[Length[newTracker["LinesLeft"]] == 0,
|
||||
newTracker["ParseDone"] = True;
|
||||
(* return the updated tracker *)
|
||||
Return[newTracker];
|
||||
];
|
||||
|
||||
(* annotate the lines of input left to be processed with their line numbers *)
|
||||
annotatedLinesLeft =
|
||||
Partition[
|
||||
Riffle[
|
||||
newTracker["LinesLeft"],
|
||||
Range[Length[newTracker["LinesLeft"]]]
|
||||
],
|
||||
2
|
||||
];
|
||||
|
||||
(* start with a line position of 1 *)
|
||||
linePos = 1;
|
||||
result =
|
||||
(* fold until an expression is built, or there are no lines of input left *)
|
||||
Fold[
|
||||
(
|
||||
(* save the new line position *)
|
||||
linePos = Last[{##}][[2]] + 1;
|
||||
(* save the new expression string with a new line of input *)
|
||||
exprStr = StringJoin[First /@ {##}];
|
||||
(* if exprStr is syntactically correct, it represents a complete expression,
|
||||
and folding can be stopped *)
|
||||
If[SyntaxQ[exprStr],
|
||||
(* return the complete expression string *)
|
||||
Return[{exprStr, linePos, False}, Fold];,
|
||||
(* exprStr may be incomplete, keep going if possible *)
|
||||
{exprStr, linePos, True}
|
||||
]
|
||||
) &,
|
||||
(* starting value *)
|
||||
{"", -1, False},
|
||||
(* the annotated lines of input left to be processed *)
|
||||
annotatedLinesLeft
|
||||
];
|
||||
|
||||
AssociateTo[
|
||||
newTracker,
|
||||
{
|
||||
(* discard the lines of input processed *)
|
||||
"LinesLeft" -> newTracker["LinesLeft"][[result[[2]];;]],
|
||||
(* increment ExpressionsParsed *)
|
||||
"ExpressionsParsed" -> newTracker["ExpressionsParsed"] + 1,
|
||||
(* save the result generated *)
|
||||
"ExpressionString" -> result[[1]],
|
||||
(* save the syntactic correctness of the result *)
|
||||
"SyntaxError" -> result[[3]]
|
||||
}
|
||||
];
|
||||
|
||||
(* return the updated tracker *)
|
||||
Return[newTracker];
|
||||
];
|
||||
|
||||
(************************************
|
||||
main evaluation command
|
||||
@ -100,7 +240,7 @@ Protect[Catch];
|
||||
|
||||
(* evaluate input, and capture required information such as generated messages *)
|
||||
(* TODO: review other method: evaluate input through WSTP in another kernel *)
|
||||
simulatedEvaluate[expr___] :=
|
||||
simulatedEvaluate[codeStr_] :=
|
||||
Module[
|
||||
{
|
||||
(* for saving $Messages before changing it *)
|
||||
@ -110,11 +250,14 @@ Protect[Catch];
|
||||
(* the string form of the generated messages, obtained from stream *)
|
||||
generatedMessages,
|
||||
|
||||
(* the length of expr *)
|
||||
exprLength,
|
||||
(* for keeping track of parsing the input into separate expressions *)
|
||||
parseTracker,
|
||||
|
||||
(* a new version of expr that simulates lines *)
|
||||
exprWithLines,
|
||||
(* a raw evaluation result to be built, before Nulls have been removed *)
|
||||
rawEvaluationResult,
|
||||
|
||||
(* for storing a single expression string *)
|
||||
exprStr,
|
||||
|
||||
(* the result of evaluation *)
|
||||
evaluationResult,
|
||||
@ -130,7 +273,8 @@ Protect[Catch];
|
||||
the result of evaluation ("EvaluationResult"),
|
||||
indices of the output lines of the result ("EvaluationResultOutputLineIndices"),
|
||||
the total number of indices consumed by this evaluation ("ConsumedIndices"),
|
||||
generated messages ("GeneratedMessages")
|
||||
generated messages ("GeneratedMessages"),
|
||||
if the input was one expression and wrapped with Interact[] ("InteractStatus")
|
||||
*)
|
||||
totalResult
|
||||
},
|
||||
@ -149,80 +293,116 @@ Protect[Catch];
|
||||
(* set $Messages to use the new stream *)
|
||||
$Messages = {stream};
|
||||
|
||||
(* obtain the length of expr *)
|
||||
exprLength = Length[Unevaluated[{expr}]];
|
||||
|
||||
(* predefine the In[n] for the input *)
|
||||
Unprotect[In];
|
||||
(* for every line input in the input, set In[n], using placeholders *)
|
||||
Table[
|
||||
ReleaseHold[
|
||||
(* replace index with the number of the input line,
|
||||
and replace placeHolder with the element in expr corresponding to inIndex'th input line using Extract *)
|
||||
Replace[
|
||||
Hold[
|
||||
SetDelayed[
|
||||
In[index],
|
||||
ReleaseHold[placeHolder]
|
||||
]
|
||||
],
|
||||
{
|
||||
index -> loopState["executionCount"] + inIndex - 1,
|
||||
placeHolder ->
|
||||
Extract[
|
||||
Hold[{expr}],
|
||||
{1, inIndex},
|
||||
Hold
|
||||
]
|
||||
},
|
||||
(* the level of index and placeHolder *)
|
||||
{3}
|
||||
]
|
||||
];,
|
||||
{inIndex, 1, exprLength}
|
||||
];
|
||||
Protect[In];
|
||||
|
||||
(* create a new version of expr that simulates lines *)
|
||||
exprWithLines =
|
||||
Table[
|
||||
$Line++;
|
||||
(* catch any Throws that were not handled by the input itself *)
|
||||
intermediate =
|
||||
Catch[
|
||||
ReleaseHold[
|
||||
Extract[
|
||||
Hold[{expr}],
|
||||
{1, inIndex},
|
||||
Hold
|
||||
]
|
||||
],
|
||||
_,
|
||||
WolframLanguageForJupyter`Private`$ThrowNoCatch[#1, #2] &
|
||||
];
|
||||
If[
|
||||
Head[intermediate] =!= WolframLanguageForJupyter`Private`$ThrowNoCatch,
|
||||
(* if we did not catch anything, set result to intermediate *)
|
||||
result = intermediate;,
|
||||
(* if we did catch something, obtain the correct held form of the Throw to return, and message *)
|
||||
If[intermediate[[2]] === WolframLanguageForJupyter`Private`$ThrowLabel,
|
||||
result = Replace[Hold[Throw[placeHolder]], {placeHolder -> intermediate[[1]]}, {2}];,
|
||||
result = Replace[Hold[Throw[placeHolder1, placeHolder2]], {placeHolder1 -> intermediate[[1]], placeHolder2 -> intermediate[[2]]}, {2}];
|
||||
];
|
||||
(* message *)
|
||||
Message[
|
||||
Throw::nocatch,
|
||||
StringTrim[ToString[result, OutputForm], "Hold[" | "]"]
|
||||
];
|
||||
];
|
||||
(* the overall result *)
|
||||
result
|
||||
,
|
||||
{inIndex, 1, exprLength}
|
||||
(* start the parse of the input *)
|
||||
parseTracker =
|
||||
startParsingInput[
|
||||
(* apply $PreRead to the input *)
|
||||
applyHook[$PreRead, codeStr]
|
||||
];
|
||||
|
||||
(* initialize rawEvaluationResult to an empty list *)
|
||||
rawEvaluationResult = {};
|
||||
(* while the parse is not done, keep evaluating expressions in the input *)
|
||||
While[
|
||||
(
|
||||
parseTracker = parseIntoExpr[parseTracker];
|
||||
!parseTracker["ParseDone"]
|
||||
),
|
||||
|
||||
(* save the current expression string *)
|
||||
exprStr = parseTracker["ExpressionString"];
|
||||
|
||||
If[
|
||||
!parseTracker["SyntaxError"],
|
||||
(* increment $Line *)
|
||||
$Line++;
|
||||
(* set InString *)
|
||||
Unprotect[InString];
|
||||
InString[
|
||||
loopState["executionCount"] + parseTracker["ExpressionsParsed"] - 1
|
||||
] = exprStr;
|
||||
Protect[InString];
|
||||
];
|
||||
|
||||
(* catch any Throws that were not handled by the input itself *)
|
||||
intermediate =
|
||||
Catch[
|
||||
(* evaluate the expression string *)
|
||||
ToExpression[
|
||||
exprStr,
|
||||
InputForm,
|
||||
uninteract
|
||||
],
|
||||
_,
|
||||
WolframLanguageForJupyter`Private`$ThrowNoCatch[#1, #2] &
|
||||
];
|
||||
|
||||
If[
|
||||
Head[intermediate] =!= WolframLanguageForJupyter`Private`$ThrowNoCatch,
|
||||
(* if we did not catch anything, set result to intermediate *)
|
||||
result = intermediate;,
|
||||
(* if we did catch something, obtain the correct held form of the Throw to return, and message *)
|
||||
If[intermediate[[2]] === WolframLanguageForJupyter`Private`$ThrowLabel,
|
||||
result = Replace[Hold[Throw[placeHolder]], {placeHolder -> intermediate[[1]]}, {2}];,
|
||||
result = Replace[Hold[Throw[placeHolder1, placeHolder2]], {placeHolder1 -> intermediate[[1]], placeHolder2 -> intermediate[[2]]}, {2}];
|
||||
];
|
||||
(* message *)
|
||||
Message[
|
||||
Throw::nocatch,
|
||||
StringTrim[ToString[result, OutputForm], "Hold[" | "]"]
|
||||
];
|
||||
];
|
||||
|
||||
If[
|
||||
!parseTracker["SyntaxError"],
|
||||
(* set the In[] for this expression *)
|
||||
Unprotect[In];
|
||||
Replace[
|
||||
ToExpression[exprStr, InputForm, Hold],
|
||||
Hold[held_] :>
|
||||
SetDelayed[
|
||||
In[
|
||||
loopState["executionCount"] + parseTracker["ExpressionsParsed"] - 1
|
||||
],
|
||||
held
|
||||
]
|
||||
];
|
||||
Protect[In];
|
||||
(* apply $Post to the result *)
|
||||
result = applyHook[$Post, result];
|
||||
(* set the Out[] for this expression *)
|
||||
Unprotect[Out];
|
||||
Out[loopState["executionCount"] + parseTracker["ExpressionsParsed"] - 1] = result;
|
||||
Protect[Out];
|
||||
(* create the overall result with $PrePrint *)
|
||||
result = applyHook[$PrePrint, result];
|
||||
,
|
||||
(* syntax error *)
|
||||
result = $Failed;
|
||||
];
|
||||
|
||||
(* save the result in rawEvaluationResult *)
|
||||
AppendTo[rawEvaluationResult, result];
|
||||
];
|
||||
|
||||
(* add the Interact[] wrapper status of the input *)
|
||||
AssociateTo[
|
||||
totalResult,
|
||||
"InteractStatus" ->
|
||||
(
|
||||
(* if the input has no syntax errors,
|
||||
is made up of only one expression,
|
||||
and is wrapped with Interact[],
|
||||
mark "InteractStatus" as True
|
||||
*)
|
||||
parseTracker["ExpressionsParsed"] == 1 &&
|
||||
!parseTracker["SyntaxError"] &&
|
||||
(interactQ @ ToExpression[parseTracker["ExpressionString"], InputForm, Hold])
|
||||
)
|
||||
];
|
||||
|
||||
(* evaluate the input from Jupyter, removing Nulls from the Output *)
|
||||
evaluationResult = DeleteCases[exprWithLines, Null];
|
||||
evaluationResult = DeleteCases[rawEvaluationResult, Null];
|
||||
|
||||
(* preserve the locations of the output lines with respect to the Nulls *)
|
||||
AssociateTo[
|
||||
@ -230,19 +410,10 @@ Protect[Catch];
|
||||
"EvaluationResultOutputLineIndices" ->
|
||||
(
|
||||
(loopState["executionCount"] - 1) +
|
||||
Flatten[Position[exprWithLines, Except[Null], {1}, Heads -> False]]
|
||||
Flatten[Position[rawEvaluationResult, Except[Null], {1}, Heads -> False]]
|
||||
)
|
||||
];
|
||||
|
||||
(* set Out[n] *)
|
||||
Unprotect[Out];
|
||||
(* for every output line, set the Out with the corresponding index *)
|
||||
Table[
|
||||
Out[loopState["executionCount"] + outIndex - 1] = exprWithLines[[outIndex]];,
|
||||
{outIndex, 1, Length[exprWithLines]}
|
||||
];
|
||||
Protect[Out];
|
||||
|
||||
(* restore $Messages *)
|
||||
$Messages = oldMessages;
|
||||
|
||||
@ -254,7 +425,13 @@ Protect[Catch];
|
||||
(* add the total number of indices consumed by this evaluation *)
|
||||
AssociateTo[
|
||||
totalResult,
|
||||
"ConsumedIndices" -> exprLength
|
||||
"ConsumedIndices" ->
|
||||
(* if parseTracker["SyntaxError"] is true, one less index was consumed *)
|
||||
If[
|
||||
parseTracker["SyntaxError"],
|
||||
parseTracker["ExpressionsParsed"] - 1,
|
||||
parseTracker["ExpressionsParsed"]
|
||||
]
|
||||
];
|
||||
|
||||
(* add the result of the evaluation and any generated messages to totalResult *)
|
||||
|
@ -5,6 +5,11 @@ Description:
|
||||
Initialization for
|
||||
WolframLanguageForJupyter
|
||||
Symbols defined:
|
||||
loopState,
|
||||
applyHook,
|
||||
$canUseFrontEnd,
|
||||
$outputSetToTraditionalForm,
|
||||
$trueFormatType,
|
||||
connectionAssoc,
|
||||
bannerWarning,
|
||||
keyString,
|
||||
@ -84,6 +89,17 @@ If[
|
||||
"printFunction" -> Function[#;]
|
||||
];
|
||||
|
||||
(* helper utility for applying hooks if they are set *)
|
||||
applyHook[hook_, value_] /; Length[OwnValues[hook]] != 0 := hook[value];
|
||||
applyHook[hook_, value_] := value;
|
||||
Attributes[applyHook] := HoldAll;
|
||||
|
||||
(* can we use the Front End? *)
|
||||
$canUseFrontEnd := (UsingFrontEnd[$FrontEnd] =!= Null);
|
||||
|
||||
$outputSetToTraditionalForm := (Lookup[Options[$Output], FormatType] === TraditionalForm);
|
||||
$trueFormatType := If[$outputSetToTraditionalForm, TraditionalForm, #&];
|
||||
|
||||
(* obtain details on how to connect to Jupyter, from Jupyter's invocation of "KernelForWolframLanguageForJupyter.wl" *)
|
||||
connectionAssoc = ToString /@ Association[Import[$CommandLine[[4]], "JSON"]];
|
||||
|
||||
|
@ -6,7 +6,7 @@ Description:
|
||||
Entry point for WolframLanguageForJupyter
|
||||
kernels started by Jupyter
|
||||
Symbols defined:
|
||||
loopState
|
||||
loop
|
||||
*************************************************)
|
||||
|
||||
(************************************
|
||||
@ -180,6 +180,7 @@ End[]; (* `Private` *)
|
||||
|
||||
(* end the WolframLanguageForJupyter package *)
|
||||
EndPackage[]; (* WolframLanguageForJupyter` *)
|
||||
(* $ContextPath = DeleteCases[$ContextPath, "WolframLanguageForJupyter`"]; *)
|
||||
|
||||
(************************************
|
||||
evaluate loop[]
|
||||
|
@ -22,6 +22,15 @@ If[
|
||||
|
||||
WolframLanguageForJupyter`Private`$GotOutputHandlingUtilities = True;
|
||||
|
||||
(************************************
|
||||
load required
|
||||
WolframLanguageForJupyter
|
||||
files
|
||||
*************************************)
|
||||
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "Initialization.wl"}]]; (* $canUseFrontEnd, $outputSetToTraditionalForm
|
||||
$trueFormatType *)
|
||||
|
||||
(************************************
|
||||
private symbols
|
||||
*************************************)
|
||||
@ -29,18 +38,40 @@ If[
|
||||
(* begin the private context for WolframLanguageForJupyter *)
|
||||
Begin["`Private`"];
|
||||
|
||||
(************************************
|
||||
helper utility for converting
|
||||
an expression into a
|
||||
textual form
|
||||
*************************************)
|
||||
|
||||
(* convert an expression into a textual form,
|
||||
using as much of the options already set for $Output as possible for ToString *)
|
||||
toStringUsingOutput[expr_] :=
|
||||
ToString[
|
||||
expr,
|
||||
Sequence @@
|
||||
Cases[
|
||||
Options[$Output],
|
||||
Verbatim[Rule][opt_, val_] /;
|
||||
MemberQ[
|
||||
Keys[Options[ToString]],
|
||||
opt
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
(************************************
|
||||
helper utility for determining
|
||||
if a result should be
|
||||
displayed as text or an image
|
||||
*************************************)
|
||||
|
||||
(* check if a string contains any private use area characters *)
|
||||
containsPUAQ[str_] :=
|
||||
AnyTrue[
|
||||
ToCharacterCode[str, "Unicode"],
|
||||
(57344 <= #1 <= 63743 || 983040 <= #1 <= 1048575 || 1048576 <= #1 <= 1114111) &
|
||||
];
|
||||
(* check if a string contains any private use area characters *)
|
||||
containsPUAQ[str_] :=
|
||||
AnyTrue[
|
||||
ToCharacterCode[str, "Unicode"],
|
||||
(57344 <= #1 <= 63743 || 983040 <= #1 <= 1048575 || 1048576 <= #1 <= 1114111) &
|
||||
];
|
||||
|
||||
(************************************
|
||||
utility for determining if a
|
||||
@ -61,16 +92,26 @@ containsPUAQ[str_] :=
|
||||
|
||||
(* if we cannot use the frontend, use text *)
|
||||
If[
|
||||
UsingFrontEnd[$FrontEnd] === Null,
|
||||
!$canUseFrontEnd,
|
||||
Return[True];
|
||||
];
|
||||
|
||||
(* if the expression is wrapped with InputForm or OutputForm, automatically format as text *)
|
||||
(* save the head of the expression *)
|
||||
exprHead = Head[expr];
|
||||
|
||||
(* if the expression is wrapped with InputForm or OutputForm,
|
||||
automatically format as text *)
|
||||
If[exprHead === InputForm || exprHead === OutputForm,
|
||||
Return[True]
|
||||
];
|
||||
|
||||
(* if the FormatType of $Output is set to TraditionalForm,
|
||||
or if the expression is wrapped with TraditionalForm,
|
||||
do not use text *)
|
||||
If[$outputSetToTraditionalForm || exprHead === TraditionalForm,
|
||||
Return[False]
|
||||
];
|
||||
|
||||
(* breakdown expr into atomic objects organized by their Head *)
|
||||
pObjects =
|
||||
GroupBy[
|
||||
@ -103,10 +144,10 @@ containsPUAQ[str_] :=
|
||||
If[
|
||||
ContainsOnly[Keys[pObjects], {Integer, Real, String, Symbol}],
|
||||
Return[
|
||||
AllTrue[
|
||||
Lookup[pObjects, String, {}],
|
||||
(!containsPUAQ[ReleaseHold[#1]]) &
|
||||
] &&
|
||||
AllTrue[
|
||||
Lookup[pObjects, String, {}],
|
||||
(!containsPUAQ[ReleaseHold[#1]]) &
|
||||
] &&
|
||||
AllTrue[
|
||||
Lookup[pObjects, Symbol, {}],
|
||||
(
|
||||
@ -140,7 +181,12 @@ containsPUAQ[str_] :=
|
||||
(* the textual form of the result *)
|
||||
(* NOTE: the OutputForm (which ToString uses) of any expressions wrapped with, say, InputForm should
|
||||
be identical to the string result of an InputForm-wrapped expression itself *)
|
||||
StringJoin[{"&#", ToString[#1], ";"} & /@ ToCharacterCode[ToString[result], "Unicode"]],
|
||||
StringJoin[{"&#", ToString[#1], ";"} & /@
|
||||
ToCharacterCode[
|
||||
(* toStringUsingOutput[result] *) ToString[result],
|
||||
"Unicode"
|
||||
]
|
||||
],
|
||||
(* end the element *)
|
||||
"</pre>"
|
||||
];
|
||||
@ -153,7 +199,8 @@ containsPUAQ[str_] :=
|
||||
(* the rasterized form of the result, converted to base64 *)
|
||||
BaseEncode[
|
||||
UsingFrontEnd[ExportByteArray[
|
||||
If[Head[result] === Manipulate, result, Rasterize[result]],
|
||||
(If[Head[#1] === Manipulate, #1, Rasterize[#1]] &) @
|
||||
$trueFormatType[result],
|
||||
"PNG"
|
||||
]]
|
||||
],
|
||||
|
@ -5,8 +5,6 @@ Description:
|
||||
Handlers for message frames of type
|
||||
"x_request" arriving from Jupyter
|
||||
Symbols defined:
|
||||
interactQ,
|
||||
uninteract,
|
||||
executeRequestHandler
|
||||
*************************************************)
|
||||
|
||||
@ -41,25 +39,6 @@ If[
|
||||
(* begin the private context for WolframLanguageForJupyter *)
|
||||
Begin["`Private`"];
|
||||
|
||||
(************************************
|
||||
helper utilities for the
|
||||
handler for
|
||||
execute_requests for
|
||||
diagnosing command
|
||||
wrappers (Interact[___])
|
||||
and redirecting to
|
||||
simulatedEvaluate
|
||||
*************************************)
|
||||
|
||||
(* check if expr is wrapped with Interact *)
|
||||
interactQ[expr___] := MatchQ[expr, Hold[Interact[___]]];
|
||||
SetAttributes[interactQ, HoldAll];
|
||||
|
||||
(* remove any Interact wrappers, and evaluate expr *)
|
||||
uninteract[Interact[expr___]] := simulatedEvaluate[expr];
|
||||
uninteract[expr___] := simulatedEvaluate[expr];
|
||||
SetAttributes[uninteract, HoldAll];
|
||||
|
||||
(************************************
|
||||
handler for execute_requests
|
||||
*************************************)
|
||||
@ -131,30 +110,11 @@ If[
|
||||
);
|
||||
|
||||
(* evaluate the input, and store the total result in totalResult *)
|
||||
totalResult = ToExpression[loopState["frameAssoc"]["content"]["code"], InputForm, uninteract];
|
||||
totalResult = simulatedEvaluate[loopState["frameAssoc"]["content"]["code"]];
|
||||
|
||||
(* restore printFunction to empty *)
|
||||
loopState["printFunction"] = Function[#;];
|
||||
|
||||
(* if totalResult fails (most likely due to a syntax error in the input),
|
||||
build a failure object form of totalResult, and use any messages generated by ToExpression *)
|
||||
If[FailureQ[totalResult],
|
||||
totalResult = Association[];
|
||||
(* failed object settings: *)
|
||||
totalResult["EvaluationResult"] = {$Failed};
|
||||
totalResult["EvaluationResultOutputLineIndices"] = {loopState["executionCount"]};
|
||||
(* when a failure like this occurs, do not increment loopState["executionCount"] *)
|
||||
totalResult["ConsumedIndices"] = 0;
|
||||
(* capture any messages generated by ToExpression *)
|
||||
totalResult["GeneratedMessages"] =
|
||||
StringJoin[
|
||||
EvaluationData[
|
||||
ToExpression[loopState["frameAssoc"]["content"]["code"], InputForm]
|
||||
]["MessagesText"]
|
||||
];
|
||||
];
|
||||
|
||||
|
||||
(* generate an HTML form of the message text *)
|
||||
errorMessage =
|
||||
If[StringLength[totalResult["GeneratedMessages"]] == 0,
|
||||
@ -185,8 +145,9 @@ If[
|
||||
|
||||
(* format output as purely text, image, or cloud interface *)
|
||||
If[
|
||||
(* interactQ checks if the input was wrapped with Interact, which is used when the output should be displayed as an embedded cloud object *)
|
||||
TrueQ[interactQ[ToExpression[loopState["frameAssoc"]["content"]["code"], InputForm, Hold]]] &&
|
||||
(* check if the input was wrapped with Interact,
|
||||
which is used when the output should be displayed as an embedded cloud object *)
|
||||
TrueQ[totalResult["InteractStatus"]] &&
|
||||
(* check if we are logged into the Cloud *)
|
||||
$CloudConnected,
|
||||
(* prepare the content for a reply message frame to be sent on the IO Publish socket *)
|
||||
|
Loading…
x
Reference in New Issue
Block a user