public HighlightedLine HighlightLine(int lineNumber) { IDocumentLine documentLine = document.GetLineByNumber(lineNumber); if (hasCrashed) { // don't highlight anymore after we've crashed return(new HighlightedLine(document, documentLine)); } ITextSourceVersion newVersion = document.Version; CachedLine cachedLine = null; if (cachedLines != null) { for (int i = 0; i < cachedLines.Count; i++) { if (cachedLines[i].DocumentLine == documentLine) { if (newVersion == null || !newVersion.BelongsToSameDocumentAs(cachedLines[i].OldVersion)) { // cannot list changes from old to new: we can't update the cache, so we'll remove it cachedLines.RemoveAt(i); } else { cachedLine = cachedLines[i]; } break; } } if (cachedLine != null && cachedLine.IsValid && newVersion.CompareAge(cachedLine.OldVersion) == 0) { // the file hasn't changed since the cache was created, so just reuse the old highlighted line #if DEBUG cachedLine.HighlightedLine.ValidateInvariants(); #endif return(cachedLine.HighlightedLine); } } bool wasInHighlightingGroup = inHighlightingGroup; if (!inHighlightingGroup) { BeginHighlighting(); } try { return(DoHighlightLine(lineNumber, documentLine, cachedLine, newVersion)); } finally { line = null; if (!wasInHighlightingGroup) { EndHighlighting(); } } }
protected override void OnDocumentClosing() { try { // text source version becomes invalid on document close. if (buffer != null) { if (version.BelongsToSameDocumentAs(buffer.Version)) { offset = version.MoveOffsetTo(buffer.Version, offset); } var location = buffer.CaretLocation; line = location.Line; column = location.Column; } } catch (Exception e) { LoggingService.LogInternalError(e); } version = null; buffer = null; }
/// <summary> /// Compares currentVersion with version. /// -1 = currentVersion is older; 0 = same version; 1 = newVersion is older /// </summary> int CompareVersions(ITextSourceVersion newVersion) { if (currentVersion != null && newVersion != null && currentVersion.BelongsToSameDocumentAs(newVersion)) { return(currentVersion.CompareAge(newVersion)); } else { return(-1); } }
/// <summary> /// Compares currentVersion with version. /// -1 = currentVersion is older; 0 = same version; 1 = newVersion is older /// </summary> int CompareVersions(ITextSourceVersion newVersion) { Debug.Assert(rwLock.IsReadLockHeld || rwLock.IsUpgradeableReadLockHeld || rwLock.IsWriteLockHeld); if (currentVersion != null && newVersion != null && currentVersion.BelongsToSameDocumentAs(newVersion)) { return(currentVersion.CompareAge(newVersion)); } else { return(-1); } }
protected void JumpToCurrentLocation(TextEditor editor) { if (version != null && version.BelongsToSameDocumentAs(editor.Version)) { var currentOffset = version.MoveOffsetTo(editor.Version, offset); var loc = editor.OffsetToLocation(currentOffset); editor.SetCaretLocation(loc); } else { editor.SetCaretLocation(Math.Max(line, 1), Math.Max(column, 1)); } }
protected void JumpToCurrentLocation(TextEditor editor) { if (version != null && version.BelongsToSameDocumentAs(editor.Version)) { var currentOffset = version.MoveOffsetTo(editor.Version, offset); var loc = editor.OffsetToLocation(currentOffset); editor.SetCaretLocation(loc); } else { var doc = IdeApp.Workbench.Documents.FirstOrDefault(d => d.Editor == editor); if (doc != null) { version = editor.Version; offset = editor.LocationToOffset(line, column); SetDocument(doc); } editor.SetCaretLocation(Math.Max(line, 1), Math.Max(column, 1)); } }
void SD_ParserService_ParseInformationUpdated(object sender, ParseInformationEventArgs e) { var parseInfo = e.NewParseInformation as CSharpFullParseInformation; ITextSourceVersion currentVersion = editor.Document.Version; if (parseInfo == null) { return; } ITextSourceVersion parsedVersion = parseInfo.ParsedVersion; if (parsedVersion != null && currentVersion != null && parsedVersion.BelongsToSameDocumentAs(currentVersion)) { if (analyzedVersion != null && analyzedVersion.CompareAge(parsedVersion) == 0) { // don't analyze the same version twice return; } RunAnalysis(editor.Document.CreateSnapshot(), parseInfo); } }
internal List <UnchangedSegment> GetReuseMapTo(ITextSourceVersion newVersion) { ITextSourceVersion oldVersion = this.Version; if (oldVersion == null || newVersion == null) { return(null); } if (!oldVersion.BelongsToSameDocumentAs(newVersion)) { return(null); } List <UnchangedSegment> reuseMap = new List <UnchangedSegment>(); reuseMap.Add(new UnchangedSegment(0, 0, this.TextLength)); foreach (var change in oldVersion.GetChangesTo(newVersion)) { bool needsSegmentRemoval = false; for (int i = 0; i < reuseMap.Count; i++) { UnchangedSegment segment = reuseMap[i]; if (segment.NewOffset + segment.Length <= change.Offset) { // change is completely after this segment continue; } if (change.Offset + change.RemovalLength <= segment.NewOffset) { // change is completely before this segment segment.NewOffset += change.InsertionLength - change.RemovalLength; reuseMap[i] = segment; continue; } // Change is overlapping segment. // Split segment into two parts: the part before change, and the part after change. var segmentBefore = new UnchangedSegment(segment.OldOffset, segment.NewOffset, change.Offset - segment.NewOffset); Debug.Assert(segmentBefore.Length < segment.Length); int lengthAtEnd = segment.NewOffset + segment.Length - (change.Offset + change.RemovalLength); var segmentAfter = new UnchangedSegment( segment.OldOffset + segment.Length - lengthAtEnd, change.Offset + change.InsertionLength, lengthAtEnd); Debug.Assert(segmentAfter.Length < segment.Length); Debug.Assert(segmentBefore.Length + segmentAfter.Length <= segment.Length); Debug.Assert(segmentBefore.NewOffset + segmentBefore.Length <= segmentAfter.NewOffset); Debug.Assert(segmentBefore.OldOffset + segmentBefore.Length <= segmentAfter.OldOffset); if (segmentBefore.Length > 0 && segmentAfter.Length > 0) { reuseMap[i] = segmentBefore; reuseMap.Insert(++i, segmentAfter); } else if (segmentBefore.Length > 0) { reuseMap[i] = segmentBefore; } else { reuseMap[i] = segmentAfter; if (segmentAfter.Length <= 0) { needsSegmentRemoval = true; } } } if (needsSegmentRemoval) { reuseMap.RemoveAll(s => s.Length <= 0); } } return(reuseMap); }
Task <ProjectEntry> DoParseAsync(ITextSource fileContent, IProject parentProject, bool requestFullParseInformation, CancellationToken cancellationToken) { // Create snapshot of file content, if required bool lookupOpenFileOnTargetThread; if (fileContent != null) { lookupOpenFileOnTargetThread = false; // File content was explicitly specified: // Let's make a snapshot in case the text source is mutable. fileContent = fileContent.CreateSnapshot(); } else if (SD.MainThread.InvokeRequired) { // fileContent == null && not on the main thread: // Don't fetch the file content right now; if we need to SafeThreadCall() anyways, // it's better to do so from the background task. lookupOpenFileOnTargetThread = true; } else { // fileContent == null && we are on the main thread: // Let's look up the file in the list of open files right now // so that we don't need to SafeThreadCall() later on. lookupOpenFileOnTargetThread = false; if (parser != null) { fileContent = parser.GetFileContent(fileName); } } Task <ProjectEntry> task; lock (runningAsyncParseLock) { if (fileContent != null) { // Optimization: // don't start a background task if fileContent was specified and up-to-date parse info is available rwLock.EnterReadLock(); try { int index = FindIndexForProject(parentProject); int versionComparison = CompareVersions(fileContent.Version); if (versionComparison == 0 && index >= 0) { // Ensure we have parse info for the specified project (entry.UnresolvedFile is null for newly registered projects) // If full parse info is requested, ensure we have full parse info. if (entries[index].UnresolvedFile != null && !(requestFullParseInformation && entries[index].CachedParseInformation == null)) { // We already have the requested version parsed, just return it: return(Task.FromResult(entries[index])); } } } finally { rwLock.ExitReadLock(); } // Optimization: // if an equivalent task is already running, return that one instead if (runningAsyncParseTask != null && (!requestFullParseInformation || runningAsyncParseFullInfoRequested) && runningAsyncParseProject == parentProject && runningAsyncParseFileContentVersion.BelongsToSameDocumentAs(fileContent.Version) && runningAsyncParseFileContentVersion.CompareAge(fileContent.Version) == 0) { return(runningAsyncParseTask); } } task = new Task <ProjectEntry>( delegate { try { if (lookupOpenFileOnTargetThread) { fileContent = SD.FileService.GetFileContentForOpenFile(fileName); } return(DoParse(fileContent, parentProject, requestFullParseInformation, cancellationToken)); } finally { lock (runningAsyncParseLock) { runningAsyncParseTask = null; runningAsyncParseFileContentVersion = null; runningAsyncParseProject = null; } } }, cancellationToken); if (fileContent != null && fileContent.Version != null && !cancellationToken.CanBeCanceled) { runningAsyncParseTask = task; runningAsyncParseFileContentVersion = fileContent.Version; runningAsyncParseProject = parentProject; runningAsyncParseFullInfoRequested = requestFullParseInformation; } } task.Start(); return(task); }