Esempio n. 1
0
 private static void TestIsEmpty(SourceText text)
 {
     Assert.Equal(0, text.Length);
     Assert.Same(string.Empty, text.ToString());
     Assert.Equal(1, text.Lines.Count);
     Assert.Equal(0, text.Lines[0].Span.Length);
 }
        private ImmutableArray<CompletionItem> GetItems(SourceText text, Document document, int position, CompletionTrigger triggerInfo, CancellationToken cancellationToken)
        {
            var line = text.Lines.GetLineFromPosition(position);
            var lineText = text.ToString(TextSpan.FromBounds(line.Start, position));
            var match = s_directiveRegex.Match(lineText);
            if (!match.Success)
            {
                return ImmutableArray<CompletionItem>.Empty;
            }

            var quotedPathGroup = match.Groups[1];
            var quotedPath = quotedPathGroup.Value;
            var endsWithQuote = PathCompletionUtilities.EndsWithQuote(quotedPath);
            if (endsWithQuote && (position >= line.Start + match.Length))
            {
                return ImmutableArray<CompletionItem>.Empty;
            }

            var buffer = text.Container.GetTextBuffer();
            var snapshot = text.FindCorrespondingEditorTextSnapshot();
            if (snapshot == null)
            {
                return ImmutableArray<CompletionItem>.Empty;
            }

            var fileSystem = CurrentWorkingDirectoryDiscoveryService.GetService(snapshot);

            // TODO: https://github.com/dotnet/roslyn/issues/5263
            // Avoid dependency on a specific resolver.
            // The search paths should be provided by specialized workspaces:
            // - InteractiveWorkspace for interactive window 
            // - ScriptWorkspace for loose .csx files (we don't have such workspace today)
            var searchPaths = (document.Project.CompilationOptions.SourceReferenceResolver as SourceFileResolver)?.SearchPaths ?? ImmutableArray<string>.Empty;

            var helper = new FileSystemCompletionHelper(
                this,
                GetTextChangeSpan(text, position, quotedPathGroup),
                fileSystem,
                Glyph.OpenFolder,
                Glyph.CSharpFile,
                searchPaths: searchPaths,
                allowableExtensions: new[] { ".csx" },
                itemRules: s_rules);

            var pathThroughLastSlash = this.GetPathThroughLastSlash(text, position, quotedPathGroup);

            return helper.GetItems(pathThroughLastSlash, documentPath: null);
        }
        private void TestTemporaryStorage(ITemporaryStorageService temporaryStorageService, SourceText text)
        {
            // create a temporary storage location
            var temporaryStorage = temporaryStorageService.CreateTemporaryTextStorage(System.Threading.CancellationToken.None);

            // write text into it
            temporaryStorage.WriteTextAsync(text).Wait();

            // read text back from it
            var text2 = temporaryStorage.ReadTextAsync().Result;

            Assert.NotSame(text, text2);
            Assert.Equal(text.ToString(), text2.ToString());

            temporaryStorage.Dispose();
        }
        private ImmutableArray<CompletionItem> GetItems(SourceText text, int position, CompletionTriggerInfo triggerInfo, CancellationToken cancellationToken)
        {
            var line = text.Lines.GetLineFromPosition(position);
            var lineText = text.ToString(TextSpan.FromBounds(line.Start, position));
            var match = s_directiveRegex.Match(lineText);
            if (!match.Success)
            {
                return ImmutableArray<CompletionItem>.Empty;
            }

            var quotedPathGroup = match.Groups[1];
            var quotedPath = quotedPathGroup.Value;
            var endsWithQuote = PathCompletionUtilities.EndsWithQuote(quotedPath);
            if (endsWithQuote && (position >= line.Start + match.Length))
            {
                return ImmutableArray<CompletionItem>.Empty;
            }

            var buffer = text.Container.GetTextBuffer();
            var snapshot = text.FindCorrespondingEditorTextSnapshot();
            if (snapshot == null)
            {
                return ImmutableArray<CompletionItem>.Empty;
            }

            var fileSystem = PathCompletionUtilities.GetCurrentWorkingDirectoryDiscoveryService(snapshot);

            var searchPaths = ImmutableArray.Create<string>(fileSystem.CurrentDirectory);

            var helper = new FileSystemCompletionHelper(
                this,
                GetTextChangeSpan(text, position, quotedPathGroup),
                fileSystem,
                Glyph.OpenFolder,
                Glyph.CSharpFile,
                searchPaths: searchPaths,
                allowableExtensions: new[] { ".csx" },
                itemRules: ItemRules.Instance);

            var pathThroughLastSlash = this.GetPathThroughLastSlash(text, position, quotedPathGroup);

            return helper.GetItems(pathThroughLastSlash, documentPath: null);
        }
        private static TextChange FixDiagnostic(IndentationOptions indentationOptions, SourceText sourceText, Diagnostic diagnostic)
        {
            TextSpan span = diagnostic.Location.SourceSpan;

            TextLine startLine = sourceText.Lines.GetLineFromPosition(span.Start);
            string text = sourceText.ToString(TextSpan.FromBounds(startLine.Start, span.End));
            StringBuilder replacement = StringBuilderPool.Allocate();
            int column = 0;
            for (int i = 0; i < text.Length; i++)
            {
                char c = text[i];
                if (c == '\t')
                {
                    var offsetWithinTabColumn = column % indentationOptions.TabSize;
                    var spaceCount = indentationOptions.TabSize - offsetWithinTabColumn;

                    if (i >= span.Start - startLine.Start)
                    {
                        replacement.Append(' ', spaceCount);
                    }

                    column += spaceCount;
                }
                else
                {
                    if (i >= span.Start - startLine.Start)
                    {
                        replacement.Append(c);
                    }

                    if (c == '\n')
                    {
                        column = 0;
                    }
                    else
                    {
                        column++;
                    }
                }
            }

            return new TextChange(span, StringBuilderPool.ReturnAndFree(replacement));
        }
