Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Emacs key bindings #6037

Merged
merged 20 commits into from
Nov 6, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/main/java/org/jabref/JabRefGUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.stage.Screen;
import javafx.stage.Stage;

Expand All @@ -19,6 +20,7 @@
import org.jabref.gui.icon.IconTheme;
import org.jabref.gui.importer.ParserResultWarningDialog;
import org.jabref.gui.importer.actions.OpenDatabaseAction;
import org.jabref.gui.keyboard.EmacsKeyBindings;
import org.jabref.gui.shared.SharedDatabaseUIManager;
import org.jabref.logic.autosaveandbackup.BackupManager;
import org.jabref.logic.importer.OpenDatabase;
Expand Down Expand Up @@ -87,6 +89,12 @@ private void openWindow(Stage mainStage) {
root.getChildren().add(JabRefGUI.mainFrame);

Scene scene = new Scene(root, 800, 800);

//Handle Emacs key bindings
calixtus marked this conversation as resolved.
Show resolved Hide resolved
scene.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
EmacsKeyBindings.executeEmacs(scene, event);
});

Globals.getThemeLoader().installCss(scene, Globals.prefs);
mainStage.setTitle(JabRefFrame.FRAME_TITLE);
mainStage.getIcons().addAll(IconTheme.getLogoSetFX());
Expand Down
103 changes: 103 additions & 0 deletions src/main/java/org/jabref/gui/keyboard/EmacsKeyBindings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package org.jabref.gui.keyboard;

import java.util.Optional;

import javafx.scene.Scene;
import javafx.scene.control.TextInputControl;
import javafx.scene.input.KeyEvent;

import org.jabref.Globals;
import org.jabref.logic.util.strings.EmacsStringManipulator;
import org.jabref.model.util.ResultingEmacsState;
import org.jabref.preferences.JabRefPreferences;

public class EmacsKeyBindings {

public static void executeEmacs(Scene scene, KeyEvent event) {
boolean EmacsFlag = Globals.prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS);
calixtus marked this conversation as resolved.
Show resolved Hide resolved
if (EmacsFlag && scene.focusOwnerProperty().get() instanceof TextInputControl) {
boolean CAFlag = Globals.prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS_REBIND_CA);
boolean CFFlag = Globals.prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS_REBIND_CF);
boolean CNFlag = Globals.prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS_REBIND_CN);
boolean AUFlag = Globals.prefs.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS_REBIND_AU);
calixtus marked this conversation as resolved.
Show resolved Hide resolved

