public ITextBuffer CreateTextBuffer(TextReader reader, IContentType contentType, long length, string traceId) { if (reader == null) { throw new ArgumentNullException("reader"); } if (contentType == null) { throw new ArgumentNullException("contentType"); } if (length > int.MaxValue) { throw new InvalidOperationException(Strings.FileTooLarge); } ITextStorageLoader loader; if (length < TextModelOptions.CompressedStorageFileSizeThreshold) { loader = new SimpleTextStorageLoader(reader, (int)length); } else { loader = new CompressedTextStorageLoader(reader, (int)length, traceId); } StringRebuilder content = SimpleStringRebuilder.Create(loader); ITextBuffer buffer = Make(contentType, content, false); if (!loader.HasConsistentLineEndings) { // leave a sign that line endings are inconsistent. This is rather nasty but for now // we don't want to pollute the API with this factoid buffer.Properties.AddProperty("InconsistentLineEndings", true); } // leave a similar sign about the longest line in the buffer. buffer.Properties.AddProperty("LongestLineLength", loader.LongestLineLength); return(buffer); }
public ReloadResult Reload(EditOptions options) { if (_isDisposed) { throw new ObjectDisposedException("ITextDocument"); } if (_raisingDirtyStateChangedEvent || _raisingFileActionChangedEvent) { throw new InvalidOperationException(); } var beforeSnapshot = _textBuffer.CurrentSnapshot; Encoding newEncoding = null; FallbackDetector fallbackDetector; try { _reloadingFile = true; // Load the file and read the contents to the text buffer long fileSize; using (var stream = TextDocumentFactoryService.OpenFileGuts(_filePath, out _lastModifiedTimeUtc, out fileSize)) { // We want to use the encoding indicated by a BoM if one is present because // VS9's editor did so. We can't let the StreamReader below detect // the byte order marks because we still want to be able to detect the // fallback condition. bool unused; newEncoding = EncodedStreamReader.CheckForBoM(stream, isStreamEmpty: out unused); Debug.Assert(newEncoding == null || newEncoding.GetPreamble().Length > 0); // TODO: Consider using the encoder detector extensions as well. if (newEncoding == null) { newEncoding = this.Encoding; } fallbackDetector = new FallbackDetector(newEncoding.DecoderFallback); var modifiedEncoding = (Encoding)newEncoding.Clone(); modifiedEncoding.DecoderFallback = fallbackDetector; using (var streamReader = new StreamReader(stream, modifiedEncoding, detectEncodingFromByteOrderMarks: false)) { TextBuffer concreteBuffer = _textBuffer as TextBuffer; if (concreteBuffer != null) { ITextStorageLoader loader; if (fileSize < TextModelOptions.CompressedStorageFileSizeThreshold) { loader = new SimpleTextStorageLoader(streamReader, (int)fileSize); } else { loader = new CompressedTextStorageLoader(streamReader, (int)fileSize, _filePath); } StringRebuilder newContent = SimpleStringRebuilder.Create(loader); if (!loader.HasConsistentLineEndings) { // leave a sign that line endings are inconsistent. This is rather nasty but for now // we don't want to pollute the API with this factoid. concreteBuffer.Properties["InconsistentLineEndings"] = true; } else { // this covers a really obscure case where on initial load the file had inconsistent line // endings, but the UI settings were such that it was ignored, and since then the file has // acquired consistent line endings and the UI settings have also changed. concreteBuffer.Properties.RemoveProperty("InconsistentLineEndings"); } // leave a similar sign about the longest line in the buffer. concreteBuffer.Properties["LongestLineLength"] = loader.LongestLineLength; concreteBuffer.ReloadContent(newContent, options, editTag: this); } else { // we may hit this path if somebody mocks the text buffer in a test. using (var edit = _textBuffer.CreateEdit(options, null, editTag: this)) { if (edit.Replace(new Span(0, edit.Snapshot.Length), streamReader.ReadToEnd())) { edit.Apply(); } else { edit.Cancel(); } } } Debug.Assert(streamReader.CurrentEncoding.CodePage == newEncoding.CodePage); Debug.Assert(streamReader.CurrentEncoding.GetPreamble().Length == newEncoding.GetPreamble().Length); } } } finally { _reloadingFile = false; } //The snapshot on a reload will change even if the contents of the before & after files are identical (differences will simply find an //empty set of changes) so this test is a measure of whether of not the reload succeeded. if (beforeSnapshot.Version.Next != null) { // Update status // set the "clean" reiterated version number to the reiterated version number of the version immediately // after the before snapshot (which is the state of the buffer after loading the document but before any // subsequent edits made in the text buffer changed events). _cleanReiteratedVersion = beforeSnapshot.Version.Next.ReiteratedVersionNumber; // TODO: the following event really should be queued up through the buffer group so that it comes before // the text changed event (and any subsequent text changed event invoked from an event handler) RaiseFileActionChangedEvent(_lastModifiedTimeUtc, FileActionTypes.ContentLoadedFromDisk, _filePath); this.Encoding = newEncoding; return(fallbackDetector.FallbackOccurred ? ReloadResult.SucceededWithCharacterSubstitutions : ReloadResult.Succeeded); } else { return(ReloadResult.Aborted); } }