Sublime Forum

RegReplace Plugin

#1

[size=150]About[/size]
Reg Replace is a plugin for Sublime Text 2 that allows the creating of commands consisting of sequences of find and replace instructions.

[size=150]Installation[/size]

  • Use Package Control to install
  • Or you can download or clone directly and drop into your Sublime Text 2 packages directory (plugin folder must be named RegReplace)

[size=150]Usage[/size]
[size=150]Create Find and Replace Sequences[/size]
To use, replacements must be defined in the reg_replace.sublime-settings file.

There are two kinds of definitions. The first uses regex to find regions, and then you can use scopes to qualify the regions before applying the replace.

// Required parameters: // find: Regex description of what you would like to target. // // Optional parameters: // replace: description of what you would like to replace target with. // Variables are okay for non-literal searches and are done by escaping // the selection number \\1 etc. Default value is "" (empty string) // literal: Boolean setting to define whether the find and replace is literal or not. // Default is false. // greedy: Boolean setting to define whether search is greedy or not. Default is true. // case: Boolean defining case sensitivity. True equals sensitive. Defualt is true. // scope_filter: an array of scope qualifiers for the match. // - Any instance of scope qualifies match: scope.name // - Entire match of scope qualifies match: !scope.name // - Any instance of scope disqualifies match: -scope.name // - Entire match of scope disqualifies match: -!scope.name { "replacements": { // Example replacements "html5_remove_deprecated_type_attr": { "find": "(<(style|script)^>]*)\\stype=(\"|')text/(css|javascript)(\"|')(^>]*>)", "replace": "\\1\\6", "greedy": true, "case": false },

The second kind of definition allows you to search for a scope type and then apply regex to the regions to filter the matches and make replaces.

// Required parameters: // scope: scope you would like to target // // Optional parameters: // find: regex description that is to be applied to the scope // to qualify. Also can be used to find and replace // within the found scope. Default is None. // replace: description of what you would like to replace within the scope. // Default value is "\\0". // literal: Boolean setting to define whether the find and replace is literal or not. // Default is false. // greedy_replace: Boolean setting to define whether regex search is greedy or not. Default is true. // greedy_scope: Boolean setting to define whether scope search is greedy or not. Default is true. // case: Boolean setting to define whether regex search is case sensitive. Default is true. // multi_pass_regex:Boolean setting to define whether there will be multiple sweeps on the scope region // region to find and replace all instances of the regex, when regex cannot be formatted // to find all instances in a greedy fashion. Default is false. { "replacements": { "remove_comments": { "scope": "comment", "find" : "((^\\n\\r]*)(\\r\\n|\\n))*(^\\n\\r]+)", "replace": "", "greedy_replace": true }

Once you have replacements defined, there are a number of ways you can run a sequence. One way is to create a command in the command palette by editing/creating a Default.sublime-commands in your User folder and adding your command. RegReplace comes with its own Default.sublime-commands file and includes some examples showing simple replacement commands and an example showing the chaining of multiple replacements.

{ "caption": "Reg Replace: Remove Trailing Spaces", "command": "reg_replace", "args": {"replacements": "remove_trailing_spaces"]} }, // Chained replacements in one command { "caption": "Reg Replace: Remove HTML Comments and Trailing Spaces", "command": "reg_replace", "args": {"replacements": "remove_html_comments", "remove_trailing_spaces"]} }

You can also bind a replacement command to a shortcut.

{ "keys": "ctrl+shift+t"], "command": "reg_replace", "args": {"replacements": "remove_trailing_spaces"]} }

[size=150]View Without Replacing[/size]
If you would simply like to view what the sequence would find without replacing, you can construct a command to highlight targets without replacing them (each pass could affect the end result, but this just shows all passes without predicting replaces).

Just add the find_only argument and set it to true.

{ "caption": "Reg Replace: Remove Trailing Spaces", "command": "reg_replace", "args": {"replacements": "remove_trailing_spaces"], "find_only": true} },

