Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RenderDocumentToText adds an extra newline #21

Closed
seanomaly opened this issue Apr 2, 2018 · 9 comments
Closed

RenderDocumentToText adds an extra newline #21

seanomaly opened this issue Apr 2, 2018 · 9 comments
Assignees
Labels

Comments

@seanomaly
Copy link

seanomaly commented Apr 2, 2018

If I do this ConsoleRenderer.RenderDocument(doc); I get the output as expected.
But if I do this:
StringWriter sw = new StringWriter();
vs ConsoleRenderer.RenderDocumentAsText(doc, sw);
and then Console.WriteLine(sw.StringBuilder().toString());
There is an extra "\r\n" between each line.

@Athari Athari self-assigned this Apr 2, 2018
@Athari Athari added the type:bug Bug label Apr 2, 2018
@Athari Athari changed the title Render as text add an extra newline RenderDocumentAsText adds an extra newline Apr 2, 2018
@Athari Athari changed the title RenderDocumentAsText adds an extra newline RenderDocumentToText adds an extra newline Apr 2, 2018
@Athari Athari added type:support Support and removed type:bug Bug labels Apr 2, 2018
@Athari
Copy link
Owner

Athari commented Apr 2, 2018

@seanomaly Full code:

var doc = new Document(/* ... */);
var sw = new StringWriter();
ConsoleRenderer.RenderDocumentToText(doc, new TextRenderTarget(sw));
string str = sw.GetStringBuilder().ToString();
Console.WriteLine(str);

The problem lies in the way Windows console is implemented (actually, configured by .NET to behave). When current cursor position reaches the end of line (that is, when Console.CursorLeft == Console.BufferWidth), it automatically wraps the line. If then newline character is written, it adds a second line. You will face exactly the same problem if you call Console.WriteLine on a string containing exactly 80 characters.

If you inspect str variable from the code above, you'll notice that newline characters are inserted correctly, exactly once. Environment.NewLine is used to wrap lines because the library can't know how the string will be used — written to text file, output to console or sent as a part of a web page.

If you want a string which can be written to console, you need to override default new line sequence, even if it looks counterintuitive:

var sw = new StringWriter { NewLine = "" };
ConsoleRenderer.RenderDocumentToText(doc, new TextRenderTarget(sw));
Console.Write(sw.GetStringBuilder().ToString());

The produced string will contain no new lines, so will be written to console correctly. You also need to change WriteLine to just Write to avoid extra line wrap at the end.

Why are you using this method of writing to console?

@seanomaly
Copy link
Author

Thanks for the detailed explanation and the workaround.
I was using it as an optimization to output to a string and then calling Console.Write.
Using ConsoleRenderer.RenderDocument was just too slow.

On a related note, how do I get the output properly formatted on the command prompt? i.e. cmd.exe
I have been using conemu on which I get the formatting/color as expected but on cmd I just get a lot of junk characters.

@Athari
Copy link
Owner

Athari commented Apr 3, 2018

@seanomaly
Hmm, I need to work on optimization then. There's #11 which should be a major improvement, but number of calls to Console.Write can be cut down, I suppose. Currently ConsoleRenderTarget calls Write for every line, if I remember correctly. If that goes through interop, it's likely slower than allocating a larger text buffer to write in one call.

Also colors may be changed even if it isn't needed by the app... I should probably add rendering options to allow disabling some of attributes. But that would make sense only after implementing #11 and #14, which are planned for the next major release, so it would take some time to get there.

Speaking of formatting in cmd, ANSI escape codes are only supported in recent Windows 10 versions. Console apps themselves can set console character attributes through Windows API calls. See How to echo with different colors in the Windows command line.

@Athari
Copy link
Owner

Athari commented Apr 5, 2018

Support issue is resolved. #22 and #23 should eventually make this workaround unnecessary.

@Athari Athari closed this as completed Apr 5, 2018
@DumboJetEngine
Copy link

DumboJetEngine commented Nov 21, 2023

@Athari
I try to output a table/grid in a file, using your code above, but it gets mangled up.
Code:

    var doc = new Document(grid);
    ConsoleRenderer.RenderDocument(doc); // Render in console.
    using var sw = new StringWriter() { NewLine = "\n" };
    ConsoleRenderer.RenderDocumentToText(doc, new TextRenderTarget(sw));
    var tableText = sw.GetStringBuilder().ToString();
    File.AppendAllText(logPath, tableText + "\r\n"); // Render in file.

It renders beautifully in the console :
image
...but not in the file :
image
It appears that there are some trailing spaces on the right, and the cell content is missing.
And there are also those weird vertical lines at the end, that I have no idea why they are there.
Any quick ideas are welcome, because I have tried playing with the NewLine parameter and other things, and I had zero luck so far.

@Athari
Copy link
Owner

Athari commented Nov 21, 2023

@DumboJetEngine
Could you provide a self-contained reproducible example, so I could test it?

@DumboJetEngine
Copy link

@Athari
Sure! :)
Here you go:
Alba_CsConsoleFormat_Demo.zip

@Athari
Copy link
Owner

Athari commented Nov 21, 2023

@DumboJetEngine
Document objects aren't reusable. You need to recreate the document tree for each separate render.

As to spaces at the end of line, they come from ConsoleBuffer.Width. Rendering is still restricted to console width by default (or 80 characters, if console width is unavailable), even when rendering to a text file.

It's possible to set buffer width after measuring and arranging elements (see ConsoleRenderer.RenderDocumentToBuffer for the details of the process), but unless you have very specific needs (like completely unrestricted width), I think it's much easier to just trim the whitespace characters afterwards.

You'll need to trim whitespace either way as, say, paragraphs of text would still have trailing whitespace, even when rendered the exactly sized ConsoleBuffer, because buffers are always rectangular.

By the way, ConsoleRenderer.RenderDocumentToText returns the final string.

@DumboJetEngine
Copy link

Aha!
Thanks a lot. :)
I didn't know couldn't reuse the document.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants