| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.netbeans.modules.php.editor.csl; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Set; |
| import javax.swing.text.BadLocationException; |
| import javax.swing.text.Document; |
| import javax.swing.text.JTextComponent; |
| import org.netbeans.modules.csl.api.KeystrokeHandler; |
| import org.netbeans.modules.csl.api.OffsetRange; |
| import org.netbeans.modules.csl.spi.ParserResult; |
| import org.netbeans.modules.php.editor.parser.PHPParseResult; |
| import org.netbeans.modules.php.editor.parser.astnodes.ASTNode; |
| import org.netbeans.modules.php.editor.parser.astnodes.visitors.DefaultVisitor; |
| |
| /** |
| * Provide bracket completion for Ruby. This class provides three broad |
| * services: - Identifying matching pairs (parentheses, begin/end pairs etc.), |
| * which is used both for highlighting in the IDE (when the caret is on for |
| * example an if statement, the corresponding end token is highlighted), and |
| * navigation where you can jump between matching pairs. - Automatically |
| * inserting corresponding pairs when you insert a character. For example, if |
| * you insert a single quote, a corresponding ending quote is inserted - unless |
| * you're typing "over" the existing quote (you should be able to type foo = |
| * "hello" without having to arrow over the second quote that was inserted after |
| * you typed the first one). - Automatically adjusting indentation in some |
| * scenarios, for example when you type the final "d" in "end" - and readjusting |
| * it back to the original indentation if you continue typing something other |
| * than "end", e.g. "endian". |
| * |
| * The logic around inserting matching ""'s is heavily based on the Java editor |
| * implementation, and probably should be rewritten to be Ruby oriented. One |
| * thing they did is process the characters BEFORE the character has been |
| * inserted into the document. This has some advantages - it's easy to detect |
| * whether you're typing in the middle of a string since the token hierarchy has |
| * not been updated yet. On the other hand, it makes it hard to identify whether |
| * some characters are what we expect - is a "/" truly a regexp starter or |
| * something else? The Ruby lexer has lots of logic and state to determine this. |
| * I think it would be better to switch to after-insert logic for this. |
| * |
| * @todo Match braces within literal strings, as in #{} |
| * @todo Match || in the argument list of blocks? do { |foo| etc. } |
| * @todo I'm currently highlighting the indentation tokens (else, elsif, ensure, |
| * etc.) by finding the corresponding begin. For "illegal" tokens, e.g. def foo; |
| * else; end; this means I'll show "def" as the matching token for else, which |
| * is wrong. I should make the "indentation tokens" list into a map and |
| * associate them with their corresponding tokens, such that an else is only |
| * lined up with an if, etc. |
| * @todo Pressing newline in a parameter list doesn't work well if it's on a |
| * blockdefining line - e.g. def foo(a,b => it will insert the end BEFORE the |
| * closing paren! |
| * @todo Pressing space in a comment beyond the textline limit should wrap text? |
| * http://ruby.netbeans.org/issues/show_bug.cgi?id=11553 |
| * @todo Make ast-selection pick up =begin/=end documentation blocks |
| * |
| * @author Tor Norbye |
| */ |
| public class PHPBracketCompleter implements KeystrokeHandler { |
| |
| public PHPBracketCompleter() { |
| } |
| |
| @Override |
| public int beforeBreak(Document document, int offset, JTextComponent target) |
| throws BadLocationException { |
| return -1; |
| } |
| |
| @Override |
| public boolean beforeCharInserted(Document document, int caretOffset, JTextComponent target, char ch) |
| throws BadLocationException { |
| return false; |
| } |
| |
| @Override |
| public boolean afterCharInserted(Document document, int dotPos, JTextComponent target, char ch) |
| throws BadLocationException { |
| return false; |
| } |
| |
| @Override |
| public OffsetRange findMatching(Document document, int offset /*, boolean simpleSearch*/) { |
| return OffsetRange.NONE; |
| } |
| |
| @Override |
| public boolean charBackspaced(Document document, int dotPos, JTextComponent target, char ch) |
| throws BadLocationException { |
| return false; |
| } |
| |
| @Override |
| public List<OffsetRange> findLogicalRanges(ParserResult info, final int caretOffset) { |
| final Set<OffsetRange> ranges = new LinkedHashSet<>(); |
| final DefaultVisitor pathVisitor = new DefaultVisitor() { |
| @Override |
| public void scan(ASTNode node) { |
| if (node != null && node.getStartOffset() <= caretOffset && caretOffset <= node.getEndOffset()) { |
| ranges.add(new OffsetRange(node.getStartOffset(), node.getEndOffset())); |
| super.scan(node); |
| } |
| } |
| }; |
| if (info instanceof PHPParseResult) { |
| pathVisitor.scan(((PHPParseResult) info).getProgram()); |
| } |
| final ArrayList<OffsetRange> retval = new ArrayList<>(ranges); |
| Collections.reverse(retval); |
| return retval; |
| } |
| |
| // UGH - this method has gotten really ugly after successive refinements based on unit tests - consider cleaning up |
| @Override |
| public int getNextWordOffset(Document document, int offset, boolean reverse) { |
| return -1; |
| } |
| } |