A prompt will appear allowing you to replace the highlighted regions. Regions will be cleared on cancel.

If for any reason the highlights do not get cleared, you can simply run the RegReplace: Clear Highlights command from the command palette.

Highlight color and style can be changed in the settings file.

[size=150]Override Actions[/size]
If instead of replacing you would like to do something else, you can override the action. Actions are defined in commands by setting the action parameter. Some actions may require additional parameters be set in the options parameter. See examples below.

{ "caption": "Reg Replace: Fold HTML Comments", "command": "reg_replace", "args": {"replacements": "remove_html_comments"], "action": "fold"} }, { "caption": "Reg Replace: Unfold HTML Comments", "command": "reg_replace", "args": {"replacements": "remove_html_comments"], "action": "unfold"} }, { "caption": "Reg Replace: Mark Example", "command": "reg_replace", "args": { "replacements": "example"], "action": "mark", "options": {"key": "name", "scope": "invalid", "underline"} } }, { "caption": "Reg Replace: Unmark Example", "command": "reg_replace", "args": { "action": "unmark", "options": {"key": "name"} } },

[size=150]Supported override actions:[/size]

  • fold
  • unfold
  • mark
  • unmark

[size=150]Fold Override[/size]
action = fold

This action overides the folds the given find target. This action has no parameters.

[size=150]Unfold Override[/size]
action = unfold

This action unfolds the all regions that match the given find target. This action has no parameters

[size=150]Mark Override[/size]
action = mark

This action highlights the regions of the given find target.

Required Parameters:

  • key = unique name for highlighted regions

Optional Parameters:

  • scope = scope name to use as the color. Default is invalid
  • style = highlight style (solid|underline|outline). Default is outline.

Input Sequencer order:

  • mark=key,scope,style:replacements

[size=150]Unmark Override[/size]
action = unmark

This action removes the highlights of a given key. Replacements can be ommitted with this com####mand.

Required Parameters:

  • key = unique name of highlighted regions to clear

Input Sequencer order:

  • unmark=key,scope,style: (replacements do not need to be defined)

[size=150]Multi-Pass[/size]
Sometimes a regular expression cannot be made to find all instances in one pass. In this case, you can use the multi-pass option.

Multi-pass cannot be paired with override actions (it will be ignored), but it can be paired with find_only. Multi-pass will sweep the file repeatedly until all instances are found and replaced. To protect against poorly constructed mult-pass regex looping forever, there is a default max sweep threshold that will cause the sequence to kick out if it is reached. This threshold can be tweaked in the settings file.

{ "caption": "Reg Replace: Remove Trailing Spaces", "command": "reg_replace", "args": {"replacements": "example"], "multi_pass": true} },

[size=150]Regex Input Sequencer[/size]
If you haven’t created a command yet, but you want to quickly run a sequence, you can search for Reg Replace: RegEx Input Sequencer in the command palette and launch an input panel where you can enter the name of replacements separated by commas and press enter.

If you only want to highlight the searches and not replace them, precede the sequence with ?:. This will highlight the regions it can find to give you an idea of what regions will be targeted. Afterwards, a panel will pop up allowing you to replace if you choose.

Also you can override the replace action with other actions like “fold” or “unfold” were the action precedes the sequence fold:. If you would like to highlight the selections only and then optionally perform the replace/action, you can precede the sequence like this ?fold:.

Some actions might have parameters. In this case, you can follow the actions with an equal sign and the paramters separated by commas. mark=key,string,outline:. If some parameters are optional, you can leave them out: ?mark=key,string or ?mark=key,outline:. The important thing is that the parameters are in the order outlined by the command.

If multiple sweeps are needed to find and replace all targets, you can use multi-pass (explained later) using +:. Multi-pass cannot be used with action overrides, but it can be used with highlighting searches ?+:.

[size=150]Source Code[/size]
github.com/facelessuser/RegRepl … all/master

[size=150]License[/size]

Reg Replace is released under the MIT license.

Copyright © 2011 Isaac Muse isaacmuse@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

