Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnjohndoe/8cf08bbc2f2d79b2393bed70f439510d to your computer and use it in GitHub Desktop.
Save johnjohndoe/8cf08bbc2f2d79b2393bed70f439510d to your computer and use it in GitHub Desktop.
IntelliJ plugin to perform multiple structural search and replace actions. Can be installed with https://github.com/dkandalov/live-plugin
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.application.*
import com.intellij.openapi.command.*
import com.intellij.openapi.diagnostic.*
import com.intellij.openapi.fileTypes.*
import com.intellij.openapi.progress.*
import com.intellij.openapi.project.*
import com.intellij.openapi.ui.*
import com.intellij.openapi.vfs.*
import com.intellij.psi.*
import com.intellij.psi.search.*
import com.intellij.structuralsearch.*
import com.intellij.structuralsearch.plugin.*
import com.intellij.structuralsearch.plugin.replace.*
import com.intellij.structuralsearch.plugin.replace.impl.*
import com.intellij.structuralsearch.plugin.ui.*
import com.intellij.structuralsearch.plugin.util.*
import java.util.*
import static liveplugin.PluginUtil.registerAction
import static liveplugin.PluginUtil.show
/**
* IntelliJ Plugin action to do multiple structural find/replaces.
* Can be installed with https://github.com/dkandalov/live-plugin v0.6.1 on IntelliJ 2018.3.
*/
class FindMatchesAction extends AnAction {
Logger logger = Logger.getInstance("FindMatches")
@Override void actionPerformed(AnActionEvent event) {
Project project = event.project
show("Finding matches in ${project.name}...")
VirtualFile searchRootFile = project.baseDir.findFileByRelativePath("libraries/feature")
PsiDirectory searchRoot = PsiManager.getInstance(project).findDirectory(searchRootFile)
GlobalSearchScope scope = GlobalSearchScopesCore.directoryScope(searchRoot, true)
/*** Do one or more calls to findMatches() here... ***/
findMatches(project, scope, "short label",
'com.example.Foo($params$)', // structural search pattern
'com.example.Barr($params$)', // structural replace pattern
Collections.emptyList())
}
private void findMatches(Project project, GlobalSearchScope scope, String name, String find, String replace, List<MatchVariableConstraint> constraints) {
try {
MatchOptions options = new MatchOptions()
options.setFileType(StdFileTypes.JAVA)
options.setScope(scope)
options.setRecursiveSearch(true)
options.setCaseSensitiveMatch(true)
options.fillSearchCriteria(find)
constraints.forEach {
options.addVariableConstraint(it)
}
ReplaceOptions replaceOptions = new ReplaceOptions(options)
replaceOptions.setToShortenFQN(true)
replaceOptions.setToUseStaticImport(true)
replaceOptions.setReplacement(replace)
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Finding matches for $name") {
void run(ProgressIndicator progressIndicator) {
CollectingMatchResultSink sink = new CollectingMatchResultSink() {
@Override ProgressIndicator getProgressIndicator() {
return progressIndicator
}
}
Matcher matcher = new Matcher(project, options)
matcher.findMatches(sink, options)
int count = sink.getMatches().size()
logger.info("Found ${count} matches for $name")
ApplicationManager.getApplication().invokeLater { show("Found ${count} matches for $name") }
WriteCommandAction.runWriteCommandAction(project) {
Replacer replacer = new Replacer(project, replaceOptions)
sink.getMatches().forEach { MatchResult matchResult ->
replacer.replace(replacer.buildReplacement(matchResult))
}
}
logger.info("Replaced ${count} matches for $name")
ApplicationManager.getApplication().invokeLater { show("Replaced ${count} matches for $name") }
}
})
} catch (Throwable throwable) {
logger.error(throwable)
Messages.showErrorDialog(project, throwable.getStackTrace().toString(), "Error finding matches for $name")
}
}
private static MatchVariableConstraint createConstraint(String name, int minCount, int maxCount, String type = null) {
MatchVariableConstraint constraint = new MatchVariableConstraint()
constraint.setName(name)
constraint.setMinCount(minCount)
constraint.setMaxCount(maxCount)
if (type != null) {
constraint.setNameOfExprType(type)
}
return constraint
}
}
registerAction("Find Matches", "alt shift M", new FindMatchesAction())
if (!isIdeStartup) show("Loaded 'Find Matches'<br/>Use alt+shift+M to run it")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment