Skip to content

multi_pass for non-scoped replacements for commands with multiple steps #116

Open

Description

@God-damnit-all

What I would like:

  {
    "caption": "Regex: My Non-Scoped Replacements",
    "command": "reg_replace",
    "args": { "replacements": ["step1_singlepass", "step2_multipass", "step3_singlepass"] }
  }

Steps 1 and 3 are assumed to meant to be a single-pass and Step 2 is assumed to be multi-pass. However, unless you're targeting a scope, this doesn't work because multi_pass on a replacement requires scope to be defined.

And if you do:

  {
    "caption": "Regex: My Non-Scoped Replacements",
    "command": "reg_replace",
    "args": { "replacements": ["step1_singlepass", "step2_multipass", "step3_singlepass"], "multi_pass": true }
  }

... this makes Step 1 and Step 3 multi-pass, which will mess up my operation.

Right now, I have to split this into 3 separate commands or do something more complicated.

If you could allow multi_pass to be definable for all replacements, that'd be great.

As for how it would work when using the command-level multi_pass, maybe make it so if it's defined in replacements, it will override whatever it's set to. So, you could define multi_pass: false to make it so a replacement in a command that uses multi_pass: true only runs a single pass. Or, I guess you could do it the other way around where the command-level multi_pass takes precedence, though I think that wouldn't be as useful.