Esempio n. 6
0
        public void SerializeSourceText(ITemporaryStorageWithName storage, SourceText text, ObjectWriter writer, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            writer.WriteInt32((int)text.ChecksumAlgorithm);
            writer.WriteString(text.Encoding?.WebName);

            // TODO: refactor this part in its own abstraction (Bits) that has multiple sub types
            //       rather than using enums
            if (storage != null && storage.Name != null)
            {
                writer.WriteInt32((int)SerializationKinds.MemoryMapFile);
                writer.WriteString(storage.Name);
                writer.WriteInt64(storage.Size);
                return;
            }

            writer.WriteInt32((int)SerializationKinds.Bits);
            writer.WriteString(text.ToString());
        }
 public override string ToString() => _sourceText.ToString();
            protected IEnumerable<SymbolDisplayPart> ConvertClassifications(SourceText text, IEnumerable<ClassifiedSpan> classifications)
            {
                var parts = new List<SymbolDisplayPart>();

                ClassifiedSpan? lastSpan = null;
                foreach (var span in classifications)
                {
                    // If there is space between this span and the last one, then add a space.
                    if (lastSpan != null && lastSpan.Value.TextSpan.End != span.TextSpan.Start)
                    {
                        parts.AddRange(Space());
                    }

                    var kind = GetClassificationKind(span.ClassificationType);
                    if (kind != null)
                    {
                        parts.Add(new SymbolDisplayPart(kind.Value, null, text.ToString(span.TextSpan)));

                        lastSpan = span;
                    }
                }

                return parts;
            }
        public void AddReference(
            string documentDestinationPath,
            SourceText referenceText,
            string destinationAssemblyName,
            ISymbol symbol,
            string symbolId,
            int startPosition,
            int endPosition,
            ReferenceKind kind)
        {
            string referenceString = referenceText.ToString(TextSpan.FromBounds(startPosition, endPosition));
            if (symbol is INamedTypeSymbol && (referenceString == "this" || referenceString == "base"))
            {
                // Don't count "this" or "base" expressions that bind to this type as references
                return;
            }

            var line = referenceText.Lines.GetLineFromPosition(startPosition);
            int start = referenceText.Lines.GetLinePosition(startPosition).Character;
            int end = start + endPosition - startPosition;
            int lineNumber = line.LineNumber + 1;
            string lineText = line.ToString();

            AddReference(
                documentDestinationPath,
                lineText,
                start,
                referenceString.Length,
                lineNumber,
                AssemblyName,
                destinationAssemblyName,
                symbol,
                symbolId,
                kind);
        }
		protected override void ApplyDocumentTextChanged (DocumentId id, SourceText text)
		{
			var document = GetDocument (id);
			if (document == null)
				return;
			bool isOpen;
			var filePath = document.FilePath;
			var data = TextFileProvider.Instance.GetTextEditorData (filePath, out isOpen);

			// Guard against already done changes in linked files.
			// This shouldn't happen but the roslyn merging seems not to be working correctly in all cases :/
			if (document.GetLinkedDocumentIds ().Length > 0 && isOpen && !(text.GetType ().FullName == "Microsoft.CodeAnalysis.Text.ChangedText")) {
				return;
			}
			SourceText formerText;
			if (changedFiles.TryGetValue (filePath, out formerText)) {
				if (formerText.Length == text.Length && formerText.ToString () == text.ToString ())
					return;
			}
			changedFiles [filePath] = text;
		
			Projection projection = null;
			foreach (var entry in ProjectionList) {
				var p = entry.Projections.FirstOrDefault (proj => FilePath.PathComparer.Equals (proj.Document.FileName, filePath));
				if (p != null) {
					filePath = entry.File.FilePath;
					projection = p;
					break;
				}
			}
			SourceText oldFile;
			if (!isOpen || !document.TryGetText (out oldFile)) {
				oldFile = new MonoDevelopSourceText (data);
			}
			var changes = text.GetTextChanges (oldFile).OrderByDescending (c => c.Span.Start).ToList ();
			int delta = 0;

			if (!isOpen) {
				delta = ApplyChanges (projection, data, changes);
				var formatter = CodeFormatterService.GetFormatter (data.MimeType);
				var mp = GetMonoProject (CurrentSolution.GetProject (id.ProjectId));
				string currentText = data.Text;

				foreach (var change in changes) {
					delta -= change.Span.Length - change.NewText.Length;
					var startOffset = change.Span.Start - delta;

					if (projection != null) {
						int originalOffset;
						if (projection.TryConvertFromProjectionToOriginal (startOffset, out originalOffset))
							startOffset = originalOffset;
					}

					string str;
					if (change.NewText.Length == 0) {
						str = formatter.FormatText (mp.Policies, currentText, TextSegment.FromBounds (Math.Max (0, startOffset - 1), Math.Min (data.Length, startOffset + 1)));
					} else {
						str = formatter.FormatText (mp.Policies, currentText, new TextSegment (startOffset, change.NewText.Length));
					}
					data.ReplaceText (startOffset, change.NewText.Length, str);
				}
				data.Save ();
				OnDocumentTextChanged (id, new MonoDevelopSourceText (data), PreservationMode.PreserveValue);
				FileService.NotifyFileChanged (filePath);
			} else {
				var formatter = CodeFormatterService.GetFormatter (data.MimeType); 
				var documentContext = IdeApp.Workbench.Documents.FirstOrDefault (d => FilePath.PathComparer.Compare (d.FileName, filePath) == 0);
				if (documentContext != null) {
					var editor = (TextEditor)data;
					using (var undo = editor.OpenUndoGroup ()) {
						delta = ApplyChanges (projection, data, changes);

						foreach (var change in changes) {
							delta -= change.Span.Length - change.NewText.Length;
							var startOffset = change.Span.Start - delta;
							if (projection != null) {
								int originalOffset;
								if (projection.TryConvertFromProjectionToOriginal (startOffset, out originalOffset))
									startOffset = originalOffset;
							}
							if (change.NewText.Length == 0) {
								formatter.OnTheFlyFormat (editor, documentContext, TextSegment.FromBounds (Math.Max (0, startOffset - 1), Math.Min (data.Length, startOffset + 1)));
							} else {
								formatter.OnTheFlyFormat (editor, documentContext, new TextSegment (startOffset, change.NewText.Length));
							}
						}
					}
				}
				OnDocumentTextChanged (id, new MonoDevelopSourceText(data.CreateDocumentSnapshot ()), PreservationMode.PreserveValue);
				Runtime.RunInMainThread (() => {
					if (IdeApp.Workbench != null)
						foreach (var w in IdeApp.Workbench.Documents)
							w.StartReparseThread ();
				});
			}
		}
        internal static void AddLexicalClassifications(SourceText text, TextSpan textSpan, List<ClassifiedSpan> result, CancellationToken cancellationToken)
        {
            var text2 = text.ToString(textSpan);
            var tokens = SyntaxFactory.ParseTokens(text2, initialTokenPosition: textSpan.Start);

            Worker.CollectClassifiedSpans(tokens, textSpan, result, cancellationToken);
        }
