mirror of
https://github.com/WolframResearch/WolframLanguageForJupyter.git
synced 2025-04-15 19:26:04 +00:00
Add rewrites for named character names
This commit is contained in:
parent
f5bcdbe765
commit
5faf681109
84
WolframLanguageForJupyter/Resources/CompletionUtilities.wl
Normal file
84
WolframLanguageForJupyter/Resources/CompletionUtilities.wl
Normal file
@ -0,0 +1,84 @@
|
||||
(************************************************
|
||||
CompletionUtilities.wl
|
||||
*************************************************
|
||||
Description:
|
||||
Utilities for the aiding in the
|
||||
(auto-)completion of Wolfram Language
|
||||
code
|
||||
Symbols defined:
|
||||
rewriteNamedCharacters
|
||||
*************************************************)
|
||||
|
||||
(************************************
|
||||
Get[] guard
|
||||
*************************************)
|
||||
|
||||
If[
|
||||
!TrueQ[WolframLanguageForJupyter`Private`$GotCompletionUtilities],
|
||||
|
||||
WolframLanguageForJupyter`Private`$GotCompletionUtilities = True;
|
||||
|
||||
(************************************
|
||||
load required
|
||||
WolframLanguageForJupyter
|
||||
files
|
||||
*************************************)
|
||||
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "Initialization.wl"}]]; (* unicodeNamedCharactersReplacements,
|
||||
verticalEllipsis *)
|
||||
|
||||
(************************************
|
||||
private symbols
|
||||
*************************************)
|
||||
|
||||
(* begin the private context for WolframLanguageForJupyter *)
|
||||
Begin["`Private`"];
|
||||
|
||||
(************************************
|
||||
utilities for rewriting
|
||||
Wolfram Language code
|
||||
*************************************)
|
||||
|
||||
(* rewrite names (in a code string) into named characters *)
|
||||
rewriteNamedCharacters[codeToAnalyze_?StringQ] :=
|
||||
Module[
|
||||
{codeUsingFullReplacements},
|
||||
codeUsingFullReplacements =
|
||||
StringReplace[
|
||||
codeToAnalyze,
|
||||
Normal @ unicodeNamedCharactersReplacements
|
||||
];
|
||||
If[
|
||||
StringCount[
|
||||
codeUsingFullReplacements,
|
||||
verticalEllipsis | "\\["
|
||||
] != 1,
|
||||
Return[{codeUsingFullReplacements}];
|
||||
];
|
||||
Return[
|
||||
Flatten[
|
||||
StringCases[
|
||||
codeUsingFullReplacements,
|
||||
before___ ~~ name : ((verticalEllipsis | "\\[") ~~ rest__ ~~ EndOfString) :>
|
||||
(
|
||||
(StringJoin[before, #1] &) /@
|
||||
Values[
|
||||
KeySelect[
|
||||
unicodeNamedCharactersReplacements,
|
||||
StringMatchQ[#1, name ~~ ___] &
|
||||
]
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
||||
];
|
||||
];
|
||||
|
||||
(* end the private context for WolframLanguageForJupyter *)
|
||||
End[]; (* `Private` *)
|
||||
|
||||
(************************************
|
||||
Get[] guard
|
||||
*************************************)
|
||||
|
||||
] (* WolframLanguageForJupyter`Private`$GotCompletionUtilities *)
|
@ -16,6 +16,8 @@ Symbols defined:
|
||||
keyString,
|
||||
baseString,
|
||||
heartbeatString,
|
||||
verticalEllipsis,
|
||||
unicodeNamedCharactersReplacements,
|
||||
ioPubString,
|
||||
controlString,
|
||||
inputString,
|
||||
@ -61,6 +63,110 @@ If[
|
||||
$Messages = {};
|
||||
$Output = {}; *)
|
||||
|
||||
(************************************
|
||||
discover the named unicode
|
||||
characters and their names
|
||||
*************************************)
|
||||
|
||||
(* the vertical ellipsis character *)
|
||||
verticalEllipsis = FromCharacterCode[8942, "Unicode"];
|
||||
|
||||
(* pre-define the association of names and named characters as empty *)
|
||||
unicodeNamedCharactersReplacements = Association[];
|
||||
|
||||
Block[
|
||||
{
|
||||
(* the absolute file name for "UnicodeCharacters.tr" *)
|
||||
unicodeCharactersTRFileName,
|
||||
|
||||
(* raw data extracted from "UnicodeCharacters.tr" *)
|
||||
charactersAndTheirNames
|
||||
},
|
||||
|
||||
(* attempt to get the full location of "UnicodeCharacters.tr" *)
|
||||
unicodeCharactersTRFileName = UsingFrontEnd[System`Dump`unicodeCharactersTR];
|
||||
|
||||
(* try again if using System`Dump`unicodeCharactersTR does not work *)
|
||||
If[
|
||||
!StringQ[unicodeCharactersTRFileName],
|
||||
unicodeCharactersTRFileName =
|
||||
UsingFrontEnd[
|
||||
ToFileName[
|
||||
FrontEnd`FileName[
|
||||
{
|
||||
$InstallationDirectory,
|
||||
"SystemFiles",
|
||||
"FrontEnd",
|
||||
"TextResources"
|
||||
},
|
||||
"UnicodeCharacters.tr"
|
||||
]
|
||||
]
|
||||
];
|
||||
];
|
||||
|
||||
If[
|
||||
StringQ[unicodeCharactersTRFileName],
|
||||
charactersAndTheirNames =
|
||||
(
|
||||
(* parse the third item of a row (for a named character) into a list *)
|
||||
ReplacePart[
|
||||
#1,
|
||||
3 ->
|
||||
StringCases[
|
||||
(* remove extraneous parentheses *)
|
||||
StringTrim[
|
||||
#1[[3]],
|
||||
"(" | ")"
|
||||
],
|
||||
(* extract the escape sequences for the named character *)
|
||||
Longest[escSeq : (Except[WhitespaceCharacter] ..)] :>
|
||||
StringJoin[verticalEllipsis, StringTrim[escSeq, "$"], verticalEllipsis]
|
||||
]
|
||||
] &
|
||||
) /@
|
||||
(
|
||||
(* parse the rows into their items (where each item is separated by two tabs) *)
|
||||
(StringSplit[#1, "\t\t"] &) /@
|
||||
(
|
||||
(* split unicodeCharactersTRFileName into its lines *)
|
||||
StringSplit[
|
||||
Import[unicodeCharactersTRFileName, "String"],
|
||||
"\n"
|
||||
(* drop the first row *)
|
||||
][[2 ;;]]
|
||||
)
|
||||
);
|
||||
|
||||
(* parse the data into an association of names and the named characters they correspond to *)
|
||||
unicodeNamedCharactersReplacements =
|
||||
(* sort the keys by string length *)
|
||||
KeySort[
|
||||
(* sort the keys in the default manner *)
|
||||
KeySort[
|
||||
(* drop "empty names" *)
|
||||
KeyDrop[
|
||||
(* make an association *)
|
||||
Association[
|
||||
(* create a list of rules of names and named characters *)
|
||||
Thread[
|
||||
Rule[
|
||||
(Prepend[#1[[3]], #1[[2]]]),
|
||||
FromCharacterCode[FromDigits[StringDrop[#1[[1]], 2], 16], "Unicode"]
|
||||
]
|
||||
] & /@ charactersAndTheirNames
|
||||
],
|
||||
{
|
||||
StringJoin[Table[verticalEllipsis, {2}]],
|
||||
"\\[]"
|
||||
}
|
||||
]
|
||||
],
|
||||
(StringLength[#1] < StringLength[#2]) &
|
||||
];
|
||||
];
|
||||
];
|
||||
|
||||
(************************************
|
||||
various important symbols
|
||||
for use by
|
||||
@ -101,13 +207,10 @@ If[
|
||||
$outputSetToTraditionalForm := (Lookup[Options[$Output], FormatType] === TraditionalForm);
|
||||
$outputSetToTeXForm := (Lookup[Options[$Output], FormatType] === TeXForm);
|
||||
$trueFormatType :=
|
||||
Which[
|
||||
If[
|
||||
$outputSetToTraditionalForm,
|
||||
TraditionalForm,
|
||||
$outputSetToTeXForm,
|
||||
TeXForm,
|
||||
True,
|
||||
Identity
|
||||
If[$outputSetToTeXForm, TeXForm, #&]
|
||||
];
|
||||
|
||||
(* obtain details on how to connect to Jupyter, from Jupyter's invocation of "KernelForWolframLanguageForJupyter.wl" *)
|
||||
|
@ -36,7 +36,7 @@ Get[FileNameJoin[{DirectoryName[$InputFileName], "Initialization.wl"}]]; (* init
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "SocketUtilities.wl"}]]; (* sendFrame *)
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "MessagingUtilities.wl"}]]; (* getFrameAssoc, createReplyFrame *)
|
||||
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "RequestHandlers.wl"}]]; (* executeRequestHandler *)
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "RequestHandlers.wl"}]]; (* executeRequestHandler, completeRequestHandler *)
|
||||
|
||||
(************************************
|
||||
private symbols
|
||||
@ -96,6 +96,10 @@ loop[] :=
|
||||
"execute_request",
|
||||
(* executeRequestHandler will read and update loopState *)
|
||||
executeRequestHandler[];,
|
||||
(* use the tab-completion functionality to rewrite named character names *)
|
||||
"complete_request",
|
||||
(* completeRequestHandler will read and update loopState *)
|
||||
completeRequestHandler[];,
|
||||
(* if asking the kernel to shutdown, set doShutdown to True *)
|
||||
"shutdown_request",
|
||||
loopState["replyMsgType"] = "shutdown_reply";
|
||||
|
@ -209,10 +209,7 @@ If[
|
||||
be identical to the string result of an InputForm-wrapped expression itself *)
|
||||
({"&#", ToString[#1], ";"} & /@
|
||||
ToCharacterCode[
|
||||
(* toStringUsingOutput[result] *)
|
||||
Quiet[
|
||||
ToString[If[!isTeXWrapped, $trueFormatType[result], result]]
|
||||
],
|
||||
(* toStringUsingOutput[result] *) ToString[If[!isTeXWrapped, $trueFormatType[result], result]],
|
||||
"Unicode"
|
||||
]),
|
||||
|
||||
|
@ -5,7 +5,8 @@ Description:
|
||||
Handlers for message frames of type
|
||||
"x_request" arriving from Jupyter
|
||||
Symbols defined:
|
||||
executeRequestHandler
|
||||
executeRequestHandler,
|
||||
completeRequestHandler
|
||||
*************************************************)
|
||||
|
||||
(************************************
|
||||
@ -30,7 +31,10 @@ If[
|
||||
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "EvaluationUtilities.wl"}]]; (* simulatedEvaluate *)
|
||||
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "OutputHandlingUtilities.wl"}]]; (* textQ, toOutText, toOutImage *)
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "OutputHandlingUtilities.wl"}]]; (* textQ, toOutText, toOutImage,
|
||||
containsPUAQ *)
|
||||
|
||||
Get[FileNameJoin[{DirectoryName[$InputFileName], "CompletionUtilities.wl"}]]; (* rewriteNamedCharacters *)
|
||||
|
||||
(************************************
|
||||
private symbols
|
||||
@ -69,7 +73,6 @@ If[
|
||||
(* set the content of the reply to information about WolframLanguageForJupyter's execution of the input *)
|
||||
loopState["replyContent"] =
|
||||
ExportString[
|
||||
(* kind of self-explanatory *)
|
||||
Association[
|
||||
"status" -> "ok",
|
||||
"execution_count" -> loopState["executionCount"],
|
||||
@ -278,6 +281,54 @@ If[
|
||||
loopState["executionCount"] += totalResult["ConsumedIndices"];
|
||||
];
|
||||
|
||||
(************************************
|
||||
handler for complete_requests
|
||||
*************************************)
|
||||
|
||||
(* handle complete_request messages frames received on the shell socket *)
|
||||
completeRequestHandler[] :=
|
||||
Module[
|
||||
{
|
||||
(* for storing the code string to offer completion suggestions on *)
|
||||
codeStr
|
||||
},
|
||||
(* get the code string to rewrite the named characters of, ending at the cursor *)
|
||||
codeStr =
|
||||
StringTake[
|
||||
loopState["frameAssoc"]["content"]["code"],
|
||||
{
|
||||
1,
|
||||
loopState["frameAssoc"]["content"]["cursor_pos"]
|
||||
}
|
||||
];
|
||||
(* set the appropriate reply type *)
|
||||
loopState["replyMsgType"] = "complete_reply";
|
||||
(* set the content of the reply to a list of rewrites for any named characters in the code string *)
|
||||
loopState["replyContent"] =
|
||||
ByteArrayToString[
|
||||
ExportByteArray[
|
||||
Association[
|
||||
"matches" ->
|
||||
DeleteDuplicates[
|
||||
Prepend[
|
||||
Select[
|
||||
rewriteNamedCharacters[codeStr],
|
||||
(!containsPUAQ[#1])&
|
||||
],
|
||||
codeStr
|
||||
]
|
||||
],
|
||||
"cursor_start" -> 0,
|
||||
"cursor_end" -> StringLength[codeStr],
|
||||
"metadata" -> {},
|
||||
"status" -> "ok"
|
||||
],
|
||||
"JSON",
|
||||
"Compact" -> True
|
||||
]
|
||||
];
|
||||
];
|
||||
|
||||
(* end the private context for WolframLanguageForJupyter *)
|
||||
End[]; (* `Private` *)
|
||||
|
||||
|
50
extras/custom.js
Normal file
50
extras/custom.js
Normal file
@ -0,0 +1,50 @@
|
||||
/* (adapted) from https://stackoverflow.com/a/19961519 by Erik Aigner */
|
||||
HTMLTextAreaElement.prototype.insertAtCaret = function (text) {
|
||||
text = text || '';
|
||||
if(document.selection) {
|
||||
// IE
|
||||
this.focus();
|
||||
var sel = document.selection.createRange();
|
||||
sel.text = text;
|
||||
}
|
||||
else if(this.selectionStart || this.selectionStart === 0) {
|
||||
// Others
|
||||
var startPos = this.selectionStart;
|
||||
var endPos = this.selectionEnd;
|
||||
this.value = this.value.substring(0, startPos) + text + this.value.substring(endPos, this.value.length);
|
||||
this.selectionStart = startPos + text.length;
|
||||
this.selectionEnd = startPos + text.length;
|
||||
}
|
||||
else {
|
||||
this.value += text;
|
||||
}
|
||||
};
|
||||
|
||||
/* (adapted) from https://stackoverflow.com/a/51114347 by bambam */
|
||||
function redirectEsc(event) {
|
||||
if(event.which == 27)
|
||||
{
|
||||
event.target.insertAtCaret(
|
||||
/* the vertical ellipsis character */
|
||||
String.fromCharCode(8942)
|
||||
);
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
/* (adapted) from https://stackoverflow.com/a/51114347 by bambam */
|
||||
var observer = new MutationObserver(function(mutations) {
|
||||
|
||||
Array.from(
|
||||
document.querySelectorAll('.input_area')
|
||||
).forEach(
|
||||
textarea =>
|
||||
{
|
||||
textarea.removeEventListener('keydown', redirectEsc);
|
||||
textarea.addEventListener('keydown', redirectEsc);
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
observer.observe(document, {childList:true, subtree:true});
|
Loading…
x
Reference in New Issue
Block a user