[size=150]Changelog[/size]

Version 1.2.1

  • Account for people still on the last offical beta since view.folded_regions() is not included in that release. This method of unfold will be deprecated on new ST2 offical beta release.

Version 1.2

  • Added support for new API command view.unfold([regions]); old method is a fallback for official beta and will be deprecated on new ST2 official beta release

Version 1.1

  • Faster unfold when many regions to unfold

Version 1.0

  • Add “literal” param for scope search defines.
  • Reduce code complexity

Version 0.9

  • Allow multipass on a scope region with regex with new “multi_pass_regex” parameter

Version 0.8

  • New “mark” and “unmark” actions
  • Return error dialog showing regex issue
  • Add support for scope search with regex find and replace in scope region
  • Smarter folding of regex regions for “fold” action
  • Small tweak to non-greedy algorithm
  • Change default of optional replace parameter to “\\0”; do not delete by default, leave unchanged by default.
  • Allow spaces in the “Regex Input Sequencer”

Version 0.7

  • Replace command examples now commented out by default
  • RegReplace Commands and Settings now available via preference menu and command palette

Version 0.6

  • Add multi-pass sweeps
  • Report bad actions

Version 0.5

  • Make replace an optional parameter defaulted to “” (empty string)
  • Allow override actions to be used instead of replace: fold and unfold

Version 0.4

  • Add support for “literal” boolean parameter for literal find and replaces
  • Allow the Regex Input Sequencer panel to highlight only by preceding the sequence with “?:”

Version 0.3

  • Allow option for highlighting find targets without replacing. Show prompt for replacing after highlighting.
  • Add clear command to allow clearing of all highlights if for any reason view loses focus and highlights aren’t cleared on cancel.

Version 0.2

  • “greedy” and “case” parameters are now optional and set to “true” by default

Version 0.1

  • Initial release
2 Likes

How to save a find/replace pair as a command?
#2

If you have any suggestions, comments, or bugs, let me know. Also, if you have some good regex tasks that you think people in general would find useful, post them here and I may put them in the plugin by default.

0 Likes

#3

I have a suggestion. Make “greedy” and “case” optional parameters, too (and just give them a default value).

0 Likes

#4

I actually meant to do that, but then got side tracked. I will go ahead and do that before I forget again :smile:.

**Edit: ** Done

0 Likes

#5

New feature added:

If you would simply like to view what the sequence would fine without replacing, you can construct a command to highlight targets without replacing them (each pass could affect the end result, but this just shows all passes without predicting replaces).

Just add the “find_only” argument and set it to true.

{ "caption": "Reg Replace: Remove Trailing Spaces", "command": "reg_replace", "args": {"replacements": "remove_trailing_spaces"], "find_only": true} },

A prompt will appear allowing you to replace the highlighted regions. Regions will be cleared on cancel.

If for any reason the highlights do not get cleared, you can simply run the “RegReplace: Clear Highlights” command from the command palette.

Highlight color and style can be changed in the settings file.


0 Likes

#6

Damn… this plugin went from a simple regex find/replace to this behemoth of awesomeness (feel free to quote me on that one). Good work.

sigh If only I could find more uses for it…

0 Likes

#7

[quote=“C0D312”]Damn… this plugin went from a simple regex find/replace to this behemoth of awesomeness (feel free to quote me on that one). Good work.

sigh If only I could find more uses for it…[/quote]

:smiley:

0 Likes

#8

Very small update.

Version 0.4

  • Add support for “literal” boolean parameter for literal find and replaces
  • Allow the Regex Input Sequencer panel to highlight only by preceding the sequence with “?:”
0 Likes

#9

Also, the plugin is now available in Package Control.

0 Likes

#10

Just got a fantastic idea from How to hide comments.

I just added it locally, but tonight or tomorrow I will commit the ability to fold code based on regex search. Just seemed like it would be a handy thing.

0 Likes

#11

