コード例 #1
0
			public IEnumerable<TextChangeEventArgs> GetChangesTo(ITextBufferVersion other)
			{
				SnapshotVersion otherVersion = other as SnapshotVersion;
				if (otherVersion == null)
					throw new ArgumentException("Does not belong to same document");
				return checkpoint.GetChangesTo(otherVersion.checkpoint).Select(c => new TextChangeEventArgs(c.Offset, c.RemovedText, c.InsertedText));
			}
コード例 #2
0
ファイル: XamlParser.cs プロジェクト: ootsby/SharpDevelop
		/// <summary>
		/// Parse the given text and enter read lock.
		/// No parsing is done if the text is older than seen before.
		/// </summary>
		public IDisposable ParseAndLock(ITextBuffer fileContent)
		{
			// Copy to ensure thread-safety
			var lastVer = this.lastParsedVersion;
			if (lastVer == null ||                                       // First parse
			    fileContent.Version == null ||                           // Versioning not supported
			    !fileContent.Version.BelongsToSameDocumentAs(lastVer) || // Different document instance? Can happen after closing and reopening of file.
			    fileContent.Version.CompareAge(lastVer) > 0)             // Is fileContent newer?
			{
				parser.Lock.EnterWriteLock();
				// Double check, now that we are thread-safe
				lastVer = this.lastParsedVersion;
				if (lastVer == null || fileContent.Version == null || !fileContent.Version.BelongsToSameDocumentAs(lastVer)) {
					// First parse or versioning not supported
					using (DebugTimer.Time("normal parse"))
						parser.Parse(fileContent.Text, null);
					this.lastParsedVersion = fileContent.Version;
				} else if (fileContent.Version.CompareAge(lastParsedVersion) > 0) {
					// Incremental parse
					var changes = lastParsedVersion.GetChangesTo(fileContent.Version).
						Select(c => new DocumentChangeEventArgs(c.Offset, c.RemovedText, c.InsertedText));
					using (DebugTimer.Time("incremental parse"))
						parser.Parse(fileContent.Text, changes);
					this.lastParsedVersion = fileContent.Version;
				} else {
					// fileContent is older - no need to parse
				}
				parser.Lock.EnterReadLock();
				parser.Lock.ExitWriteLock();
			} else {
				// fileContent is older - no need to parse
				parser.Lock.EnterReadLock();
			}
			return new CallbackOnDispose(() => parser.Lock.ExitReadLock());
		}
コード例 #3
0
			public int CompareAge(ITextBufferVersion other)
			{
				SnapshotVersion otherVersion = other as SnapshotVersion;
				if (otherVersion == null)
					throw new ArgumentException("Does not belong to same document");
				return checkpoint.CompareAge(otherVersion.checkpoint);
			}
コード例 #4
0
			public int MoveOffsetTo(ITextBufferVersion other, int oldOffset, AnchorMovementType movement)
			{
				SnapshotVersion otherVersion = other as SnapshotVersion;
				if (otherVersion == null)
					throw new ArgumentException("Does not belong to same document");
				switch (movement) {
					case AnchorMovementType.AfterInsertion:
						return checkpoint.MoveOffsetTo(otherVersion.checkpoint, oldOffset, ICSharpCode.AvalonEdit.Document.AnchorMovementType.AfterInsertion);
					case AnchorMovementType.BeforeInsertion:
						return checkpoint.MoveOffsetTo(otherVersion.checkpoint, oldOffset, ICSharpCode.AvalonEdit.Document.AnchorMovementType.BeforeInsertion);
					default:
						throw new NotSupportedException();
				}
			}
