|
|
|
/* This file is part of the KDE libraries
|
|
|
|
Copyright (C) 2000 David Smith <dsmith@algonet.se>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <tqstring.h>
|
|
|
|
#include <tqstringlist.h>
|
|
|
|
#include <tqregexp.h>
|
|
|
|
#include <kcompletion.h>
|
|
|
|
|
|
|
|
#include "kshellcompletion.h"
|
|
|
|
|
|
|
|
class KShellCompletionPrivate
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
KShellCompletion::KShellCompletion() : KURLCompletion()
|
|
|
|
{
|
|
|
|
m_word_break_char = ' ';
|
|
|
|
m_quote_char1 = '\"';
|
|
|
|
m_quote_char2 = '\'';
|
|
|
|
m_escape_char = '\\';
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* makeCompletion()
|
|
|
|
*
|
|
|
|
* Entry point for file name completion
|
|
|
|
*/
|
|
|
|
TQString KShellCompletion::makeCompletion(const TQString &text)
|
|
|
|
{
|
|
|
|
// Split text at the last unquoted space
|
|
|
|
//
|
|
|
|
splitText(text, m_text_start, m_text_compl);
|
|
|
|
|
|
|
|
// Remove quotes from the text to be completed
|
|
|
|
//
|
|
|
|
TQString tmp = unquote(m_text_compl);
|
|
|
|
m_text_compl = tmp;
|
|
|
|
|
|
|
|
// Do exe-completion if there was no unquoted space
|
|
|
|
//
|
|
|
|
bool is_exe_completion = true;
|
|
|
|
|
|
|
|
for ( uint i = 0; i < m_text_start.length(); i++ ) {
|
|
|
|
if ( m_text_start[i] != m_word_break_char ) {
|
|
|
|
is_exe_completion = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Mode mode = (is_exe_completion ? ExeCompletion : FileCompletion );
|
|
|
|
|
|
|
|
setMode(mode);
|
|
|
|
|
|
|
|
// Make completion on the last part of text
|
|
|
|
//
|
|
|
|
return KURLCompletion::makeCompletion( m_text_compl );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* postProcessMatch, postProcessMatches
|
|
|
|
*
|
|
|
|
* Called by TDECompletion before emitting match() and matches()
|
|
|
|
*
|
|
|
|
* Add add the part of the text that was not completed
|
|
|
|
* Add quotes when needed
|
|
|
|
*/
|
|
|
|
void KShellCompletion::postProcessMatch( TQString *match ) const
|
|
|
|
{
|
|
|
|
//kDebugInfo("KShellCompletion::postProcessMatch() in: '%s'",
|
|
|
|
// match->latin1());
|
|
|
|
|
|
|
|
KURLCompletion::postProcessMatch( match );
|
|
|
|
|
|
|
|
if ( match->isNull() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( match->right(1) == TQChar('/') )
|
|
|
|
quoteText( match, false, true ); // don't quote the trailing '/'
|
|
|
|
else
|
|
|
|
quoteText( match, false, false ); // quote the whole text
|
|
|
|
|
|
|
|
match->prepend( m_text_start );
|
|
|
|
|
|
|
|
//kDebugInfo("KShellCompletion::postProcessMatch() ut: '%s'",
|
|
|
|
// match->latin1());
|
|
|
|
}
|
|
|
|
|
|
|
|
void KShellCompletion::postProcessMatches( TQStringList *matches ) const
|
|
|
|
{
|
|
|
|
KURLCompletion::postProcessMatches( matches );
|
|
|
|
|
|
|
|
for ( TQStringList::Iterator it = matches->begin();
|
|
|
|
it != matches->end(); it++ )
|
|
|
|
{
|
|
|
|
if ( !(*it).isNull() ) {
|
|
|
|
if ( (*it).right(1) == TQChar('/') )
|
|
|
|
quoteText( &(*it), false, true ); // don't quote trailing '/'
|
|
|
|
else
|
|
|
|
quoteText( &(*it), false, false ); // quote the whole text
|
|
|
|
|
|
|
|
(*it).prepend( m_text_start );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KShellCompletion::postProcessMatches( TDECompletionMatches *matches ) const
|
|
|
|
{
|
|
|
|
KURLCompletion::postProcessMatches( matches );
|
|
|
|
|
|
|
|
for ( TDECompletionMatches::Iterator it = matches->begin();
|
|
|
|
it != matches->end(); it++ )
|
|
|
|
{
|
|
|
|
if ( !(*it).value().isNull() ) {
|
|
|
|
if ( (*it).value().right(1) == TQChar('/') )
|
|
|
|
quoteText( &(*it).value(), false, true ); // don't quote trailing '/'
|
|
|
|
else
|
|
|
|
quoteText( &(*it).value(), false, false ); // quote the whole text
|
|
|
|
|
|
|
|
(*it).value().prepend( m_text_start );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* splitText
|
|
|
|
*
|
|
|
|
* Split text at the last unquoted space
|
|
|
|
*
|
|
|
|
* text_start = [out] text at the left, including the space
|
|
|
|
* text_compl = [out] text at the right
|
|
|
|
*/
|
|
|
|
void KShellCompletion::splitText(const TQString &text, TQString &text_start,
|
|
|
|
TQString &text_compl) const
|
|
|
|
{
|
|
|
|
bool in_quote = false;
|
|
|
|
bool escaped = false;
|
|
|
|
TQChar p_last_quote_char;
|
|
|
|
int last_unquoted_space = -1;
|
|
|
|
int end_space_len = 0;
|
|
|
|
|
|
|
|
for (uint pos = 0; pos < text.length(); pos++) {
|
|
|
|
|
|
|
|
end_space_len = 0;
|
|
|
|
|
|
|
|
if ( escaped ) {
|
|
|
|
escaped = false;
|
|
|
|
}
|
|
|
|
else if ( in_quote && text[pos] == p_last_quote_char ) {
|
|
|
|
in_quote = false;
|
|
|
|
}
|
|
|
|
else if ( !in_quote && text[pos] == m_quote_char1 ) {
|
|
|
|
p_last_quote_char = m_quote_char1;
|
|
|
|
in_quote = true;
|
|
|
|
}
|
|
|
|
else if ( !in_quote && text[pos] == m_quote_char2 ) {
|
|
|
|
p_last_quote_char = m_quote_char2;
|
|
|
|
in_quote = true;
|
|
|
|
}
|
|
|
|
else if ( text[pos] == m_escape_char ) {
|
|
|
|
escaped = true;
|
|
|
|
}
|
|
|
|
else if ( !in_quote && text[pos] == m_word_break_char ) {
|
|
|
|
|
|
|
|
end_space_len = 1;
|
|
|
|
|
|
|
|
while ( pos+1 < text.length() && text[pos+1] == m_word_break_char ) {
|
|
|
|
end_space_len++;
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pos+1 == text.length() )
|
|
|
|
break;
|
|
|
|
|
|
|
|
last_unquoted_space = pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
text_start = text.left( last_unquoted_space + 1 );
|
|
|
|
|
|
|
|
// the last part without trailing blanks
|
|
|
|
text_compl = text.mid( last_unquoted_space + 1 );
|
|
|
|
|
|
|
|
// text_compl = text.mid( last_unquoted_space + 1,
|
|
|
|
// text.length() - end_space_len - (last_unquoted_space + 1) );
|
|
|
|
|
|
|
|
//kDebugInfo("split right = '%s'", text_compl.latin1());
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* quoteText()
|
|
|
|
*
|
|
|
|
* Add quotations to 'text' if needed or if 'force' = true
|
|
|
|
* Returns true if quotes were added
|
|
|
|
*
|
|
|
|
* skip_last => ignore the last charachter (we add a space or '/' to all filenames)
|
|
|
|
*/
|
|
|
|
bool KShellCompletion::quoteText(TQString *text, bool force, bool skip_last) const
|
|
|
|
{
|
|
|
|
int pos = 0;
|
|
|
|
|
|
|
|
if ( !force ) {
|
|
|
|
pos = text->find( m_word_break_char );
|
|
|
|
if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !force && pos == -1 ) {
|
|
|
|
pos = text->find( m_quote_char1 );
|
|
|
|
if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !force && pos == -1 ) {
|
|
|
|
pos = text->find( m_quote_char2 );
|
|
|
|
if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !force && pos == -1 ) {
|
|
|
|
pos = text->find( m_escape_char );
|
|
|
|
if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( force || (pos >= 0) ) {
|
|
|
|
|
|
|
|
// Escape \ in the string
|
|
|
|
text->replace( m_escape_char,
|
|
|
|
TQString( m_escape_char ) + m_escape_char );
|
|
|
|
|
|
|
|
// Escape " in the string
|
|
|
|
text->replace( m_quote_char1,
|
|
|
|
TQString( m_escape_char ) + m_quote_char1 );
|
|
|
|
|
|
|
|
// " at the beginning
|
|
|
|
text->insert( 0, m_quote_char1 );
|
|
|
|
|
|
|
|
// " at the end
|
|
|
|
if ( skip_last )
|
|
|
|
text->insert( text->length()-1, m_quote_char1 );
|
|
|
|
else
|
|
|
|
text->insert( text->length(), m_quote_char1 );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* unquote
|
|
|
|
*
|
|
|
|
* Remove quotes and return the result in a new string
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
TQString KShellCompletion::unquote(const TQString &text) const
|
|
|
|
{
|
|
|
|
bool in_quote = false;
|
|
|
|
bool escaped = false;
|
|
|
|
TQChar p_last_quote_char;
|
|
|
|
TQString result;
|
|
|
|
|
|
|
|
for (uint pos = 0; pos < text.length(); pos++) {
|
|
|
|
|
|
|
|
if ( escaped ) {
|
|
|
|
escaped = false;
|
|
|
|
result.insert( result.length(), text[pos] );
|
|
|
|
}
|
|
|
|
else if ( in_quote && text[pos] == p_last_quote_char ) {
|
|
|
|
in_quote = false;
|
|
|
|
}
|
|
|
|
else if ( !in_quote && text[pos] == m_quote_char1 ) {
|
|
|
|
p_last_quote_char = m_quote_char1;
|
|
|
|
in_quote = true;
|
|
|
|
}
|
|
|
|
else if ( !in_quote && text[pos] == m_quote_char2 ) {
|
|
|
|
p_last_quote_char = m_quote_char2;
|
|
|
|
in_quote = true;
|
|
|
|
}
|
|
|
|
else if ( text[pos] == m_escape_char ) {
|
|
|
|
escaped = true;
|
|
|
|
result.insert( result.length(), text[pos] );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
result.insert( result.length(), text[pos] );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KShellCompletion::virtual_hook( int id, void* data )
|
|
|
|
{ KURLCompletion::virtual_hook( id, data ); }
|
|
|
|
|
|
|
|
#include "kshellcompletion.moc"
|
|
|
|
|