6
\$\begingroup\$

I have this little project i am about to release.

https://github.com/holli-holzer/perl6-Win-VT

I would be happy about a code review and suggestions for a better name.

Discussion in IRC yielded Terminal::Win::VT or Terminal::Win32::VT::Enable as better alternatives. Or even Win32::Console::VT.

This is the gist of it. There are additional files, but those provide just sugar.

unit module Win::VT;
use NativeCall;
constant STD_INPUT_HANDLE = -0xA;
constant STD_OUTPUT_HANDLE = -0xB;
constant ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200;
constant ENABLE_PROCESSED_INPUT = 0x0001;
constant ENABLE_PROCESSED_OUTPUT = 0x0001;
constant ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
constant DWORD := uint32;
constant BOOL := int32;
constant HANDLE := Pointer[void];
sub GetConsoleMode(HANDLE, DWORD is rw) is native('Kernel32') returns BOOL { * };
sub SetConsoleMode(HANDLE, DWORD) is native('Kernel32') returns BOOL { * };
sub GetStdHandle(DWORD) is native('Kernel32') returns HANDLE { * };
my HANDLE $input-handle;
my HANDLE $output-handle;
my DWORD $output-mode;
my DWORD $input-mode;
INIT {
 if $*VM.osname eq "mswin32"
 {
 $input-handle = GetStdHandle( STD_INPUT_HANDLE );
 $output-handle = GetStdHandle( STD_OUTPUT_HANDLE );
 }
}
sub vt-on(Bool :$vt-input=True, Bool :$vt-output=True ) returns Bool is export(:MANDATORY)
{
 return False
 unless $input-handle.defined && $output-handle.defined;
 return False
 unless GetConsoleMode($input-handle, $input-mode) && GetConsoleMode($output-handle, $output-mode);
 my $new-input-mode = $input-mode +| ENABLE_PROCESSED_INPUT +| ENABLE_VIRTUAL_TERMINAL_INPUT;
 my $new-output-mode = $output-mode +| ENABLE_PROCESSED_OUTPUT +| ENABLE_VIRTUAL_TERMINAL_PROCESSING;
 return (
 ( $vt-input ?? SetConsoleMode($input-handle, $new-input-mode) !! 1 ) &&
 ( $vt-output ?? SetConsoleMode($output-handle, $new-output-mode) !! 1 )
 ).Bool;
}
sub vt-off() returns Bool is export(:MANDATORY) {
 return (
 $input-handle.defined && $output-handle.defined &&
 SetConsoleMode($output-handle, $output-mode) &&
 SetConsoleMode($input-handle, $input-mode)
 ).Bool;
}
sub cls() is export(:cls) {
 vt-on;
 print chr(27) ~ '[2J' ~ chr(27) ~ '[;H';
 vt-off;
}
rolfl
98.1k17 gold badges219 silver badges419 bronze badges
asked Sep 11, 2019 at 15:48
\$\endgroup\$
1
  • 1
    \$\begingroup\$ *::ANSI maybe? The VT series may have introduced these codes but they were formalized by an ANSI spec and most people would call them "ANSI escape sequences" today. Also chr(27) seems like it should be a constant. \$\endgroup\$ Commented Sep 11, 2019 at 23:00

1 Answer 1

4
\$\begingroup\$

Since no one else has replied, here's somewhat of a "rubber duck code review" given that I don't know much about Windows, vt, and NativeCall. Plus I've got a suggestion about the API and module name.


It looks like the not-explicitly-initialized $input-mode and $output-mode variables are actually constants implicitly initialized to zero. I think the code would be less confusing if they were declared as constants or even if you used literal 0s instead of them. Perhaps other code or configuration you have, or have in mind, will vary these values? Anyhow, at the very least, I think a comment making it clear the values the user passes to vt-on don't alter these, and vt-off is resetting them no matter what vt-on did, would be helpful.


From an API perspective, aiui, if one calls vt-on it turns the vt stuff on for both input and output. You have to pass :vt-input(False) if you only want vt-output and vice-versa. And vt-off always turns both off.

To me, having to write vt-input(False) is a bit ugly because:

  • It repeats the vt;

  • Mentions input when what one is trying to do is control output;

  • Requires explicit use of False.

It seems to me it could be more ergonomic to have just one routine, vt. To switch both input and output on use vt :on. To switch both off use vt :off. To switch just one on and leave the other as it is, use vt :on<input> or vt :on<output>. To switch just one off and leave the other as it is, use vt :off<input> or vt :off<output>.

I've never used vt stuff and could imagine one doesn't need the extra flexibility of the API I suggest but my suggestion is really more about keeping the API sweet than it is about the additional flexibility.


As for the module name...

I currently think we should shift all of our emphasis related to module discovery to an assumption of widespread use of global search via keywords, tags, etc. For now that means eg 'terminal' tag search or 'terminal' keyword search but one day there'll surely be search of a module's Pod and other aspects as well. In summary, imo, don't worry about a name's discoverability.

To the degree that a module's name matters, I think it's beyond discoverability. I think the two key things are considering clustering with names already chosen or likely to be chosen by other module authors, and making a name nice in a use statement. For these latter aspects I'd say:

  • Consider following accepted hierarchical namespace norms already established for modules.perl6.org. But don't sweat it.

  • If there are no obvious relevant norms to follow then keep a module name fairly short and sweet. Do you really need bumpy case or hyphens? Do you really need more than one :: divider? Then again, don't pick something egregiously short-sighted. You could name it just VT but a module such as yours doesn't warrant such a name.


Other than that the code all makes sense to me and looks fine to me from a pure P6 perspective.

answered Sep 15, 2019 at 13:26
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.