Add 'src/jexer/' from commit 'cf01c92f5809a0732409e280fb0f32f27393618d'
[fanfix.git] / src / jexer / teditor / Word.java
index d7a65760e628e9295e7932d6b0b38b690a1258bb..eada29cff83ed8b1c61c59d1741b5646d1f645b8 100644 (file)
@@ -3,7 +3,7 @@
  *
  * The MIT License (MIT)
  *
- * Copyright (C) 2017 Kevin Lamonte
+ * Copyright (C) 2019 Kevin Lamonte
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
 package jexer.teditor;
 
 import jexer.bits.CellAttributes;
+import jexer.bits.StringUtils;
 
 /**
  * A Word represents text that was entered by the user.  It can be either
  * whitespace or non-whitespace.
+ *
+ * Very dumb highlighting is supported, it has no sense of parsing (not even
+ * comments).  For now this only highlights some Java keywords and
+ * puctuation.
  */
 public class Word {
 
+    // ------------------------------------------------------------------------
+    // Variables --------------------------------------------------------------
+    // ------------------------------------------------------------------------
+
     /**
      * The color to render this word as on screen.
      */
     private CellAttributes color = new CellAttributes();
 
+    /**
+     * The default color for the TEditor class.
+     */
+    private CellAttributes defaultColor = null;
+
+    /**
+     * The text highlighter to use.
+     */
+    private Highlighter highlighter = null;
+
     /**
      * The actual text of this word.  Average word length is 6 characters,
      * with a lot of shorter ones, so start with 3.
      */
     private StringBuilder text = new StringBuilder(3);
 
+    // ------------------------------------------------------------------------
+    // Constructors -----------------------------------------------------------
+    // ------------------------------------------------------------------------
+
+    /**
+     * Construct a word with one character.
+     *
+     * @param ch the first character of the word
+     * @param defaultColor the color for unhighlighted text
+     * @param highlighter the highlighter to use
+     */
+    public Word(final int ch, final CellAttributes defaultColor,
+        final Highlighter highlighter) {
+
+        this.defaultColor = defaultColor;
+        this.highlighter = highlighter;
+        text.append(Character.toChars(ch));
+    }
+
+    /**
+     * Construct a word with an empty string.
+     *
+     * @param defaultColor the color for unhighlighted text
+     * @param highlighter the highlighter to use
+     */
+    public Word(final CellAttributes defaultColor,
+        final Highlighter highlighter) {
+
+        this.defaultColor = defaultColor;
+        this.highlighter = highlighter;
+    }
+
+    // ------------------------------------------------------------------------
+    // Word -------------------------------------------------------------------
+    // ------------------------------------------------------------------------
+
     /**
      * Get the color used to display this word on screen.
      *
@@ -85,7 +140,7 @@ public class Word {
 
         // TODO: figure out how to handle the tab character.  Do we have a
         // global tab stops list and current word position?
-        return text.length();
+        return StringUtils.width(text.toString());
     }
 
     /**
@@ -105,49 +160,66 @@ public class Word {
     }
 
     /**
-     * Construct a word with one character.
-     *
-     * @param ch the first character of the word
+     * Perform highlighting.
      */
-    public Word(final char ch) {
-        text.append(ch);
+    public void applyHighlight() {
+        color.setTo(defaultColor);
+        if (highlighter == null) {
+            return;
+        }
+        String key = text.toString();
+        CellAttributes newColor = highlighter.getColor(key);
+        if (newColor != null) {
+            color.setTo(newColor);
+        }
     }
 
-    /**
-     * Construct a word with an empty string.
-     */
-    public Word() {}
-
     /**
      * Add a character to this word.  If this is a whitespace character
      * adding to a non-whitespace word, create a new word and return that;
      * similarly if this a non-whitespace character adding to a whitespace
-     * word, create a new word and return that.
+     * word, create a new word and return that.  Note package private access:
+     * this is only called by Line to figure out highlighting boundaries.
      *
      * @param ch the new character to add
      * @return either this word (if it was added), or a new word that
      * contains ch
      */
-    public Word addChar(final char ch) {
+    public Word addChar(final int ch) {
         if (text.length() == 0) {
-            text.append(ch);
+            text.append(Character.toChars(ch));
             return this;
         }
+
+        // Give the highlighter the option to split here.
+        if (highlighter != null) {
+            if (highlighter.shouldSplit(ch)
+                || highlighter.shouldSplit(text.charAt(0))
+            ) {
+                Word newWord = new Word(ch, defaultColor, highlighter);
+                return newWord;
+            }
+        }
+
+        // Highlighter didn't care, so split at whitespace.
         if (Character.isWhitespace(text.charAt(0))
             && Character.isWhitespace(ch)
         ) {
-            text.append(ch);
+            // Adding to a whitespace word, keep at it.
+            text.append(Character.toChars(ch));
             return this;
         }
         if (!Character.isWhitespace(text.charAt(0))
             && !Character.isWhitespace(ch)
         ) {
-            text.append(ch);
+            // Adding to a non-whitespace word, keep at it.
+            text.append(Character.toChars(ch));
             return this;
         }
 
-        // We will be splitting here.
-        Word newWord = new Word(ch);
+        // Switching from whitespace to non-whitespace or vice versa, so
+        // split here.
+        Word newWord = new Word(ch, defaultColor, highlighter);
         return newWord;
     }