Merge remote-tracking branch 'upstream/master'

Conflicts:
	PSReadLine/PSReadLineResources.Designer.cs
	PSReadLine/PSReadLineResources.resx
	PSReadLine/UndoRedo.cs

Signed-off-by: srdubya <stevewy@gmail.com>
This commit is contained in:
srdubya
2014-05-18 06:57:26 -06:00
19 changed files with 461 additions and 96 deletions
+4 -2
View File
@@ -88,7 +88,8 @@ namespace PSConsoleUtilities
_singleton._consoleBuffer[i+1].BackgroundColor = Console.BackgroundColor;
WriteBufferLines(_singleton._consoleBuffer, ref _singleton._initialY);
_singleton.PlaceCursor(0, coordinates.Y + 1);
var y = coordinates.Y + 1;
_singleton.PlaceCursor(0, ref y);
_singleton._buffer.Clear(); // Clear so we don't actually run the input
_singleton._currentHistoryIndex = _singleton._history.Count;
_singleton._inputAccepted = true;
@@ -216,7 +217,8 @@ namespace PSConsoleUtilities
ReallyRender();
}
var coordinates = ConvertOffsetToCoordinates(_current);
PlaceCursor(0, coordinates.Y + 1);
var y = coordinates.Y + 1;
PlaceCursor(0, ref y);
_inputAccepted = true;
return true;
}
+6
View File
@@ -1,3 +1,9 @@
### Version 1.0.0.9
Bug fixes:
* Items loaded from history work with RevertLine
### Version 1.0.0.8
New features:
+221 -49
View File
@@ -5,7 +5,6 @@ using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;
using System.Text.RegularExpressions;
using PSConsoleUtilities.Internal;
namespace PSConsoleUtilities
@@ -83,11 +82,27 @@ namespace PSConsoleUtilities
/// </summary>
public static void Complete(ConsoleKeyInfo? key = null, object arg = null)
{
var completions = _singleton.GetCompletions();
_singleton.CompleteImpl(key, arg, false);
}
/// <summary>
/// Attempt to perform completion on the text surrounding the cursor.
/// If there are multiple possible completions, the longest unambiguous
/// prefix is used for completion. If trying to complete the longest
/// unambiguous completion, a list of possible completions is displayed.
/// </summary>
public static void MenuComplete(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton.CompleteImpl(key, arg, true);
}
private void CompleteImpl(ConsoleKeyInfo? key, object arg, bool menuSelect)
{
var completions = GetCompletions();
if (completions == null || completions.CompletionMatches.Count == 0)
return;
if (_singleton._tabCommandCount > 0)
if (_tabCommandCount > 0)
{
if (completions.CompletionMatches.Count == 1)
{
@@ -95,7 +110,7 @@ namespace PSConsoleUtilities
}
else
{
PossibleCompletions();
PossibleCompletionsImpl(completions, menuSelect);
}
return;
}
@@ -107,7 +122,13 @@ namespace PSConsoleUtilities
// completions, then we'll be showing the possible completions where it's very
// unlikely that we would add a trailing backslash.
_singleton.DoReplacementForCompletion(completions.CompletionMatches[0], completions);
DoReplacementForCompletion(completions.CompletionMatches[0], completions);
return;
}
if (menuSelect)
{
PossibleCompletionsImpl(completions, true);
return;
}
@@ -159,10 +180,10 @@ namespace PSConsoleUtilities
{
// No common prefix, don't wait for a second tab, just show the possible completions
// right away.
PossibleCompletions();
PossibleCompletionsImpl(completions, false);
}
_singleton._tabCommandCount += 1;
_tabCommandCount += 1;
}
private CommandCompletion GetCompletions()
@@ -259,96 +280,247 @@ namespace PSConsoleUtilities
return replacementText;
}
private static void InvertSelectedCompletion(CHAR_INFO[] buffer, int selectedItem, int menuColumnWidth, int menuRows)
{
var selectedX = selectedItem / menuRows;
var selectedY = selectedItem - (selectedX * menuRows);
var start = selectedY * Console.BufferWidth + selectedX * menuColumnWidth;
for (int i = 0; i < menuColumnWidth; i++)
{
int j = i + start;
buffer[j].ForegroundColor = (ConsoleColor)((int)buffer[j].ForegroundColor ^ 7);
buffer[j].BackgroundColor = (ConsoleColor)((int)buffer[j].BackgroundColor ^ 7);
}
}
/// <summary>
/// Display the list of possible completions.
/// </summary>
public static void PossibleCompletions(ConsoleKeyInfo? key = null, object arg = null)
{
var completions = _singleton.GetCompletions();
_singleton.PossibleCompletionsImpl(completions, menuSelect: false);
}
private static string HandleNewlinesForPossibleCompletions(string s)
{
s = s.Trim();
var newlineIndex = s.IndexOfAny(new []{'\r', '\n'});
if (newlineIndex >= 0)
{
s = s.Substring(0, newlineIndex) + "...";
}
return s;
}
private void PossibleCompletionsImpl(CommandCompletion completions, bool menuSelect)
{
if (completions == null || completions.CompletionMatches.Count == 0)
{
Ding();
return;
}
if (completions.CompletionMatches.Count >= _singleton._options.CompletionQueryItems)
if (completions.CompletionMatches.Count >= _options.CompletionQueryItems)
{
if (!_singleton.PromptYesOrNo(string.Format(PSReadLineResources.DisplayAllPossibilities, completions.CompletionMatches.Count)))
if (!PromptYesOrNo(string.Format(PSReadLineResources.DisplayAllPossibilities, completions.CompletionMatches.Count)))
{
return;
}
}
// Don't overwrite any of the line - so move to first line after the end of our buffer.
var coords = _singleton.ConvertOffsetToCoordinates(_singleton._buffer.Length);
_singleton.PlaceCursor(0, coords.Y + 1);
var sb = new StringBuilder();
var matches = completions.CompletionMatches.Select(
completion =>
new {ListItemText = Regex.Replace(completion.ListItemText, "\n.*", "..."),
ToolTip = Regex.Replace(completion.ToolTip, "\n.*", "...")})
.ToArray();
var matches = completions.CompletionMatches;
var minColWidth = matches.Max(c => c.ListItemText.Length);
minColWidth += 2;
var menuColumnWidth = minColWidth;
if (_singleton.Options.ShowToolTips)
int displayRows;
var bufferWidth = Console.BufferWidth;
ConsoleBufferBuilder cb;
if (Options.ShowToolTips)
{
const string seperator = "- ";
var maxTooltipWidth = Console.BufferWidth - minColWidth - seperator.Length;
var maxTooltipWidth = bufferWidth - minColWidth - seperator.Length;
foreach (var match in matches)
displayRows = matches.Count;
cb = new ConsoleBufferBuilder(displayRows * bufferWidth);
for (int index = 0; index < matches.Count; index++)
{
sb.Append(match.ListItemText);
var spacesNeeded = minColWidth - match.ListItemText.Length;
if (spacesNeeded > 0)
sb.Append(' ', spacesNeeded);
sb.Append(seperator);
var toolTip = match.ToolTip.Length <= maxTooltipWidth
? match.ToolTip
: match.ToolTip.Substring(0, maxTooltipWidth);
sb.Append(toolTip.Trim());
// Make sure we always write out exactly 1 buffer width
spacesNeeded = Console.BufferWidth - sb.Length;
var match = matches[index];
var listItemText = HandleNewlinesForPossibleCompletions(match.ListItemText);
cb.Append(listItemText);
var spacesNeeded = minColWidth - listItemText.Length;
if (spacesNeeded > 0)
{
sb.Append(' ', spacesNeeded);
cb.Append(' ', spacesNeeded);
}
cb.Append(seperator);
var toolTip = HandleNewlinesForPossibleCompletions(match.ToolTip);
toolTip = toolTip.Length <= maxTooltipWidth
? toolTip
: toolTip.Substring(0, maxTooltipWidth);
cb.Append(toolTip);
// Make sure we always write out exactly 1 buffer width
spacesNeeded = (bufferWidth * (index + 1)) - cb.Length;
if (spacesNeeded > 0)
{
cb.Append(' ', spacesNeeded);
}
Console.Write(sb.ToString());
sb.Clear();
}
menuColumnWidth = bufferWidth;
}
else
{
var screenColumns = Console.BufferWidth;
var screenColumns = bufferWidth;
var displayColumns = Math.Max(1, screenColumns / minColWidth);
var displayRows = (completions.CompletionMatches.Count + displayColumns - 1) / displayColumns;
displayRows = (completions.CompletionMatches.Count + displayColumns - 1) / displayColumns;
cb = new ConsoleBufferBuilder(displayRows * bufferWidth);
for (var row = 0; row < displayRows; row++)
{
for (var col = 0; col < displayColumns; col++)
{
var index = row + (displayRows * col);
if (index >= matches.Length)
if (index >= matches.Count)
break;
var item = matches[index].ListItemText;
sb.Append(item);
sb.Append(' ', minColWidth - item.Length);
var match = matches[index];
var item = HandleNewlinesForPossibleCompletions(match.ListItemText);
cb.Append(item);
cb.Append(' ', minColWidth - item.Length);
}
// Make sure we always write out exactly 1 buffer width
var spacesNeeded = Console.BufferWidth - sb.Length;
var spacesNeeded = (bufferWidth * (row + 1)) - cb.Length;
if (spacesNeeded > 0)
{
sb.Append(' ', spacesNeeded);
cb.Append(' ', spacesNeeded);
}
Console.Write(sb.ToString());
sb.Clear();
}
}
_singleton._initialY = Console.CursorTop;
_singleton.Render();
var menuBuffer = cb.ToArray();
if (menuSelect)
{
// Make sure the menu and line can appear on the screen at the same time,
// if not, we'll skip the menu.
var endBufferCoords = ConvertOffsetToCoordinates(_buffer.Length);
var bufferLines = endBufferCoords.Y - _initialY + 1;
if ((bufferLines + displayRows) > Console.WindowHeight)
{
menuSelect = false;
}
}
if (menuSelect)
{
StartEditGroup();
int selectedItem = 0;
bool undo = false;
DoReplacementForCompletion(matches[0], completions);
// Recompute end of buffer coordinates as the replacement could have
// added a line.
var endBufferCoords = ConvertOffsetToCoordinates(_buffer.Length);
var menuAreaTop = endBufferCoords.Y + 1;
var previousMenuTop = menuAreaTop;
InvertSelectedCompletion(menuBuffer, selectedItem, menuColumnWidth, displayRows);
WriteBufferLines(menuBuffer, ref menuAreaTop);
if (previousMenuTop != menuAreaTop)
{
// Showing the menu scrolled the screen, update initialY to reflect that.
_initialY -= (previousMenuTop - menuAreaTop);
PlaceCursor();
previousMenuTop = menuAreaTop;
}
int previousItem = selectedItem;
bool processingKeys = true;
while (processingKeys)
{
var nextKey = ReadKey();
if (nextKey == Keys.RightArrow)
{
selectedItem = Math.Min(selectedItem + displayRows, matches.Count - 1);
}
else if (nextKey == Keys.LeftArrow)
{
selectedItem = Math.Max(selectedItem - displayRows, 0);
}
else if (nextKey == Keys.DownArrow)
{
selectedItem = Math.Min(selectedItem + 1, matches.Count - 1);
}
else if (nextKey == Keys.UpArrow)
{
selectedItem = Math.Max(selectedItem - 1, 0);
}
else if (nextKey == Keys.Tab)
{
selectedItem = (selectedItem + 1) % matches.Count;
}
else if (nextKey == Keys.ShiftTab)
{
selectedItem = (selectedItem - 1) % matches.Count;
if (selectedItem < 0)
{
selectedItem += matches.Count;
}
}
else if (nextKey == Keys.CtrlG || nextKey == Keys.Escape)
{
undo = true;
processingKeys = false;
}
else
{
PrependQueuedKeys(nextKey);
processingKeys = false;
}
if (selectedItem != previousItem)
{
DoReplacementForCompletion(matches[selectedItem], completions);
endBufferCoords = ConvertOffsetToCoordinates(_buffer.Length);
menuAreaTop = endBufferCoords.Y + 1;
InvertSelectedCompletion(menuBuffer, previousItem, menuColumnWidth, displayRows);
InvertSelectedCompletion(menuBuffer, selectedItem, menuColumnWidth, displayRows);
WriteBufferLines(menuBuffer, ref menuAreaTop);
previousItem = selectedItem;
if (previousMenuTop > menuAreaTop)
{
WriteBlankLines(previousMenuTop - menuAreaTop, menuAreaTop + displayRows);
}
}
}
WriteBlankLines(displayRows, menuAreaTop);
EndEditGroup();
if (undo)
{
// Pretend it never happened.
Undo();
}
}
else
{
var endBufferCoords = ConvertOffsetToCoordinates(_buffer.Length);
var menuAreaTop = endBufferCoords.Y + 1;
WriteBufferLines(menuBuffer, ref menuAreaTop);
_initialY = menuAreaTop + displayRows;
Render();
}
}
}
}
+61
View File
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
namespace PSConsoleUtilities
{
internal class ConsoleBufferBuilder
{
private List<CHAR_INFO> buffer;
public ConsoleBufferBuilder()
{
buffer = new List<CHAR_INFO>();
}
public ConsoleBufferBuilder(int capacity)
{
buffer = new List<CHAR_INFO>(capacity);
}
CHAR_INFO NewCharInfo(char c)
{
return new CHAR_INFO
{
UnicodeChar = c,
BackgroundColor = Console.BackgroundColor,
ForegroundColor = Console.ForegroundColor
};
}
public void Append(char c)
{
buffer.Add(NewCharInfo(c));
}
public void Append(string s)
{
foreach (char c in s)
{
buffer.Add(NewCharInfo(c));
}
}
public void Append(char c, int count)
{
while (count-- > 0)
{
buffer.Add(NewCharInfo(c));
}
}
public CHAR_INFO[] ToArray()
{
return buffer.ToArray();
}
public int Length
{
get { return buffer.Count; }
}
}
}
+1 -1
View File
@@ -33,7 +33,7 @@ namespace PSConsoleUtilities
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool ScrollConsoleScreenBuffer(IntPtr hConsoleOutput,
ref SMALL_RECT lpScrollRectangle,
ref SMALL_RECT lpClipRectangle,
IntPtr lpClipRectangle,
COORD dwDestinationOrigin,
ref CHAR_INFO lpFill);
+8 -18
View File
@@ -63,7 +63,8 @@ namespace PSConsoleUtilities
public static void AddToHistory(string command)
{
command = command.Replace("\r\n", "\n");
_singleton.MaybeAddToHistory(command, new List<EditItem>(), 0);
var editItems = new List<EditItem> {EditItemInsertString.Create(command, 0)};
_singleton.MaybeAddToHistory(command, editItems, 0);
}
/// <summary>
@@ -127,7 +128,7 @@ namespace PSConsoleUtilities
while (true)
{
newHistoryIndex = newHistoryIndex + direction;
if (newHistoryIndex < 0 && newHistoryIndex >= _history.Count)
if (newHistoryIndex < 0 || newHistoryIndex >= _history.Count)
{
break;
}
@@ -149,12 +150,11 @@ namespace PSConsoleUtilities
newHistoryIndex = _currentHistoryIndex + direction;
}
_recallHistoryCommandCount += 1;
if (newHistoryIndex >= 0 && newHistoryIndex < _history.Count)
if (newHistoryIndex >= 0 && newHistoryIndex <= _history.Count)
{
_currentHistoryIndex = newHistoryIndex;
UpdateFromHistory(moveCursor: true);
}
}
/// <summary>
@@ -189,9 +189,9 @@ namespace PSConsoleUtilities
}
_searchHistoryCommandCount += 1;
for (int i = _currentHistoryIndex + direction; i >=0 && i < _history.Count; i += direction)
for (int i = _currentHistoryIndex + direction; i >= 0 && i <= _history.Count; i += direction)
{
var line = _history[i]._line;
var line = i == _history.Count ? _savedCurrentLine._line : _history[i]._line;
if (line.StartsWith(_searchHistoryPrefix, Options.HistoryStringComparison))
{
if (Options.HistoryNoDuplicates)
@@ -376,18 +376,7 @@ namespace PSConsoleUtilities
}
else if (EndInteractiveHistorySearch(key, function))
{
if (_queuedKeys.Count > 0)
{
// This should almost never happen so being inefficient is fine.
var list = new List<ConsoleKeyInfo>(_queuedKeys);
_queuedKeys.Clear();
_queuedKeys.Enqueue(key);
list.ForEach(k => _queuedKeys.Enqueue(k));
}
else
{
_queuedKeys.Enqueue(key);
}
PrependQueuedKeys(key);
break;
}
else
@@ -441,6 +430,7 @@ namespace PSConsoleUtilities
InteractiveHistorySearchLoop(direction);
_hashedHistory = null;
_currentHistoryIndex = _history.Count;
// Remove our status line
_statusBuffer.Clear();
+5 -3
View File
@@ -108,7 +108,6 @@ namespace PSConsoleUtilities
{ Keys.CtrlSpace, MakeKeyHandler(PossibleCompletions, "PossibleCompletions") },
{ Keys.Tab, MakeKeyHandler(TabCompleteNext, "TabCompleteNext") },
{ Keys.ShiftTab, MakeKeyHandler(TabCompletePrevious, "TabCompletePrevious") },
{ Keys.CtrlV, MakeKeyHandler(Paste, "Paste") },
{ Keys.VolumeDown, MakeKeyHandler(Ignore, "Ignore") },
{ Keys.VolumeUp, MakeKeyHandler(Ignore, "Ignore") },
{ Keys.VolumeMute, MakeKeyHandler(Ignore, "Ignore") },
@@ -118,6 +117,7 @@ namespace PSConsoleUtilities
{ Keys.CtrlL, MakeKeyHandler(ClearScreen, "ClearScreen") },
{ Keys.CtrlR, MakeKeyHandler(ReverseSearchHistory, "ReverseSearchHistory") },
{ Keys.CtrlS, MakeKeyHandler(ForwardSearchHistory, "ForwardSearchHistory") },
{ Keys.CtrlV, MakeKeyHandler(Paste, "Paste") },
{ Keys.CtrlX, MakeKeyHandler(Cut, "Cut") },
{ Keys.CtrlY, MakeKeyHandler(Redo, "Redo") },
{ Keys.CtrlZ, MakeKeyHandler(Undo, "Undo") },
@@ -275,7 +275,8 @@ namespace PSConsoleUtilities
// Don't overwrite any of the line - so move to first line after the end of our buffer.
var coords = _singleton.ConvertOffsetToCoordinates(_singleton._buffer.Length);
_singleton.PlaceCursor(0, coords.Y + 1);
var y = coords.Y + 1;
_singleton.PlaceCursor(0, ref y);
Console.WriteLine(buffer.ToString());
_singleton._initialY = Console.CursorTop;
@@ -334,7 +335,8 @@ namespace PSConsoleUtilities
// Don't overwrite any of the line - so move to first line after the end of our buffer.
var coords = _singleton.ConvertOffsetToCoordinates(_singleton._buffer.Length);
_singleton.PlaceCursor(0, coords.Y + 1);
var y = coords.Y + 1;
_singleton.PlaceCursor(0, ref y);
Console.WriteLine(buffer.ToString());
_singleton._initialY = Console.CursorTop;
+2 -1
View File
@@ -53,6 +53,7 @@
<Compile Include="BasicEditing.cs" />
<Compile Include="Cmdlets.cs" />
<Compile Include="Completion.cs" />
<Compile Include="ConsoleBufferBuilder.cs" />
<Compile Include="ConsoleKeyChordConverter.cs" />
<Compile Include="ConsoleLib.cs" />
<Compile Include="History.cs" />
@@ -85,9 +86,9 @@
<ItemGroup>
<EmbeddedResource Include="PSReadLineResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>PSReadLineResources.Designer.cs</LastGenOutput>
<CustomToolNamespace>PSConsoleUtilities</CustomToolNamespace>
<SubType>Designer</SubType>
<LastGenOutput>PSReadLineResources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
+9
View File
@@ -591,6 +591,15 @@ namespace PSConsoleUtilities {
}
}
/// <summary>
/// Looks up a localized string similar to Complete the input if there is a single completion, otherwise complete the input by selecting from a menu of possible completions..
/// </summary>
internal static string MenuCompleteDescription {
get {
return ResourceManager.GetString("MenuCompleteDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Move to the end of the line..
/// </summary>
+3
View File
@@ -534,4 +534,7 @@
<data name="ViBackwardReplaceWordDescription" xml:space="preserve">
<value>Replace the previous word.</value>
</data>
<data name="MenuCompleteDescription" xml:space="preserve">
<value>Complete the input if there is a single completion, otherwise complete the input by selecting from a menu of possible completions.</value>
</data>
</root>
+21 -2
View File
@@ -31,7 +31,6 @@ namespace PSConsoleUtilities
private readonly StringBuilder _statusBuffer;
private string _statusLinePrompt;
private List<EditItem> _edits;
private int _editGroupCount;
private readonly Stack<int> _pushedEditGroupCount;
private int _undoEditIndex;
private int _mark;
@@ -124,6 +123,22 @@ namespace PSConsoleUtilities
return key;
}
private void PrependQueuedKeys(ConsoleKeyInfo key)
{
if (_queuedKeys.Count > 0)
{
// This should almost never happen so being inefficient is fine.
var list = new List<ConsoleKeyInfo>(_queuedKeys);
_queuedKeys.Clear();
_queuedKeys.Enqueue(key);
list.ForEach(k => _queuedKeys.Enqueue(k));
}
else
{
_queuedKeys.Enqueue(key);
}
}
private bool BreakHandler(ConsoleBreakSignal signal)
{
if (signal == ConsoleBreakSignal.Close || signal == ConsoleBreakSignal.Shutdown)
@@ -215,12 +230,17 @@ namespace PSConsoleUtilities
_emphasisStart = -1;
_emphasisLength = 0;
Render();
_currentHistoryIndex = _history.Count;
}
_searchHistoryCommandCount = 0;
_searchHistoryPrefix = null;
}
if (recallHistoryCommandCount == _recallHistoryCommandCount)
{
if (_recallHistoryCommandCount > 0)
{
_currentHistoryIndex = _history.Count;
}
_recallHistoryCommandCount = 0;
}
if (searchHistoryCommandCount == _searchHistoryCommandCount &&
@@ -315,7 +335,6 @@ namespace PSConsoleUtilities
_buffer.Clear();
_edits = new List<EditItem>();
_undoEditIndex = 0;
_editGroupCount = 0;
_pushedEditGroupCount.Clear();
_current = 0;
_mark = 0;
+25 -5
View File
@@ -255,15 +255,34 @@ namespace PSConsoleUtilities
Y = (short) bufferLineCount
};
var bufferCoord = new COORD {X = 0, Y = 0};
var bottom = top + bufferLineCount - 1;
var writeRegion = new SMALL_RECT
{
Top = (short) top,
Left = 0,
Bottom = (short) (top + bufferLineCount - 1),
Bottom = (short) bottom,
Right = (short) bufferWidth
};
NativeMethods.WriteConsoleOutput(handle, buffer,
bufferSize, bufferCoord, ref writeRegion);
// Now make sure the bottom line is visible
if (bottom >= (Console.WindowTop + Console.WindowHeight))
{
Console.CursorTop = bottom;
}
}
private static void WriteBlankLines(int count, int top)
{
var blanks = new CHAR_INFO[count * Console.BufferWidth];
for (int i = 0; i < count; i++)
{
blanks[i].BackgroundColor = Console.BackgroundColor;
blanks[i].ForegroundColor = Console.ForegroundColor;
blanks[i].UnicodeChar = ' ';
}
WriteBufferLines(blanks, ref top);
}
private static CHAR_INFO[] ReadBufferLines(int top, int count)
@@ -420,15 +439,15 @@ namespace PSConsoleUtilities
{
Top = (short) lines,
Left = 0,
Bottom = (short) (lines + Console.BufferHeight - 1),
Bottom = (short) (Console.BufferHeight - 1),
Right = (short)Console.BufferWidth
};
var destinationOrigin = new COORD {X = 0, Y = 0};
var fillChar = new CHAR_INFO(' ', Console.ForegroundColor, Console.BackgroundColor);
NativeMethods.ScrollConsoleScreenBuffer(handle, ref scrollRectangle, ref scrollRectangle, destinationOrigin, ref fillChar);
NativeMethods.ScrollConsoleScreenBuffer(handle, ref scrollRectangle, IntPtr.Zero, destinationOrigin, ref fillChar);
}
private void PlaceCursor(int x, int y)
private void PlaceCursor(int x, ref int y)
{
int statusLineCount = GetStatusLineCount();
if ((y + _demoWindowLineCount + statusLineCount) >= Console.BufferHeight)
@@ -442,7 +461,8 @@ namespace PSConsoleUtilities
private void PlaceCursor()
{
var coordinates = ConvertOffsetToCoordinates(_current);
PlaceCursor(coordinates.X, coordinates.Y);
int y = coordinates.Y;
PlaceCursor(coordinates.X, ref y);
}
private COORD ConvertOffsetToCoordinates(int offset)
+47
View File
@@ -355,3 +355,50 @@ Set-PSReadlineKeyHandler -Key F1 `
}
}
}
#
# Ctrl+Shift+j then type a key to mark the current directory.
# Ctrj+j then the same key will change back to that directory without
# needing to type cd and won't change the command line.
#
$global:PSReadlineMarks = @{}
Set-PSReadlineKeyHandler -Key Ctrl+Shift+j `
-BriefDescription MarkDirectory `
-LongDescription "Mark the current directory" `
-ScriptBlock {
param($key, $arg)
$key = [Console]::ReadKey($true)
$global:PSReadlineMarks[$key.KeyChar] = $pwd
}
Set-PSReadlineKeyHandler -Key Ctrl+j `
-BriefDescription JumpDirectory `
-LongDescription "Goto the marked directory" `
-ScriptBlock {
param($key, $arg)
$key = [Console]::ReadKey()
$dir = $global:PSReadlineMarks[$key.KeyChar]
if ($dir)
{
cd $dir
[PSConsoleUtilities.PSConsoleReadLine]::InvokePrompt()
}
}
Set-PSReadlineKeyHandler -Key Alt+j `
-BriefDescription ShowDirectoryMarks `
-LongDescription "Show the currently marked directories" `
-ScriptBlock {
param($key, $arg)
$global:PSReadlineMarks.GetEnumerator() | % {
[PSCustomObject]@{Key = $_.Key; Dir = $_.Value} } |
Format-Table -AutoSize | Out-Host
[PSConsoleUtilities.PSConsoleReadLine]::InvokePrompt()
}
+7 -10
View File
@@ -9,7 +9,7 @@ namespace PSConsoleUtilities
private void SaveEditItem(EditItem editItem)
{
// If there is some sort of edit after an undo, forget
// the
// any edit items that were undone.
int removeCount = _edits.Count - _undoEditIndex;
if (removeCount > 0)
{
@@ -17,23 +17,20 @@ namespace PSConsoleUtilities
}
_edits.Add(editItem);
_undoEditIndex = _edits.Count;
_editGroupCount++;
}
private void StartEditGroup()
{
_pushedEditGroupCount.Push(_editGroupCount);
_editGroupCount = 0;
_pushedEditGroupCount.Push(_edits.Count);
}
private void EndEditGroup(Action<ConsoleKeyInfo?, object> instigator = null, object instigatorArg = null)
{
// The last _editGroupCount edits are treated as a single item for undo
var start = _edits.Count - _editGroupCount;
var groupedEditItems = _edits.GetRange(start, _editGroupCount);
_edits.RemoveRange(start, _editGroupCount);
SaveEditItem(GroupedEdit.Create(groupedEditItems, instigator, instigatorArg));
_editGroupCount = _pushedEditGroupCount.Pop();
var groupEditStart = _pushedEditGroupCount.Pop();
var groupEditCount = _edits.Count - groupEditStart;
var groupedEditItems = _edits.GetRange(groupEditStart, groupEditCount);
_edits.RemoveRange(groupEditStart, groupEditCount);
SaveEditItem(GroupedEdit.Create(groupedEditItems));
}
/// <summary>
@@ -247,6 +247,15 @@ LONG DESCRIPTION
prefix is used for completion. If trying to complete the longest
unambiguous completion, a list of possible completions is displayed.
MenuComplete (Cmd: unbound Emacs: unbound)
Attempt to perform completion on the text surrounding the cursor.
If there are multiple possible completions, a list of possible
completions is displayed and you can select the correct completion
using the arrow keys or Tab/Shift+Tab. Escape and Ctrl+G cancel
the menu selection and reverts the line to the state before invoking
MenuComplete.
PossibleCompletions (Cmd: <Ctrl+Space> Emacs: <Alt+Equals>)
Display the list of possible completions.
+6 -3
View File
@@ -100,10 +100,13 @@ namespace TestPSReadLine
PSConsoleReadLine.SetOptions(new SetPSReadlineOption
{
EditMode = EditMode.Emacs,
EditMode = EditMode.Windows,
HistoryNoDuplicates = true,
});
//PSConsoleReadLine.SetKeyHandler(new[] {"UpArrow"}, PSConsoleReadLine.HistorySearchBackward, "", "");
//PSConsoleReadLine.SetKeyHandler(new[] {"DownArrow"}, PSConsoleReadLine.HistorySearchForward, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+LeftArrow"}, PSConsoleReadLine.ShellBackwardWord, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+RightArrow"}, PSConsoleReadLine.ShellNextWord, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"UpArrow"}, PSConsoleReadLine.HistorySearchBackward, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"DownArrow"}, PSConsoleReadLine.HistorySearchForward, "", "");
//PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+E"}, PSConsoleReadLine.EnableDemoMode, "", "");
//PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+D"}, PSConsoleReadLine.DisableDemoMode, "", "");
//PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+C"}, PSConsoleReadLine.CaptureScreen, "", "");
+24
View File
@@ -34,6 +34,26 @@ namespace UnitTestPSReadLine
Test("dir c*", Keys(_.UpArrow, _.UpArrow, _.DownArrow));
}
[TestMethod]
public void TestHistoryRecallCurrentLine()
{
TestSetup(KeyMode.Cmd);
SetHistory("echo foo", "echo bar");
Test("ec", Keys("ec", _.UpArrow, _.UpArrow, _.DownArrow, _.DownArrow));
}
[TestMethod]
public void TestHistorySearchCurrentLine()
{
TestSetup(KeyMode.Cmd,
new KeyHandler("UpArrow", PSConsoleReadLine.HistorySearchBackward),
new KeyHandler("DownArrow", PSConsoleReadLine.HistorySearchForward));
SetHistory("echo foo", "echo bar");
Test("ec", Keys("ec", _.UpArrow, _.UpArrow, _.DownArrow, _.DownArrow));
}
[TestMethod]
public void TestSearchHistory()
{
@@ -422,6 +442,10 @@ namespace UnitTestPSReadLine
Test("cccc", Keys(
Enumerable.Repeat(_.UpArrow, 3),
Enumerable.Repeat(_.DownArrow, 2)));
// No history
SetHistory();
Test("", Keys(_.UpArrow, _.DownArrow));
}
[TestMethod]
+1 -1
View File
@@ -1 +1 @@
<Playlist Version="1.0"><Add Test="UnitTestPSReadLine.UnitTest.TestHistorySearchCursorMovesToEnd" /><Add Test="UnitTestPSReadLine.UnitTest.TestBeginningOfHistory" /><Add Test="UnitTestPSReadLine.UnitTest.TestInteractiveHistorySearch" /><Add Test="UnitTestPSReadLine.UnitTest.TestHistory" /><Add Test="UnitTestPSReadLine.UnitTest.TestAddToHistoryHandler" /><Add Test="UnitTestPSReadLine.UnitTest.TestHistoryCount" /><Add Test="UnitTestPSReadLine.UnitTest.TestSearchHistory" /><Add Test="UnitTestPSReadLine.UnitTest.TestInteractiveHistorySearchNoDuplicates" /><Add Test="UnitTestPSReadLine.UnitTest.TestHistorySearchNoDuplicates" /><Add Test="UnitTestPSReadLine.UnitTest.TestHistoryNoDuplicates" /></Playlist>
<Playlist Version="1.0"><Add Test="UnitTestPSReadLine.UnitTest.TestHistorySearchCursorMovesToEnd" /><Add Test="UnitTestPSReadLine.UnitTest.TestBeginningOfHistory" /><Add Test="UnitTestPSReadLine.UnitTest.TestInteractiveHistorySearch" /><Add Test="UnitTestPSReadLine.UnitTest.TestHistory" /><Add Test="UnitTestPSReadLine.UnitTest.TestAddToHistoryHandler" /><Add Test="UnitTestPSReadLine.UnitTest.TestHistoryCount" /><Add Test="UnitTestPSReadLine.UnitTest.TestSearchHistory" /><Add Test="UnitTestPSReadLine.UnitTest.TestInteractiveHistorySearchNoDuplicates" /><Add Test="UnitTestPSReadLine.UnitTest.TestHistorySearchNoDuplicates" /><Add Test="UnitTestPSReadLine.UnitTest.TestHistoryNoDuplicates" /><Add Test="UnitTestPSReadLine.UnitTest.TestEndOfHistory" /></Playlist>
+1 -1
View File
@@ -455,7 +455,7 @@ namespace UnitTestPSReadLine
};
var destinationOrigin = new COORD {X = 0, Y = 0};
var fillChar = new CHAR_INFO(' ', Console.ForegroundColor, Console.BackgroundColor);
NativeMethods.ScrollConsoleScreenBuffer(handle, ref scrollRectangle, ref scrollRectangle, destinationOrigin, ref fillChar);
NativeMethods.ScrollConsoleScreenBuffer(handle, ref scrollRectangle, IntPtr.Zero, destinationOrigin, ref fillChar);
}
private static void WriteBufferLines(CHAR_INFO[] buffer, ref int top)