libraries/lineeditor/src/line_editor.cpp
changeset 0 7f656887cf89
child 66 9c352d34f5aa
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     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 	}