Skip to content

Commit 304c1b1

Browse files
authored
Merge pull request #466 from kapilmb/enhance-help-comment
Auto-complete comment help in function body
2 parents 2a26642 + e9f4016 commit 304c1b1

File tree

2 files changed

+87
-14
lines changed

2 files changed

+87
-14
lines changed

src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs

+20-14
Original file line numberDiff line numberDiff line change
@@ -1082,32 +1082,38 @@ protected async Task HandleCommentHelpRequest(
10821082
{
10831083
var scriptFile = EditorSession.Workspace.GetFile(requestParams.DocumentUri);
10841084
var expectedFunctionLine = requestParams.TriggerPosition.Line + 2;
1085-
var functionDefinitionAst = EditorSession.LanguageService.GetFunctionDefinitionAtLine(
1085+
1086+
string helpLocation;
1087+
var functionDefinitionAst = EditorSession.LanguageService.GetFunctionDefinitionForHelpComment(
10861088
scriptFile,
1087-
expectedFunctionLine);
1089+
requestParams.TriggerPosition.Line + 1,
1090+
out helpLocation);
10881091
var result = new CommentHelpRequestResult();
1089-
10901092
if (functionDefinitionAst != null)
10911093
{
1092-
// todo create a semantic marker api that take only string
10931094
var analysisResults = await EditorSession.AnalysisService.GetSemanticMarkersAsync(
10941095
functionDefinitionAst.Extent.Text,
10951096
AnalysisService.GetCommentHelpRuleSettings(
10961097
true,
10971098
false,
10981099
requestParams.BlockComment,
10991100
true,
1100-
"before"));
1101-
1102-
// find the analysis result whose correction starts on
1101+
helpLocation));
11031102
result.Content = analysisResults?
1104-
.FirstOrDefault()?
1105-
.Correction?
1106-
.Edits[0]
1107-
.Text
1108-
.Split('\n')
1109-
.Select(x => x.Trim('\r'))
1110-
.ToArray();
1103+
.FirstOrDefault()?
1104+
.Correction?
1105+
.Edits[0]
1106+
.Text
1107+
.Split('\n')
1108+
.Select(x => x.Trim('\r'))
1109+
.ToArray();
1110+
if (helpLocation != null &&
1111+
!helpLocation.Equals("before", StringComparison.OrdinalIgnoreCase))
1112+
{
1113+
// we need to trim the leading `{` and newline when helpLocation=="begin"
1114+
// we also need to trim the leading newline when helpLocation=="end"
1115+
result.Content = result.Content?.Skip(1).ToArray();
1116+
}
11111117
}
11121118

11131119
await requestContext.SendResult(result);

src/PowerShellEditorServices/Language/LanguageService.cs

+67
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,73 @@ public FunctionDefinitionAst GetFunctionDefinitionAtLine(
539539
return functionDefinitionAst as FunctionDefinitionAst;
540540
}
541541

542+
/// <summary>
543+
/// Finds a function definition that follows or contains the given line number.
544+
/// </summary>
545+
/// <param name="scriptFile">Open script file.</param>
546+
/// <param name="lineNumber">The 1 based line on which to look for function definition.</param>
547+
/// <param name="helpLocation"></param>
548+
/// <returns>If found, returns the function definition, otherwise, returns null.</returns>
549+
public FunctionDefinitionAst GetFunctionDefinitionForHelpComment(
550+
ScriptFile scriptFile,
551+
int lineNumber,
552+
out string helpLocation)
553+
{
554+
// check if the next line contains a function definition
555+
var funcDefnAst = GetFunctionDefinitionAtLine(scriptFile, lineNumber + 1);
556+
if (funcDefnAst != null)
557+
{
558+
helpLocation = "before";
559+
return funcDefnAst;
560+
}
561+
562+
// find all the script definitions that contain the line `lineNumber`
563+
var foundAsts = scriptFile.ScriptAst.FindAll(
564+
ast =>
565+
{
566+
var fdAst = ast as FunctionDefinitionAst;
567+
if (fdAst == null)
568+
{
569+
return false;
570+
}
571+
572+
return fdAst.Body.Extent.StartLineNumber < lineNumber &&
573+
fdAst.Body.Extent.EndLineNumber > lineNumber;
574+
},
575+
true);
576+
577+
if (foundAsts != null && foundAsts.Any())
578+
{
579+
// of all the function definitions found, return the innermost function
580+
// definition that contains `lineNumber`
581+
funcDefnAst = foundAsts.Cast<FunctionDefinitionAst>().Aggregate((x, y) =>
582+
{
583+
if (x.Extent.StartOffset >= y.Extent.StartOffset && x.Extent.EndOffset <= x.Extent.EndOffset)
584+
{
585+
return x;
586+
}
587+
588+
return y;
589+
});
590+
591+
// TODO use tokens to check for non empty character instead of just checking for line offset
592+
if (funcDefnAst.Body.Extent.StartLineNumber == lineNumber - 1)
593+
{
594+
helpLocation = "begin";
595+
return funcDefnAst;
596+
}
597+
598+
if (funcDefnAst.Body.Extent.EndLineNumber == lineNumber + 1)
599+
{
600+
helpLocation = "end";
601+
return funcDefnAst;
602+
}
603+
}
604+
605+
helpLocation = null;
606+
return null;
607+
}
608+
542609
#endregion
543610

544611
#region Private Fields

0 commit comments

Comments
 (0)