KeyBindingRepository keyBindingRepository = Globals.getKeyPrefs();
TextInputControl focusedTextField = (TextInputControl) scene.focusOwnerProperty().get();
Optional<KeyBinding> keyBinding = keyBindingRepository.mapToKeyBinding(event);
if (keyBinding.isPresent()) {
calixtus marked this conversation as resolved.
Show resolved Hide resolved
if (keyBinding.get().equals(KeyBinding.EMACS_DELETE)) {
focusedTextField.deletePreviousChar();
event.consume();
calixtus marked this conversation as resolved.
Show resolved Hide resolved
} else if (keyBinding.get().equals(KeyBinding.EMACS_BACKWARD)) {
focusedTextField.backward();
event.consume();
} else if (CFFlag && keyBinding.get().equals(KeyBinding.EMACS_FORWARD)) {
focusedTextField.forward();
event.consume();
} else if (CAFlag && keyBinding.get().equals(KeyBinding.EMACS_BEGINNING)) {
focusedTextField.home();
event.consume();
} else if (keyBinding.get().equals(KeyBinding.EMACS_END)) {
focusedTextField.end();
event.consume();
} else if (keyBinding.get().equals(KeyBinding.EMACS_BEGINNING_DOC)) {
focusedTextField.home();
event.consume();
} else if (keyBinding.get().equals(KeyBinding.EMACS_END_DOC)) {
focusedTextField.end();
event.consume();
} else if (keyBinding.get().equals(KeyBinding.EMACS_UP)) {
focusedTextField.home();
event.consume();
} else if (CNFlag && keyBinding.get().equals(KeyBinding.EMACS_DOWN)) {
focusedTextField.end();
event.consume();
} else if (keyBinding.get().equals(KeyBinding.EMACS_CAPITALIZE)) {
int pos = focusedTextField.getCaretPosition();
String text = focusedTextField.getText(0, focusedTextField.getText().length());
ResultingEmacsState res = EmacsStringManipulator.capitalize(pos, text);
focusedTextField.setText(res.text);
focusedTextField.positionCaret(res.caretPos);
event.consume();
}
else if (keyBinding.get().equals(KeyBinding.EMACS_LOWERCASE)) {
calixtus marked this conversation as resolved.
Show resolved Hide resolved
int pos = focusedTextField.getCaretPosition();
String text = focusedTextField.getText(0, focusedTextField.getText().length());
ResultingEmacsState res = EmacsStringManipulator.lowercase(pos, text);
focusedTextField.setText(res.text);
focusedTextField.positionCaret(res.caretPos);
event.consume();
}
else if (AUFlag && keyBinding.get().equals(KeyBinding.EMACS_UPPERCASE)) {
int pos = focusedTextField.getCaretPosition();
String text = focusedTextField.getText(0, focusedTextField.getText().length());
ResultingEmacsState res = EmacsStringManipulator.uppercase(pos, text);
focusedTextField.setText(res.text);
focusedTextField.positionCaret(res.caretPos);
event.consume();
}
else if (keyBinding.get().equals(KeyBinding.EMACS_KILLLINE)) {
int pos = focusedTextField.getCaretPosition();
focusedTextField.setText(focusedTextField.getText(0, pos));
focusedTextField.positionCaret(pos);
event.consume();
} else if (keyBinding.get().equals(KeyBinding.EMACS_KILLWORD)) {
int pos = focusedTextField.getCaretPosition();
String text = focusedTextField.getText(0, focusedTextField.getText().length());
ResultingEmacsState res = EmacsStringManipulator.killWord(pos, text);
focusedTextField.setText(res.text);
focusedTextField.positionCaret(res.caretPos);
event.consume();
}
else if (keyBinding.get().equals(KeyBinding.EMACS_BACKWARDKILLWORD)) {
int pos = focusedTextField.getCaretPosition();
String text = focusedTextField.getText(0, focusedTextField.getText().length());
ResultingEmacsState res = EmacsStringManipulator.backwardKillWord(pos, text);
focusedTextField.setText(res.text);
focusedTextField.positionCaret(res.caretPos);
event.consume();
}
}
}
}
}
15 changes: 15 additions & 0 deletions src/main/java/org/jabref/gui/keyboard/KeyBinding.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,21 @@
import org.jabref.logic.l10n.Localization;

