-
Notifications
You must be signed in to change notification settings - Fork 8.4k
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
Fix console aliases not working #14991
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1019,27 +1019,43 @@ void COOKED_READ_DATA::SavePendingInput(const size_t index, const bool multiline | |
} | ||
|
||
Tracing::s_TraceCookedRead(_clientProcess, _backupLimit, base::saturated_cast<ULONG>(idx)); | ||
ProcessAliases(LineCount); | ||
|
||
// Don't be fooled by ProcessAliases only taking one argument. It rewrites multiple | ||
// class members on return, including `_bytesRead`, requiring us to reconstruct `input`. | ||
Comment on lines
+1023
to
+1024
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good callout! |
||
ProcessAliases(LineCount); | ||
input = { _backupLimit, _bytesRead / sizeof(wchar_t) }; | ||
|
||
// The exact reasons for this are unclear to me (the one writing this comment), but this code used to | ||
// split the contents of a multiline alias (for instance `doskey test=echo foo$Techo bar$Techo baz`) | ||
// into multiple separate read outputs, ensuring that the client receives them line by line. | ||
// | ||
// This code first truncates the `input` to only contain the first line, so that Consume() below only | ||
// writes that line into the user buffer. We'll later store the remainder in SaveMultilinePendingInput(). | ||
if (LineCount > 1) | ||
{ | ||
input = input.substr(0, idx + 1); | ||
// ProcessAliases() is supposed to end each line with \r\n. If it doesn't we might as well fail-fast. | ||
const auto firstLineEnd = input.find(UNICODE_LINEFEED) + 1; | ||
input = input.substr(0, firstLineEnd); | ||
} | ||
} | ||
} | ||
|
||
const auto inputSizeBefore = input.size(); | ||
GetInputBuffer()->Consume(isUnicode, input, writer); | ||
|
||
if (!input.empty()) | ||
if (LineCount > 1) | ||
{ | ||
if (LineCount > 1) | ||
{ | ||
GetInputReadHandleData()->SaveMultilinePendingInput(input); | ||
} | ||
else | ||
{ | ||
GetInputReadHandleData()->SavePendingInput(input); | ||
} | ||
// This is a continuation of the above identical if condition. | ||
// We've truncated the `input` slice and now we need to restore it. | ||
const auto inputSizeAfter = input.size(); | ||
const auto amountConsumed = inputSizeBefore - inputSizeAfter; | ||
input = { _backupLimit, _bytesRead / sizeof(wchar_t) }; | ||
input = input.substr(amountConsumed); | ||
GetInputReadHandleData()->SaveMultilinePendingInput(input); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't necessarily the most readable code I've written so far... But it does do the correct thing: After An alternative I've considered is to change |
||
} | ||
else if (!input.empty()) | ||
{ | ||
GetInputReadHandleData()->SavePendingInput(input); | ||
} | ||
|
||
numBytes = _userBufferSize - writer.size(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -288,28 +288,36 @@ try | |
{ | ||
bytesRead = 0; | ||
|
||
auto pending = readHandleState.GetPendingInput(); | ||
const auto pending = readHandleState.GetPendingInput(); | ||
auto input = pending; | ||
|
||
// This is basically the continuation of COOKED_READ_DATA::_handlePostCharInputLoop. | ||
if (readHandleState.IsMultilineInput()) | ||
{ | ||
const auto idx = pending.find(UNICODE_LINEFEED); | ||
if (idx != decltype(pending)::npos) | ||
{ | ||
// +1 to include the newline. | ||
pending = pending.substr(0, idx + 1); | ||
} | ||
const auto firstLineEnd = input.find(UNICODE_LINEFEED) + 1; | ||
lhecker marked this conversation as resolved.
Show resolved
Hide resolved
|
||
input = input.substr(0, firstLineEnd); | ||
} | ||
|
||
const auto inputSizeBefore = input.size(); | ||
std::span writer{ buffer }; | ||
inputBuffer.Consume(unicode, pending, writer); | ||
inputBuffer.Consume(unicode, input, writer); | ||
|
||
// Since we truncated `input` to only include the first line, | ||
// we need to restore `input` here to the entirety of the remaining input. | ||
if (readHandleState.IsMultilineInput()) | ||
{ | ||
const auto inputSizeAfter = input.size(); | ||
const auto amountConsumed = inputSizeBefore - inputSizeAfter; | ||
input = pending.substr(amountConsumed); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code block is identical to the other one, but it's shorter because we can easily access the previously saved |
||
} | ||
|
||
if (pending.empty()) | ||
if (input.empty()) | ||
{ | ||
readHandleState.CompletePending(); | ||
} | ||
else | ||
{ | ||
readHandleState.UpdatePending(pending); | ||
readHandleState.UpdatePending(input); | ||
} | ||
|
||
bytesRead = buffer.size() - writer.size(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another one down the list #14298.