/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Management.Automation;
using System.Management.Automation.Language;
using System.Management.Automation.Runspaces;
namespace Microsoft.PowerShell
{
namespace Internal
{
#pragma warning disable 1591
[SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")]
public interface IPSConsoleReadLineMockableMethods
{
void Ding();
CommandCompletion CompleteInput(string input, int cursorIndex, Hashtable options, System.Management.Automation.PowerShell powershell);
bool RunspaceIsRemote(Runspace runspace);
}
[SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes")]
public interface IConsole
{
object GetConsoleInputMode();
void SetConsoleInputMode(object mode);
void RestoreConsoleInputMode(object mode);
ConsoleKeyInfo ReadKey();
bool KeyAvailable { get; }
int CursorLeft { get; set; }
int CursorTop { get; set;}
int CursorSize { get; set; }
int BufferWidth { get; set; }
int BufferHeight { get; set;}
int WindowWidth { get; set; }
int WindowHeight { get; set; }
int WindowTop { get; set; }
ConsoleColor BackgroundColor { get; set; }
ConsoleColor ForegroundColor { get; set; }
void SetWindowPosition(int left, int top);
void SetCursorPosition(int left, int top);
void WriteLine(string s);
void Write(string s);
void WriteBufferLines(BufferChar[] buffer, ref int top);
void WriteBufferLines(BufferChar[] buffer, ref int top, bool ensureBottomLineVisible);
void ScrollBuffer(int lines);
BufferChar[] ReadBufferLines(int top, int count);
void StartRender();
int LengthInBufferCells(char c);
void EndRender();
#if UNIX
void Clear();
#endif
}
#pragma warning restore 1591
}
///
public partial class PSConsoleReadLine
{
///
/// Insert a character at the current position. Supports undo.
///
/// Character to insert
public static void Insert(char c)
{
_singleton.SaveEditItem(EditItemInsertChar.Create(c, _singleton._current));
// Use Append if possible because Insert at end makes StringBuilder quite slow.
if (_singleton._current == _singleton._buffer.Length)
{
_singleton._buffer.Append(c);
}
else
{
_singleton._buffer.Insert(_singleton._current, c);
}
_singleton._current += 1;
_singleton.Render();
}
///
/// Insert a string at the current position. Supports undo.
///
/// String to insert
public static void Insert(string s)
{
_singleton.SaveEditItem(EditItemInsertString.Create(s, _singleton._current));
// Use Append if possible because Insert at end makes StringBuilder quite slow.
if (_singleton._current == _singleton._buffer.Length)
{
_singleton._buffer.Append(s);
}
else
{
_singleton._buffer.Insert(_singleton._current, s);
}
_singleton._current += s.Length;
_singleton.Render();
}
///
/// Delete some text at the given position. Supports undo.
///
/// The start position to delete
/// The length to delete
public static void Delete(int start, int length)
{
Replace(start, length, null);
}
///
/// Replace some text at the given position. Supports undo.
///
/// The start position to replace
/// The length to replace
/// The replacement text
/// The action that initiated the replace (used for undo)
/// The argument to the action that initiated the replace (used for undo)
public static void Replace(int start, int length, string replacement, Action instigator = null, object instigatorArg = null)
{
if (start < 0 || start > _singleton._buffer.Length)
{
throw new ArgumentException(PSReadLineResources.StartOutOfRange, "start");
}
if (length > (_singleton._buffer.Length - start))
{
throw new ArgumentException(PSReadLineResources.ReplacementLengthTooBig, "length");
}
bool useEditGroup = (_singleton._editGroupStart == -1);
if (useEditGroup)
{
_singleton.StartEditGroup();
}
var str = _singleton._buffer.ToString(start, length);
_singleton.SaveEditItem(EditItemDelete.Create(str, start));
_singleton._buffer.Remove(start, length);
if (replacement != null)
{
_singleton.SaveEditItem(EditItemInsertString.Create(replacement, start));
_singleton._buffer.Insert(start, replacement);
_singleton._current = start + replacement.Length;
}
else
{
_singleton._current = start;
}
if (useEditGroup)
{
_singleton.EndEditGroup(instigator, instigatorArg); // Instigator is needed for VI undo
_singleton.Render();
}
}
///
/// Get the state of the buffer - the current input and the position of the cursor
///
public static void GetBufferState(out string input, out int cursor)
{
input = _singleton._buffer.ToString();
cursor = _singleton._current;
}
///
/// Get the state of the buffer - the ast, tokens, errors, and position of the cursor
///
public static void GetBufferState(out Ast ast, out Token[] tokens, out ParseError[] parseErrors, out int cursor)
{
_singleton.ParseInput();
ast = _singleton._ast;
tokens = _singleton._tokens;
parseErrors = _singleton._parseErrors;
cursor = _singleton._current;
}
///
/// Get the selection state of the buffer
///
/// The start of the current selection or -1 if nothing is selected.
/// The length of the current selection or -1 if nothing is selected.
public static void GetSelectionState(out int start, out int length)
{
if (_singleton._visualSelectionCommandCount == 0)
{
start = -1;
length = -1;
}
else
{
_singleton.GetRegion(out start, out length);
}
}
///
/// Set the position of the cursor.
///
public static void SetCursorPosition(int cursor)
{
if (cursor > _singleton._buffer.Length + ViEndOfLineFactor)
{
cursor = _singleton._buffer.Length + ViEndOfLineFactor;
}
if (cursor < 0)
{
cursor = 0;
}
_singleton._current = cursor;
_singleton.PlaceCursor();
}
///
/// A helper method when your function expects an optional int argument (e.g. from DigitArgument)
/// If there is not argument (it's null), returns true and sets numericArg to defaultNumericArg.
/// Dings and returns false if the argument is not an int (no conversion is attempted)
/// Otherwise returns true, and numericArg has the result.
///
public static bool TryGetArgAsInt(object arg, out int numericArg, int defaultNumericArg)
{
if (arg == null)
{
numericArg = defaultNumericArg;
return true;
}
if (arg is int)
{
numericArg = (int)arg;
return true;
}
Ding();
numericArg = 0;
return false;
}
}
}