Sublime Forum

Plugin Idea: Would This Be Useful?

#1

Hey guys -

I was thinking about a plugin that might be useful. It essentially offers a way to execute saved regular expressions on demand. For example, I’m often working with other people’s code or HTML, and I find myself making the same set of changes over and over. One thing that I’m constantly doing is removing type=“text/javascript” and type=“text/css” from script and link tags, respectively (they’re not necessary). If there was a plugin with a settings file…

{ replacements: { 'Remove Link and Script Types': /\stype="text\/(?:css|javascript)/ig } }

I could then pull up the command palette, choose “Remove Link and Script Types,” and the associated regular expression will instantly be run on the contents of the focused page.

…Or maybe to remove all HTML comments from the page:

replacements: { 'Remove HTML Comments': /<!--\s\S]+?-->/g }

It would be even neater if there was a way to stack these. So, in addition to single commands, I could also execute a series of them with a single command: first use this regular expression to remove comments, then make the first letter of all words in h1 tags capital, etc.

sequence: { "Optimize HTML": [replacement1, replacement1, replacement1] }

The regex references in the array would then be executed sequentially on the document.

Personally, I’d have a lot of uses for something like this, but I’m not sure if anyone else would. Let me know, and, if so, we may hire @weslly to make it. :smile:

0 Likes

#2

This will really be useful for me too.

0 Likes

#3

This wouldn’t be too difficult of a plugin to write. It would actually be quite straight forward. If I get a little time, I might code it up.

0 Likes

#4

I already have the basics in place and example of setting would look like this:

{ "commands": { "example command 1": { "find": "\\bword1\\b", "replace": "", "greedy": true, "case": true }, { "find": "\\bword2\\b", "replace": "", "greedy": true, "case": true }, ], "example command 2": { "find": "\\bword1\\b", "replace": "", "greedy": true, "case": true } ] } }

I just need to do a little bit of clean up and testing. I will let you know when I am done.

Finds and replaces are done with the find, find_all, and replace commands found in the SublimeText 2 API. They are simple find and replaces. Don’t expect anything too fancy.

0 Likes

#5

Beta Project is here:

github.com/facelessuser/RegReplace

Your desired settings would look like this:

{ "commands": { "Optimize HTML": { "find": "\\stype=\"text\\/(?:css|javascript)\"", "replace": "", "greedy": true, "case": false }, { "find": "<!--\\s\\S]+?-->", "replace": "", "greedy": true, "case": true } ] } }

Let me know what you think. That is all I plan on doing today :smile: .

0 Likes

#6

@facelessuser

The second arg to view.find is actually the start pt rather than the flags.

Also, view.find_all has a signature that’s (pattern, flags, replace_format_string, empty_list_reference). It’s a somewhat weird/awkward API but the empty_list_reference will be filled with renderings of the format string for each found region in order.

When it comes to replacing the regions, you don’t have to track offsets manually if you perform the operations in reverse order ( end of document towards beginning). view.find_all will return the regions in the order they are found so you just need to reverse them. Python has a handy builtin function [reversed](http://docs.python.org/library/functions.html#reversed) for this.

0 Likes

#7

Whoops, I actually knew this, but still forget it anyways. I will fix it. :smile:. It is really more of a place holder right now, I plan to have it look forward from the current cursor location, but this is a very early implementation. Alpha is probably more accurate than beta, but it will get there.

Interesting. I will look into this more. I literally threw this thing together while my kids were napping, so I didn’t look to deep.

Clever. I will implement this as well.

Thanks for the input and interest. I will patch it up soon.

0 Likes

#8

May I suggest that rather than using window.show_quick_panel(), just integrating into the Command Palette instead? The replacements can then be specified in a .sublime-commands file (passing the find and replace strings via the args parameter), and you’ll get to reuse the Command Palette key binding, which should be easier on the user.

0 Likes

#9

Thanks for the input and interest.

np :smile: I’m actually just trying to help out and answer a few questions on the forums, sucking up to Jon, so he’ll give me (get|set)_view_position APIs. Ulterior motives haha.

I plan to have it look forward from the current cursor location, but this is a very early implementation

Only real issue you’ll have is if you decide to use the replacement format string capabilities of view.find_all then you’ll want the interface to be consistent with single selection replace. view.find doesn’t have the replace functionality. You could bisect the view.find_all regions to find the closest selection to your first selection though (copping the wasted perf on the chin) The other option is integration with find/replace commands somehow. I don’t think that’s viable with the current state of the api though.

May I suggest that rather than using window.show_quick_panel(), just integrating into the Command Palette instead?

what he said :smile: You could still use the sublime-settings file though keyed with identifiers for parameters for the case that you want to run a batch (DRY! and all that …)

eg.

{ "replacements": { "html5_remove_deprecated_type_attr": { "find": "<(style|script)^>]+type=(\"|')text/(css|javascript)(\"|')^>]*>", "replace": "<\\1>", "greedy": true, "case": true } ] } }
You could have the RegReplaceCommand accept a list of ids(declared in the sublime-commands file) to do the lookup.

