public override ICompletionDataList CodeCompletionCommand(CodeCompletionContext completionContext) { int triggerWordLength = 0; char ch = completionContext.TriggerOffset > 0 ? textEditorData.GetCharAt(completionContext.TriggerOffset - 1) : '\0'; return(InternalHandleCodeCompletion(completionContext, ch, true, ref triggerWordLength)); }
public static string FindAttributeName (TextEditorData editor, ICompilationUnit unit, string fileName) { int caretOffset = editor.Caret.Offset; int pos = -1; for (int i = caretOffset - 1; i >= 0; i--) { if (editor.GetCharAt (i) == '[') { pos = i; break; } } if (pos <= 0) return null; pos++; StringBuilder result = new StringBuilder (); while (pos < caretOffset) { char ch = editor.GetCharAt (pos); if (!(Char.IsLetterOrDigit (ch) || ch == '_')) break; result.Append (ch); pos++; } return result.ToString (); }
void ConvertVerbatimStringToNormal (TextEditorData textEditorData, int offset) { var endOffset = offset; while (endOffset < textEditorData.Length) { char ch = textEditorData.GetCharAt (endOffset); if (ch == '"' && (endOffset + 1 < textEditorData.Length && textEditorData.GetCharAt (endOffset + 1) == '"')) { endOffset += 2; continue; } if (ch == '"') break; endOffset++; } textEditorData.Replace (offset, endOffset - offset, ConvertToStringLiteral (ConvertFromVerbatimString (textEditorData.GetTextAt (offset, endOffset - offset)))); }
public ExpressionContext FindExactContextForObjectInitializer (TextEditorData editor, ICompilationUnit unit, string fileName, IType callingType) { int caretOffset = editor.Caret.Offset; // create a table with all opening brackets Dictionary<int, int> brackets = new Dictionary<int, int> (); Stack<int> bracketStack = new Stack<int> (); for (int i = 0; i < caretOffset; i++) { char ch = editor.GetCharAt (i); switch (ch) { case '/': if (i + 1 < caretOffset) { if (editor.GetCharAt (i + 1) == '/') { while (i < caretOffset) { if (editor.GetCharAt (i) == '\n') break; i++; } } else if (editor.GetCharAt (i + 1) == '*') { while (i + 1 < caretOffset) { if (editor.GetCharAt (i) == '*' && editor.GetCharAt (i + 1) == '/') break; i++; } } } break; case '(': case '{': case '[': bracketStack.Push (i); break; case ')': case '}': case ']': if (bracketStack.Count > 0) brackets[i] = bracketStack.Pop (); break; } } bool foundCurlyBrace = false; for (int i = caretOffset - 1; i >= 0; i--) { char ch = editor.GetCharAt (i); if (ch == '{') { foundCurlyBrace = true; } else if (ch == ')' || ch == '}' || ch == ']') { int newPos; if (brackets.TryGetValue (i, out newPos)) { i = newPos; // we've had a Property = new Name (), expression, now search for the '=' // otherwise the "new Name" would be falsly taken as object initializer if (!foundCurlyBrace) { while (i >= 0) { if (editor.GetCharAt (i) == '=' || editor.GetCharAt (i) == ';') break; i--; } } continue; } } if (i + 4 < caretOffset && editor.GetTextAt (i, 4) == "new ") { bool skip = false; for (int j2 = i; j2 < caretOffset; j2++) { if (editor.GetCharAt (j2) == '{') break; if (editor.GetCharAt (j2) == ',') { skip = true; break; } } if (skip) continue; int j = i + 4; while (j < caretOffset && Char.IsWhiteSpace (editor.GetCharAt (j))) j++; // int start = j; while (j < caretOffset && (Char.IsLetterOrDigit (editor.GetCharAt (j)) || editor.GetCharAt (j) == '_' || editor.GetCharAt (j) == '.')) j++; ExpressionResult firstExprs = FindExpression (editor, j); if (firstExprs.Expression != null) { // skip ws while (j < caretOffset && Char.IsWhiteSpace (editor.GetCharAt (j))) j++; if (editor.GetCharAt (j) == '[') { StringBuilder expr = new StringBuilder (firstExprs.Expression); while (j < caretOffset) { ch = editor.GetCharAt (j); switch (ch) { case '[': case ',': case ']': expr.Append (ch); break; case ' ': case '\t': break; default: j = caretOffset; break; } j++; } firstExprs.Expression = expr.ToString (); } IReturnType unresolvedReturnType = NRefactoryResolver.ParseReturnType (firstExprs); if (unresolvedReturnType != null) { IType resolvedType = projectContent.SearchType (unit, (INode)callingType ?? unit, unresolvedReturnType); return ExpressionContext.TypeDerivingFrom (resolvedType != null ? new DomReturnType (resolvedType) : null, unresolvedReturnType, true); } } } } return null; }
// // TODO - It seems the support for properties varies // depending on the ECMA script requested version. // Fix the code here. // public static int GuessSemicolonInsertionOffset(TextEditorData data, DocumentLine currLine, int caretOffset) { int lastNonWsOffset = caretOffset; char lastNonWsChar = '\0'; int max = currLine.EndOffset; // PORT NOTE: Honestly, this looks like a hack. if (caretOffset - 2 >= currLine.Offset && data.Document.GetCharAt (caretOffset - 2) == ')') return caretOffset; int end = caretOffset; while (end > 1 && Char.IsWhiteSpace (data.GetCharAt (end))) end--; int end2 = end; while (end2 > 1 && Char.IsLetter (data.GetCharAt (end2 - 1))) end2--; if (end != end2) { string token = data.GetTextBetween (end2, end + 1); // guess property context if (token == "get" || token == "set") return caretOffset; } bool isInDQuotedString = false, isInSQuotedString = false; bool isInLineComment = false , isInBlockComment = false; // Compare the first check against the original one. for (int pos = caretOffset; pos < max; pos++) { if (pos == caretOffset) { if (isInDQuotedString || isInSQuotedString || isInLineComment || isInBlockComment) return pos; } char ch = data.Document.GetCharAt (pos); switch (ch) { case '/': if (isInBlockComment) { if (pos > 0 && data.Document.GetCharAt (pos - 1) == '*') isInBlockComment = false; } else if (!(isInDQuotedString || isInSQuotedString) && pos + 1 < max) { char nextChar = data.Document.GetCharAt (pos + 1); if (nextChar == '/') { isInLineComment = true; return lastNonWsOffset; } if (!isInLineComment && nextChar == '*') { isInBlockComment = true; return lastNonWsOffset; } } break; case '\\': if (isInSQuotedString || isInDQuotedString) pos++; break; case '"': if (!(isInSQuotedString || isInLineComment || isInBlockComment)) { if (isInDQuotedString && pos + 1 < max && data.Document.GetCharAt (pos + 1) == '"') pos++; else isInDQuotedString = !isInDQuotedString; } break; case '\'': if (!(isInDQuotedString || isInLineComment || isInBlockComment)) isInSQuotedString = !isInSQuotedString; break; } if (!Char.IsWhiteSpace (ch)) { lastNonWsOffset = pos; lastNonWsChar = ch; } } // if the line ends with ';' the line end is not the correct place for a new semicolon. if (lastNonWsChar == ';') return caretOffset; return lastNonWsOffset; }
public static List<InsertionPoint> GetInsertionPoints (TextEditorData data, ParsedDocument parsedDocument, IUnresolvedTypeDefinition type) { if (data == null) throw new ArgumentNullException ("data"); if (parsedDocument == null) throw new ArgumentNullException ("parsedDocument"); if (type == null) throw new ArgumentNullException ("type"); // update type from parsed document, since this is always newer. //type = parsedDocument.GetInnermostTypeDefinition (type.GetLocation ()) ?? type; List<InsertionPoint> result = new List<InsertionPoint> (); int offset = data.LocationToOffset (type.Region.Begin); if (offset < 0 || type.BodyRegion.IsEmpty) return result; while (offset < data.Length && data.GetCharAt (offset) != '{') { offset++; } var realStartLocation = data.OffsetToLocation (offset); result.Add (GetInsertionPosition (data.Document, realStartLocation.Line, realStartLocation.Column)); result [0].LineBefore = NewLineInsertion.None; foreach (var member in type.Members) { TextLocation domLocation = member.BodyRegion.End; if (domLocation.Line <= 0) { DocumentLine lineSegment = data.GetLine (member.Region.BeginLine); if (lineSegment == null) continue; domLocation = new TextLocation (member.Region.BeginLine, lineSegment.Length + 1); } result.Add (GetInsertionPosition (data.Document, domLocation.Line, domLocation.Column)); } foreach (var nestedType in type.NestedTypes) { TextLocation domLocation = nestedType.BodyRegion.End; if (domLocation.Line <= 0) { DocumentLine lineSegment = data.GetLine (nestedType.Region.BeginLine); if (lineSegment == null) continue; domLocation = new TextLocation (nestedType.Region.BeginLine, lineSegment.Length + 1); } result.Add (GetInsertionPosition (data.Document, domLocation.Line, domLocation.Column)); } result [result.Count - 1].LineAfter = NewLineInsertion.None; CheckStartPoint (data.Document, result [0], result.Count == 1); if (result.Count > 1) { result.RemoveAt (result.Count - 1); NewLineInsertion insertLine; var lineBefore = data.GetLine (type.BodyRegion.EndLine - 1); if (lineBefore != null && lineBefore.Length == lineBefore.GetIndentation (data.Document).Length) { insertLine = NewLineInsertion.None; } else { insertLine = NewLineInsertion.Eol; } // search for line start int col = type.BodyRegion.EndColumn - 1; var line = data.GetLine (type.BodyRegion.EndLine); if (line != null) { while (col > 1 && char.IsWhiteSpace (data.GetCharAt (line.Offset + col - 2))) col--; } result.Add (new InsertionPoint (new DocumentLocation (type.BodyRegion.EndLine, col), insertLine, NewLineInsertion.Eol)); CheckEndPoint (data.Document, result [result.Count - 1], result.Count == 1); } foreach (var region in parsedDocument.UserRegions.Where (r => type.BodyRegion.IsInside (r.Region.Begin))) { result.Add (new InsertionPoint (new DocumentLocation (region.Region.BeginLine + 1, 1), NewLineInsertion.Eol, NewLineInsertion.Eol)); result.Add (new InsertionPoint (new DocumentLocation (region.Region.EndLine, 1), NewLineInsertion.Eol, NewLineInsertion.Eol)); result.Add (new InsertionPoint (new DocumentLocation (region.Region.EndLine + 1, 1), NewLineInsertion.Eol, NewLineInsertion.Eol)); } result.Sort ((left, right) => left.Location.CompareTo (right.Location)); return result; }
static void ConvertVerbatimStringToNormal (TextEditorData textEditorData, int offset) { var endOffset = offset; while (endOffset < textEditorData.Length) { char ch = textEditorData.GetCharAt (endOffset); if (ch == '"' && (endOffset + 1 < textEditorData.Length && textEditorData.GetCharAt (endOffset + 1) == '"')) { endOffset += 2; continue; } if (ch == '"') { break; } endOffset++; } var plainText = TextPasteUtils.VerbatimStringStrategy.Decode (textEditorData.GetTextAt (offset, endOffset - offset)); var newText = TextPasteUtils.StringLiteralPasteStrategy.Instance.Encode (plainText); textEditorData.Replace (offset, endOffset - offset, newText); }
public static void SetCompletionText (TextEditorData data, CodeCompletionContext ctx, string partialWord, string completeWord, int wordOffset) { if (data == null || data.Document == null) return; int triggerOffset = ctx.TriggerOffset; int length = String.IsNullOrEmpty (partialWord) ? 0 : partialWord.Length; // for named arguments invoke(arg:<Expr>); if (completeWord.EndsWith (":", StringComparison.Ordinal)) { if (data.GetCharAt (triggerOffset + length) == ':') length++; } bool blockMode = false; if (data.IsSomethingSelected) { blockMode = data.MainSelection.SelectionMode == Mono.TextEditor.SelectionMode.Block; if (blockMode) { data.Caret.PreserveSelection = true; triggerOffset = data.Caret.Offset - length; } else { if (data.SelectionRange.Offset < ctx.TriggerOffset) triggerOffset = ctx.TriggerOffset - data.SelectionRange.Length; data.DeleteSelectedText (); } length = 0; } // | in the completion text now marks the caret position int idx = completeWord.IndexOf ('|'); if (idx >= 0) { completeWord = completeWord.Remove (idx, 1); } triggerOffset += data.EnsureCaretIsNotVirtual (); if (blockMode) { using (var undo = data.OpenUndoGroup ()) { int minLine = data.MainSelection.MinLine; int maxLine = data.MainSelection.MaxLine; int column = triggerOffset - data.Document.GetLineByOffset (triggerOffset).Offset; for (int lineNumber = minLine; lineNumber <= maxLine; lineNumber++) { DocumentLine lineSegment = data.Document.GetLine (lineNumber); if (lineSegment == null) continue; int offset = lineSegment.Offset + column; data.Replace (offset, length, completeWord); } int minColumn = Math.Min (data.MainSelection.Anchor.Column, data.MainSelection.Lead.Column); data.MainSelection = data.MainSelection.WithRange ( new Mono.TextEditor.DocumentLocation (data.Caret.Line == minLine ? maxLine : minLine, minColumn), data.Caret.Location ); data.Document.CommitMultipleLineUpdate (data.MainSelection.MinLine, data.MainSelection.MaxLine); data.Caret.PreserveSelection = false; } } else { data.Replace (triggerOffset, length, completeWord); } data.Document.CommitLineUpdate (data.Caret.Line); if (idx >= 0) data.Caret.Offset = triggerOffset + idx; }
public MonoDevelop.Projects.Dom.ResolveResult GetLanguageItem(ProjectDom dom, Mono.TextEditor.TextEditorData data, int offset, string expression) { string fileName = data.Document.FileName; MonoDevelop.Ide.Gui.Document doc = IdeApp.Workbench.ActiveDocument; if (doc == null) { return(null); } IParser parser = ProjectDomService.GetParser(fileName); if (parser == null) { return(null); } IResolver resolver = parser.CreateResolver(dom, doc, fileName); IExpressionFinder expressionFinder = parser.CreateExpressionFinder(dom); if (resolver == null || expressionFinder == null) { return(null); } int wordEnd = offset; while (wordEnd < data.Length && (Char.IsLetterOrDigit(data.GetCharAt(wordEnd)) || data.GetCharAt(wordEnd) == '_')) { wordEnd++; } ExpressionResult expressionResult = new ExpressionResult(expression); expressionResult.ExpressionContext = ExpressionContext.MethodBody; DocumentLocation loc = data.Document.OffsetToLocation(offset); string savedExpression = null; ResolveResult resolveResult; if (expressionResult.ExpressionContext == ExpressionContext.Attribute) { savedExpression = expressionResult.Expression; expressionResult.Expression += "Attribute"; expressionResult.ExpressionContext = ExpressionContext.ObjectCreation; } resolveResult = resolver.Resolve(expressionResult, new DomLocation(loc.Line, loc.Column)); if (savedExpression != null && resolveResult == null) { expressionResult.Expression = savedExpression; resolveResult = resolver.Resolve(expressionResult, new DomLocation(loc.Line, loc.Column)); } if (expressionResult.Region.End.IsEmpty) { return(resolveResult); } // Search for possible generic parameters. // if (this.resolveResult == null || this.resolveResult.ResolvedType == null || String.IsNullOrEmpty (this.resolveResult.ResolvedType.Name)) { int j = data.Document.LocationToOffset(expressionResult.Region.End.Line, expressionResult.Region.End.Column); int bracket = 0; for (int i = j; i >= 0 && i < data.Document.Length; i++) { char ch = data.Document.GetCharAt(i); if (Char.IsWhiteSpace(ch)) { continue; } if (ch == '<') { bracket++; } else if (ch == '>') { bracket--; if (bracket == 0) { expressionResult.Expression += data.Document.GetTextBetween(j, i + 1); expressionResult.ExpressionContext = ExpressionContext.ObjectCreation; resolveResult = resolver.Resolve(expressionResult, new DomLocation(loc.Line, loc.Column)) ?? resolveResult; break; } } else { if (bracket == 0) { break; } } } // } // To resolve method overloads the full expression must be parsed. // ex.: Overload (1)/ Overload("one") - parsing "Overload" gives just a MethodResolveResult if (resolveResult is MethodResolveResult) { resolveResult = resolver.Resolve(expressionFinder.FindFullExpression(data, wordEnd), new DomLocation(loc.Line, loc.Column)) ?? resolveResult; } return(resolveResult); }
static bool TryFindSymbolBlock(TextEditorData data, char command, out SymbolBlock result) { char end, begin; if (!BeginToEndCharMap.TryGetValue (command, out end)) end = command; if (!EndToBeginCharMap.TryGetValue (command, out begin)) begin = command; var offset = data.Caret.Offset; var startTokenOffset = ParseForChar(data, offset, 0, end, begin, false); var endTokenOffset = ParseForChar(data, offset, data.Length, begin, end, true); // Use the editor's FindMatchingBrace built-in functionality. It's better at handling erroneous braces // inside quotes. We still need to do the above paragraph because we needed to find the braces. var matchingStartBrace = endTokenOffset.HasValue ? data.Document.GetMatchingBracketOffset( endTokenOffset.GetValueOrDefault ()) : -1; if (matchingStartBrace >= 0 && (!startTokenOffset.HasValue || matchingStartBrace != startTokenOffset.GetValueOrDefault ())) startTokenOffset = matchingStartBrace; var matchingEndBrace = startTokenOffset.HasValue && data.GetCharAt (offset) != end ? data.Document.GetMatchingBracketOffset(startTokenOffset.GetValueOrDefault ()) : -1; if (matchingEndBrace >= 0 && (!endTokenOffset.HasValue || matchingEndBrace != endTokenOffset.GetValueOrDefault ())) endTokenOffset = matchingEndBrace; if (!startTokenOffset.HasValue || !endTokenOffset.HasValue) throw new ViModeAbortException(); result = new SymbolBlock { StartOffset = startTokenOffset.GetValueOrDefault (), EndOffset = endTokenOffset.GetValueOrDefault (), StartLine = data.GetLineByOffset (startTokenOffset.GetValueOrDefault()), EndLine = data.GetLineByOffset (endTokenOffset.GetValueOrDefault()), }; return true; }
static int? ParseForChar(TextEditorData data, int fromOffset, int toOffset, char oppositeToken, char findToken, bool forward) { int increment = forward ? 1 : -1; var symbolCount = 0; for (int i = fromOffset; forward && i < toOffset || !forward && i >= toOffset; i += increment) { var c = data.GetCharAt(i); if (c == oppositeToken) symbolCount++; else if (c == findToken) { if (symbolCount == 0) return i; symbolCount--; } } return null; }
string GetWordAtOffset (TextEditorData text, int offset, out int begin) { if (offset < 0 || offset >= text.Length) { begin = offset; return String.Empty; } StringBuilder sb = new StringBuilder (); int i = offset; char c; // Look forward for break char for (i = offset; i < text.Length; i++) { c = text.GetCharAt (i); if (Char.IsWhiteSpace (c)) break; bool needsBreak = false; switch (c) { case '(': case ')': case '[': case ']': case '{': case '}': case ':': case ',': case '@': case '.': needsBreak = true; break; default: sb.Append (c); break; } if (Char.IsWhiteSpace (c) || needsBreak) break; } if (offset > 0) { // look backwards for break char for (i = offset - 1; i > 0; i--) { c = text.GetCharAt (i); if (Char.IsWhiteSpace (c)) break; bool needsBreak = false; switch (c) { case '(': case ')': case '[': case ']': case '{': case '}': case ':': case ',': case '@': case '.': needsBreak = true; break; default: sb.Insert (0, c); break; } if (needsBreak) break; } } begin = i; return sb.ToString (); }
public static bool GuessSemicolonInsertionOffset (TextEditorData data, ISegment curLine, int caretOffset, out int outOffset) { int lastNonWsOffset = caretOffset; char lastNonWsChar = '\0'; outOffset = caretOffset; int max = curLine.EndOffset; int end = caretOffset; while (end > 1 && char.IsWhiteSpace (data.GetCharAt (end))) end--; int end2 = end; while (end2 > 1 && char.IsLetter (data.GetCharAt (end2 - 1))) end2--; if (end != end2) { string token = data.GetTextBetween (end2, end + 1); // guess property context if (token == "get" || token == "set") return false; } var offset = curLine.Offset; string lineText = data.GetTextAt (caretOffset, max - caretOffset); var lexer = new CSharpCompletionEngineBase.MiniLexer (lineText); lexer.Parse ((ch, i) => { if (lexer.IsInSingleComment || lexer.IsInMultiLineComment) return true; if (ch == '}' && lexer.IsFistNonWs && !IsSemicolonalreadyPlaced (data, caretOffset)) { lastNonWsChar = ';'; return true; } if (!char.IsWhiteSpace (ch)) { lastNonWsOffset = caretOffset + i; lastNonWsChar = ch; } return false; }); // if the line ends with ';' the line end is not the correct place for a new semicolon. if (lastNonWsChar == ';') return false; outOffset = lastNonWsOffset; return true; }
static int SearchMatchingBracket (TextEditorData editor, int offset, char openBracket, char closingBracket, int direction) { bool isInString = false; bool isInChar = false; bool isInBlockComment = false; int depth = -1; while (offset >= 0 && offset < editor.Length) { char ch = editor.GetCharAt (offset); switch (ch) { case '/': if (isInBlockComment) isInBlockComment = editor.GetCharAt (offset + direction) != '*'; if (!isInString && !isInChar && offset - direction < editor.Length) isInBlockComment = offset > 0 && editor.GetCharAt (offset - direction) == '*'; break; case '"': if (!isInChar && !isInBlockComment) isInString = !isInString; break; case '\'': if (!isInString && !isInBlockComment) isInChar = !isInChar; break; default : if (ch == closingBracket) { if (!(isInString || isInChar || isInBlockComment)) --depth; } else if (ch == openBracket) { if (!(isInString || isInChar || isInBlockComment)) { ++depth; if (depth == 0) return offset; } } break; } offset += direction; } return -1; }
public MonoDevelop.Projects.Dom.ResolveResult GetLanguageItem(ProjectDom dom, Mono.TextEditor.TextEditorData data, int offset) { if (offset < 0) { return(null); } string fileName = data.Document.FileName; IParser parser = ProjectDomService.GetParser(fileName); if (parser == null) { return(null); } MonoDevelop.Ide.Gui.Document doc = IdeApp.Workbench.ActiveDocument; if (doc == null) { return(null); } IResolver resolver = parser.CreateResolver(dom, doc, fileName); if (resolver == null) { return(null); } var expressionFinder = new NewCSharpExpressionFinder(dom); int wordEnd = Math.Min(offset, data.Length - 1); if (wordEnd < 0) { return(null); } if (data.GetCharAt(wordEnd) == '@') { wordEnd++; } while (wordEnd < data.Length && (Char.IsLetterOrDigit(data.GetCharAt(wordEnd)) || data.GetCharAt(wordEnd) == '_')) { wordEnd++; } while (wordEnd < data.Length - 1 && Char.IsWhiteSpace(data.GetCharAt(wordEnd))) { wordEnd++; } /* is checked at the end. * int saveEnd = wordEnd; * if (wordEnd < data.Length && data.GetCharAt (wordEnd) == '<') { * int matchingBracket = data.Document.GetMatchingBracketOffset (wordEnd); * if (matchingBracket > 0) * wordEnd = matchingBracket; * while (wordEnd < data.Length - 1 && Char.IsWhiteSpace (data.GetCharAt (wordEnd))) * wordEnd++; * } * * bool wasMethodCall = false; * if (data.GetCharAt (wordEnd) == '(') { * int matchingBracket = data.Document.GetMatchingBracketOffset (wordEnd); * if (matchingBracket > 0) { * wordEnd = matchingBracket; * wasMethodCall = true; * } * } * if (!wasMethodCall) * wordEnd = saveEnd;*/ ExpressionResult expressionResult = expressionFinder.FindExpression(data, wordEnd); if (expressionResult == null) { return(null); } ResolveResult resolveResult; DocumentLocation loc = data.Document.OffsetToLocation(offset); string savedExpression = null; // special handling for 'var' "keyword" if (expressionResult.ExpressionContext == ExpressionContext.IdentifierExpected && expressionResult.Expression != null && expressionResult.Expression.Trim() == "var") { int endOffset = data.Document.LocationToOffset(expressionResult.Region.End.Line, expressionResult.Region.End.Column); StringBuilder identifer = new StringBuilder(); for (int i = endOffset; i >= 0 && i < data.Document.Length; i++) { char ch = data.Document.GetCharAt(i); if (Char.IsWhiteSpace(ch)) { continue; } if (ch == '=') { break; } if (Char.IsLetterOrDigit(ch) || ch == '_') { identifer.Append(ch); continue; } identifer.Length = 0; break; } if (identifer.Length > 0) { expressionResult.Expression = identifer.ToString(); resolveResult = resolver.Resolve(expressionResult, new DomLocation(loc.Line, loc.Column)); if (resolveResult != null) { resolveResult = new MemberResolveResult(dom.GetType(resolveResult.ResolvedType)); resolveResult.ResolvedExpression = expressionResult; return(resolveResult); } } } if (expressionResult.ExpressionContext == ExpressionContext.Attribute && !string.IsNullOrEmpty(expressionResult.Expression)) { savedExpression = expressionResult.Expression; expressionResult.Expression = expressionResult.Expression.Trim() + "Attribute"; expressionResult.ExpressionContext = ExpressionContext.ObjectCreation; } resolveResult = resolver.Resolve(expressionResult, new DomLocation(loc.Line, loc.Column)); if (savedExpression != null && resolveResult == null) { expressionResult.Expression = savedExpression; resolveResult = resolver.Resolve(expressionResult, new DomLocation(loc.Line, loc.Column)); } // Search for possible generic parameters. // if (this.resolveResult == null || this.resolveResult.ResolvedType == null || String.IsNullOrEmpty (this.resolveResult.ResolvedType.Name)) { if (!expressionResult.Region.IsEmpty) { int j = data.Document.LocationToOffset(expressionResult.Region.End.Line, expressionResult.Region.End.Column); int bracket = 0; for (int i = j; i >= 0 && i < data.Document.Length; i++) { char ch = data.Document.GetCharAt(i); if (Char.IsWhiteSpace(ch)) { continue; } if (ch == '<') { bracket++; } else if (ch == '>') { bracket--; if (bracket == 0) { expressionResult.Expression += data.Document.GetTextBetween(j, i + 1); expressionResult.ExpressionContext = ExpressionContext.ObjectCreation; resolveResult = resolver.Resolve(expressionResult, new DomLocation(loc.Line, loc.Column)); break; } } else { if (bracket == 0) { break; } } } } // To resolve method overloads the full expression must be parsed. // ex.: Overload (1)/ Overload("one") - parsing "Overload" gives just a MethodResolveResult // and for constructor initializers it's tried too to to resolve constructor overloads. if (resolveResult is ThisResolveResult || resolveResult is BaseResolveResult || resolveResult is MethodResolveResult && ((MethodResolveResult)resolveResult).Methods.Count > 1) { // put the search offset at the end of the invocation to be able to find the full expression // the resolver finds it itself if spaces are between the method name and the argument opening parentheses. while (wordEnd < data.Length - 1 && Char.IsWhiteSpace(data.GetCharAt(wordEnd))) { wordEnd++; } if (data.GetCharAt(wordEnd) == '(') { int matchingBracket = data.Document.GetMatchingBracketOffset(wordEnd); if (matchingBracket > 0) { wordEnd = matchingBracket; } } //Console.WriteLine (expressionFinder.FindFullExpression (txt, wordEnd)); ResolveResult possibleResult = resolver.Resolve(expressionFinder.FindFullExpression(data, wordEnd), new DomLocation(loc.Line, loc.Column)) ?? resolveResult; //Console.WriteLine ("possi:" + resolver.Resolve (expressionFinder.FindFullExpression (txt, wordEnd), new DomLocation (loc.Line, loc.Column))); if (possibleResult is MethodResolveResult) { resolveResult = possibleResult; } } return(resolveResult); }
static int FindPrevWordStart (TextEditorData editor, int offset) { while (--offset >= 0 && !Char.IsWhiteSpace (editor.GetCharAt (offset))) ; return ++offset; }
public ExpressionContext FindExactContextForNewCompletion (TextEditorData editor, ICompilationUnit unit, string fileName, IType callingType, int cursorPos) { // find expression on left hand side of the assignment int caretOffset = editor.Caret.Offset; int pos = -1; for (int i = caretOffset - 1; i >= 0; i--) { if (editor.GetCharAt (i) == '=') { if (i > 0 && (editor.GetCharAt (i - 1) == '+' || editor.GetCharAt (i - 1) == '-')) i--; pos = i; break; } } if (pos <= 0) return null; // check if new +=/-=/= is right before "new" for (int i = pos; i < cursorPos; i++) { char ch = editor.GetCharAt (i); if (Char.IsWhiteSpace (ch)) continue; if (ch != '=' && ch != '+' && ch != '-' && ch != 'n' && ch != 'e' && ch != 'w') return null; } int lastWs = pos - 1; while (lastWs > 0 && char.IsWhiteSpace (editor.GetCharAt (lastWs))) lastWs--; int varTypePos = lastWs; while (varTypePos > 0 && !char.IsWhiteSpace (editor.GetCharAt (varTypePos))) varTypePos--; while (varTypePos > 0 && char.IsWhiteSpace (editor.GetCharAt (varTypePos))) varTypePos--; ExpressionResult possibleTypeExpression = FindFullExpression (editor, varTypePos); if (possibleTypeExpression.Expression != null) { if (possibleTypeExpression.Expression == "var") return ExpressionContext.TypeDerivingFrom (DomReturnType.Object, DomReturnType.Object, true); IReturnType unresolvedReturnType = NRefactoryResolver.ParseReturnType (possibleTypeExpression); if (unresolvedReturnType != null) { IType resolvedType = projectContent.SearchType (unit, callingType, new DomLocation (editor.Caret.Line, editor.Caret.Column), unresolvedReturnType); if (resolvedType != null) return ExpressionContext.TypeDerivingFrom (new DomReturnType (resolvedType), unresolvedReturnType, true); } } ExpressionResult lhsExpr = FindFullExpression (editor, lastWs); if (lhsExpr.Expression != null) { NRefactoryResolver resolver = new NRefactoryResolver (projectContent, unit, ICSharpCode.OldNRefactory.SupportedLanguage.CSharp, editor, fileName); ResolveResult rr = resolver.Resolve (lhsExpr, new DomLocation (editor.Caret.Line, editor.Caret.Column)); //ResolveResult rr = ParserService.Resolve (lhsExpr, currentLine.LineNumber, pos, editor.FileName, editor.Text); if (rr != null && rr.ResolvedType != null) { ExpressionContext context; IType c; /* if (rr.ResolvedType.IsArrayReturnType) { // when creating an array, all classes deriving from the array's element type are allowed IReturnType elementType = rr.ResolvedType.CastToArrayReturnType().ArrayElementType; c = elementType != null ? dom.GetType (elementType) : null; context = ExpressionContext.TypeDerivingFrom(elementType, false); } else */ { // when creating a normal instance, all non-abstract classes deriving from the type // are allowed c = projectContent.GetType (rr.ResolvedType); context = ExpressionContext.TypeDerivingFrom (rr.ResolvedType, null, true); } if (c != null && !context.FilterEntry (c)) { // Try to suggest an entry (List<int> a = new => suggest List<int>). string suggestedClassName = null; /*LanguageProperties.CSharp.CodeGenerator.GenerateCode( CodeGenerator.ConvertType( rr.ResolvedType, new ClassFinder(ParserService.GetParseInformation(editor.FileName), editor.ActiveTextAreaControl.Caret.Line + 1, editor.ActiveTextAreaControl.Caret.Column + 1) ), "");*/ if (suggestedClassName != c.Name) { // create an IType instance that includes the type arguments in its name //context.DefaultItem = new RenamedClass (c, suggestedClassName); } else { context.DefaultItem = c; } } return context; } } return null; }
static void ConvertNormalToVerbatimString (TextEditorData textEditorData, int offset) { var endOffset = offset; while (endOffset < textEditorData.Length) { char ch = textEditorData.GetCharAt (endOffset); if (ch == '\\') { if (endOffset + 1 < textEditorData.Length && NewLine.IsNewLine (textEditorData.GetCharAt (endOffset + 1))) return; endOffset += 2; continue; } if (ch == '"') break; if (NewLine.IsNewLine (ch)) return; endOffset++; } if (offset > endOffset || endOffset == textEditorData.Length) return; var plainText = TextPasteUtils.StringLiteralPasteStrategy.Instance.Decode (textEditorData.GetTextAt (offset, endOffset - offset)); var newText = TextPasteUtils.VerbatimStringStrategy.Encode (plainText); textEditorData.Replace (offset, endOffset - offset, newText); }
public static List<InsertionPoint> GetInsertionPoints (TextEditorData data, ParsedDocument parsedDocument, IType type) { if (data == null) throw new ArgumentNullException ("data"); if (parsedDocument == null) throw new ArgumentNullException ("parsedDocument"); if (type == null) throw new ArgumentNullException ("type"); List<InsertionPoint> result = new List<InsertionPoint> (); int offset = data.LocationToOffset (type.BodyRegion.Start.Line, type.BodyRegion.Start.Column); if (offset < 0) return result; while (offset < data.Length && data.GetCharAt (offset) != '{') { offset++; } var realStartLocation = data.OffsetToLocation (offset); result.Add (GetInsertionPosition (data.Document, realStartLocation.Line, realStartLocation.Column)); result[0].LineBefore = NewLineInsertion.None; foreach (IMember member in type.Members) { DomLocation domLocation = member.BodyRegion.End; if (domLocation.Line <= 0) { LineSegment lineSegment = data.GetLine (member.Location.Line); if (lineSegment == null) continue; domLocation = new DomLocation (member.Location.Line, lineSegment.EditableLength + 1); } result.Add (GetInsertionPosition (data.Document, domLocation.Line, domLocation.Column)); } result[result.Count - 1].LineAfter = NewLineInsertion.None; CheckStartPoint (data.Document, result[0], result.Count == 1); if (result.Count > 1) { result.RemoveAt (result.Count - 1); NewLineInsertion insertLine; var lineBefore = data.GetLine (type.BodyRegion.End.Line - 1); if (lineBefore != null && lineBefore.EditableLength == lineBefore.GetIndentation (data.Document).Length) { insertLine = NewLineInsertion.None; } else { insertLine = NewLineInsertion.Eol; } // search for line start var line = data.GetLine (type.BodyRegion.End.Line); int col = type.BodyRegion.End.Column - 1; while (col > 1 && char.IsWhiteSpace (data.GetCharAt (line.Offset + col - 2))) col--; result.Add (new InsertionPoint (new DocumentLocation (type.BodyRegion.End.Line, col), insertLine, NewLineInsertion.Eol)); CheckEndPoint (data.Document, result[result.Count - 1], result.Count == 1); } foreach (var region in parsedDocument.UserRegions.Where (r => type.BodyRegion.Contains (r.Region))) { result.Add (new InsertionPoint (new DocumentLocation (region.Region.Start.Line + 1, 1), NewLineInsertion.Eol, NewLineInsertion.Eol)); result.Add (new InsertionPoint (new DocumentLocation (region.Region.End.Line, 1), NewLineInsertion.Eol, NewLineInsertion.Eol)); result.Add (new InsertionPoint (new DocumentLocation (region.Region.End.Line + 1, 1), NewLineInsertion.Eol, NewLineInsertion.Eol)); } result.Sort ((left, right) => left.Location.CompareTo (right.Location)); return result; }
public static bool GuessSemicolonInsertionOffset (TextEditorData data, IDocumentLine curLine, int caretOffset, out int outOffset) { int lastNonWsOffset = caretOffset; char lastNonWsChar = '\0'; outOffset = caretOffset; int max = curLine.EndOffset; // if (caretOffset - 2 >= curLine.Offset && data.Document.GetCharAt (caretOffset - 2) == ')' && !IsSemicolonalreadyPlaced (data, caretOffset)) // return false; int end = caretOffset; while (end > 1 && char.IsWhiteSpace (data.GetCharAt (end))) end--; int end2 = end; while (end2 > 1 && char.IsLetter(data.GetCharAt (end2 - 1))) end2--; if (end != end2) { string token = data.GetTextBetween (end2, end + 1); // guess property context if (token == "get" || token == "set") return false; } bool isInString = false , isInChar= false , isVerbatimString= false; bool isInLineComment = false , isInBlockComment= false; bool firstChar = true; for (int pos = caretOffset; pos < max; pos++) { if (pos == caretOffset) { if (isInString || isInChar || isVerbatimString || isInLineComment || isInBlockComment) { outOffset = pos; return true; } } char ch = data.Document.GetCharAt (pos); switch (ch) { case '}': if (firstChar && !IsSemicolonalreadyPlaced (data, caretOffset)) return false; break; case '/': if (isInBlockComment) { if (pos > 0 && data.Document.GetCharAt (pos - 1) == '*') isInBlockComment = false; } else if (!isInString && !isInChar && pos + 1 < max) { char nextChar = data.Document.GetCharAt (pos + 1); if (nextChar == '/') { outOffset = lastNonWsOffset; return true; } if (!isInLineComment && nextChar == '*') { outOffset = lastNonWsOffset; return true; } } break; case '\\': if (isInChar || (isInString && !isVerbatimString)) pos++; break; case '@': if (!(isInString || isInChar || isInLineComment || isInBlockComment) && pos + 1 < max && data.Document.GetCharAt (pos + 1) == '"') { isInString = true; isVerbatimString = true; pos++; } break; case '"': if (!(isInChar || isInLineComment || isInBlockComment)) { if (isInString && isVerbatimString && pos + 1 < max && data.Document.GetCharAt (pos + 1) == '"') { pos++; } else { isInString = !isInString; isVerbatimString = false; } } break; case '\'': if (!(isInString || isInLineComment || isInBlockComment)) isInChar = !isInChar; break; } if (!char.IsWhiteSpace (ch)) { firstChar = false; lastNonWsOffset = pos; lastNonWsChar = ch; } } // if the line ends with ';' the line end is not the correct place for a new semicolon. if (lastNonWsChar == ';') return false; outOffset = lastNonWsOffset; return true; }
public ExpressionContext FindExactContextForAsCompletion (TextEditorData editor, ICompilationUnit unit, string fileName, IType callingType) { // find expression on left hand side of the assignment int caretOffset = editor.Caret.Offset; int pos = -1; for (int i = caretOffset - 1; i >= 0; i--) { char ch = editor.GetCharAt (i); if (Char.IsWhiteSpace (ch)) continue; if (ch == '=') { pos = i; break; } if (!(Char.IsLetterOrDigit (ch) || ch == '_')) return null; } if (pos <= 0) return null; int lastWs = pos - 1; while (lastWs > 0 && Char.IsWhiteSpace (editor.GetCharAt (lastWs))) lastWs--; while (lastWs > 0 && !Char.IsWhiteSpace (editor.GetCharAt (lastWs))) lastWs--; ExpressionResult firstExprs = FindExpression (editor, lastWs); if (firstExprs.Expression != null) { IReturnType unresolvedReturnType = NRefactoryResolver.ParseReturnType (firstExprs); if (unresolvedReturnType != null) { IType resolvedType = projectContent.SearchType (unit, (INode)callingType ?? unit, unresolvedReturnType); return ExpressionContext.TypeDerivingFrom (resolvedType != null ? new DomReturnType (resolvedType) : null, unresolvedReturnType, true); } } ExpressionResult lhsExpr = FindExpression (editor, pos); if (lhsExpr.Expression != null) { NRefactoryResolver resolver = new NRefactoryResolver (projectContent, unit, ICSharpCode.NRefactory.SupportedLanguage.CSharp, editor, fileName); ResolveResult rr = resolver.Resolve (lhsExpr, new DomLocation (editor.Caret.Line, editor.Caret.Column)); //ResolveResult rr = ParserService.Resolve (lhsExpr, currentLine.LineNumber, pos, editor.FileName, editor.Text); if (rr != null && rr.ResolvedType != null) { ExpressionContext context; IType c; /* if (rr.ResolvedType.IsArrayReturnType) { // when creating an array, all classes deriving from the array's element type are allowed IReturnType elementType = rr.ResolvedType.CastToArrayReturnType().ArrayElementType; c = elementType != null ? dom.GetType (elementType) : null; context = ExpressionContext.TypeDerivingFrom(elementType, false); } else */ { // when creating a normal instance, all non-abstract classes deriving from the type // are allowed c = projectContent.GetType (rr.ResolvedType); context = ExpressionContext.TypeDerivingFrom (rr.ResolvedType, null, true); } if (c != null && !context.FilterEntry (c)) { // Try to suggest an entry (List<int> a = new => suggest List<int>). string suggestedClassName = null; /*LanguageProperties.CSharp.CodeGenerator.GenerateCode( CodeGenerator.ConvertType( rr.ResolvedType, new ClassFinder(ParserService.GetParseInformation(editor.FileName), editor.ActiveTextAreaControl.Caret.Line, editor.ActiveTextAreaControl.Caret.Column) ), "");*/ if (suggestedClassName != c.Name) { // create an IType instance that includes the type arguments in its name //context.DefaultItem = new RenamedClass (c, suggestedClassName); } else { context.DefaultItem = c; } } return context; } } return null; }
private InsertionPoint GetInsertionPoint(MonoDevelop.Ide.Gui.Document document, IType type) { data = document.Editor; if (data == null) { throw new System.ArgumentNullException ("data"); } var parsedDocument = document.ParsedDocument; if (parsedDocument == null) { throw new System.ArgumentNullException ("parsedDocument"); } if (type == null) { throw new System.ArgumentNullException ("type"); } type = (parsedDocument.CompilationUnit.GetTypeAt (type.Location) ?? type); DomRegion domRegion = type.BodyRegion; var start = type.BodyRegion.Start.Line; indent = data.GetLine(start).GetIndentation(data.Document); DomLocation domLocation = domRegion.End; int num = data.LocationToOffset (domLocation.Line, 1); while (num < data.Length && data.GetCharAt(num) != '}') { num++; } num++; DocumentLocation documentLocation = data.OffsetToLocation (num); LineSegment lineAfterClassEnd = data.GetLine (domLocation.Line + 1); NewLineInsertion lineAfter; if (lineAfterClassEnd != null && lineAfterClassEnd.EditableLength == lineAfterClassEnd.GetIndentation (data.Document).Length) lineAfter = NewLineInsertion.BlankLine; else lineAfter = NewLineInsertion.None; return new InsertionPoint (documentLocation, NewLineInsertion.None, lineAfter); }
public static void Left(TextEditorData data) { using (var undo = data.OpenUndoGroup()) { if (Platform.IsMac && data.IsSomethingSelected && !data.Caret.PreserveSelection) { data.Caret.Offset = System.Math.Min(data.SelectionAnchor, data.Caret.Offset); data.ClearSelection(); return; } if (data.Caret.Column > DocumentLocation.MinColumn) { DocumentLine line = data.Document.GetLine(data.Caret.Line); if (data.Caret.Column > line.Length + 1) { if (data.Caret.AllowCaretBehindLineEnd) { data.Caret.Column--; } else { data.Caret.Column = line.Length + 1; } } else { int offset = data.Caret.Offset - 1; bool foundFolding = false; foreach (var folding in data.Document.GetFoldingsFromOffset(offset).Where(f => f.IsCollapsed && f.Offset < offset)) { offset = System.Math.Min(offset, folding.Offset); foundFolding = true; } if (!foundFolding) { var layout = data.Parent?.TextViewMargin?.GetLayout(line); if (layout != null && data.Caret.Column < line.Length) { uint curIndex = 0, byteIndex = 0; int utf8ByteIndex = (int)layout.TranslateToUTF8Index((uint)(offset - line.Offset), ref curIndex, ref byteIndex); layout.Layout.GetCursorPos(utf8ByteIndex, out var strong_pos, out var weak_pos); if (strong_pos.X != weak_pos.X) { offset--; } } } data.Caret.Offset = offset; } } else if (data.Caret.Line > DocumentLocation.MinLine) { DocumentLine prevLine = data.Document.GetLine(data.Caret.Line - 1); var nextLocation = new DocumentLocation(data.Caret.Line - 1, prevLine.Length + 1); if (data.HasIndentationTracker && data.Options.IndentStyle == IndentStyle.Virtual && nextLocation.Column == DocumentLocation.MinColumn) { nextLocation = new DocumentLocation(data.Caret.Line - 1, data.GetVirtualIndentationColumn(nextLocation)); } data.Caret.Location = nextLocation; } var curOffset = data.Caret.Offset; if (curOffset > 0 && curOffset < data.Length && ((ushort)data.GetCharAt(curOffset) & LowSurrogateMarker) == LowSurrogateMarker) { data.Caret.Offset--; } } }