Esempio n. 12
0
 public override string ToString(TextSpan span)
 {
     return(_newText.ToString(span));
 }
Esempio n. 13
0
        private static StyleCopSettings GetStyleCopSettings(SourceText text, DeserializationFailureBehavior failureBehavior)
        {
            try
            {
                var root = JsonConvert.DeserializeObject<SettingsFile>(text.ToString());
                return root.Settings;
            }
            catch (JsonException) when (failureBehavior == DeserializationFailureBehavior.ReturnDefaultSettings)
            {
                // The settings file is invalid -> return the default settings.
            }

            return new StyleCopSettings();
        }
Esempio n. 14
0
        private static List<SymbolDisplayPart> ConvertClassifications(
            SourceText sourceText, int startPosition, IEnumerable<ClassifiedSpan> classifiedSpans, bool insertSourceTextInGaps = false)
        {
            var parts = new List<SymbolDisplayPart>();
 
            foreach (var span in classifiedSpans)
            {
                // If there is space between this span and the last one, then add a space.
                if (startPosition != span.TextSpan.Start)
                {
                    if (insertSourceTextInGaps)
                    {
                        parts.Add(new SymbolDisplayPart(SymbolDisplayPartKind.Text, null,
                            sourceText.ToString(TextSpan.FromBounds(
                                startPosition, span.TextSpan.Start))));
                    }
                    else
                    {
                        parts.AddRange(Space());
                    }
                }
 
                var kind = GetClassificationKind(span.ClassificationType);
                if (kind != null)
                {
                    parts.Add(new SymbolDisplayPart(kind.Value, null, sourceText.ToString(span.TextSpan)));

                    startPosition = span.TextSpan.End;
                }
            }
 
            return parts;
        }
 public void WriteText(SourceText text, CancellationToken cancellationToken = default(CancellationToken))
 {
     // Decompose the SourceText into it's underlying parts, since we use it as a key
     // into many other caches that don't expect it to be held
     _text = text.ToString();
     _encoding = text.Encoding;
 }
            private VirtualTreePoint GetBodyStartPoint(SourceText text, SyntaxToken openBrace)
            {
                Debug.Assert(!openBrace.IsMissing);

                var openBraceLine = text.Lines.GetLineFromPosition(openBrace.Span.End);
                var textAfterBrace = text.ToString(TextSpan.FromBounds(openBrace.Span.End, openBraceLine.End));

                return string.IsNullOrWhiteSpace(textAfterBrace)
                    ? new VirtualTreePoint(openBrace.SyntaxTree, text, text.Lines[openBraceLine.LineNumber + 1].Start)
                    : new VirtualTreePoint(openBrace.SyntaxTree, text, openBrace.Span.End);
            }
