How to add text to an empty file?

How can I update a IDocument object for an empty file? Everything I try throws an exception saying that a document can not be updated during a PSI transaction.

I've tried this

            IProjectFile newFile = AddNewItemUtil.AddFile(folder, unitTest + ".cs");
            IDocument doc = newFile.GetDocument();
            doc.InsertText(0, "public class test {}");


And I've tried this

            IProjectFile newFile = AddNewItemUtil.AddFile(folder, unitTest + ".cs");
            IDocument doc = newFile.GetDocument();
 
            pModule.GetPsiServices().Transactions.Execute("Write test class", () =>
            {
                doc.InsertText(0, "public class test {}");
            });


Please, can someone answer. I have googled, browse codeplex and github, searched these forums, but can not figure it out.

6 comments
Comment actions Permalink

You can't modify the document during a PSI transaction - ReSharper is expecting the PSI (that is, the abstract syntax tree) to be modified, and it will resync the document once the PSI transaction is committed. So, you could add content via the PSI, using something like CSharpElementFactory, or you need to start a document transaction, using DocumentTransactionManager.CreateTransactionCookie(DefaultAction.Commit, "useful debugging id")

0
Comment actions Permalink

Thanks Matt,

I've had success adding things to an existing ICSharpFile because I can get a reference to it from ICSharpContextActionDataProvider.PsiFile, but when I add a new file to a project I'm stuck.

 
IProjectFile newFile = AddNewItemUtil.AddFile(folder, unitTest + ".cs");


How do I get a reference to ICSharpFile from the IProjectFile reference above?

Once I have ICSharpFile I think I'll be able to do the rest on my own.

0
Comment actions Permalink

You can use the ToSourceFile() extension method on IProjectFile.

0
Comment actions Permalink

Okay, but ToSourceFile() returns IPsiSourceFile and ICSharpFile does not implement that interface.

Am I to cast from IPsiSourceFile to ICSharpFile?

0
Comment actions Permalink

I think I figured it out.

Is this the correct way to get the ICSharpFile reference?

            IProjectFile newFile = AddNewItemUtil.AddFile(folder, unitTest + ".cs");
            IPsiSourceFile sourceFile = newFile.ToSourceFile();
            CachedPsiFile cachedPsiFile = pModule.GetPsiServices().Files.GetCachedPsiFile(sourceFile, sourceFile.PrimaryPsiLanguage);
            ICSharpFile sharpFile = cachedPsiFile.PsiFile as ICSharpFile;
0
Comment actions Permalink

Gah! Half an answer. Sorry. That will do the trick, but it's better to call one of the overloaded GetPsiFiles methods. These defer to the cached files, but will also make sure the cache is primed first. There are also a couple of helper extension methods such as GetPrimaryPsiFile that simplify the method call (primary is the main language of the file, e.g. C#. Secondary is the tree for a "code behind file", e.g. the generated C# of an aspx file. Dominant is either the primary file, or the language of the code behind file, if there isn't a primary). And then once you've got the IFile, you need to downcast that to ICSharpFile.

0

Please sign in to leave a comment.