未验证 提交 3130e06c 编写于 作者: D dotnet bot 提交者: GitHub

Merge pull request #14466 from dotnet/merges/main-to-release/dev17.5

Merge main to release/dev17.5
......@@ -48,6 +48,13 @@ let newInfo () =
addZeros = false
precision = false}
let escapeDotnetFormatString str =
str
// We need to double '{' and '}', because even if they were escaped in the
// original string, extra curly braces were stripped away by the F# lexer.
|> Seq.collect (fun x -> if x = '{' || x = '}' then [x;x] else [x])
|> System.String.Concat
let parseFormatStringInternal
(m: range)
(fragRanges: range list)
......@@ -55,7 +62,7 @@ let parseFormatStringInternal
isInterpolated
isFormattableString
(context: FormatStringCheckContext option)
fmt
(fmt: string)
printerArgTy
printerResidueTy =
......@@ -86,6 +93,8 @@ let parseFormatStringInternal
// there are no accurate intra-string ranges available for exact error message locations within the string.
// The 'm' range passed as an input is however accurate and covers the whole string.
//
let escapeFormatStringEnabled = g.langVersion.SupportsFeature Features.LanguageFeature.EscapeDotnetFormattableStrings
let fmt, fragments =
//printfn "--------------------"
......@@ -175,7 +184,7 @@ let parseFormatStringInternal
| _ ->
// Don't muck with the fmt when there is no source code context to go get the original
// source code (i.e. when compiling or background checking)
fmt, [ (0, 1, m) ]
(if escapeFormatStringEnabled then escapeDotnetFormatString fmt else fmt), [ (0, 1, m) ]
let len = fmt.Length
......
......@@ -1662,3 +1662,4 @@ reprStateMachineInvalidForm,"The state machine has an unexpected form"
3548,matchNotAllowedForUnionCaseWithNoData,"Pattern discard is not allowed for union case that takes no data."
3549,tcSynTypeOrInvalidInDeclaration,"SynType.Or is not permitted in this declaration"
3550,chkDuplicatedMethodParameter,"Duplicate parameter. The parameter '%s' has been used more that once in this method."
featureEscapeBracesInFormattableString,"Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString"
\ No newline at end of file
......@@ -57,6 +57,7 @@ type LanguageFeature =
| MatchNotAllowedForUnionCaseWithNoData
| CSharpExtensionAttributeNotRequired
| ErrorForNonVirtualMembersOverrides
| EscapeDotnetFormattableStrings
| ArithmeticInLiterals
/// LanguageVersion management
......@@ -131,6 +132,7 @@ type LanguageVersion(versionText) =
LanguageFeature.MatchNotAllowedForUnionCaseWithNoData, previewVersion
LanguageFeature.CSharpExtensionAttributeNotRequired, previewVersion
LanguageFeature.ErrorForNonVirtualMembersOverrides, previewVersion
LanguageFeature.EscapeDotnetFormattableStrings, previewVersion
LanguageFeature.ArithmeticInLiterals, previewVersion
]
......@@ -242,6 +244,7 @@ type LanguageVersion(versionText) =
| LanguageFeature.MatchNotAllowedForUnionCaseWithNoData -> FSComp.SR.featureMatchNotAllowedForUnionCaseWithNoData ()
| LanguageFeature.CSharpExtensionAttributeNotRequired -> FSComp.SR.featureCSharpExtensionAttributeNotRequired ()
| LanguageFeature.ErrorForNonVirtualMembersOverrides -> FSComp.SR.featureErrorForNonVirtualMembersOverrides ()
| LanguageFeature.EscapeDotnetFormattableStrings -> FSComp.SR.featureEscapeBracesInFormattableString ()
| LanguageFeature.ArithmeticInLiterals -> FSComp.SR.featureArithmeticInLiterals ()
/// Get a version string associated with the given feature.
......
......@@ -47,6 +47,7 @@ type LanguageFeature =
| MatchNotAllowedForUnionCaseWithNoData
| CSharpExtensionAttributeNotRequired
| ErrorForNonVirtualMembersOverrides
| EscapeDotnetFormattableStrings
| ArithmeticInLiterals
/// LanguageVersion management
......
......@@ -192,6 +192,11 @@
<target state="translated">chyba při zastaralém přístupu konstruktoru s atributem RequireQualifiedAccess</target>
<note />
</trans-unit>
<trans-unit id="featureEscapeBracesInFormattableString">
<source>Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</source>
<target state="new">Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</target>
<note />
</trans-unit>
<trans-unit id="featureExpandedMeasurables">
<source>more types support units of measure</source>
<target state="translated">více typů podporuje měrné jednotky</target>
......
......@@ -192,6 +192,11 @@
<target state="translated">Beim veralteten Zugriff auf das Konstrukt mit dem RequireQualifiedAccess-Attribut wird ein Fehler ausgegeben.</target>
<note />
</trans-unit>
<trans-unit id="featureEscapeBracesInFormattableString">
<source>Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</source>
<target state="new">Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</target>
<note />
</trans-unit>
<trans-unit id="featureExpandedMeasurables">
<source>more types support units of measure</source>
<target state="translated">Maßeinheitenunterstützung durch weitere Typen</target>
......
......@@ -192,6 +192,11 @@
<target state="translated">error en el acceso en desuso de la construcción con el atributo RequireQualifiedAccess</target>
<note />
</trans-unit>
<trans-unit id="featureEscapeBracesInFormattableString">
<source>Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</source>
<target state="new">Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</target>
<note />
</trans-unit>
<trans-unit id="featureExpandedMeasurables">
<source>more types support units of measure</source>
<target state="translated">más tipos admiten las unidades de medida</target>
......
......@@ -192,6 +192,11 @@
<target state="translated">donner une erreur sur l’accès déconseillé de la construction avec l’attribut RequireQualifiedAccess</target>
<note />
</trans-unit>
<trans-unit id="featureEscapeBracesInFormattableString">
<source>Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</source>
<target state="new">Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</target>
<note />
</trans-unit>
<trans-unit id="featureExpandedMeasurables">
<source>more types support units of measure</source>
<target state="translated">d'autres types prennent en charge les unités de mesure</target>
......
......@@ -192,6 +192,11 @@
<target state="translated">errore durante l'accesso deprecato del costrutto con l'attributo RequireQualifiedAccess</target>
<note />
</trans-unit>
<trans-unit id="featureEscapeBracesInFormattableString">
<source>Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</source>
<target state="new">Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</target>
<note />
</trans-unit>
<trans-unit id="featureExpandedMeasurables">
<source>more types support units of measure</source>
<target state="translated">più tipi supportano le unità di misura</target>
......
......@@ -192,6 +192,11 @@
<target state="translated">RequireQualifiedAccess 属性を持つコンストラクトの非推奨アクセスでエラーが発生しました</target>
<note />
</trans-unit>
<trans-unit id="featureEscapeBracesInFormattableString">
<source>Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</source>
<target state="new">Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</target>
<note />
</trans-unit>
<trans-unit id="featureExpandedMeasurables">
<source>more types support units of measure</source>
<target state="translated">単位をサポートするその他の型</target>
......
......@@ -192,6 +192,11 @@
<target state="translated">RequireQualifiedAccess 특성을 사용하여 사용되지 않는 구문 액세스에 대한 오류 제공</target>
<note />
</trans-unit>
<trans-unit id="featureEscapeBracesInFormattableString">
<source>Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</source>
<target state="new">Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</target>
<note />
</trans-unit>
<trans-unit id="featureExpandedMeasurables">
<source>more types support units of measure</source>
<target state="translated">더 많은 형식이 측정 단위를 지원함</target>
......
......@@ -192,6 +192,11 @@
<target state="translated">wskazywanie błędu w przypadku przestarzałego dostępu do konstrukcji z atrybutem RequireQualifiedAccess</target>
<note />
</trans-unit>
<trans-unit id="featureEscapeBracesInFormattableString">
<source>Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</source>
<target state="new">Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</target>
<note />
</trans-unit>
<trans-unit id="featureExpandedMeasurables">
<source>more types support units of measure</source>
<target state="translated">więcej typów obsługuje jednostki miary</target>
......
......@@ -192,6 +192,11 @@
<target state="translated">fornecer erro no acesso preterido do constructo com o atributo RequireQualifiedAccess</target>
<note />
</trans-unit>
<trans-unit id="featureEscapeBracesInFormattableString">
<source>Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</source>
<target state="new">Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</target>
<note />
</trans-unit>
<trans-unit id="featureExpandedMeasurables">
<source>more types support units of measure</source>
<target state="translated">mais tipos dão suporte para unidades de medida</target>
......
......@@ -192,6 +192,11 @@
<target state="translated">выдать ошибку при устаревшем доступе к конструкции с атрибутом RequireQualifiedAccess</target>
<note />
</trans-unit>
<trans-unit id="featureEscapeBracesInFormattableString">
<source>Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</source>
<target state="new">Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</target>
<note />
</trans-unit>
<trans-unit id="featureExpandedMeasurables">
<source>more types support units of measure</source>
<target state="translated">другие типы поддерживают единицы измерения</target>
......
......@@ -192,6 +192,11 @@
<target state="translated">RequireQualifiedAccess özniteliğine sahip yapının kullanım dışı erişiminde hata</target>
<note />
</trans-unit>
<trans-unit id="featureEscapeBracesInFormattableString">
<source>Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</source>
<target state="new">Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</target>
<note />
</trans-unit>
<trans-unit id="featureExpandedMeasurables">
<source>more types support units of measure</source>
<target state="translated">tür daha ölçü birimlerini destekler</target>
......
......@@ -192,6 +192,11 @@
<target state="translated">对具有 RequireQualifiedAccess 属性的构造进行弃用的访问时出错</target>
<note />
</trans-unit>
<trans-unit id="featureEscapeBracesInFormattableString">
<source>Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</source>
<target state="new">Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</target>
<note />
</trans-unit>
<trans-unit id="featureExpandedMeasurables">
<source>more types support units of measure</source>
<target state="translated">更多类型支持度量单位</target>
......
......@@ -192,6 +192,11 @@
<target state="translated">對具有 RequireQualifiedAccess 屬性的建構的已取代存取發出錯誤</target>
<note />
</trans-unit>
<trans-unit id="featureEscapeBracesInFormattableString">
<source>Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</source>
<target state="new">Escapes curly braces before calling FormattableStringFactory.Create when interpolated string literal is typed as FormattableString</target>
<note />
</trans-unit>
<trans-unit id="featureExpandedMeasurables">
<source>more types support units of measure</source>
<target state="translated">更多支援測量單位的類型</target>
......
......@@ -104,6 +104,103 @@ module internal Utils =
| ' ', false -> nextWordFromIdx line (idx + 1, false)
| _, _ -> nextWordFromIdx line (idx + 1, true)
/// An array stores ranges of full-width chars.
///
/// The ranges are sorted by increasing order in the array, and each range are stored in the 2nth and 2n+1th
/// position in the array (n is the ordinal number of the range)
///
/// Array [| a; b; c; d |] represents range [a, b] or [c, d], means chars in these ranges are full-width.
///
/// Definition: https://www.unicode.org/reports/tr11/
///
/// Data source: https://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt
let private fullWidthCharRanges =
Array.concat
[|
[| '\u1100'; '\u115f' |]
[| '\u231a'; '\u231b' |]
[| '\u2329'; '\u232a' |]
[| '\u23e9'; '\u23ec' |]
[| '\u23f0'; '\u23f0' |]
[| '\u23f3'; '\u23f3' |]
[| '\u25fd'; '\u25fe' |]
[| '\u2614'; '\u2615' |]
[| '\u2648'; '\u2653' |]
[| '\u267f'; '\u267f' |]
[| '\u2693'; '\u2693' |]
[| '\u26a1'; '\u26a1' |]
[| '\u26aa'; '\u26ab' |]
[| '\u26bd'; '\u26be' |]
[| '\u26c4'; '\u26c5' |]
[| '\u26ce'; '\u26ce' |]
[| '\u26d4'; '\u26d4' |]
[| '\u26ea'; '\u26ea' |]
[| '\u26f2'; '\u26f3' |]
[| '\u26f5'; '\u26f5' |]
[| '\u26fa'; '\u26fa' |]
[| '\u26fd'; '\u26fd' |]
[| '\u2705'; '\u2705' |]
[| '\u270a'; '\u270b' |]
[| '\u2728'; '\u2728' |]
[| '\u274c'; '\u274c' |]
[| '\u274e'; '\u274e' |]
[| '\u2753'; '\u2755' |]
[| '\u2757'; '\u2757' |]
[| '\u2795'; '\u2797' |]
[| '\u27b0'; '\u27b0' |]
[| '\u27bf'; '\u27bf' |]
[| '\u2b1b'; '\u2b1c' |]
[| '\u2b50'; '\u2b50' |]
[| '\u2b55'; '\u2b55' |]
[| '\u2e80'; '\u303e' |]
[| '\u3041'; '\u3096' |]
[| '\u3099'; '\u30ff' |]
[| '\u3105'; '\u312f' |]
[| '\u3131'; '\u318e' |]
[| '\u3190'; '\u3247' |]
[| '\u3250'; '\u4dbf' |]
[| '\u4e00'; '\ua4c6' |]
[| '\ua960'; '\ua97c' |]
[| '\uac00'; '\ud7a3' |]
[| '\uf900'; '\ufaff' |]
[| '\ufe10'; '\ufe1f' |]
[| '\ufe30'; '\ufe6b' |]
[| '\uff01'; '\uff60' |]
[| '\uffe0'; '\uffe6' |]
|]
let isFullWidth (char) =
// for array [| a; b; c; d |],
// if a value is in (a, b) or (c, d), the result of Array.BinarySearch will be a negative even number
// if a value is a, b, c, d, the result will be a positive number
let n = Array.BinarySearch(fullWidthCharRanges, char)
n >= 0 || n % 2 = 0
/// Limits BufferWidth to make sure that full-width characters will not be print to wrong position.
///
/// The return value is Console.BufferWidth - 2.
///
/// When printing full-width characters to the screen (such as 一二三四五六七八九零),
///
/// if BufferWidth = Console.BufferWidth, the output will be
///
/// #> 一二三四五六七八九零一二三四五六七八九 # (零 is missing)
///
/// #一二三四五六七八九零 #
///
/// if BufferWidth = Console.BufferWidth - 1, the output will be
///
/// #> 一二三四五六七八九零一二三四五六七八九零# (零 is printed, but will not correctly cauculate cursor position)
///
/// #一二三四五六七八九零 # (cursor may appear in the middle of the character)
///
/// if BufferWidth = Console.BufferWidth - 2, the output will be
///
/// #> 一二三四五六七八九零一二三四五六七八九 #
///
/// #零一二三四五六七八九零 # (work correctly)
let bufferWidth () = Console.BufferWidth - 2
[<Sealed>]
type internal Cursor =
static member ResetTo(top, left) =
......@@ -111,14 +208,12 @@ type internal Cursor =
Console.CursorTop <- min top (Console.BufferHeight - 1)
Console.CursorLeft <- left)
static member Move(inset, delta) =
let position =
Console.CursorTop * (Console.BufferWidth - inset)
+ (Console.CursorLeft - inset)
+ delta
static member Move(delta) =
let width = Utils.bufferWidth ()
let position = Console.CursorTop * width + Console.CursorLeft + delta
let top = position / (Console.BufferWidth - inset)
let left = inset + position % (Console.BufferWidth - inset)
let top = position / width
let left = position % width
Cursor.ResetTo(top, left)
type internal Anchor =
......@@ -137,8 +232,11 @@ type internal Anchor =
member p.PlaceAt(inset, index) =
//printf "p.top = %d, p.left = %d, inset = %d, index = %d\n" p.top p.left inset index
let left = inset + (((p.left - inset) + index) % (Console.BufferWidth - inset))
let top = p.top + ((p.left - inset) + index) / (Console.BufferWidth - inset)
let width = Utils.bufferWidth ()
let index = inset + index
let left = index % width
let top = p.top + index / width
Cursor.ResetTo(top, left)
type internal ReadLineConsole() =
......@@ -209,7 +307,9 @@ type internal ReadLineConsole() =
| _ -> "^?"
member x.GetCharacterSize(c) =
if Char.IsControl(c) then x.MapCharacter(c).Length else 1
if Char.IsControl(c) then x.MapCharacter(c).Length
elif Utils.isFullWidth c then 2
else 1
static member TabSize = 4
......@@ -242,19 +342,21 @@ type internal ReadLineConsole() =
/// Cache of optionsCache
let mutable optionsCache = Options()
let moveCursorToNextLine c =
let charSize = x.GetCharacterSize(c)
if Console.CursorLeft + charSize > Utils.bufferWidth () then
if Console.CursorTop + 1 = Console.BufferHeight then
Console.BufferHeight <- Console.BufferHeight + 1
Cursor.Move(0)
let writeBlank () =
moveCursorToNextLine (' ')
Console.Write(' ')
checkLeftEdge false
let writeChar (c) =
if
Console.CursorTop = Console.BufferHeight - 1
&& Console.CursorLeft = Console.BufferWidth - 1
then
//printf "bottom right!\n"
anchor <- { anchor with top = (anchor).top - 1 }
checkLeftEdge true
moveCursorToNextLine (c)
if Char.IsControl(c) then
let s = x.MapCharacter c
......@@ -262,9 +364,7 @@ type internal ReadLineConsole() =
rendered <- rendered + s.Length
else
Console.Write(c)
rendered <- rendered + 1
checkLeftEdge true
rendered <- rendered + x.GetCharacterSize(c)
/// The console input buffer.
let input = new StringBuilder()
......@@ -273,25 +373,16 @@ type internal ReadLineConsole() =
let mutable current = 0
let render () =
//printf "render\n"
let curr = current
anchor.PlaceAt(x.Inset, 0)
let output = new StringBuilder()
let mutable position = -1
for i = 0 to input.Length - 1 do
if (i = curr) then
position <- output.Length
let c = input.Chars(i)
if (Char.IsControl c) then
output.Append(x.MapCharacter c) |> ignore
let rec getLineWidth state i =
if i = curr || i = input.Length then
state
else
output.Append(c) |> ignore
getLineWidth (state + x.GetCharacterSize(input.Chars i)) (i + 1)
if (curr = input.Length) then
position <- output.Length
let position = getLineWidth 0 0
// render the current text, computing a new value for "rendered"
let old_rendered = rendered
......@@ -326,13 +417,13 @@ type internal ReadLineConsole() =
if current > 0 && (current - 1 < input.Length) then
current <- current - 1
let c = input.Chars(current)
Cursor.Move(x.Inset, -x.GetCharacterSize c)
Cursor.Move(-x.GetCharacterSize c)
let moveRight () =
if current < input.Length then
let c = input.Chars(current)
current <- current + 1
Cursor.Move(x.Inset, x.GetCharacterSize c)
Cursor.Move(x.GetCharacterSize c)
let moveWordLeft () =
if current > 0 && (current - 1 < input.Length) then
......
......@@ -32,8 +32,19 @@ let c: System.IFormattable = $"string"
|> compile
|> shouldSucceed
[<Fact>]
let ``Interpolated string literal typed as FormattableString handles double braces correctly`` () =
Fsx """
let a = $"{{hello}} world" : System.FormattableString
printf $"{a.Format}"
"""
|> withLangVersionPreview
|> compileExeAndRun
|> shouldSucceed
|> withStdOutContains "{{hello}} world"
[<Fact>]
let ``Percent sign characters in interpolated strings`` () =
Assert.Equal("%", $"%%")
Assert.Equal("42%", $"{42}%%")
Assert.Equal("% 42", $"%%%3d{42}")
\ No newline at end of file
Assert.Equal("% 42", $"%%%3d{42}")
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册