コード例 #5
0
        /// <summary>
        /// Parse the given text and enter read lock.
        /// No parsing is done if the text is older than seen before.
        /// </summary>
        public IDisposable ParseAndLock(ITextBuffer fileContent)
        {
            // Copy to ensure thread-safety
            var lastVer = this.lastParsedVersion;

            if (lastVer == null ||                                                   // First parse
                fileContent.Version == null ||                                       // Versioning not supported
                !fileContent.Version.BelongsToSameDocumentAs(lastVer) ||             // Different document instance? Can happen after closing and reopening of file.
                fileContent.Version.CompareAge(lastVer) > 0)                         // Is fileContent newer?
            {
                parser.Lock.EnterWriteLock();
                // Double check, now that we are thread-safe
                lastVer = this.lastParsedVersion;
                if (lastVer == null || fileContent.Version == null || !fileContent.Version.BelongsToSameDocumentAs(lastVer))
                {
                    // First parse or versioning not supported
                    using (DebugTimer.Time("normal parse"))
                        parser.Parse(fileContent.Text, null);
                    this.lastParsedVersion = fileContent.Version;
                }
                else if (fileContent.Version.CompareAge(lastParsedVersion) > 0)
                {
                    // Incremental parse
                    var changes = lastParsedVersion.GetChangesTo(fileContent.Version).
                                  Select(c => new DocumentChangeEventArgs(c.Offset, c.RemovedText, c.InsertedText));
                    using (DebugTimer.Time("incremental parse"))
                        parser.Parse(fileContent.Text, changes);
                    this.lastParsedVersion = fileContent.Version;
                }
                else
                {
                    // fileContent is older - no need to parse
                }
                parser.Lock.EnterReadLock();
                parser.Lock.ExitWriteLock();
            }
            else
            {
                // fileContent is older - no need to parse
                parser.Lock.EnterReadLock();
            }
            return(new CallbackOnDispose(() => parser.Lock.ExitReadLock()));
        }
コード例 #6
0
            public void Clear()
            {
                ParseInformation parseInfo;

                ICompilationUnit[] oldUnits;
                lock (this) {
                    // by setting the disposed flag, we'll cause all running ParseFile() calls to return null and not
                    // call into the parser anymore, so we can do the remainder of the clean-up work outside the lock
                    this.disposed      = true;
                    parseInfo          = this.parseInfo;
                    oldUnits           = this.oldUnits;
                    this.oldUnits      = null;
                    this.bufferVersion = null;
                    this.parseInfo     = null;
                }
                foreach (ICompilationUnit oldUnit in oldUnits)
                {
                    oldUnit.ProjectContent.RemoveCompilationUnit(oldUnit);
                    bool isPrimary = parseInfo != null && parseInfo.CompilationUnit == oldUnit;
                    RaiseParseInformationUpdated(new ParseInformationEventArgs(fileName, oldUnit.ProjectContent, oldUnit, null, isPrimary));
                }
            }
コード例 #7
0
            public bool BelongsToSameDocumentAs(ITextBufferVersion other)
            {
                SnapshotVersion otherVersion = other as SnapshotVersion;

                return(otherVersion != null && checkpoint.BelongsToSameDocumentAs(otherVersion.checkpoint));
            }
コード例 #8
0
 public Snapshot(ITextSource textSource, ChangeTrackingCheckpoint checkpoint)
     : base(textSource)
 {
     this.version = new SnapshotVersion(checkpoint);
 }
コード例 #9
0
			public int MoveOffsetTo(ITextBufferVersion other, int oldOffset, AnchorMovementType movement)
			{
				SnapshotVersion otherVersion = other as SnapshotVersion;
				if (otherVersion == null)
					throw new ArgumentException("Does not belong to same document");
				switch (movement) {
					case AnchorMovementType.AfterInsertion:
						return checkpoint.MoveOffsetTo(otherVersion.checkpoint, oldOffset, ICSharpCode.AvalonEdit.Document.AnchorMovementType.AfterInsertion);
					case AnchorMovementType.BeforeInsertion:
						return checkpoint.MoveOffsetTo(otherVersion.checkpoint, oldOffset, ICSharpCode.AvalonEdit.Document.AnchorMovementType.BeforeInsertion);
					default:
						throw new NotSupportedException();
				}
			}
