From 99a511f60e3cd4d201c802476ac4970470ba2dd8 Mon Sep 17 00:00:00 2001 From: bobbylight Date: Sun, 9 Aug 2026 10:27:48 -0400 Subject: [PATCH] fix: use DocumentEvent offset, not caret position, for auto-activation checks isAutoActivateOkay() relied on JTextComponent#getCaretPosition() to find the just-typed character, but the caret is not guaranteed to be updated yet when the insertUpdate() DocumentListener callback fires. This made auto-activation depend on incidental document listener ordering, breaking when a component's Document was swapped (e.g. via TextEditorPane.load()), as reported in #77. isAutoActivateOkay() now takes the inserted character's offset explicitly, sourced from DocumentEvent#getOffset() in AutoCompletion's insertUpdate() listener, which is authoritative regardless of listener order. Also adds the PR template. Fixes #77 --- .github/pull_request_template.md | 31 +++++++++++++++++++ .../fife/ui/autocomplete/AutoCompletion.java | 2 +- .../ui/autocomplete/CompletionProvider.java | 9 ++++-- .../autocomplete/CompletionProviderBase.java | 4 +-- .../LanguageAwareCompletionProvider.java | 4 +-- 5 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..e685822 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,31 @@ +## Summary + + + +## Details + +<-- +Start with 1-2 sentences describing *what* has changed, e.g. the "how" the +change was implemented. If the change set is small and straightforward, this +is all that's needed in this section. + +If it's a more complex change, or modifies a lot of files, also include a +bulleted list that highlights important changes in the PR. Note this doesn't +have to be a huge list, but should include anything noteworthy or that should +not be missed by a reviewer. +--> + +## Test plan + +<-- +Add any manual tests that should be performed to verify this fix before +merging. If there are none, this entire section can be omitted. +--> diff --git a/AutoComplete/src/main/java/org/fife/ui/autocomplete/AutoCompletion.java b/AutoComplete/src/main/java/org/fife/ui/autocomplete/AutoCompletion.java index 36eb615..a2a7032 100644 --- a/AutoComplete/src/main/java/org/fife/ui/autocomplete/AutoCompletion.java +++ b/AutoComplete/src/main/java/org/fife/ui/autocomplete/AutoCompletion.java @@ -1367,7 +1367,7 @@ public void insertUpdate(DocumentEvent e) { justInserted = false; if (isAutoCompleteEnabled() && isAutoActivationEnabled() && e.getLength() == 1) { - if (textComponent != null && provider.isAutoActivateOkay(textComponent)) { + if (textComponent != null && provider.isAutoActivateOkay(textComponent, e.getOffset())) { timer.restart(); justInserted = true; } diff --git a/AutoComplete/src/main/java/org/fife/ui/autocomplete/CompletionProvider.java b/AutoComplete/src/main/java/org/fife/ui/autocomplete/CompletionProvider.java index 7f7355d..95fb96d 100644 --- a/AutoComplete/src/main/java/org/fife/ui/autocomplete/CompletionProvider.java +++ b/AutoComplete/src/main/java/org/fife/ui/autocomplete/CompletionProvider.java @@ -154,16 +154,21 @@ public interface CompletionProvider { /** * This method is called if auto-activation is enabled in the parent * {@link AutoCompletion} after the user types a single character. This - * provider should check the text at the current caret position of the + * provider should check the text at the offset just inserted into the * text component, and decide whether auto-activation would be appropriate * here. For example, a CompletionProvider for Java might * want to return true for this method only if the last * character typed was a '.'. * * @param tc The text component. + * @param offs The offset of the character just inserted into the text + * component. This is passed explicitly, rather than being + * derived from the text component's caret position, since the + * caret is not guaranteed to have been updated yet when this + * method is called. * @return Whether auto-activation would be appropriate. */ - boolean isAutoActivateOkay(JTextComponent tc); + boolean isAutoActivateOkay(JTextComponent tc, int offs); /** diff --git a/AutoComplete/src/main/java/org/fife/ui/autocomplete/CompletionProviderBase.java b/AutoComplete/src/main/java/org/fife/ui/autocomplete/CompletionProviderBase.java index df6387e..9a6ba04 100644 --- a/AutoComplete/src/main/java/org/fife/ui/autocomplete/CompletionProviderBase.java +++ b/AutoComplete/src/main/java/org/fife/ui/autocomplete/CompletionProviderBase.java @@ -170,11 +170,11 @@ public CompletionProvider getParent() { @Override - public boolean isAutoActivateOkay(JTextComponent tc) { + public boolean isAutoActivateOkay(JTextComponent tc, int offs) { Document doc = tc.getDocument(); char ch = 0; try { - doc.getText(tc.getCaretPosition(), 1, s); + doc.getText(offs, 1, s); ch = s.first(); } catch (BadLocationException ble) { // Never happens ble.printStackTrace(); diff --git a/AutoComplete/src/main/java/org/fife/ui/autocomplete/LanguageAwareCompletionProvider.java b/AutoComplete/src/main/java/org/fife/ui/autocomplete/LanguageAwareCompletionProvider.java index 2f43854..905a3fb 100644 --- a/AutoComplete/src/main/java/org/fife/ui/autocomplete/LanguageAwareCompletionProvider.java +++ b/AutoComplete/src/main/java/org/fife/ui/autocomplete/LanguageAwareCompletionProvider.java @@ -303,9 +303,9 @@ public CompletionProvider getStringCompletionProvider() { @Override - public boolean isAutoActivateOkay(JTextComponent tc) { + public boolean isAutoActivateOkay(JTextComponent tc, int offs) { CompletionProvider provider = getProviderFor(tc); - return provider != null && provider.isAutoActivateOkay(tc); + return provider != null && provider.isAutoActivateOkay(tc, offs); }