in vsintegration/src/FSharp.LanguageService.Base/Source.cs [951:1033]
public void OnCommand(IVsTextView textView, VsCommands2K command, char ch)
{
if (textView == null || this.service == null || !this.service.Preferences.EnableCodeSense)
return;
bool backward = (command == VsCommands2K.BACKSPACE || command == VsCommands2K.BACKTAB || command == VsCommands2K.LEFT || command == VsCommands2K.LEFT_EXT);
int line, idx;
var hr = textView.GetCaretPos(out line, out idx);
if (NativeMethods.Failed(hr))
return;
TokenInfo info = GetTokenInfo(line, idx);
TokenTriggers triggerClass = info.Trigger;
var matchBraces = false;
var methodTip = false;
MethodTipMiscellany_DEPRECATED misc = 0;
if ((triggerClass & TokenTriggers.MemberSelect) != 0 && (command == VsCommands2K.TYPECHAR))
{
BackgroundRequestReason reason = ((triggerClass & TokenTriggers.MatchBraces) != 0) ? BackgroundRequestReason.MemberSelectAndHighlightBraces : BackgroundRequestReason.MemberSelect;
this.Completion(textView, info, reason, RequireFreshResults.No);
}
else if (this.service.Preferences.EnableMatchBraces &&
((command != VsCommands2K.BACKSPACE) && ((command == VsCommands2K.TYPECHAR) || this.service.Preferences.EnableMatchBracesAtCaret)))
{
// For brace matching when the caret is before the opening brace, we need to check the token at next index
TokenInfo nextInfo = GetTokenInfo(line, idx + 1); // ??? overflow
TokenTriggers nextTriggerClass = nextInfo.Trigger;
if (((nextTriggerClass & (TokenTriggers.MatchBraces)) != 0) || ((triggerClass & (TokenTriggers.MatchBraces)) != 0))
matchBraces = true;
}
if ((triggerClass & TokenTriggers.MethodTip) != 0 // open paren, close paren, or comma
&& (command == VsCommands2K.TYPECHAR)) // they typed it, not just arrowed over it
{
methodTip = true;
misc = MethodTipMiscellany_DEPRECATED.JustPressedOpenParen;
if ((triggerClass & TokenTriggers.ParameterNext) != 0)
misc = MethodTipMiscellany_DEPRECATED.JustPressedComma;
if ((triggerClass & TokenTriggers.ParameterEnd) != 0)
misc = MethodTipMiscellany_DEPRECATED.JustPressedCloseParen;
}
else if (this.methodData.IsDisplayed)
{
if (command == VsCommands2K.BACKSPACE)
{
// the may have just erased a paren or comma, need to re-parse
methodTip = true;
misc = MethodTipMiscellany_DEPRECATED.JustPressedBackspace;
}
else
{
this.methodData.Refresh(MethodTipMiscellany_DEPRECATED.Typing);
}
}
if (matchBraces && methodTip)
{
// matchBraces = true and methodTip = true
// backward is true when command is one of these: VsCommands2K.BACKSPACE | VsCommands2K.BACKTAB | VsCommands2K.LEFT | VsCommands2K.LEFT_EXT (1)
// matchBraces = true when command is not BACKSPACE => BACKSPACE is excluded from the set (1)
// methodTip = true when command is TYPECHAR or BACKSPACE => BACKSPACE is already excluded and TYPECHAR is not contained in set (1)
// ergo: backward is always false here
Debug.Assert(!backward);
MatchBracesAndMethodTip(textView, line, idx, misc, info);
}
else if (matchBraces)
{
MatchBraces(textView, line, idx, info);
}
else if (methodTip)
{
MethodTip(textView, line, (backward && idx > 0) ? idx - 1 : idx, info, misc, RequireFreshResults.No);
}
}