TEditor 50% complete
[nikiroo-utils.git] / src / jexer / teditor / Document.java
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 */
29 package jexer.teditor;
30
31 import java.util.ArrayList;
32 import java.util.List;
33
34 import jexer.bits.CellAttributes;
35
36 /**
37 * A Document represents a text file, as a collection of lines.
38 */
39 public class Document {
40
41 /**
42 * The list of lines.
43 */
44 private ArrayList<Line> lines = new ArrayList<Line>();
45
46 /**
47 * The current line number being edited. Note that this is 0-based, the
48 * first line is line number 0.
49 */
50 private int lineNumber = 0;
51
52 /**
53 * The overwrite flag. When true, characters overwrite data.
54 */
55 private boolean overwrite = false;
56
57 /**
58 * The default color for the TEditor class.
59 */
60 private CellAttributes defaultColor = null;
61
62 /**
63 * The text highlighter to use.
64 */
65 private Highlighter highlighter = new Highlighter();
66
67 /**
68 * Get the overwrite flag.
69 *
70 * @return true if addChar() overwrites data, false if it inserts
71 */
72 public boolean getOverwrite() {
73 return overwrite;
74 }
75
76 /**
77 * Set the overwrite flag.
78 *
79 * @param overwrite true if addChar() should overwrite data, false if it
80 * should insert
81 */
82 public void setOverwrite(final boolean overwrite) {
83 this.overwrite = overwrite;
84 }
85
86 /**
87 * Get the current line number being edited.
88 *
89 * @return the line number. Note that this is 0-based: 0 is the first
90 * line.
91 */
92 public int getLineNumber() {
93 return lineNumber;
94 }
95
96 /**
97 * Get the current editing line.
98 *
99 * @return the line
100 */
101 public Line getCurrentLine() {
102 return lines.get(lineNumber);
103 }
104
105 /**
106 * Get a specific line by number.
107 *
108 * @param lineNumber the line number. Note that this is 0-based: 0 is
109 * the first line.
110 * @return the line
111 */
112 public Line getLine(final int lineNumber) {
113 return lines.get(lineNumber);
114 }
115
116 /**
117 * Set the current line number being edited.
118 *
119 * @param n the line number. Note that this is 0-based: 0 is the first
120 * line.
121 */
122 public void setLineNumber(final int n) {
123 if ((n < 0) || (n > lines.size())) {
124 throw new IndexOutOfBoundsException("Lines array size is " +
125 lines.size() + ", requested index " + n);
126 }
127 lineNumber = n;
128 }
129
130 /**
131 * Get the current cursor position of the editing line.
132 *
133 * @return the cursor position
134 */
135 public int getCursor() {
136 return lines.get(lineNumber).getCursor();
137 }
138
139 /**
140 * Construct a new Document from an existing text string.
141 *
142 * @param str the text string
143 * @param defaultColor the color for unhighlighted text
144 */
145 public Document(final String str, final CellAttributes defaultColor) {
146 this.defaultColor = defaultColor;
147
148 // TODO: set different colors based on file extension
149 highlighter.setJavaColors();
150
151 String [] rawLines = str.split("\n");
152 for (int i = 0; i < rawLines.length; i++) {
153 lines.add(new Line(rawLines[i], this.defaultColor, highlighter));
154 }
155 }
156
157 /**
158 * Increment the line number by one. If at the last line, do nothing.
159 *
160 * @return true if the editing line changed
161 */
162 public boolean down() {
163 if (lineNumber < lines.size() - 1) {
164 int x = lines.get(lineNumber).getCursor();
165 lineNumber++;
166 if (x > lines.get(lineNumber).getDisplayLength()) {
167 lines.get(lineNumber).end();
168 } else {
169 lines.get(lineNumber).setCursor(x);
170 }
171 return true;
172 }
173 return false;
174 }
175
176 /**
177 * Increment the line number by n. If n would go past the last line,
178 * increment only to the last line.
179 *
180 * @param n the number of lines to increment by
181 * @return true if the editing line changed
182 */
183 public boolean down(final int n) {
184 if (lineNumber < lines.size() - 1) {
185 int x = lines.get(lineNumber).getCursor();
186 lineNumber += n;
187 if (lineNumber > lines.size() - 1) {
188 lineNumber = lines.size() - 1;
189 }
190 if (x > lines.get(lineNumber).getDisplayLength()) {
191 lines.get(lineNumber).end();
192 } else {
193 lines.get(lineNumber).setCursor(x);
194 }
195 return true;
196 }
197 return false;
198 }
199
200 /**
201 * Decrement the line number by one. If at the first line, do nothing.
202 *
203 * @return true if the editing line changed
204 */
205 public boolean up() {
206 if (lineNumber > 0) {
207 int x = lines.get(lineNumber).getCursor();
208 lineNumber--;
209 if (x > lines.get(lineNumber).getDisplayLength()) {
210 lines.get(lineNumber).end();
211 } else {
212 lines.get(lineNumber).setCursor(x);
213 }
214 return true;
215 }
216 return false;
217 }
218
219 /**
220 * Decrement the line number by n. If n would go past the first line,
221 * decrement only to the first line.
222 *
223 * @param n the number of lines to decrement by
224 * @return true if the editing line changed
225 */
226 public boolean up(final int n) {
227 if (lineNumber > 0) {
228 int x = lines.get(lineNumber).getCursor();
229 lineNumber -= n;
230 if (lineNumber < 0) {
231 lineNumber = 0;
232 }
233 if (x > lines.get(lineNumber).getDisplayLength()) {
234 lines.get(lineNumber).end();
235 } else {
236 lines.get(lineNumber).setCursor(x);
237 }
238 return true;
239 }
240 return false;
241 }
242
243 /**
244 * Decrement the cursor by one. If at the first column, do nothing.
245 *
246 * @return true if the cursor position changed
247 */
248 public boolean left() {
249 return lines.get(lineNumber).left();
250 }
251
252 /**
253 * Increment the cursor by one. If at the last column, do nothing.
254 *
255 * @return true if the cursor position changed
256 */
257 public boolean right() {
258 return lines.get(lineNumber).right();
259 }
260
261 /**
262 * Go to the first column of this line.
263 *
264 * @return true if the cursor position changed
265 */
266 public boolean home() {
267 return lines.get(lineNumber).home();
268 }
269
270 /**
271 * Go to the last column of this line.
272 *
273 * @return true if the cursor position changed
274 */
275 public boolean end() {
276 return lines.get(lineNumber).end();
277 }
278
279 /**
280 * Delete the character under the cursor.
281 */
282 public void del() {
283 lines.get(lineNumber).del();
284 }
285
286 /**
287 * Delete the character immediately preceeding the cursor.
288 */
289 public void backspace() {
290 lines.get(lineNumber).backspace();
291 }
292
293 /**
294 * Replace or insert a character at the cursor, depending on overwrite
295 * flag.
296 *
297 * @param ch the character to replace or insert
298 */
299 public void addChar(final char ch) {
300 if (overwrite) {
301 lines.get(lineNumber).replaceChar(ch);
302 } else {
303 lines.get(lineNumber).addChar(ch);
304 }
305 }
306
307 /**
308 * Get a (shallow) copy of the list of lines.
309 *
310 * @return the list of lines
311 */
312 public List<Line> getLines() {
313 return new ArrayList<Line>(lines);
314 }
315
316 /**
317 * Get the number of lines.
318 *
319 * @return the number of lines
320 */
321 public int getLineCount() {
322 return lines.size();
323 }
324
325 /**
326 * Compute the maximum line length for this document.
327 *
328 * @return the number of cells needed to display the longest line
329 */
330 public int getLineLengthMax() {
331 int n = 0;
332 for (Line line : lines) {
333 if (line.getDisplayLength() > n) {
334 n = line.getDisplayLength();
335 }
336 }
337 return n;
338 }
339
340 }