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();
                }
            }
        }
示例#2
0
 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;
 }
示例#3
0
 /// <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);
     }
 }
示例#5
0
 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));
     }
 }
示例#7
0
        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);
            }
        }
示例#8
0
        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);
        }