/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.PowerShell
{
public partial class PSConsoleReadLine
{
///
/// Move the cursor forward to the start of the next word.
/// Word boundaries are defined by a configurable set of characters.
///
public static void ViNextWord(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
ViBackwardWord(key, -numericArg);
return;
}
while (numericArg-- > 0)
{
int i = _singleton.ViFindNextWordPoint(_singleton.Options.WordDelimiters);
if (i >= _singleton._buffer.Length)
{
i += ViEndOfLineFactor;
}
_singleton._current = i;
_singleton.PlaceCursor();
}
}
///
/// Move the cursor back to the start of the current word, or if between words,
/// the start of the previous word. Word boundaries are defined by a configurable
/// set of characters.
///
public static void ViBackwardWord(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
ViNextWord(key, -numericArg);
return;
}
while (numericArg-- > 0)
{
int i = _singleton.ViFindPreviousWordPoint(_singleton.Options.WordDelimiters);
_singleton._current = i;
_singleton.PlaceCursor();
}
}
///
/// Moves the cursor back to the beginning of the previous word, using only white space as delimiters.
///
public static void ViBackwardGlob(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
int i = _singleton._current;
while (numericArg-- > 0)
{
i = _singleton.ViFindPreviousGlob(i - 1);
}
_singleton._current = i;
_singleton.PlaceCursor();
}
///
/// Moves to the next word, using only white space as a word delimiter.
///
private static void ViNextGlob(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
int i = _singleton._current;
while (numericArg-- > 0)
{
i = _singleton.ViFindNextGlob(i);
}
_singleton._current = Math.Min(i, _singleton._buffer.Length - 1);
_singleton.PlaceCursor();
}
private static void ViEndOfGlob(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
ViEndOfPreviousGlob(key, -numericArg);
return;
}
while (numericArg-- > 0)
{
int i = _singleton.ViFindEndOfGlob();
_singleton._current = i;
_singleton.PlaceCursor();
}
}
private static void ViEndOfPreviousGlob(ConsoleKeyInfo? key = null, object arg = null)
{
int numericArg;
if (!TryGetArgAsInt(arg, out numericArg, 1))
{
return;
}
if (numericArg < 0)
{
ViEndOfGlob(key, -numericArg);
return;
}
while (numericArg-- > 0)
{
int i = _singleton.ViFindEndOfPreviousGlob();
_singleton._current = i;
_singleton.PlaceCursor();
}
}
///
/// Returns 0 if the cursor is allowed to go past the last character in the line, -1 otherwise.
///
///
private static int ViEndOfLineFactor
{
get
{
if (_singleton._dispatchTable == _viCmdKeyMap)
{
return -1;
}
return 0;
}
}
///
/// Move the cursor to the end of the input.
///
public static void MoveToEndOfLine(ConsoleKeyInfo? key = null, object arg = null)
{
_singleton._current = Math.Max(0, _singleton._buffer.Length + ViEndOfLineFactor);
_singleton.PlaceCursor();
}
///
/// Move the cursor forward to the end of the current word, or if between words,
/// to the end of the next word. Word boundaries are defined by a configurable
/// set of characters.
///
public static void NextWordEnd(ConsoleKeyInfo? key = null, object arg = null)
{
int qty = (arg is int) ? (int)arg : 1;
for (; qty > 0 && _singleton._current < _singleton._buffer.Length - 1; qty--)
{
int i = _singleton.ViFindNextWordEnd(_singleton.Options.WordDelimiters);
_singleton._current = i;
_singleton.PlaceCursor();
}
}
///
/// Move to the column indicated by arg.
///
public static void GotoColumn(ConsoleKeyInfo? key = null, object arg = null)
{
int col = (arg is int) ? (int) arg : -1;
if (col < 0 ) {
Ding();
return;
}
if (col < _singleton._buffer.Length + ViEndOfLineFactor)
{
_singleton._current = Math.Min(col, _singleton._buffer.Length) - 1;
}
else
{
_singleton._current = _singleton._buffer.Length + ViEndOfLineFactor;
Ding();
}
_singleton.PlaceCursor();
}
///
/// Move the cursor to the first non-blank character in the line.
///
public static void GotoFirstNonBlankOfLine(ConsoleKeyInfo? key = null, object arg = null)
{
for (int i = 0; i < _singleton._buffer.Length; i++)
{
if (!Char.IsWhiteSpace(_singleton._buffer[i]))
{
_singleton._current = i;
_singleton.PlaceCursor();
return;
}
}
}
///
/// Similar to , but is character based instead of token based.
///
public static void ViGotoBrace(ConsoleKeyInfo? key = null, object arg = null)
{
int i = _singleton.ViFindBrace(_singleton._current);
if (i == _singleton._current)
{
Ding();
return;
}
_singleton._current = i;
_singleton.PlaceCursor();
}
private int ViFindBrace(int i)
{
switch (_buffer[i])
{
case '{':
return ViFindForward(i, '}', withoutPassing: '{');
case '[':
return ViFindForward(i, ']', withoutPassing: '[');
case '(':
return ViFindForward(i, ')', withoutPassing: '(');
case '}':
return ViFindBackward(i, '{', withoutPassing: '}');
case ']':
return ViFindBackward(i, '[', withoutPassing: ']');
case ')':
return ViFindBackward(i, '(', withoutPassing: ')');
default:
return i;
}
}
private int ViFindBackward(int start, char target, char withoutPassing)
{
if (start == 0)
{
return start;
}
int i = start - 1;
int withoutPassingCount = 0;
while (i != 0 && !(_buffer[i] == target && withoutPassingCount == 0))
{
if (_buffer[i] == withoutPassing)
{
withoutPassingCount++;
}
if (_buffer[i] == target)
{
withoutPassingCount--;
}
i--;
}
if (_buffer[i] == target && withoutPassingCount == 0)
{
return i;
}
return start;
}
private int ViFindForward(int start, char target, char withoutPassing)
{
if (IsAtEndOfLine(start))
{
return start;
}
int i = start + 1;
int withoutPassingCount = 0;
while (!IsAtEndOfLine(i) && !(_buffer[i] == target && withoutPassingCount == 0))
{
if (_buffer[i] == withoutPassing)
{
withoutPassingCount++;
}
if (_buffer[i] == target)
{
withoutPassingCount--;
}
i++;
}
if (_buffer[i] == target && withoutPassingCount == 0)
{
return i;
}
return start;
}
}
}