Not dead note
[fanfix.git] / src / jexer / teditor / Line.java
CommitLineData
cd92b0ba
KL
1/*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2017 Kevin Lamonte
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29package jexer.teditor;
30
31import java.util.ArrayList;
32import java.util.List;
33
e8a11f98
KL
34import jexer.bits.CellAttributes;
35
cd92b0ba 36/**
12b55d76
KL
37 * A Line represents a single line of text on the screen, as a collection of
38 * words.
cd92b0ba 39 */
12b55d76 40public class Line {
cd92b0ba 41
615a0d99
KL
42 // ------------------------------------------------------------------------
43 // Variables --------------------------------------------------------------
44 // ------------------------------------------------------------------------
45
cd92b0ba 46 /**
12b55d76 47 * The list of words.
cd92b0ba 48 */
12b55d76 49 private ArrayList<Word> words = new ArrayList<Word>();
cd92b0ba 50
e8a11f98
KL
51 /**
52 * The default color for the TEditor class.
53 */
54 private CellAttributes defaultColor = null;
55
56 /**
57 * The text highlighter to use.
58 */
59 private Highlighter highlighter = null;
60
cd92b0ba 61 /**
12b55d76 62 * The current cursor position on this line.
cd92b0ba 63 */
e8a11f98 64 private int cursor = 0;
cd92b0ba
KL
65
66 /**
71a389c9
KL
67 * The raw text of this line, what is passed to Word to determine
68 * highlighting behavior.
cd92b0ba 69 */
71a389c9 70 private StringBuilder rawText;
cd92b0ba 71
615a0d99
KL
72 // ------------------------------------------------------------------------
73 // Constructors -----------------------------------------------------------
74 // ------------------------------------------------------------------------
75
76 /**
77 * Construct a new Line from an existing text string, and highlight
78 * certain strings.
79 *
80 * @param str the text string
81 * @param defaultColor the color for unhighlighted text
82 * @param highlighter the highlighter to use
83 */
84 public Line(final String str, final CellAttributes defaultColor,
85 final Highlighter highlighter) {
86
87 this.defaultColor = defaultColor;
88 this.highlighter = highlighter;
89 this.rawText = new StringBuilder(str);
90
91 scanLine();
92 }
93
94 /**
95 * Construct a new Line from an existing text string.
96 *
97 * @param str the text string
98 * @param defaultColor the color for unhighlighted text
99 */
100 public Line(final String str, final CellAttributes defaultColor) {
101 this(str, defaultColor, null);
102 }
103
104 // ------------------------------------------------------------------------
105 // Line -------------------------------------------------------------------
106 // ------------------------------------------------------------------------
107
cd92b0ba 108 /**
71a389c9
KL
109 * Get a (shallow) copy of the words in this line.
110 *
111 * @return a copy of the word list
cd92b0ba 112 */
71a389c9
KL
113 public List<Word> getWords() {
114 return new ArrayList<Word>(words);
115 }
cd92b0ba 116
e8a11f98
KL
117 /**
118 * Get the current cursor position.
119 *
120 * @return the cursor position
121 */
122 public int getCursor() {
123 return cursor;
124 }
125
126 /**
127 * Set the current cursor position.
128 *
129 * @param cursor the new cursor position
130 */
131 public void setCursor(final int cursor) {
132 if ((cursor < 0)
133 || ((cursor >= getDisplayLength())
134 && (getDisplayLength() > 0))
135 ) {
136 throw new IndexOutOfBoundsException("Max length is " +
137 getDisplayLength() + ", requested position " + cursor);
138 }
139 this.cursor = cursor;
e8a11f98
KL
140 }
141
cd92b0ba 142 /**
71a389c9 143 * Get the on-screen display length.
cd92b0ba 144 *
71a389c9 145 * @return the number of cells needed to display this line
cd92b0ba 146 */
71a389c9
KL
147 public int getDisplayLength() {
148 int n = rawText.length();
149
150 // For now just return the raw text length.
151 if (n > 0) {
152 // If we have any visible characters, add one to the display so
153 // that the cursor is immediately after the data.
154 return n + 1;
155 }
156 return n;
cd92b0ba
KL
157 }
158
159 /**
71a389c9 160 * Get the raw string that matches this line.
cd92b0ba 161 *
71a389c9 162 * @return the string
cd92b0ba 163 */
71a389c9
KL
164 public String getRawString() {
165 return rawText.toString();
166 }
e8a11f98 167
71a389c9
KL
168 /**
169 * Scan rawText and make words out of it.
170 */
171 private void scanLine() {
172 words.clear();
173 Word word = new Word(this.defaultColor, this.highlighter);
174 words.add(word);
175 for (int i = 0; i < rawText.length(); i++) {
176 char ch = rawText.charAt(i);
177 Word newWord = word.addChar(ch);
178 if (newWord != word) {
179 words.add(newWord);
180 word = newWord;
181 }
182 }
183 for (Word w: words) {
184 w.applyHighlight();
e8a11f98 185 }
cd92b0ba
KL
186 }
187
cd92b0ba 188 /**
12b55d76 189 * Decrement the cursor by one. If at the first column, do nothing.
e8a11f98
KL
190 *
191 * @return true if the cursor position changed
cd92b0ba 192 */
e8a11f98
KL
193 public boolean left() {
194 if (cursor == 0) {
195 return false;
cd92b0ba 196 }
e8a11f98
KL
197 cursor--;
198 return true;
cd92b0ba
KL
199 }
200
201 /**
12b55d76 202 * Increment the cursor by one. If at the last column, do nothing.
e8a11f98
KL
203 *
204 * @return true if the cursor position changed
cd92b0ba 205 */
e8a11f98
KL
206 public boolean right() {
207 if (getDisplayLength() == 0) {
208 return false;
cd92b0ba 209 }
e8a11f98
KL
210 if (cursor == getDisplayLength() - 1) {
211 return false;
212 }
e8a11f98
KL
213 cursor++;
214 return true;
cd92b0ba
KL
215 }
216
217 /**
12b55d76 218 * Go to the first column of this line.
e8a11f98
KL
219 *
220 * @return true if the cursor position changed
cd92b0ba 221 */
e8a11f98
KL
222 public boolean home() {
223 if (cursor > 0) {
224 cursor = 0;
e8a11f98
KL
225 return true;
226 }
227 return false;
cd92b0ba
KL
228 }
229
230 /**
12b55d76 231 * Go to the last column of this line.
e8a11f98
KL
232 *
233 * @return true if the cursor position changed
cd92b0ba 234 */
e8a11f98
KL
235 public boolean end() {
236 if (cursor != getDisplayLength() - 1) {
237 cursor = getDisplayLength() - 1;
238 if (cursor < 0) {
239 cursor = 0;
240 }
e8a11f98
KL
241 return true;
242 }
243 return false;
cd92b0ba
KL
244 }
245
246 /**
12b55d76 247 * Delete the character under the cursor.
cd92b0ba 248 */
12b55d76 249 public void del() {
71a389c9
KL
250 assert (words.size() > 0);
251
252 if (cursor < getDisplayLength()) {
253 rawText.deleteCharAt(cursor);
254 }
255
256 // Re-scan the line to determine the new word boundaries.
257 scanLine();
cd92b0ba
KL
258 }
259
260 /**
12b55d76 261 * Delete the character immediately preceeding the cursor.
cd92b0ba 262 */
12b55d76 263 public void backspace() {
71a389c9
KL
264 if (left()) {
265 del();
266 }
cd92b0ba
KL
267 }
268
269 /**
e8a11f98 270 * Insert a character at the cursor.
cd92b0ba 271 *
e8a11f98 272 * @param ch the character to insert
cd92b0ba 273 */
12b55d76 274 public void addChar(final char ch) {
71a389c9
KL
275 if (cursor < getDisplayLength() - 1) {
276 rawText.insert(cursor, ch);
277 } else {
278 rawText.append(ch);
279 }
280 scanLine();
281 cursor++;
cd92b0ba
KL
282 }
283
e8a11f98
KL
284 /**
285 * Replace a character at the cursor.
286 *
287 * @param ch the character to replace
288 */
289 public void replaceChar(final char ch) {
71a389c9
KL
290 if (cursor < getDisplayLength() - 1) {
291 rawText.setCharAt(cursor, ch);
292 } else {
293 rawText.append(ch);
294 }
295 scanLine();
296 cursor++;
e8a11f98
KL
297 }
298
cd92b0ba 299}