Activity

  1. facelessuser commented on Apr 13, 2026

    @facelessuser
    Owner

    I'll have to think about this. Have you considered pairing this with plugins that chain multiple commands together?

    If I were to consider this, I think it would be good to provide a real-world example that can be used to test such functionality.

  2. God-damnit-all commented on Apr 14, 2026

    @God-damnit-all
    Author

    Have you considered pairing this with plugins that chain multiple commands together?

    Didn't know there was one.

    I think it would be good to provide a real-world example that can be used to test such functionality.

    I'm reformatting documents related to health coverage to optimize how effective LLMs are at reviewing it and I'm afraid I can't really share any of it since it's related to legal proceedings, but the most common case is situations where one might normally use a repeating group (e.g. ( (?:\w))+ in a b c d e) BUT without losing the value of each time the group is captured (e.g. ( (?:\w)) configured as a multi-pass with the replacement value being, let's say, _\1).

    And, in other cases, I'm finding it far more performant to do multiple passes of a more basic regex than to rely on lookahead and lookbehinds. This is due in no small part due to the staggering size of these documents making lookahead and lookbehind grossly inefficient.

    It's a bit stressful trying to articulate the specifics of why I need multi-pass for certain steps without showing you the documents in question (this involves an ongoing case), as it makes it hard to overcome the XY problem.

    I would appreciate it if you could recommend me a plugin that does what you describe. I'm sure I could find one on my own, but a lot of Sublime Text plugins are just buggy and I generally don't figure that out until wasting a lot of time learning how they work. Having something you could vouch for would be nice.

    Though I do think it makes sense to allow per-replacement multi-step in RegReplace regardless, considering Regex's limitations when trying to use it as a pseudo-parser for conditional replacement operations.

  3. facelessuser commented on Apr 14, 2026

    @facelessuser
    Owner

    I would appreciate it if you could recommend me a plugin that does what you describe.

    Assuming it still works: https://packagecontrol.io/packages/Chain%20of%20Command. I'll leave it to you to find an alternative if it doesn't.

    It's a bit stressful trying to articulate the specifics of why I need multi-pass for certain steps without showing you the documents in question (this involves an ongoing case), as it makes it hard to overcome the XY problem.

    Due to the way I use the tool, I haven't really run into this issue, but that isn't to say such situations don't exist. My request is simply a toy example that allows us to apply new logic and verify that we are doing what you hope. The converse is that you are asking me to come up with this case, which, as stated earlier, I haven't really run into.

    Keep in mind, regular expressions are best used for regular cases. It's possible you have a case that is truly best served with some conditional/advanced logic. We allow for users to write custom plugins for such cases: https://facelessuser.github.io/RegReplace/usage/?h=plugins#custom-replace-plugins. I understand that there are people who may not want to go this route, but that is why we added such options.

    Sure, I can just try and add the functionality, but having a real-world example to test against helps improve my motivation as it gives me something to test against instead of me having to come up with some kind of contrived example.

  4. facelessuser commented on Apr 14, 2026

    @facelessuser
    Owner

    I'm reformatting documents related to health coverage to optimize how effective LLMs are at reviewing it and I'm afraid I can't really share any of it since it's related to legal proceedings, but the most common case is situations where one might normally use a repeating group (e.g. ( (?:\w))+ in a b c d e) BUT without losing the value of each time the group is captured (e.g. ( (?:\w)) configured as a multi-pass with the replacement value being, let's say, _\1).

    I'm having a difficult time understanding this use case. Keep in mind, I'm not asking you to provide me with sensitive information. If you can just provide input patterns and input text for a made-up case that is similar (even if it is nonsense), it would definitely be helpful. The expected output should be clear as well.

  5. God-damnit-all commented on Apr 14, 2026

    @God-damnit-all
    Author

    Assuming it still works: https://packagecontrol.io/packages/Chain%20of%20Command. I'll leave it to you to find an alternative if it doesn't.

    Thanks. If I come up with a more conventional use-case I'll stop by again.

  6. added
    P: maybePending approval of low priority request.
    and removed
    S: triageIssue needs triage.
    on Apr 28, 2026
  7. God-damnit-all commented on May 20, 2026

    @God-damnit-all
    Author

    The good news:

    Chain of Command is no longer needed because Sublime Text 4 has a built in "chain" command: https://docs.sublimetext.io/reference/commands.html#chain

    The bad news:

    Both Chain of Command and the built-in "chain" command only work with WindowCommand-typed commands, and RegReplace seems to be a TextCommand. See: https://forum.sublimetext.com/t/subllime-4-built-in-chain-command-fail/77436

  8. facelessuser commented on May 21, 2026

    @facelessuser
    Owner

    I'm sure we could create a simple Text based one, but it would be really helpful to see a simple, minimal example so we could make sure the way in which we would want to chain even makes sense.

  9. God-damnit-all commented on May 21, 2026

    @God-damnit-all
    Author

    I'm sure we could create a simple Text based one, but it would be really helpful to see a simple, minimal example so we could make sure the way in which we would want to chain even makes sense.

    Okay... I wanted to reformat the Markdown that is provided when you use the copy button on https://google.com/ai

    It seems to use a Markdown flavor that considers [1, 2, 3] to work for reference linking, which is always placed at the end of a line.

    The backreference URL syntax it uses is odd too, where you could have it look like this:

    [1] [https://example.com](https://example.com/here-is-a-page/)
    [2] [https://example.com](https://example.com/foo/)
    [3] [https://foobar.com](https://foobar.com/loremipsum.txt)
    

    So I would need to not only morph the backreferences it provides at the end to this:

    [1]: https://example.com/here-is-a-page/
    [2]: https://example.com/foo/
    [3]: https://foobar.com/loremipsum.txt
    

    But I would also need to alter [1, 2, 3] to [1] [2] [3].

    For the backreference URLs, that can be done in a single pass:

        "google_md_fix_1": {
          "find": "^(\\[\\d{1,2}\\]) \\[.*?\\]\\((.*)\\) *$",
          "replace": "\\1: \\2",
          "greedy": true,
        },

    But [1, 2, 3], since that can be any amount of numbers, would either require some complicated lookarounds or a much safer, faster, and simpler multi-pass:

        "google_md_fix_2": {
          "find": "\\[(\\d{1,2}), ((?:\\d{1,2}(?:, )?)+\\]) *$",
          "replace": "[\\1] [\\2",
          "greedy": true,
          "multi_pass": true,
        },

    (I'm aware the "multi_pass": true, line in this currently does nothing)

    This is what I tried, based on the official ST4 documentation I linked above for the "chain" command, and sadly it didn't work:

      {
        "caption": "Regex: Fix Google AI Markdown",
        "command": "chain", 
        "args": {
          "commands": [
            {"command": "reg_replace", "args": {"replacements": "google_md_fix_1"}},
            {"command": "reg_replace", "args": {"replacements": "google_md_fix_2", "multi_pass": true}},
          ]
        }
      },

    No console messages or anything.

    Here is an example input:

    test [1, 2, 3]
    
    [1] [https://example.com](https://example.com/here-is-a-page/)
    [2] [https://example.com](https://example.com/foo/)
    [3] [https://foobar.com](https://foobar.com/loremipsum.txt)
    

    And the desired output:

    test [1] [2] [3]
    
    [1]: https://example.com/here-is-a-page/
    [2]: https://example.com/foo/
    [3]: https://foobar.com/loremipsum.txt
    
  10. God-damnit-all commented on May 21, 2026

    @God-damnit-all
    Author

    Also, I do know I could've just marked the whole operation as multi_pass so that it would do multi_pass for every single replacement, but it would take a far more complicated example to show when multi_pass on every single step would be potentially destructive.

  11. God-damnit-all commented on Jul 18, 2026

    @God-damnit-all
    Author

    Was that example good enough to pass the smell test?

  12. facelessuser commented on Jul 18, 2026

    @facelessuser
    Owner

    I think so, I just got derailed with other things, like security vulnerabilities on other projects due to everyone running every project through AI...

  13. self-assigned this
    on Jul 27, 2026
  14. facelessuser commented on Jul 28, 2026

    @facelessuser
    Owner

    Sorry it took so long for me to get around to this, but I've added a simple chain command in PR #117.

    You're example was helpful. In the future, you should be able to do something like this:

        {
            "caption": "Reg Replace: Issue 116",
            "command": "reg_replace_chain",
            "args": {
                "commands": [
                    {"command": "reg_replace", "replacements": ["google_md_fix_1"]},
                    {"command": "reg_replace", "replacements": ["google_md_fix_2"], "multi_pass": true}
                ]
            }
        }
  15. facelessuser commented on Jul 28, 2026

    @facelessuser
    Owner

    Chains probably work fine for replacement, but I probably do need to run this through some other scenarios. I may have to alter the approach... It at least works for your case, but I might need a deeper integration to allow for other things. I'll look into it a bit more before pulling the trigger.

  16. God-damnit-all commented on Jul 28, 2026

    @God-damnit-all
    Author

    Chains probably work fine for replacement, but I probably do need to run this through some other scenarios. I may have to alter the approach... It at least works for your case, but I might need a deeper integration to allow for other things. I'll look into it a bit more before pulling the trigger.

    What did you have in mind?

  17. facelessuser commented on Jul 29, 2026

    @facelessuser
    Owner

    Well, I need to play with it. What I've provided works fine for your use case, an automated find and replace, but probably doesn't work with some of the other features, like highlighting finds and then prompting if the user wants to replace. The more I think about it, it should do all the looping in one command in order to work with other features.

    You can easily grab the current chain command from the PR and drop it in a script in your User folder, and it should work fine for what you were doing; I just probably need something more thorough for a final solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P: maybePending approval of low priority request.T: featureFeature.

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions