/// <summary> /// Replaces given IVsTextLines with given MemoryStream content /// </summary> /// <param name="stream"></param> /// <param name="textLines"></param> /// <param name="removeFromUndoStack">True if new undo units (created by this operation) should be removed</param> public static void SaveStreamToBuffer(MemoryStream stream, IVsTextLines textLines, bool removeFromUndoStack) { if (stream == null) { throw new ArgumentNullException("stream"); } if (textLines == null) { throw new ArgumentNullException("textLines"); } byte[] buffer = stream.ToArray(); string text = Encoding.UTF8.GetString(buffer, 3, buffer.Length - 3); // get ResX file text int lastLine, lastLineIndex; int hr = textLines.GetLastLineIndex(out lastLine, out lastLineIndex); Marshal.ThrowExceptionForHR(hr); TextSpan[] spans = null; // replace current buffer text with new text hr = textLines.ReplaceLines(0, 0, lastLine, lastLineIndex, Marshal.StringToBSTR(text), text.Length, spans); Marshal.ThrowExceptionForHR(hr); if (removeFromUndoStack) { IOleUndoManager manager; // previous operation created undo unit - remove it hr = textLines.GetUndoManager(out manager); Marshal.ThrowExceptionForHR(hr); manager.RemoveTopFromUndoStack(1); } }
private IVsTextLines EnsureBufferCoordinator() { if (_secondaryBuffer != null) { return(_secondaryBuffer); } var vsTextBuffer = owner.Document.TextBuffer.QueryInterface <IVsTextBuffer>(); IVsEditorAdaptersFactoryService adapterFactory = WebEditor.ExportProvider.GetExport <IVsEditorAdaptersFactoryService>().Value; _secondaryBuffer = (adapterFactory.GetBufferAdapter(ProjectionBuffer.IProjectionBuffer) as IVsTextLines); if (_secondaryBuffer == null) { _secondaryBuffer = (adapterFactory.CreateVsTextBufferAdapterForSecondaryBuffer(vsTextBuffer.GetServiceProvider(), ProjectionBuffer.IProjectionBuffer) as IVsTextLines); } _secondaryBuffer.SetTextBufferData(VSConstants.VsTextBufferUserDataGuid.VsBufferDetectLangSID_guid, false); _secondaryBuffer.SetTextBufferData(VSConstants.VsTextBufferUserDataGuid.VsBufferMoniker_guid, owner.WorkspaceItem.PhysicalPath); IOleUndoManager oleUndoManager; _secondaryBuffer.GetUndoManager(out oleUndoManager); oleUndoManager.Enable(0); _textBufferCoordinator = adapterFactory.CreateVsTextBufferCoordinatorAdapter(); vsTextBuffer.SetTextBufferData(HtmlConstants.SID_SBufferCoordinatorServerLanguage, _textBufferCoordinator); vsTextBuffer.SetTextBufferData(typeof(VsTextBufferCoordinatorClass).GUID, _textBufferCoordinator); _textBufferCoordinator.SetBuffers(vsTextBuffer as IVsTextLines, _secondaryBuffer); return(_secondaryBuffer); }
/// <summary> /// Initializes objects used to access opened document's buffer /// </summary> protected void InitializeVariables() { currentDocument = VisualLocalizerPackage.Instance.DTE.ActiveDocument; if (currentDocument == null) { throw new Exception("No selected document"); } if (currentDocument.ReadOnly) { throw new Exception("Cannot perform this operation - active document is readonly"); } bool fileOpened; currentCodeModel = currentDocument.ProjectItem.GetCodeModel(false, false, out fileOpened); textManager = (IVsTextManager)Package.GetGlobalService(typeof(SVsTextManager)); if (textManager == null) { throw new Exception("Cannot consume IVsTextManager service"); } int hr = textManager.GetActiveView(1, null, out textView); Marshal.ThrowExceptionForHR(hr); hr = textView.GetBuffer(out textLines); Marshal.ThrowExceptionForHR(hr); hr = textLines.GetUndoManager(out undoManager); Marshal.ThrowExceptionForHR(hr); }
/// <remarks> /// <para>The optional project is used to obtain an <see cref="IVsProject"/> instance. When this instance is /// provided, Visual Studio will use <see cref="IVsProject.IsDocumentInProject"/> to attempt to locate the /// specified file within a project. If no project is specified, Visual Studio falls back to using /// <see cref="IVsUIShellOpenDocument4.IsDocumentInAProject2"/>, which performs a much slower query of all /// projects in the solution.</para> /// </remarks> public InvisibleEditor(IServiceProvider serviceProvider, string filePath, IVsHierarchy?hierarchy, bool needsSave, bool needsUndoDisabled) : base(serviceProvider.GetMefService <IThreadingContext>(), assertIsForeground: true) { _serviceProvider = serviceProvider; _filePath = filePath; _needsSave = needsSave; var invisibleEditorManager = (IIntPtrReturningVsInvisibleEditorManager)serviceProvider.GetService(typeof(SVsInvisibleEditorManager)); var vsProject = hierarchy as IVsProject; Marshal.ThrowExceptionForHR(invisibleEditorManager.RegisterInvisibleEditor(filePath, vsProject, 0, null, out var invisibleEditorPtr)); try { _invisibleEditor = (IVsInvisibleEditor)Marshal.GetUniqueObjectForIUnknown(invisibleEditorPtr); var docDataPtr = IntPtr.Zero; Marshal.ThrowExceptionForHR(_invisibleEditor.GetDocData(fEnsureWritable: needsSave ? 1 : 0, riid: typeof(IVsTextLines).GUID, ppDocData: out docDataPtr)); try { var docData = Marshal.GetObjectForIUnknown(docDataPtr); _vsTextLines = (IVsTextLines)docData; var editorAdapterFactoryService = serviceProvider.GetMefService <IVsEditorAdaptersFactoryService>(); _buffer = editorAdapterFactoryService.GetDocumentBuffer(_vsTextLines); if (needsUndoDisabled) { Marshal.ThrowExceptionForHR(_vsTextLines.GetUndoManager(out _manager)); Marshal.ThrowExceptionForHR(((IVsUndoState)_manager).IsEnabled(out var isEnabled)); _needsUndoRestored = isEnabled != 0; if (_needsUndoRestored) { _manager.DiscardFrom(null); // Discard the undo history for this document _manager.Enable(0); // Disable Undo for this document } } } finally { Marshal.Release(docDataPtr); } } finally { // We need to clean up the extra reference we have, now that we have an RCW holding onto the object. Marshal.Release(invisibleEditorPtr); } }
public int GetUndoManager(out IOleUndoManager ppUndoManager) { return(_textBuffer.GetUndoManager(out ppUndoManager)); }
public void Move(List <CodeStringResultItem> dataList, ref int errorRows) { // sort according to position dataList.Sort(new ResultItemsPositionCompararer <CodeStringResultItem>()); for (int i = dataList.Count - 1; i >= 0; i--) { try { // initialization of data CodeStringResultItem resultItem = dataList[i]; string path = resultItem.SourceItem.GetFullPath(); ReferenceString referenceText = null; bool addUsingBlock = false; CONTAINS_KEY_RESULT keyConflict = CONTAINS_KEY_RESULT.DOESNT_EXIST; if (resultItem.MoveThisItem) // row was checked in the toolwindow { Validate(resultItem); // check that key, value and destination item was specifed and that row has no errors if (!resultItem.DestinationItem.IsLoaded) { resultItem.DestinationItem.Load(); } if (!loadedResxItems.Contains(resultItem.DestinationItem)) { loadedResxItems.Add(resultItem.DestinationItem); } // check if such item already exists in destination file keyConflict = resultItem.DestinationItem.GetKeyConflictType(resultItem.Key, resultItem.Value, true); if (keyConflict == CONTAINS_KEY_RESULT.EXISTS_WITH_DIFF_VALUE) { throw new InvalidOperationException(string.Format("Key \"{0}\" already exists with different value.", resultItem.Key)); } resultItem.Key = resultItem.DestinationItem.GetRealKey(resultItem.Key); // if key already exists, return its name (solves case-sensitivity problems) NamespacesList usedNamespaces = GetUsedNamespacesFor(resultItem); if (UseFullName || resultItem.MustUseFullName || (resultItem.Language == LANGUAGE.VB && resultItem.DestinationItem.IsProjectDefault(resultItem.SourceItem.ContainingProject))) // reference will contain namespace { referenceText = new ReferenceString(resultItem.DestinationItem.Namespace, resultItem.DestinationItem.Class, resultItem.Key); addUsingBlock = false; // no using block will be added } else { // use resolver whether it is ok to add using block addUsingBlock = usedNamespaces.ResolveNewElement(resultItem.DestinationItem.Namespace, resultItem.DestinationItem.Class, resultItem.Key, resultItem.SourceItem.ContainingProject, out referenceText); } if (addUsingBlock) // new using block will be added { if (!usedNamespacesCache.ContainsKey(resultItem.SourceItem)) { usedNamespacesCache.Add(resultItem.SourceItem, new NamespacesList()); } foreach (var pair in usedNamespacesCache) { if (!pair.Value.ContainsNamespace(resultItem.DestinationItem.Namespace)) { pair.Value.Add(resultItem.DestinationItem.Namespace, null, true); } } } } if (RDTManager.IsFileOpen(path) && RDTManager.IsFileVisible(path)) // file is open { if (resultItem.MoveThisItem || (MarkUncheckedStringsWithComment && !resultItem.IsMarkedWithUnlocalizableComment)) // string literal in text will be modified (referenced or marked with comment) { if (!buffersCache.ContainsKey(path)) { // load file's buffer IVsTextLines textLines = DocumentViewsManager.GetTextLinesForFile(path, false); buffersCache.Add(path, textLines); IOleUndoManager m; // get file's undo manager int hr = textLines.GetUndoManager(out m); Marshal.ThrowExceptionForHR(hr); undoManagersCache.Add(path, m); } } if (resultItem.MoveThisItem) { // perform the text replacement MoveToResource(buffersCache[path], resultItem, referenceText); if (resultItem.IsConst && resultItem.CodeModelSource is CodeVariable2) { CodeVariable2 codeVar = (CodeVariable2)resultItem.CodeModelSource; codeVar.ConstKind = vsCMConstKind.vsCMConstKindNone; } if (addUsingBlock) { // add using block to the source file int beforeLines, afterLines; buffersCache[path].GetLineCount(out beforeLines); resultItem.AddUsingBlock(buffersCache[path]); buffersCache[path].GetLineCount(out afterLines); int diff = afterLines - beforeLines; // because of the previous step, it is necessary to adjust position of all not-yet referenced result items for (int j = i; j >= 0; j--) { var item = dataList[j]; if (item.SourceItem == resultItem.SourceItem) { TextSpan ts = new TextSpan(); ts.iEndIndex = item.ReplaceSpan.iEndIndex; ts.iEndLine = item.ReplaceSpan.iEndLine + diff; ts.iStartIndex = item.ReplaceSpan.iStartIndex; ts.iStartLine = item.ReplaceSpan.iStartLine + diff; item.ReplaceSpan = ts; } } } // previous step (replace and possibly new using block) caused undo unit to be added - remove it int unitsToRemoveCount = (resultItem.IsConst && addUsingBlock ? 3 : (resultItem.IsConst || addUsingBlock ? 2 : 1)); List <IOleUndoUnit> units = undoManagersCache[path].RemoveTopFromUndoStack(unitsToRemoveCount); // and add custom undo unit AbstractUndoUnit newUnit = null; if (keyConflict == CONTAINS_KEY_RESULT.DOESNT_EXIST) { newUnit = new MoveToResourcesUndoUnit(resultItem.Key, resultItem.Value, resultItem.DestinationItem); } else if (keyConflict == CONTAINS_KEY_RESULT.EXISTS_WITH_SAME_VALUE) { newUnit = new MoveToResourcesReferenceUndoUnit(resultItem.Key); } newUnit.AppendUnits.AddRange(units); undoManagersCache[path].Add(newUnit); } else if (MarkUncheckedStringsWithComment && !resultItem.IsMarkedWithUnlocalizableComment) // string literal should be marked with comment { AspNetStringResultItem aitem = resultItem as AspNetStringResultItem; // this operation is only possible if string literal comes from C# code if (resultItem is CSharpStringResultItem || (aitem != null && aitem.ComesFromCodeBlock && aitem.Language == LANGUAGE.CSHARP)) { // add the comment int c = MarkAsNoLoc(buffersCache[path], resultItem); // add undo unit List <IOleUndoUnit> units = undoManagersCache[path].RemoveTopFromUndoStack(1); MarkAsNotLocalizedStringUndoUnit newUnit = new MarkAsNotLocalizedStringUndoUnit(resultItem.Value); newUnit.AppendUnits.AddRange(units); undoManagersCache[path].Add(newUnit); } } } else // file is closed // same as with open file, only operating with text, not buffers { if (resultItem.MoveThisItem || (MarkUncheckedStringsWithComment && !resultItem.IsMarkedWithUnlocalizableComment)) // string literal will be modified // load file's text into the cache { if (!filesCache.ContainsKey(path)) { filesCache.Add(path, new StringBuilder(File.ReadAllText(path))); } } if (resultItem.IsConst && resultItem.CodeModelSource is CodeVariable2) { CodeVariable2 codeVar = (CodeVariable2)resultItem.CodeModelSource; fieldsToRemoveConst.Add(codeVar); } if (resultItem.MoveThisItem) { StringBuilder b = filesCache[path]; // perform the replacement string insertText = resultItem.GetReferenceText(referenceText); b.Remove(resultItem.AbsoluteCharOffset, resultItem.AbsoluteCharLength); b.Insert(resultItem.AbsoluteCharOffset, insertText); if (addUsingBlock) { // add using block if (!newUsingsPlan.ContainsKey(path)) { newUsingsPlan.Add(path, new List <string>()); } newUsingsPlan[path].Add(resultItem.DestinationItem.Namespace); } } else if (MarkUncheckedStringsWithComment && !resultItem.IsMarkedWithUnlocalizableComment) { AspNetStringResultItem aitem = resultItem as AspNetStringResultItem; if (resultItem is CSharpStringResultItem || (aitem != null && aitem.ComesFromCodeBlock && aitem.Language == LANGUAGE.CSHARP)) { StringBuilder b = filesCache[path]; b.Insert(resultItem.AbsoluteCharOffset, resultItem.NoLocalizationComment); } } } if (resultItem.MoveThisItem && keyConflict == CONTAINS_KEY_RESULT.DOESNT_EXIST) { if (!resultItem.DestinationItem.IsInBatchMode) { resultItem.DestinationItem.BeginBatch(); } // add the key to the ResX file resultItem.DestinationItem.AddString(resultItem.Key, resultItem.Value); } } catch (Exception ex) { errorRows++; VLOutputWindow.VisualLocalizerPane.WriteException(ex); } } // add using blocks to closed files texts foreach (var pair in newUsingsPlan) { foreach (string nmspc in pair.Value) { AddUsingBlockTo(pair.Key, nmspc); } } // flush closed files texts foreach (var pair in filesCache) { if (RDTManager.IsFileOpen(pair.Key)) { RDTManager.SetIgnoreFileChanges(pair.Key, true); File.WriteAllText(pair.Key, pair.Value.ToString()); RDTManager.SetIgnoreFileChanges(pair.Key, false); RDTManager.SilentlyReloadFile(pair.Key); } else { File.WriteAllText(pair.Key, pair.Value.ToString()); } } // remove 'const' modifier from fields in closed files HashSet <ProjectItem> itemsToSave = new HashSet <ProjectItem>(); foreach (CodeVariable2 codeVar in fieldsToRemoveConst) { codeVar.ConstKind = vsCMConstKind.vsCMConstKindNone; itemsToSave.Add(codeVar.ProjectItem); } foreach (ProjectItem item in itemsToSave) { item.Save(null); } foreach (ResXProjectItem item in loadedResxItems) { if (item.IsInBatchMode) { item.EndBatch(); } item.Unload(); } if (errorRows > 0) { throw new Exception("Error occured while processing some rows - see Output window for details."); } }
public void Inline(List <CodeReferenceResultItem> dataList, bool externalChange, ref int errorRows) { // sort according to position dataList.Sort(new ResultItemsPositionCompararer <CodeReferenceResultItem>()); // start with the last items - not necessary to adjust position of many items after replace for (int i = dataList.Count - 1; i >= 0; i--) { try { CodeReferenceResultItem resultItem = dataList[i]; if (resultItem.MoveThisItem) // the item was checked in the toolwindow grid { int absoluteStartIndex, absoluteLength; // get text that replaces the result item string text = GetReplaceString(resultItem); // get position information about block to replace TextSpan inlineSpan = GetInlineReplaceSpan(resultItem, out absoluteStartIndex, out absoluteLength); string path = resultItem.SourceItem.GetFullPath(); if (RDTManager.IsFileOpen(path) && RDTManager.IsFileVisible(path)) // file is open { if (!buffersCache.ContainsKey(path)) // file's buffer is not yet loaded // load buffer { IVsTextLines textLines = DocumentViewsManager.GetTextLinesForFile(path, false); buffersCache.Add(path, textLines); IOleUndoManager m; // load undo manager int hr = textLines.GetUndoManager(out m); Marshal.ThrowExceptionForHR(hr); undoManagersCache.Add(path, m); } // replace the result item with the new text int h = buffersCache[path].ReplaceLines(inlineSpan.iStartLine, inlineSpan.iStartIndex, inlineSpan.iEndLine, inlineSpan.iEndIndex, Marshal.StringToBSTR(text), text.Length, new TextSpan[] { inlineSpan }); Marshal.ThrowExceptionForHR(h); // previous step caused undo unit to be added - remove it List <IOleUndoUnit> units = undoManagersCache[path].RemoveTopFromUndoStack(1); // and add custom undo unit which includes whole operation AbstractUndoUnit newUnit = GetUndoUnit(resultItem, externalChange); newUnit.AppendUnits.AddRange(units); undoManagersCache[path].Add(newUnit); } else { if (!filesCache.ContainsKey(path)) // file is not yet loaded // load the file and save it in cache { filesCache.Add(path, new StringBuilder(File.ReadAllText(path))); } StringBuilder b = filesCache[path]; // replace the text b = b.Remove(absoluteStartIndex, absoluteLength); b = b.Insert(absoluteStartIndex, text); filesCache[path] = b; } } } catch (Exception ex) { errorRows++; VLOutputWindow.VisualLocalizerPane.WriteException(ex); } } foreach (var pair in filesCache) { if (RDTManager.IsFileOpen(pair.Key)) { RDTManager.SetIgnoreFileChanges(pair.Key, true); File.WriteAllText(pair.Key, pair.Value.ToString()); RDTManager.SetIgnoreFileChanges(pair.Key, false); RDTManager.SilentlyReloadFile(pair.Key); } else { File.WriteAllText(pair.Key, pair.Value.ToString()); } } if (errorRows > 0) { throw new Exception("Error occured while processing some rows - see Output window for details."); } }