Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

Autocomplete nearing desired behaviour.

Authordjarvis <email>
Date2016-11-06 21:54:00 GMT-0800
Commit2caf526e925a421b51d6eea2483e0906d0cfc645
Parentd2d3825
Delta98 lines added, 48 lines removed, 50-line increase
src/main/java/com/scrivendor/editor/VariableEditor.java
import static com.scrivendor.definition.Lists.getLast;
import com.scrivendor.service.Settings;
+import static java.lang.Math.min;
+import java.util.StringTokenizer;
import java.util.function.Consumer;
import javafx.collections.ObservableList;
*/
public class VariableEditor {
+
+ private static final int NO_DIFFERENCE = -1;
private final Settings settings = Services.load( Settings.class );
startEventCapture();
setInitialCaretPosition();
- advancePath();
}
// Break out of variable mode by back spacing to the original position.
- if( getCurrentCaretColumn() > getInitialCaretPosition() ) {
+ if( getCurrentCaretPosition() > getInitialCaretPosition() ) {
+ autocomplete();
break;
}
case ESCAPE:
stopEventCapture();
break;
+ /*
case RIGHT:
case END:
advancePath();
break;
-
+ */
case ENTER:
acceptPath();
default:
if( isVariableNameKey( e ) ) {
- updateEditorText( e.getText() );
- advancePath();
+ typed( e.getText() );
}
* Updates the text with the path selected (or typed) by the user.
*/
- private void advancePath() {
- System.out.println( "----------" );
- System.out.println( "advancePath" );
+ private void autocomplete() {
+ System.out.println( "------------" );
+ System.out.println( "autocomplete" );
- final String word = getCurrentWord();
- System.out.println( "current word = '" + word + "'" );
+ final String path = getCurrentPath();
+ System.out.println( "word = '" + path + "'" );
- final TreeItem<String> node = findNode( word );
- final String text = node.getValue();
+ final TreeItem<String> node = findNode( path );
if( !node.isLeaf() ) {
- expand( node );
+ final String word = getLastPathWord();
+ final String label = node.getValue();
+ final int delta = difference( label, word );
- System.out.println( "node = '" + node.getValue() + "'" );
+ String remainder = label;
-// final TreeItem<String> child = getFirst( node.getChildren() );
- // TODO: Magically decide how much of the path overlaps the node.
-// final String nodeValue = node.getValue();
-// final int index = nodeValue.indexOf( word );
-//
-// if( index == 0 && !nodeValue.equals( word ) ) {
-// typeAhead = nodeValue.substring( word.length() );
-// }
- }
+ if( delta != NO_DIFFERENCE ) {
+ remainder = label.substring( delta );
+ }
- updateEditorText( text );
+ System.out.println( "label = '" + label + "'" );
+ System.out.println( "remain = '" + remainder + "'" );
+
+ final StyledTextArea t = getEditor();
+ final int posBegan = getCurrentCaretPosition();
+ final int posEnded = posBegan + remainder.length();
+
+ t.replaceSelection( remainder );
+
+ if( posEnded - posBegan > 0 ) {
+ t.selectRange( posEnded, posBegan );
+ }
+
+ expand( node );
+ }
}
/**
- * Inserts the string at the current caret position, replacing any selected
- * text.
+ * Inserts text that the user typed at the current caret position, then
+ * performs an autocomplete for the variable name.
*
* @param text The text to insert, never null.
*/
- private void updateEditorText( final String text ) {
- final StyledTextArea t = getEditor();
-
- final int length = text.length();
- final int posBegan = getInitialCaretPosition();
- final int posEnded = posBegan + length;
-
- t.replaceSelection( text );
-
- if( posEnded - posBegan > 0 ) {
- t.selectRange( posEnded, posBegan );
- }
+ private void typed( final String text ) {
+ getEditor().replaceSelection( text );
+ autocomplete();
}
*/
private void cycleSelection( final boolean direction ) {
- final String word = getCurrentWord();
+ final String word = getCurrentPath();
final TreeItem<String> node = findNode( word );
expand( cycled );
- updateEditorText( cycled.getValue() );
+ typed( cycled.getValue() );
}
private void cyclePathPrev() {
cycleSelection( false );
+ }
+
+ /**
+ * Returns the index where the two strings diverge.
+ *
+ * @param s1 The string that could be a substring of s2, null allowed.
+ * @param s2 The string that could be a substring of s1, null allowed.
+ *
+ * @return NO_DIFFERENCE if the strings are the same, otherwise the index
+ * where they differ.
+ */
+ @SuppressWarnings( "StringEquality" )
+ public int difference( final CharSequence s1, final CharSequence s2 ) {
+ if( s1 == s2 ) {
+ return NO_DIFFERENCE;
+ }
+
+ if( s1 == null || s2 == null ) {
+ return 0;
+ }
+
+ int i = 0;
+ final int limit = min( s1.length(), s2.length() );
+
+ while( i < limit && s1.charAt( i ) == s2.charAt( i ) ) {
+ i++;
+ }
+
+ // If one string was shorter than the other, that's where they differ.
+ return i;
}
}
- /**
- * Returns the caret's offset into the current paragraph.
- *
- * @return
- */
- private int getCurrentCaretColumn() {
- return getEditor().getCaretColumn();
+ private int getCurrentCaretPosition() {
+ return getEditor().getCaretPosition();
}
/**
* Returns all the characters from the initial caret column to the the first
* whitespace character. This will return a path that contains zero or more
* separators.
*
* @return A non-null string, possibly empty.
*/
- private String getCurrentWord() {
+ private String getCurrentPath() {
final String s = globText();
int i = 0;
while( i < s.length() && !Character.isWhitespace( s.charAt( i ) ) ) {
i++;
}
return s.substring( 0, i );
+ }
+
+ /**
+ * Returns the last word from the path.
+ *
+ * @return The last token.
+ */
+ private String getLastPathWord() {
+ final String path = getCurrentPath();
+ final StringTokenizer st = new StringTokenizer( path, getSeparator() );
+ String result = path;
+
+ while( st.hasMoreTokens() ) {
+ result = st.nextToken();
+ }
+
+ return result;
+ }
+
+ private String getSeparator() {
+ return getDefinitionPane().getSeparator();
}