public static bool GuessSemicolonInsertionOffset(IReadonlyTextDocument data, MonoDevelop.Core.Text.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 ICSharpCode.NRefactory.CSharp.Completion.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 InsertionPoint GetInsertionPosition(IReadonlyTextDocument doc, int line, int column) { int bodyEndOffset = doc.LocationToOffset(line, column) + 1; var curLine = doc.GetLine(line); if (curLine != null) { if (bodyEndOffset < curLine.Offset + curLine.Length) { // case1: positition is somewhere inside the start line return(new InsertionPoint(new DocumentLocation(line, column + 1), NewLineInsertion.Eol, NewLineInsertion.BlankLine)); } } // -> if position is at line end check next line var nextLine = doc.GetLine(line + 1); if (nextLine == null) // check for 1 line case. { return(new InsertionPoint(new DocumentLocation(line, column + 1), NewLineInsertion.BlankLine, NewLineInsertion.BlankLine)); } for (int i = nextLine.Offset; i < nextLine.EndOffset; i++) { char ch = doc.GetCharAt(i); if (!char.IsWhiteSpace(ch)) { // case2: next line contains non ws chars. return(new InsertionPoint(new DocumentLocation(line + 1, 1), NewLineInsertion.Eol, NewLineInsertion.BlankLine)); } } var nextLine2 = doc.GetLine(line + 2); if (nextLine2 != null) { for (int i = nextLine2.Offset; i < nextLine2.EndOffset; i++) { char ch = doc.GetCharAt(i); if (!char.IsWhiteSpace(ch)) { // case3: one blank line return(new InsertionPoint(new DocumentLocation(line + 1, 1), NewLineInsertion.Eol, NewLineInsertion.Eol)); } } } // case4: more than 1 blank line return(new InsertionPoint(new DocumentLocation(line + 1, 1), NewLineInsertion.Eol, NewLineInsertion.None)); }
// public static void QueueQuickFixAnalysis (Document doc, TextLocation loc, CancellationToken token, Action<List<CodeAction>> callback) // { // var ext = doc.GetContent<MonoDevelop.AnalysisCore.Gui.ResultsEditorExtension> (); // var issues = ext != null ? ext.GetResultsAtOffset (doc.Editor.LocationToOffset (loc), token).OrderBy (r => r.Level).ToList () : new List<Result> (); // // ThreadPool.QueueUserWorkItem (delegate { // try { // var result = new List<CodeAction> (); // foreach (var r in issues) { // if (token.IsCancellationRequested) // return; // var fresult = r as FixableResult; // if (fresult == null) // continue; //// foreach (var action in FixOperationsHandler.GetActions (doc, fresult)) { //// result.Add (new AnalysisContextActionProvider.AnalysisCodeAction (action, r) { //// DocumentRegion = action.DocumentRegion //// }); //// } // } // result.AddRange (GetValidActions (doc, loc).Result); // callback (result); // } catch (Exception ex) { // LoggingService.LogError ("Error in analysis service", ex); // } // }); // } public static MonoDevelop.Ide.Editor.DocumentLocation GetCorrectResolveLocation(IReadonlyTextDocument editor, MonoDevelop.Ide.Editor.DocumentLocation location) { if (editor == null || location.Column == 1) { return(location); } /*if (editor is TextEditor) { * if (((TextEditor)editor).IsSomethingSelected) * return ((TextEditor)editor).SelectionRegion.Begin; * }*/ var line = editor.GetLine(location.Line); if (line == null || location.Column > line.LengthIncludingDelimiter) { return(location); } int offset = editor.LocationToOffset(location); if (offset > 0 && !char.IsLetterOrDigit(editor.GetCharAt(offset)) && char.IsLetterOrDigit(editor.GetCharAt(offset - 1))) { return(new MonoDevelop.Ide.Editor.DocumentLocation(location.Line, location.Column - 1)); } return(location); }
public static int GetMatchingBracketOffset(IReadonlyTextDocument document, int offset, CancellationToken cancellationToken = default(CancellationToken)) { if (offset < 0 || offset >= document.Length) { return(-1); } char ch = document.GetCharAt(offset); int bracket = openBrackets.IndexOf(ch); int result; if (bracket >= 0) { result = SearchMatchingBracketForward(document, offset + 1, closingBrackets [bracket], openBrackets [bracket], cancellationToken); } else { bracket = closingBrackets.IndexOf(ch); if (bracket >= 0 && offset > 0) { result = SearchMatchingBracketBackward(document, offset - 1, openBrackets [bracket], closingBrackets [bracket], cancellationToken); } else { result = -1; } } return(result); }
public PaketDependencyFileLineParseResult Parse(IReadonlyTextDocument document, int offset, int lastOffset) { parts = new List <PaketDependencyRulePart> (); int currentOffset = offset; while (currentOffset < lastOffset) { char currentChar = document.GetCharAt(currentOffset); if (currentChar == ' ') { currentOffset++; } else if (currentChar == '"') { currentOffset = ParseString(document, currentOffset, lastOffset); } else if (IsCommentCharacter(currentChar) && !parts.Any()) { return(PaketDependencyFileLineParseResult.CommentLine); } else { currentOffset = ParsePart(document, currentOffset, lastOffset); } } return(new PaketDependencyFileLineParseResult(parts, lastOffset)); }
/// <summary> /// This method gets the line indentation. /// </summary> /// <param name = "line"></param> /// <param name="doc"> /// The <see cref="IReadonlyTextDocument"/> the line belongs to. /// </param> /// <returns> /// The indentation of the line (all whitespace chars up to the first non ws char). /// </returns> public static string GetIndentation(this IDocumentLine line, IReadonlyTextDocument doc) { if (line == null) { throw new ArgumentNullException(nameof(line)); } if (doc == null) { throw new ArgumentNullException(nameof(doc)); } var result = new StringBuilder(); int offset = line.Offset; int max = Math.Min(offset + line.LengthIncludingDelimiter, doc.Length); for (int i = offset; i < max; i++) { char ch = doc.GetCharAt(i); if (ch != ' ' && ch != '\t') { break; } result.Append(ch); } return(result.ToString()); }
static bool IsBlankLine(IReadonlyTextDocument doc, IDocumentLine line) { for (int i = 0; i < line.Length; i++) { if (!Char.IsWhiteSpace(doc.GetCharAt(line.Offset + i))) { return(false); } } return(true); }
static bool IsSemicolonalreadyPlaced(IReadonlyTextDocument data, int caretOffset) { for (int pos2 = caretOffset - 1; pos2-- > 0;) { var ch2 = data.GetCharAt(pos2); if (ch2 == ';') { return(true); } if (!char.IsWhiteSpace(ch2)) { return(false); } } return(false); }
public static int GetMatchingBracketOffset (IReadonlyTextDocument document, int offset, CancellationToken cancellationToken = default(CancellationToken)) { if (offset < 0 || offset >= document.Length) return -1; char ch = document.GetCharAt (offset); int bracket = openBrackets.IndexOf (ch); int result; if (bracket >= 0) { result = SearchMatchingBracketForward (document, offset + 1, closingBrackets [bracket], openBrackets [bracket], cancellationToken); } else { bracket = closingBrackets.IndexOf (ch); if (bracket >= 0) { result = SearchMatchingBracketBackward (document, offset - 1, openBrackets [bracket], closingBrackets [bracket], cancellationToken); } else { result = -1; } } return result; }
static void CheckLine(IReadonlyTextDocument doc, IDocumentLine line, out bool isBlank, out bool isBracket) { isBlank = true; isBracket = false; for (int i = 0; i < line.LengthIncludingDelimiter; i++) { char c = doc.GetCharAt(line.Offset + i); if (c == '{') { isBracket = true; isBlank = false; } else if (!Char.IsWhiteSpace(c)) { isBlank = false; if (isBracket) { isBracket = false; break; } } } }
static bool IsSemicolonalreadyPlaced (IReadonlyTextDocument data, int caretOffset) { for (int pos2 = caretOffset - 1; pos2-- > 0;) { var ch2 = data.GetCharAt (pos2); if (ch2 == ';') { return true; } if (!char.IsWhiteSpace (ch2)) return false; } return false; }
static List <XObject> GetNodePath(XmlParser parser, IReadonlyTextDocument document) { int offset = parser.Position; var length = document.Length; int i = offset; var nodePath = parser.Nodes.ToList(); //if inside body of unclosed element, capture whole body if (parser.CurrentState is XmlRootState && parser.Nodes.Peek() is XElement unclosedEl) { while (i < length && InRootOrClosingTagState() && !unclosedEl.IsClosed) { parser.Push(document.GetCharAt(i++)); } } //if in potential start of a state, capture it else if (parser.CurrentState is XmlRootState && GetStateTag() > 0) { //eat until we figure out whether it's a state transition while (i < length && GetStateTag() > 0) { parser.Push(document.GetCharAt(i++)); } //if it transitioned to another state, eat until we get a new node on the stack if (NotInRootState()) { var newState = parser.CurrentState; while (i < length && NotInRootState() && parser.Nodes.Count <= nodePath.Count) { parser.Push(document.GetCharAt(i++)); } if (parser.Nodes.Count > nodePath.Count) { nodePath.Insert(0, parser.Nodes.Peek()); } } } //ensure any unfinished names are captured while (i < length && InNameOrAttributeState()) { parser.Push(document.GetCharAt(i++)); } //if nodes are incomplete, they won't get connected //HACK: the only way to reconnect them is reflection if (nodePath.Count > 1) { for (int idx = 0; idx < nodePath.Count - 1; idx++) { var node = nodePath [idx]; if (node.Parent == null) { var parent = nodePath [idx + 1]; node.Parent = parent; } } } return(nodePath); bool InNameOrAttributeState() => parser.CurrentState is XmlNameState || parser.CurrentState is XmlAttributeState || parser.CurrentState is XmlAttributeValueState; bool InRootOrClosingTagState() => parser.CurrentState is XmlRootState || parser.CurrentState is XmlNameState || parser.CurrentState is XmlClosingTagState; int GetStateTag() => ((IXmlParserContext)parser).StateTag; bool NotInRootState() => !(parser.CurrentState is XmlRootState); }
// public static void QueueQuickFixAnalysis (Document doc, TextLocation loc, CancellationToken token, Action<List<CodeAction>> callback) // { // var ext = doc.GetContent<MonoDevelop.AnalysisCore.Gui.ResultsEditorExtension> (); // var issues = ext != null ? ext.GetResultsAtOffset (doc.Editor.LocationToOffset (loc), token).OrderBy (r => r.Level).ToList () : new List<Result> (); // // ThreadPool.QueueUserWorkItem (delegate { // try { // var result = new List<CodeAction> (); // foreach (var r in issues) { // if (token.IsCancellationRequested) // return; // var fresult = r as FixableResult; // if (fresult == null) // continue; //// foreach (var action in FixOperationsHandler.GetActions (doc, fresult)) { //// result.Add (new AnalysisContextActionProvider.AnalysisCodeAction (action, r) { //// DocumentRegion = action.DocumentRegion //// }); //// } // } // result.AddRange (GetValidActions (doc, loc).Result); // callback (result); // } catch (Exception ex) { // LoggingService.LogError ("Error in analysis service", ex); // } // }); // } public static MonoDevelop.Ide.Editor.DocumentLocation GetCorrectResolveLocation (IReadonlyTextDocument editor, MonoDevelop.Ide.Editor.DocumentLocation location) { if (editor == null || location.Column == 1) return location; /*if (editor is TextEditor) { if (((TextEditor)editor).IsSomethingSelected) return ((TextEditor)editor).SelectionRegion.Begin; }*/ var line = editor.GetLine (location.Line); if (line == null || location.Column > line.LengthIncludingDelimiter) return location; int offset = editor.LocationToOffset (location); if (offset > 0 && !char.IsLetterOrDigit (editor.GetCharAt (offset)) && char.IsLetterOrDigit (editor.GetCharAt (offset - 1))) return new MonoDevelop.Ide.Editor.DocumentLocation (location.Line, location.Column - 1); return location; }
static int SearchMatchingBracketForward (IReadonlyTextDocument document, int offset, char openBracket, char closingBracket, CancellationToken cancellationToken) { bool isInBlockComment = false; bool isInLineComment = false; int curStringQuote = -1; bool startsInLineComment = StartsInLineComment (document, offset); var lineComments = GetList (document, "LineComment"); var blockCommentStarts = GetList (document, "BlockCommentStart"); var blockCommentEnds = GetList (document, "BlockCommentEnd"); var stringQuotes = GetList (document, "StringQuote"); int depth = -1; while (offset >= 0 && offset < document.Length) { if (offset % 100 == 0 && cancellationToken.IsCancellationRequested) return -1; if (curStringQuote < 0) { // check line comments if (!isInBlockComment && !isInLineComment) isInLineComment = StartsWithListMember (document, lineComments, offset) >= 0; // check block comments if (!isInLineComment) { if (!isInBlockComment) { isInBlockComment = StartsWithListMember (document, blockCommentStarts, offset) >= 0; } else { isInBlockComment = StartsWithListMember (document, blockCommentEnds, offset) < 0; } } } if (!isInBlockComment && !isInLineComment) { int i = StartsWithListMember (document, stringQuotes, offset); if (i >= 0) { if (curStringQuote >= 0) { if (curStringQuote == i) curStringQuote = -1; } else { curStringQuote = i; } } } char ch = document.GetCharAt (offset); switch (ch) { case '\n': case '\r': if (startsInLineComment) return -1; isInLineComment = false; break; default: if (ch == closingBracket) { if (!(isInLineComment || curStringQuote >= 0 || isInBlockComment)) --depth; } else if (ch == openBracket) { if (!(isInLineComment || curStringQuote >= 0 || isInBlockComment)) { ++depth; if (depth == 0) return offset; } } break; } offset++; } return -1; }
static int SearchMatchingBracketBackward (IReadonlyTextDocument document, int offset, char openBracket, char closingBracket, CancellationToken cancellationToken) { bool isInBlockComment = false; bool isInLineComment = false; int curStringQuote = -1; IList<string> blockCommentStarts = GetList (document, "BlockCommentStart"); IList<string> blockCommentEnds = GetList (document, "BlockCommentEnd"); IList<string> stringQuotes = GetList (document, "StringQuote"); bool startsInLineComment = StartsInLineComment (document, offset); int depth = -1; if (!startsInLineComment) offset = GetLastSourceCodePosition (document, offset); while (offset >= 0 && offset < document.Length) { if (offset % 100 == 0 && cancellationToken.IsCancellationRequested) return -1; char ch = document.GetCharAt (offset); // check block comments if (!isInLineComment && curStringQuote < 0) { if (!isInBlockComment) { isInBlockComment = StartsWithListMember (document, blockCommentEnds, offset) >= 0; } else { isInBlockComment = StartsWithListMember (document, blockCommentStarts, offset) < 0; } } if (!isInBlockComment && !isInLineComment) { int i = StartsWithListMember (document, stringQuotes, offset); if (i >= 0) { if (curStringQuote >= 0) { if (curStringQuote == i) curStringQuote = -1; } else { curStringQuote = i; } } } switch (ch) { case '\n': case '\r': if (startsInLineComment) return -1; offset--; while (offset > 0 && (document.GetCharAt (offset) == '\n' || document.GetCharAt (offset) == '\r')) { offset--; } offset = GetLastSourceCodePosition (document, offset) + 1; break; default: if (ch == closingBracket) { if (!(curStringQuote >= 0 || isInBlockComment)) --depth; } else if (ch == openBracket) { if (!(curStringQuote >= 0 || isInBlockComment)) { ++depth; if (depth == 0) return offset; } } break; } offset--; } return -1; }
static int SearchMatchingBracket(IReadonlyTextDocument 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); }
static int SearchMatchingBracketBackward(IReadonlyTextDocument document, int offset, char openBracket, char closingBracket, CancellationToken cancellationToken) { bool isInBlockComment = false; bool isInLineComment = false; int curStringQuote = -1; IList <string> blockCommentStarts = GetList(document, "BlockCommentStart"); IList <string> blockCommentEnds = GetList(document, "BlockCommentEnd"); IList <string> stringQuotes = GetList(document, "StringQuote"); bool startsInLineComment = StartsInLineComment(document, offset); int depth = -1; if (!startsInLineComment) { offset = GetLastSourceCodePosition(document, offset); } while (offset >= 0 && offset < document.Length) { if (offset % 100 == 0 && cancellationToken.IsCancellationRequested) { return(-1); } char ch = document.GetCharAt(offset); // check block comments if (!isInLineComment && curStringQuote < 0) { if (!isInBlockComment) { isInBlockComment = StartsWithListMember(document, blockCommentEnds, offset) >= 0; } else { isInBlockComment = StartsWithListMember(document, blockCommentStarts, offset) < 0; } } if (!isInBlockComment && !isInLineComment) { int i = StartsWithListMember(document, stringQuotes, offset); if (i >= 0) { if (curStringQuote >= 0) { if (curStringQuote == i) { curStringQuote = -1; } } else { curStringQuote = i; } } } switch (ch) { case '\n': case '\r': if (startsInLineComment) { return(-1); } offset--; while (offset > 0 && (document.GetCharAt(offset) == '\n' || document.GetCharAt(offset) == '\r')) { offset--; } offset = GetLastSourceCodePosition(document, offset) + 1; break; default: if (ch == closingBracket) { if (!(curStringQuote >= 0 || isInBlockComment)) { --depth; } } else if (ch == openBracket) { if (!(curStringQuote >= 0 || isInBlockComment)) { ++depth; if (depth == 0) { return(offset); } } } break; } offset--; } return(-1); }
static List <InsertionPoint> GetInsertionPoints(IReadonlyTextDocument data, ITypeSymbol type, List <InsertionPoint> result, TextSpan sourceSpan, SyntaxReference declaringType) { var openBraceToken = declaringType.GetSyntax().ChildTokens().FirstOrDefault(t => t.IsKind(SyntaxKind.OpenBraceToken)); if (!openBraceToken.IsMissing) { var domLocation = data.OffsetToLocation(openBraceToken.SpanStart); result.Add(GetInsertionPosition(data, domLocation.Line, domLocation.Column)); // result.Add (GetInsertionPosition (data, realStartLocation.Line, realStartLocation.Column)); result [0].LineBefore = NewLineInsertion.None; } foreach (var member in type.GetMembers()) { if (member.IsImplicitlyDeclared || !member.IsDefinedInSource()) { continue; } //var domLocation = member.BodyRegion.End; foreach (var loc in member.DeclaringSyntaxReferences) { if (loc.SyntaxTree.FilePath != declaringType.SyntaxTree.FilePath || !declaringType.Span.Contains(sourceSpan)) { continue; } var domLocation = data.OffsetToLocation(loc.Span.End); if (domLocation.Line <= 0) { var lineSegment = data.GetLineByOffset(loc.Span.Start); if (lineSegment == null) { continue; } domLocation = new DocumentLocation(lineSegment.LineNumber, lineSegment.Length + 1); } result.Add(GetInsertionPosition(data, domLocation.Line, domLocation.Column)); break; } } result [result.Count - 1].LineAfter = NewLineInsertion.None; CheckStartPoint(data, result [0], result.Count == 1); if (result.Count > 1) { result.RemoveAt(result.Count - 1); NewLineInsertion insertLine; var typeSyntaxReference = type.DeclaringSyntaxReferences.FirstOrDefault(r => r.SyntaxTree.FilePath == data.FileName && r.Span.Contains(sourceSpan)); var lineBefore = data.GetLineByOffset(typeSyntaxReference.Span.End).PreviousLine; if (lineBefore != null && lineBefore.Length == lineBefore.GetIndentation(data).Length) { insertLine = NewLineInsertion.None; } else { insertLine = NewLineInsertion.Eol; } // search for line start var line = data.GetLineByOffset(typeSyntaxReference.Span.End); int col = typeSyntaxReference.Span.End - line.Offset; if (line != null) { var lineOffset = line.Offset; col = Math.Min(line.Length, col); while (lineOffset + col - 2 >= 0 && col > 1 && char.IsWhiteSpace(data.GetCharAt(lineOffset + col - 2))) { col--; } } result.Add(new InsertionPoint(new DocumentLocation(line.LineNumber, col), insertLine, NewLineInsertion.Eol)); CheckEndPoint(data, 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)); //foreach (var res in result) // Console.WriteLine (res); return(result); }
static void CheckLine (IReadonlyTextDocument doc, IDocumentLine line, out bool isBlank, out bool isBracket) { isBlank = true; isBracket = false; for (int i = 0; i < line.LengthIncludingDelimiter; i++) { char c = doc.GetCharAt (line.Offset + i); if (c == '{') { isBracket = true; isBlank = false; } else if (!Char.IsWhiteSpace (c)) { isBlank = false; if (isBracket) { isBracket = false; break; } } } }
static bool IsBlankLine (IReadonlyTextDocument doc, IDocumentLine line) { for (int i = 0; i < line.Length; i++) { if (!Char.IsWhiteSpace (doc.GetCharAt (line.Offset + i))) return false; } return true; }
static int SearchMatchingBracketForward(IReadonlyTextDocument document, int offset, char openBracket, char closingBracket, CancellationToken cancellationToken) { bool isInBlockComment = false; bool isInLineComment = false; int curStringQuote = -1; bool startsInLineComment = StartsInLineComment(document, offset); var lang = TextMateLanguage.Create(SyntaxHighlightingService.GetScopeForFileName(document.FileName)); var lineComments = lang.LineComments.ToArray(); var blockCommentStarts = lang.BlockComments.Select(b => b.Item1).ToList(); var blockCommentEnds = lang.BlockComments.Select(b => b.Item2).ToList(); var stringQuotes = new string [] { "\"", "'" }; int depth = -1; while (offset >= 0 && offset < document.Length) { if (offset % 100 == 0 && cancellationToken.IsCancellationRequested) { return(-1); } if (curStringQuote < 0) { // check line comments if (!isInBlockComment && !isInLineComment) { isInLineComment = StartsWithListMember(document, lineComments, offset) >= 0; } // check block comments if (!isInLineComment) { if (!isInBlockComment) { isInBlockComment = StartsWithListMember(document, blockCommentStarts, offset) >= 0; } else { isInBlockComment = StartsWithListMember(document, blockCommentEnds, offset) < 0; } } } if (!isInBlockComment && !isInLineComment) { int i = StartsWithListMember(document, stringQuotes, offset); if (i >= 0) { if (curStringQuote >= 0) { if (curStringQuote == i) { curStringQuote = -1; } } else { curStringQuote = i; } } } char ch = document.GetCharAt(offset); switch (ch) { case '\n': case '\r': if (startsInLineComment) { return(-1); } isInLineComment = false; break; default: if (ch == closingBracket) { if (!(isInLineComment || curStringQuote >= 0 || isInBlockComment)) { --depth; } } else if (ch == openBracket) { if (!(isInLineComment || curStringQuote >= 0 || isInBlockComment)) { ++depth; if (depth == 0) { return(offset); } } } break; } offset++; } return(-1); }
public static List<InsertionPoint> GetInsertionPoints (IReadonlyTextDocument data, MonoDevelop.Ide.TypeSystem.ParsedDocument parsedDocument, ITypeSymbol type, int part) { if (data == null) throw new ArgumentNullException (nameof (data)); if (parsedDocument == null) throw new ArgumentNullException (nameof (parsedDocument)); if (type == null) throw new ArgumentNullException (nameof (type)); if (!type.IsDefinedInSource ()) throw new ArgumentException ("The given type needs to be defined in source code.", nameof (type)); // update type from parsed document, since this is always newer. //type = parsedDocument.GetInnermostTypeDefinition (type.GetLocation ()) ?? type; List<InsertionPoint> result = new List<InsertionPoint> (); //var realStartLocation = data.OffsetToLocation (offset); var model = parsedDocument.GetAst<SemanticModel> (); type = model.GetEnclosingNamedType (part, default(CancellationToken)) as ITypeSymbol ?? type; var sourceSpan = new TextSpan (part, 0); var filePath = data.FileName; var declaringType = type.DeclaringSyntaxReferences.FirstOrDefault (dsr => dsr.SyntaxTree.FilePath == filePath && dsr.Span.Contains (sourceSpan)) ?? type.DeclaringSyntaxReferences.FirstOrDefault (); if (declaringType == null) return result; var openBraceToken = declaringType.GetSyntax ().ChildTokens ().FirstOrDefault (t => t.IsKind (SyntaxKind.OpenBraceToken)); if (!openBraceToken.IsMissing) { var domLocation = data.OffsetToLocation (openBraceToken.SpanStart); result.Add (GetInsertionPosition (data, domLocation.Line, domLocation.Column)); // result.Add (GetInsertionPosition (data, realStartLocation.Line, realStartLocation.Column)); result [0].LineBefore = NewLineInsertion.None; } foreach (var member in type.GetMembers ()) { if (member.IsImplicitlyDeclared || !member.IsDefinedInSource()) continue; //var domLocation = member.BodyRegion.End; foreach (var loc in member.DeclaringSyntaxReferences) { if (loc.SyntaxTree.FilePath != declaringType.SyntaxTree.FilePath || !declaringType.Span.Contains (sourceSpan)) continue; var domLocation = data.OffsetToLocation (loc.Span.End); if (domLocation.Line <= 0) { var lineSegment = data.GetLineByOffset (loc.Span.Start); if (lineSegment == null) continue; domLocation = new DocumentLocation (lineSegment.LineNumber, lineSegment.Length + 1); } result.Add (GetInsertionPosition (data, domLocation.Line, domLocation.Column)); break; } } result [result.Count - 1].LineAfter = NewLineInsertion.None; CheckStartPoint (data, result [0], result.Count == 1); if (result.Count > 1) { result.RemoveAt (result.Count - 1); NewLineInsertion insertLine; var typeSyntaxReference = type.DeclaringSyntaxReferences.FirstOrDefault (r => r.Span.Contains (sourceSpan)); var lineBefore = data.GetLineByOffset (typeSyntaxReference.Span.End).PreviousLine; if (lineBefore != null && lineBefore.Length == lineBefore.GetIndentation (data).Length) { insertLine = NewLineInsertion.None; } else { insertLine = NewLineInsertion.Eol; } // search for line start var line = data.GetLineByOffset (typeSyntaxReference.Span.End); int col = typeSyntaxReference.Span.End - line.Offset; if (line != null) { var lineOffset = line.Offset; col = Math.Min (line.Length, col); while (lineOffset + col - 2 >= 0 && col > 1 && char.IsWhiteSpace (data.GetCharAt (lineOffset + col - 2))) col--; } result.Add (new InsertionPoint (new DocumentLocation (line.LineNumber, col), insertLine, NewLineInsertion.Eol)); CheckEndPoint (data, 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)); //foreach (var res in result) // Console.WriteLine (res); return result; }
public static bool GuessSemicolonInsertionOffset (IReadonlyTextDocument data, MonoDevelop.Core.Text.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 ICSharpCode.NRefactory.CSharp.Completion.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; }
public static List <InsertionPoint> GetInsertionPoints(IReadonlyTextDocument data, MonoDevelop.Ide.TypeSystem.ParsedDocument parsedDocument, ITypeSymbol type, int part) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (parsedDocument == null) { throw new ArgumentNullException(nameof(parsedDocument)); } if (type == null) { throw new ArgumentNullException(nameof(type)); } if (!type.IsDefinedInSource()) { throw new ArgumentException("The given type needs to be defined in source code.", nameof(type)); } // update type from parsed document, since this is always newer. //type = parsedDocument.GetInnermostTypeDefinition (type.GetLocation ()) ?? type; List <InsertionPoint> result = new List <InsertionPoint> (); //var realStartLocation = data.OffsetToLocation (offset); var model = parsedDocument.GetAst <SemanticModel> (); type = model.GetEnclosingNamedType(part, default(CancellationToken)) as ITypeSymbol ?? type; var sourceSpan = new TextSpan(part, 0); var filePath = data.FileName; var declaringType = type.DeclaringSyntaxReferences.FirstOrDefault(dsr => dsr.SyntaxTree.FilePath == filePath && dsr.Span.Contains(sourceSpan)) ?? type.DeclaringSyntaxReferences.FirstOrDefault(); if (declaringType == null) { return(result); } var openBraceToken = declaringType.GetSyntax().ChildTokens().FirstOrDefault(t => t.IsKind(SyntaxKind.OpenBraceToken)); if (!openBraceToken.IsMissing) { var domLocation = data.OffsetToLocation(openBraceToken.SpanStart); result.Add(GetInsertionPosition(data, domLocation.Line, domLocation.Column)); // result.Add (GetInsertionPosition (data, realStartLocation.Line, realStartLocation.Column)); result [0].LineBefore = NewLineInsertion.None; } foreach (var member in type.GetMembers()) { if (member.IsImplicitlyDeclared || !member.IsDefinedInSource()) { continue; } //var domLocation = member.BodyRegion.End; foreach (var loc in member.DeclaringSyntaxReferences) { if (loc.SyntaxTree.FilePath != declaringType.SyntaxTree.FilePath || !declaringType.Span.Contains(sourceSpan)) { continue; } var domLocation = data.OffsetToLocation(loc.Span.End); if (domLocation.Line <= 0) { var lineSegment = data.GetLineByOffset(loc.Span.Start); if (lineSegment == null) { continue; } domLocation = new DocumentLocation(lineSegment.LineNumber, lineSegment.Length + 1); } result.Add(GetInsertionPosition(data, domLocation.Line, domLocation.Column)); break; } } result [result.Count - 1].LineAfter = NewLineInsertion.None; CheckStartPoint(data, result [0], result.Count == 1); if (result.Count > 1) { result.RemoveAt(result.Count - 1); NewLineInsertion insertLine; var typeSyntaxReference = type.DeclaringSyntaxReferences.FirstOrDefault(r => r.Span.Contains(sourceSpan)); var lineBefore = data.GetLineByOffset(typeSyntaxReference.Span.End).PreviousLine; if (lineBefore != null && lineBefore.Length == lineBefore.GetIndentation(data).Length) { insertLine = NewLineInsertion.None; } else { insertLine = NewLineInsertion.Eol; } // search for line start var line = data.GetLineByOffset(typeSyntaxReference.Span.End); int col = typeSyntaxReference.Span.End - line.Offset; if (line != null) { var lineOffset = line.Offset; col = Math.Min(line.Length, col); while (lineOffset + col - 2 >= 0 && col > 1 && char.IsWhiteSpace(data.GetCharAt(lineOffset + col - 2))) { col--; } } result.Add(new InsertionPoint(new DocumentLocation(line.LineNumber, col), insertLine, NewLineInsertion.Eol)); CheckEndPoint(data, 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)); //foreach (var res in result) // Console.WriteLine (res); return(result); }
public static MSBuildResolveResult Resolve( XmlParser parser, IReadonlyTextDocument document, MSBuildDocument context) { int offset = parser.Position; //clones and connects nodes to their parents parser = parser.GetTreeParser(); var nodePath = parser.Nodes.ToList(); nodePath.Reverse(); //capture incomplete names, attributes and element values int i = offset; if (parser.CurrentState is XmlRootState && parser.Nodes.Peek() is XElement unclosedEl) { while (i < document.Length && InRootOrClosingTagState() && !unclosedEl.IsClosed) { parser.Push(document.GetCharAt(i++)); } } else { while (i < document.Length && InNameOrAttributeState()) { parser.Push(document.GetCharAt(i++)); } } //if nodes are incomplete, they won't get connected //HACK: the only way to reconnect them is reflection if (nodePath.Count > 1) { for (int idx = 1; idx < nodePath.Count; idx++) { var node = nodePath [idx]; if (node.Parent == null) { var parent = nodePath [idx - 1]; ParentProp.SetValue(node, parent); } } } //need to look up element by walking how the path, since at each level, if the parent has special children, //then that gives us information to identify the type of its children MSBuildLanguageElement languageElement = null; MSBuildLanguageAttribute languageAttribute = null; XElement el = null; XAttribute att = null; foreach (var node in nodePath) { if (node is XAttribute xatt && xatt.Name.Prefix == null) { att = xatt; languageAttribute = languageElement?.GetAttribute(att.Name.Name); break; } //if children of parent is known to be arbitrary data, don't go into it if (languageElement != null && languageElement.ValueKind == MSBuildValueKind.Data) { break; } //code completion is forgiving, all we care about best guess resolve for deepest child if (node is XElement xel && xel.Name.Prefix == null) { el = xel; languageElement = MSBuildLanguageElement.Get(el.Name.Name, languageElement); if (languageElement != null) { continue; } } languageElement = null; } if (languageElement == null) { return(null); } var rr = new MSBuildResolveResult { LanguageElement = languageElement, LanguageAttribute = languageAttribute, XElement = el, XAttribute = att }; var rv = new MSBuildResolveVisitor(offset, rr); rv.Run(el, languageElement, document.FileName, document, context); return(rr); bool InNameOrAttributeState() => parser.CurrentState is XmlNameState || parser.CurrentState is XmlAttributeState || parser.CurrentState is XmlAttributeValueState; bool InRootOrClosingTagState() => parser.CurrentState is XmlRootState || parser.CurrentState is XmlNameState || parser.CurrentState is XmlClosingTagState; }
static int SearchMatchingBracket (IReadonlyTextDocument 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; }
static InsertionPoint GetInsertionPosition (IReadonlyTextDocument doc, int line, int column) { int bodyEndOffset = doc.LocationToOffset (line, column) + 1; var curLine = doc.GetLine (line); if (curLine != null) { if (bodyEndOffset < curLine.Offset + curLine.Length) { // case1: positition is somewhere inside the start line return new InsertionPoint (new DocumentLocation (line, column + 1), NewLineInsertion.Eol, NewLineInsertion.BlankLine); } } // -> if position is at line end check next line var nextLine = doc.GetLine (line + 1); if (nextLine == null) // check for 1 line case. return new InsertionPoint (new DocumentLocation (line, column + 1), NewLineInsertion.BlankLine, NewLineInsertion.BlankLine); for (int i = nextLine.Offset; i < nextLine.EndOffset; i++) { char ch = doc.GetCharAt (i); if (!char.IsWhiteSpace (ch)) { // case2: next line contains non ws chars. return new InsertionPoint (new DocumentLocation (line + 1, 1), NewLineInsertion.Eol, NewLineInsertion.BlankLine); } } var nextLine2 = doc.GetLine (line + 2); if (nextLine2 != null) { for (int i = nextLine2.Offset; i < nextLine2.EndOffset; i++) { char ch = doc.GetCharAt (i); if (!char.IsWhiteSpace (ch)) { // case3: one blank line return new InsertionPoint (new DocumentLocation (line + 1, 1), NewLineInsertion.Eol, NewLineInsertion.Eol); } } } // case4: more than 1 blank line return new InsertionPoint (new DocumentLocation (line + 1, 1), NewLineInsertion.Eol, NewLineInsertion.None); }
static int SearchMatchingBracketForward(IReadonlyTextDocument document, int offset, char openBracket, char closingBracket, CancellationToken cancellationToken) { bool isInBlockComment = false; bool isInLineComment = false; int curStringQuote = -1; bool startsInLineComment = StartsInLineComment(document, offset); var lineComments = GetList(document, "LineComment"); var blockCommentStarts = GetList(document, "BlockCommentStart"); var blockCommentEnds = GetList(document, "BlockCommentEnd"); var stringQuotes = GetList(document, "StringQuote"); int depth = -1; while (offset >= 0 && offset < document.Length) { if (offset % 100 == 0 && cancellationToken.IsCancellationRequested) { return(-1); } if (curStringQuote < 0) { // check line comments if (!isInBlockComment && !isInLineComment) { isInLineComment = StartsWithListMember(document, lineComments, offset) >= 0; } // check block comments if (!isInLineComment) { if (!isInBlockComment) { isInBlockComment = StartsWithListMember(document, blockCommentStarts, offset) >= 0; } else { isInBlockComment = StartsWithListMember(document, blockCommentEnds, offset) < 0; } } } if (!isInBlockComment && !isInLineComment) { int i = StartsWithListMember(document, stringQuotes, offset); if (i >= 0) { if (curStringQuote >= 0) { if (curStringQuote == i) { curStringQuote = -1; } } else { curStringQuote = i; } } } char ch = document.GetCharAt(offset); switch (ch) { case '\n': case '\r': if (startsInLineComment) { return(-1); } isInLineComment = false; break; default: if (ch == closingBracket) { if (!(isInLineComment || curStringQuote >= 0 || isInBlockComment)) { --depth; } } else if (ch == openBracket) { if (!(isInLineComment || curStringQuote >= 0 || isInBlockComment)) { ++depth; if (depth == 0) { return(offset); } } } break; } offset++; } return(-1); }
static List<InsertionPoint> GetInsertionPoints (IReadonlyTextDocument data, ITypeSymbol type, List<InsertionPoint> result, TextSpan sourceSpan, SyntaxReference declaringType) { var openBraceToken = declaringType.GetSyntax ().ChildTokens ().FirstOrDefault (t => t.IsKind (SyntaxKind.OpenBraceToken)); if (!openBraceToken.IsMissing) { var domLocation = data.OffsetToLocation (openBraceToken.SpanStart); result.Add (GetInsertionPosition (data, domLocation.Line, domLocation.Column)); // result.Add (GetInsertionPosition (data, realStartLocation.Line, realStartLocation.Column)); result [0].LineBefore = NewLineInsertion.None; } foreach (var member in type.GetMembers ()) { if (member.IsImplicitlyDeclared || !member.IsDefinedInSource ()) continue; //var domLocation = member.BodyRegion.End; foreach (var loc in member.DeclaringSyntaxReferences) { if (loc.SyntaxTree.FilePath != declaringType.SyntaxTree.FilePath || !declaringType.Span.Contains (sourceSpan)) continue; var domLocation = data.OffsetToLocation (loc.Span.End); if (domLocation.Line <= 0) { var lineSegment = data.GetLineByOffset (loc.Span.Start); if (lineSegment == null) continue; domLocation = new DocumentLocation (lineSegment.LineNumber, lineSegment.Length + 1); } result.Add (GetInsertionPosition (data, domLocation.Line, domLocation.Column)); break; } } result [result.Count - 1].LineAfter = NewLineInsertion.None; CheckStartPoint (data, result [0], result.Count == 1); if (result.Count > 1) { result.RemoveAt (result.Count - 1); NewLineInsertion insertLine; var typeSyntaxReference = type.DeclaringSyntaxReferences.FirstOrDefault (r => r.Span.Contains (sourceSpan)); var lineBefore = data.GetLineByOffset (typeSyntaxReference.Span.End).PreviousLine; if (lineBefore != null && lineBefore.Length == lineBefore.GetIndentation (data).Length) { insertLine = NewLineInsertion.None; } else { insertLine = NewLineInsertion.Eol; } // search for line start var line = data.GetLineByOffset (typeSyntaxReference.Span.End); int col = typeSyntaxReference.Span.End - line.Offset; if (line != null) { var lineOffset = line.Offset; col = Math.Min (line.Length, col); while (lineOffset + col - 2 >= 0 && col > 1 && char.IsWhiteSpace (data.GetCharAt (lineOffset + col - 2))) col--; } result.Add (new InsertionPoint (new DocumentLocation (line.LineNumber, col), insertLine, NewLineInsertion.Eol)); CheckEndPoint (data, 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)); //foreach (var res in result) // Console.WriteLine (res); return result; }
/// <summary> /// This method gets the line indentation. /// </summary> /// <param name = "line"></param> /// <param name="doc"> /// The <see cref="IReadonlyTextDocument"/> the line belongs to. /// </param> /// <returns> /// The indentation of the line (all whitespace chars up to the first non ws char). /// </returns> public static string GetIndentation (this IDocumentLine line, IReadonlyTextDocument doc) { var result = new StringBuilder (); int offset = line.Offset; int max = Math.Min (offset + line.LengthIncludingDelimiter, doc.Length); for (int i = offset; i < max; i++) { char ch = doc.GetCharAt (i); if (ch != ' ' && ch != '\t') break; result.Append (ch); } return result.ToString (); }