Esempio n. 17
0
        internal static ImmutableArray<SymbolDisplayPart> ConvertClassificationsToParts(
            SourceText sourceText, int startPosition, IEnumerable<ClassifiedSpan> classifiedSpans)
        {
            var parts = ArrayBuilder<SymbolDisplayPart>.GetInstance();
 
            foreach (var span in classifiedSpans)
            {
                // If there is space between this span and the last one, then add a space.
                if (startPosition != span.TextSpan.Start)
                {
                    parts.AddRange(Space());
                }
 
                var kind = GetClassificationKind(span.ClassificationType);
                if (kind != null)
                {
                    parts.Add(new SymbolDisplayPart(kind.Value, null, sourceText.ToString(span.TextSpan)));

                    startPosition = span.TextSpan.End;
                }
            }
 
            return parts.ToImmutableAndFree();
        }
 public void WriteText(SourceText text, CancellationToken cancellationToken = default(CancellationToken))
 {
     _text = text.ToString();
     _encoding = text.Encoding;
 }
        internal static ClassifiedSpan AdjustStaleClassification(SourceText rawText, ClassifiedSpan classifiedSpan)
        {
            // If we marked this as an identifier and it should now be a keyword
            // (or vice versa), then fix this up and return it. 
            var classificationType = classifiedSpan.ClassificationType;

            // Check if the token's type has changed.  Note: we don't check for "wasPPKeyword &&
            // !isPPKeyword" here.  That's because for fault tolerance any identifier will end up
            // being parsed as a PP keyword eventually, and if we have the check here, the text
            // flickers between blue and black while typing.  See
            // http://vstfdevdiv:8080/web/wi.aspx?id=3521 for details.
            var wasKeyword = classificationType == ClassificationTypeNames.Keyword;
            var wasIdentifier = classificationType == ClassificationTypeNames.Identifier;

            // We only do this for identifiers/keywords.
            if (wasKeyword || wasIdentifier)
            {
                // Get the current text under the tag.
                var span = classifiedSpan.TextSpan;
                var text = rawText.ToString(span);

                // Now, try to find the token that corresponds to that text.  If
                // we get 0 or 2+ tokens, then we can't do anything with this.  
                // Also, if that text includes trivia, then we can't do anything.
                var token = SyntaxFactory.ParseToken(text);
                if (token.Span.Length == span.Length)
                {
                    // var and dynamic are not contextual keywords.  They are always identifiers
                    // (that we classify as keywords).  Because we are just parsing a token we don't
                    // know if we're in the right context for them to be identifiers or keywords.
                    // So, we base on decision on what they were before.  i.e. if we had a keyword
                    // before, then assume it stays a keyword if we see 'var' or 'dynamic.
                    var isKeyword = SyntaxFacts.IsKeywordKind(token.CSharpKind())
                        || (wasKeyword && SyntaxFacts.GetContextualKeywordKind(text) != SyntaxKind.None)
                        || (wasKeyword && token.ToString() == "var")
                        || (wasKeyword && token.ToString() == "dynamic");

                    var isIdentifier = token.CSharpKind() == SyntaxKind.IdentifierToken;

                    // We only do this for identifiers/keywords.
                    if (isKeyword || isIdentifier)
                    {
                        if ((wasKeyword && !isKeyword) ||
                            (wasIdentifier && !isIdentifier))
                        {
                            // It changed!  Return the new type of tagspan.
                            return new ClassifiedSpan(
                                isKeyword ? ClassificationTypeNames.Keyword : ClassificationTypeNames.Identifier, span);
                        }
                    }
                }
            }

            // didn't need to do anything to this one.
            return classifiedSpan;
        }
Esempio n. 20
0
        public static IHierarchicalDifferenceCollection ComputeDiffSpans(SourceText oldText, SourceText newText, ITextDifferencingService diffService, CancellationToken cancellationToken)
        {
            var diffResult = diffService.DiffStrings(oldText.ToString(), newText.ToString(), new StringDifferenceOptions()
            {
                DifferenceType = StringDifferenceTypes.Line
            });

            return diffResult;
        }
