1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-08-10 15:40:37 +02:00

Improve handling of Delete and Backspace in ex entry

This commit is contained in:
Matt Ellis 2019-06-18 13:27:32 +01:00
parent 31d30a9115
commit b157d07b6d
No known key found for this signature in database
GPG Key ID: FA6025D54131324B
4 changed files with 128 additions and 48 deletions
src/com/maddyhome/idea/vim/ui
test/org/jetbrains/plugins/ideavim/ex

View File

@ -102,8 +102,6 @@ public class ExEditorKit extends DefaultEditorKit {
static final String CancelEntry = "cancel-entry";
static final String CompleteEntry = "complete-entry";
static final String EscapeChar = "escape";
static final String DeletePreviousChar = "delete-prev-char";
static final String DeletePreviousWord = "delete-prev-word";
static final String DeleteToCursor = "delete-to-cursor";
static final String ToggleInsertReplace = "toggle-insert";
static final String InsertRegister = "insert-register";
@ -114,18 +112,19 @@ public class ExEditorKit extends DefaultEditorKit {
static final String StartDigraph = "start-digraph";
@NotNull private final Action[] exActions = new Action[]{
new ExEditorKit.CancelEntryAction(),
new ExEditorKit.CompleteEntryAction(),
new ExEditorKit.EscapeCharAction(),
new ExEditorKit.DeletePreviousCharAction(),
new ExEditorKit.DeletePreviousWordAction(),
new ExEditorKit.DeleteToCursorAction(),
new ExEditorKit.HistoryUpAction(),
new ExEditorKit.HistoryDownAction(),
new ExEditorKit.HistoryUpFilterAction(),
new ExEditorKit.HistoryDownFilterAction(),
new ExEditorKit.ToggleInsertReplaceAction(),
new ExEditorKit.StartDigraphAction(),
new CancelEntryAction(),
new CompleteEntryAction(),
new EscapeCharAction(),
new DeleteNextCharAction(),
new DeletePreviousCharAction(),
new DeletePreviousWordAction(),
new DeleteToCursorAction(),
new HistoryUpAction(),
new HistoryDownAction(),
new HistoryUpFilterAction(),
new HistoryDownFilterAction(),
new ToggleInsertReplaceAction(),
new StartDigraphAction(),
new InsertRegisterAction(),
};
@ -295,14 +294,95 @@ public class ExEditorKit extends DefaultEditorKit {
}
}
public static class DeletePreviousCharAction extends TextAction {
DeletePreviousCharAction() {
super(DeletePreviousChar);
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private static abstract class DeleteCharAction extends TextAction {
DeleteCharAction(String name) {
super(name);
}
boolean deleteSelection(Document doc, int dot, int mark) throws BadLocationException {
if (dot != mark) {
doc.remove(Math.min(dot, mark), Math.abs(dot - mark));
return true;
}
return false;
}
boolean deleteNextChar(Document doc, int dot) throws BadLocationException {
if (dot < doc.getLength()) {
int delChars = 1;
if (dot < doc.getLength() - 1) {
final String dotChars = doc.getText(dot, 2);
final char c0 = dotChars.charAt(0);
final char c1 = dotChars.charAt(1);
if (c0 >= '\uD800' && c0 <= '\uDBFF' &&
c1 >= '\uDC00' && c1 <= '\uDFFF') {
delChars = 2;
}
}
doc.remove(dot, delChars);
return true;
}
return false;
}
boolean deletePrevChar(Document doc, int dot) throws BadLocationException {
if (dot > 0) {
int delChars = 1;
if (dot > 1) {
final String dotChars = doc.getText(dot - 2, 2);
final char c0 = dotChars.charAt(0);
final char c1 = dotChars.charAt(1);
if (c0 >= '\uD800' && c0 <= '\uDBFF' &&
c1 >= '\uDC00' && c1 <= '\uDFFF') {
delChars = 2;
}
}
doc.remove(dot - delChars, delChars);
return true;
}
return false;
}
}
public static class DeleteNextCharAction extends DeleteCharAction {
DeleteNextCharAction() {
super(deleteNextCharAction);
}
@Override
public void actionPerformed(ActionEvent e) {
final ExTextField target = (ExTextField)getTextComponent(e);
target.saveLastEntry();
try {
final Document doc = target.getDocument();
final Caret caret = target.getCaret();
final int dot = caret.getDot();
final int mark = caret.getMark();
if (!deleteSelection(doc, dot, mark) && !deleteNextChar(doc, dot) && !deletePrevChar(doc, dot)) {
target.cancel();
}
} catch (BadLocationException ex) {
// ignore
}
}
}
public static class DeletePreviousCharAction extends DeleteCharAction {
DeletePreviousCharAction() {
super(deletePrevCharAction);
}
/**
* Invoked when an action occurs.
*/
public void actionPerformed(ActionEvent e) {
ExTextField target = (ExTextField)getTextComponent(e);
target.saveLastEntry();
@ -312,27 +392,10 @@ public class ExEditorKit extends DefaultEditorKit {
Caret caret = target.getCaret();
int dot = caret.getDot();
int mark = caret.getMark();
if (dot != mark) {
doc.remove(Math.min(dot, mark), Math.abs(dot - mark));
}
else if (dot > 0) {
int delChars = 1;
if (dot > 1) {
String dotChars = doc.getText(dot - 2, 2);
char c0 = dotChars.charAt(0);
char c1 = dotChars.charAt(1);
if (c0 >= '\uD800' && c0 <= '\uDBFF' &&
c1 >= '\uDC00' && c1 <= '\uDFFF') {
delChars = 2;
}
if (!deleteSelection(doc, dot, mark) && !deletePrevChar(doc, dot)) {
if (dot == 0 && doc.getLength() == 0) {
target.cancel();
}
doc.remove(dot - delChars, delChars);
}
else if (dot == 0 && doc.getLength() == 0){
target.cancel();
}
}
catch (BadLocationException bl) {
@ -343,7 +406,7 @@ public class ExEditorKit extends DefaultEditorKit {
public static class DeletePreviousWordAction extends TextAction {
DeletePreviousWordAction() {
super(DeletePreviousWord);
super(deletePrevWordAction);
}
/**

View File

@ -52,13 +52,13 @@ public class ExKeyBindings {
new KeyBinding(KeyStroke.getKeyStroke((char)0x05, KeyEvent.CTRL_MASK), ExEditorKit.endLineAction),
new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), ExEditorKit.endLineAction),
new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), ExEditorKit.DeletePreviousChar),
new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_MASK), ExEditorKit.DeletePreviousChar),
new KeyBinding(KeyStroke.getKeyStroke((char)0x08, KeyEvent.CTRL_MASK), ExEditorKit.DeletePreviousChar),
new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), ExEditorKit.deletePrevCharAction),
new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_MASK), ExEditorKit.deletePrevCharAction),
new KeyBinding(KeyStroke.getKeyStroke((char)0x08, KeyEvent.CTRL_MASK), ExEditorKit.deletePrevCharAction),
new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), ExEditorKit.deleteNextCharAction),
new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_MASK), ExEditorKit.DeletePreviousWord),
new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_MASK), ExEditorKit.deletePrevWordAction),
new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_MASK), ExEditorKit.DeleteToCursor),

View File

@ -133,6 +133,11 @@ public class ExTextField extends JTextField {
}
}
/**
* Stores the current text for use in filtering history. Required for scrolling through multiple history entries
*
* Called whenever the text is changed, either by typing, or by special characters altering the text (e.g. Delete)
*/
void saveLastEntry() {
lastEntry = super.getText();
}

View File

@ -112,7 +112,7 @@ class ExEntryTest: VimTestCase() {
assertExOffset(13)
}
fun `test delete character in front of caret`() {
fun `test backspace deletes character in front of caret`() {
typeExInput(":set incsearch<BS>")
assertExText("set incsearc")
@ -120,7 +120,7 @@ class ExEntryTest: VimTestCase() {
assertExText("set incsear")
}
fun `test delete at start of text cancels entry`() {
fun `test backspace at start of text cancels entry`() {
typeExInput(":<BS>")
assertIsDeactivated()
@ -143,12 +143,24 @@ class ExEntryTest: VimTestCase() {
assertIsActive()
}
fun `test delete character under caret`() {
fun `test delete deletes character under caret`() {
typeExInput(":set<Left>")
typeText("<Del>")
assertExText("se")
}
fun `test delete at end of string deletes character to left of caret`() {
typeExInput(":set")
typeText("<Del>")
assertExText("se")
}
fun `test delete with no text cancels entry`() {
typeExInput(":set")
typeText("<Del><Del><Del><Del>")
assertIsDeactivated()
}
fun `test delete word before caret`() {
typeExInput(":set incsearch<C-W>")
assertExText("set ")