Dela via


Rå strängliteral

Not

Den här artikeln är en funktionsspecifikation. Specifikationen fungerar som designdokument för funktionen. Den innehåller föreslagna specifikationsändringar, tillsammans med information som behövs under utformningen och utvecklingen av funktionen. Dessa artiklar publiceras tills de föreslagna specifikationsändringarna har slutförts och införlivats i den aktuella ECMA-specifikationen.

Det kan finnas vissa skillnader mellan funktionsspecifikationen och den slutförda implementeringen. Dessa skillnader fångas i de relevanta anteckningarna från Language Design Meeting (LDM) .

Du kan läsa mer om processen för att införa funktionsspecifikationer i C#-språkstandarden i artikeln om specifikationerna.

Champion-problem: https://github.com/dotnet/csharplang/issues/8647

Sammanfattning

Tillåt en ny form av strängliteral som börjar med minst tre """ tecken (men inget maxtecken), eventuellt följt av en new_line, innehållet i strängen och slutar sedan med samma antal citattecken som literalen började med. Till exempel:

var xml = """
          <element attr="content"/>
          """;

Eftersom det kapslade innehållet kanske vill använda """ kan start-/slutavgränsarna vara längre så här:

var xml = """"
          Ok to use """ here
          """";

För att göra texten lättläst och tillåta indrag som utvecklare gillar i kod tar dessa strängliteraler naturligt bort indraget som anges på den sista raden när du skapar det slutliga literalvärdet. Till exempel en literal av formuläret:

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
          """;

Kommer att innehålla:

<element attr="content">
  <body>
  </body>
</element>

Detta gör att koden kan se naturlig ut, samtidigt som den producerar önskade literaler och undviker körningskostnader om detta kräver användning av specialiserade strängmanipuleringsrutiner.

Om indragsbeteendet inte är önskvärt är det också trivialt att inaktivera så här:

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
""";

Ett formulär med en rad stöds också. Det börjar med minst tre """ tecken (men inte maximalt), innehållet i strängen (som inte får innehålla några new_line tecken) och slutar sedan med samma antal citattecken som literalen började med. Till exempel:

var xml = """<summary><element attr="content"/></summary>""";

Interpolerade råsträngar stöds också. I det här fallet anger strängen antalet klammerparenteser som behövs för att starta en interpolation (bestäms av antalet dollartecken som finns i början av literalen). En klammersekvens med färre klammer än så behandlas bara som innehåll. Till exempel:

var json = $$"""
             {
                "summary": "text",
                "length" : {{value.Length}},
             };
             """;

Motivation

C# saknar ett allmänt sätt att skapa enkla strängliteraler som effektivt kan innehålla valfri godtycklig text. Alla C#-strängliterala formulär behöver i dag någon form av undflyende om innehållet använder ett specialtecken (alltid om en avgränsare används). Detta förhindrar att det är enkelt att ha literaler som innehåller andra språk i dem (till exempel en XML-, HTML- eller JSON-literal).

Alla aktuella metoder för att bilda dessa literaler i C# tvingar i dag alltid användaren att manuellt undkomma innehållet. Redigering vid den tidpunkten kan vara mycket irriterande eftersom flykten inte kan undvikas och måste hanteras när det uppstår i innehållet. Detta är särskilt smärtsamt för regexes, särskilt när de innehåller citattecken eller omvänt snedstreck. Även med en ordagrann (@"") sträng måste citattecken själva escaperas, vilket resulterar i en blandning av C# och regex som blandas in. { och } är lika frustrerande i interpolerade ($"") strängar.

Kruxet med problemet är att alla våra strängar har en fast start/slut avgränsare. Så länge det är fallet måste vi alltid ha en flyktmekanism eftersom stränginnehållet kan behöva inkludera den slutliga avgränsaren i sitt innehåll. Detta är särskilt problematiskt eftersom avgränsare " är mycket vanligt på många språk.

För att åtgärda detta möjliggör det här förslaget flexibla start- och slutavgränsare så att de alltid kan göras på ett sätt som inte står i konflikt med innehållet i strängen.

