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)); }
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); }
public override string ToString(TextSpan span) { return(_newText.ToString(span)); }
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(); }
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); }
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; }
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; }
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; }
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); }
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); }
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); }
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; }
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); } }
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); } }
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); }); } }
public override string ToString(TextSpan span) { CheckSubSpan(span); return(_text.ToString(GetCompositeSpan(span.Start, span.Length))); }