feat: String conversion intentions

This commit is contained in:
FalsePattern 2024-10-26 20:56:54 +02:00
parent 824f797eaa
commit bac9a8f8d1
Signed by: falsepattern
GPG key ID: E930CDEC50C50E23
4 changed files with 147 additions and 0 deletions

View file

@ -21,6 +21,7 @@ Changelog structure reference:
- Zig - Zig
- Enter key handling in strings and multi line strings - Enter key handling in strings and multi line strings
- Intentions for converting between multi line and quoted strings
### Fixed ### Fixed

View file

@ -39,6 +39,17 @@
id="ZigEnterInQuotedStringHandler" id="ZigEnterInQuotedStringHandler"
implementation="com.falsepattern.zigbrains.zig.editing.ZigEnterInQuotedStringHandler" /> implementation="com.falsepattern.zigbrains.zig.editing.ZigEnterInQuotedStringHandler" />
<intentionAction>
<language>Zig</language>
<className>com.falsepattern.zigbrains.zig.intentions.MakeStringMultiline</className>
<category>Zig intentions</category>
</intentionAction>
<intentionAction>
<language>Zig</language>
<className>com.falsepattern.zigbrains.zig.intentions.MakeStringQuoted</className>
<category>Zig intentions</category>
</intentionAction>
<postStartupActivity implementation="com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity"/> <postStartupActivity implementation="com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity"/>
<!-- LSP textDocument/signatureHelp --> <!-- LSP textDocument/signatureHelp -->

View file

@ -0,0 +1,44 @@
package com.falsepattern.zigbrains.zig.intentions;
import com.falsepattern.zigbrains.zig.psi.ZigStringLiteral;
import com.falsepattern.zigbrains.zig.psi.ZigTypes;
import com.falsepattern.zigbrains.zig.util.PsiTextUtil;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.codeInspection.util.IntentionFamilyName;
import com.intellij.codeInspection.util.IntentionName;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import lombok.val;
import org.jetbrains.annotations.NotNull;
public class MakeStringMultiline extends PsiElementBaseIntentionAction implements IntentionAction {
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
val str = PsiTreeUtil.getParentOfType(element, ZigStringLiteral.class);
return str != null && !str.isMultiLine();
}
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element)
throws IncorrectOperationException {
val str = PsiTreeUtil.getParentOfType(element, ZigStringLiteral.class);
if (str == null)
return;
PsiTextUtil.splitString(editor, str, editor.getCaretModel().getOffset(), false);
}
@Override
public @NotNull @IntentionName String getText() {
return getFamilyName();
}
@Override
public @NotNull @IntentionFamilyName String getFamilyName() {
return "Convert to multiline";
}
}

View file

@ -0,0 +1,91 @@
package com.falsepattern.zigbrains.zig.intentions;
import com.falsepattern.zigbrains.zig.psi.ZigStringLiteral;
import com.falsepattern.zigbrains.zig.util.PsiTextUtil;
import com.falsepattern.zigbrains.zig.util.ZigStringUtil;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.codeInspection.util.IntentionFamilyName;
import com.intellij.codeInspection.util.IntentionName;
import com.intellij.formatting.CoreFormatterUtil;
import com.intellij.formatting.FormatterEx;
import com.intellij.formatting.FormattingModel;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.MathUtil;
import lombok.val;
import org.jetbrains.annotations.NotNull;
public class MakeStringQuoted extends PsiElementBaseIntentionAction implements IntentionAction {
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
val str = PsiTreeUtil.getParentOfType(element, ZigStringLiteral.class);
return str != null && str.isMultiLine();
}
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element)
throws IncorrectOperationException {
val document = editor.getDocument();
val file = element.getContainingFile();
val str = PsiTreeUtil.getParentOfType(element, ZigStringLiteral.class);
if (str == null)
return;
val escaper = str.createLiteralTextEscaper();
val contentRange = escaper.getRelevantTextRange();
val contentStart = contentRange.getStartOffset();
val contentEnd = contentRange.getEndOffset();
val fullRange = str.getTextRange();
var caretOffset = editor.getCaretModel().getOffset();
val prefix = new TextRange(contentStart, Math.max(contentStart, caretOffset - fullRange.getStartOffset()));
val suffix = new TextRange(Math.min(contentEnd, caretOffset - fullRange.getStartOffset()), contentEnd);
val sb = new StringBuilder();
escaper.decode(prefix, sb);
val prefixStr = ZigStringUtil.escape(sb.toString());
sb.setLength(0);
escaper.decode(suffix, sb);
val suffixStr = ZigStringUtil.escape(sb.toString());
val stringRange = document.createRangeMarker(fullRange.getStartOffset(), fullRange.getEndOffset());
stringRange.setGreedyToRight(true);
document.deleteString(stringRange.getStartOffset(), stringRange.getEndOffset());
document.insertString(stringRange.getEndOffset(), "\"");
document.insertString(stringRange.getEndOffset(), prefixStr);
caretOffset = stringRange.getEndOffset();
document.insertString(stringRange.getEndOffset(), suffixStr);
document.insertString(stringRange.getEndOffset(), "\"");
val documentText = document.getCharsSequence();
int scanStart = stringRange.getEndOffset();
stringRange.dispose();
int scanEnd = scanStart;
loop:
while (scanEnd < documentText.length()) {
switch (documentText.charAt(scanEnd)) {
case ' ', '\t':
break;
default:
break loop;
}
scanEnd++;
}
if (scanEnd > scanStart) {
document.deleteString(scanStart, scanEnd);
}
editor.getCaretModel().moveToOffset(caretOffset);
}
@Override
public @NotNull @IntentionName String getText() {
return getFamilyName();
}
@Override
public @NotNull @IntentionFamilyName String getFamilyName() {
return "Convert to quoted";
}
}