Mål

  1. Ange en mekanism som gör att alla strängvärden tillhandahålls av användaren utan att användaren behöver några escape-sekvenser. Eftersom alla strängar måste kunna representeras utan escape-sekvenser måste det alltid vara möjligt för användaren att ange avgränsare som garanterat inte kolliderar med något textinnehåll.
  2. Stöd för interpoleringar på samma sätt. Som ovan, eftersom alla strängar måste representeras utan escapes, måste användaren alltid ha möjlighet att ange en interpolation avgränsare som garanterat inte kolliderar med något textinnehåll. Det är viktigt att språk som använder vår interpolation avgränsartecken ({ och }) ska kännas förstklassiga och inte smärtsamma att använda.
  3. Flerradssträngliteraler bör se trevliga ut i kod och bör inte göra att indrag i kompileringsenheten ser konstigt ut. Det är viktigt att literala värden som i sig inte har någon indragning inte ska tvingas att uppta den första kolumnen i filen eftersom det kan bryta upp kodflödet och ser ojusterat ut jämfört med resten av koden som omger den.
    • Det här beteendet bör vara enkelt att åsidosätta samtidigt som litterala uttryck är tydliga och lättlästa.
  4. För alla strängar som inte själva innehåller ett new_line eller börjar eller slutar med ett citattecken (") bör det vara möjligt att representera själva strängliteralen på en enda rad.
    • Valfritt, med ytterligare komplexitet, skulle vi kunna förfina detta för att ange att: För alla strängar som inte själva innehåller en new_line (men kan börja eller sluta med ett citattecken ") ska det vara möjligt att representera hela strängliteralen på en enda rad. Mer information finns i det utökade förslaget i avsnittet Drawbacks.

Detaljerad design (icke-interpoleringsfall)

Vi lägger till en ny string_literal-produktion med följande form.

string_literal
    : regular_string_literal
    | verbatim_string_literal
    | raw_string_literal
    ;

raw_string_literal
    : single_line_raw_string_literal
    | multi_line_raw_string_literal
    ;

raw_string_literal_delimiter
    : """
    | """"
    | """""
    | etc.
    ;

raw_content
    : not_new_line+
    ;

single_line_raw_string_literal
    : raw_string_literal_delimiter raw_content raw_string_literal_delimiter
    ;

multi_line_raw_string_literal
    : raw_string_literal_delimiter whitespace* new_line (raw_content | new_line)* new_line whitespace* raw_string_literal_delimiter
    ;

not_new_line
    : <any unicode character that is not new_line>
    ;

Slutavgränsaren till en raw_string_literal måste matcha den inledande avgränsaren. Så om startavgränsaren är """"" måste den avslutande avgränsare också vara det.

Grammatiken ovan för en raw_string_literal ska tolkas som:

  1. Den börjar med minst tre citattecken (men ingen övre gräns för citattecken).
  2. Den fortsätter sedan med innehållet på samma rad som startcitaten. Innehållet på samma rad kan vara tomt eller inte tomt. "blank" är synonymt med "helt tomt utrymme".
  3. Om innehållet på samma rad inte är tomt kan inget ytterligare innehåll följa. Med andra ord ska literalen sluta med samma antal citat på samma rad.
  4. Om innehållet på samma rad är tomt kan literalen fortsätta med en new_line och ett antal efterföljande innehållsrader och new_lines.
    • En innehållsrad är all text förutom en new_line.
    • Det avslutas sedan med ett new_line, ett antal (möjligen noll) av whitespace och samma antal citattecken som literalen började med.

Literalvärde för råsträng

Delarna mellan start och slut raw_string_literal_delimiter används för att bilda värdet för raw_string_literal på följande sätt:

  • I fallet med single_line_raw_string_literal kommer värdet av literalen exakt att vara innehållet mellan början och slutet av raw_string_literal_delimiter.
  • När det gäller multi_line_raw_string_literal, ingår den inledande whitespace* new_line och den sista new_line whitespace* inte i strängens värde. Den avslutande whitespace*-delen före raw_string_literal_delimiter-terminalen anses dock vara det 'blanksteg för indrag' och kommer att påverka hur de övriga raderna tolkas.
  • För att få fram det slutliga värdet genomgås sekvensen av (raw_content | new_line)* och följande utförs:
    • Om det är en new_line läggs innehållet i new_line till i det slutliga strängvärdet.
    • Om det inte är en "tom" raw_content (dvs. not_new_line+ innehåller ett icke-whitespace tecken):
      • tomt utrymme för indrag måste vara ett prefix för raw_content. Annars är det ett fel.
      • Indragningen av blankstecken tas bort från början av raw_content och den återstående delen läggs till i det slutliga strängvärdet.
    • Om det är en "tom" raw_content (dvs. not_new_line+ är helt whitespace):
      • blanksteget "indrag" måste vara ett prefix till raw_content eller så måste raw_content vara ett prefix till blanksteget "indrag". Annars är det ett fel.
      • så mycket av blanksteget "indrag" tas bort från början av raw_content och eventuella rester läggs till i det slutliga strängvärdet.

Förtydliganden:

  1. En single_line_raw_string_literal kan inte representera en sträng med ett new_line värde i den. En single_line_raw_string_literal deltar inte i trimningen av indragsutrymmet. Dess värde är alltid de exakta tecknen mellan start- och slutavgränsarna.

  2. Eftersom en multi_line_raw_string_literal ignorerar den sista new_line av den sista innehållsraden representerar följande en sträng utan start new_line och ingen avslutande new_line

var v1 = """
         This is the entire content of the string.
         """;

Detta upprätthåller symmetrin med hur start-new_line ignoreras, och det ger också ett enhetligt sätt att se till att "indragets blanksteg" alltid kan justeras. Om du vill representera en sträng med en terminal new_line måste en extra rad anges så här:

var v1 = """
         This string ends with a new line.

         """;
  1. En single_line_raw_string_literal kan inte representera ett strängvärde som börjar eller slutar med ett citattecken (") även om en förstoring av det här förslaget finns i avsnittet Drawbacks som visar hur det kan stödjas.

  2. En multi_line_raw_string_literal börjar med whitespace* new_line efter den första raw_string_literal_delimiter. Det här innehållet efter avgränsaren ignoreras helt och används inte på något sätt när värdet för strängen fastställs. På så sätt kan en mekanism ange en raw_string_literal vars innehåll börjar med ett " tecken. Till exempel:

var v1 = """
         "The content of this string starts with a quote
         """;
  1. En raw_string_literal kan också representera innehåll som slutar med ett citattecken ("). Detta stöds eftersom den avslutande avgränsaren måste vara på sin egen rad. Till exempel:
var v1 = """
         "The content of this string starts and ends with a quote"
         """;
var v1 = """
         ""The content of this string starts and ends with two quotes""
         """;
  1. Kravet att ett 'blankt' raw_content antingen måste vara ett prefix för 'indragets blanksteg' eller att 'indragets blanksteg' måste vara ett prefix för det, hjälper till att säkerställa att förvirrande scenarier med blandat blanksteg inte uppstår, särskilt eftersom det skulle vara oklart vad som ska ske med den raden. Följande fall är till exempel ogiltigt:
var v1 = """
         Start
<tab>
         End
         """;
  1. Här består "indragets blanksteg" av nio blankstegtecken, men "blank" raw_content börjar inte med detta som prefix. Det finns inget tydligt svar på hur den <tab> linjen ska behandlas alls. Ska den ignoreras? Ska det vara samma som .........<tab>? Att göra det olagligt verkar därför vara det tydligaste för att undvika förvirring.

  2. Följande fall är dock juridiska och representerar samma sträng:

var v1 = """
         Start
<four spaces>
         End
         """;
var v1 = """
         Start
<nine spaces>
         End
         """;

I båda dessa fall blir blanksteget "indrag" nio blanksteg. Och i båda fallen tar vi bort så mycket av prefixet som möjligt, vilket leder till att den tomma raw_content i varje fall är tom (räknar inte varje new_line). Detta gör att användarna inte behöver se och potentiellt oroa sig för blanksteg på dessa rader när de kopierar/klistrar in eller redigerar dessa rader.

  1. I fallet med:
var v1 = """
         Start
<ten spaces>
         End
         """;

Tomt utrymme för indrag är fortfarande nio blanksteg. Här tar vi dock bort så mycket av "indragsutrymmet" som möjligt, och "blank" raw_content kommer att bidra med ett enda mellanslag till det slutliga innehållet. Detta möjliggör fall där innehållet kräver blanksteg på dessa rader, som måste bevaras.

  1. Följande är tekniskt sett inte lagligt:
var v1 = """
         """;

Det beror på att början av den råa strängen måste ha en new_line (vilket den gör) men slutet måste också ha en new_line (vilket den inte har). Den minimala juridiska raw_string_literal är:

var v1 = """

         """;

Den här strängen är dock avgjort ointressant eftersom den motsvarar "".

Indragsexempel

Algoritmen 'indrag vitrymd' kan visualiseras för flera indata på följande sätt. I följande exempel används det lodräta stapeltecknet | för att illustrera den första kolumnen i den resulterande råsträngen:

Exempel 1 – Standardfall

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
          """;

tolkas som

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |</element>
           """;

Exempel 2 – Avsluta avgränsare på samma rad som innehåll.

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>""";

Det här är olagligt. Den sista innehållsraden måste sluta med en new_line.

Exempel 3 – Slutavgränsare före startavgränsare

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
""";

tolkas som

var xml = """
|          <element attr="content">
|            <body>
|            </body>
|          </element>
""";

Exempel 4 – Slutavgränsare efter startavgränsare

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
              """;

Det här är olagligt. Innehållsraderna måste börja med blanksteget "indrag"

Exempel 5 – Tom rad

var xml = """
          <element attr="content">
            <body>
            </body>

          </element>
          """;

tolkas som

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |
          |</element>
           """;

Exempel 6 – Tom linje med mindre blanksteg än prefix (punkter representerar blanksteg)

var xml = """
          <element attr="content">
            <body>
            </body>
....
          </element>
          """;

tolkas som

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |
          |</element>
           """;

Exempel 7 – Tom linje med mer blanksteg än prefix (punkter representerar blanksteg)

var xml = """
          <element attr="content">
            <body>
            </body>
..............
          </element>
          """;

tolkas som

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |....
          |</element>
           """;

Detaljerad design (fall för interpolation)

Interpoleringar i normala interpolerade strängar (t.ex. $"...") stöds idag genom användning av tecknet { för att initiera en interpolation och användningen av en {{ escape-sekvens för att infoga ett verkligt öppnande klammerparentestecken. Att använda samma mekanism skulle strida mot målen "1" och "2" i detta förslag. Språk som har { som ett kärntecken (exempel som JavaScript, JSON, Regex och till och med inbäddad C#) skulle nu behöva fly och ångra syftet med råa strängliteraler.

För att stödja interpoleringar introducerar vi dem på ett annat sätt än normalt $" interpolerade strängar. Mer specifikt börjar en interpolated_raw_string_literal med ett antal $ tecken. Antalet dessa anger hur många { (och }) tecken som behövs i innehållet i literalen för att avgränsa interpolation. Det är viktigt att det fortfarande inte finns någon escapeing-mekanism för klammerparenteser. I stället, precis som med citattecken (") kan själva literalen alltid se till att den anger avgränsare för interpoleringar som säkert inte kolliderar med något av resten av innehållet i strängen. Till exempel kan en JSON-literal som innehåller interpolationshål skrivas så här:

var v1 = $$"""
         {
            "orders": 
            [
                { "number": {{order_number}} }
            ]
         }
         """

Här matchar {{...}} det nödvändiga antalet av två klammerparenteser som anges av avgränsaren $$. När det gäller en enda $ innebär det att interpolationen anges precis som {...} som i normala interpolerade strängliteraler. Viktigt är att detta innebär att en interpolerad literal med N$ tecken kan ha en sekvens med 2*N-1 klammerparenteser (av samma typ i en rad). De sista N klammerparenteserna startar (eller avslutar) en interpolering, och de återstående N-1 klammerparenteserna kommer bara att utgöra innehåll. Till exempel:

var v1 = $$"""X{{{1+1}}}Z""";

I det här fallet tillhör de två inre {{ och }} klammerparenteser interpolationen, och de yttre enskilda klammerparenteserna utgör endast innehåll. Strängen ovan motsvarar därför innehållet X{2}Z. Att ha 2*N (eller fler) klammerparenteser är alltid ett fel. Om du vill ha längre sekvenser av klammerparenteser som innehåll måste antalet $ tecken ökas i enlighet med detta.

Interpolerade råsträngliteraler definieras som:

interpolated_raw_string_literal
    : single_line_interpolated_raw_string_literal
    | multi_line_interpolated_raw_string_literal
    ;

interpolated_raw_string_start
    : $
    | $$
    | $$$
    | etc.
    ;

interpolated_raw_string_literal_delimiter
    : interpolated_raw_string_start raw_string_literal_delimiter
    ;

single_line_interpolated_raw_string_literal
    : interpolated_raw_string_literal_delimiter interpolated_raw_content raw_string_literal_delimiter
    ;

multi_line_interpolated_raw_string_literal
    : interpolated_raw_string_literal_delimiter whitespace* new_line (interpolated_raw_content | new_line)* new_line whitespace* raw_string_literal_delimiter
    ;

interpolated_raw_content
    : (not_new_line | raw_interpolation)+
    ;

raw_interpolation
    : raw_interpolation_start interpolation raw_interpolation_end
    ;

raw_interpolation_start
    : {
    | {{
    | {{{
    | etc.
    ;

raw_interpolation_end
    : }
    | }}
    | }}}
    | etc.
    ;

Ovanstående liknar definitionen av raw_string_literal men med några viktiga skillnader. En interpolated_raw_string_literal ska tolkas som:

  1. Det börjar med minst ett dollartecken (men ingen övre gräns) och sedan tre citattecken (också utan övre gräns).
  2. Den fortsätter sedan med innehåll på samma rad som de inledande citattecknaderna. Innehållet på samma rad kan vara tomt eller inte tomt. "blank" är synonymt med "helt tomt utrymme".
  3. Om innehållet på samma rad inte är tomt kan inget ytterligare innehåll följa. Med andra ord ska literalen sluta med samma antal citat på samma rad.
  4. Om innehållet på samma rad är tomt kan literalen fortsätta med en new_line och ett antal efterföljande innehållsrader och new_lines.
    • En innehållsrad är all text förutom en new_line.
    • En innehållsrad kan innehålla flera raw_interpolation förekomster på valfri plats. raw_interpolation måste börja med lika många öppna klammerparenteser ({) som antalet dollartecken i början av literalen.
    • Om "blanksteg för indrag" inte är tomt kan en raw_interpolation inte omedelbart följa en new_line.
    • raw_interpolation följer de normala regler som anges i §12.8.3. Alla raw_interpolation måste sluta med samma antal slutna klammerparenteser (}) som dollartecken och öppna klammerparenteser.
    • Alla interpolation kan i sig innehålla nya rader på samma sätt som en interpolation i en normal verbatim_string_literal (@"").
    • Det avslutas sedan med ett new_line, ett antal (möjligen noll) av whitespace och samma antal citattecken som literalen började med.

Beräkningen av det interpolerade strängvärdet följer samma regler som en normal raw_string_literal förutom uppdaterad för att hantera rader som innehåller raw_interpolations. Att skapa strängvärdet sker på samma sätt, bara med interpoleringshålen ersatta med de värden som uttrycken producerar vid körning. Om interpolated_raw_string_literal konverteras till en FormattableString skickas värdena av interpolationerna i respektive ordning till arguments-matrisen till FormattableString.Create. Resten av innehållet i interpolated_raw_string_literalefter att "whitespace för indrag" har tagits bort från alla rader används för att generera format strängen som skickas till FormattableString.Create, förutom med lämpligt numrerat {N} innehåll på varje plats där en raw_interpolation inträffade (eller {N,constant} om dess interpolation är av formuläret expression ',' constant_expression).

Det finns en tvetydighet i specifikationen ovan. Specifikt när en del av { i text och { av en interpolation kommer i kontakt med varandra. Till exempel:

var v1 = $$"""
         {{{order_number}}}
         """

Detta kan tolkas som: {{ {order_number } }} eller { {{order_number}} }. Men eftersom det förstnämnda är olagligt (inget C#-uttryck kan börja med {) skulle det vara meningslöst att tolka på det sättet. Så vi tolkar på det senare sättet, där de innersta { och } klammerparenteser bildar interpolationen, och alla yttersta bildar texten. I framtiden kan detta vara ett problem om språket någonsin har stöd för uttryck som omges av klammerparenteser. I så fall skulle rekommendationen dock vara att skriva ett sådant ärende så här: {{({some_new_expression_form})}}. Här skulle parenteser hjälpa till att ange uttrycksdelen från resten av literalen/interpolationen. Detta har redan en överensstämmelse med hur ternära villkorsuttryck måste omslutas för att inte krocka med en interpolations formaterings-/justeringsspecifikation (t.ex. {(x ? y : z)}).

Nackdelar

Råsträngliteraler lägger till mer komplexitet i språket. Vi har redan många strängliterala formulär redan för många syften. "" strängar, @"" strängar och $"" strängar har redan mycket kraft och flexibilitet. Men de saknar alla ett sätt att tillhandahålla råinnehåll som aldrig behöver fly.

Ovanstående regler stöder inte fallet med 4.a:

  1. ...
    • Valfritt, med ytterligare komplexitet, skulle vi kunna förfina detta för att ange att: För alla strängar som inte själva innehåller en new_line (men kan börja eller sluta med ett citattecken ") ska det vara möjligt att representera hela strängliteralen på en enda rad.

Det beror på att vi inte har något sätt att veta att ett start- eller slutcitat (") ska tillhöra innehållet och inte själva avgränsare. Om det här är ett viktigt scenario som vi vill stödja kan vi lägga till en parallell '''-konstruktion för att motsvara """-formen. Med den parallella konstruktionen kan en enda radsträng som startar och slutar med " enkelt skrivas som '''"This string starts and ends with quotes"''' tillsammans med den parallella konstruktionen """'This string starts and ends with apostrophes'""". Detta kan också vara önskvärt att stödja för att visuellt separera citattecken, vilket kan vara till hjälp när du bäddar in språk som främst använder ett citattecken mycket mer än det andra.

Alternativ

https://github.com/dotnet/csharplang/discussions/89 omfattar många alternativ här. Alternativen är många, men jag tycker att de avviker för långt in på komplexitet och för dålig ergonomi. Den här metoden väljer enkelhet där du bara fortsätter att öka citatlängden för start/slut tills det inte finns någon risk för en konflikt med stränginnehållet. Det gör också att koden du skriver ser väl indragen ut, samtidigt som den producerar en avindragen bokstavlig representation som är vad de flesta koder föredrar.

En av de mest intressanta potentiella variationerna är dock användningen av ` (eller ```) avgränsare för dessa råsträngslitteraler. Detta skulle ha flera fördelar:

  1. Det skulle undvika alla problem med strängar som börjar eller slutar med citattecken.
  2. Det skulle se bekant ut som markdown. Även om det i sig inte är potentiellt bra eftersom användarna kan förvänta sig stöd för markdown.
  3. En rå strängliteral skulle bara behöva börja och sluta med ett enda tecken i de flesta fall, och skulle bara behöva flera i det mycket ovanligare fallet med innehåll som innehåller back-ticks själva.
  4. Det skulle kännas naturligt att utöka detta i framtiden med ```xml, likt markdown. Även om det naturligtvis också gäller för den """ formen.

På det hela taget verkar nettoförmånen här dock liten. I enlighet med C#-historiken tycker jag att " bör fortsätta att vara den string literal avgränsaren, precis som för @"" och $"".

Designa möten

Öppna problem för att diskutera Lösta problem:

  • [x] ska vi ha ett formulär med en rad? Vi skulle tekniskt sett klara oss utan det. Men det skulle innebära att enkla strängar som inte innehåller en ny rad alltid tar minst tre rader. Jag tycker att vi ska det är mycket tungviktare att tvinga enradskonstruktioner att vara tre linjer bara för att undvika att fly.

Designbeslut: Ja, vi kommer att ha ett formulär med en rad.

  • [x] ska vi kräva att flerrads-måste börja med en ny rad? Jag tycker att vi borde göra det. Det ger oss också möjlighet att stödja saker som """xml i framtiden.

Designbeslut: Ja, vi kommer kräva att flerradig text måste börja med en ny rad

  • [x] bör den automatiska dedenteringen göras överhuvudtaget? Jag tycker att vi borde göra det. Det gör att koden ser så mycket trevligare ut.

Designbeslut: Ja, automatisk indragning kommer att göras.

  • [x] bör vi begränsa common-whitespace från att blanda blankstegstyper? Jag tycker inte att vi ska göra det. Det finns faktiskt en gemensam indragsstrategi som kallas "tabb för indrag, mellanslag för justering". Det vore mycket naturligt att använda detta för att justera slutavgränsaren så att den stämmer överens med startavgränsaren i ett fall där startavgränsaren inte börjar vid ett tabbstopp.

Designbeslut: Vi kommer inte att ha några begränsningar för att blanda blanksteg.

  • [x] ska vi använda något annat för stängslen? ` skulle matcha markdown-syntaxen och skulle innebära att vi inte alltid behövde starta dessa strängar med tre citattecken. Bara en skulle räcka för det vanliga fallet.

Designbeslut: Vi använder """

  • [x] bör vi ha ett krav på att avgränsaren har fler citattecken än den längsta sekvensen med citattecken i strängvärdet? Tekniskt sett krävs det inte. till exempel:
var v = """
        contents"""""
        """

Det här är en sträng med """ som avgränsare. Flera communitymedlemmar har sagt att detta är förvirrande och vi bör kräva i ett fall som detta att avgränsare alltid har fler tecken. Det skulle då vara:

var v = """"""
        contents"""""
        """"""

Designbeslut: Ja, avgränsaren måste vara längre än någon sekvens med citattecken i själva strängen.