/* This file is part of the KDE libraries Copyright (C) 2000 David Smith 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 #include #include #include #include #include #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"