mirror of
https://github.com/PowerShell/PSReadLine
synced 2026-06-08 12:12:13 +00:00
Finish refactoring so unit tests run in VS2015
The mock of the console api is complete enough so unit tests run. It's still a hack, not exactly factored nicely to support other hosts, but at least some of the real interface is in one place, not scattered about.
This commit is contained in:
@@ -409,6 +409,38 @@ namespace Microsoft.PowerShell
|
||||
|
||||
internal class ConhostConsole : IConsole
|
||||
{
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
|
||||
private IntPtr _hwnd = (IntPtr)0;
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
|
||||
private IntPtr _hDC = (IntPtr)0;
|
||||
private uint _codePage;
|
||||
private bool _istmInitialized = false;
|
||||
private TEXTMETRIC _tm = new TEXTMETRIC();
|
||||
private bool _trueTypeInUse = false;
|
||||
|
||||
private readonly Lazy<SafeFileHandle> _outputHandle = new Lazy<SafeFileHandle>(() =>
|
||||
{
|
||||
// We use CreateFile here instead of GetStdWin32Handle, as GetStdWin32Handle will return redirected handles
|
||||
var handle = NativeMethods.CreateFile(
|
||||
"CONOUT$",
|
||||
(UInt32)(AccessQualifiers.GenericRead | AccessQualifiers.GenericWrite),
|
||||
(UInt32)ShareModes.ShareWrite,
|
||||
(IntPtr)0,
|
||||
(UInt32)CreationDisposition.OpenExisting,
|
||||
0,
|
||||
(IntPtr)0);
|
||||
|
||||
if (handle == NativeMethods.INVALID_HANDLE_VALUE)
|
||||
{
|
||||
int err = Marshal.GetLastWin32Error();
|
||||
Win32Exception innerException = new Win32Exception(err);
|
||||
throw new Exception("Failed to retreive the input console handle.", innerException);
|
||||
}
|
||||
|
||||
return new SafeFileHandle(handle, true);
|
||||
}
|
||||
);
|
||||
|
||||
private readonly Lazy<SafeFileHandle> _inputHandle = new Lazy<SafeFileHandle>(() =>
|
||||
{
|
||||
// We use CreateFile here instead of GetStdWin32Handle, as GetStdWin32Handle will return redirected handles
|
||||
@@ -613,5 +645,197 @@ namespace Microsoft.PowerShell
|
||||
readBufferSize, readBufferCoord, ref readRegion);
|
||||
return result;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods",
|
||||
Justification = "Then the API we pass the handle to will return an error if it is invalid. They are not exposed.")]
|
||||
internal static CONSOLE_FONT_INFO_EX GetConsoleFontInfo(SafeFileHandle consoleHandle)
|
||||
{
|
||||
|
||||
CONSOLE_FONT_INFO_EX fontInfo = new CONSOLE_FONT_INFO_EX();
|
||||
fontInfo.cbSize = Marshal.SizeOf(fontInfo);
|
||||
bool result = NativeMethods.GetCurrentConsoleFontEx(consoleHandle.DangerousGetHandle(), false, ref fontInfo);
|
||||
|
||||
if (result == false)
|
||||
{
|
||||
int err = Marshal.GetLastWin32Error();
|
||||
Win32Exception innerException = new Win32Exception(err);
|
||||
throw new Exception("Failed to get console font information.", innerException);
|
||||
}
|
||||
return fontInfo;
|
||||
}
|
||||
|
||||
public int LengthInBufferCells(char c)
|
||||
{
|
||||
if (!IsCJKOutputCodePage() || !_trueTypeInUse)
|
||||
return 1;
|
||||
|
||||
return LengthInBufferCellsFE(c);
|
||||
}
|
||||
|
||||
internal static bool IsAnyDBCSCharSet(uint charSet)
|
||||
{
|
||||
const uint SHIFTJIS_CHARSET = 128;
|
||||
const uint HANGEUL_CHARSET = 129;
|
||||
const uint CHINESEBIG5_CHARSET = 136;
|
||||
const uint GB2312_CHARSET = 134;
|
||||
return charSet == SHIFTJIS_CHARSET || charSet == HANGEUL_CHARSET ||
|
||||
charSet == CHINESEBIG5_CHARSET || charSet == GB2312_CHARSET;
|
||||
}
|
||||
|
||||
internal uint CodePageToCharSet()
|
||||
{
|
||||
CHARSETINFO csi;
|
||||
const uint TCI_SRCCODEPAGE = 2;
|
||||
const uint OEM_CHARSET = 255;
|
||||
if (!NativeMethods.TranslateCharsetInfo((IntPtr)_codePage, out csi, TCI_SRCCODEPAGE))
|
||||
{
|
||||
csi.ciCharset = OEM_CHARSET;
|
||||
}
|
||||
return csi.ciCharset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the output buffer code page is Japanese, Simplified Chinese, Korean, or Traditional Chinese
|
||||
/// </summary>
|
||||
/// <returns>true if it is CJK code page; otherwise, false.</returns>
|
||||
internal bool IsCJKOutputCodePage()
|
||||
{
|
||||
return _codePage == 932 || // Japanese
|
||||
_codePage == 936 || // Simplified Chinese
|
||||
_codePage == 949 || // Korean
|
||||
_codePage == 950; // Traditional Chinese
|
||||
}
|
||||
|
||||
internal bool IsAvailableFarEastCodePage()
|
||||
{
|
||||
uint charSet = CodePageToCharSet();
|
||||
return IsAnyDBCSCharSet(charSet);
|
||||
}
|
||||
|
||||
internal int LengthInBufferCellsFE(char c)
|
||||
{
|
||||
if (0x20 <= c && c <= 0x7e)
|
||||
{
|
||||
/* ASCII */
|
||||
return 1;
|
||||
}
|
||||
else if (0x3041 <= c && c <= 0x3094)
|
||||
{
|
||||
/* Hiragana */
|
||||
return 2;
|
||||
}
|
||||
else if (0x30a1 <= c && c <= 0x30f6)
|
||||
{
|
||||
/* Katakana */
|
||||
return 2;
|
||||
}
|
||||
else if (0x3105 <= c && c <= 0x312c)
|
||||
{
|
||||
/* Bopomofo */
|
||||
return 2;
|
||||
}
|
||||
else if (0x3131 <= c && c <= 0x318e)
|
||||
{
|
||||
/* Hangul Elements */
|
||||
return 2;
|
||||
}
|
||||
else if (0xac00 <= c && c <= 0xd7a3)
|
||||
{
|
||||
/* Korean Hangul Syllables */
|
||||
return 2;
|
||||
}
|
||||
else if (0xff01 <= c && c <= 0xff5e)
|
||||
{
|
||||
/* Fullwidth ASCII variants */
|
||||
return 2;
|
||||
}
|
||||
else if (0xff61 <= c && c <= 0xff9f)
|
||||
{
|
||||
/* Halfwidth Katakana variants */
|
||||
return 1;
|
||||
}
|
||||
else if ((0xffa0 <= c && c <= 0xffbe) ||
|
||||
(0xffc2 <= c && c <= 0xffc7) ||
|
||||
(0xffca <= c && c <= 0xffcf) ||
|
||||
(0xffd2 <= c && c <= 0xffd7) ||
|
||||
(0xffda <= c && c <= 0xffdc))
|
||||
{
|
||||
/* Halfwidth Hangule variants */
|
||||
return 1;
|
||||
}
|
||||
else if (0xffe0 <= c && c <= 0xffe6)
|
||||
{
|
||||
/* Fullwidth symbol variants */
|
||||
return 2;
|
||||
}
|
||||
else if (0x4e00 <= c && c <= 0x9fa5)
|
||||
{
|
||||
/* Han Ideographic */
|
||||
return 2;
|
||||
}
|
||||
else if (0xf900 <= c && c <= 0xfa2d)
|
||||
{
|
||||
/* Han Compatibility Ideographs */
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unknown character: need to use GDI*/
|
||||
if (_hDC == (IntPtr)0)
|
||||
{
|
||||
_hwnd = NativeMethods.GetConsoleWindow();
|
||||
if ((IntPtr)0 == _hwnd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
_hDC = NativeMethods.GetDC(_hwnd);
|
||||
if ((IntPtr)0 == _hDC)
|
||||
{
|
||||
//Don't throw exception so that output can continue
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
bool result = true;
|
||||
if (!_istmInitialized)
|
||||
{
|
||||
result = NativeMethods.GetTextMetrics(_hDC, out _tm);
|
||||
if (!result)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
_istmInitialized = true;
|
||||
}
|
||||
int width;
|
||||
result = NativeMethods.GetCharWidth32(_hDC, (uint)c, (uint)c, out width);
|
||||
if (!result)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (width >= _tm.tmMaxCharWidth)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void StartRender()
|
||||
{
|
||||
_codePage = NativeMethods.GetConsoleOutputCP();
|
||||
_istmInitialized = false;
|
||||
var consoleHandle = _outputHandle.Value;
|
||||
CONSOLE_FONT_INFO_EX fontInfo = ConhostConsole.GetConsoleFontInfo(consoleHandle);
|
||||
int fontType = fontInfo.FontFamily & NativeMethods.FontTypeMask;
|
||||
_trueTypeInUse = (fontType & NativeMethods.TrueTypeFont) == NativeMethods.TrueTypeFont;
|
||||
|
||||
}
|
||||
|
||||
public void EndRender()
|
||||
{
|
||||
if (_hwnd != (IntPtr)0 && _hDC != (IntPtr)0)
|
||||
{
|
||||
NativeMethods.ReleaseDC(_hwnd, _hDC);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,10 @@ namespace Microsoft.PowerShell
|
||||
void WriteBufferLines(CHAR_INFO[] buffer, ref int top, bool ensureBottomLineVisible);
|
||||
void ScrollBuffer(int lines);
|
||||
CHAR_INFO[] ReadBufferLines(int top, int count);
|
||||
|
||||
void StartRender();
|
||||
int LengthInBufferCells(char c);
|
||||
void EndRender();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
-238
@@ -4,13 +4,10 @@ Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Management.Automation.Language;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.PowerShell.Internal;
|
||||
using ConsoleHandle = Microsoft.Win32.SafeHandles.SafeFileHandle;
|
||||
|
||||
namespace Microsoft.PowerShell
|
||||
{
|
||||
@@ -26,37 +23,6 @@ namespace Microsoft.PowerShell
|
||||
private int _current;
|
||||
private int _emphasisStart;
|
||||
private int _emphasisLength;
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
|
||||
private IntPtr _hwnd = (IntPtr)0;
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
|
||||
private IntPtr _hDC = (IntPtr)0;
|
||||
private uint _codePage;
|
||||
private bool _istmInitialized = false;
|
||||
private TEXTMETRIC _tm = new TEXTMETRIC();
|
||||
private bool _trueTypeInUse = false;
|
||||
|
||||
private readonly Lazy<ConsoleHandle> _outputHandle = new Lazy<ConsoleHandle>(() =>
|
||||
{
|
||||
// We use CreateFile here instead of GetStdWin32Handle, as GetStdWin32Handle will return redirected handles
|
||||
var handle = NativeMethods.CreateFile(
|
||||
"CONOUT$",
|
||||
(UInt32)(AccessQualifiers.GenericRead | AccessQualifiers.GenericWrite),
|
||||
(UInt32)ShareModes.ShareWrite,
|
||||
(IntPtr)0,
|
||||
(UInt32)CreationDisposition.OpenExisting,
|
||||
0,
|
||||
(IntPtr)0);
|
||||
|
||||
if (handle == NativeMethods.INVALID_HANDLE_VALUE)
|
||||
{
|
||||
int err = Marshal.GetLastWin32Error();
|
||||
Win32Exception innerException = new Win32Exception(err);
|
||||
throw new Exception("Failed to retreive the input console handle.", innerException);
|
||||
}
|
||||
|
||||
return new ConsoleHandle(handle, true);
|
||||
}
|
||||
);
|
||||
|
||||
private class SavedTokenState
|
||||
{
|
||||
@@ -112,12 +78,6 @@ namespace Microsoft.PowerShell
|
||||
private void ReallyRender()
|
||||
{
|
||||
var text = ParseInput();
|
||||
_codePage = NativeMethods.GetConsoleOutputCP();
|
||||
_istmInitialized = false;
|
||||
ConsoleHandle consoleHandle = _outputHandle.Value;
|
||||
CONSOLE_FONT_INFO_EX fontInfo = GetConsoleFontInfo(consoleHandle);
|
||||
int fontType = fontInfo.FontFamily & NativeMethods.FontTypeMask;
|
||||
_trueTypeInUse = (fontType & NativeMethods.TrueTypeFont) == NativeMethods.TrueTypeFont;
|
||||
|
||||
int statusLineCount = GetStatusLineCount();
|
||||
int j = _initialX + (_bufferWidth * Options.ExtraPromptLineCount);
|
||||
@@ -140,6 +100,8 @@ namespace Microsoft.PowerShell
|
||||
|
||||
try
|
||||
{
|
||||
_console.StartRender();
|
||||
|
||||
bufferLineCount = ConvertOffsetToCoordinates(text.Length).Y - _initialY + 1 + statusLineCount;
|
||||
if (_consoleBuffer.Length != bufferLineCount * bufferWidth)
|
||||
{
|
||||
@@ -160,13 +122,12 @@ namespace Microsoft.PowerShell
|
||||
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
SavedTokenState state = null;
|
||||
totalBytes = totalBytes % bufferWidth;
|
||||
if (!afterLastToken)
|
||||
{
|
||||
// Figure out the color of the character - if it's in a token,
|
||||
// use the tokens color otherwise use the initial color.
|
||||
state = tokenStack.Peek();
|
||||
var state = tokenStack.Peek();
|
||||
var token = state.Tokens[state.Index];
|
||||
if (i == token.Extent.EndOffset)
|
||||
{
|
||||
@@ -228,7 +189,8 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
}
|
||||
|
||||
if (text[i] == '\n')
|
||||
var charToRender = text[i];
|
||||
if (charToRender == '\n')
|
||||
{
|
||||
while ((j % bufferWidth) != 0)
|
||||
{
|
||||
@@ -244,7 +206,7 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
else
|
||||
{
|
||||
int size = LengthInBufferCells(text[i]);
|
||||
int size = LengthInBufferCells(charToRender);
|
||||
totalBytes += size;
|
||||
|
||||
//if there is no enough space for the character at the edge, fill in spaces at the end and
|
||||
@@ -256,28 +218,28 @@ namespace Microsoft.PowerShell
|
||||
totalBytes++;
|
||||
}
|
||||
|
||||
if (char.IsControl(text[i]))
|
||||
if (char.IsControl(charToRender))
|
||||
{
|
||||
_consoleBuffer[j].UnicodeChar = '^';
|
||||
MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
|
||||
_consoleBuffer[j].UnicodeChar = (char)('@' + text[i]);
|
||||
_consoleBuffer[j].UnicodeChar = (char)('@' + charToRender);
|
||||
MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
|
||||
|
||||
}
|
||||
else if (size > 1 && IsCJKOutputCodePage() && _trueTypeInUse)
|
||||
else if (size > 1)
|
||||
{
|
||||
_consoleBuffer[j].UnicodeChar = text[i];
|
||||
_consoleBuffer[j].Attributes = (ushort)((uint)_consoleBuffer[j].Attributes |
|
||||
_consoleBuffer[j].UnicodeChar = charToRender;
|
||||
_consoleBuffer[j].Attributes = (ushort)(_consoleBuffer[j].Attributes |
|
||||
(uint)CHAR_INFO_Attributes.COMMON_LVB_LEADING_BYTE);
|
||||
MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
|
||||
_consoleBuffer[j].UnicodeChar = text[i];
|
||||
_consoleBuffer[j].Attributes = (ushort)((uint)_consoleBuffer[j].Attributes |
|
||||
_consoleBuffer[j].UnicodeChar = charToRender;
|
||||
_consoleBuffer[j].Attributes = (ushort)(_consoleBuffer[j].Attributes |
|
||||
(uint)CHAR_INFO_Attributes.COMMON_LVB_TRAILING_BYTE);
|
||||
MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
_consoleBuffer[j].UnicodeChar = text[i];
|
||||
_consoleBuffer[j].UnicodeChar = charToRender;
|
||||
MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
|
||||
}
|
||||
}
|
||||
@@ -285,10 +247,7 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_hwnd != (IntPtr)0 && _hDC != (IntPtr)0)
|
||||
{
|
||||
NativeMethods.ReleaseDC(_hwnd, _hDC);
|
||||
}
|
||||
_console.EndRender();
|
||||
}
|
||||
|
||||
for (; j < (_consoleBuffer.Length - (statusLineCount * _bufferWidth)); j++)
|
||||
@@ -358,6 +317,16 @@ namespace Microsoft.PowerShell
|
||||
_lastRenderTime.Restart();
|
||||
}
|
||||
|
||||
private int LengthInBufferCells(char c)
|
||||
{
|
||||
int length = Char.IsControl(c) ? 1 : 0;
|
||||
if (c < 256)
|
||||
{
|
||||
return length + 1;
|
||||
}
|
||||
return _console.LengthInBufferCells(c);
|
||||
}
|
||||
|
||||
private static void WriteBlankLines(int count, int top)
|
||||
{
|
||||
var console = _singleton._console;
|
||||
@@ -479,24 +448,6 @@ namespace Microsoft.PowerShell
|
||||
return i >= start && i < end;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods",
|
||||
Justification = "Then the API we pass the handle to will return an error if it is invalid. They are not exposed.")]
|
||||
private static CONSOLE_FONT_INFO_EX GetConsoleFontInfo(ConsoleHandle consoleHandle)
|
||||
{
|
||||
|
||||
CONSOLE_FONT_INFO_EX fontInfo = new CONSOLE_FONT_INFO_EX();
|
||||
fontInfo.cbSize = Marshal.SizeOf(fontInfo);
|
||||
bool result = NativeMethods.GetCurrentConsoleFontEx(consoleHandle.DangerousGetHandle(), false, ref fontInfo);
|
||||
|
||||
if (result == false)
|
||||
{
|
||||
int err = Marshal.GetLastWin32Error();
|
||||
Win32Exception innerException = new Win32Exception(err);
|
||||
throw new Exception("Failed to get console font information.", innerException);
|
||||
}
|
||||
return fontInfo;
|
||||
}
|
||||
|
||||
private void MaybeEmphasize(ref CHAR_INFO charInfo, int i, ConsoleColor foregroundColor, ConsoleColor backgroundColor)
|
||||
{
|
||||
if (i >= _emphasisStart && i < (_emphasisStart + _emphasisLength))
|
||||
@@ -537,163 +488,6 @@ namespace Microsoft.PowerShell
|
||||
PlaceCursor(coordinates.X, ref y);
|
||||
}
|
||||
|
||||
private int LengthInBufferCells(char c)
|
||||
{
|
||||
int length = char.IsControl(c) ? 1 : 0;
|
||||
if (c < 256 || !IsAvailableFarEastCodePage())
|
||||
{
|
||||
return length + 1;
|
||||
}
|
||||
return length + LengthInBufferCellsFE(c);
|
||||
}
|
||||
|
||||
private bool IsAnyDBCSCharSet(uint charSet)
|
||||
{
|
||||
const uint SHIFTJIS_CHARSET = 128;
|
||||
const uint HANGEUL_CHARSET = 129;
|
||||
const uint CHINESEBIG5_CHARSET = 136;
|
||||
const uint GB2312_CHARSET = 134;
|
||||
return charSet == SHIFTJIS_CHARSET || charSet == HANGEUL_CHARSET ||
|
||||
charSet == CHINESEBIG5_CHARSET || charSet == GB2312_CHARSET;
|
||||
}
|
||||
|
||||
private uint CodePageToCharSet()
|
||||
{
|
||||
CHARSETINFO csi;
|
||||
const uint TCI_SRCCODEPAGE = 2;
|
||||
const uint OEM_CHARSET = 255;
|
||||
if (!NativeMethods.TranslateCharsetInfo((IntPtr)_codePage, out csi, TCI_SRCCODEPAGE))
|
||||
{
|
||||
csi.ciCharset = OEM_CHARSET;
|
||||
}
|
||||
return csi.ciCharset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the output buffer code page is Japanese, Simplified Chinese, Korean, or Traditional Chinese
|
||||
/// </summary>
|
||||
/// <returns>true if it is CJK code page; otherwise, false.</returns>
|
||||
private bool IsCJKOutputCodePage()
|
||||
{
|
||||
return _codePage == 932 || // Japanese
|
||||
_codePage == 936 || // Simplified Chinese
|
||||
_codePage == 949 || // Korean
|
||||
_codePage == 950; // Traditional Chinese
|
||||
}
|
||||
|
||||
private bool IsAvailableFarEastCodePage()
|
||||
{
|
||||
uint charSet = CodePageToCharSet();
|
||||
return IsAnyDBCSCharSet(charSet);
|
||||
}
|
||||
|
||||
private int LengthInBufferCellsFE(char c)
|
||||
{
|
||||
if (0x20 <= c && c <= 0x7e)
|
||||
{
|
||||
/* ASCII */
|
||||
return 1;
|
||||
}
|
||||
else if (0x3041 <= c && c <= 0x3094)
|
||||
{
|
||||
/* Hiragana */
|
||||
return 2;
|
||||
}
|
||||
else if (0x30a1 <= c && c <= 0x30f6)
|
||||
{
|
||||
/* Katakana */
|
||||
return 2;
|
||||
}
|
||||
else if (0x3105 <= c && c <= 0x312c)
|
||||
{
|
||||
/* Bopomofo */
|
||||
return 2;
|
||||
}
|
||||
else if (0x3131 <= c && c <= 0x318e)
|
||||
{
|
||||
/* Hangul Elements */
|
||||
return 2;
|
||||
}
|
||||
else if (0xac00 <= c && c <= 0xd7a3)
|
||||
{
|
||||
/* Korean Hangul Syllables */
|
||||
return 2;
|
||||
}
|
||||
else if (0xff01 <= c && c <= 0xff5e)
|
||||
{
|
||||
/* Fullwidth ASCII variants */
|
||||
return 2;
|
||||
}
|
||||
else if (0xff61 <= c && c <= 0xff9f)
|
||||
{
|
||||
/* Halfwidth Katakana variants */
|
||||
return 1;
|
||||
}
|
||||
else if ((0xffa0 <= c && c <= 0xffbe) ||
|
||||
(0xffc2 <= c && c <= 0xffc7) ||
|
||||
(0xffca <= c && c <= 0xffcf) ||
|
||||
(0xffd2 <= c && c <= 0xffd7) ||
|
||||
(0xffda <= c && c <= 0xffdc))
|
||||
{
|
||||
/* Halfwidth Hangule variants */
|
||||
return 1;
|
||||
}
|
||||
else if (0xffe0 <= c && c <= 0xffe6)
|
||||
{
|
||||
/* Fullwidth symbol variants */
|
||||
return 2;
|
||||
}
|
||||
else if (0x4e00 <= c && c <= 0x9fa5)
|
||||
{
|
||||
/* Han Ideographic */
|
||||
return 2;
|
||||
}
|
||||
else if (0xf900 <= c && c <= 0xfa2d)
|
||||
{
|
||||
/* Han Compatibility Ideographs */
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unknown character: need to use GDI*/
|
||||
if (_hDC == (IntPtr)0)
|
||||
{
|
||||
_hwnd = NativeMethods.GetConsoleWindow();
|
||||
if ((IntPtr)0 == _hwnd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
_hDC = NativeMethods.GetDC(_hwnd);
|
||||
if ((IntPtr)0 == _hDC)
|
||||
{
|
||||
//Don't throw exception so that output can continue
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
bool result = true;
|
||||
if (!_istmInitialized)
|
||||
{
|
||||
result = NativeMethods.GetTextMetrics(_hDC, out _tm);
|
||||
if (!result)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
_istmInitialized = true;
|
||||
}
|
||||
int width;
|
||||
result = NativeMethods.GetCharWidth32(_hDC, (uint)c, (uint)c, out width);
|
||||
if (!result)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (width >= _tm.tmMaxCharWidth)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private COORD ConvertOffsetToCoordinates(int offset)
|
||||
{
|
||||
int x = _initialX;
|
||||
@@ -752,19 +546,15 @@ namespace Microsoft.PowerShell
|
||||
int j = startIndex;
|
||||
for (int i = 0; i < offset; i++)
|
||||
{
|
||||
char c = _buffer[i];
|
||||
if (_buffer[i] == '\n')
|
||||
var c = _buffer[i];
|
||||
if (c == '\n')
|
||||
{
|
||||
for (int k = 0; k < Options.ContinuationPrompt.Length; k++)
|
||||
{
|
||||
j++;
|
||||
}
|
||||
}
|
||||
else if (char.IsControl(_buffer[i]))
|
||||
{
|
||||
j += 2;
|
||||
}
|
||||
else if (LengthInBufferCells(_buffer[i]) > 1 && IsCJKOutputCodePage() && _trueTypeInUse)
|
||||
else if (LengthInBufferCells(c) > 1)
|
||||
{
|
||||
j += 2;
|
||||
}
|
||||
|
||||
@@ -237,6 +237,19 @@ namespace UnitTestPSReadLine
|
||||
Array.Copy(buffer, top * BufferWidth, result, 0, toCopy);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void StartRender()
|
||||
{
|
||||
}
|
||||
|
||||
public int LengthInBufferCells(char c)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void EndRender()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[TestClass]
|
||||
|
||||
Reference in New Issue
Block a user