Version 0.5

  • Make replace an optional parameter defaulted to “” (empty string)
  • Allow override actions to use instead of replace: fold and unfold

Currently all finds are regex with option scope qualifiers. I plan on implementing the opposite as well: scope searches with regex qualifiers. That way you can find all regions of any scope and apply an optional regex on the region and determine if you want to do something to it.

0 Likes

#12

If I have enough time today, I plan on pushing out the option to do multi-passes using a regex sequence.

There are times when you have a regex that can be fairly complicated and can only find one instance of a particular target on a line. The nature of regex is that it can only find a finite number of matches. So if the complexity is so great that it is not feasible to target all in a single pass, multi-pass can help.

For example (I got this from another post today):
Somebody wanted to find instances of un-escaped dollar symbols between a certain tag. It is easy enough to target one, but to target an unknown number is quite a bit more difficult without perform regex on the regex result returned.
So this example will find one instance for every content tag.

((?=<content)(?:.*))(^\\])\$((?:.*)(?<=</content>))

But I plan on adding a feature that will keep sweeping the file until no instances are found (or if you hit some threshold; I want to protect against infinite loops due to bad regex defines).

I think this will be a pretty good feature, and it shouldn’t be to difficult to implement; I have most of it done already; I just need to restrict it to replace actions only and maybe update how I do feedback results to work with multi-pass.

0 Likes

#13

Version 0.6

  • Add multi-pass sweeps
  • Report bad actions

Enjoy.

0 Likes

#14

Just a heads up; I will be commenting out all of the default commands except the “Reg Replace: Regex Input Sequencer” and “Reg Replace: Clear Highlights”. I originally added the others as examples, so that is why I am going to have them commented out and remain, but I realized, I didn’t want all of them, and they would have to be removed after every update.

So, moving forward, I will leave the default replace definitions in place because they hurt nothing and you can override them in your User folder if you don’t want them. And I will leave the two commands mentioned above in place and comment out the rest so they can still be used as examples. I you like any of them, you can simply copy them to your Packages/User/Default.sublime-commands file, and those will persist with updates.

Figured I needed to mention it though in case some people used any of them and they disappeared on them.

0 Likes

#15

Version 0.7

  • Replace command examples now commented out by default
  • RegReplace Commands and Settings now available via preference menu and command palette

Very small update. So default replace commands are commented out, you can define your own in Default.sublime-commands in your User directory. Now you don’t have to delete the default ones every time if you didn’t want them.

0 Likes

#16

I have some fairly useful replacements.

These are definitions and commands for comments. Some C/C++ style, CSS (c multi-line), python style, and batch. They also come in multi line (where applicable), single line, and consecutive single line (good for code folding).

What is nice about these, is that they seem to work pretty good with folding without collapsing the next line into the first line. They seem to be working pretty good for me.

"batch_comments": { "find": "((?:^)?^\\S\\r\\n]*)(::^\\r\\n]*)", "replace": "", "scope_filter": "comment", "-string"] }, "batch_consecutive_single_comments": { "find": "((?:^\\S\\r\\n]*::^\\r\\n]*(?:\\r\\n])?)*)(^\\S\\r\\n]*::^\\r\\n]*)", "replace": "", "scope_filter": "comment", "-string"] }, "c_comments": { "find": "((?:^)?^\\S\\r\\n]*)(//^\\r\\n]*)", "replace": "", "scope_filter": "comment", "-string"] }, "c_consecutive_single_comments": { "find": "((?:^\\S\\r\\n]*//^\\r\\n]*(?:\\r\\n])?)*)(^\\S\\r\\n]*//^\\r\\n]*)", "replace": "", "scope_filter": "comment", "-string"] }, "c_multi_line_comments": { "find": "((?:^)?^\\S\\r\\n]*)/(\\*(\\w\\W]*?)\\*/)(^\\S\\r\\n]*)", "replace": " ", "scope_filter": "comment", "-string"] }, "python_comments": { "find": "((?:^)?^\\S\\r\\n]*)(#^\\r\\n]*)", "replace": "", "scope_filter": "comment", "-string"] }, "python_consecutive_single_comments": { "find": "((?:^\\S\\r\\n]*#^\\r\\n]*(?:\\r\\n])?)*)(^\\S\\r\\n]*#^\\r\\n]*)", "replace": "", "scope_filter": "comment", "-!string"] }, "python_multi_line_double_block_strings": { "find": "((?:^)?^\\S\\r\\n]*)(\"\"\"(\\w\\W]*?)\"\"\")(^\\S\\r\\n]*)", "replace": " ", "scope_filter": "-comment", "string.quoted.double.block.python"] }, "python_multi_line_single_block_strings": { "find": "((?:^)?^\\S\\r\\n]*)('''(\\w\\W]*?)''')(^\\S\\r\\n]*)", "replace": " ", "scope_filter": "-comment", "string.quoted.single.block.python"] }

