|
1 // line_editor.cpp |
|
2 // |
|
3 // Copyright (c) 2006 - 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "Eclipse Public License v1.0" |
|
6 // which accompanies this distribution, and is available |
|
7 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 // |
|
9 // Initial Contributors: |
|
10 // Accenture - Initial contribution |
|
11 // |
|
12 |
|
13 #include "line_editor.h" |
|
14 #include <f32file.h> |
|
15 #include <fshell/ioutils.h> |
|
16 #include <fshell/common.mmh> |
|
17 |
|
18 using namespace IoUtils; |
|
19 |
|
20 |
|
21 // |
|
22 // Constants. |
|
23 // |
|
24 |
|
25 _LIT(KSpace, " "); |
|
26 _LIT(KNewLine, "\r\n"); |
|
27 _LIT(KBackspace, "\x08 \x08"); |
|
28 |
|
29 |
|
30 // |
|
31 // RConsole. |
|
32 // |
|
33 |
|
34 RConsole::RConsole(MAbstractConsoleWriter& aStdout) |
|
35 : iStdout(aStdout), iCursorPos(TPoint(0, 0)), iCursorMode(EInsert), iCursorVisible(EFalse) |
|
36 { |
|
37 iStdout.GetScreenSize(iSize); |
|
38 SetCursorVisible(ETrue); |
|
39 } |
|
40 |
|
41 void RConsole::Close() |
|
42 { |
|
43 iScrollObservers.Close(); |
|
44 } |
|
45 |
|
46 void RConsole::Start() |
|
47 { |
|
48 Refresh(); |
|
49 } |
|
50 |
|
51 void RConsole::Refresh() |
|
52 { |
|
53 iStdout.GetScreenSize(iSize); |
|
54 iStdout.GetCursorPos(iCursorPos); |
|
55 } |
|
56 |
|
57 void RConsole::Write(const TDesC &aDes) |
|
58 { |
|
59 const TInt desLength = aDes.Length(); |
|
60 for (TInt i = 0; i < desLength; ++i) |
|
61 { |
|
62 switch(aDes[i]) |
|
63 { |
|
64 case 0x00: // Null. |
|
65 break; |
|
66 case 0x07: // Bell. |
|
67 break; |
|
68 case 0x08: // Backspace. |
|
69 case 0x7f: // Delete. |
|
70 CursorLeft(); |
|
71 break; |
|
72 case 0x09: // Tab. |
|
73 case 0x0b: // Vertical tab. |
|
74 case 0x0c: // Form feed. |
|
75 // These should already have been swallowed by CLineEditor::HandleKey. |
|
76 ASSERT(FALSE); |
|
77 break; |
|
78 case 0x0a: |
|
79 LineFeed(); |
|
80 break; |
|
81 case 0x0d: |
|
82 CarriageReturn(); |
|
83 break; |
|
84 default: |
|
85 CursorRight(); |
|
86 } |
|
87 } |
|
88 iStdout.Write(aDes); |
|
89 } |
|
90 |
|
91 void RConsole::SetCursorPosAbs(const TPoint& aPoint) |
|
92 { |
|
93 iCursorPos = aPoint; |
|
94 iStdout.SetCursorPosAbs(aPoint); |
|
95 } |
|
96 |
|
97 void RConsole::SetCursorPosRel(const TPoint& aPoint) |
|
98 { |
|
99 iCursorPos += aPoint; |
|
100 iStdout.SetCursorPosRel(aPoint); |
|
101 } |
|
102 |
|
103 void RConsole::MoveCursorLeft() |
|
104 { |
|
105 CursorLeft(); |
|
106 iStdout.SetCursorPosAbs(iCursorPos); |
|
107 } |
|
108 |
|
109 void RConsole::MoveCursorRight() |
|
110 { |
|
111 CursorRight(); |
|
112 iStdout.SetCursorPosAbs(iCursorPos); |
|
113 } |
|
114 |
|
115 void RConsole::SetCursorMode(TCursorMode aMode) |
|
116 { |
|
117 iCursorMode = aMode; |
|
118 SetCursorVisible(iCursorVisible); |
|
119 } |
|
120 |
|
121 void RConsole::SetCursorVisible(TBool aVisible) |
|
122 { |
|
123 iCursorVisible = aVisible; |
|
124 iStdout.SetCursorHeight(iCursorVisible ? (iCursorMode == EInsert ? 20 : 100) : 0); |
|
125 } |
|
126 |
|
127 void RConsole::ClearToEndOfLine() |
|
128 { |
|
129 iStdout.ClearToEndOfLine(); |
|
130 // no affect on cursor position |
|
131 } |
|
132 |
|
133 void RConsole::Clear() |
|
134 { |
|
135 iStdout.ClearScreen(); |
|
136 iCursorPos.iX = iCursorPos.iY = 0; |
|
137 } |
|
138 |
|
139 TPoint RConsole::PosFrom(const TPoint& aStartPos, TInt aLength) const |
|
140 { |
|
141 // if the width is 0 we'll enter an infinite loop below. |
|
142 if (iSize.iWidth == 0) return TPoint(aStartPos.iX + aLength, aStartPos.iY); |
|
143 |
|
144 TPoint endPos(aStartPos); |
|
145 if (aLength > 0) |
|
146 { |
|
147 while (aLength) |
|
148 { |
|
149 const TInt min = Min(iSize.iWidth - endPos.iX, aLength); |
|
150 aLength -= min; |
|
151 if ((endPos.iX + min) < iSize.iWidth) |
|
152 { |
|
153 endPos.iX += min; |
|
154 } |
|
155 else |
|
156 { |
|
157 ASSERT((endPos.iX + min) == iSize.iWidth); |
|
158 endPos.iX = 0; |
|
159 ++endPos.iY; |
|
160 } |
|
161 } |
|
162 } |
|
163 else |
|
164 { |
|
165 aLength = -aLength; |
|
166 while (aLength) |
|
167 { |
|
168 const TInt min = Min(endPos.iX, aLength); |
|
169 if (min == 0) |
|
170 { |
|
171 endPos.iX = (iSize.iWidth - 1); |
|
172 --endPos.iY; |
|
173 --aLength; |
|
174 } |
|
175 else |
|
176 { |
|
177 endPos.iX -= min; |
|
178 aLength -= min; |
|
179 } |
|
180 } |
|
181 } |
|
182 return endPos; |
|
183 } |
|
184 |
|
185 TPoint RConsole::CursorPos() const |
|
186 { |
|
187 return iCursorPos; |
|
188 } |
|
189 |
|
190 TInt RConsole::AddObserver(MConsoleScrollObserver& aObserver) |
|
191 { |
|
192 return iScrollObservers.Append(&aObserver); |
|
193 } |
|
194 |
|
195 void RConsole::RemoveObserver(MConsoleScrollObserver& aObserver) |
|
196 { |
|
197 const TInt numObservers = iScrollObservers.Count(); |
|
198 for (TInt i = 0; i < numObservers; ++i) |
|
199 { |
|
200 if (iScrollObservers[i] == &aObserver) |
|
201 { |
|
202 iScrollObservers.Remove(i); |
|
203 return; |
|
204 } |
|
205 } |
|
206 ASSERT(EFalse); |
|
207 } |
|
208 |
|
209 TSize RConsole::Size() const |
|
210 { |
|
211 return iSize; |
|
212 } |
|
213 |
|
214 void RConsole::CursorLeft() |
|
215 { |
|
216 if (iCursorPos.iX > 0) |
|
217 { |
|
218 // Not yet reached beginning of line. |
|
219 --iCursorPos.iX; |
|
220 } |
|
221 else if (iCursorPos.iY > 0) |
|
222 { |
|
223 // Reached beginning of line, so jump to end of line above. |
|
224 iCursorPos.iX = (iSize.iWidth - 1); |
|
225 --iCursorPos.iY; |
|
226 } |
|
227 } |
|
228 |
|
229 void RConsole::CursorRight() |
|
230 { |
|
231 if (iCursorPos.iX < (iSize.iWidth - 1)) |
|
232 { |
|
233 // Not yet reached the end of the line. |
|
234 ++iCursorPos.iX; |
|
235 } |
|
236 else if (iCursorPos.iY < (iSize.iHeight - 1)) |
|
237 { |
|
238 // Reached the end of the line and there's space below - jump to the beginning of the line below. |
|
239 iCursorPos.iX = 0; |
|
240 ++iCursorPos.iY; |
|
241 } |
|
242 else |
|
243 { |
|
244 // Reached the end of the line and there's no space below - console will scroll up a line and jump to the beginning of the newly exposed line. |
|
245 iCursorPos.iX = 0; |
|
246 NotifyScrollObservers(); |
|
247 } |
|
248 } |
|
249 |
|
250 void RConsole::LineFeed() |
|
251 { |
|
252 if (iCursorPos.iY < (iSize.iHeight - 1)) |
|
253 { |
|
254 iCursorPos.iX = 0; |
|
255 ++iCursorPos.iY; |
|
256 } |
|
257 else |
|
258 { |
|
259 iCursorPos.iX = 0; |
|
260 NotifyScrollObservers(); |
|
261 } |
|
262 } |
|
263 |
|
264 void RConsole::CarriageReturn() |
|
265 { |
|
266 iCursorPos.iX = 0; |
|
267 } |
|
268 |
|
269 void RConsole::NewLine() |
|
270 { |
|
271 iStdout.Write(KNewLine); |
|
272 iCursorPos.iX = 0; |
|
273 if (iCursorPos.iY < (iSize.iHeight - 1)) |
|
274 { |
|
275 ++iCursorPos.iY; |
|
276 } |
|
277 else |
|
278 { |
|
279 iCursorPos.iX = 0; |
|
280 NotifyScrollObservers(); |
|
281 } |
|
282 } |
|
283 |
|
284 void RConsole::NotifyScrollObservers() |
|
285 { |
|
286 const TInt numObservers = iScrollObservers.Count(); |
|
287 for (TInt i = 0; i < numObservers; ++i) |
|
288 { |
|
289 iScrollObservers[i]->CsoHandleConsoleScrolled(); |
|
290 } |
|
291 } |
|
292 |
|
293 |
|
294 // |
|
295 // TConsoleLine. |
|
296 // |
|
297 |
|
298 EXPORT_C TConsoleLine::TConsoleLine(RConsole& aConsole) |
|
299 : iConsole(aConsole), iPromptLength(0), iBufPos(0), iStartPos(aConsole.CursorPos()), iHidden(ETrue) |
|
300 { |
|
301 } |
|
302 |
|
303 EXPORT_C void TConsoleLine::Start(const TDesC& aPrompt) |
|
304 { |
|
305 Start(aPrompt, KNullDesC); |
|
306 } |
|
307 |
|
308 EXPORT_C void TConsoleLine::Start(const TDesC& aPrompt, const TDesC& aInitialInput) |
|
309 { |
|
310 if (iStarted) |
|
311 { |
|
312 Restart(aPrompt); |
|
313 return; |
|
314 } |
|
315 |
|
316 iStarted = ETrue; |
|
317 if (!iHidden) |
|
318 { |
|
319 iConsole.AddObserver(*this); |
|
320 } |
|
321 iConsole.Start(); |
|
322 iBuf = aPrompt; |
|
323 iBuf.Append(aInitialInput); |
|
324 iPromptLength = aPrompt.Length(); |
|
325 iBufPos = iBuf.Length(); |
|
326 if (!iHidden) |
|
327 { |
|
328 Redraw(); |
|
329 iConsole.SetCursorVisible(ETrue); |
|
330 } |
|
331 } |
|
332 |
|
333 void TConsoleLine::Abort() |
|
334 { |
|
335 iStarted = EFalse; |
|
336 iConsole.RemoveObserver(*this); |
|
337 } |
|
338 |
|
339 void TConsoleLine::Restart(const TDesC& aPrompt) |
|
340 { |
|
341 // a) Hide the cursor. |
|
342 // b) Move the cursor to the start of the line. |
|
343 // c) Create a buffer that will fully overwrite the old line. |
|
344 // d) Write the buffer to the console. |
|
345 // e) Set the cursor to the end of the new prompt. |
|
346 // f) Make the cursor visible again. |
|
347 iConsole.SetCursorVisible(EFalse); |
|
348 iConsole.SetCursorPosAbs(iStartPos); |
|
349 const TInt origBufLength = iBuf.Length(); |
|
350 iBuf = aPrompt; |
|
351 if (iBuf.Length() < origBufLength) |
|
352 { |
|
353 iBuf.AppendFill(' ', origBufLength - iBuf.Length()); |
|
354 } |
|
355 iConsole.Write(iBuf); |
|
356 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, aPrompt.Length())); |
|
357 iBuf.SetLength(aPrompt.Length()); |
|
358 iBufPos = aPrompt.Length(); |
|
359 iConsole.SetCursorVisible(ETrue); |
|
360 } |
|
361 |
|
362 EXPORT_C void TConsoleLine::Insert(TChar aChar) |
|
363 { |
|
364 TPtrC charDes((TUint16*)&aChar, 1); |
|
365 const TInt availableSpace = iBuf.MaxLength() - iBuf.Length(); |
|
366 if (iBufPos < iBuf.Length()) |
|
367 { |
|
368 if (availableSpace < 1) |
|
369 { |
|
370 iBuf.Delete(iBuf.Length() - 1, 1); |
|
371 } |
|
372 iBuf.Insert(iBufPos, charDes); |
|
373 iConsole.SetCursorVisible(EFalse); |
|
374 iConsole.Write(iBuf.Mid(iBufPos)); |
|
375 iConsole.SetCursorPosAbs(iConsole.PosFrom(iConsole.CursorPos(), iBufPos - iBuf.Length() + 1)); |
|
376 iConsole.SetCursorVisible(ETrue); |
|
377 iBufPos++; |
|
378 } |
|
379 else |
|
380 { |
|
381 ASSERT(iBufPos == iBuf.Length()); |
|
382 if (availableSpace > 0) |
|
383 { |
|
384 ++iBufPos; |
|
385 iBuf.Append(charDes); |
|
386 iConsole.Write(charDes); |
|
387 } |
|
388 } |
|
389 } |
|
390 |
|
391 EXPORT_C void TConsoleLine::Overwrite(TChar aChar) |
|
392 { |
|
393 if (iBufPos < iBuf.MaxLength()) |
|
394 { |
|
395 TPtrC charDes((TUint16*)&aChar, 1); |
|
396 if (iBufPos < iBuf.Length()) |
|
397 { |
|
398 iBuf.Replace(iBufPos++, 1, charDes); |
|
399 } |
|
400 else |
|
401 { |
|
402 ASSERT(iBufPos == iBuf.Length()); |
|
403 iBuf.Append(charDes); |
|
404 ++iBufPos; |
|
405 } |
|
406 iConsole.Write(charDes); |
|
407 } |
|
408 } |
|
409 |
|
410 EXPORT_C void TConsoleLine::Replace(const TDesC& aDes) |
|
411 { |
|
412 // a) Hide the cursor. |
|
413 // b) Move the cursor to the start of the line (after the prompt). |
|
414 // c) Create a buffer that will fully overwrite the old line. |
|
415 // d) Write the buffer to the console. |
|
416 // e) Set the cursor to the end of the new line contents. |
|
417 // f) Make the cursor visible again. |
|
418 iConsole.SetCursorVisible(EFalse); |
|
419 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, iPromptLength)); |
|
420 const TInt origBufLength = iBuf.Length() - iPromptLength; |
|
421 iBuf.Delete(iPromptLength, origBufLength); |
|
422 iBuf.Append(aDes); |
|
423 if (aDes.Length() < origBufLength) |
|
424 { |
|
425 iBuf.AppendFill(' ', origBufLength - aDes.Length()); |
|
426 } |
|
427 iConsole.Write(iBuf.Mid(iPromptLength)); |
|
428 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, iPromptLength + aDes.Length())); |
|
429 iBuf.SetLength(iPromptLength + aDes.Length()); |
|
430 iBufPos = iPromptLength + aDes.Length(); |
|
431 iConsole.SetCursorVisible(ETrue); |
|
432 } |
|
433 |
|
434 EXPORT_C void TConsoleLine::Replace(TInt aFrom, const TDesC& aDes) |
|
435 { |
|
436 // a) Hide the cursor. |
|
437 // b) Move the cursor to aFrom. |
|
438 // c) Overwrite chars up to iBufPos. |
|
439 // d) Insert remaining chars (if any). |
|
440 // e) Make the cursor visible again. |
|
441 aFrom += iPromptLength; |
|
442 ASSERT(iBufPos >= aFrom); |
|
443 iConsole.SetCursorVisible(EFalse); |
|
444 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, aFrom)); |
|
445 const TInt desLength = aDes.Length(); |
|
446 const TInt numOverwriteChars = iBufPos - aFrom; |
|
447 TInt lengthAdjust = 0; |
|
448 if (numOverwriteChars > 0) |
|
449 { |
|
450 iBuf.Replace(aFrom, numOverwriteChars, aDes.Left(numOverwriteChars)); |
|
451 if (desLength < numOverwriteChars) |
|
452 { |
|
453 lengthAdjust = numOverwriteChars - desLength; |
|
454 iBuf.AppendFill(' ', lengthAdjust); |
|
455 iBufPos -= lengthAdjust; |
|
456 } |
|
457 } |
|
458 const TInt numInsertChars = desLength - numOverwriteChars; |
|
459 if (numInsertChars > 0) |
|
460 { |
|
461 iBuf.Insert(iBufPos, aDes.Mid(numOverwriteChars)); |
|
462 iBufPos += numInsertChars; |
|
463 } |
|
464 iConsole.Write(iBuf.Mid(aFrom)); |
|
465 iBuf.SetLength(iBuf.Length() - lengthAdjust); |
|
466 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, aFrom + aDes.Length())); |
|
467 iConsole.SetCursorVisible(ETrue); |
|
468 } |
|
469 |
|
470 EXPORT_C void TConsoleLine::Redraw() |
|
471 { |
|
472 if (!iStarted) return; |
|
473 iConsole.Refresh(); |
|
474 iStartPos = iConsole.CursorPos(); |
|
475 if (iStartPos.iX > 0) |
|
476 { |
|
477 iConsole.NewLine(); |
|
478 iStartPos = iConsole.CursorPos(); |
|
479 } |
|
480 iConsole.Write(iBuf); |
|
481 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, iBufPos)); |
|
482 } |
|
483 |
|
484 EXPORT_C void TConsoleLine::End() |
|
485 { |
|
486 iStarted = EFalse; |
|
487 if (!iHidden) |
|
488 { |
|
489 iConsole.RemoveObserver(*this); |
|
490 if (iBufPos < iBuf.Length()) |
|
491 { |
|
492 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, iBuf.Length())); |
|
493 } |
|
494 iConsole.NewLine(); |
|
495 } |
|
496 } |
|
497 |
|
498 EXPORT_C void TConsoleLine::DeleteLeft() |
|
499 { |
|
500 if (iBufPos > iPromptLength) |
|
501 { |
|
502 iBuf.Delete(--iBufPos, 1); |
|
503 iConsole.SetCursorVisible(EFalse); |
|
504 if (iBufPos == iBuf.Length()) |
|
505 { |
|
506 iConsole.Write(KBackspace); |
|
507 } |
|
508 else |
|
509 { |
|
510 iBuf.Append(KSpace); |
|
511 iConsole.MoveCursorLeft(); |
|
512 TPoint cursorPos(iConsole.CursorPos()); |
|
513 iConsole.Write(iBuf.Mid(iBufPos)); |
|
514 iBuf.SetLength(iBuf.Length() - 1); |
|
515 iConsole.SetCursorPosAbs(cursorPos); |
|
516 } |
|
517 iConsole.SetCursorVisible(ETrue); |
|
518 } |
|
519 } |
|
520 |
|
521 EXPORT_C void TConsoleLine::DeleteRight() |
|
522 { |
|
523 if (iBufPos < iBuf.Length()) |
|
524 { |
|
525 iBuf.Delete(iBufPos, 1); |
|
526 iConsole.SetCursorVisible(EFalse); |
|
527 TPoint cursorPos(iConsole.CursorPos()); |
|
528 iBuf.Append(KSpace); |
|
529 iConsole.Write(iBuf.Mid(iBufPos)); |
|
530 iBuf.SetLength(iBuf.Length() - 1); |
|
531 iConsole.SetCursorPosAbs(cursorPos); |
|
532 iConsole.SetCursorVisible(ETrue); |
|
533 } |
|
534 } |
|
535 |
|
536 EXPORT_C void TConsoleLine::CursorLeft() |
|
537 { |
|
538 if (iBufPos > iPromptLength) |
|
539 { |
|
540 --iBufPos; |
|
541 iConsole.MoveCursorLeft(); |
|
542 } |
|
543 } |
|
544 |
|
545 EXPORT_C void TConsoleLine::CursorRight() |
|
546 { |
|
547 if (iBufPos < iBuf.Length()) |
|
548 { |
|
549 ++iBufPos; |
|
550 iConsole.MoveCursorRight(); |
|
551 } |
|
552 } |
|
553 |
|
554 EXPORT_C void TConsoleLine::CursorPreviousWord() |
|
555 { |
|
556 TLex lex(iBuf); |
|
557 lex.Inc(iBufPos - 1); |
|
558 while ((lex.Offset() > iPromptLength) && lex.Peek().IsSpace()) |
|
559 { |
|
560 lex.UnGet(); |
|
561 } |
|
562 while ((lex.Offset() > iPromptLength) && !lex.Peek().IsSpace()) |
|
563 { |
|
564 lex.UnGet(); |
|
565 } |
|
566 lex.SkipSpace(); |
|
567 iBufPos = Max(iPromptLength, lex.Offset()); |
|
568 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, iBufPos)); |
|
569 } |
|
570 |
|
571 EXPORT_C void TConsoleLine::CursorNextWord() |
|
572 { |
|
573 TLex lex(iBuf); |
|
574 lex.Inc(iBufPos); |
|
575 lex.SkipSpace(); |
|
576 lex.SkipCharacters(); |
|
577 iBufPos = lex.Offset(); |
|
578 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, iBufPos)); |
|
579 } |
|
580 |
|
581 EXPORT_C void TConsoleLine::CursorBeginning() |
|
582 { |
|
583 iBufPos = iPromptLength; |
|
584 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, iPromptLength)); |
|
585 } |
|
586 |
|
587 EXPORT_C void TConsoleLine::CursorEnd() |
|
588 { |
|
589 iBufPos = iBuf.Length(); |
|
590 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, iBuf.Length())); |
|
591 } |
|
592 |
|
593 EXPORT_C void TConsoleLine::PrintCompletionPossibilitiesL(const TDesC& aPossibilities) |
|
594 { |
|
595 if (iBufPos < iBuf.Length()) |
|
596 { |
|
597 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, iBuf.Length())); |
|
598 } |
|
599 iConsole.NewLine(); |
|
600 CTextFormatter* formatter = CTextFormatter::NewLC(iConsole.Size().iWidth); |
|
601 formatter->ColumnizeL(0, 2, aPossibilities); |
|
602 iConsole.Write(formatter->Descriptor()); |
|
603 CleanupStack::PopAndDestroy(formatter); |
|
604 iStartPos = iConsole.CursorPos(); |
|
605 iConsole.Write(iBuf); |
|
606 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, iBufPos)); |
|
607 } |
|
608 |
|
609 EXPORT_C TPtrC TConsoleLine::Contents() const |
|
610 { |
|
611 return iBuf.Mid(iPromptLength); |
|
612 } |
|
613 |
|
614 EXPORT_C TPtrC TConsoleLine::ContentsToCursor() const |
|
615 { |
|
616 return iBuf.Mid(iPromptLength, iBufPos - iPromptLength); |
|
617 } |
|
618 |
|
619 void TConsoleLine::CsoHandleConsoleScrolled() |
|
620 { |
|
621 --iStartPos.iY; |
|
622 } |
|
623 |
|
624 void TConsoleLine::Hide() |
|
625 { |
|
626 if (iHidden) return; |
|
627 iHidden = ETrue; |
|
628 if (!iStarted) return; |
|
629 iConsole.RemoveObserver(*this); |
|
630 iConsole.SetCursorPosAbs(TPoint(0, iConsole.CursorPos().iY)); |
|
631 iConsole.ClearToEndOfLine(); |
|
632 iConsole.SetCursorVisible(EFalse); |
|
633 } |
|
634 |
|
635 void TConsoleLine::Show() |
|
636 { |
|
637 if (!iHidden) return; |
|
638 iHidden = EFalse; |
|
639 if (!iStarted) return; |
|
640 |
|
641 iConsole.AddObserver(*this); |
|
642 iConsole.Start(); |
|
643 Redraw(); |
|
644 iConsole.SetCursorVisible(ETrue); |
|
645 } |
|
646 |
|
647 void TConsoleLine::SetCursorPosition(TInt aPosition) |
|
648 { |
|
649 TInt newPos = iPromptLength + aPosition; |
|
650 if (newPos < iBuf.Length()) |
|
651 { |
|
652 iBufPos = newPos; |
|
653 iConsole.SetCursorPosAbs(iConsole.PosFrom(iStartPos, newPos)); |
|
654 } |
|
655 } |
|
656 |
|
657 // |
|
658 // CLineHistory. |
|
659 // |
|
660 |
|
661 NONSHARABLE_CLASS(CLineHistory) : public CBase |
|
662 { |
|
663 public: |
|
664 enum TRecallType |
|
665 { |
|
666 ENext, |
|
667 EPrevious, |
|
668 EFirst, |
|
669 ELast |
|
670 }; |
|
671 public: |
|
672 static CLineHistory* NewL(RFs& aFs, TInt aMaximumSize, const TDesC& aFileName); |
|
673 ~CLineHistory(); |
|
674 void AddL(const TDesC& aLine, TInt aPos=0); |
|
675 const TDesC& Recall(TRecallType aType); |
|
676 const TDesC& RecallMatch(const TDesC& aMatch); // Always searches backwards |
|
677 void Reset(); |
|
678 private: |
|
679 CLineHistory(RFs& aFs, TInt aMaximumSize, const TDesC& aFileName); |
|
680 void ConstructL(); |
|
681 void RestoreL(); |
|
682 void StoreL(); |
|
683 TInt Find(const TDesC& aLine); |
|
684 void ResetBackgroundWriter(); |
|
685 static TInt BackgroundWriterCallback(TAny* aSelf); |
|
686 void DoBackgroundWriterCallback(); |
|
687 private: |
|
688 RFs& iFs; |
|
689 const TInt iMaximumSize; |
|
690 TFileName iFileName; |
|
691 TInt iIndex; |
|
692 RPointerArray<HBufC> iHistory; |
|
693 CPeriodic* iBackgroundWriter; |
|
694 TTime iLastChangedTime; |
|
695 TTime iLastSyncedTime; |
|
696 }; |
|
697 |
|
698 CLineHistory* CLineHistory::NewL(RFs& aFs, TInt aMaximumSize, const TDesC& aFileName) |
|
699 { |
|
700 CLineHistory* self = new(ELeave) CLineHistory(aFs, aMaximumSize, aFileName); |
|
701 CleanupStack::PushL(self); |
|
702 self->ConstructL(); |
|
703 CleanupStack::Pop(self); |
|
704 return self; |
|
705 } |
|
706 |
|
707 CLineHistory::~CLineHistory() |
|
708 { |
|
709 #ifdef EKA2 |
|
710 TRAP_IGNORE(StoreL()); |
|
711 #else |
|
712 TRAPD(err, StoreL()); |
|
713 #endif |
|
714 iHistory.ResetAndDestroy(); |
|
715 delete iBackgroundWriter; |
|
716 } |
|
717 |
|
718 void CLineHistory::AddL(const TDesC& aLine, TInt aPos) |
|
719 { |
|
720 if (aLine.Length() > 0) |
|
721 { |
|
722 TInt index = Find(aLine); |
|
723 if (index == 0) |
|
724 { |
|
725 // Already present and at begining - nothing to do. |
|
726 } |
|
727 else if (index > 0) |
|
728 { |
|
729 // Already present - move to beginning. |
|
730 HBufC* line = iHistory[index]; |
|
731 iHistory.Remove(index); |
|
732 iHistory.Insert(line, aPos); // Should not fail due to the above deletion. |
|
733 iLastChangedTime.UniversalTime(); |
|
734 } |
|
735 else |
|
736 { |
|
737 if (iHistory.Count() == iMaximumSize) |
|
738 { |
|
739 // History at maximum size - throw away the oldest entry. |
|
740 delete iHistory[iMaximumSize - 1]; |
|
741 iHistory.Remove(iMaximumSize - 1); |
|
742 } |
|
743 HBufC* line = aLine.AllocLC(); |
|
744 User::LeaveIfError(iHistory.Insert(line, aPos)); |
|
745 CleanupStack::Pop(line); |
|
746 iLastChangedTime.UniversalTime(); |
|
747 } |
|
748 } |
|
749 iIndex = -1; |
|
750 ResetBackgroundWriter(); |
|
751 } |
|
752 |
|
753 const TDesC& CLineHistory::Recall(TRecallType aType) |
|
754 { |
|
755 switch (aType) |
|
756 { |
|
757 case ENext: |
|
758 { |
|
759 if (iIndex >= 0) |
|
760 { |
|
761 --iIndex; |
|
762 } |
|
763 break; |
|
764 } |
|
765 case EPrevious: |
|
766 { |
|
767 if (iIndex < (iHistory.Count() - 1)) |
|
768 { |
|
769 ++iIndex; |
|
770 } |
|
771 break; |
|
772 } |
|
773 case EFirst: |
|
774 { |
|
775 iIndex = 0; |
|
776 break; |
|
777 } |
|
778 case ELast: |
|
779 { |
|
780 iIndex = (iHistory.Count() - 1); |
|
781 break; |
|
782 } |
|
783 default: |
|
784 { |
|
785 ASSERT(EFalse); |
|
786 break; |
|
787 } |
|
788 } |
|
789 |
|
790 if ((iIndex >= 0) && (iIndex < iHistory.Count())) |
|
791 { |
|
792 return *iHistory[iIndex]; |
|
793 } |
|
794 else |
|
795 { |
|
796 return KNullDesC(); |
|
797 } |
|
798 } |
|
799 |
|
800 CLineHistory::CLineHistory(RFs& aFs, TInt aMaximumSize, const TDesC& aFileName) |
|
801 : iFs(aFs), iMaximumSize(aMaximumSize), iFileName(aFileName), iIndex(-1) |
|
802 { |
|
803 } |
|
804 |
|
805 void CLineHistory::ConstructL() |
|
806 { |
|
807 if (CActiveScheduler::Current()) |
|
808 { |
|
809 // Line editor may be run without a scheduler, in which case we can't try using an AO. |
|
810 iBackgroundWriter = CPeriodic::NewL(CActive::EPriorityStandard); |
|
811 } |
|
812 |
|
813 TRAPD(err, RestoreL()); |
|
814 if (err) |
|
815 { |
|
816 iHistory.ResetAndDestroy(); |
|
817 iFs.Delete(iFileName); |
|
818 } |
|
819 } |
|
820 |
|
821 void CLineHistory::RestoreL() |
|
822 { |
|
823 if (iFileName.Length() == 0) return; |
|
824 |
|
825 RFile file; |
|
826 TInt err = file.Open(iFs, iFileName, EFileRead); |
|
827 if (err == KErrNone) |
|
828 { |
|
829 CleanupClosePushL(file); |
|
830 TInt32 int32; |
|
831 TPckg<TInt32> intPckg(int32); |
|
832 User::LeaveIfError(file.Read(intPckg)); |
|
833 const TInt historyCount = Min(int32, iMaximumSize); |
|
834 for (TInt i = 0; i < historyCount; ++i) |
|
835 { |
|
836 User::LeaveIfError(file.Read(intPckg)); |
|
837 iFs.Delete(KNullDesC); |
|
838 HBufC* line = HBufC::NewLC(int32); |
|
839 TPtr linePtr(line->Des()); |
|
840 TInt size = int32 * 2; |
|
841 TPtr8 linePtr8((TUint8*)linePtr.Ptr(), 0, size); |
|
842 User::LeaveIfError(file.Read(linePtr8, size)); |
|
843 linePtr.SetLength(int32); |
|
844 User::LeaveIfError(iHistory.Append(line)); |
|
845 CleanupStack::Pop(line); |
|
846 } |
|
847 iLastSyncedTime.UniversalTime(); |
|
848 CleanupStack::PopAndDestroy(&file); |
|
849 } |
|
850 else if ((err == KErrNotFound) || (err == KErrPathNotFound)) |
|
851 { |
|
852 // Ignore error - leave history empty. |
|
853 } |
|
854 else |
|
855 { |
|
856 User::Leave(err); |
|
857 } |
|
858 } |
|
859 |
|
860 void CLineHistory::StoreL() |
|
861 { |
|
862 if (iFileName.Length() == 0) return; // User clearly doesn't want to be persisted |
|
863 |
|
864 TTime modified; |
|
865 TInt err = iFs.Modified(iFileName, modified); |
|
866 if (err == KErrNone && modified > iLastSyncedTime) |
|
867 { |
|
868 // Someone else has updated our history under our feet - have a stab at merging them |
|
869 // For the moment we'll follow the algorithm of: |
|
870 // * In newest-first order, insert anything in the history file that isn't in ours (maintaining the newest-first order) |
|
871 // * Stop if we get to half the max history size, otherwise we'll risk reinserting stuff that we've just evicted, or something. Not quite sure that's totally correct but sounds fairly sensible. |
|
872 CLineHistory* newerHistory = CLineHistory::NewL(iFs, iMaximumSize, iFileName); |
|
873 newerHistory->iFileName.Zero(); // So newerHistory doesn't try and overwrite our history when we delete it |
|
874 CleanupStack::PushL(newerHistory); |
|
875 iLastSyncedTime.UniversalTime(); // Otherwise the AddLs below will go recursive... |
|
876 const TInt historyCount = newerHistory->iHistory.Count(); |
|
877 TInt insertionPoint = 0; |
|
878 for (TInt i = 0; i < historyCount; i++) |
|
879 { |
|
880 HBufC* line = newerHistory->iHistory[i]; |
|
881 TInt index = Find(*line); |
|
882 if (index == KErrNotFound) |
|
883 { |
|
884 AddL(*line, insertionPoint); |
|
885 insertionPoint++; |
|
886 } |
|
887 if (i >= iMaximumSize/2) break; |
|
888 } |
|
889 CleanupStack::PopAndDestroy(newerHistory); |
|
890 } |
|
891 |
|
892 iFs.MkDirAll(iFileName); |
|
893 RFile file; |
|
894 User::LeaveIfError(file.Replace(iFs, iFileName, EFileWrite)); |
|
895 CleanupClosePushL(file); |
|
896 const TInt32 historyCount = iHistory.Count(); |
|
897 TPckgC<TInt32> countPckg(historyCount); |
|
898 User::LeaveIfError(file.Write(countPckg)); |
|
899 for (TInt i = 0; i < historyCount; ++i) |
|
900 { |
|
901 const HBufC* line = iHistory[i]; |
|
902 const TInt32 length = line->Length(); |
|
903 TPckgC<TInt32> lengthPckg(length); |
|
904 User::LeaveIfError(file.Write(lengthPckg)); |
|
905 TPtrC8 linePtr8((const TUint8*)line->Ptr(), length * 2); |
|
906 User::LeaveIfError(file.Write(linePtr8)); |
|
907 } |
|
908 CleanupStack::PopAndDestroy(&file); |
|
909 iLastSyncedTime.UniversalTime(); |
|
910 } |
|
911 |
|
912 TInt CLineHistory::Find(const TDesC& aLine) |
|
913 { |
|
914 const TInt historyCount = iHistory.Count(); |
|
915 for (TInt i = 0; i < historyCount; ++i) |
|
916 { |
|
917 if (aLine == *iHistory[i]) |
|
918 { |
|
919 return i; |
|
920 } |
|
921 } |
|
922 return KErrNotFound; |
|
923 } |
|
924 |
|
925 void CLineHistory::Reset() |
|
926 { |
|
927 iIndex = -1; |
|
928 } |
|
929 |
|
930 const TDesC& CLineHistory::RecallMatch(const TDesC& aMatch) |
|
931 { |
|
932 const TInt historyCount = iHistory.Count(); |
|
933 TInt oldIndex = iIndex; |
|
934 for (iIndex = iIndex+1; iIndex < historyCount; iIndex++) |
|
935 { |
|
936 const TDesC& line = *iHistory[iIndex]; |
|
937 if (line.Left(aMatch.Length()).CompareF(aMatch) == 0) |
|
938 { |
|
939 return line; |
|
940 } |
|
941 } |
|
942 // If nothing found, restore iIndex to what it was |
|
943 iIndex = oldIndex; |
|
944 return KNullDesC; |
|
945 } |
|
946 |
|
947 const static TInt KWriterPeriod = 10*1000*1000; // 10 seconds |
|
948 |
|
949 void CLineHistory::ResetBackgroundWriter() |
|
950 { |
|
951 if (iLastChangedTime.Int64() > iLastSyncedTime.Int64() + KWriterPeriod) |
|
952 { |
|
953 // For whatever reason (probably that the scheduler doesn't exist or isn't running) it's been ages since we last persisted the history |
|
954 // but the background writer hasn't kicked in - so do it now |
|
955 DoBackgroundWriterCallback(); |
|
956 } |
|
957 else if (iBackgroundWriter) |
|
958 { |
|
959 iBackgroundWriter->Cancel(); |
|
960 iBackgroundWriter->Start(KWriterPeriod, KWriterPeriod, TCallBack(&BackgroundWriterCallback, this)); |
|
961 } |
|
962 } |
|
963 |
|
964 TInt CLineHistory::BackgroundWriterCallback(TAny* aSelf) |
|
965 { |
|
966 static_cast<CLineHistory*>(aSelf)->DoBackgroundWriterCallback(); |
|
967 return KErrNone; |
|
968 } |
|
969 |
|
970 void CLineHistory::DoBackgroundWriterCallback() |
|
971 { |
|
972 if (iBackgroundWriter) iBackgroundWriter->Cancel(); // No point the periodic going off repeatedly if nothing has actually changed. We'll restart it in ResetBackgroundWriter if the history actually changes |
|
973 |
|
974 if (iLastChangedTime.Int64() > iLastSyncedTime.Int64()) |
|
975 { |
|
976 TRAP_IGNORE(StoreL()); |
|
977 } |
|
978 } |
|
979 |
|
980 // |
|
981 // CLineEditor. |
|
982 // |
|
983 |
|
984 EXPORT_C CLineEditor* CLineEditor::NewL(RFs& aFs, |
|
985 MAbstractConsoleWriter& aStdout, |
|
986 MLineEditorObserver& aObserver, |
|
987 MLineCompleter& aCompleter, |
|
988 const TDesC& aConsoleHistoryFile) |
|
989 { |
|
990 CLineEditor* self = new(ELeave) CLineEditor(aStdout, aObserver, aCompleter); |
|
991 CleanupStack::PushL(self); |
|
992 self->ConstructL(aFs, aConsoleHistoryFile); |
|
993 CleanupStack::Pop(self); |
|
994 return self; |
|
995 } |
|
996 |
|
997 |
|
998 EXPORT_C CLineEditor::~CLineEditor() |
|
999 { |
|
1000 delete iHistory; |
|
1001 iConsole.Close(); |
|
1002 } |
|
1003 |
|
1004 CLineEditor::CLineEditor(MAbstractConsoleWriter& aStdout, MLineEditorObserver& aObserver, MLineCompleter& aCompleter) |
|
1005 : iObserver(aObserver), iCompleter(aCompleter), iConsole(aStdout), iLine(iConsole) |
|
1006 { |
|
1007 } |
|
1008 |
|
1009 void CLineEditor::ConstructL(RFs& aFs, const TDesC& aConsoleHistoryFile) |
|
1010 { |
|
1011 iHistory = CLineHistory::NewL(aFs, 50, aConsoleHistoryFile); |
|
1012 } |
|
1013 |
|
1014 EXPORT_C void CLineEditor::HandleKey(TUint aKeyCode, TUint aModifiers) |
|
1015 { |
|
1016 iLine.Show(); |
|
1017 TBool handled(EFalse); |
|
1018 if (aModifiers & EModifierFunc) |
|
1019 { |
|
1020 handled = ETrue; |
|
1021 switch (aKeyCode) |
|
1022 { |
|
1023 case 'b': |
|
1024 case EKeyLeftArrow: |
|
1025 { |
|
1026 HandlePreviousWord(); |
|
1027 break; |
|
1028 } |
|
1029 case 'f': |
|
1030 case EKeyRightArrow: |
|
1031 { |
|
1032 HandleNextWord(); |
|
1033 break; |
|
1034 } |
|
1035 default: |
|
1036 { |
|
1037 handled = EFalse; |
|
1038 } |
|
1039 } |
|
1040 } |
|
1041 |
|
1042 if (!handled) |
|
1043 { |
|
1044 switch (aKeyCode) |
|
1045 { |
|
1046 case EKeyEnter: |
|
1047 #ifdef FSHELL_PLATFORM_S60 |
|
1048 case EKeyDevice3: // confirm key |
|
1049 #endif |
|
1050 { |
|
1051 HandleEnter(); |
|
1052 break; |
|
1053 } |
|
1054 case EKeyBackspace: |
|
1055 { |
|
1056 HandleBackspace(); |
|
1057 break; |
|
1058 } |
|
1059 case EKeyTab: |
|
1060 { |
|
1061 HandleTab(); |
|
1062 break; |
|
1063 }; |
|
1064 case CTRL('d'): |
|
1065 case EKeyDelete: |
|
1066 { |
|
1067 HandleDelete(); |
|
1068 break; |
|
1069 } |
|
1070 case CTRL('b'): |
|
1071 case EKeyLeftArrow: |
|
1072 { |
|
1073 HandleLeftArrow(); |
|
1074 break; |
|
1075 } |
|
1076 case CTRL('f'): |
|
1077 case EKeyRightArrow: |
|
1078 { |
|
1079 HandleRightArrow(); |
|
1080 break; |
|
1081 } |
|
1082 case CTRL('p'): |
|
1083 case EKeyUpArrow: |
|
1084 { |
|
1085 HandleUpArrow(); |
|
1086 break; |
|
1087 } |
|
1088 case CTRL('n'): |
|
1089 case EKeyDownArrow: |
|
1090 { |
|
1091 HandleDownArrow(); |
|
1092 break; |
|
1093 } |
|
1094 case CTRL('a'): |
|
1095 case EKeyHome: |
|
1096 { |
|
1097 HandleHome(); |
|
1098 break; |
|
1099 } |
|
1100 case CTRL('e'): |
|
1101 case EKeyEnd: |
|
1102 { |
|
1103 HandleEnd(); |
|
1104 break; |
|
1105 } |
|
1106 case EKeyPageUp: |
|
1107 { |
|
1108 HandlePageUp(); |
|
1109 break; |
|
1110 } |
|
1111 case EKeyPageDown: |
|
1112 { |
|
1113 HandlePageDown(); |
|
1114 break; |
|
1115 } |
|
1116 case EKeyInsert: |
|
1117 { |
|
1118 HandleInsert(); |
|
1119 break; |
|
1120 } |
|
1121 case EKeyEscape: |
|
1122 { |
|
1123 HandleEscape(); |
|
1124 break; |
|
1125 } |
|
1126 case EKeyF4: |
|
1127 case EKeyF8: |
|
1128 { |
|
1129 HandleF8Completion(); |
|
1130 break; |
|
1131 } |
|
1132 default: |
|
1133 { |
|
1134 if ((aKeyCode >= EKeySpace) && (aKeyCode < ENonCharacterKeyBase)) |
|
1135 { |
|
1136 InsertChar(aKeyCode); |
|
1137 } |
|
1138 break; |
|
1139 } |
|
1140 } |
|
1141 } |
|
1142 } |
|
1143 |
|
1144 EXPORT_C void CLineEditor::Start(const TDesC& aPrompt) |
|
1145 { |
|
1146 iLine.Start(aPrompt, KNullDesC); |
|
1147 } |
|
1148 |
|
1149 EXPORT_C void CLineEditor::Start(const TDesC& aPrompt, const TDesC& aInitialInput) |
|
1150 { |
|
1151 iLine.Start(aPrompt, aInitialInput); |
|
1152 } |
|
1153 |
|
1154 EXPORT_C void CLineEditor::Abort() |
|
1155 { |
|
1156 iLine.Abort(); |
|
1157 } |
|
1158 |
|
1159 EXPORT_C void CLineEditor::Redraw() |
|
1160 { |
|
1161 iLine.Redraw(); |
|
1162 } |
|
1163 |
|
1164 EXPORT_C void CLineEditor::RemovePromptAndUserInput() |
|
1165 { |
|
1166 iLine.Hide(); |
|
1167 } |
|
1168 |
|
1169 EXPORT_C void CLineEditor::ReinstatePromptAndUserInput() |
|
1170 { |
|
1171 iLine.Show(); |
|
1172 } |
|
1173 |
|
1174 void CLineEditor::InsertChar(TChar aChar) |
|
1175 { |
|
1176 (iMode == EInsert) ? iLine.Insert(aChar) : iLine.Overwrite(aChar); |
|
1177 SetState(EEditing); |
|
1178 } |
|
1179 |
|
1180 void CLineEditor::HandleEnter() |
|
1181 { |
|
1182 if (iLine.Contents().Length() > 0) |
|
1183 { |
|
1184 iHistory->AddL(iLine.Contents()); |
|
1185 } |
|
1186 iLine.End(); |
|
1187 iObserver.LeoHandleLine(iLine.Contents()); |
|
1188 SetState(EIdle); |
|
1189 } |
|
1190 |
|
1191 void CLineEditor::HandleBackspace() |
|
1192 { |
|
1193 SetState(EEditing); |
|
1194 iLine.DeleteLeft(); |
|
1195 } |
|
1196 |
|
1197 void CLineEditor::HandleTab() |
|
1198 { |
|
1199 SetState(EEditing); |
|
1200 #ifdef EKA2 |
|
1201 TRAP_IGNORE(HandleTabL()); |
|
1202 #else |
|
1203 TRAPD(err, HandleTabL()); |
|
1204 #endif |
|
1205 } |
|
1206 |
|
1207 void CLineEditor::HandleTabL() |
|
1208 { |
|
1209 iCompleter.LcCompleteLineL(iLine, TChar('/')); |
|
1210 } |
|
1211 |
|
1212 void CLineEditor::HandleDelete() |
|
1213 { |
|
1214 SetState(EEditing); |
|
1215 iLine.DeleteRight(); |
|
1216 } |
|
1217 |
|
1218 void CLineEditor::HandleLeftArrow() |
|
1219 { |
|
1220 SetState(EEditing); |
|
1221 iLine.CursorLeft(); |
|
1222 } |
|
1223 |
|
1224 void CLineEditor::HandleRightArrow() |
|
1225 { |
|
1226 SetState(EEditing); |
|
1227 iLine.CursorRight(); |
|
1228 } |
|
1229 |
|
1230 void CLineEditor::HandleUpArrow() |
|
1231 { |
|
1232 ReplaceLine(iHistory->Recall(CLineHistory::EPrevious)); |
|
1233 } |
|
1234 |
|
1235 void CLineEditor::HandleDownArrow() |
|
1236 { |
|
1237 ReplaceLine(iHistory->Recall(CLineHistory::ENext)); |
|
1238 } |
|
1239 |
|
1240 void CLineEditor::HandlePreviousWord() |
|
1241 { |
|
1242 SetState(EEditing); |
|
1243 iLine.CursorPreviousWord(); |
|
1244 } |
|
1245 |
|
1246 void CLineEditor::HandleNextWord() |
|
1247 { |
|
1248 SetState(EEditing); |
|
1249 iLine.CursorNextWord(); |
|
1250 } |
|
1251 |
|
1252 void CLineEditor::HandleHome() |
|
1253 { |
|
1254 SetState(EEditing); |
|
1255 iLine.CursorBeginning(); |
|
1256 } |
|
1257 |
|
1258 void CLineEditor::HandleEnd() |
|
1259 { |
|
1260 SetState(EEditing); |
|
1261 iLine.CursorEnd(); |
|
1262 } |
|
1263 |
|
1264 void CLineEditor::HandlePageUp() |
|
1265 { |
|
1266 ReplaceLine(iHistory->Recall(CLineHistory::ELast)); |
|
1267 } |
|
1268 |
|
1269 void CLineEditor::HandlePageDown() |
|
1270 { |
|
1271 ReplaceLine(iHistory->Recall(CLineHistory::EFirst)); |
|
1272 } |
|
1273 |
|
1274 void CLineEditor::HandleInsert() |
|
1275 { |
|
1276 SetState(EEditing); |
|
1277 if (iMode == EInsert) |
|
1278 { |
|
1279 iMode = EOverwrite; |
|
1280 iConsole.SetCursorMode(RConsole::EOverwrite); |
|
1281 } |
|
1282 else |
|
1283 { |
|
1284 iMode = EInsert; |
|
1285 iConsole.SetCursorMode(RConsole::EInsert); |
|
1286 } |
|
1287 } |
|
1288 |
|
1289 void CLineEditor::HandleEscape() |
|
1290 { |
|
1291 SetState(EEditing); |
|
1292 iLine.Replace(KNullDesC); |
|
1293 } |
|
1294 |
|
1295 |
|
1296 void CLineEditor::ReplaceLine(const TDesC& aNewLine) |
|
1297 { |
|
1298 TPtrC newLine(aNewLine); |
|
1299 |
|
1300 if (iState == EEditing) |
|
1301 { |
|
1302 if (aNewLine.Length() == 0) |
|
1303 { |
|
1304 return; |
|
1305 } |
|
1306 iLineBackup = iLine.Contents(); |
|
1307 SetState(ERecallingHistory); |
|
1308 } |
|
1309 else if ((iState == ERecallingHistory) && (aNewLine.Length() == 0)) |
|
1310 { |
|
1311 SetState(EEditing); |
|
1312 newLine.Set(iLineBackup); |
|
1313 } |
|
1314 else |
|
1315 { |
|
1316 SetState(ERecallingHistory); |
|
1317 } |
|
1318 |
|
1319 iLine.Replace(newLine); |
|
1320 } |
|
1321 |
|
1322 void CLineEditor::SetState(TState aState) |
|
1323 { |
|
1324 if ((aState == EEditing) && (iState != EEditing)) |
|
1325 { |
|
1326 iHistory->Reset(); |
|
1327 } |
|
1328 iState = aState; |
|
1329 } |
|
1330 |
|
1331 void CLineEditor::HandleF8Completion() |
|
1332 { |
|
1333 // Search the history backwards for a line matching everything currently entered |
|
1334 TPtrC toMatch = iLine.ContentsToCursor(); |
|
1335 TPtrC history = iHistory->RecallMatch(toMatch); |
|
1336 if (history.Length()) |
|
1337 { |
|
1338 ReplaceLine(history); |
|
1339 iLine.SetCursorPosition(toMatch.Length()); |
|
1340 } |
|
1341 } |