Оптимизация кода Java - как я могу оптимизировать эту функцию remove()?

Я делаю пользовательский язык как проект для класса под названием Compilers. Весь проект на Java, с использованием JFlex в качестве моего лексического анализатора и Cup в качестве моего синтаксического анализатора.

Я создал простой текстовый редактор для языка, который в основном состоит из JTextPane, где пользователь может вводить пользовательский код, который будет проанализирован. Этот JTextPane имеет DefaultStyledDocument, используемый для установки атрибутов символов, например, изменения цвета для ключевых слов, комментариев, строк, чисел и т. Д. Для кода (текста) внутри JTextPane.

Вот код, который я использую:

        DefaultStyledDocument doc = new DefaultStyledDocument() {
        @Override
        public void insertString(int offset, String str, AttributeSet a) throws BadLocationException { //cuando se insertan caracteres.
            super.insertString(offset, str, a);
            String text = getText(0, getLength());
            syntax = new SyntaxHighlighter(new java.io.StringReader(text));
            Token val;
            try {
                while ((val = syntax.yylex()) != null) {
                    switch (val.type) {
                        case TokenType.KEYWORD:
                            setCharacterAttributes(val.start, val.length, keyword, true);
                            break;
                        case TokenType.COMMENT:
                            setCharacterAttributes(val.start, val.length, comment, true);
                            break;
                        case TokenType.STRING:
                            setCharacterAttributes(val.start, val.length, string, true);
                            break;
                        case TokenType.FUNCTION:
                            setCharacterAttributes(val.start, val.length, function, true);
                            break;
                        case TokenType.NUMBER:
                            setCharacterAttributes(val.start, val.length, plain, true);
                            break;
                        case TokenType.OPERATOR:
                            setCharacterAttributes(val.start, val.length, operator, true);
                            break;
                        case TokenType.READ:
                            setCharacterAttributes(val.start, val.length, number, true);
                            break;
                        default:
                            setCharacterAttributes(val.start, val.length, plain, true);
                            break;
                    }
                }
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(rootPane, "Oops! Exception triggered\n" + ex.getMessage());
            }
        }

        @Override
        //this is the method I want to optimize
        public void remove(int offs, int len) throws BadLocationException { 
            super.remove(offs, len);
            String text = getText(0, getLength());
            syntax = new SyntaxHighlighter(new java.io.StringReader(text));
            Token val;
            try {
                while ((val = syntax.yylex()) != null) {
                    switch (val.type) {
                        case TokenType.KEYWORD:
                            setCharacterAttributes(val.start, val.length, keyword, true);
                            break;
                        case TokenType.COMMENT:
                            setCharacterAttributes(val.start, val.length, comment, true);
                            break;
                        case TokenType.STRING:
                            setCharacterAttributes(val.start, val.length, string, true);
                            break;
                        case TokenType.FUNCTION:
                            setCharacterAttributes(val.start, val.length, function, true);
                            break;
                        case TokenType.NUMBER:
                            setCharacterAttributes(val.start, val.length, plain, true);
                            break;
                        case TokenType.OPERATOR:
                            setCharacterAttributes(val.start, val.length, operator, true);
                            break;
                        case TokenType.READ:
                            setCharacterAttributes(val.start, val.length, number, true);
                            break;
                        default:
                            setCharacterAttributes(val.start, val.length, plain, true);
                            break;
                    }
                }
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(rootPane, "Oops! Exception triggered\n" + ex.getMessage());
            }
        }
    };

this.codeTextPane.setStyledDocument(doc);

Класс SyntaxHighlighter - это, по сути, лексер (созданный с помощью JFlex), используемый только для поиска определенных фрагментов текста (ключевые слова, строки и т. Д.). Все отлично работает, но...

Эта проблема:

Когда в JTextPane содержится приличное количество текста, нажатие клавиши "Backspace" для удаления текста приводит к запаздыванию программы. Я думаю, что это происходит потому, что SyntaxHighlighter запускается с каждым удаляемым символом, потому что, удерживая нажатой клавишу Backspace, вызывается функция remove() для каждого удаляемого символа. Вставка текста на самом деле не является проблемой, поскольку вы можете либо загрузить код из файла (где весь текст в этом файле будет проанализирован SyntaxHighlighter в целом), либо вы просто не можете набрать достаточно быстро, чтобы заметить задержку.

Есть ли способ, которым я могу оптимизировать это? Спасибо вам всем!

3 ответа

Моим первым инстинктом было бы использовать оконную стратегию. В вашем коде поддерживайте дерево или какую-либо другую структуру, способную представлять автономную область видимости. Затем настройте подсветку синтаксиса и другие части кода, чтобы они работали только с теми частями дерева (или какими-либо другими), которые, как они знают, затронуты.

Абстрактно, у вас могут быть такие отношения:

class
  |
+----------+
method1    method2
              |
           +--------+--------+
           line1    line2    line3

... который позволяет удалить строку в строке 3 в контексте того, что не меняется

В целом этот код кажется структурированным и понятным, я понял его очень быстро. Итак, мое предложение: оставьте это как можно дольше (форсированный принцип открытого-закрытого).

Единственное изменение, которое я бы предложил, это отделить удаление символов от выделения. Это уже упоминалось. Но причина, по которой вы должны это сделать, заключается в следующем: вы сможете отложить подсветку синтаксиса до тех пор, пока пользователь не удалит часть символов. Таким образом, подсветка синтаксиса не будет срабатывать каждый раз, когда вы удаляете только один символ.

Я думаю, что вы должны разбить основной текст на синтаксические единицы, а затем применять подсветку синтаксиса только к измененным синтаксическим единицам. Основной проблемой является разбор и идентификация измененного блока.

Как упоминал предыдущий автор, выделение подсветки синтаксиса в отдельном потоке также улучшит производительность.

Эти изменения не тривиальны, но возможны.

Определить поле класса javax.swing.Timer syntaxTimer,

На каждой insert() или же remove() проверить, является ли syntaxTimer является нулевым или нет.

Если это ноль, создайте syntaxTimer экземпляр с задержкой 500 мс (может быть 300 или 1000, как вы хотите) и запустить syntaxTimer, Если нет, просто пропустите инициализацию таймера, потому что он уже инициализирован.

Когда syntaxTimer"s actionPerformed() называется сделать свой SyntaxHighlighter связанная логика и очистить syntaxTimer (остановите это и установите syntaxTimer=null).

Другие вопросы по тегам