KIO
kshellcompletion.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kshellcompletion.h"
00021
00022 #include <stdlib.h>
00023 #include <kdebug.h>
00024 #include <QtCore/QCharRef>
00025 #include <QtCore/QMutableStringListIterator>
00026 #include <QtCore/QRegExp>
00027 #include <kcompletion.h>
00028
00029 class KShellCompletionPrivate
00030 {
00031 public:
00032 KShellCompletionPrivate()
00033 : m_word_break_char(' ')
00034 , m_quote_char1( '\"' )
00035 , m_quote_char2( '\'' )
00036 , m_escape_char( '\\' )
00037 {
00038 }
00039
00040 void splitText(const QString &text, QString &text_start, QString &text_compl) const;
00041 bool quoteText(QString *text, bool force, bool skip_last) const;
00042 QString unquote(const QString &text) const;
00043
00044 QString m_text_start;
00045 QString m_text_compl;
00046
00047 QChar m_word_break_char;
00048 QChar m_quote_char1;
00049 QChar m_quote_char2;
00050 QChar m_escape_char;
00051 };
00052
00053 KShellCompletion::KShellCompletion()
00054 : KUrlCompletion(),
00055 d( new KShellCompletionPrivate )
00056 {
00057 }
00058
00059 KShellCompletion::~KShellCompletion()
00060 {
00061 delete d;
00062 }
00063
00064
00065
00066
00067
00068
00069
00070 QString KShellCompletion::makeCompletion(const QString &text)
00071 {
00072
00073
00074 d->splitText(text, d->m_text_start, d->m_text_compl);
00075
00076
00077
00078 QString tmp = d->unquote(d->m_text_compl);
00079 d->m_text_compl = tmp;
00080
00081
00082
00083 bool is_exe_completion = true;
00084
00085 for ( int i = 0; i < d->m_text_start.length(); i++ ) {
00086 if ( d->m_text_start[i] != d->m_word_break_char ) {
00087 is_exe_completion = false;
00088 break;
00089 }
00090 }
00091
00092 Mode mode = (is_exe_completion ? ExeCompletion : FileCompletion );
00093
00094 setMode(mode);
00095
00096
00097
00098 return KUrlCompletion::makeCompletion( d->m_text_compl );
00099 }
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109 void KShellCompletion::postProcessMatch( QString *match ) const
00110 {
00111 KUrlCompletion::postProcessMatch( match );
00112
00113 if ( match->isNull() )
00114 return;
00115
00116 if ( match->endsWith( QLatin1Char( '/' ) ) )
00117 d->quoteText( match, false, true );
00118 else
00119 d->quoteText( match, false, false );
00120
00121 match->prepend( d->m_text_start );
00122 }
00123
00124 void KShellCompletion::postProcessMatches( QStringList *matches ) const
00125 {
00126 KUrlCompletion::postProcessMatches( matches );
00127
00128 for ( QStringList::Iterator it = matches->begin();
00129 it != matches->end(); ++it )
00130 {
00131 if ( !(*it).isNull() ) {
00132 if ( (*it).endsWith( QLatin1Char( '/' ) ) )
00133 d->quoteText( &(*it), false, true );
00134 else
00135 d->quoteText( &(*it), false, false );
00136
00137 (*it).prepend( d->m_text_start );
00138 }
00139 }
00140 }
00141
00142 void KShellCompletion::postProcessMatches( KCompletionMatches *matches ) const
00143 {
00144 KUrlCompletion::postProcessMatches( matches );
00145
00146 for ( KCompletionMatches::Iterator it = matches->begin();
00147 it != matches->end(); ++it )
00148 {
00149 if ( !(*it).value().isNull() ) {
00150 if ( (*it).value().endsWith( QLatin1Char( '/' ) ) )
00151 d->quoteText( &(*it).value(), false, true );
00152 else
00153 d->quoteText( &(*it).value(), false, false );
00154
00155 (*it).value().prepend( d->m_text_start );
00156 }
00157 }
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 void KShellCompletionPrivate::splitText(const QString &text, QString &text_start,
00169 QString &text_compl) const
00170 {
00171 bool in_quote = false;
00172 bool escaped = false;
00173 QChar p_last_quote_char;
00174 int last_unquoted_space = -1;
00175 int end_space_len = 0;
00176
00177 for (int pos = 0; pos < text.length(); pos++) {
00178
00179 end_space_len = 0;
00180
00181 if ( escaped ) {
00182 escaped = false;
00183 }
00184 else if ( in_quote && text[pos] == p_last_quote_char ) {
00185 in_quote = false;
00186 }
00187 else if ( !in_quote && text[pos] == m_quote_char1 ) {
00188 p_last_quote_char = m_quote_char1;
00189 in_quote = true;
00190 }
00191 else if ( !in_quote && text[pos] == m_quote_char2 ) {
00192 p_last_quote_char = m_quote_char2;
00193 in_quote = true;
00194 }
00195 else if ( text[pos] == m_escape_char ) {
00196 escaped = true;
00197 }
00198 else if ( !in_quote && text[pos] == m_word_break_char ) {
00199
00200 end_space_len = 1;
00201
00202 while ( pos+1 < text.length() && text[pos+1] == m_word_break_char ) {
00203 end_space_len++;
00204 pos++;
00205 }
00206
00207 if ( pos+1 == text.length() )
00208 break;
00209
00210 last_unquoted_space = pos;
00211 }
00212 }
00213
00214 text_start = text.left( last_unquoted_space + 1 );
00215
00216
00217 text_compl = text.mid( last_unquoted_space + 1 );
00218 }
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 bool KShellCompletionPrivate::quoteText(QString *text, bool force, bool skip_last) const
00229 {
00230 int pos = 0;
00231
00232 if ( !force ) {
00233 pos = text->indexOf( m_word_break_char );
00234 if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
00235 }
00236
00237 if ( !force && pos == -1 ) {
00238 pos = text->indexOf( m_quote_char1 );
00239 if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
00240 }
00241
00242 if ( !force && pos == -1 ) {
00243 pos = text->indexOf( m_quote_char2 );
00244 if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
00245 }
00246
00247 if ( !force && pos == -1 ) {
00248 pos = text->indexOf( m_escape_char );
00249 if ( skip_last && (pos == (int)(text->length())-1) ) pos = -1;
00250 }
00251
00252 if ( force || (pos >= 0) ) {
00253
00254
00255 text->replace( m_escape_char,
00256 QString( m_escape_char ) + m_escape_char );
00257
00258
00259 text->replace( m_quote_char1,
00260 QString( m_escape_char ) + m_quote_char1 );
00261
00262
00263 text->insert( 0, m_quote_char1 );
00264
00265
00266 if ( skip_last )
00267 text->insert( text->length()-1, m_quote_char1 );
00268 else
00269 text->insert( text->length(), m_quote_char1 );
00270
00271 return true;
00272 }
00273
00274 return false;
00275 }
00276
00277
00278
00279
00280
00281
00282
00283 QString KShellCompletionPrivate::unquote(const QString &text) const
00284 {
00285 bool in_quote = false;
00286 bool escaped = false;
00287 QChar p_last_quote_char;
00288 QString result;
00289
00290 for (int pos = 0; pos < text.length(); pos++) {
00291
00292 if ( escaped ) {
00293 escaped = false;
00294 result.insert( result.length(), text[pos] );
00295 }
00296 else if ( in_quote && text[pos] == p_last_quote_char ) {
00297 in_quote = false;
00298 }
00299 else if ( !in_quote && text[pos] == m_quote_char1 ) {
00300 p_last_quote_char = m_quote_char1;
00301 in_quote = true;
00302 }
00303 else if ( !in_quote && text[pos] == m_quote_char2 ) {
00304 p_last_quote_char = m_quote_char2;
00305 in_quote = true;
00306 }
00307 else if ( text[pos] == m_escape_char ) {
00308 escaped = true;
00309 result.insert( result.length(), text[pos] );
00310 }
00311 else {
00312 result.insert( result.length(), text[pos] );
00313 }
00314
00315 }
00316
00317 return result;
00318 }
00319
00320 #include "kshellcompletion.moc"
00321