1. 22

I simplified the problem at hand greatly, to shorten the post, but if you have quicker solutions, I’d love to hear them!

  1. 10

    I couldn’t search and replace that trivially

    I love that you demonstrated how to use the quickfix list.

    But here’s how to trivially search and replace that string, for the curious:

    Step 1. match the string: /r#"[^#]*#/

    In English this says, Find (/) a string starting with r#", followed by anything that is not # ([^#]), as many times as you can (*) until you DO find find a #.

    Step 2. Search and replace: :%s/r#"\([^#]*\)#/json!(\1)/c

    This is :%s, a global search (more specifically a search with a range of %, which is the whole file), followed by the same search string from above with \( ... \) grouping added so we can remember the bit between the #s later. Then replace it with json!(\1) where \1 is the bit we remembered from \( ... \). Finally the trailing c stands for “confirm” and it will ask each time whether you want to perform the substitution.

    Then you can do an argdo or a buffdo, or otherwise find some way to run that in all buffers: :argdo norm! @:

    Tip: when crafting searches and commands, know that they are respectively saved to the / and : registers. So after performing a search, you can "/p to paste your search to a buffer to edit it. And you can @: to repeat a command. Anything you can do with registers and macros, you can do with the search and command registers.

    Tip: if you do a search, and then want to do a search and replace, instead of retyping the search again into :s/old/new (or typing :s/<c-r>//new as you just learned to do, since searches are saved in the search register) you can simply :s//new because the search and replace command will auto-insert the most recent search if the search term is omitted.

    1. 1

      The only reason I went with a macro was because I am not too familiar with regexes, would that work for strings that contain a # in them? something like r#"#room:matrix.org"#?

      Thank you for your detailed reply!

      1. 1

        No, it wouldn’t, but the general regex pattern for a delimited string that doesn’t contain it’s delimiters is:


        If your content (the stuff in [^<delimiter>] contains a delimiter, you have a pretty classic problem that regexes technically can’t solve (PCRE I think can, but technically those are more general than regular expressions proper, as I understand it).

        I think I would’ve also gone w/ the macro approach here, if only because it makes the process more interactive so I can selectively apply a re-usable edit. You can do similar w/ :s and & to do a substitution and then repeat that substitution, but doing a @@ and encoding the :next into the macro is also really nice, it leaves you with either hitting the @@ to apply or the :next to skip (in my case it’s @@ and C to apply/skip once I’ve recorded the macro).

        1. 1

          You’re welcome! I love vim and I love regex.

          With that added wrinkle, what my eye settles on is the final #) of the line from_str::<Action>(r#"{"set_tweak": "highlight"}"#),, and it feels like it’s even easier to match on that.

          Here’s a search: /r#".*#)/. This is finding a string starting with r#", followed by a bunch of anything (.*), followed by #). This will work for strings that contain a # in them.

          so your final search and replace should be something like this: :%s/r#"\(.*\)#)/json!(\1)/c

          I think I’d still go regex for this one. Although macros would obviously also do the trick just fine.

      2. 4

        Very useful, I didn’t know about arglists before. Also, calling !uniq to remove repeated imports is genius.

        1. 2

          I found some helpful hints in here, thank you!