Esempio n. 21
0
 private static void TokenByTokenBottomUp(SourceText oldText, string token, out SyntaxTree incrementalTree, out SyntaxTree parsedTree)
 {
     var startTree = SyntaxFactory.ParseSyntaxTree(oldText);
     SourceText newText = SourceText.From(token + oldText.ToString());
     incrementalTree = startTree.WithInsertAt(0, token);
     parsedTree = SyntaxFactory.ParseSyntaxTree(newText);
 }
        /// <summary>
        /// make sure current location is okay to put semicolon
        /// </summary>
        private static bool CheckLocation(SourceText text, int position, SyntaxNode owningNode, SyntaxToken lastToken)
        {
            var line = text.Lines.GetLineFromPosition(position);

            // if caret is at the end of the line and containing statement is expression statement
            // don't do anything
            if (position == line.End && owningNode is ExpressionStatementSyntax)
            {
                return false;
            }

            var locatedAtTheEndOfLine = LocatedAtTheEndOfLine(line, lastToken);

            // make sure that there is no trailing text after last token on the line if it is not at the end of the line
            if (!locatedAtTheEndOfLine)
            {
                var endingString = text.ToString(TextSpan.FromBounds(lastToken.Span.End, line.End));
                if (!string.IsNullOrWhiteSpace(endingString))
                {
                    return false;
                }
            }

            // check whether using has contents
            if (owningNode.TypeSwitch((UsingDirectiveSyntax u) => u.Name == null || u.Name.IsMissing))
            {
                return false;
            }

            // make sure there is no open string literals
            var previousToken = lastToken.GetPreviousToken();
            if (previousToken.Kind() == SyntaxKind.StringLiteralToken && previousToken.ToString().Last() != '"')
            {
                return false;
            }

            if (previousToken.Kind() == SyntaxKind.CharacterLiteralToken && previousToken.ToString().Last() != '\'')
            {
                return false;
            }

            // now, check embedded statement case
            if (owningNode.IsEmbeddedStatementOwner())
            {
                var embeddedStatement = owningNode.GetEmbeddedStatement();
                if (embeddedStatement == null || embeddedStatement.Span.IsEmpty)
                {
                    return false;
                }
            }

            return true;
        }
