[autocomplete] 87/143: Starting work on TemplateCompletions - allows completions for parameterized boilerplate code - for-loops, etc.
Benjamin Mesing
ben at alioth.debian.org
Sat Oct 19 12:53:23 UTC 2013
This is an automated email from the git hooks/post-receive script.
ben pushed a commit to branch master
in repository autocomplete.
commit ff7db970571a3b5f306efd94bea5092198da5aeb
Author: bobbylight <robert at fifesoft.com>
Date: Sun Jun 17 17:33:03 2012 +0000
Starting work on TemplateCompletions - allows completions for parameterized boilerplate code - for-loops, etc.
---
.../fife/ui/autocomplete/FunctionCompletion.java | 15 +-
.../ui/autocomplete/ParameterizedCompletion.java | 37 +-
.../ParameterizedCompletionChoicesWindow.java | 4 +
.../ParameterizedCompletionDescriptionToolTip.java | 376 ++++++++++++++++----
.../ParameterizedCompletionInsertionInfo.java | 67 +++-
src/org/fife/ui/autocomplete/SizeGrip.java | 3 -
.../fife/ui/autocomplete/TemplateCompletion.java | 213 ++++++++---
src/org/fife/ui/autocomplete/TemplatePiece.java | 63 ++++
8 files changed, 647 insertions(+), 131 deletions(-)
diff --git a/src/org/fife/ui/autocomplete/FunctionCompletion.java b/src/org/fife/ui/autocomplete/FunctionCompletion.java
index 9f9b13e..427d146 100644
--- a/src/org/fife/ui/autocomplete/FunctionCompletion.java
+++ b/src/org/fife/ui/autocomplete/FunctionCompletion.java
@@ -147,7 +147,8 @@ public class FunctionCompletion extends VariableCompletion
public ParameterizedCompletionInsertionInfo getInsertionInfo(
- JTextComponent tc, boolean addParamStartList) {
+ JTextComponent tc, boolean addParamStartList,
+ boolean replaceTabsWithSpaces) {
ParameterizedCompletionInsertionInfo info =
new ParameterizedCompletionInsertionInfo();
@@ -163,8 +164,10 @@ public class FunctionCompletion extends VariableCompletion
// this tool tip.
int minPos = dot;
Position maxPos = null;
+ int defaultEndOffs = -1;
try {
- maxPos = tc.getDocument().createPosition(dot-sb.length());
+ maxPos = tc.getDocument().createPosition(dot-sb.length()+1);
+ defaultEndOffs = dot-sb.length();
} catch (BadLocationException ble) {
ble.printStackTrace(); // Never happens
}
@@ -192,7 +195,13 @@ public class FunctionCompletion extends VariableCompletion
}
}
sb.append(getProvider().getParameterListEnd());
-
+ int endOffs = dot + sb.length();
+ if (addParamStartList) {
+ endOffs -= 1;//getProvider().getParameterListStart().length();
+ }
+ info.addReplacementLocation(endOffs, endOffs); // offset after function
+ info.setDefaultEndOffs(endOffs);
+
int selectionEnd = paramCount>0 ? (dot+firstParamLen) : dot;
info.setInitialSelection(dot, selectionEnd);
info.setTextToInsert(sb.toString());
diff --git a/src/org/fife/ui/autocomplete/ParameterizedCompletion.java b/src/org/fife/ui/autocomplete/ParameterizedCompletion.java
index 1d995f0..acd674f 100644
--- a/src/org/fife/ui/autocomplete/ParameterizedCompletion.java
+++ b/src/org/fife/ui/autocomplete/ParameterizedCompletion.java
@@ -50,7 +50,8 @@ public interface ParameterizedCompletion extends Completion {
public ParameterizedCompletionInsertionInfo getInsertionInfo(
- JTextComponent tc, boolean addParamStartList);
+ JTextComponent tc, boolean addParamStartList,
+ boolean replaceTabsWithSpaces);
/**
@@ -64,6 +65,7 @@ public interface ParameterizedCompletion extends Completion {
private String name;
private Object type;
private String desc;
+ private boolean isEndParam;
/**
* Constructor.
@@ -77,8 +79,30 @@ public interface ParameterizedCompletion extends Completion {
* @param name The name of the parameter.
*/
public Parameter(Object type, String name) {
+ this(type, name, false);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param type The type of this parameter. This may be
+ * <code>null</code> for languages without specific types,
+ * dynamic typing, etc. Usually you'll pass a String for this
+ * value, but you may pass any object representing a type in
+ * your language, as long as its <code>toString()</code> method
+ * returns a string representation of the type.
+ * @param name The name of the parameter.
+ * @param endParam Whether this parameter is an "ending parameter;"
+ * that is, whether this parameter is at a logical "ending
+ * point" in the completion text. If the user types in a
+ * parameter that is an ending point, parameter completion mode
+ * terminates. Set this to <code>true</code> for a trailing
+ * parameter after a function call's closing ')', for example.
+ */
+ public Parameter(Object type, String name, boolean endParam) {
this.name = name;
this.type = type;
+ this.isEndParam = endParam;
}
public String getDescription() {
@@ -107,6 +131,17 @@ public interface ParameterizedCompletion extends Completion {
return type;
}
+ /**
+ * @return Whether this parameter is an "ending parameter;"
+ * that is, whether this parameter is at a logical "ending
+ * point" in the completion text. If the user types in a
+ * parameter that is an ending point, parameter completion mode
+ * terminates.
+ */
+ public boolean isEndParam() {
+ return isEndParam;
+ }
+
public void setDescription(String desc) {
this.desc = desc;
}
diff --git a/src/org/fife/ui/autocomplete/ParameterizedCompletionChoicesWindow.java b/src/org/fife/ui/autocomplete/ParameterizedCompletionChoicesWindow.java
index cd553cf..31f21e8 100644
--- a/src/org/fife/ui/autocomplete/ParameterizedCompletionChoicesWindow.java
+++ b/src/org/fife/ui/autocomplete/ParameterizedCompletionChoicesWindow.java
@@ -280,6 +280,10 @@ public class ParameterizedCompletionChoicesWindow extends JWindow {
}
+ else {
+ setVisible(false);
+ }
+
}
diff --git a/src/org/fife/ui/autocomplete/ParameterizedCompletionDescriptionToolTip.java b/src/org/fife/ui/autocomplete/ParameterizedCompletionDescriptionToolTip.java
index 677c2f7..47a1e48 100644
--- a/src/org/fife/ui/autocomplete/ParameterizedCompletionDescriptionToolTip.java
+++ b/src/org/fife/ui/autocomplete/ParameterizedCompletionDescriptionToolTip.java
@@ -20,6 +20,7 @@ import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
@@ -34,6 +35,9 @@ import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Highlighter;
@@ -41,7 +45,13 @@ import javax.swing.text.JTextComponent;
import javax.swing.text.Position;
import javax.swing.text.Highlighter.Highlight;
+import org.fife.ui.autocomplete.ParameterizedCompletion.Parameter;
+import org.fife.ui.autocomplete.ParameterizedCompletionInsertionInfo.ReplacementCopy;
+import org.fife.ui.rsyntaxtextarea.DocumentRange;
import org.fife.ui.rsyntaxtextarea.PopupWindowDecorator;
+import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
+import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
+import org.fife.ui.rtextarea.ChangeableHighlightPainter;
/**
@@ -63,11 +73,17 @@ class ParameterizedCompletionDescriptionToolTip {
*/
Highlighter.HighlightPainter p;
+ Highlighter.HighlightPainter paramCopyP;
+
/**
* The tags for the highlights around parameters.
*/
List tags;
+ private List paramCopyInfos;
+
+ private transient boolean ignoringDocumentEvents;
+
/**
* The parent AutoCompletion instance.
*/
@@ -100,6 +116,8 @@ class ParameterizedCompletionDescriptionToolTip {
*/
private Position maxPos; // Moves with text inserted.
+ private Position defaultEndOffs;
+
/**
* A small popup window giving likely choices for parameterized completions.
*/
@@ -158,7 +176,7 @@ class ParameterizedCompletionDescriptionToolTip {
descLabel = new JLabel();
descLabel.setBorder(BorderFactory.createCompoundBorder(
- BorderFactory.createLineBorder(Color.BLACK),
+ TipUtil.getToolTipBorder(),
BorderFactory.createEmptyBorder(2, 5, 2, 5)));
descLabel.setOpaque(true);
descLabel.setBackground(TipUtil.getToolTipBackground());
@@ -185,7 +203,9 @@ class ParameterizedCompletionDescriptionToolTip {
listener = new Listener();
p = new OutlineHighlightPainter(Color.GRAY);
+ paramCopyP = new ChangeableHighlightPainter(new Color(255, 224, 224));
tags = new ArrayList(1); // Usually small
+ paramCopyInfos = new ArrayList(1);
paramChoicesWindow = createParamChoicesWindow();
@@ -206,6 +226,31 @@ class ParameterizedCompletionDescriptionToolTip {
}
+ public String getArgumentText(int offs) {
+ List paramHighlights = getParameterHighlights();
+ if (paramHighlights==null || paramHighlights.size()==0) {
+ return null;
+ }
+ for (int i=0; i<paramHighlights.size(); i++) {
+ Highlight h = (Highlight)paramHighlights.get(i);
+ if (offs>=h.getStartOffset() && offs<=h.getEndOffset()) {
+ int start = h.getStartOffset() + 1;
+ int len = h.getEndOffset() - start;
+ JTextComponent tc = ac.getTextComponent();
+ Document doc = tc.getDocument();
+ try {
+ return doc.getText(start, len);
+ } catch (BadLocationException ble) {
+ UIManager.getLookAndFeel().provideErrorFeedback(tc);
+ ble.printStackTrace();
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+
+
/**
* Returns the highlight of the current parameter.
*
@@ -234,6 +279,27 @@ class ParameterizedCompletionDescriptionToolTip {
}
+ private int getCurrentParameterIndex() {
+
+ JTextComponent tc = ac.getTextComponent();
+ int dot = tc.getCaretPosition();
+ if (dot>0) {
+ dot--; // Workaround for Java Highlight issues
+ }
+
+ List paramHighlights = getParameterHighlights();
+ for (int i=0; i<paramHighlights.size(); i++) {
+ Highlight h = (Highlight)paramHighlights.get(i);
+ if (dot>=h.getStartOffset() && dot<h.getEndOffset()) {
+ return i;
+ }
+ }
+
+ return -1;
+
+ }
+
+
/**
* Returns the starting offset of the current parameter.
*
@@ -247,6 +313,54 @@ class ParameterizedCompletionDescriptionToolTip {
}
+ /**
+ * Returns the highlight from a list that comes "first" in a list. Even
+ * though most parameter highlights are ordered, sometimes they aren't
+ * (e.g. the "cursor" parameter in a template completion is always last,
+ * even though it can be anywhere in the template).
+ *
+ * @param highlights The list of highlights. Assumed to be non-empty.
+ * @return The highlight that comes first in the document.
+ * @see #getLastHighlight(List)
+ */
+ private static final int getFirstHighlight(List highlights) {
+ int first = -1;
+ Highlight firstH = null;
+ for (int i=0; i<highlights.size(); i++) {
+ Highlight h = (Highlight)highlights.get(i);
+ if (firstH==null || h.getStartOffset()<firstH.getStartOffset()) {
+ firstH = h;
+ first = i;
+ }
+ }
+ return first;
+ }
+
+
+ /**
+ * Returns the highlight from a list that comes "last" in that list. Even
+ * though most parameter highlights are ordered, sometimes they aren't
+ * (e.g. the "cursor" parameter in a template completion is always last,
+ * even though it can be anywhere in the template.
+ *
+ * @param highlights The list of highlights. Assumed to be non-empty.
+ * @return The highlight that comes last in the document.
+ * @see #getFirstHighlight(List)
+ */
+ private static final int getLastHighlight(List highlights) {
+ int last = -1;
+ Highlight lastH = null;
+ for (int i=highlights.size()-1; i>=0; i--) {
+ Highlight h = (Highlight)highlights.get(i);
+ if (lastH==null || h.getStartOffset()>lastH.getStartOffset()) {
+ lastH = h;
+ last = i;
+ }
+ }
+ return last;
+ }
+
+
private List getParameterHighlights() {
List paramHighlights = new ArrayList(1);
JTextComponent tc = ac.getTextComponent();
@@ -360,7 +474,6 @@ class ParameterizedCompletionDescriptionToolTip {
JTextComponent tc = ac.getTextComponent();
int dot = tc.getCaretPosition();
-
int tagCount = tags.size();
if (tagCount==0) {
tc.setCaretPosition(maxPos.getOffset());
@@ -383,17 +496,18 @@ class ParameterizedCompletionDescriptionToolTip {
}
}
- if (currentNext!=null && dot<=currentNext.getStartOffset()) {
- // "+1" is a workaround for Java Highlight issues.
- tc.setSelectionStart(currentNext.getStartOffset()+1);
- tc.setSelectionEnd(currentNext.getEndOffset());
- updateText(pos);
- }
- else {
- tc.setCaretPosition(maxPos.getOffset());
- setVisible(false, false);
+ // No params after caret - go to first one
+ if (currentNext.getStartOffset()+1<=dot) {
+ int nextIndex = getFirstHighlight(highlights);
+ currentNext = (Highlight)highlights.get(nextIndex);
+ pos = 0;
}
+ // "+1" is a workaround for Java Highlight issues.
+ tc.setSelectionStart(currentNext.getStartOffset()+1);
+ tc.setSelectionEnd(currentNext.getEndOffset());
+ updateText(pos);
+
}
@@ -422,15 +536,18 @@ class ParameterizedCompletionDescriptionToolTip {
Highlight h = (Highlight)highlights.get(i);
if (currentPrev==null || currentPrev.getStartOffset()>=dot ||
(h.getStartOffset()<selStart &&
- h.getStartOffset()>currentPrev.getStartOffset())) {
+ (h.getStartOffset()>currentPrev.getStartOffset() ||
+ pos==lastSelectedParam))) {
currentPrev = h;
pos = i;
}
}
// Loop back from param 0 to last param.
- if (pos==0 && lastSelectedParam==0 && highlights.size()>1) {
- pos = highlights.size() - 1;
+ int firstIndex = getFirstHighlight(highlights);
+ //if (pos==0 && lastSelectedParam==0 && highlights.size()>1) {
+ if (pos==firstIndex && lastSelectedParam==firstIndex && highlights.size()>1) {
+ pos = getLastHighlight(highlights);
currentPrev = (Highlight)highlights.get(pos);
// "+1" is a workaround for Java Highlight issues.
tc.setSelectionStart(currentPrev.getStartOffset()+1);
@@ -451,6 +568,49 @@ class ParameterizedCompletionDescriptionToolTip {
}
+ private void possiblyUpdateParamCopies(Document doc) {
+
+ int index = getCurrentParameterIndex();
+ // FunctionCompletions add an extra param at end of inserted text
+ if (index>-1 && index<pc.getParamCount()) {
+
+ // Typing in an "end parameter" => stop parameter assistance.
+ Parameter param = pc.getParam(index);
+ if (param.isEndParam()) {
+ setVisible(false, false);
+ return;
+ }
+
+ // Get the current value of the current parameter.
+ List paramHighlights = getParameterHighlights();
+ Highlight h = (Highlight)paramHighlights.get(index);
+ int start = h.getStartOffset() + 1; // param offsets are offset (!) by 1
+ int len = h.getEndOffset() - start;
+ String replacement = null;
+ try {
+ replacement = doc.getText(start, len);
+ } catch (BadLocationException ble) {
+ ble.printStackTrace(); // Never happens
+ }
+
+ // Replace any param copies tracking this parameter with the
+ // value of this parameter.
+ for (Iterator i=paramCopyInfos.iterator(); i.hasNext(); ) {
+ ParamCopyInfo pci = (ParamCopyInfo)i.next();
+ if (pci.paramName.equals(param.getName())) {
+ pci.h = replaceHighlightedText(doc, pci.h, replacement);
+ }
+ }
+
+ }
+
+ else { // Probably the "end parameter" for FunctionCompletions.
+ setVisible(false, false);
+ }
+
+ }
+
+
/**
* Updates the optional window listing likely completion choices,
*/
@@ -496,6 +656,52 @@ class ParameterizedCompletionDescriptionToolTip {
h.removeHighlight(tags.get(i));
}
tags.clear();
+ for (int i=0; i<paramCopyInfos.size(); i++) {
+ ParamCopyInfo pci = (ParamCopyInfo)paramCopyInfos.get(i);
+ h.removeHighlight(pci.h);
+ }
+ paramCopyInfos.clear();
+ }
+
+
+ /**
+ * Replaces highlighted text with new text. Takes special care so that
+ * the highlight stays just around the newly-highlighted text, since
+ * Swing's <code>Highlight</code> classes are funny about insertions at
+ * their start offsets.
+ *
+ * @param doc The document.
+ * @param h The highlight whose text to change.
+ * @param replacement The new text to be in the highlight.
+ * @return The replacement highlight for <code>h</code>.
+ */
+ private Highlight replaceHighlightedText(Document doc, Highlight h,
+ String replacement) {
+ try {
+
+ int start = h.getStartOffset();
+ int len = h.getEndOffset() - start;
+ Highlighter highlighter = ac.getTextComponent().getHighlighter();
+ highlighter.removeHighlight(h);
+
+ if (doc instanceof AbstractDocument) {
+ ((AbstractDocument)doc).replace(start, len, replacement, null);
+ }
+ else {
+ doc.remove(start, len);
+ doc.insertString(start, replacement, null);
+ }
+
+ int newEnd = start + replacement.length();
+ h = (Highlight)highlighter.addHighlight(start, newEnd, paramCopyP);
+ return h;
+
+ } catch (BadLocationException ble) {
+ ble.printStackTrace(); // Never happens
+ }
+
+ return null;
+
}
@@ -693,28 +899,7 @@ class ParameterizedCompletionDescriptionToolTip {
// (such as type parameters in Java). We need to take care to
// escape these.
String temp = pc.getParam(i).toString();
- int lt = temp.indexOf('<');
- if (lt>-1) {
- sb.append(temp.substring(0, lt));
- sb.append("<");
- for (int j=lt+1; j<temp.length(); j++) {
- char ch = temp.charAt(j);
- switch (ch) {
- case '<':
- sb.append("<");
- break;
- case '>':
- sb.append(">");
- break;
- default:
- sb.append(ch);
- break;
- }
- }
- }
- else {
- sb.append(temp);
- }
+ sb.append(RSyntaxUtilities.escapeForHtml(temp, "<br>", false));
if (i==selectedParam) {
sb.append("</b>");
@@ -775,7 +960,7 @@ class ParameterizedCompletionDescriptionToolTip {
// Otherwise, just move to the end.
JTextComponent tc = ac.getTextComponent();
- tc.setCaretPosition(maxPos.getOffset());
+ tc.setCaretPosition(defaultEndOffs.getOffset());
setVisible(false, false);
}
@@ -799,9 +984,9 @@ class ParameterizedCompletionDescriptionToolTip {
char end = pc.getProvider().getParameterListEnd();
// Are they at or past the end of the parameters?
- if (dot>=maxPos.getOffset()-1) { // ">=" for overwrite mode
+ if (dot>=maxPos.getOffset()-2) { // ">=" for overwrite mode
- if (dot==maxPos.getOffset()) { // Happens in overwrite mode
+ if (dot==maxPos.getOffset()-1) { // Happens in overwrite mode
tc.replaceSelection(Character.toString(end));
}
@@ -818,7 +1003,8 @@ class ParameterizedCompletionDescriptionToolTip {
return;
}
}
- tc.setCaretPosition(maxPos.getOffset());
+ //tc.setCaretPosition(maxPos.getOffset());
+ tc.setCaretPosition(tc.getCaretPosition()+1);
}
setVisible(false, false);
@@ -832,30 +1018,6 @@ class ParameterizedCompletionDescriptionToolTip {
}
- public String getArgumentText(int offs) {
- List paramHighlights = getParameterHighlights();
- if (paramHighlights==null || paramHighlights.size()==0) {
- return null;
- }
- for (int i=0; i<paramHighlights.size(); i++) {
- Highlight h = (Highlight)paramHighlights.get(i);
- if (offs>=h.getStartOffset() && offs<=h.getEndOffset()) {
- int start = h.getStartOffset() + 1;
- int len = h.getEndOffset() - start;
- JTextComponent tc = ac.getTextComponent();
- Document doc = tc.getDocument();
- try {
- return doc.getText(start, len);
- } catch (BadLocationException ble) {
- UIManager.getLookAndFeel().provideErrorFeedback(tc);
- ble.printStackTrace();
- return null;
- }
- }
- }
- return null;
- }
-
public int getCount(String text, char ch) {
int count = 0;
int old = 0;
@@ -903,7 +1065,10 @@ class ParameterizedCompletionDescriptionToolTip {
* @author Robert Futrell
* @version 1.0
*/
- private class Listener implements FocusListener, CaretListener {
+ private class Listener implements FocusListener, CaretListener,
+ DocumentListener {
+
+ private boolean markOccurrencesEnabled;
/**
* Called when the text component's caret moves.
@@ -917,6 +1082,7 @@ class ParameterizedCompletionDescriptionToolTip {
}
int dot = e.getDot();
if (dot<minPos || dot>=maxPos.getOffset()) {
+ System.err.println(">>>>> dot==" + dot + ", " + minPos + ", " + maxPos);
setVisible(false, false);
return;
}
@@ -927,6 +1093,10 @@ class ParameterizedCompletionDescriptionToolTip {
}
+ public void changedUpdate(DocumentEvent e) {
+ }
+
+
/**
* Called when the text component gains focus.
*
@@ -947,6 +1117,24 @@ class ParameterizedCompletionDescriptionToolTip {
}
+ private void handleDocumentEvent(final DocumentEvent e) {
+ if (!ignoringDocumentEvents) {
+ ignoringDocumentEvents = true;
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ possiblyUpdateParamCopies(e.getDocument());
+ ignoringDocumentEvents = false;
+ }
+ });
+ }
+ }
+
+
+ public void insertUpdate(DocumentEvent e) {
+ handleDocumentEvent(e);
+ }
+
+
/**
* Installs this listener onto a text component.
*
@@ -963,20 +1151,34 @@ class ParameterizedCompletionDescriptionToolTip {
tc.addFocusListener(this);
installKeyBindings();
+ boolean replaceTabs = false;
+ if (tc instanceof RSyntaxTextArea) {
+ RSyntaxTextArea textArea = (RSyntaxTextArea)tc;
+ markOccurrencesEnabled = textArea.getMarkOccurrences();
+ textArea.setMarkOccurrences(false);
+ replaceTabs = textArea.getTabsEmulated();
+ }
+
Highlighter h = tc.getHighlighter();
try {
+ // Insert the parameter text
ParameterizedCompletionInsertionInfo info =
- pc.getInsertionInfo(tc, addParamStartList);
-
- // Insert the parameter text and add highlights around the
- // parameters.
+ pc.getInsertionInfo(tc, addParamStartList, replaceTabs);
tc.replaceSelection(info.getTextToInsert());
+
+ // Add highlights around the parameters.
for (int i=0; i<info.getReplacementCount(); i++) {
- Point pt = info.getReplacementLocation(i);
+ DocumentRange dr = info.getReplacementLocation(i);
// "-1" is a workaround for Java Highlight issues.
- tags.add(h.addHighlight(pt.x-1, pt.y, p));
+ tags.add(h.addHighlight(dr.getStartOffset()-1, dr.getEndOffset(), p));
+ }
+ for (int i=0; i<info.getReplacementCopyCount(); i++) {
+ ReplacementCopy rc = info.getReplacementCopy(i);
+ paramCopyInfos.add(new ParamCopyInfo(rc.getId(),
+ (Highlight)h.addHighlight(rc.getStart(), rc.getEnd(),
+ paramCopyP)));
}
// Go back and start at the first parameter.
@@ -987,6 +1189,15 @@ class ParameterizedCompletionDescriptionToolTip {
minPos = info.getMinOffset();
maxPos = info.getMaxOffset();
+ try {
+ defaultEndOffs = tc.getDocument().createPosition(
+ info.getDefaultEndOffs());
+ } catch (BadLocationException ble) {
+ ble.printStackTrace(); // Never happens
+ }
+
+ // Listen for document events AFTER we insert
+ tc.getDocument().addDocumentListener(this);
} catch (BadLocationException ble) {
ble.printStackTrace(); // Never happens
@@ -995,6 +1206,11 @@ class ParameterizedCompletionDescriptionToolTip {
}
+ public void removeUpdate(DocumentEvent e) {
+ handleDocumentEvent(e);
+ }
+
+
/**
* Uninstalls this listener from the current text component.
*
@@ -1004,8 +1220,13 @@ class ParameterizedCompletionDescriptionToolTip {
JTextComponent tc = ac.getTextComponent();
tc.removeCaretListener(this);
tc.removeFocusListener(this);
+ tc.getDocument().removeDocumentListener(this);
uninstallKeyBindings();
+ if (markOccurrencesEnabled) {
+ ((RSyntaxTextArea)tc).setMarkOccurrences(markOccurrencesEnabled);
+ }
+
// Remove WeakReferences in javax.swing.text.
maxPos = null;
minPos = -1;
@@ -1064,6 +1285,19 @@ class ParameterizedCompletionDescriptionToolTip {
}
+ private static class ParamCopyInfo {
+
+ private String paramName;
+ private Highlight h;
+
+ public ParamCopyInfo(String paramName, Highlight h) {
+ this.paramName = paramName;
+ this.h = h;
+ }
+
+ }
+
+
/**
* Action performed when the user hits shift+tab.
*
diff --git a/src/org/fife/ui/autocomplete/ParameterizedCompletionInsertionInfo.java b/src/org/fife/ui/autocomplete/ParameterizedCompletionInsertionInfo.java
index b82430d..f7e3a94 100644
--- a/src/org/fife/ui/autocomplete/ParameterizedCompletionInsertionInfo.java
+++ b/src/org/fife/ui/autocomplete/ParameterizedCompletionInsertionInfo.java
@@ -9,11 +9,12 @@
*/
package org.fife.ui.autocomplete;
-import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import javax.swing.text.Position;
+import org.fife.ui.rsyntaxtextarea.DocumentRange;
+
/**
* Describes a parameterized completion - what's being inserted, where the
@@ -26,13 +27,24 @@ class ParameterizedCompletionInsertionInfo {
private int minOffs;
private Position maxOffs;
+ private int defaultEnd;
private int selStart;
private int selEnd;
private String textToInsert;
private List replacementLocations;
+ private List replacementCopies;
public ParameterizedCompletionInsertionInfo() {
+ defaultEnd = -1;
+ }
+
+
+ public void addReplacementCopy(String id, int start, int end) {
+ if (replacementCopies==null) {
+ replacementCopies = new ArrayList(1);
+ }
+ replacementCopies.add(new ReplacementCopy(id, start, end));
}
@@ -49,7 +61,12 @@ class ParameterizedCompletionInsertionInfo {
if (replacementLocations==null) {
replacementLocations = new ArrayList(1);
}
- replacementLocations.add(new Point(start, end));
+ replacementLocations.add(new DocumentRange(start, end));
+ }
+
+
+ public int getDefaultEndOffs() {
+ return defaultEnd>-1 ? defaultEnd : getMaxOffset().getOffset();
}
@@ -77,6 +94,11 @@ class ParameterizedCompletionInsertionInfo {
}
+ public int getReplacementCopyCount() {
+ return replacementCopies==null ? 0 : replacementCopies.size();
+ }
+
+
/**
* Returns the number of replacements in the completion.
*
@@ -87,6 +109,11 @@ class ParameterizedCompletionInsertionInfo {
}
+ public ReplacementCopy getReplacementCopy(int index) {
+ return (ReplacementCopy)replacementCopies.get(index);
+ }
+
+
/**
* Returns the starting- and ending-offsets of the replacement regions
* in the completion.
@@ -95,8 +122,8 @@ class ParameterizedCompletionInsertionInfo {
* @return The range in the document of that replacement region.
* @see #getReplacementCount()
*/
- public Point getReplacementLocation(int index) {
- return (Point)replacementLocations.get(index);
+ public DocumentRange getReplacementLocation(int index) {
+ return (DocumentRange)replacementLocations.get(index);
}
@@ -178,6 +205,11 @@ class ParameterizedCompletionInsertionInfo {
}
+ public void setDefaultEndOffs(int end) {
+ defaultEnd = end;
+ }
+
+
/**
* Sets the text to insert for the completion.
*
@@ -189,4 +221,31 @@ class ParameterizedCompletionInsertionInfo {
}
+ public static class ReplacementCopy {
+
+ private String id;
+ private int start;
+ private int end;
+
+ public ReplacementCopy(String id, int start, int end) {
+ this.id = id;
+ this.start = start;
+ this.end = end;
+ }
+
+ public int getEnd() {
+ return end;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ }
+
+
}
\ No newline at end of file
diff --git a/src/org/fife/ui/autocomplete/SizeGrip.java b/src/org/fife/ui/autocomplete/SizeGrip.java
index e698cc8..3f90b84 100644
--- a/src/org/fife/ui/autocomplete/SizeGrip.java
+++ b/src/org/fife/ui/autocomplete/SizeGrip.java
@@ -193,9 +193,6 @@ class SizeGrip extends JPanel {
/**
* Listens for mouse events on this panel and resizes the parent window
* appropriately.
- *
- * @author Robert Futrell
- * @version 1.0
*/
/*
* NOTE: We use SwingUtilities.convertPointToScreen() instead of just using
diff --git a/src/org/fife/ui/autocomplete/TemplateCompletion.java b/src/org/fife/ui/autocomplete/TemplateCompletion.java
index 19a085c..6e5efad 100644
--- a/src/org/fife/ui/autocomplete/TemplateCompletion.java
+++ b/src/org/fife/ui/autocomplete/TemplateCompletion.java
@@ -15,8 +15,11 @@ import java.util.List;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
+import javax.swing.text.PlainDocument;
import javax.swing.text.Position;
+import org.fife.ui.autocomplete.TemplatePiece.Param;
+import org.fife.ui.autocomplete.TemplatePiece.ParamCopy;
import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
@@ -25,7 +28,26 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
* can tab through and fill in. This completion type is useful for inserting
* common boilerplate code, such as for-loops.<p>
*
- * This class is a work in progress and currently should not be used.
+ * The format of a template is similar to those in Eclipse. The following
+ * example would be the format for a for-loop template:
+ *
+ * <pre>
+ * for (int ${i} = 0; ${i} < ${array}.length; ${i}++) {
+ * ${cursor}
+ * }
+ * </pre>
+ *
+ * In the above example, the first <code>${i}</code> is a parameter for the
+ * user to type into; all the other <code>${i}</code> instances are
+ * automatically changed to what the user types in the first one. The parameter
+ * named <code>${cursor}</code> is the "ending position" of the template. It's
+ * where the caret moves after it cycles through all other parameters. If the
+ * user types into it, template mode terminates. If more than one
+ * <code>${cursor}</code> parameter is specified, behavior is undefined.<p>
+ *
+ * Leading whitespace is automatically added to lines if the template spans
+ * more than one line, and if used with a text component using a
+ * <code>PlainDocument</code>, tabs will be converted to spaces if requested.
*
* @author Robert Futrell
* @version 1.0
@@ -35,7 +57,7 @@ public class TemplateCompletion extends AbstractCompletion
private List pieces;
- private String replacementText;
+ private String inputText;
private String definitionString;
@@ -45,43 +67,35 @@ public class TemplateCompletion extends AbstractCompletion
private List params;
-
- public TemplateCompletion(CompletionProvider provider, String replacementText,
- String definitionString) {
+ public TemplateCompletion(CompletionProvider provider,
+ String inputText, String definitionString, String template) {
super(provider);
- this.replacementText = replacementText;
+ this.inputText = inputText;
this.definitionString = definitionString;
pieces = new ArrayList(3);
params = new ArrayList(3);
+ parse(template);
}
- public void addTemplatePiece(TemplatePiece piece) {
+ private void addTemplatePiece(TemplatePiece piece) {
pieces.add(piece);
- if (piece.isParam) {
+ if (piece instanceof Param && !"cursor".equals(piece.getText())) {
final String type = null; // TODO
- Parameter param = new Parameter(type, piece.text);
+ Parameter param = new Parameter(type, piece.getText());
params.add(param);
}
}
+ public String getInputText() {
+ return inputText;
+ }
+
+
private String getPieceText(int index, String leadingWS) {
- String text = null;
TemplatePiece piece = (TemplatePiece)pieces.get(index);
- if (piece.id!=null) {
- final String id = piece.id;
- for (int i=0; i<pieces.size(); i++) {
- piece = (TemplatePiece)pieces.get(i);
- if (id.equals(piece.id)) {
- text = piece.text;
- break;
- }
- }
- }
- else {
- text = piece.text;
- }
+ String text = piece.getText();
if (text.indexOf('\n')>-1) {
text = text.replaceAll("\n", "\n" + leadingWS);
}
@@ -90,13 +104,13 @@ public class TemplateCompletion extends AbstractCompletion
/**
- * For template completions, the "replacement text" is really just the
- * first piece of the template, not the entire thing. You should add
- * template pieces so that the rest of the template is dynamically
- * generated.
+ * Returns <code>null</code>; template completions insert all of their
+ * text via <code>getInsertionInfo()</code>.
+ *
+ * @return <code>null</code> always.
*/
public String getReplacementText() {
- return replacementText;
+ return null;
}
@@ -112,19 +126,20 @@ public class TemplateCompletion extends AbstractCompletion
public ParameterizedCompletionInsertionInfo getInsertionInfo(
- JTextComponent tc, boolean addParamStartList) {
+ JTextComponent tc, boolean addParamStartList,
+ boolean replaceTabsWithSpaces) {
ParameterizedCompletionInsertionInfo info =
new ParameterizedCompletionInsertionInfo();
StringBuffer sb = new StringBuffer();
int dot = tc.getCaretPosition();
- int paramCount = getParamCount();
// Get the range in which the caret can move before we hide
// this tool tip.
int minPos = dot;
Position maxPos = null;
+ int defaultEndOffs = -1;
try {
maxPos = tc.getDocument().createPosition(dot);
} catch (BadLocationException ble) {
@@ -132,6 +147,8 @@ public class TemplateCompletion extends AbstractCompletion
}
info.setCaretRange(minPos, maxPos);
int firstParamLen = 0;
+ int selStart = dot; // Default value
+ int selEnd = selStart;
Document doc = tc.getDocument();
String leadingWS = null;
@@ -148,19 +165,38 @@ public class TemplateCompletion extends AbstractCompletion
for (int i=0; i<pieces.size(); i++) {
TemplatePiece piece = (TemplatePiece)pieces.get(i);
String text = getPieceText(i, leadingWS);
- sb.append(text);
- int end = start + text.length();
- if (piece.isParam) {
- info.addReplacementLocation(start, end);
- if (firstParamLen==0) {
- firstParamLen = text.length();
+ if (piece instanceof Param && "cursor".equals(text)) {
+ if (replaceTabsWithSpaces) {
+ start = possiblyReplaceTabsWithSpaces(sb, tc, start);
}
+ defaultEndOffs = start;
+ }
+ else {
+ int end = start + text.length();
+ sb.append(text);
+ if (piece instanceof Param) {
+ info.addReplacementLocation(start, end);
+ if (firstParamLen==0) {
+ firstParamLen = text.length();
+ selStart = start;
+ selEnd = selStart + firstParamLen;
+ }
+ }
+ else if (piece instanceof ParamCopy) {
+ info.addReplacementCopy(piece.getText(), start, end);
+ }
+ start = end;
}
- start = end;
}
- int selectionEnd = paramCount>0 ? (dot+firstParamLen) : dot;
- info.setInitialSelection(dot, selectionEnd);
+
+ info.setInitialSelection(selStart, selEnd);
+ if (defaultEndOffs>-1) {
+ // Keep this location "after" all others when tabbing
+ info.addReplacementLocation(defaultEndOffs, defaultEndOffs);
+ }
+ info.setDefaultEndOffs(defaultEndOffs);
info.setTextToInsert(sb.toString());
+
return info;
}
@@ -182,23 +218,102 @@ public class TemplateCompletion extends AbstractCompletion
}
- public String toString() {
- return getDefinitionString();
+ /**
+ * Returns whether a parameter is already defined with a specific name.
+ *
+ * @param name The name.
+ * @return Whether a parameter is defined with that name.
+ */
+ private boolean isParamDefined(String name) {
+ for (int i=0; i<getParamCount(); i++) {
+ Parameter param = getParam(i);
+ if (name.equals(param.getName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * Parses a template string into logical pieces used by this class.
+ *
+ * @param template The template to parse.
+ */
+ private void parse(String template) {
+
+ int offs = 0;
+ int lastOffs = 0;
+
+ while ((offs=template.indexOf('$', lastOffs))>-1 && offs<template.length()-1) {
+
+ char next = template.charAt(offs+1);
+ switch (next) {
+ case '$': // "$$" => escaped single dollar sign
+ addTemplatePiece(new TemplatePiece.Text(
+ template.substring(lastOffs, offs+1)));
+ lastOffs = offs += 2;
+ break;
+ case '{': // "${...}" => variable
+ int closingCurly = template.indexOf('}', offs+2);
+ if (closingCurly>-1) {
+ addTemplatePiece(new TemplatePiece.Text(
+ template.substring(lastOffs, offs)));
+ String varName = template.substring(offs+2, closingCurly);
+ if (!"cursor".equals(varName) && isParamDefined(varName)) {
+ addTemplatePiece(new TemplatePiece.ParamCopy(varName));
+ }
+ else {
+ addTemplatePiece(new TemplatePiece.Param(varName));
+ }
+ lastOffs = offs = closingCurly + 1;
+ }
+ break;
+ }
+
+ }
+
+ if (lastOffs<template.length()) {
+ String text = template.substring(lastOffs);
+ addTemplatePiece(new TemplatePiece.Text(text));
+ }
+
}
- public static class TemplatePiece {
+ private int possiblyReplaceTabsWithSpaces(StringBuffer sb, JTextComponent tc,
+ int start) {
- private String id;
- private String text;
- private boolean isParam;
+ int size = 4;
+ Document doc = tc.getDocument();
+ if (doc != null) {
+ Integer i = (Integer) doc.getProperty(PlainDocument.tabSizeAttribute);
+ if (i != null) {
+ size = i.intValue();
+ }
+ }
+ String tab = "";
+ for (int i=0; i<size; i++) {
+ tab += " ";
+ }
- public TemplatePiece(String id, String text, boolean isParam) {
- this.id = id;
- this.text = text;
- this.isParam = isParam;
+ int lastNewline = sb.lastIndexOf("\n");
+ int lineOffs = 0;
+ for (int j=lastNewline+1; j<sb.length(); j++) {
+ if (sb.charAt(j)=='\t') {
+ int count = size - (lineOffs%size);
+ sb.replace(j, j+1, tab.substring(0, count));
+ start += count - 1;
+ }
}
+ return start;
+
+ }
+
+
+ public String toString() {
+ return getDefinitionString();
}
diff --git a/src/org/fife/ui/autocomplete/TemplatePiece.java b/src/org/fife/ui/autocomplete/TemplatePiece.java
new file mode 100644
index 0000000..df69343
--- /dev/null
+++ b/src/org/fife/ui/autocomplete/TemplatePiece.java
@@ -0,0 +1,63 @@
+package org.fife.ui.autocomplete;
+
+
+/**
+ * A piece of a <code>TemplateCompletion</code>. You add instances of this
+ * class to template completions to define them.
+ *
+ * @author Robert Futrell
+ * @version 1.0
+ * @see TemplateCompletion
+ */
+interface TemplatePiece {
+
+
+ String getText();
+
+
+ public class Text implements TemplatePiece {
+
+ private String text;
+
+ public Text(String text) {
+ this.text = text;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ }
+
+
+ public class Param implements TemplatePiece {
+
+ String text;
+
+ public Param(String text) {
+ this.text = text;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ }
+
+
+ public class ParamCopy implements TemplatePiece {
+
+ private String text;
+
+ public ParamCopy(String text) {
+ this.text = text;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ }
+
+
+}
\ No newline at end of file
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/autocomplete.git
More information about the pkg-java-commits
mailing list