public enum KeyBinding {
EMACS_DELETE("Emacs delete", Localization.lang("Delete text"), "ctrl+D", KeyBindingCategory.EDIT),
calixtus marked this conversation as resolved.
Show resolved Hide resolved
EMACS_BACKWARD("Emacs move caret left", Localization.lang("Move caret left"), "ctrl+B", KeyBindingCategory.EDIT),
EMACS_FORWARD("Emacs move caret right", Localization.lang("Move caret right"), "ctrl+F", KeyBindingCategory.EDIT),
EMACS_BEGINNING("Emacs move caret to beginning", Localization.lang("Move caret to beginning"), "ctrl+A", KeyBindingCategory.EDIT),
EMACS_END("Emacs move caret to end", Localization.lang("Move caret to end"), "ctrl+E", KeyBindingCategory.EDIT),
EMACS_BEGINNING_DOC("Emacs move caret to beginning of the document", Localization.lang("Move the caret to the beginning of the document"), "alt+LESS", KeyBindingCategory.EDIT),
EMACS_END_DOC("Emacs move caret to end of the document", Localization.lang("Move the caret to the end of the document"), "alt+shift+LESS", KeyBindingCategory.EDIT),
EMACS_UP("Emacs move caret up", Localization.lang("Move the caret up"), "ctrl+P", KeyBindingCategory.EDIT),
EMACS_DOWN("Emacs move caret down", Localization.lang("Move the caret down"), "ctrl+N", KeyBindingCategory.EDIT),
EMACS_CAPITALIZE("Emacs capitalize next word", Localization.lang("Capitalize the next word"), "alt+C", KeyBindingCategory.EDIT),
EMACS_LOWERCASE("Emacs lowercase next word", Localization.lang("Make all characters in the next word lowercase"), "alt+L", KeyBindingCategory.EDIT),
EMACS_UPPERCASE("Emacs uppercase next word", Localization.lang("Make all characters in the next word uppercase"), "alt+U", KeyBindingCategory.EDIT),
EMACS_KILLLINE("Emacs remove line", Localization.lang("Remove words after the cursor"), "ctrl+K", KeyBindingCategory.EDIT),
EMACS_KILLWORD("Emacs remove the next word", Localization.lang("Remove the next word in the line"), "alt+D", KeyBindingCategory.EDIT),
EMACS_BACKWARDKILLWORD("Emacs remove the previous word", Localization.lang("Remove the previous word in the line"), "alt+DELETE", KeyBindingCategory.EDIT),

ABBREVIATE("Abbreviate", Localization.lang("Abbreviate journal names"), "ctrl+alt+A", KeyBindingCategory.TOOLS),
AUTOGENERATE_BIBTEX_KEYS("Autogenerate BibTeX keys", Localization.lang("Autogenerate BibTeX keys"), "ctrl+G", KeyBindingCategory.QUALITY),
Expand Down
22 changes: 21 additions & 1 deletion src/main/java/org/jabref/gui/preferences/EntryEditorTab.fxml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,27 @@
</CheckBox>
<CheckBox fx:id="enableLatexCitationsTab" text="%Show 'LaTeX Citations' tab"/>
<CheckBox fx:id="enableValidation" text="%Show validation messages"/>

<CheckBox fx:id="enableEmacsKeyBindings" text="%Use Emacs key bindings"/>
<CheckBox fx:id="enableEmacsRebindCA" text="%Rebind C-a, too" disable="${!enableEmacsKeyBindings.selected}">
<padding>
<Insets left="20.0"/>
</padding>
</CheckBox>
<CheckBox fx:id="enableEmacsRebindCF" text="%Rebind C-f, too" disable="${!enableEmacsKeyBindings.selected}">
<padding>
<Insets left="20.0"/>
</padding>
</CheckBox>
<CheckBox fx:id="enableEmacsRebindCN" text="%Rebind C-n, too" disable="${!enableEmacsKeyBindings.selected}">
<padding>
<Insets left="20.0"/>
</padding>
</CheckBox>
<CheckBox fx:id="enableEmacsRebindAU" text="%Rebind A-u, too" disable="${!enableEmacsKeyBindings.selected}">
<padding>
<Insets left="20.0"/>
</padding>
</CheckBox>
<Label styleClass="sectionHeader" text="%Autocompletion"/>
<CheckBox fx:id="enableAutoComplete" text="%Use autocompletion"/>
<VBox spacing="10.0">
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/org/jabref/gui/preferences/EntryEditorTabView.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ public class EntryEditorTabView extends AbstractPreferenceTabView<EntryEditorTab
@FXML private CheckBox enableLatexCitationsTab;
@FXML private CheckBox enableValidation;
@FXML private CheckBox enableAutoComplete;
@FXML private CheckBox enableEmacsKeyBindings;
@FXML private CheckBox enableEmacsRebindCA;
@FXML private CheckBox enableEmacsRebindCF;
@FXML private CheckBox enableEmacsRebindCN;
@FXML private CheckBox enableEmacsRebindAU;
@FXML private TextField autoCompleteFields;
@FXML private RadioButton autoCompleteFirstLast;
@FXML private RadioButton autoCompleteLastFirst;
Expand Down Expand Up @@ -48,6 +53,11 @@ public void initialize () {
enableLatexCitationsTab.selectedProperty().bindBidirectional(viewModel.enableLatexCitationsTabProperty());
enableValidation.selectedProperty().bindBidirectional(viewModel.enableValidationProperty());
enableAutoComplete.selectedProperty().bindBidirectional(viewModel.enableAutoCompleteProperty());
enableEmacsKeyBindings.selectedProperty().bindBidirectional(viewModel.enableEmacsKeyBindingsProperty());
enableEmacsRebindCA.selectedProperty().bindBidirectional(viewModel.enableEmacsRebindCAProperty());
enableEmacsRebindCF.selectedProperty().bindBidirectional(viewModel.enableEmacsRebindCFProperty());
enableEmacsRebindCN.selectedProperty().bindBidirectional(viewModel.enableEmacsRebindCNProperty());
enableEmacsRebindAU.selectedProperty().bindBidirectional(viewModel.enableEmacsRebindAUProperty());
autoCompleteFields.textProperty().bindBidirectional(viewModel.autoCompleteFieldsProperty());
autoCompleteFirstLast.selectedProperty().bindBidirectional(viewModel.autoCompleteFirstLastProperty());
autoCompleteLastFirst.selectedProperty().bindBidirectional(viewModel.autoCompleteLastFirstProperty());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public class EntryEditorTabViewModel implements PreferenceTabViewModel {
private final BooleanProperty firstNameModeAbbreviatedProperty = new SimpleBooleanProperty();
private final BooleanProperty firstNameModeFullProperty = new SimpleBooleanProperty();
private final BooleanProperty firstNameModeBothProperty = new SimpleBooleanProperty();
private final BooleanProperty enableEmacsKeyBindingsProperty = new SimpleBooleanProperty();
private final BooleanProperty enableEmacsRebindCAProperty = new SimpleBooleanProperty();
private final BooleanProperty enableEmacsRebindCFProperty = new SimpleBooleanProperty();
private final BooleanProperty enableEmacsRebindCNProperty = new SimpleBooleanProperty();
private final BooleanProperty enableEmacsRebindAUProperty = new SimpleBooleanProperty();

private AutoCompletePreferences autoCompletePreferences;

Expand All @@ -52,6 +57,11 @@ public void setValues() {
acceptRecommendationsProperty.setValue(preferences.getBoolean(JabRefPreferences.ACCEPT_RECOMMENDATIONS));
enableLatexCitationsTabProperty.setValue(preferences.getBoolean(JabRefPreferences.SHOW_LATEX_CITATIONS));
enableValidationProperty.setValue(preferences.getBoolean(JabRefPreferences.VALIDATE_IN_ENTRY_EDITOR));
enableEmacsKeyBindingsProperty.setValue(preferences.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS));
enableEmacsRebindCAProperty.setValue(preferences.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS_REBIND_CA));
enableEmacsRebindCFProperty.setValue(preferences.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS_REBIND_CF));
enableEmacsRebindCNProperty.setValue(preferences.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS_REBIND_CN));
enableEmacsRebindAUProperty.setValue(preferences.getBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS_REBIND_AU));
enableAutoCompleteProperty.setValue(autoCompletePreferences.shouldAutoComplete());
autoCompleteFieldsProperty.setValue(autoCompletePreferences.getCompleteNamesAsString());

