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);
        }
Пример #2
0
        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));
        }
Пример #3
0
//		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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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));
        }
Пример #6
0
        /// <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;
		}
Пример #10
0
 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;
		}
Пример #12
0
            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;
		}
Пример #16
0
        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);
        }
Пример #17
0
        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);
        }
Пример #18
0
        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;
		}
Пример #21
0
        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;
		}
Пример #24
0
        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;
        }
Пример #26
0
		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);
		}
Пример #28
0
        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;
		}
Пример #30
0
		/// <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 ();
		}