コード例 #10
0
			public IEnumerable<TextChangeEventArgs> GetChangesTo(ITextBufferVersion other)
			{
				SnapshotVersion otherVersion = other as SnapshotVersion;
				if (otherVersion == null)
					throw new ArgumentException("Does not belong to same document");
				return checkpoint.GetChangesTo(otherVersion.checkpoint).Select(c => new TextChangeEventArgs(c.Offset, c.RemovedText, c.InsertedText));
			}
コード例 #11
0
			public int CompareAge(ITextBufferVersion other)
			{
				SnapshotVersion otherVersion = other as SnapshotVersion;
				if (otherVersion == null)
					throw new ArgumentException("Does not belong to same document");
				return checkpoint.CompareAge(otherVersion.checkpoint);
			}
コード例 #12
0
			public bool BelongsToSameDocumentAs(ITextBufferVersion other)
			{
				SnapshotVersion otherVersion = other as SnapshotVersion;
				return otherVersion != null && checkpoint.BelongsToSameDocumentAs(otherVersion.checkpoint);
			}
コード例 #13
0
			public Snapshot(ITextSource textSource, ChangeTrackingCheckpoint checkpoint)
				: base(textSource)
			{
				this.version = new SnapshotVersion(checkpoint);
			}
コード例 #14
0
			public void Clear()
			{
				ICompilationUnit[] oldUnits;
				lock (this) {
					// by setting the disposed flag, we'll cause all running ParseFile() calls to return null and not
					// call into the parser anymore, so we can do the remainder of the clean-up work outside the lock
					this.disposed = true;
					oldUnits = this.oldUnits;
					this.oldUnits = null;
					this.bufferVersion = null;
				}
				foreach (ICompilationUnit oldUnit in oldUnits) {
					oldUnit.ProjectContent.RemoveCompilationUnit(oldUnit);
					RaiseParseInformationUpdated(new ParseInformationEventArgs(fileName, oldUnit.ProjectContent, oldUnit, null));
				}
			}