Esempio n. 23
0
		protected override async void ApplyDocumentTextChanged (DocumentId id, SourceText text)
		{
			var document = GetDocument (id);
			if (document == null)
				return;
			bool isOpen;
			var filePath = document.FilePath;

			Projection projection = null;
			foreach (var entry in ProjectionList) {
				var p = entry.Projections.FirstOrDefault (proj => proj?.Document?.FileName != null && FilePath.PathComparer.Equals (proj.Document.FileName, filePath));
				if (p != null) {
					filePath = entry.File.FilePath;
					projection = p;
					break;
				}
			}

			var data = TextFileProvider.Instance.GetTextEditorData (filePath, out isOpen);

			// Guard against already done changes in linked files.
			// This shouldn't happen but the roslyn merging seems not to be working correctly in all cases :/
			if (document.GetLinkedDocumentIds ().Length > 0 && isOpen && !(text.GetType ().FullName == "Microsoft.CodeAnalysis.Text.ChangedText")) {
				return;
			}
			SourceText formerText;
			lock (changedFiles) {
				if (changedFiles.TryGetValue (filePath, out formerText)) {
					if (formerText.Length == text.Length && formerText.ToString () == text.ToString ())
						return;
				}
				changedFiles [filePath] = text;
			}

			SourceText oldFile;
			if (!isOpen || !document.TryGetText (out oldFile)) {
				oldFile = await document.GetTextAsync ();
			}
			var changes = text.GetTextChanges (oldFile).OrderByDescending (c => c.Span.Start).ToList ();
			int delta = 0;

			if (!isOpen) {
				delta = ApplyChanges (projection, data, changes);
				var formatter = CodeFormatterService.GetFormatter (data.MimeType);
				if (formatter.SupportsPartialDocumentFormatting) {
					var mp = GetMonoProject (CurrentSolution.GetProject (id.ProjectId));
					string currentText = data.Text;

					foreach (var change in changes) {
						delta -= change.Span.Length - change.NewText.Length;
						var startOffset = change.Span.Start - delta;

						if (projection != null) {
							int originalOffset;
							if (projection.TryConvertFromProjectionToOriginal (startOffset, out originalOffset))
								startOffset = originalOffset;
						}

						string str;
						if (change.NewText.Length == 0) {
							str = formatter.FormatText (mp.Policies, currentText, TextSegment.FromBounds (Math.Max (0, startOffset - 1), Math.Min (data.Length, startOffset + 1)));
						} else {
							str = formatter.FormatText (mp.Policies, currentText, new TextSegment (startOffset, change.NewText.Length));
						}
						data.ReplaceText (startOffset, change.NewText.Length, str);
					}
				}
				data.Save ();
				if (projection != null) {
					await UpdateProjectionsDocuments (document, data);
				} else {
					OnDocumentTextChanged (id, new MonoDevelopSourceText (data), PreservationMode.PreserveValue);
				}
				FileService.NotifyFileChanged (filePath);
			} else {
				var formatter = CodeFormatterService.GetFormatter (data.MimeType);
				var documentContext = IdeApp.Workbench.Documents.FirstOrDefault (d => FilePath.PathComparer.Compare (d.FileName, filePath) == 0);
				var root = await projectChanges.NewProject.GetDocument (id).GetSyntaxRootAsync ();
				var annotatedNode = root.DescendantNodesAndSelf ().FirstOrDefault (n => n.HasAnnotation (TypeSystemService.InsertionModeAnnotation));
				SyntaxToken? renameTokenOpt = root.GetAnnotatedNodesAndTokens (Microsoft.CodeAnalysis.CodeActions.RenameAnnotation.Kind)
												  .Where (s => s.IsToken)
												  .Select (s => s.AsToken ())
												  .Cast<SyntaxToken?> ()
												  .FirstOrDefault ();

				if (documentContext != null) {
					var editor = (TextEditor)data;
					await Runtime.RunInMainThread (async () => {
						using (var undo = editor.OpenUndoGroup ()) {
							var oldVersion = editor.Version;
							delta = ApplyChanges (projection, data, changes);
							var versionBeforeFormat = editor.Version;

							if (formatter.SupportsOnTheFlyFormatting) {
								foreach (var change in changes) {
									delta -= change.Span.Length - change.NewText.Length;
									var startOffset = change.Span.Start - delta;
									if (projection != null) {
										int originalOffset;
										if (projection.TryConvertFromProjectionToOriginal (startOffset, out originalOffset))
											startOffset = originalOffset;
									}
									if (change.NewText.Length == 0) {
										formatter.OnTheFlyFormat (editor, documentContext, TextSegment.FromBounds (Math.Max (0, startOffset - 1), Math.Min (data.Length, startOffset + 1)));
									} else {
										formatter.OnTheFlyFormat (editor, documentContext, new TextSegment (startOffset, change.NewText.Length));
									}
								}
							}
							if (annotatedNode != null && GetInsertionPoints != null) {
								IdeApp.Workbench.Documents.First (d => d.FileName == editor.FileName).Select ();
								var formattedVersion = editor.Version;

								int startOffset = versionBeforeFormat.MoveOffsetTo (editor.Version, annotatedNode.Span.Start);
								int endOffset = versionBeforeFormat.MoveOffsetTo (editor.Version, annotatedNode.Span.End);

								// alway whole line start & delimiter
								var startLine = editor.GetLineByOffset (startOffset);
								startOffset = startLine.Offset;

								var endLine = editor.GetLineByOffset (endOffset);
								endOffset = endLine.EndOffsetIncludingDelimiter + 1;

								var insertionCursorSegment = TextSegment.FromBounds (startOffset, endOffset);
								string textToInsert = editor.GetTextAt (insertionCursorSegment).TrimEnd ();
								editor.RemoveText (insertionCursorSegment);
								var insertionPoints = await GetInsertionPoints (editor, editor.CaretOffset);
								if (insertionPoints.Count == 0) {
									// Just to get sure if no insertion points -> go back to the formatted version.
									var textChanges = editor.Version.GetChangesTo (formattedVersion).ToList ();
									using (var undo2 = editor.OpenUndoGroup ()) {
										foreach (var v in textChanges) {
											editor.ReplaceText (v.Offset, v.RemovalLength, v.InsertedText);
										}
									}
									return;
								}
								string insertionModeOperation;
								const int CSharpMethodKind = 8875;


								bool isMethod = annotatedNode.RawKind == CSharpMethodKind;

								if (!isMethod) {
									// atm only for generate field/property : remove all new lines generated & just insert the plain node.
									// for methods it's not so easy because of "extract code" changes.
									foreach (var v in editor.Version.GetChangesTo (oldVersion).ToList ()) {
										editor.ReplaceText (v.Offset, v.RemovalLength, v.InsertedText);
									}
								}

								switch (annotatedNode.RawKind) {
								case 8873: // C# field
									insertionModeOperation = GettextCatalog.GetString ("Insert Field");
									break;
								case CSharpMethodKind:
									insertionModeOperation = GettextCatalog.GetString ("Insert Method");
									break;
								case 8892: // C# property 
									insertionModeOperation = GettextCatalog.GetString ("Insert Property");
									break;
								default:
									insertionModeOperation = GettextCatalog.GetString ("Insert Code");
									break;
								}

								var options = new InsertionModeOptions (
									insertionModeOperation,
									insertionPoints,
									point => {
										if (!point.Success)
											return;
										point.InsertionPoint.Insert (editor, textToInsert);
									}
								);
								options.ModeExitedAction += delegate (InsertionCursorEventArgs args) {
									if (!args.Success) {
										var textChanges = editor.Version.GetChangesTo (oldVersion).ToList ();
										using (var undo2 = editor.OpenUndoGroup ()) {
											foreach (var v in textChanges) {
												editor.ReplaceText (v.Offset, v.RemovalLength, v.InsertedText);
											}
										}
									}
								};
								for (int i = 0; i < insertionPoints.Count; i++) {
									if (insertionPoints [i].Location.Line < editor.CaretLine) {
										options.FirstSelectedInsertionPoint = Math.Min (isMethod ? i + 1 : i, insertionPoints.Count - 1);
									} else {
										break;
									}
								}
								options.ModeExitedAction += delegate {
									if (renameTokenOpt.HasValue)
										StartRenameSession (editor, documentContext, versionBeforeFormat, renameTokenOpt.Value);
								};
								editor.StartInsertionMode (options);
							}
						}
					});
				}

				if (projection != null) {
					await UpdateProjectionsDocuments (document, data);
				} else {
					OnDocumentTextChanged (id, new MonoDevelopSourceText (data.CreateDocumentSnapshot ()), PreservationMode.PreserveValue);
				}
				await Runtime.RunInMainThread (() => {
						if (IdeApp.Workbench != null)
						foreach (var w in IdeApp.Workbench.Documents)
							w.StartReparseThread ();
				});
			}
		}
        private TextChange Collapse(SourceText newText, List<TextChange> changes)
        {
            if (changes.Count == 0)
            {
                return new TextChange(new TextSpan(0, 0), "");
            }
            else if (changes.Count == 1)
            {
                return changes[0];
            }

            // The span we want to replace goes from the start of the first span to the end of
            // the  last span.
            var totalOldSpan = TextSpan.FromBounds(changes.First().Span.Start, changes.Last().Span.End);

            // We figure out the text we're replacing with by actually just figuring out the
            // new span in the newText and grabbing the text out of that.  The newSpan will
            // start from the same position as the oldSpan, but it's length will be the old
            // span's length + all the deltas we accumulate through each text change.  i.e.
            // if the first change adds 2 characters and the second change adds 4, then 
            // the newSpan will be 2+4=6 characters longer than the old span.
            var sumOfDeltas = changes.Sum(c => c.NewText.Length - c.Span.Length);
            var totalNewSpan = new TextSpan(totalOldSpan.Start, totalOldSpan.Length + sumOfDeltas);

            return new TextChange(totalOldSpan, newText.ToString(totalNewSpan));
        }
        private static TextChange FixDiagnostic(IndentationSettings indentationSettings, SourceText sourceText, Diagnostic diagnostic)
        {
            TextSpan span = diagnostic.Location.SourceSpan;

            TextLine startLine = sourceText.Lines.GetLineFromPosition(span.Start);

            bool useTabs = false;
            string behavior;
            if (diagnostic.Properties.TryGetValue(SA1027UseTabsCorrectly.BehaviorKey, out behavior))
            {
                useTabs = behavior == SA1027UseTabsCorrectly.ConvertToTabsBehavior;
            }

            string text = sourceText.ToString(TextSpan.FromBounds(startLine.Start, span.End));
            StringBuilder replacement = StringBuilderPool.Allocate();
            int spaceCount = 0;
            int column = 0;
            for (int i = 0; i < text.Length; i++)
            {
                char c = text[i];
                if (c == '\t')
                {
                    var offsetWithinTabColumn = column % indentationSettings.TabSize;
                    var tabWidth = indentationSettings.TabSize - offsetWithinTabColumn;

                    if (i >= span.Start - startLine.Start)
                    {
                        if (useTabs)
                        {
                            replacement.Length = replacement.Length - spaceCount;
                            replacement.Append('\t');
                            spaceCount = 0;
                        }
                        else
                        {
                            replacement.Append(' ', tabWidth);
                        }
                    }

                    column += tabWidth;
                }
                else
                {
                    if (i >= span.Start - startLine.Start)
                    {
                        replacement.Append(c);
                        if (c == ' ')
                        {
                            spaceCount++;
                            if (useTabs)
                            {
                                // Note that we account for column not yet being incremented
                                var offsetWithinTabColumn = (column + 1) % indentationSettings.TabSize;
                                if (offsetWithinTabColumn == 0)
                                {
                                    // We reached a tab stop.
                                    replacement.Length = replacement.Length - spaceCount;
                                    replacement.Append('\t');
                                    spaceCount = 0;
                                }
                            }
                        }
                        else
                        {
                            spaceCount = 0;
                        }
                    }

                    if (c == '\r' || c == '\n')
                    {
                        // Handle newlines. We can ignore CR/LF/CRLF issues because we are only tracking column position
                        // in a line, and not the line numbers themselves.
                        column = 0;
                        spaceCount = 0;
                    }
                    else
                    {
                        column++;
                    }
                }
            }

            return new TextChange(span, StringBuilderPool.ReturnAndFree(replacement));
        }
            private VirtualTreePoint GetBodyEndPoint(SourceText text, SyntaxToken closeBrace)
            {
                var closeBraceLine = text.Lines.GetLineFromPosition(closeBrace.SpanStart);
                var textBeforeBrace = text.ToString(TextSpan.FromBounds(closeBraceLine.Start, closeBrace.SpanStart));

                return string.IsNullOrWhiteSpace(textBeforeBrace)
                    ? new VirtualTreePoint(closeBrace.SyntaxTree, text, closeBraceLine.Start)
                    : new VirtualTreePoint(closeBrace.SyntaxTree, text, closeBrace.SpanStart);
            }
