goblinfactory / konsole

Home of the simple console library consisting of ProgressBar, Window, Form, Draw & MockConsole (C# console progress bar with support for single or multithreaded progress updates) Window is a 100%-ish console compatible window, supporting all normal console writing to a windowed section of the screen, supporting scrolling and clipping of console output.
718 stars 62 forks source link

Prevent console window resize #68

Open martinweihrauch opened 3 years ago

martinweihrauch commented 3 years ago

Thank you for your great library! However, I ran into the problem that resizing of the console messes up the styling. I have read your closed "issue" about it, but I cannot figure out how to implement it with the current version. Could you give me a hint? Thx!

goblinfactory commented 3 years ago

That behaviour is actually a windows behavior of the windows console. there's a checkbox under windows console settings that you need to deselect, there's a screenshot described in issue https://github.com/goblinfactory/konsole/issues/33

goblinfactory commented 3 years ago

...also, if you use a HighSpeedWriter, you will get screen resize locking automatically. This will be simplified in the next major release of konsole, for now, use a highspeed writer as follows

using var writer = new HighSpeedWriter();
var window = new Window(writer);
window.CursorVisible = false;
window.Write("Hello");
window.WriteLine("  world!");
// call flush on the writer whenever you want to update the screen
writer.Flush();
goblinfactory commented 3 years ago

Drop me a message if you have any problems with the above.

martinweihrauch commented 3 years ago

Thank you for your fast reply! Now I transitioned from using the static Window to the window object, works excellent, also with the Flush! I am writing a very helpful application (open source) to copy Azure blobs to local storage, where the multiple progress is excellent, using Konsole. Will place it on GitHub under MIT, too! Again, thx!

goblinfactory commented 3 years ago

great! just be aware that it won't be cross platform. The highspeedWriter is windows platform only. you might want to have your app "log" events using a class you wire up depending on what platform you detect the user is on, use a sexy console app for windows, or a vanilla console writer for non windows platform. I hope to create a cross platform writer for konsole ...if I get enough time. For now, the highspeedWriter is windows only.

martinweihrauch commented 3 years ago

Ah OK! Would be great, if it also runs on e. g. Linux. Ok, then I would either use the highspeedwriter on Windows or use the static Window class for Linux.

martinweihrauch commented 3 years ago

BTW: After I implemented this new highspeedWriter with "locking" the screen, I sometimes get a weird effect after a while of having the console open: it repeats on the right side:

grafik

goblinfactory commented 3 years ago

Hi Martin what's the least amount of code possible to reproduce the problem reliably? If you can provide that, then I can look at a fix for you straight away. I can't promise a fix, but I can spend a bit of time right now if you can provide the same code to reproduce the problem. Txs, Alan

martinweihrauch commented 3 years ago

Sure. This program now runs for 24+ hours straight (copying blobs) and I just unlocked my windows to get this (not resizable, which is nice, but the to be refreshed parts were either completely gone or broken: grafik

martinweihrauch commented 3 years ago

The code:

`using BlobBackupLib.Azure.Model; using BlobBackupLib.Jobs.Model; using BlobBackupLib.Logging; using Konsole; using Konsole.Platform; using Microsoft.Azure.Management.Network.Fluent; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Text;

namespace AzureBlobToLocalBackupConsole { public class ConsoleOutput { private IConsole _topWindow; private IConsole _lowerWindow; private readonly List _pB; private readonly Job _job; private int _numberOfThreads; private AppSettings _aS; private HighSpeedWriter _writer;

    public ConsoleOutput(int num, Job job, AppSettings aS)
    {
        _pB = new List<ProgressBar>();
        _job = job;
        _aS = aS;
        _writer = new HighSpeedWriter();
        CreateConsoleElements(num);
        _numberOfThreads = num;
    }

    private void CreateConsoleElements(int num)
    {
        var window = new Window(_writer);
        window.CursorVisible = false;
        _topWindow = window.OpenBox("Azure Blob Backup - Info Console", 5, 1, _aS.ConsoleWidth - 10, _aS.ConsoleHeight - (num + 5), new BoxStyle() { ThickNess = LineThickNess.Double, Body = new Colors(ConsoleColor.White, ConsoleColor.Blue) });
        _lowerWindow = window.OpenBox("Current file(s) to backup", 5, _aS.ConsoleHeight - (num + 4), _aS.ConsoleWidth - 10, num + 3, new BoxStyle() { ThickNess = LineThickNess.Single });
        _topWindow.WriteLine("");
        _topWindow.WriteLine("      **** COMMODORE 64 BASIC V2 ****");
        _topWindow.WriteLine(" 64K RAM SYSTEM 38911 BASIC BYTES FREE");
        _topWindow.WriteLine("READY.");
        _topWindow.WriteLine("");
        _topWindow.WriteLine("Azure Blob to local Backup was programmed by (c) Smart In Media 2020");
        _topWindow.WriteLine("by Martin Weihrauch :)");

        for (var i = 0; i < num + 1; i++)

        {
            _pB.Add(new ProgressBar(_lowerWindow, _aS.ConsoleWidth - 2, _aS.ConsoleWidth - (int)(0.3 * (double)_aS.ConsoleWidth)));
        }
        _writer.Flush();
    }

    public void Flush()
    {
        _writer.Flush();
    }

    public void OutputToConsole(LoggingConsoleActions.Actions action, string text, bool lineFeed = true,  int id = -1, int progress = -1)
    {
        if(action == LoggingConsoleActions.Actions.Important)
        {
            if (lineFeed)
            {
                _topWindow.WriteLine(ConsoleColor.Yellow, text);
            }
            else
            {
                _topWindow.Write(ConsoleColor.Yellow, text);
            }
        }
        else if(action == LoggingConsoleActions.Actions.Error)
        {
            if (lineFeed)
            {
                _topWindow.WriteLine(ConsoleColor.Magenta, text);
            }
            else
            {
                _topWindow.Write(ConsoleColor.Magenta, text);

            }
        }

        else if(action == LoggingConsoleActions.Actions.Information)
        {
            if (lineFeed)
            {
                _topWindow.WriteLine(text);
            }
            else
            {
                _topWindow.Write(text);
            }
        }
        else
        {
            if(id == -1)
            {
                id = _numberOfThreads;
            }
            //Progress Update and text is filename
            text = text.Replace("\\", "/");
            string targetFolder = _job.DestinationFolder.Replace("\\", "/");
            text = text.Replace(targetFolder, "");
            _pB[id].Refresh(progress, text);

        }
        Flush();

    }
}

} `

martinweihrauch commented 3 years ago

But: I will publish the whole thing on Github in a week, then you can also check it out easier maybe...

goblinfactory commented 3 years ago

Hi Martin

The reason I ask for the least amount of code, is twofold, first, ...many times the act of creating that minimal "proof of problem" you find a work around that you can use while you wait for a fix. And secondly, it allows me to get a fix out for you a whole lot quicker.

p.s. looking at your code I think I should create a fluent add on for konsole so that you can chain calls to a window, that would be handly.

.WriteLine("")
.WriteLine("----")
or even

.WriteLine( 
  "",
  "------",
  "some line",
  "another line",
 "-------");

Anyhoo ... I Digress... if you can help me with a really small example, the absolutely most minimal code possible that reproduces the problem, that would help me get a fix out for you quickly.

(I'm going on leave next Friday and I have a few project commitments that will keep me busy at work till quite late each day.) Without something a lot simpler I'm going to have to wait until this weekend to investigate.

In the meantime I can suggest testing making the window 1 to 3 characters narrower or shorter than your window to see if either my code or your code is not clipping or handling the window height or width correctly. These are some random thoughts looking at your code.

Also, I'm assuming that the corruption only slowly happens over time, or does it start corrupting straight away? Last question, are you running from a standard window console or from within something like ConEmu or some other terminal emulator?

chat later, Alan

goblinfactory commented 3 years ago

Also, instead of

.WriteLine(ConsoleColor.Yellow, "I am Yellow");

you can add static using System.Console.ConsoleColor at the top of your code and then simply write

.WriteLine(Yellow, "I am yellow");
goblinfactory commented 3 years ago

also, if you're writing a command line utility, you may want to checkout https://github.com/psmacchia/NDepend.Path, .. looking at this bit of path munging you're doing it might be taking a look in case it's helpful?

text = text.Replace("\\", "/");
            string targetFolder = _job.DestinationFolder.Replace("\\", "/");
            text = text.Replace(targetFolder, "");
            _pB[id].Refresh(progress, text);
martinweihrauch commented 3 years ago

Thanks a lot for your great support! I was very busy now releasing the Blob to Local Backup program, which is completely open source under MIT and solves a major headache for backing up Azure blobs to local storage (because I feel that with a admin password on Azure, nothing is "really safe".

Here it is: https://github.com/smartinmedia/BlobToLocalBackup

It would be excellent, if you would ever support .NET Core with your new viewing capabilities, then my software would also work on Linux, but for now this doesn't seem so important :-)

goblinfactory commented 3 years ago

Nice! Glad I was able to help a great project! -> BlobToLocalBackup (I hope to find some time over this Christmas break to test BlobToLocalBackup) I can easily see something like that running as a custom synology app under docker, running on a schedule to backup the "tail" blobs (all blobs since "correlationID" x). I've not taken a look yet at your code, so you may already be doing that. Nice job on the excellent initial documentation! cheers, Alan (leaving this issue open for a bit, to give your project a bit of exposure)