{
        "caption": "Reg Replace: HTML5: Remove deprecated `@type` for script|style",
        "command": "reg_replace_menu",
        "args"   : {"replacements" : "html5_remove_deprecated_type_attr"]}
}

The replacements list (in either sublime-settings or sublime-commands files) could do sublime-settings lookups on finding a “string” or inline parameterisation for {objects}.

0 Likes

#10

Hope you get it :smile:

Good idea. I haven’t thought everything 100% through yet; kind of picked this one up on a whim, so things will be in flux for a bit until I find what really works. I am completely open to suggestions though and will take them in to account as I mold this into something useful.

Yeah, I haven’t played with the find/replace API much yet. I am just going to have to play around with it and see what works. I will look into your suggestions and see what the most viable option is. Using the find_all for the closest might be the best option. Thanks for the suggestions.

0 Likes

#11

Cheers!

A layout splitting plugin is what I want it for. Messed around on one around xmas time but got API stuck :frowning:

0 Likes

#12

Currently when you set a layout from a 1+n size (in terms of cells) layout to a 2+n layout the views will just be placed in the cell via their index position in the cells array you pass to set_layout. It make more sense to regroup geometrically with more elaborate layouts (splits and merges)

0 Likes

#13

Looks cool. I personally know a number of people who would love to see something like that.

0 Likes

#14

Okay, reworked the code. I am now taking full use of the find_all command. This means you can do some more complicated substitutions. I went ahead and committed as an example the replacements requested on the opening page.

{ "replacements": { // Example replacements "html5_remove_deprecated_type_attr": { "find": "(<(style|script)^>]*)\\stype=(\"|')text/(css|javascript)(\"|')(^>]*>)", "replace": "\\1\\6", "greedy": true, "case": false }, "remove_html_comments": { "find": "<!--\\s\\S]+?-->", "replace": "", "greedy": true, "case": true } } }

To access the commands, you simply define a command in the command palette. I have provided an example, and you can chain the replacements.

	{
		"caption": "Reg Replace: Example - Cleanup HTML",
		"command": "reg_replace",
		"args": {"replacements": "html5_remove_deprecated_type_attr", "remove_html_comments"]}
	}
]

So the quick_panel is removed now.

Non-greedy searches are still limited to the first in the entire file. I plan on applying non-greedy changes from the cursor forward and allow wrapping, but not today.

As always, feedback, bug reports, and suggestions are appreciated.

0 Likes

#15

For people looking for a link (like me :smile: ):https://github.com/facelessuser/RegReplace

0 Likes

#16

You could probably even put a scope selector restriction in.

I’ve always wished you could optionally pass a list of regions and/or a scope selector to the find_all api to further restrict the finds. If find_all returned regions in the ordering of the regions you passed it, eg ([R(caret_pos, view.size()), R(0, caret_pos)] seems like you could easily enough implement wrapped search that way. To restrict your search to a bunch of particular regions currently isn’t as easy as it could be.

Some feedback of which regions were replaced would likely come in handy.

0 Likes

#17

[quote=“castles_made_of_sand”]You could probably even put a scope selector restriction in.

I’ve always wished you could optionally pass a list of regions and/or a scope selector to the find_all api to further restrict the finds. If find_all returned regions in the ordering of the regions you passed it, eg ([R(caret_pos, view.size()), R(0, caret_pos)] seems like you could easily enough implement wrapped search that way. To restrict your search to a bunch of particular regions currently isn’t as easy as it could be.

Some feedback of which regions were replaced would likely come in handy.[/quote]

The regions are returned in order and caret position is easy to calculate, so it is easy enough to at least filter the results. Not really worried about the calculating after the cursor, more just need to get around to it.

In what way would you use the scope selector? I am just curious in what context you would use this. I have no problem adding it, but I would like to better understand it so I can test the scenario.

Added the link in an earlier post, but yeah, I probably need to open up a specific thread for this sometime soon.

0 Likes

#18

easy enough to at least filter the results

Yeah, it’s just tedious. It’s just such a common task that it’d be nicer (and likely a lot more efficient) if there was a more direct api for it. You’ll probably end up implementing replace restricted to selections for example.

In what way would you use the scope selector?

The scope selector would be used most commonly for restricting to, or filtering, string and comment scopes I’d imagine.

0 Likes

#19

I agree.

Ahh. That makes sense. I will add a simplistic filtering based on scope. Initially I will make it include or exclude filtering based on any part of the target exhibiting the scope; it will also be optional parameter that can be left out if not desired. If needed later, I can add options for “absolute filter” (meaning that the entire selection must be completely contained within the specified scope type). I am going to start out as simple as possible and only ramp it up to more complicated rule sets if it becomes needed. Even then, I will probably have to draw a line somewhere so I am not implementing some kind of regex for scopes. I surely see why you desire this feature now; I do hate it when a regex find targets inside comments and/or strings that I just don’t care about.

0 Likes

#20

So, as I get time, these are the current tasks on my plate:

-Feedback on replaced regions
-Non-greedy searches relative to the cursor
-Scope filtering of results

If you don’t see a feature you really want, run it by me, and I will evaluate the request and possibly add it to my todo list.

0 Likes