Esempio n. 27
0
 internal static SourceText WithReplaceFirst(SourceText text, string oldText, string newText)
 {
     var oldFullText = text.ToString();
     int offset = oldFullText.IndexOf(oldText, StringComparison.Ordinal);
     int length = oldText.Length;
     var span = new TextSpan(offset, length);
     var newFullText = oldFullText.Substring(0, offset) + newText + oldFullText.Substring(span.End);
     return SourceText.From(newFullText);
 }
Esempio n. 28
0
        private static void CharByCharIncrementalParse(SourceText oldText, char newChar, out SyntaxTree incrementalTree, out SyntaxTree parsedTree)
        {
            var startTree = SyntaxFactory.ParseSyntaxTree(oldText);

            // first make certain this text round trips
            Assert.Equal(oldText.ToString(), startTree.GetCompilationUnitRoot().ToFullString());
            var newText = oldText.WithChanges(new TextChange(new TextSpan(oldText.Length, 0), newChar.ToString()));
            incrementalTree = startTree.WithChangedText(newText);
            parsedTree = SyntaxFactory.ParseSyntaxTree(newText);
        }
Esempio n. 29
0
 private static SourceText FromChanges(SourceText text)
 {
     var span = new TextSpan(0, 1);
     var change = new TextChange(span, text.ToString(span));
     var changed = text.WithChanges(change);
     Assert.NotEqual(text, changed);
     return changed;
 }