Here are some remove and folding commands for comments.

{ "caption": "Remove: Python Style Comments", "command": "reg_replace", "args": {"replacements": "python_comments", "remove_trailing_spaces"], "find_only": true} }, { "caption": "Remove: Python Block Strings", "command": "reg_replace", "args": {"replacements": "python_multi_line_double_block_strings", "python_multi_line_single_block_strings", "remove_trailing_spaces" ], "find_only": true} }, { "caption": "Remove: C Style Comments", "command": "reg_replace", "args": {"replacements": "c_comments", "c_multi_line_comments", "remove_trailing_spaces"], "find_only": true} }, { "caption": "Remove: CSS Comments", "command": "reg_replace", "args": {"replacements": "c_multi_line_comments", "remove_trailing_spaces"], "find_only": true} }, { "caption": "Remove: Batch Comments", "command": "reg_replace", "args": {"replacements": "batch_comments", "batch_multi_line_comments", "remove_trailing_spaces"], "find_only": true} }, // Fold Comments { "caption": "Code Folding: Fold Python Style Comments", "command": "reg_replace", "args": {"replacements": "python_consecutive_single_comments"], "action": "fold"} }, { "caption": "Code Folding: Fold Python Block Strings", "command": "reg_replace", "args": {"replacements": "python_multi_line_double_block_strings", "python_multi_line_single_block_strings" ], "action": "fold"} }, { "caption": "Code Folding: Fold C Style Comments", "command": "reg_replace", "args": {"replacements": "c_consecutive_single_comments", "c_multi_line_comments"], "action": "fold"} }, { "caption": "Code Folding: Fold CSS Comments", "command": "reg_replace", "args": {"replacements": "c_multi_line_comments"], "action": "fold"} }, { "caption": "Code Folding: Fold Batch Comments", "command": "reg_replace", "args": {"replacements": "batch_consecutive_single_comments", "batch_multi_line_comments"], "action": "fold"} }

Unfold commands would be the same as the fold, except you change the caption to say “unfold” and change the action to “unfold”.

If you have any improvements, let me know. If you know of some other comment styles, let me know. I may add some of these definitions by default to the plugin; I will have to see.

**Edit: ** Typo fixed on Python block strings.
**Edit: ** Scope fix on all comments

0 Likes

#17

They can get a little tripped up with some symbols in strings. Like if you have a comment symbol in a string and comment at the end of a line, but it isn’t too bad.

This is quite common for regex though. You pretty much have to parse the entire line to determine where comments really start and stop. And in some languages it is easier than others. Currently if you parse the entire line, you may be able to target comment exactly, but currently “fold” actions etc, are performed on the entire regex selection. I do not allow fine targeting of regions within a regex at this time, maybe in the future.

Eventually, I will get the scope searching done, with regex qualifiers, and then comments can be targeted very accurately.

0 Likes

#18

Okay, so I now have scope searching working, but I am not committing it yet; I only have parts of it working.

I have it now where you can greedily find scopes and apply an optional find and replace with regex on those scopes (greedy or non-greedy).

