userlibandfileserver/fileserver/etshell/ts_clicomp.cpp
author Mike Kinghan <mikek@symbian.org>
Tue, 16 Nov 2010 14:39:21 +0000
branchGCC_SURGE
changeset 303 9b85206a602c
parent 0 a41df078684a
permissions -rw-r--r--
We need a way to pass flags to rombuilds in Raptor via extension flm interfaces, so that the CPP pass of the rom input files can be informed what toolchain we are building with and conditionally include or exclude files depending on whether the toolchain could build them.

// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// f32\etshell\ts_clicomp.cpp
// 
//

#include "ts_clicomp.h"
#include "ts_std.h"

CCliCompleter::CCliCompleter()
	{	
	}
	
CCliCompleter* CCliCompleter::NewL()
	{
	CCliCompleter* self = new(ELeave) CCliCompleter();
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop();
	
	return self;
	}
	
void CCliCompleter::ConstructL()
	{
	User::LeaveIfError(iFs.Connect());
	}

CCliCompleter::~CCliCompleter()
	{
	iFs.Close();
	}

void CCliCompleter::EstablishCompletionContext(TDesC& aBuf, TUint aPos, TDes& aKnownPart)
	{
	// Try and locate a double-quote to the left of the current cursor position
	TInt contextStart = aBuf.Mid(0, aPos).LocateReverse(TChar('"'));	
	TInt contextEnd;
	
	if(contextStart != KErrNotFound)
		{ // Double-quote found
		contextEnd = aPos - contextStart;
		// Grab a copy of the text we will be trying to complete
		aKnownPart = aBuf.Mid(contextStart, contextEnd);
		}
	else
		{ // Try from the last space character
		contextStart = aBuf.Mid(0, aPos).LocateReverse(TChar(' '));

		if(contextStart == KErrNotFound)
			{
			contextStart = 0;
			}
		else
			{
			contextStart += 1;
			}
			
		contextEnd = aPos - contextStart;

		aKnownPart = aBuf.Mid(contextStart, contextEnd);
		aKnownPart.Trim();
		}
	}

TBool CCliCompleter::AttemptCompletionL(TDes& aKnownPart, RPointerArray<HBufC>& aAlternatives)
	{
	// Turn the known part into something with a path
	TParse parsedKnownPart;

	// ShellFunction::GetFullPath() modifies the source path so create
	// a temporary buffer for a throwaway copy
	TBuf<KMaxPath> tmpKnownPart = aKnownPart;
	ShellFunction::StripQuotes(tmpKnownPart);
	tmpKnownPart.Append(KMatchAny);
	
	if(ShellFunction::GetFullPath(tmpKnownPart, parsedKnownPart) != KErrNone)
		{
		return EFalse;
		}
	
	CDir* entries;	
	if(iFs.GetDir(parsedKnownPart.FullName(), KEntryAttNormal | KEntryAttDir, ESortByName, entries) != KErrNone)
		{
		return EFalse;
		}

	CleanupStack::PushL(entries);

	TEntry entry;
	TBool result;

	if(entries->Count() == 1)
		{
		entry = (*entries)[0];
	
		TPtrC completedPart;	
		completedPart.Set(entry.iName.Mid(parsedKnownPart.NameAndExt().Length() - 1));
		aKnownPart.Append(completedPart);

		if(entry.IsDir()) aKnownPart.Append(KPathDelimiter);
		
		if(((TUint)aKnownPart[0] != TChar('"')) && 
			(aKnownPart.LocateF(TChar(' ')) != KErrNotFound))
			{
			aKnownPart.Insert(0, _L("\""));
			}
		
		result = ETrue;
		}
	else if(entries->Count() > 1)
		{
		TInt entryIdx;		
		
		// Find the smallest matching entry so as to not run off the end of
		// an index when trying to establish the greatest overlap between the
		// matches.  We're also caching the raw entries in a seperate array so
		// we can use them when displaying the ambiguous matches.
		TInt minLength = KMaxFileName;		
		
		for(entryIdx=0;entryIdx<entries->Count();entryIdx++)
			{
			entry = (*entries)[entryIdx];
			
			HBufC* buf = HBufC::NewLC(entry.iName.Length() + 100);
			*buf = entry.iName;
			if(entry.IsDir()) 
				{
				buf->Des().Append(KPathDelimiter);
				}
			aAlternatives.AppendL(buf);
			
			if(entry.iName.Length() < minLength)
				{
				minLength = entry.iName.Length();
				}
			}
		CleanupStack::Pop(entries->Count());
			
		// Find the greatest overlap between the matches.  Even though we can't
		// get a final match we can at least make a best-effort completion based 
		// on anything they've not told us but which matches anyway.
		
		// There's an asterisk on the end of the parsed filename that we want
		// to disregard when calculating the length of what we already know.
		TInt knownPartLength = parsedKnownPart.NameAndExt().Length() - 1;
		
		TInt matchLength = knownPartLength;
		TBool matching = ETrue;
		while(matching && matchLength < minLength)
			{			
			for(entryIdx=1;entryIdx<entries->Count();entryIdx++)
				{
				if(((*entries)[0].iName[matchLength]) != ((*entries)[entryIdx].iName[matchLength]))
					{
					matching = EFalse;
					}
				}
			if(matching) matchLength++;
			}

		if(matchLength > knownPartLength)
			{
			entry = (*entries)[0];
			
			TUint additionalKnownStart = knownPartLength;
			TUint additionalKnownLength = matchLength - knownPartLength;
			
			aKnownPart.Append(entry.iName.Mid(additionalKnownStart, additionalKnownLength));
			}

		result = EFalse;
		}
	else	
		{
		result = EFalse;
		}
	
	CleanupStack::PopAndDestroy(entries);
	
	return result;
	}


/*
	Note: method has the potential to modify the size of aAlternatives as 
	a side-effect of the call to ShellFunction::AlignTextIntoColumns().
*/
void CCliCompleter::DisplayAlternatives(RPointerArray<HBufC>& aAlternatives)
	{
	ShellFunction::AlignTextIntoColumns(aAlternatives);
	
	CShell::NewLine();
	for(TInt entryIdx=0;entryIdx<aAlternatives.Count();entryIdx++)
		{
		CShell::OutputStringToConsole(EFalse, *aAlternatives[entryIdx]);
		CShell::NewLine();
		}
	}