Maximus5 / conemu-inside

An example, how to embed http://conemu.github.io/ into another graphical application
57 stars 42 forks source link

Write Text to Console Programmatically #3

Closed hypersw closed 8 years ago

hypersw commented 8 years ago

Here I mean not stdin but emulating stdout, as if the program has written smth to the console, as the "second stream".

99% cases would probably be:

1) Write out smth before the console payload process runs.

(which means this has to be set up in conemu cmdline or better settings XML, because otherwise we can't guarantee the greeting goes before the payload text)

2) Write out smth after it terminates.

(which can be set up as customizing the conemuc's "press esc or enter" text, also has to be done before starting)

These two could be seen in wide use e.g. in GitExtensions in the console windows I'm currently in process of upgrading.

Writing smth in the process might also be useful (e.g. we parsed the stage out of the stream and want to comment on it), but is much less critical.

Maximus5 commented 8 years ago

The solution may be either simple or complicated.

Actually, I think that greetings message may differ my shell/Task. So, probably the best way is adding something like type "bla-bla-bla.txt" & to Task contents. Alternatives: ConEmuC -t "file" &, ConEmuC -e "string with escapes" &.

Final message... Well, may be it may be implemented as -cur_console:c:"Your final message". Yep, it may depends on shell/Task too.

Printing while process is running? Hmm... That may harm running process output, or may be overwritten by processes in next second. Well, there's no problem to implement something like Write("bla-bla-bla") GuiMacro, but where you'll write it? Above cursor? It may overwrite process output. Below cursor? Process may go next line next second and overwrite this text.

hypersw commented 8 years ago

1) How to pass the messages. I'd say that some out-of-cmdline method is a must because of: (a) cmdline string escaping which makes it complicated to pass arbitrary messages, even worse, it is irreversible with standard cmdline parsers; (b) there's a limit over the length of the cmdline, some payload processes might come close to that limit (java with its classpath is often at risk), so adding a lengthy text to the payload cmdline might go over the limit. So there should be a way to pass it in some file.

Intuitively I'd prefer the Settings.xml file. It's got StartTasksName and EnvironmentSet and probably smth else per-task. It's already being written to run conemu in the control, so this keeps the writing to the single file. Escaping is not a problem with XML.

hypersw commented 8 years ago

2) Final message. Logically, and based on GE usages analysis, the final message might not be known until the payload process exits. At a minimum, it's "Done"/"Failed" based on the errorlevel, or some other info based on what the process has done. So I'd file it under "writing to the terminal stdout programmatically".

hypersw commented 8 years ago

2.1) Still need a way to suppress the standard message by -cur_console:c, of "… with ESC or Enter".

hypersw commented 8 years ago

3) Writing to stdout. If it's possible to write to the terminal's stdout right the way the process itself would do it, then that's it. This decides on above/below caret question: just writes at the caret location and moves it. Looks as if you're doing printf from more than one thread. Yep might interfere with the process output, but let's assume the controlling app knows what it's doing and why. Parses process ANSI stream output, or detects some files written, and knows where to say the additional stuff. When the payload process has exited, for example. That's one useful thing to do.

Maximus5 commented 8 years ago

OK, here is the concept:

  1. Implement switch -cur_console:c0 which would "Wait for ESC or ENTER", but without confirmation message.
  2. Implement GuiMacro Shell("cur_console",...) which would execute an application in the existing console. Of course, parent process must be aware of the consenquences. So, you would be able to run ConEmuC with switches -e or -t to print anything.
hypersw commented 8 years ago
  1. Yep, that's good.
  2. So it's a recipe to spawn a conemuc process which will spawn another process (like cmd with type command) with its satellite processes like conhost, all to print a message to the stdout console file… well, If you say so…
  3. I've analyzed usages, in many of the cases the greeting is but echo of the command itself. Is it possible to make the terminal echo its task command into stdout before actually running it (much like ECHO ON would do)?
Maximus5 commented 8 years ago
  1. Nope. ConEmuC has switches -echo and -type. Check docs. You would be able to execute it or new root process, I hope.
  2. This is not possible now. I don't think this feature must be deployed to end-users. On the contrary, they like "clean" terminal statup screen. But if you need to do some troubleshooting... I use ProcessExplorer to check ConEmuC startup command line.
hypersw commented 8 years ago

On the “clean” terminal startup screen, are you sure? Here's the idea: — If you want a built-in CMD in your app, then well, it's true. No use in its cmd echoed. — But if you're inserting a terminal for running console commands (like, calling git, or THGW has a similar window for calling hg), then you most likely want to let user see the specific command the terminal is executing right now. One reason is that all this red-eyed cmdline stuff is only vaguely integrated into GUI, often you have to go manually into command-line, for that it's very useful to see what the GUI app were trying to do in terms of command line, and why those error messages, for example. Another reason is that unix-way utils are not very verbose on startup, won't say anything until there's an error or a result or a progress msg at least. So if you run git pull, first it goes connecting with the terminal window all blank for a while, you don't know if it's working or what. Same for git checkout. It's comforting if you see the command line written first. That's what I see by comparing old GE impl with the terminal-enabled one. So I think this is quite end-user (as an option on the control / conemu cmdline).

Maximus5 commented 8 years ago

I'm lost. What is the suggestion?

