Skip to content

Instantly share code, notes, and snippets.

@dkandalov
Last active September 19, 2022 12:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dkandalov/34daca651fb3fbb9b33f to your computer and use it in GitHub Desktop.
Save dkandalov/34daca651fb3fbb9b33f to your computer and use it in GitHub Desktop.
Text Munging mini-plugin
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.editor.Document
import com.intellij.testFramework.MapDataContext
import static liveplugin.PluginUtil.*
registerAction("MungeText", "ctrl alt shift M") { AnActionEvent event ->
def project = event.project
showPopupMenu([
"Group by": {
def keyRegex = showInputDialog("Regex to group by (must have a capturing group):", "Group by")
if (keyRegex == null) return
def separator = showInputDialog("String to join with:", "Group by")
runDocumentWriteAction(project, currentDocumentIn(project)) { Document document ->
document.text = document.text.split("\n")
.groupBy {
def matcher = (it =~ keyRegex)
matcher.matches() ?matcher.group(1) : ""
}
.values().collect{ it.join(separator) }
.join("\n")
}
},
"Sort": {
runDocumentWriteAction(project, currentDocumentIn(project)) { Document document ->
document.text = document.text.split("\n").sort().join("\n")
}
},
"Join": {
def separator = showInputDialog("Join with text:", "Join lines")
if (separator == null) return
runDocumentWriteAction(project, currentDocumentIn(project)) { Document document ->
document.text = document.text.replaceAll("\n", separator)
}
},
"Split": {
def separator = showInputDialog("Split text on string:", "Split text")
if (separator == null) return
runDocumentWriteAction(project, currentDocumentIn(project)) { Document document ->
document.text = document.text.replaceAll(separator, "\n")
}
},
"Unique": {
runDocumentWriteAction(project, currentDocumentIn(project)) { Document document ->
document.text = document.text.split("\n").toList().unique().join("\n")
}
},
"Keep Lines": {
def text = showInputDialog("Keep lines with text:", "Keep lines")
if (text == null) return
runDocumentWriteAction(project, currentDocumentIn(project)) { Document document ->
document.text = document.text.split("\n").findAll{ it.matches(".*?" + text + ".*") }.join("\n")
}
},
"Delete Lines": {
def text = showInputDialog("Delete lines with text:", "Delete lines")
if (text == null) return
runDocumentWriteAction(project, currentDocumentIn(project)) { Document document ->
document.text = document.text.split("\n").findAll{ !it.matches(".*?" + text + ".*") }.join("\n")
}
}
], "Munge Text")
}
if (!isIdeStartup) show("Reloaded text munging")
@kirkw
Copy link

kirkw commented Sep 11, 2022

First, this is CRAZY Cool. But being new to the API and to GROOVY... I tried to setup a handful of standard search / replaces
(I am converting code from one DB to another, and there are 5 search/replaces I do in the file. With this, I got it started.)

  1. OMG I put a $ in the replacement string: "now this$" ... Okay, switch to single quotes, that was groovy.
  2. It's not clear that these searches/replacements are REGEX (so that dollar, that period and that Backslash, uggh)
  3. It's not clear when/how to call something like: regexEscape()...
  4. I did learn that prefixing with '(?i)' on the search string did it case insensitive... I manually escaped my strings.
    \\$ and \\. and \\( and \\) for those wondering. [Double up the backslash so regex sees ONE backslash, then the character!]

The question is. Inside of a replaceAll(), could you demonstrate how to do a call to PROTECT IT from regex?
On BOTH the search and replace?
Answer:

import java.util.regex.*

    def str = Matcher.quoteReplacement('THis\\(is\\).Cool')  // This escapes the string (Class Function)

  I can define my searches and replacements this way...

Or does this force you to have to take a different approach, create a matcher, and then loop through them yourself?

Final Question... Is there a way to trigger a custom BUILD event (where I can edit the sql script??? I want to inject a line of code at the top, that sets the 'name' of the procedure I am working on... To call a linter on THIS function. Currently I have to copy, click run, paste the name in, and continue. It would be great to be able to "Push to Changes to the DB (an Action, this is easy enough)", Then re-lint the result specific to this "procedure". [The Haskell Build example falls short]

Answer the questions, include a donation link, and there is a BOX of coffee in it for you! (Hopefully this helps other people).

PS: Great Plugin Tool.

@dkandalov
Copy link
Author

dkandalov commented Sep 19, 2022

Hi. Thank you!

The question is. Inside of a replaceAll(), could you demonstrate how to do a call to PROTECT IT from regex?
On BOTH the search and replace?

I guess you already found the answer :) In case it's helpful, this looks like a generic Java/Groovy question. For Groovy I personally would look here https://groovy-lang.org/single-page-documentation.html Also for any somewhat complicated regex code it might be a good idea to write some tests (i.e. executable examples).

Final Question... Is there a way to trigger a custom BUILD event

I guess you mean something along the lines of invoking "Build Project" action and when it's done, invoke "Push to Changes to the DB" action. This might be a starting point https://github.com/dkandalov/live-plugin/wiki/Scripting-a-macros Unfortunately, there are few problems like finding the ids of actions you want to invoke (can be done by looking at source or recording a macros Main Menu -> Edit -> Macro and viewing action name in macro editor), how to pass arguments to an action (most likely via DataContext but you'll have to read action source code) and how to know when action finished execution (for which there is no single answer). All these problems are hard and can really be fully fixed only if Jetbrains refactors IJ codebase to make these things easy. If you can use external tools via command line to build and relint, then in my experience this might be a path of least resistance.

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