Esempio n. 30
0
        void CheckLine(SourceText text, int lineNumber, int start, int length, int newlineLength, string lineText)
        {
            var textLine = text.Lines[lineNumber];

            Assert.Equal(start, textLine.Start);
            Assert.Equal(start + length, textLine.End);
            Assert.Equal(start + length + newlineLength, textLine.EndIncludingLineBreak);
            Assert.Equal(start, textLine.Span.Start);
            Assert.Equal(length, textLine.Span.Length);
            Assert.Equal(start, textLine.SpanIncludingLineBreak.Start);
            Assert.Equal(length + newlineLength, textLine.SpanIncludingLineBreak.Length);
            Assert.Equal(lineNumber, textLine.LineNumber);
            Assert.Equal(lineText, textLine.ToString());
            Assert.Equal(text.ToString().Substring(start, length), textLine.ToString());

            CheckEqualLine(textLine, text.Lines[lineNumber]);
            for (int p = textLine.Start; p < textLine.EndIncludingLineBreak; ++p)
            {
                CheckEqualLine(textLine, text.Lines.GetLineFromPosition(p));
                Assert.Equal(lineNumber, text.Lines.IndexOf(p));
                Assert.Equal(lineNumber, text.Lines.GetLinePosition(p).Line);
                Assert.Equal(p - start, text.Lines.GetLinePosition(p).Character);
            }

            if (start != 0)
            {
                CheckNotEqualLine(textLine, text.Lines.GetLineFromPosition(start - 1));
                Assert.Equal(lineNumber - 1, text.Lines.IndexOf(start - 1));
                Assert.Equal(lineNumber - 1, text.Lines.GetLinePosition(start - 1).Line);
            }

            int nextPosition = start + length + newlineLength;
            if (nextPosition < text.Length)
            {
                CheckNotEqualLine(textLine, text.Lines.GetLineFromPosition(nextPosition));
                Assert.Equal(lineNumber + 1, text.Lines.IndexOf(nextPosition));
                Assert.Equal(lineNumber + 1, text.Lines.GetLinePosition(nextPosition).Line);
            }
        }
Esempio n. 31
0
        private IEnumerable<TextChange> GetSubTextChanges(SourceText originalText, TextChange changeInOriginalText, TextSpan visibleSpanInOriginalText)
        {
            using (var changes = SharedPools.Default<List<TextChange>>().GetPooledObject())
            {
                var leftText = originalText.ToString(changeInOriginalText.Span);
                var rightText = changeInOriginalText.NewText;
                var offsetInOriginalText = changeInOriginalText.Span.Start;

                if (TryGetSubTextChanges(originalText, visibleSpanInOriginalText, leftText, rightText, offsetInOriginalText, changes.Object))
                {
                    return changes.Object.ToList();
                }

                return GetSubTextChanges(originalText, visibleSpanInOriginalText, leftText, rightText, offsetInOriginalText);
            }
        }
Esempio n. 32
0
		protected override void ApplyDocumentAdded (DocumentInfo info, SourceText text)
		{
			var id = info.Id;
			MonoDevelop.Projects.Project mdProject = null;

			if (id.ProjectId != null) {
				var project = CurrentSolution.GetProject (id.ProjectId);
				mdProject = GetMonoProject (project);
				if (mdProject == null)
					LoggingService.LogWarning ("Couldn't find project for newly generated file {0} (Project {1}).", info.Name, info.Id.ProjectId);
			}
			var path = DetermineFilePath (info.Id, info.Name, info.FilePath, info.Folders, mdProject?.FileName.ParentDirectory, true);

			string formattedText;
			var formatter = CodeFormatterService.GetFormatter (DesktopService.GetMimeTypeForUri (path)); 
			if (formatter != null && mdProject != null) {
				formattedText = formatter.FormatText (mdProject.Policies, text.ToString ());
			} else {
				formattedText = text.ToString ();
			}

			var textSource = new StringTextSource (formattedText, text.Encoding ?? System.Text.Encoding.UTF8);
			try {
				textSource.WriteTextTo (path);
			} catch (Exception e) {
				LoggingService.LogError ("Exception while saving file to " + path, e);
			}

			if (mdProject != null) {
				var file = new MonoDevelop.Projects.ProjectFile (path);
				Application.Invoke (delegate {
					mdProject.Files.Add (file);
					IdeApp.ProjectOperations.SaveAsync (mdProject);
				});
			}
		}
Esempio n. 33
0
        public override string ToString(TextSpan span)
        {
            CheckSubSpan(span);

            return(_text.ToString(GetCompositeSpan(span.Start, span.Length)));
        }