private string getProto(IXMemberSymbol xMember, XSharpSignatureProperties props) { var proto = xMember.Prototype; // Adjust SELF() and SUPER: remove typename and replace {} with () if (xMember.Kind == Kind.Constructor && props.triggerChar == '(') { var parlist = proto.Substring(proto.IndexOf('{') + 1); parlist = parlist.Substring(0, parlist.Length - 1); proto = props.triggerToken + "(" + parlist + ")"; } return(proto); }
internal bool StartSignatureSession(bool comma, IXTypeSymbol type = null, string methodName = null, char triggerchar = '\0') { WriteOutputMessage("StartSignatureSession()"); if (_signatureSession != null) { return(false); } IXMemberSymbol currentElement = null; SnapshotPoint ssp = this._textView.Caret.Position.BufferPosition; if (triggerchar == '(' && ssp.Position < ssp.Snapshot.Length && ssp.GetChar() == ')') { ssp -= 1; } var location = _textView.FindLocation(ssp); if (location == null || location.Member == null) { return(false); } if (location.Member.Range.StartLine == location.LineNumber) { return(false); } var props = new XSharpSignatureProperties(location); props.triggerChar = triggerchar; props.triggerPosition = this._textView.Caret.Position.BufferPosition.Position; if (type != null && methodName != null) { var findStatic = triggerchar == '.'; currentElement = XSharpLookup.SearchMethod(location, type, methodName, Modifiers.Private, findStatic).FirstOrDefault(); } else { currentElement = findElementAt(comma, ssp, props); } if (currentElement == null) { return(false); } SnapshotPoint caret = _textView.Caret.Position.BufferPosition; ITextSnapshot caretsnapshot = caret.Snapshot; // if (_signatureBroker.IsSignatureHelpActive(_textView)) { _signatureSession = _signatureBroker.GetSessions(_textView)[0]; } else { _signatureSession = _signatureBroker.CreateSignatureHelpSession(_textView, caretsnapshot.CreateTrackingPoint(caret, PointTrackingMode.Positive), true); } _signatureSession.Properties[typeof(XSharpSignatureProperties)] = props; if (location.Member.Kind.IsGlobalTypeMember()) { props.Visibility = Modifiers.Public; } else { props.Visibility = Modifiers.Protected; } _signatureSession.Dismissed += OnSignatureSessionDismiss; props.Element = currentElement; if (comma) { var tokenList = XSharpTokenTools.GetTokenListBeforeCaret(location, out var state); bool done = false; int nested = 0; for (int i = tokenList.Count - 1; i >= 0 && !done; i--) { var token = tokenList[i]; switch (token.Type) { case XSharpLexer.LPAREN: case XSharpLexer.LCURLY: case XSharpLexer.LBRKT: done = nested == 0; if (done) { props.Start = token.Position; props.Length = _textView.Caret.Position.BufferPosition.Position - token.Position; } nested -= 1; break; case XSharpLexer.RPAREN: case XSharpLexer.RCURLY: case XSharpLexer.RBRKT: nested += 1; break; } } } else { props.Start = ssp.Position; props.Length = _textView.Caret.Position.BufferPosition.Position - ssp.Position; } try { _signatureSession.Start(); } catch (Exception e) { XSettings.LogException(e, "Start Signature session failed:"); } // return(true); }
IXMemberSymbol findElementAt(bool comma, SnapshotPoint ssp, XSharpSignatureProperties props) { // when coming from the completion list then there is no need to check a lot of stuff // we can then simply lookup the method and that is it. // Also no need to filter on visibility since that has been done in the completionlist already ! // First, where are we ? var location = props.Location; // When we have a multi line source line this is the line where the open paren or open curly is if (location.Member != null && location.Member.Range.StartLine == ssp.GetContainingLine().LineNumber) { // if we are at the start of an entity then do not start a signature session return(null); } // Then, the corresponding Type/Element if possible // Check if we can get the member where we are var tokenList = XSharpTokenTools.GetTokenListBeforeCaret(location, out var state); // tokenlist may look like ID1 ( ID2 ( e1 , e2) // after the closing paren we come here and want to completely remove the ID2 ( e1, e2 ) part // when we have this ID1 ( e1 ) then there should be no parameter completion at all // The same for ID1 { e1 } // so we need to see if LPAREN / RPAREN is closed and if LCURLY / RCURLY is closed and if LBRKT / RBRKT is closed int nested = 0; var openTokens = new Stack <XSharpToken>(); for (int i = 0; i < tokenList.Count; i++) { var token = tokenList[i]; switch (token.Type) { case XSharpLexer.LPAREN: case XSharpLexer.LCURLY: case XSharpLexer.LBRKT: openTokens.Push(token); break; case XSharpLexer.RPAREN: if (openTokens.Count > 0 && openTokens.Peek().Type == XSharpLexer.LPAREN) { openTokens.Pop(); } break; case XSharpLexer.RCURLY: if (openTokens.Count > 0 && openTokens.Peek().Type == XSharpLexer.LCURLY) { openTokens.Pop(); } break; case XSharpLexer.RBRKT: if (openTokens.Count > 0 && openTokens.Peek().Type == XSharpLexer.LBRKT) { openTokens.Pop(); } break; case XSharpLexer.STRING_CONST: case XSharpLexer.INTERPOLATED_STRING_CONST: case XSharpLexer.CHAR_CONST: if (token.Position < location.Position && location.Position < token.Position + token.Text.Length) { // comma inside literal ! return(null); } break; } } if (openTokens.Count == 0) { tokenList.Clear(); } else { var pos = tokenList.IndexOf(openTokens.Peek()); if (pos >= 0) { tokenList.RemoveRange(pos + 1, tokenList.Count - pos - 1); } } if (comma) { // check to see if there is a lparen or lcurly before the comma bool done = false; nested = 0; while (tokenList.Count > 0 && !done) { var token = tokenList[tokenList.Count - 1]; bool delete = false; switch (token.Type) { case XSharpLexer.RPAREN: case XSharpLexer.RBRKT: case XSharpLexer.RCURLY: nested += 1; delete = true; break; case XSharpLexer.LBRKT: nested -= 1; delete = true; break; case XSharpLexer.LPAREN: case XSharpLexer.LCURLY: nested -= 1; if (nested < 0) { done = true; } else { delete = true; } break; default: delete = true; break; } if (delete) { tokenList.RemoveAt(tokenList.Count - 1); } } } IXMemberSymbol currentElement = null; // We don't care of the corresponding Type, we are looking for the currentElement var element = XSharpLookup.RetrieveElement(location, tokenList, state, out var notProcessed, true).FirstOrDefault(); if (element is IXMemberSymbol mem) { currentElement = mem; if (currentElement.Kind == Kind.Constructor) { bool done = false; for (int i = tokenList.Count - 1; !done && i > 0; i--) { var token = tokenList[i]; switch (token.Type) { case XSharpLexer.LPAREN: case XSharpLexer.LCURLY: props.triggerToken = tokenList[i - 1].Text; break; } } } } else if (element is IXTypeSymbol xtype) { currentElement = xtype.Members.Where(m => m.Kind == Kind.Constructor).FirstOrDefault(); } return(currentElement); }