Here's a partial implementation, working from the DownValues
and friends:
We start with a bunch of DownValues
cleaning:
$usageTypeReplacements =
{
Integer :> int,
Real :> float,
String :> str,
List :> list,
Association :> assoc,
Symbol :> sym
};
$usageSymNames =
{
Alternatives -> alt,
PatternTest -> test,
Condition -> cond,
s_Symbol :>
RuleCondition[
Symbol@
ToLowerCase[StringTake[SymbolName[Unevaluated@s], UpTo[3]]],
True
]
};
symbolUsageReplacementPattern[names_, conts_] :=
s_Symbol?(
GeneralUtilities`HoldFunction[
! MatchQ[Context[#], conts] &&
!
MemberQ[$ContextPath, Context[#]] &&
!
KeyMemberQ[names, SymbolName@Unevaluated[#]]
]
) :>
RuleCondition[
ToExpression@
Evaluate[$Context <>
With[{name = SymbolName@Unevaluated[s]},
If[StringLength@StringTrim[name, "$"] > 0,
StringTrim[name, "$"],
name
]
]
],
True];
usagePatternReplace[
vals_,
reps_: {}
] :=
With[{
names = AssociationMap[Null &, {}(*Names[]*)],
conts =
Alternatives @@ {"System`", "FrontEnd`", "PacletManager`",
"Internal`"}
},
Replace[
Replace[
#,
{
Verbatim[HoldPattern][a___] :> a
},
{2, 10}
],
Join[$usageTypeReplacements, $usageSymNames],
Depth[#]
] &@
ReplaceRepeated[
FixedPoint[
Replace[
#,
{
Verbatim[Pattern][_, e_] :>
e,
Verbatim[HoldPattern][Verbatim[Pattern][_, e_]] :>
HoldPattern[e],
Verbatim[HoldPattern][Verbatim[HoldPattern][e_]] :>
HoldPattern[e]
},
1
] &,
vals
],
Flatten@{
reps,
Verbatim[PatternTest][_, ColorQ] :>
color,
Verbatim[PatternTest][_, ImageQ] :>
im,
Verbatim[Optional][name_, _] :>
name,
Verbatim[Pattern][_, _OptionsPattern] :>
Sequence[],
Verbatim[Pattern][name_, _] :>
name,
Verbatim[PatternTest][p_, _] :>
p,
Verbatim[Condition][p_, _] :>
p,
Verbatim[Alternatives][a_, ___][___] |
Verbatim[Alternatives][a_, ___][___][___] |
Verbatim[Alternatives][a_, ___][___][___][___] |
Verbatim[Alternatives][a_, ___][___][___][___][___] |
Verbatim[Alternatives][a_, ___][___][___][___][___][___] :>
a,
Verbatim[Alternatives][a_, ___] :>
RuleCondition[
Blank[
Replace[Hold@a,
{
Hold[p : Verbatim[HoldPattern][_]] :>
p,
Hold[e_[___]] :> e,
_ :> a
}
]
],
True
],
Verbatim[Verbatim][p_][a___] :>
p,
Verbatim[Blank][] :>
expr,
Verbatim[Blank][
t : Alternatives @@ Keys[$usageTypeReplacements]] :>
RuleCondition[
Replace[t,
$usageTypeReplacements
],
True
],
Verbatim[Blank][t_] :>
t,
Verbatim[BlankSequence][] :>
Sequence @@ ToExpression[{"expr1", "expr2"}],
Verbatim[BlankNullSequence][] :>
Sequence[],
symbolUsageReplacementPattern[names, conts],
h_[a___, Verbatim[Sequence][b___], c___] :> h[a, b, c]
}
]
];
Then we take a function that uses this to build out a little template for the DownValues
:
generateSymbolUsage[f_,
defaultMessages : {(_Rule | _RuleDelayed) ...} : {}] :=
With[
{
uml =
Replace[defaultMessages,
{
(h : Rule | RuleDelayed)[Verbatim[HoldPattern][pat___], m_] :>
h[HoldPattern[Verbatim[HoldPattern][pat]], m],
(h : Rule | RuleDelayed)[pat___, m_] :>
h[Verbatim[HoldPattern][pat], m],
_ -> Nothing
},
{1}
]
},
Replace[
DeleteDuplicates@usagePatternReplace[Keys@getCodeValues[f]],
{
Verbatim[HoldPattern][s_[a___]] :>
With[
{
uu =
StringTrim@
Replace[HoldPattern[s[a]] /. uml,
Except[_String] :>
Replace[s::usage, Except[_String] -> ""]
],
sn = ToString[Unevaluated@s],
meuu = ToString[Unevaluated[s[a]], InputForm]
},
(* change this chunk to customize the template *)
If[! StringContainsQ[uu, meuu],
meuu <> " " <>
If[! StringStartsQ[uu,
sn | (Except[WordCharacter] .. ~~ "RowBox[{" ~~ sn)],
uu,
""
] // StringTrim,
StringCases[uu,
(StartOfLine | StartOfString) ~~ Except["\n"] ... ~~ meuu ~~
Except["\n"] ... ~~ EndOfLine,
1
][[1]]
]
],
_ -> Nothing
},
{1}
]
];
generateSymbolUsage~SetAttributes~HoldFirst;
generateSymbolUsage /@ {generateSymbolUsage,
autoCompletionsExtractSeeder}
{{"generateSymbolUsage[f, def]"}, \
{"autoCompletionsExtractSeeder[test, n]",
"autoCompletionsExtractSeeder[alt, n]",
"autoCompletionsExtractSeeder[pat, n]"}}
This doesn't fill out the rest of the template, but we can tweak it like so:
generateSymbolUsage2[f_,
defaultMessages : {(_Rule | _RuleDelayed) ...} : {}] :=
With[
{
uml =
Replace[defaultMessages,
{
(h : Rule | RuleDelayed)[Verbatim[HoldPattern][pat___], m_] :>
h[HoldPattern[Verbatim[HoldPattern][pat]], m],
(h : Rule | RuleDelayed)[pat___, m_] :>
h[Verbatim[HoldPattern][pat], m],
_ -> Nothing
},
{1}
]
},
Replace[
DeleteDuplicates@usagePatternReplace[Keys@getCodeValues[f]],
{
Verbatim[HoldPattern][s_[a___]] :>
With[
{
aerger =
{ReleaseHold@
Map[
Function[
Null,
ToString[#, InputForm],
HoldFirst
],
Hold[a]
]},
opa = ToString[#, InputForm] & /@ Options[s],
meuu = ToString[Unevaluated[s[a]], InputForm]
},
TemplateApply[
meuu <>
" takes `nopenopenope`argument`argplur` \
`argggggggggggg``hasopa``oppppppppp`",
<|
"nopenopenope" -> If[Length@aerger == 0, "no ", ""],
"argplur" -> If[Length@aerger == 1, "", "s"],
"argggggggggggg" ->
Switch[Length@aerger,
0 | 1,
StringJoin@aerger,
2,
StringRiffle[aerger, " and "],
_,
StringJoin@
Insert[
Riffle[aerger, ", "],
"and " ,
-2
]
],
"hasopa" -> If[Length@opa > 0, " and options ", ""],
"oppppppppp" ->
Switch[Length@opa,
0 | 1,
StringJoin@opa,
2,
StringRiffle[opa, " and "],
_,
StringJoin@
Insert[
Riffle[opa, ", "],
"and " ,
-2
]
]
|>
]
],
_ -> Nothing
},
{1}
]
];
generateSymbolUsage2~SetAttributes~HoldFirst;
and then we're like 80% of the way there:
StringRiffle[generateSymbolUsage2@#, "\n"] & /@ {generateSymbolUsage2,
AutoSyntax}
{"generateSymbolUsage2[f, def] takes arguments f and def", \
"AutoSyntax[f] takes argument f and options \"SyntaxInformation\" -> \
{}, \"Autocompletions\" -> {}, \"UsageMessages\" -> {}, \"SetSyntax\" \
-> False, and \"GatherInfo\" -> True"}
This is undoubtedly not my most robust piece of code ever, though.
Definition[functionWithALongName]
$\endgroup$