bobbylight / AutoComplete

A code completion library for Swing text components, with special support for RSyntaxTextArea.
BSD 3-Clause "New" or "Revised" License
166 stars 55 forks source link

Facing 2 bugs in autocompletion with RSyntaxArea #90

Closed RishonDev closed 1 year ago

RishonDev commented 1 year ago

There are two bugs (In HTML specifically):

(After)

Screenshot 2023-02-26 at 6 12 33 PM

(Just in case if the second one is not a bug I have pasted the code below.)

import java.awt.*;
import javax.swing.*;
import org.fife.ui.autocomplete.*;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rtextarea.RTextScrollPane;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.InputEvent;
import java.util.ArrayList;

public class AutoCompleteDemo extends JFrame {

    public AutoCompleteDemo() {

        JPanel contentPane = new JPanel(new BorderLayout());
        RSyntaxTextArea textArea = new RSyntaxTextArea(20, 60);
        textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
        textArea.setCodeFoldingEnabled(true);
        contentPane.add(new RTextScrollPane(textArea));
        CompletionProvider provider = createCompletionProvider();
        AutoCompletion ac = new AutoCompletion(provider);
        ac.setTriggerKey(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
        ac.setAutoActivationEnabled(true);
        ac.install(textArea);
        setContentPane(contentPane);
        setTitle("AutoComplete Demo");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setLocationRelativeTo(null);

        // Add key listener to trigger autocomplete on key press
        textArea.addKeyListener(new KeyAdapter() {
            public void keyTyped(KeyEvent evt) {
                if (evt.getKeyCode() == KeyEvent.VK_ENTER) {

                }
                else{
                    SwingUtilities.invokeLater(ac::doCompletion);
                }
            }
            public void keyPressed(KeyEvent evt) {

            }
        });
    }

    /**
     * Create a simple provider that adds some Java-related completions.
     */
    private CompletionProvider createCompletionProvider() {
        DefaultCompletionProvider provider = new DefaultCompletionProvider();
        ArrayList<String> suggestions = getSuggestions();
        for(String suggestion: suggestions) {
            provider.addCompletion(new BasicCompletion(provider, suggestion + "</" + suggestion.replaceAll("<", "")));
        }
        provider.addCompletion(new ShorthandCompletion(provider, "$BASE",
                "System.err.println("));

        return provider;

    }
    private ArrayList<String> getSuggestions() {
        ArrayList<String> suggestions = new ArrayList<>();
        suggestions.add("<!DOCTYPE html>");
        suggestions.add("<html>");
        suggestions.add("<head>");
        suggestions.add("<title>");
        suggestions.add("<meta>");
        suggestions.add("<link>");
        suggestions.add("<script>");
        suggestions.add("<style>");
        suggestions.add("<body>");
        suggestions.add("<div>");
        suggestions.add("<span>");
        suggestions.add("<h1>");
        suggestions.add("<h2>");
        suggestions.add("<h3>");
        suggestions.add("<h4>");
        suggestions.add("<h5>");
        suggestions.add("<h6>");
        suggestions.add("<p>");
        suggestions.add("<a>");
        suggestions.add("<img>");
        suggestions.add("<ul>");
        suggestions.add("<ol>");
        suggestions.add("<li");
        suggestions.add("<table>");
        suggestions.add("<tr>");
        suggestions.add("<th></th>");
        suggestions.add("<td></td>");
        suggestions.add("<form></form>");
        suggestions.add("<input>");
        suggestions.add("<textarea>");
        suggestions.add("<button>");
        suggestions.add("<select>");
        suggestions.add("<option>");
        suggestions.add("<label>");
        suggestions.add("<fieldset>");
        suggestions.add("<legend>");
        suggestions.add("<nav>");
        suggestions.add("<header>");
        suggestions.add("<footer>");
        suggestions.add("<aside>");
        suggestions.add("<article>");
        suggestions.add("<section>");
        return suggestions;
    }
    public static void main(String[] args) {
        // Instantiate GUI on the EDT.
        SwingUtilities.invokeLater(() -> {
            try {
                String laf = UIManager.getSystemLookAndFeelClassName();
                UIManager.setLookAndFeel(laf);
            } catch (Exception e) { /* Never happens */ }
            new AutoCompleteDemo().setVisible(true);
        });
    }

}
shuntaochen commented 1 year ago

Use DefaultCompletionProvider provider = new DefaultCompletionProvider(); provider.setAutoActivationRules(true, "."); instead, the keylistener is redundant;

Minenash commented 1 year ago

Hey, I know it's 5 months latter, but I ran into one of the problems you had and found the cause. Specifically,

The auto-completion does not replace the typed-out text

That's because the < is not a valid char to the DefaultCompletionProvider. You can fix this by extending the class and overriding the method:

DefaultCompletionProvider provider = new DefaultCompletionProvider() {
            @Override
            protected boolean isValidChar(char ch) {
                return super.isValidChar(ch) || /*Extra chars here*/;
            }
        };
bobbylight commented 1 year ago

Looks like some kind folks havae pointed out the ways to address these issues :) The CompletionProvider should handle showing and hiding the completion choices list, as well as defines which characters are part of an "identifier" to code-complete. You'll find a few examples of this approach in the sister project RSTALanguageSupport (exmaple for Perl).