Skip to content

Commit ce56092

Browse files
committed
Fix exception after certain keywords
Rendering in PSReadline assumed all input had corresponding tokens, but the PowerShell parser doesn't return any tokens after in at least one case - after input like 'process foo'. The fix is to gracefully handle running out of tokens. Fixes #148.
1 parent dff4793 commit ce56092

File tree

2 files changed

+53
-32
lines changed

2 files changed

+53
-32
lines changed

PSReadLine/Changes.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Bug fixes:
1313
* Occasional exception with AcceptAndGetNext (Ctrl+O) followed by something other than Enter
1414
* Event handlers that register for the engine event PowerShell.OnIdle should work now.
1515
* ClearScreen now just clears the visible screen, not the entire buffer.
16+
* Fix exception on error input during rendering after certain keywords like process, begin, or end.
1617

1718
New functions:
1819
* ValidateAndAcceptLine

PSReadLine/Render.cs

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -107,49 +107,69 @@ private void ReallyRender()
107107
int j = _initialX + (_bufferWidth * Options.ExtraPromptLineCount);
108108
var backgroundColor = _initialBackgroundColor;
109109
var foregroundColor = _initialForegroundColor;
110+
bool afterLastToken = false;
110111

111112
for (int i = 0; i < text.Length; i++)
112113
{
113-
// Figure out the color of the character - if it's in a token,
114-
// use the tokens color otherwise use the initial color.
115-
var state = tokenStack.Peek();
116-
var token = state.Tokens[state.Index];
117-
if (i == token.Extent.EndOffset)
114+
SavedTokenState state = null;
115+
116+
if (!afterLastToken)
118117
{
119-
if (token == state.Tokens[state.Tokens.Length - 1])
118+
// Figure out the color of the character - if it's in a token,
119+
// use the tokens color otherwise use the initial color.
120+
state = tokenStack.Peek();
121+
var token = state.Tokens[state.Index];
122+
if (i == token.Extent.EndOffset)
120123
{
121-
tokenStack.Pop();
122-
state = tokenStack.Peek();
123-
}
124-
foregroundColor = state.ForegroundColor;
125-
backgroundColor = state.BackgroundColor;
124+
if (token == state.Tokens[state.Tokens.Length - 1])
125+
{
126+
tokenStack.Pop();
127+
if (tokenStack.Count == 0)
128+
{
129+
afterLastToken = true;
130+
token = null;
131+
foregroundColor = _initialForegroundColor;
132+
backgroundColor = _initialBackgroundColor;
133+
}
134+
else
135+
{
136+
state = tokenStack.Peek();
137+
}
138+
}
126139

127-
token = state.Tokens[++state.Index];
128-
}
140+
if (!afterLastToken)
141+
{
142+
foregroundColor = state.ForegroundColor;
143+
backgroundColor = state.BackgroundColor;
129144

130-
if (i == token.Extent.StartOffset)
131-
{
132-
GetTokenColors(token, out foregroundColor, out backgroundColor);
145+
token = state.Tokens[++state.Index];
146+
}
147+
}
133148

134-
var stringToken = token as StringExpandableToken;
135-
if (stringToken != null)
149+
if (!afterLastToken && i == token.Extent.StartOffset)
136150
{
137-
// We might have nested tokens.
138-
if (stringToken.NestedTokens != null && stringToken.NestedTokens.Any())
139-
{
140-
var tokens = new Token[stringToken.NestedTokens.Count + 1];
141-
stringToken.NestedTokens.CopyTo(tokens, 0);
142-
// NestedTokens doesn't have an "EOS" token, so we use
143-
// the string literal token for that purpose.
144-
tokens[tokens.Length - 1] = stringToken;
151+
GetTokenColors(token, out foregroundColor, out backgroundColor);
145152

146-
tokenStack.Push(new SavedTokenState
153+
var stringToken = token as StringExpandableToken;
154+
if (stringToken != null)
155+
{
156+
// We might have nested tokens.
157+
if (stringToken.NestedTokens != null && stringToken.NestedTokens.Any())
147158
{
148-
Tokens = tokens,
149-
Index = 0,
150-
BackgroundColor = backgroundColor,
151-
ForegroundColor = foregroundColor
152-
});
159+
var tokens = new Token[stringToken.NestedTokens.Count + 1];
160+
stringToken.NestedTokens.CopyTo(tokens, 0);
161+
// NestedTokens doesn't have an "EOS" token, so we use
162+
// the string literal token for that purpose.
163+
tokens[tokens.Length - 1] = stringToken;
164+
165+
tokenStack.Push(new SavedTokenState
166+
{
167+
Tokens = tokens,
168+
Index = 0,
169+
BackgroundColor = backgroundColor,
170+
ForegroundColor = foregroundColor
171+
});
172+
}
153173
}
154174
}
155175
}

0 commit comments

Comments
 (0)