コード例 #15
0
			public ParseInformation ParseFile(IProjectContent parentProjectContent, ITextBuffer fileContent)
			{
				if (parser == null)
					return null;
				
				if (fileContent == null) {
					// GetParseableFileContent must not be called inside any lock
					// (otherwise we'd risk deadlocks because GetParseableFileContent must invoke on the main thread)
					fileContent = GetParseableFileContent(fileName);
				}
				
				ITextBufferVersion fileContentVersion = fileContent.Version;
				List<IProjectContent> projectContents;
				lock (this) {
					if (this.disposed)
						return null;
					
					if (fileContentVersion != null && this.bufferVersion != null && this.bufferVersion.BelongsToSameDocumentAs(fileContentVersion)) {
						if (this.bufferVersion.CompareAge(fileContentVersion) >= 0) {
							// Special case: (necessary due to parentProjectContent optimization)
							// Detect when a file belongs to multiple projects but the ParserService hasn't realized
							// that, yet. In this case, do another parse run to detect all parent projects.
							if (!(parentProjectContent != null && this.oldUnits.Length == 1 && this.oldUnits[0].ProjectContent != parentProjectContent)) {
								return this.parseInfo;
							}
						}
					}
					
					if (parentProjectContent != null && (oldUnits.Length == 0 || (oldUnits.Length == 1 && oldUnits[0].ProjectContent == parentProjectContent))) {
						// Optimization: if parentProjectContent is specified and doesn't conflict with what we already know,
						// we will use it instead of doing an expensive GetProjectContents call.
						projectContents = new List<IProjectContent>();
						projectContents.Add(parentProjectContent);
					} else {
						projectContents = GetProjectContents(fileName);
					}
				}
				// We now leave the lock to do the actual parsing.
				// This is done to allow IParser implementations to invoke methods on the main thread without
				// risking deadlocks.
				
				// parse once for each project content that contains the file
				ICompilationUnit[] newUnits = new ICompilationUnit[projectContents.Count];
				ICompilationUnit resultUnit = null;
				for (int i = 0; i < newUnits.Length; i++) {
					IProjectContent pc = projectContents[i];
					try {
						newUnits[i] = parser.Parse(pc, fileName, fileContent);
					} catch (Exception ex) {
						throw new ApplicationException("Error parsing " + fileName, ex);
					}
					if (i == 0 || pc == parentProjectContent)
						resultUnit = newUnits[i];
				}
				lock (this) {
					if (this.disposed)
						return null;
					
					// ensure we never go backwards in time (we need to repeat this check after we've reacquired the lock)
					if (fileContentVersion != null && this.bufferVersion != null && this.bufferVersion.BelongsToSameDocumentAs(fileContentVersion)) {
						if (this.bufferVersion.CompareAge(fileContentVersion) >= 0) {
							if (parentProjectContent != null && parentProjectContent != parseInfo.CompilationUnit.ProjectContent) {
								ICompilationUnit oldUnit = oldUnits.FirstOrDefault(o => o.ProjectContent == parentProjectContent);
								if (oldUnit != null)
									return new ParseInformation(oldUnit);
							}
							return this.parseInfo;
						}
					}
					
					ParseInformation newParseInfo = new ParseInformation(resultUnit);
					
					for (int i = 0; i < newUnits.Length; i++) {
						IProjectContent pc = projectContents[i];
						// update the compilation unit
						ICompilationUnit oldUnit = oldUnits.FirstOrDefault(o => o.ProjectContent == pc);
						pc.UpdateCompilationUnit(oldUnit, newUnits[i], fileName);
						ParseInformation newUnitParseInfo = (newUnits[i] == resultUnit) ? newParseInfo : new ParseInformation(newUnits[i]);
						RaiseParseInformationUpdated(new ParseInformationEventArgs(fileName, pc, oldUnit, newUnitParseInfo));
					}
					
					// remove all old units that don't exist anymore
					foreach (ICompilationUnit oldUnit in oldUnits) {
						if (!newUnits.Any(n => n.ProjectContent == oldUnit.ProjectContent)) {
							oldUnit.ProjectContent.RemoveCompilationUnit(oldUnit);
							RaiseParseInformationUpdated(new ParseInformationEventArgs(fileName, oldUnit.ProjectContent, oldUnit, null));
						}
					}
					
					this.bufferVersion = fileContentVersion;
					this.oldUnits = newUnits;
					this.parseInfo = newParseInfo;
					return newParseInfo;
				}
			}
