zls icon indicating copy to clipboard operation
zls copied to clipboard

feat: Implement string literal conversion code actions

Open WillLillis opened this issue 1 year ago • 4 comments

This PR adds a few things:

  • A code action to convert string literals to multiline string literals (see https://github.com/zigtools/zls/issues/689#issuecomment-1349087990)
  • A code action to convert multiline string literals to string literals (same issue as above)
  • General instrumentation and testing for non-diagnostic driven code actions

The code actions make a best effort to make things work nicely with stuff like leading equals sign and trailing newlines, but it by no means produces correctly formatted code in many scenarios. I tried to base the instrumentation and testing code around what was already in the project, but I did have to make some a few guesses. Happy to rework/ refactor this if need be :)

WillLillis avatar Jun 24 '24 00:06 WillLillis

I have not yet taken a close look at the implementation but here are some cases that are incorrect:

const s1 = "\t";
const s2 = "\r";
const s3 =
    \\"
;
const s4 =
    \\\
;

I was able to fix the tab issue pretty readily, but ran into issues with the carriage return case. After some digging, I found https://github.com/ziglang/zig-spec/issues/38, which explicitly says that both carriage returns and tabs aren't allowed in multiline strings. However, a quick grep over the zig codebase says otherwise for tabs at least

Output
[lillis@DESKTOP-1H3O3N6] ~/projects/zig (master)
❯ grep -rnP --include \*.zig '\\\\.*[\t]+.*$' .                                                                                                                                           ⏎
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:306:            \\    <key>ProductBuildVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:307:            \\    <string>7W98</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:308:            \\    <key>ProductCopyright</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:309:            \\    <string>Apple Computer, Inc. 1983-2004</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:310:            \\    <key>ProductName</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:311:            \\    <string>Mac OS X</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:312:            \\    <key>ProductUserVisibleVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:313:            \\    <string>10.3.9</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:314:            \\    <key>ProductVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:315:            \\    <string>10.3.9</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:326:            \\    <key>ProductBuildVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:327:            \\    <string>19G68</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:328:            \\    <key>ProductCopyright</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:329:            \\    <string>1983-2020 Apple Inc.</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:330:            \\    <key>ProductName</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:331:            \\    <string>Mac OS X</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:332:            \\    <key>ProductUserVisibleVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:333:            \\    <string>10.15.6</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:334:            \\    <key>ProductVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:335:            \\    <string>10.15.6</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:336:            \\    <key>iOSSupportVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:337:            \\    <string>13.6</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:348:            \\    <key>ProductBuildVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:349:            \\    <string>20A2408</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:350:            \\    <key>ProductCopyright</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:351:            \\    <string>1983-2020 Apple Inc.</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:352:            \\    <key>ProductName</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:353:            \\    <string>macOS</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:354:            \\    <key>ProductUserVisibleVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:355:            \\    <string>11.0</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:356:            \\    <key>ProductVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:357:            \\    <string>11.0</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:358:            \\    <key>iOSSupportVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:359:            \\    <string>14.2</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:370:            \\    <key>ProductBuildVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:371:            \\    <string>20C63</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:372:            \\    <key>ProductCopyright</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:373:            \\    <string>1983-2020 Apple Inc.</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:374:            \\    <key>ProductName</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:375:            \\    <string>macOS</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:376:            \\    <key>ProductUserVisibleVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:377:            \\    <string>11.1</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:378:            \\    <key>ProductVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:379:            \\    <string>11.1</string>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:380:            \\    <key>iOSSupportVersion</key>
./zig-out/lib/zig/std/zig/system/darwin/macos.zig:381:            \\    <string>14.3</string>
./zig-out/lib/zig/std/zig/system/linux.zig:112:        \\processor      : 0
./zig-out/lib/zig/std/zig/system/linux.zig:113:        \\hart           : 1
./zig-out/lib/zig/std/zig/system/linux.zig:114:        \\isa            : rv64imafdc
./zig-out/lib/zig/std/zig/system/linux.zig:115:        \\mmu            : sv39
./zig-out/lib/zig/std/zig/system/linux.zig:117:        \\uarch          : sifive,u74-mc
./zig-out/lib/zig/std/zig/system/linux.zig:180:        \\processor      : 0
./zig-out/lib/zig/std/zig/system/linux.zig:181:        \\cpu            : PPC970MP, altivec supported
./zig-out/lib/zig/std/zig/system/linux.zig:182:        \\clock          : 1250.000000MHz
./zig-out/lib/zig/std/zig/system/linux.zig:183:        \\revision       : 1.1 (pvr 0044 0101)
./zig-out/lib/zig/std/zig/system/linux.zig:186:        \\processor      : 0
./zig-out/lib/zig/std/zig/system/linux.zig:187:        \\cpu            : POWER8 (raw), altivec supported
./zig-out/lib/zig/std/zig/system/linux.zig:188:        \\clock          : 2926.000000MHz
./zig-out/lib/zig/std/zig/system/linux.zig:189:        \\revision       : 2.0 (pvr 004d 0200)
./zig-out/lib/zig/std/zig/system/linux.zig:307:        \\processor      : 0
./zig-out/lib/zig/std/zig/system/linux.zig:308:        \\model name     : ARMv7 Processor rev 3 (v7l)
./zig-out/lib/zig/std/zig/system/linux.zig:309:        \\BogoMIPS       : 18.00
./zig-out/lib/zig/std/zig/system/linux.zig:310:        \\Features       : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
./zig-out/lib/zig/std/zig/system/linux.zig:311:        \\CPU implementer        : 0x41
./zig-out/lib/zig/std/zig/system/linux.zig:313:        \\CPU variant    : 0x0
./zig-out/lib/zig/std/zig/system/linux.zig:314:        \\CPU part       : 0xc07
./zig-out/lib/zig/std/zig/system/linux.zig:315:        \\CPU revision   : 3
./zig-out/lib/zig/std/zig/system/linux.zig:317:        \\processor      : 4
./zig-out/lib/zig/std/zig/system/linux.zig:318:        \\model name     : ARMv7 Processor rev 3 (v7l)
./zig-out/lib/zig/std/zig/system/linux.zig:319:        \\BogoMIPS       : 90.00
./zig-out/lib/zig/std/zig/system/linux.zig:320:        \\Features       : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
./zig-out/lib/zig/std/zig/system/linux.zig:321:        \\CPU implementer        : 0x41
./zig-out/lib/zig/std/zig/system/linux.zig:323:        \\CPU variant    : 0x2
./zig-out/lib/zig/std/zig/system/linux.zig:324:        \\CPU part       : 0xc0f
./zig-out/lib/zig/std/zig/system/linux.zig:325:        \\CPU revision   : 3
./zig-out/lib/zig/std/zig/tokenizer.zig:1554:        \\\\foo    bar
./zig-out/lib/zig/std/zig/tokenizer.zig:1562:        \\//foo    bar
./zig-out/lib/zig/std/zig/tokenizer.zig:1563:        \\//!foo   bar
./zig-out/lib/zig/std/zig/tokenizer.zig:1564:        \\///foo   bar
./zig-out/lib/zig/std/zig/tokenizer.zig:1565:        \\//       foo
./zig-out/lib/zig/std/zig/tokenizer.zig:1566:        \\///      foo
./zig-out/lib/zig/std/zig/tokenizer.zig:1567:        \\///      /foo
./test/translate_c.zig:136:        \\   typedef union {
./test/translate_c.zig:137:        \\           int A;
./test/translate_c.zig:138:        \\           int B;
./test/translate_c.zig:139:        \\           int C;
./test/translate_c.zig:140:        \\   } Foo;
./test/translate_c.zig:141:        \\   Foo a = {0};
./test/translate_c.zig:142:        \\   {
./test/translate_c.zig:143:        \\           typedef union {
./test/translate_c.zig:144:        \\                   int A;
./test/translate_c.zig:145:        \\                   int B;
./test/translate_c.zig:146:        \\                   int C;
./test/translate_c.zig:147:        \\           } Foo;
./test/translate_c.zig:148:        \\           Foo a = {0};
./test/translate_c.zig:149:        \\   }
./test/translate_c.zig:2046:        \\          case 5:
./test/translate_c.zig:2050:        \\                    return;
./test/translate_c.zig:2057:        \\                    return;
./test/run_translated_c.zig:29:        \\       struct foo tmp;
./test/run_translated_c.zig:33:        \\       struct foo tmp;
./test/run_translated_c.zig:37:        \\       bar();
./test/run_translated_c.zig:38:        \\       baz();
./test/run_translated_c.zig:39:        \\       return 0;
./test/run_translated_c.zig:56:        \\       foo(("bar"));
./lib/std/zig/system/darwin/macos.zig:306:            \\        <key>ProductBuildVersion</key>
./lib/std/zig/system/darwin/macos.zig:307:            \\        <string>7W98</string>
./lib/std/zig/system/darwin/macos.zig:308:            \\        <key>ProductCopyright</key>
./lib/std/zig/system/darwin/macos.zig:309:            \\        <string>Apple Computer, Inc. 1983-2004</string>
./lib/std/zig/system/darwin/macos.zig:310:            \\        <key>ProductName</key>
./lib/std/zig/system/darwin/macos.zig:311:            \\        <string>Mac OS X</string>
./lib/std/zig/system/darwin/macos.zig:312:            \\        <key>ProductUserVisibleVersion</key>
./lib/std/zig/system/darwin/macos.zig:313:            \\        <string>10.3.9</string>
./lib/std/zig/system/darwin/macos.zig:314:            \\        <key>ProductVersion</key>
./lib/std/zig/system/darwin/macos.zig:315:            \\        <string>10.3.9</string>
./lib/std/zig/system/darwin/macos.zig:326:            \\        <key>ProductBuildVersion</key>
./lib/std/zig/system/darwin/macos.zig:327:            \\        <string>19G68</string>
./lib/std/zig/system/darwin/macos.zig:328:            \\        <key>ProductCopyright</key>
./lib/std/zig/system/darwin/macos.zig:329:            \\        <string>1983-2020 Apple Inc.</string>
./lib/std/zig/system/darwin/macos.zig:330:            \\        <key>ProductName</key>
./lib/std/zig/system/darwin/macos.zig:331:            \\        <string>Mac OS X</string>
./lib/std/zig/system/darwin/macos.zig:332:            \\        <key>ProductUserVisibleVersion</key>
./lib/std/zig/system/darwin/macos.zig:333:            \\        <string>10.15.6</string>
./lib/std/zig/system/darwin/macos.zig:334:            \\        <key>ProductVersion</key>
./lib/std/zig/system/darwin/macos.zig:335:            \\        <string>10.15.6</string>
./lib/std/zig/system/darwin/macos.zig:336:            \\        <key>iOSSupportVersion</key>
./lib/std/zig/system/darwin/macos.zig:337:            \\        <string>13.6</string>
./lib/std/zig/system/darwin/macos.zig:348:            \\        <key>ProductBuildVersion</key>
./lib/std/zig/system/darwin/macos.zig:349:            \\        <string>20A2408</string>
./lib/std/zig/system/darwin/macos.zig:350:            \\        <key>ProductCopyright</key>
./lib/std/zig/system/darwin/macos.zig:351:            \\        <string>1983-2020 Apple Inc.</string>
./lib/std/zig/system/darwin/macos.zig:352:            \\        <key>ProductName</key>
./lib/std/zig/system/darwin/macos.zig:353:            \\        <string>macOS</string>
./lib/std/zig/system/darwin/macos.zig:354:            \\        <key>ProductUserVisibleVersion</key>
./lib/std/zig/system/darwin/macos.zig:355:            \\        <string>11.0</string>
./lib/std/zig/system/darwin/macos.zig:356:            \\        <key>ProductVersion</key>
./lib/std/zig/system/darwin/macos.zig:357:            \\        <string>11.0</string>
./lib/std/zig/system/darwin/macos.zig:358:            \\        <key>iOSSupportVersion</key>
./lib/std/zig/system/darwin/macos.zig:359:            \\        <string>14.2</string>
./lib/std/zig/system/darwin/macos.zig:370:            \\        <key>ProductBuildVersion</key>
./lib/std/zig/system/darwin/macos.zig:371:            \\        <string>20C63</string>
./lib/std/zig/system/darwin/macos.zig:372:            \\        <key>ProductCopyright</key>
./lib/std/zig/system/darwin/macos.zig:373:            \\        <string>1983-2020 Apple Inc.</string>
./lib/std/zig/system/darwin/macos.zig:374:            \\        <key>ProductName</key>
./lib/std/zig/system/darwin/macos.zig:375:            \\        <string>macOS</string>
./lib/std/zig/system/darwin/macos.zig:376:            \\        <key>ProductUserVisibleVersion</key>
./lib/std/zig/system/darwin/macos.zig:377:            \\        <string>11.1</string>
./lib/std/zig/system/darwin/macos.zig:378:            \\        <key>ProductVersion</key>
./lib/std/zig/system/darwin/macos.zig:379:            \\        <string>11.1</string>
./lib/std/zig/system/darwin/macos.zig:380:            \\        <key>iOSSupportVersion</key>
./lib/std/zig/system/darwin/macos.zig:381:            \\        <string>14.3</string>
./lib/std/zig/system/linux.zig:112:        \\processor  : 0
./lib/std/zig/system/linux.zig:113:        \\hart               : 1
./lib/std/zig/system/linux.zig:114:        \\isa                : rv64imafdc
./lib/std/zig/system/linux.zig:115:        \\mmu                : sv39
./lib/std/zig/system/linux.zig:117:        \\uarch              : sifive,u74-mc
./lib/std/zig/system/linux.zig:180:        \\processor  : 0
./lib/std/zig/system/linux.zig:181:        \\cpu                : PPC970MP, altivec supported
./lib/std/zig/system/linux.zig:182:        \\clock              : 1250.000000MHz
./lib/std/zig/system/linux.zig:183:        \\revision   : 1.1 (pvr 0044 0101)
./lib/std/zig/system/linux.zig:186:        \\processor  : 0
./lib/std/zig/system/linux.zig:187:        \\cpu                : POWER8 (raw), altivec supported
./lib/std/zig/system/linux.zig:188:        \\clock              : 2926.000000MHz
./lib/std/zig/system/linux.zig:189:        \\revision   : 2.0 (pvr 004d 0200)
./lib/std/zig/system/linux.zig:307:        \\processor  : 0
./lib/std/zig/system/linux.zig:308:        \\model name : ARMv7 Processor rev 3 (v7l)
./lib/std/zig/system/linux.zig:309:        \\BogoMIPS   : 18.00
./lib/std/zig/system/linux.zig:310:        \\Features   : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
./lib/std/zig/system/linux.zig:311:        \\CPU implementer    : 0x41
./lib/std/zig/system/linux.zig:313:        \\CPU variant        : 0x0
./lib/std/zig/system/linux.zig:314:        \\CPU part   : 0xc07
./lib/std/zig/system/linux.zig:315:        \\CPU revision       : 3
./lib/std/zig/system/linux.zig:317:        \\processor  : 4
./lib/std/zig/system/linux.zig:318:        \\model name : ARMv7 Processor rev 3 (v7l)
./lib/std/zig/system/linux.zig:319:        \\BogoMIPS   : 90.00
./lib/std/zig/system/linux.zig:320:        \\Features   : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
./lib/std/zig/system/linux.zig:321:        \\CPU implementer    : 0x41
./lib/std/zig/system/linux.zig:323:        \\CPU variant        : 0x2
./lib/std/zig/system/linux.zig:324:        \\CPU part   : 0xc0f
./lib/std/zig/system/linux.zig:325:        \\CPU revision       : 3
./lib/std/zig/tokenizer.zig:1554:        \\\\foo        bar
./lib/std/zig/tokenizer.zig:1562:        \\//foo        bar
./lib/std/zig/tokenizer.zig:1563:        \\//!foo       bar
./lib/std/zig/tokenizer.zig:1564:        \\///foo       bar
./lib/std/zig/tokenizer.zig:1565:        \\//   foo
./lib/std/zig/tokenizer.zig:1566:        \\///  foo
./lib/std/zig/tokenizer.zig:1567:        \\///  /foo
./src/link/tapi/yaml/test.zig:242:        \\are supported

I think a simple solution would be to just have the handler short circuit and not provide the code action if a carriage return is found. I've taken that approach for now.

I would suggest to take a look at the std.zig and std.zig.string_literal namespaces. There are some very useful functions there.

std.zig.string_literal.parseWrite and std.zig.stringEsacpe were incredibly helpful, thank you!

WillLillis avatar Jul 19 '24 21:07 WillLillis

Wanted to note that the expected outputs for a few of the added tests in here will have to be slightly modified if https://github.com/ziglang/zig/issues/19299 is accepted.

WillLillis avatar Jul 19 '24 22:07 WillLillis

You don't need to rebase your branches whenever a new commit is pushed to the master branch unless a conflict occured.

Techatrix avatar Jul 19 '24 22:07 Techatrix

You don't need to rebase your branches whenever a new commit is pushed to the master branch unless a conflict occured.

Sorry about that. Will hold off going forward 👍

WillLillis avatar Jul 19 '24 22:07 WillLillis

Superseded by #2097

WillLillis avatar Nov 30 '24 19:11 WillLillis