Expand Down Expand Up @@ -84,6 +94,11 @@ public void storeSettings() {
preferences.putBoolean(JabRefPreferences.ACCEPT_RECOMMENDATIONS, acceptRecommendationsProperty.getValue());
preferences.putBoolean(JabRefPreferences.SHOW_LATEX_CITATIONS, enableLatexCitationsTabProperty.getValue());
preferences.putBoolean(JabRefPreferences.VALIDATE_IN_ENTRY_EDITOR, enableValidationProperty.getValue());
preferences.putBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS, enableEmacsKeyBindingsProperty.getValue());
preferences.putBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS_REBIND_CA, enableEmacsRebindCAProperty.getValue());
preferences.putBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS_REBIND_CF, enableEmacsRebindCFProperty.getValue());
preferences.putBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS_REBIND_CN, enableEmacsRebindCNProperty.getValue());
preferences.putBoolean(JabRefPreferences.EDITOR_EMACS_KEYBINDINGS_REBIND_AU, enableEmacsRebindAUProperty.getValue());

autoCompletePreferences.setShouldAutoComplete(enableAutoCompleteProperty.getValue());
autoCompletePreferences.setCompleteNames(autoCompleteFieldsProperty.getValue());
Expand Down Expand Up @@ -148,4 +163,15 @@ public List<String> getRestartWarnings() {
public BooleanProperty firstNameModeFullProperty() { return firstNameModeFullProperty; }

public BooleanProperty firstNameModeBothProperty() { return firstNameModeBothProperty; }

public BooleanProperty enableEmacsKeyBindingsProperty() { return enableEmacsKeyBindingsProperty; }

public BooleanProperty enableEmacsRebindCAProperty() { return enableEmacsRebindCAProperty; }

public BooleanProperty enableEmacsRebindCFProperty() { return enableEmacsRebindCFProperty; }

public BooleanProperty enableEmacsRebindCNProperty() { return enableEmacsRebindCNProperty; }

public BooleanProperty enableEmacsRebindAUProperty() { return enableEmacsRebindAUProperty; }
}

Loading