コード例 #16
0
            public ParseInformation ParseFile(IProjectContent parentProjectContent, ITextBuffer fileContent)
            {
                if (parser == null)
                {
                    return(null);
                }

                if (fileContent == null)
                {
                    // GetParseableFileContent must not be called inside any lock
                    // (otherwise we'd risk deadlocks because GetParseableFileContent must invoke on the main thread)
                    try
                    {
                        fileContent = GetParseableFileContent(fileName);
                    }
                    catch (System.Reflection.TargetInvocationException ex)
                    {
                        // It is possible that the file gets deleted/becomes inaccessible while a background parse
                        // operation is enqueued, so we have to handle IO exceptions.
                        if (ex.InnerException is IOException || ex.InnerException is UnauthorizedAccessException)
                        {
                            return(null);
                        }
                        else
                        {
                            throw;
                        }
                    }
                    catch (IOException)
                    {
                        return(null);
                    }
                    catch (UnauthorizedAccessException)
                    {
                        return(null);
                    }
                }

                ITextBufferVersion     fileContentVersion = fileContent.Version;
                List <IProjectContent> projectContents;

                lock (this)
                {
                    if (this.disposed)
                    {
                        return(null);
                    }

                    if (fileContentVersion != null && this.bufferVersion != null && this.bufferVersion.BelongsToSameDocumentAs(fileContentVersion))
                    {
                        if (this.bufferVersion.CompareAge(fileContentVersion) >= 0)
                        {
                            // Special case: (necessary due to parentProjectContent optimization)
                            // Detect when a file belongs to multiple projects but the ParserService hasn't realized
                            // that, yet. In this case, do another parse run to detect all parent projects.
                            if (!(parentProjectContent != null && this.oldUnits.Length == 1 && this.oldUnits[0].ProjectContent != parentProjectContent))
                            {
                                return(this.parseInfo);
                            }
                        }
                    }

                    if (parentProjectContent != null && (oldUnits.Length == 0 || (oldUnits.Length == 1 && oldUnits[0].ProjectContent == parentProjectContent)))
                    {
                        // Optimization: if parentProjectContent is specified and doesn't conflict with what we already know,
                        // we will use it instead of doing an expensive GetProjectContents call.
                        projectContents = new List <IProjectContent>();
                        projectContents.Add(parentProjectContent);
                    }
                    else
                    {
                        projectContents = GetProjectContents(fileName);
                    }
                }
                // We now leave the lock to do the actual parsing.
                // This is done to allow IParser implementations to invoke methods on the main thread without
                // risking deadlocks.

                // parse once for each project content that contains the file
                ICompilationUnit[] newUnits   = new ICompilationUnit[projectContents.Count];
                ICompilationUnit   resultUnit = null;

                for (int i = 0; i < newUnits.Length; i++)
                {
                    IProjectContent pc = projectContents[i];
                    try
                    {
                        newUnits[i] = parser.Parse(pc, fileName, fileContent);
                    }
                    catch (Exception ex)
                    {
                        throw new ApplicationException("Error parsing " + fileName, ex);
                    }
                    if (i == 0 || pc == parentProjectContent)
                    {
                        resultUnit = newUnits[i];
                    }
                }
                lock (this)
                {
                    if (this.disposed)
                    {
                        return(null);
                    }

                    // ensure we never go backwards in time (we need to repeat this check after we've reacquired the lock)
                    if (fileContentVersion != null && this.bufferVersion != null && this.bufferVersion.BelongsToSameDocumentAs(fileContentVersion))
                    {
                        if (this.bufferVersion.CompareAge(fileContentVersion) >= 0)
                        {
                            if (parentProjectContent != null && parentProjectContent != parseInfo.CompilationUnit.ProjectContent)
                            {
                                ICompilationUnit oldUnit = oldUnits.FirstOrDefault(o => o.ProjectContent == parentProjectContent);
                                if (oldUnit != null)
                                {
                                    return(new ParseInformation(oldUnit));
                                }
                            }
                            return(this.parseInfo);
                        }
                    }

                    ParseInformation newParseInfo = new ParseInformation(resultUnit);

                    for (int i = 0; i < newUnits.Length; i++)
                    {
                        IProjectContent pc = projectContents[i];
                        // update the compilation unit
                        ICompilationUnit oldUnit = oldUnits.FirstOrDefault(o => o.ProjectContent == pc);
                        pc.UpdateCompilationUnit(oldUnit, newUnits[i], fileName);
                        ParseInformation newUnitParseInfo = (newUnits[i] == resultUnit) ? newParseInfo : new ParseInformation(newUnits[i]);
                        RaiseParseInformationUpdated(new ParseInformationEventArgs(fileName, pc, oldUnit, newUnitParseInfo, newUnits[i] == resultUnit));
                    }

                    // remove all old units that don't exist anymore
                    foreach (ICompilationUnit oldUnit in oldUnits)
                    {
                        if (!newUnits.Any(n => n.ProjectContent == oldUnit.ProjectContent))
                        {
                            oldUnit.ProjectContent.RemoveCompilationUnit(oldUnit);
                            RaiseParseInformationUpdated(new ParseInformationEventArgs(fileName, oldUnit.ProjectContent, oldUnit, null, false));
                        }
                    }

                    this.bufferVersion = fileContentVersion;
                    this.oldUnits      = newUnits;
                    this.parseInfo     = newParseInfo;
                    return(newParseInfo);
                }
            }