I do not have non-greedy scope search done yet. I do not have literal search and replace on a scope done yet either. But it does work great on greedy scope searches with regex. I have been playing around with, and it just made all of my regex for comments obsolete. :smile: .

The rules for defining a scope find and replace will be different.

"scope_test": { "scope": "comment", "find": "SomeRegex", "replace": "PrependText\\0", "greedy_replace": false, "greedy_scope": true, "literal": false, "case": true }

0 Likes

#19

Should have a new release out tonight hopefully; if not, tomorrow for sure.

I have the “searching by scope and then applying regex to the scope region” feature pretty much done (I am skipping literal find and replace for now). Something to note though, due to the nature of Python’s subn function, you need to be careful with optional captured groups. Normally you will expect something like this to return an empty string for group 1 if this or that is not found.

(this|that)?(SomethingElse)

But subn, which I am using for applying regex to the the scope region, will return “unmatched group error” if you try and access group 1 and group 2 when this or that is not found.

You can still use the “?” in all sorts of other instances, but it might give you issues if you try and use it on a group. There are probably other scenarios you might need to be mindful of.

So to fix this, you would have to provide an empty option. This probably makes the “?” mark unneeded now, but I just want to illustrate what you have to do to fix the error.

(this|that|)?(SomethingElse)

This only applies to regex applied to scope regions. Regex with scope qualifiers goes through ST2’s api which does not suffer from this.
I could use Python’s findall function, but then I have to perform some coding gymnastics which I am not anxious to do right now, maybe down the road; we will see.

I also modified the folding command to not fold the trailing newline at the end of a selection. This makes folding regex much better, especially when targeting scopes like comments.

I also added a “mark” and “unmark” command where you can permanently highlight regions based on regex and also clear them; not sure how much use one might get out of this one, but it was easy to add, so I went ahead. It might come in handy.

0 Likes

#20

Version 0.8

  • New “mark” and “unmark” actions
  • Return error dialog showing regex issue
  • Add support for scope search with regex find and replace in scope region
  • Smarter folding of regex regions for “fold” action
  • Small tweak to non-greedy algorithm
  • Change default of optional replace parameter to “\0”; do not delete by default, leave unchanged by default.
  • Allow spaces in the “Regex Input Sequencer”

One big thing to stress is the change of the default value of replace. If you have definitions that relied on the old default of “”, the new default is “\0”. I decided it was better to not replace anything by default instead of deleting everything by default.

The other thing to note, is now when you create a malformed regex expression, you should get an error dialog giving you the internal error: things like unmatched brackets etc.

So now that scope selection is in, it is super easy to target difficult things like comments in every language. Here is a simple definition to delete all comments.

This is included in the default settings. It simply removes the comments leaving the line in tact

"remove_comments": { "scope": "comment", "find" : "(^\\n\\r]+)", "replace": "", "greedy_replace": true }

Here is the actual command:

{ "caption": "Remove: All Comments", "command": "reg_replace", "args": {"replacements": "remove_comments", "remove_trailing_spaces"], "find_only": true} },

Folding is much better now. Folding now will automatically adjust regions that have trailing newlines so as not to fold lines into each other.


Here are the fold/unfold commands:

// Folding { "caption": "Code Folding: Fold All Comments", "command": "reg_replace", "args": {"replacements": "remove_comments"], "action": "fold"} }, { "caption": "Code Folding: Unfold All Comments", "command": "reg_replace", "args": {"replacements": "remove_comments"], "action": "unfold"} }

The mark and unmark actions are pretty self explanatory. It simply allows you to highlight specific searches by whatever scope you choose. You can have multiple different regex highlights on the screen at the same time as long as you give them unique keys. How to use them is documented in the readme. The highlights will persist until you delete the region, or clear them with the unmark command, etc. I guess it might be good if you have things you are always looking for in certain files. You can make them stand out a lot. It might not be that useful, it is kind of similar to the “find_only” option; the only difference is it doesn’t disappear until you clear it. But it was easy to to add…so there it is.

0 Likes