mirror of
https://github.com/PowerShell/PSReadLine
synced 2026-06-08 12:12:13 +00:00
300 lines
12 KiB
C#
300 lines
12 KiB
C#
using System.Collections;
|
|
using System.Collections.ObjectModel;
|
|
using System.IO;
|
|
using System.Management.Automation;
|
|
using System.Reflection;
|
|
using Microsoft.PowerShell;
|
|
using Xunit;
|
|
|
|
namespace Test
|
|
{
|
|
public partial class ReadLine
|
|
{
|
|
[SkippableFact]
|
|
public void TabComplete()
|
|
{
|
|
TestSetup(KeyMode.Cmd);
|
|
|
|
Test("$true", Keys(
|
|
"$tr",
|
|
_.Tab,
|
|
CheckThat(() => AssertCursorLeftIs(5))));
|
|
|
|
// Validate no change on no match
|
|
Test("$zz", Keys(
|
|
"$zz",
|
|
_.Tab,
|
|
CheckThat(() => AssertCursorLeftIs(3))));
|
|
|
|
Test("$this", Keys(
|
|
"$t",
|
|
_.Tab,
|
|
CheckThat(() => AssertLineIs("$thing")),
|
|
_.Tab,
|
|
CheckThat(() => AssertLineIs("$this")),
|
|
_.Tab,
|
|
CheckThat(() => AssertLineIs("$true")),
|
|
_.Shift_Tab,
|
|
CheckThat(() => AssertLineIs("$this"))));
|
|
}
|
|
|
|
[SkippableFact]
|
|
public void InvalidCompletionResult()
|
|
{
|
|
TestSetup(KeyMode.Cmd);
|
|
|
|
for (int i = 1; i <= 4; i++)
|
|
{
|
|
var input = $"invalid result {i}";
|
|
Test(input, Keys(input, _.Tab));
|
|
}
|
|
}
|
|
|
|
[SkippableFact]
|
|
public void Complete()
|
|
{
|
|
TestSetup(KeyMode.Emacs);
|
|
|
|
Test("ambiguous1", Keys(
|
|
"ambig",
|
|
_.Tab,
|
|
CheckThat(() => AssertLineIs("ambiguous")),
|
|
'1'));
|
|
}
|
|
|
|
[SkippableFact]
|
|
public void PossibleCompletions()
|
|
{
|
|
TestSetup(KeyMode.Emacs);
|
|
|
|
_console.Clear();
|
|
// Test empty input, make sure line after the cursor is blank and cursor didn't move
|
|
Test("", Keys(
|
|
_.Alt_Equals,
|
|
CheckThat(() =>
|
|
{
|
|
AssertCursorLeftTopIs(0, 0);
|
|
AssertScreenIs(2, NextLine);
|
|
})));
|
|
|
|
const string promptLine1 = "c:\\windows";
|
|
const string promptLine2 = "PS> ";
|
|
using (var ps = PowerShell.Create(RunspaceMode.CurrentRunspace))
|
|
{
|
|
ps.AddScript($@"function prompt {{ ""{promptLine1}`n{promptLine2}"" }}");
|
|
ps.Invoke();
|
|
}
|
|
PSConsoleReadLine.SetOptions(new SetPSReadLineOption {ExtraPromptLineCount = 1});
|
|
|
|
_console.Clear();
|
|
Test("psvar", Keys(
|
|
"psvar",
|
|
_.Alt_Equals,
|
|
CheckThat(() => AssertScreenIs(5,
|
|
TokenClassification.None, promptLine1,
|
|
NextLine,
|
|
promptLine2,
|
|
TokenClassification.Command, "psvar",
|
|
NextLine,
|
|
"$pssomething",
|
|
NextLine,
|
|
TokenClassification.None, promptLine1,
|
|
NextLine,
|
|
promptLine2,
|
|
TokenClassification.Command, "psvar"))),
|
|
prompt: promptLine1 + "\n" + promptLine2);
|
|
|
|
using (var ps = PowerShell.Create(RunspaceMode.CurrentRunspace))
|
|
{
|
|
ps.AddCommand("Remove-Item").AddArgument("function:prompt");
|
|
ps.Invoke();
|
|
}
|
|
|
|
_console.Clear();
|
|
TestMustDing("none", Keys(
|
|
"none",
|
|
_.Alt_Equals,
|
|
CheckThat(() => AssertScreenIs(2, TokenClassification.Command, "none", NextLine))));
|
|
}
|
|
|
|
[SkippableFact]
|
|
public void PossibleCompletionsPrompt()
|
|
{
|
|
TestSetup(KeyMode.Cmd, new KeyHandler("Ctrl+Spacebar", PSConsoleReadLine.PossibleCompletions));
|
|
|
|
PSConsoleReadLine.GetOptions().CompletionQueryItems = 10;
|
|
_console.Clear();
|
|
Test("Get-Many", Keys(
|
|
"Get-Many", _.Ctrl_Spacebar,
|
|
CheckThat(() => AssertScreenIs(2,
|
|
TokenClassification.Command, "Get-Many", NextLine,
|
|
TokenClassification.None, "Display all 15 possibilities? (y or n) _")),
|
|
"n"));
|
|
|
|
_console.Clear();
|
|
Test("Get-Many", Keys(
|
|
"Get-Many", _.Ctrl_Spacebar,
|
|
CheckThat(() => AssertScreenIs(2,
|
|
TokenClassification.Command, "Get-Many", NextLine,
|
|
TokenClassification.None, "Display all 15 possibilities? (y or n) _")),
|
|
"y",
|
|
CheckThat(() => AssertScreenIs(4,
|
|
TokenClassification.Command, "Get-Many", NextLine,
|
|
TokenClassification.None,
|
|
"Get-Many0 Get-Many3 Get-Many6 Get-Many9 Get-Many12", NextLine,
|
|
"Get-Many1 Get-Many4 Get-Many7 Get-Many10 Get-Many13", NextLine,
|
|
"Get-Many2 Get-Many5 Get-Many8 Get-Many11 Get-Many14"))));
|
|
}
|
|
|
|
[SkippableFact]
|
|
public void MenuCompletions()
|
|
{
|
|
TestSetup(KeyMode.Cmd, new KeyHandler("Ctrl+Spacebar", PSConsoleReadLine.MenuComplete));
|
|
|
|
_console.Clear();
|
|
Test("Get-Many4", Keys(
|
|
"Get-Many", _.Ctrl_Spacebar,
|
|
CheckThat(() => AssertScreenIs(4,
|
|
TokenClassification.Command, "Get-Many",
|
|
TokenClassification.Selection, "0", NextLine,
|
|
TokenClassification.Selection, "Get-Many0 ",
|
|
TokenClassification.None,
|
|
"Get-Many3 Get-Many6 Get-Many9 Get-Many12", NextLine,
|
|
"Get-Many1 Get-Many4 Get-Many7 Get-Many10 Get-Many13", NextLine,
|
|
"Get-Many2 Get-Many5 Get-Many8 Get-Many11 Get-Many14")),
|
|
"4",
|
|
CheckThat(() => AssertScreenIs(4,
|
|
TokenClassification.Command, "Get-Many4", NextLine,
|
|
TokenClassification.Selection, "Get-Many4 ", NextLine,
|
|
" ", NextLine,
|
|
" ", NextLine)),
|
|
_.Enter,
|
|
_.Enter
|
|
));
|
|
}
|
|
|
|
[SkippableFact]
|
|
public void ShowTooltips()
|
|
{
|
|
TestSetup(KeyMode.Cmd, new KeyHandler("Ctrl+Spacebar", PSConsoleReadLine.PossibleCompletions));
|
|
|
|
PSConsoleReadLine.GetOptions().ShowToolTips = true;
|
|
_console.Clear();
|
|
// TODO:
|
|
}
|
|
|
|
[SkippableFact]
|
|
public void DirectoryCompletion()
|
|
{
|
|
TestSetup(KeyMode.Cmd);
|
|
|
|
Test("", Keys(
|
|
"Get-Directory", _.Tab,
|
|
CheckThat(() => AssertLineIs("abc" + Path.DirectorySeparatorChar)),
|
|
_.Tab,
|
|
CheckThat(() => AssertLineIs("'e f" + Path.DirectorySeparatorChar + "'")),
|
|
CheckThat(() => AssertCursorLeftIs(5)),
|
|
_.Tab,
|
|
CheckThat(() => AssertLineIs("a" + Path.DirectorySeparatorChar)),
|
|
_.Tab,
|
|
CheckThat(() => AssertLineIs("'a b" + Path.DirectorySeparatorChar + "'")),
|
|
CheckThat(() => AssertCursorLeftIs(5)),
|
|
_.Tab,
|
|
CheckThat(() => AssertLineIs("\"a b" + Path.DirectorySeparatorChar + "\"")),
|
|
CheckThat(() => AssertCursorLeftIs(5)),
|
|
_.Ctrl_c, InputAcceptedNow));
|
|
}
|
|
|
|
internal static CommandCompletion MockedCompleteInput(string input, int cursor, Hashtable options, PowerShell powerShell)
|
|
{
|
|
var ctor = typeof (CommandCompletion).GetConstructor(
|
|
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null,
|
|
new [] {typeof (Collection<CompletionResult>), typeof (int), typeof (int), typeof (int)}, null);
|
|
|
|
var completions = new Collection<CompletionResult>();
|
|
const int currentMatchIndex = -1;
|
|
var replacementIndex = 0;
|
|
var replacementLength = 0;
|
|
switch (input)
|
|
{
|
|
case "$t":
|
|
replacementIndex = 0;
|
|
replacementLength = 2;
|
|
completions.Add(new CompletionResult("$thing"));
|
|
completions.Add(new CompletionResult("$this"));
|
|
completions.Add(new CompletionResult("$true"));
|
|
break;
|
|
case "$tr":
|
|
replacementIndex = 0;
|
|
replacementLength = 3;
|
|
completions.Add(new CompletionResult("$true"));
|
|
break;
|
|
case "psvar":
|
|
replacementIndex = 0;
|
|
replacementLength = 5;
|
|
completions.Add(new CompletionResult("$pssomething"));
|
|
break;
|
|
case "ambig":
|
|
replacementIndex = 0;
|
|
replacementLength = 5;
|
|
completions.Add(new CompletionResult("ambiguous1"));
|
|
completions.Add(new CompletionResult("ambiguous2"));
|
|
completions.Add(new CompletionResult("ambiguous3"));
|
|
break;
|
|
case "Get-Many":
|
|
replacementIndex = 0;
|
|
replacementLength = 8;
|
|
for (int i = 0; i < 15; i++)
|
|
{
|
|
completions.Add(new CompletionResult("Get-Many" + i));
|
|
}
|
|
break;
|
|
case "Get-Tooltips":
|
|
replacementIndex = 0;
|
|
replacementLength = 12;
|
|
completions.Add(new CompletionResult("something really long", "item1", CompletionResultType.Command, "useful description goes here"));
|
|
break;
|
|
case "Get-Directory":
|
|
replacementIndex = 0;
|
|
replacementLength = 13;
|
|
completions.Add(new CompletionResult("abc", "abc", CompletionResultType.ProviderContainer, "abc"));
|
|
completions.Add(new CompletionResult("'e f'", "'e f'", CompletionResultType.ProviderContainer, "'e f'"));
|
|
completions.Add(new CompletionResult("a", "a", CompletionResultType.ProviderContainer, "a"));
|
|
completions.Add(new CompletionResult("'a b" + Path.DirectorySeparatorChar + "'", "a b" + Path.DirectorySeparatorChar + "'", CompletionResultType.ProviderContainer, "a b" + Path.DirectorySeparatorChar + "'"));
|
|
completions.Add(new CompletionResult("\"a b" + Path.DirectorySeparatorChar + "\"", "\"a b" + Path.DirectorySeparatorChar + "\"", CompletionResultType.ProviderContainer, "\"a b" + Path.DirectorySeparatorChar + "\""));
|
|
break;
|
|
case "invalid result 1":
|
|
replacementIndex = -1;
|
|
replacementLength = 1;
|
|
completions.Add(new CompletionResult("result"));
|
|
break;
|
|
case "invalid result 2":
|
|
replacementIndex = 0;
|
|
replacementLength = -1;
|
|
completions.Add(new CompletionResult("result"));
|
|
break;
|
|
case "invalid result 3":
|
|
replacementIndex = int.MaxValue;
|
|
replacementLength = 1;
|
|
completions.Add(new CompletionResult("result"));
|
|
break;
|
|
case "invalid result 4":
|
|
replacementIndex = 0;
|
|
replacementLength = int.MaxValue;
|
|
completions.Add(new CompletionResult("result"));
|
|
break;
|
|
case "ls -H":
|
|
replacementIndex = cursor;
|
|
replacementLength = 0;
|
|
completions.Add(new CompletionResult("idden"));
|
|
break;
|
|
case "none":
|
|
break;
|
|
}
|
|
|
|
return (CommandCompletion)ctor.Invoke(
|
|
new object[] {completions, currentMatchIndex, replacementIndex, replacementLength});
|
|
}
|
|
}
|
|
}
|