Closed GoogleCodeExporter closed 8 years ago
Original comment by RoryBec...@gmail.com
on 15 Oct 2012 at 8:43
Without knowing how to repro it, the best I can do is add a catch/log there,
which I'll do.
Original comment by travis.illig
on 25 Oct 2012 at 10:58
It's throwing on a document activate call. That is...
var docToFormat; // method parameter
Document active = CodeRush.Documents.Active;
if(docToFormat != active)
{
docToFormat.Activate();
}
Have to do that because I can only call CodeRush.Documents.Format() on an
active document, which means basically that the format-on-save function is
cycling through all the docs, making each one active, and doing the format.
I'm guessing this scenario was a "saving while the file is closing" thing.
Like, hit the "Close" button, see the option to save, click OK, and a race
condition happens where the doc is closed before it can be formatted.
Like I said, I can add the catch, but I'm not sure about how to truly fix it. I
might need some help with that from someone more involved with DXCore...
ALEX...? :)
Original comment by travis.illig
on 25 Oct 2012 at 11:03
OK, I added that catch/log block. I'll test it some more and post an update,
but it'd be nice to know how I might be able to determine if the document is
closing... and get to format it before the close finishes. I think that's
beyond the scope of my abilities.
Original comment by travis.illig
on 25 Oct 2012 at 11:13
I think try/catch will work. To determine if the document is being closed,
there's an event for this - EventNexus.DocumentClosing.
Original comment by AlexSkor...@gmail.com
on 26 Oct 2012 at 8:40
try/catch does catch it and it is when the user does a save-on-close.
I'm not sure how I'd actually fix that. I can't format a document unless it's
made active but I can't make a closing document active (can I?). I guess it's
an edge case I won't be able to handle.
Original comment by travis.illig
on 26 Oct 2012 at 10:23
Released version 2.0.2 of the extension which includes the try/catch/log. I
still can't format a document that's closing, but at least it won't blow up.
Original comment by travis.illig
on 26 Oct 2012 at 10:54
Travis,
I don't think you should activate the document when it is closing. However, you
may try formatting a document when it is just closed via a text buffer
string documentFullName = textDocument.FullName;
ITextBuffer textBuffer = CodeRush.TextBuffers[documentFullName];
if (textBuffer == null)
textBuffer = CodeRush.TextBuffers.Open(documentFullName);
if (textBuffer != null)
textBuffer.Format(textBuffer.Range);
Original comment by AlexSkor...@gmail.com
on 29 Oct 2012 at 1:42
Okay, that's something I didn't know you could do - I'll see if I can do that
instead of what I'm doing now.
Original comment by travis.illig
on 29 Oct 2012 at 10:34
This is probably pretty dumb but... once I've formatted it like that (which
works) how do I save the document back? CodeRush.TextBuffers doesn't have a
Save option, ITextBuffer doesn't have a Save, and I don't see any static Save
methods on any related classes.
Original comment by travis.illig
on 29 Oct 2012 at 11:00
I may have spoken too soon on this working at all. When the document is
closing/closed, the document FullName property is null, so the text buffer
never gets loaded. The private field _FullName has a value (I can see it in the
debugger) but the property returns null, which I gather means the document
itself has been otherwise removed from Visual Studio.
What that boils down to is, this:
if(textBuffer == null)
textBuffer = CodeRush.TextBuffers.Open(documentFullName);
is effectively
if(textBuffer == null)
textBuffer = CodeRush.TextBuffers.Open(null);
Or, with the Open call evaluated:
if(textBuffer == null)
textBuffer = null;
So I can get around activating the document, it seems, but I still can't format
a document when someone closes it unless I do some reflection spelunking to get
the _FullName variable and then do some manual file saving using streams and
the contents of the ITextBuffer.
Does that sound right?
Original comment by travis.illig
on 29 Oct 2012 at 11:19
Well... right or wrong, here's what I have working. Double-check me, if you
would:
public static void FormatDocument(Document doc)
{
if (doc == null)
{
throw new ArgumentNullException("doc");
}
bool isClosed = false;
var docFullName = doc.FullName;
if (docFullName == null)
{
// The document name will be null if the file is closed, but the
// private instance property will still have the filename we need
// to re-format.
isClosed = true;
docFullName = typeof(Document).GetField("_FullName", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic).GetValue(doc) as String;
}
var textBuffer = CodeRush.TextBuffers[docFullName];
if (textBuffer == null)
{
// If the document has already closed, we can re-open it in the
// background to format it.
textBuffer = CodeRush.TextBuffers.Open(docFullName);
}
if (textBuffer != null)
{
var result = textBuffer.Format(textBuffer.Range);
if (result == FormatResult.Success)
{
if (isClosed)
{
// If the document is closed, we have to manually save
// it using an exclusive locking filestream. Without the
// locking, VS may not have fully written the doc yet and we
// end up in a race condition where the file contents
// get all mangled.
using (var stream = File.Open(docFullName, FileMode.Truncate, FileAccess.Write, FileShare.None))
using (var writer = new StreamWriter(stream))
{
writer.Write(textBuffer.Text);
}
}
else
{
// If the document is still active in VS, saving is way easier.
doc.Save(docFullName);
}
}
}
}
Original comment by travis.illig
on 29 Oct 2012 at 11:45
Travis,
What about the Path property of a TextDocument? Is it null as well? If not, I
think you can use that instead.
To save the formatted text buffer, you may use the FileChange object as
described in this article -
http://www.skorkin.com/2011/07/how-to-automatically-edit-source-files-of-an-enti
re-visual-studio-solution-using-dxcore/
Original comment by devexpre...@gmail.com
on 30 Oct 2012 at 3:54
TextDocument.Path throws a NullReferenceException. I'm guessing the
DocumentObject has already been nulled out since the doc is closing/closed from
Visual Studio.
I'll have to check out the FileChange thing. Is that recommended over just
writing to files using a stream as shown above? What's the benefit/difference?
Original comment by travis.illig
on 30 Oct 2012 at 10:18
One downside to FileChange - since I'm replacing the contents of the whole
document (for each document that is being formatted) I lose the caret position.
It jumps down to the end of the file. Document.Save doesn't lose the position,
even with the formatting.
I suppose I could save/restore all the positions manually, but... eh. Unless
there's some benefit to FileChange I don't know about, I will just stick with
doc.Save for open docs and writing via streams for the closed docs.
Original comment by travis.illig
on 30 Oct 2012 at 10:29
One case I still can't handle - user saves the document while closing Visual
Studio. My plugin doesn't seem to get the event.
That's SUPER edge case, though.
Original comment by travis.illig
on 31 Oct 2012 at 12:40
FileChange has the benefits when you do multiple edits of a single file. It
will automatically sort, group and apply them to not break the structure of the
code. If you replace the entire file, then there are now benefits.
Original comment by devexpre...@gmail.com
on 31 Oct 2012 at 9:50
When I close Visual Studio, I can't save the file. Furthermore, Visual Studio
checks if there are unsaved files and suggests you to save them.
Original comment by devexpre...@gmail.com
on 31 Oct 2012 at 9:52
The last two comments are posted by me :-)
Original comment by AlexSkor...@gmail.com
on 31 Oct 2012 at 9:54
For now it appears I'm going to be unable to deal with save-on-close, but I
posted a fix for everything else. I'll mark it closed for now; feel free to
re-open if it breaks again. :)
Original comment by travis.illig
on 31 Oct 2012 at 9:21
Thank you for the fix, Travis!
Original comment by AlexSkor...@gmail.com
on 1 Nov 2012 at 9:15
Original issue reported on code.google.com by
AlexSkor...@gmail.com
on 15 Oct 2012 at 8:21