hypersw commented 8 years ago

I'd suggest for adding a switch which makes ConEmu echo the payload command AS IS into the terminal before beginning to execute it. I can see this useful for one pattern of use for conemu-inside.

As for the -e | -t things, I'll try them as soon as we get the core nuget, with all the other features.

hypersw commented 8 years ago

c0/c/n choice implemented

hypersw commented 8 years ago

We've been using GE with ConEmu since early January full-scale on the team. Can say it solves the original problem for sure, and works almost nicely. Thanks for help with the stuff.

There're, like, two noticeable glitches though, one of them is this one issue, for it is a slight regression from the original GE functionality.

I tried to play with -e/-t in December, but didn't think up a nice way. conemu.exe won't accept these switches, while calling conemuc is too late because the echoed cmdline has to be yielded before it starts to run. Maybe the idea was to run an empty terminal (with cmd), then use guimacro to write text, then use guimacro to invoke whatever command should be run for payload?

Maximus5 commented 8 years ago

conemu.exe won't accept these switches, while calling conemuc is too late because the echoed cmdline has to be yielded before it starts to run.

Either I misunderstood what you are complaining of, or you tried -e/-t in some wrong way. What have you tried exactly, and what was the problem?

hypersw commented 8 years ago

Tried it on the main conemu.exe — it didn't work, yet were not quite expected to. Just to check.

As with conemuc, how do I make it write smth before the main executable runs under conemu.exe? There were numerous hypothetical recipes mentioned above, which one is the true one?

The first goal is to have "git pull bla bla bla" text appear in the terminal before "git pull bla bla bla" actually gets running.

UPD: The commit says it about conemuc again, but how do I use it when I run the root conemu.exe? And the type & approach feels wrong because that type/& is parsed by the command interpreter, which has its own feelings about escaping e.g. ^ chars, as opposed to just starting a child process with such cmdline, and git likes using ^ for some of its revlog expressions.

Maximus5 commented 8 years ago

False. Commit says that echo and type are parsed and processed by ConEmu and suggests to use either Settings/Environment or just a Task commands.

There is just one drawback. In current sources, Task's echo commands are executed before echo from Settings/Environment. I consider this is wrong behavior. Task's echo will be executed after echo from Settings.

2016-02-16_10-33-54

2016-02-16_10-35-01

2016-02-16_10-35-59

Maximus5 commented 8 years ago

Screenshots were taken from debug local build of course

hypersw commented 8 years ago

Great!

But unlike the conventional echo it only takes the text up to the first space, i.e. comspec echo bla bla bla would write bla bla bla, while this one writes bla. Means the arg has to be quoted and escaped, what are the exact escaping rules here? Commandlines would have all sorts of special chars in them. I've applied MSBuild's escaper, but probably it will be slipping.

Maximus5 commented 8 years ago

Actually, one cmdline parser is used everywhere in ConEmu. So the rules are the same.

  1. Use double quotes
  2. Use caret to escape: ^t -> tab-char, etc.
  3. (AFAICR) two sequential double quotes are replaced with one: "" -> "
hypersw commented 8 years ago

so ^^ is for ^, right? and ^"?

hypersw commented 8 years ago

Will have to implement the mangler, otherwise it's no chance git cmdlines will look right. Where's the parser logic located?

Maximus5 commented 8 years ago

^^ - yes. ^" - no. Can't check ATM

Parser - NextArg Demangler - DoOutput

Maximus5 commented 8 years ago

^^ - yes. ^" - no. Can't check ATM

Parser - NextArg Demangler - DoOutput

hypersw commented 8 years ago

Is there a mangler as well there in cpp? Would like to write a test which takes all possible pairs of symbols in 0…127 except for some specials like \0 and makes sure it roundtrips.

hypersw commented 8 years ago

Writing a similar thing for command line gave us knowledge that with WinNT command line it is simply not possible to roundtrip an arbitrary string with ", \, ^ in it (i.e. to reliably embed a cmdline). I mean the CRT parser and .NET's which is similar to it. WinAPI parser has some weird rules different from everything else and is not used by anything I know.

Maximus5 commented 8 years ago

There is no "mangler" in a code, didn't need it yet.

As for parser... Anyone may check and compare parser from command line, ConEmuC has special -args switch. Example

ConEmuC -args "Test & "" Test"

Can't recall why the rule for double quotes was selected in ConEmu.

Maximus5 commented 8 years ago

http://stackoverflow.com/a/15262019/1405560

But seems like CommandLineToArgW do not conform rules. Thats why internal parser was written.

hypersw commented 8 years ago

CommandLineToArgW has its own rules. Which is not a big deal on itself, koz there are no "The Rules" in WinNT, it's up to each cmdline utility of how to parse is input. The issue is that often you want to mangle params for the average utility input (e.g. MSBuild, compilers, cmd, etc), and CommandLineToArgW falls out of the line and behaves differently. Luckily, hardly anyone uses it.

In the native netfx bootstrapper (e.g. this one ) I tried CommandLineToArgW as a very natural idea but soon switched to using MSVS CRT parser from stdargv.c, by taking __argc and __wargv in the ready form.

hypersw commented 8 years ago

I've implemented echoing the command and custom greeting text via the environment, and added support for the new Write macro.