Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git
M src/main/java/com/scrivenvar/definition/DefinitionPane.java
6161
6262
  /**
63
   * Trimmed off the end of a word to match a variable name.
64
   */
65
  private final static String TERMINALS = ":;,.!?-/\\¡¿";
66
67
  /**
6863
   * Contains a view of the definitions.
6964
   */
...
249244
250245
  /**
251
   * Returns the leaf that matches the given value. If the value is terminally
252
   * punctuated, the punctuation is removed if no match was found.
246
   * Delegates to {@link VariableTreeItem#findLeafExact(String)}.
253247
   *
254
   * @param value    The value to find, never null.
255
   * @param findMode Defines how to match words.
256
   * @return The leaf that contains the given value, or null if neither the
257
   * original value nor the terminally-trimmed value was found.
248
   * @param text The value to find, never {@code null}.
249
   * @return The leaf that contains the given value, or {@code null} if
250
   * not found.
258251
   */
259
  public VariableTreeItem<String> findLeaf(
260
      final String value, final FindMode findMode ) {
261
    final var root = getTreeRoot();
262
    final var leaf = root.findLeaf( value, findMode );
263
264
    return leaf == null
265
        ? root.findLeaf( rtrimTerminalPunctuation( value ) )
266
        : leaf;
252
  public VariableTreeItem<String> findLeafExact( final String text ) {
253
    return getTreeRoot().findLeafExact( text );
267254
  }
268255
269256
  /**
270
   * Removes punctuation from the end of a string.
257
   * Delegates to {@link VariableTreeItem#findLeafContains(String)}.
271258
   *
272
   * @param s The string to trim, never null.
273
   * @return The string trimmed of all terminal characters from the end
259
   * @param text The value to find, never {@code null}.
260
   * @return The leaf that contains the given value, or {@code null} if
261
   * not found.
274262
   */
275
  private String rtrimTerminalPunctuation( final String s ) {
276
    assert s != null;
277
    int index = s.length() - 1;
263
  public VariableTreeItem<String> findLeafContains( final String text ) {
264
    return getTreeRoot().findLeafContains( text );
265
  }
278266
279
    while( index > 0 && (TERMINALS.indexOf( s.charAt( index ) ) >= 0) ) {
280
      index--;
281
    }
267
  /**
268
   * Delegates to {@link VariableTreeItem#findLeafContains(String)}.
269
   *
270
   * @param text The value to find, never {@code null}.
271
   * @return The leaf that contains the given value, or {@code null} if
272
   * not found.
273
   */
274
  public VariableTreeItem<String> findLeafContainsNoCase( final String text ) {
275
    return getTreeRoot().findLeafContainsNoCase( text );
276
  }
282277
283
    return s.substring( 0, index );
278
  /**
279
   * Delegates to {@link VariableTreeItem#findLeafStartsWith(String)}.
280
   *
281
   * @param text The value to find, never {@code null}.
282
   * @return The leaf that contains the given value, or {@code null} if
283
   * not found.
284
   */
285
  public VariableTreeItem<String> findLeafStartsWith( final String text ) {
286
    return getTreeRoot().findLeafStartsWith( text );
284287
  }
285288
D src/main/java/com/scrivenvar/definition/FindMode.java
1
/*
2
 * Copyright 2020 White Magic Software, Ltd.
3
 *
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are met:
8
 *
9
 *  o Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 *
12
 *  o Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
package com.scrivenvar.definition;
29
30
/**
31
 * Used to find variable keys by matching values. The values are matched
32
 * according to the relationships provided in this enumeration.
33
 */
34
public enum FindMode {
35
  EXACT,
36
  CONTAINS,
37
  STARTS_WITH,
38
  LEVENSHTEIN
39
}
40
411
M src/main/java/com/scrivenvar/definition/VariableTreeItem.java
3232
import java.text.Normalizer;
3333
import java.util.Stack;
34
import java.util.function.BiFunction;
3435
35
import static com.scrivenvar.definition.FindMode.*;
3636
import static java.text.Normalizer.Form.NFD;
3737
...
5454
  /**
5555
   * Finds a leaf starting at the current node with text that matches the given
56
   * value.
56
   * value. Search is performed case-sensitively.
5757
   *
5858
   * @param text The text to match against each leaf in the tree.
59
   * @return The leaf that has a value starting with the given text.
59
   * @return The leaf that has a value exactly matching the given text.
6060
   */
61
  public VariableTreeItem<T> findLeaf( final String text ) {
62
    return findLeaf( text, STARTS_WITH );
61
  public VariableTreeItem<T> findLeafExact( final String text ) {
62
    return findLeaf( text, VariableTreeItem::valueEquals );
63
  }
64
65
  /**
66
   * Finds a leaf starting at the current node with text that matches the given
67
   * value. Search is performed case-sensitively.
68
   *
69
   * @param text The text to match against each leaf in the tree.
70
   * @return The leaf that has a value that contains the given text.
71
   */
72
  public VariableTreeItem<T> findLeafContains( final String text ) {
73
    return findLeaf( text, VariableTreeItem::valueContains );
74
  }
75
76
  /**
77
   * Finds a leaf starting at the current node with text that matches the given
78
   * value. Search is performed case-insensitively.
79
   *
80
   * @param text The text to match against each leaf in the tree.
81
   * @return The leaf that has a value that contains the given text.
82
   */
83
  public VariableTreeItem<T> findLeafContainsNoCase( final String text ) {
84
    return findLeaf( text, VariableTreeItem::valueContainsNoCase );
85
  }
86
87
  /**
88
   * Finds a leaf starting at the current node with text that matches the given
89
   * value. Search is performed case-sensitively.
90
   *
91
   * @param text The text to match against each leaf in the tree.
92
   * @return The leaf that has a value that starts with the given text.
93
   */
94
  public VariableTreeItem<T> findLeafStartsWith( final String text ) {
95
    return findLeaf( text, VariableTreeItem::valueStartsWith );
6396
  }
6497
6598
  /**
6699
   * Finds a leaf starting at the current node with text that matches the given
67100
   * value.
68101
   *
69102
   * @param text     The text to match against each leaf in the tree.
70103
   * @param findMode What algorithm is used to match the given text.
71
   * @return The leaf that has a value starting with the given text.
104
   * @return The leaf that has a value starting with the given text, or {@code
105
   * null} if there was no match found.
72106
   */
73107
  public VariableTreeItem<T> findLeaf(
74
      final String text, final FindMode findMode ) {
108
      final String text,
109
      final BiFunction<VariableTreeItem<T>, String, Boolean> findMode ) {
75110
    final Stack<VariableTreeItem<T>> stack = new Stack<>();
76
    final VariableTreeItem<T> root = this;
77
78
    stack.push( root );
111
    stack.push( this );
79112
80
    // Don't try to find keys for blank/empty variable values.
113
    // Don't hunt for blank (empty) keys.
81114
    boolean found = text.isBlank();
82
    VariableTreeItem<T> node = null;
83115
84116
    while( !found && !stack.isEmpty() ) {
85
      node = stack.pop();
117
      final VariableTreeItem<T> node = stack.pop();
86118
87
      if( findMode == EXACT && node.valueEquals( text ) ) {
88
        found = true;
89
      }
90
      else if( findMode == CONTAINS && node.valueContains( text ) ) {
91
        found = true;
92
      }
93
      else if( findMode == STARTS_WITH && node.valueStartsWith( text ) ) {
94
        found = true;
95
      }
96
      else {
97
        for( final TreeItem<T> child : node.getChildren() ) {
98
          stack.push( (VariableTreeItem<T>) child );
99
        }
119
      for( final TreeItem<T> child : node.getChildren() ) {
120
        final VariableTreeItem<T> result = (VariableTreeItem<T>) child;
100121
101
        // No match found, yet.
102
        node = null;
122
        if( result.isLeaf() ) {
123
          if( found = findMode.apply( result, text ) ) {
124
            return result;
125
          }
126
        }
127
        else {
128
          stack.push( result );
129
        }
103130
      }
104131
    }
105132
106
    return node;
133
    return null;
107134
  }
108135
...
118145
119146
  /**
120
   * Returns true if this node is a leaf and its value starts with the given
121
   * text.
147
   * Returns true if this node is a leaf and its value equals the given text.
122148
   *
123149
   * @param s The text to compare against the node value.
124
   * @return true Node is a leaf and its value starts with the given value.
150
   * @return true Node is a leaf and its value equals the given value.
125151
   */
126
  private boolean valueStartsWith( final String s ) {
127
    return isLeaf() && getDiacriticlessValue().startsWith( s );
152
  private boolean valueEquals( final String s ) {
153
    return isLeaf() && getValue().equals( s );
128154
  }
129155
...
139165
140166
  /**
141
   * Returns true if this node is a leaf and its value equals the given text.
167
   * Returns true if this node is a leaf and its value contains the given text.
142168
   *
143169
   * @param s The text to compare against the node value.
144
   * @return true Node is a leaf and its value equals the given value.
170
   * @return true Node is a leaf and its value contains the given value.
145171
   */
146
  private boolean valueEquals( final String s ) {
147
    return isLeaf() && getValue().equals( s );
172
  private boolean valueContainsNoCase( final String s ) {
173
    return isLeaf() && getDiacriticlessValue()
174
        .toLowerCase()
175
        .contains( s.toLowerCase() );
176
  }
177
178
  /**
179
   * Returns true if this node is a leaf and its value starts with the given
180
   * text.
181
   *
182
   * @param s The text to compare against the node value.
183
   * @return true Node is a leaf and its value starts with the given value.
184
   */
185
  private boolean valueStartsWith( final String s ) {
186
    return isLeaf() && getDiacriticlessValue().startsWith( s );
148187
  }
149188
M src/main/java/com/scrivenvar/editors/EditorPane.java
7474
  }
7575
76
  /**
77
   * Cuts the actively selected text; if no text is selected, this will cut
78
   * the entire paragraph.
79
   */
7680
  public void cut() {
77
    getEditor().selectParagraph();
78
    getEditor().cut();
81
    final var editor = getEditor();
82
    final var selected = editor.getSelectedText();
83
84
    if( selected == null || selected.isEmpty() ) {
85
      editor.selectParagraph();
86
    }
87
88
    editor.cut();
7989
  }
8090
M src/main/java/com/scrivenvar/editors/VariableNameInjector.java
3131
import com.scrivenvar.decorators.VariableDecorator;
3232
import com.scrivenvar.definition.DefinitionPane;
33
import com.scrivenvar.definition.FindMode;
3433
import com.scrivenvar.definition.VariableTreeItem;
3534
import javafx.scene.control.TreeItem;
3635
import javafx.scene.input.KeyEvent;
3736
import org.fxmisc.richtext.StyledTextArea;
3837
3938
import java.nio.file.Path;
4039
import java.text.BreakIterator;
4140
42
import static com.scrivenvar.definition.FindMode.*;
4341
import static javafx.scene.input.KeyCode.SPACE;
4442
import static javafx.scene.input.KeyCombination.CONTROL_DOWN;
...
8583
8684
  /**
87
   * Inserts the variable
85
   * Inserts the currently selected variable from the {@link DefinitionPane}.
8886
   */
8987
  public void injectSelectedItem() {
9088
    final var pane = getDefinitionPane();
9189
    final TreeItem<String> item = pane.getSelectedItem();
9290
9391
    if( item.isLeaf() ) {
94
      final var leaf = pane.findLeaf( item.getValue(), FindMode.EXACT );
92
      final var leaf = pane.findLeafExact( item.getValue() );
9593
      final var editor = getEditor();
9694
...
198196
  }
199197
198
  /**
199
   * Looks for the given word, matching first by exact, next by a starts-with
200
   * condition with diacritics replaced, then by containment.
201
   *
202
   * @param word
203
   * @return
204
   */
205
  @SuppressWarnings("ConstantConditions")
200206
  private VariableTreeItem<String> findLeaf( final String word ) {
201207
    assert word != null;
202208
203
    VariableTreeItem<String> leaf = findLeafExact( word );
209
    final var pane = getDefinitionPane();
210
    VariableTreeItem<String> leaf = null;
204211
205
    leaf = leaf == null ? findLeafStartsWith( word ) : leaf;
206
    leaf = leaf == null ? findLeafContains( word ) : leaf;
207
    leaf = leaf == null ? findLeafLevenshtein( word ) : leaf;
212
    leaf = leaf == null ? pane.findLeafExact( word ) : leaf;
213
    leaf = leaf == null ? pane.findLeafStartsWith( word ) : leaf;
214
    leaf = leaf == null ? pane.findLeafContains( word ) : leaf;
215
    leaf = leaf == null ? pane.findLeafContainsNoCase( word ) : leaf;
208216
209217
    return leaf;
210
  }
211
212
  private VariableTreeItem<String> findLeafExact( final String text ) {
213
    return findLeaf( text, EXACT );
214
  }
215
216
  private VariableTreeItem<String> findLeafContains( final String text ) {
217
    return findLeaf( text, CONTAINS );
218
  }
219
220
  private VariableTreeItem<String> findLeafStartsWith( final String text ) {
221
    return findLeaf( text, STARTS_WITH );
222
  }
223
224
  private VariableTreeItem<String> findLeafLevenshtein( final String text ) {
225
    return findLeaf( text, LEVENSHTEIN );
226
  }
227
228
  /**
229
   * Finds the first leaf having a value that starts with the given text, or
230
   * contains the text if contains is true.
231
   *
232
   * @param text     The text to find in the definition tree.
233
   * @param findMode Dictates what search criteria to use for matching words.
234
   * @return The leaf that starts with the given text, or null if not found.
235
   */
236
  private VariableTreeItem<String> findLeaf(
237
      final String text, final FindMode findMode ) {
238
    return getDefinitionPane().findLeaf( text, findMode );
239218
  }
240219