Index: interfaces/ktexteditor/codecompletionmodel.h
===================================================================
--- interfaces/ktexteditor/codecompletionmodel.h	(Revision 884497)
+++ interfaces/ktexteditor/codecompletionmodel.h	(Arbeitskopie)
@@ -421,6 +421,7 @@
 
   Q_SIGNALS:
     void hasGroupsChanged(KTextEditor::CodeCompletionModel *model,bool hasGroups);
+    void modifyCompletionRange(const KTextEditor::Range& word, const QRegExp& allowedText);
 
   protected:
     void setHasGroups(bool hasGroups);
Index: kate/completion/katecompletionmodel.cpp
===================================================================
--- kate/completion/katecompletionmodel.cpp	(Revision 884497)
+++ kate/completion/katecompletionmodel.cpp	(Arbeitskopie)
@@ -586,7 +586,7 @@
   Item item = Item(this, handler, ModelRow(handler.model(), QPersistentModelIndex(sourceIndex)));
 
   if(g != m_argumentHints)
-    item.match(m_currentMatch);
+    item.match();
 
   g->addItem(item, notifyModel);
 
@@ -859,44 +859,47 @@
   return QModelIndex();
 }
 
-void KateCompletionModel::setCurrentCompletion( const QString & completion )
+void KateCompletionModel::setCurrentCompletion( KTextEditor::CodeCompletionModel* model, const QString & completion )
 {
-  if (m_currentMatch == completion)
+  if (m_currentMatch[model] == completion)
     return;
 
   if (!hasCompletionModel()) {
-    m_currentMatch = completion;
+    m_currentMatch[model] = completion;
     return;
   }
 
   changeTypes changeType = Change;
 
-  if (m_currentMatch.length() > completion.length() && m_currentMatch.startsWith(completion, m_matchCaseSensitivity)) {
+  if (m_currentMatch[model].length() > completion.length() && m_currentMatch[model].startsWith(completion, m_matchCaseSensitivity)) {
     // Filter has been broadened
     changeType = Broaden;
 
-  } else if (m_currentMatch.length() < completion.length() && completion.startsWith(m_currentMatch, m_matchCaseSensitivity)) {
+  } else if (m_currentMatch[model].length() < completion.length() && completion.startsWith(m_currentMatch[model], m_matchCaseSensitivity)) {
     // Filter has been narrowed
     changeType = Narrow;
   }
 
-  kDebug( 13035 ) << "Old match: " << m_currentMatch << ", new: " << completion << ", type: " << changeType;
+  kDebug( 13035 ) << model << "Old match: " << m_currentMatch[model] << ", new: " << completion << ", type: " << changeType;
 
-  if (!hasGroups())
-    changeCompletions(m_ungrouped, completion, changeType);
-  else {
-    foreach (Group* g, m_rowTable)
+  m_currentMatch[model] = completion;
+
+  if (!hasGroups()) {
+    changeCompletions(m_ungrouped, changeType);
+  } else {
+    foreach (Group* g, m_rowTable) {
       if(g != m_argumentHints)
-        changeCompletions(g, completion, changeType);
-    foreach (Group* g, m_emptyGroups)
+        changeCompletions(g, changeType);
+    }
+    foreach (Group* g, m_emptyGroups) {
       if(g != m_argumentHints)
-        changeCompletions(g, completion, changeType);
+        changeCompletions(g, changeType);
+    }
 
     updateBestMatches();
   }
 
   clearExpanding(); //We need to do this, or be aware of expanding-widgets while filtering.
-  m_currentMatch = completion;
 
   emit contentGeometryChanged();
 }
@@ -904,16 +907,16 @@
 void KateCompletionModel::rematch()
 {
   if (!hasGroups()) {
-    changeCompletions(m_ungrouped, m_currentMatch, Change);
+    changeCompletions(m_ungrouped, Change);
 
   } else {
     foreach (Group* g, m_rowTable)
       if(g != m_argumentHints)
-        changeCompletions(g, m_currentMatch, Change);
+        changeCompletions(g, Change);
 
     foreach (Group* g, m_emptyGroups)
       if(g != m_argumentHints)
-        changeCompletions(g, m_currentMatch, Change);
+        changeCompletions(g, Change);
 
     updateBestMatches();
   }
@@ -940,7 +943,7 @@
     rowAdd.clear(); \
   }
 
-void KateCompletionModel::changeCompletions( Group * g, const QString & newCompletion, changeTypes changeType )
+void KateCompletionModel::changeCompletions( Group * g, changeTypes changeType )
 {
   QMutableListIterator<Item> filtered = g->filtered;
   QMutableListIterator<Item> prefilter = g->prefilter;
@@ -956,7 +959,7 @@
       if (filtered.peekNext().sourceRow() == prefilter.peekNext().sourceRow()) {
         // Currently being displayed
         if (changeType != Broaden) {
-          if (prefilter.peekNext().match(newCompletion)) {
+          if (prefilter.peekNext().match()) {
             // no change required to this item
             COMPLETE_DELETE
             COMPLETE_ADD
@@ -981,7 +984,7 @@
       } else {
         // Currently hidden
         if (changeType != Narrow) {
-          if (prefilter.peekNext().match(newCompletion)) {
+          if (prefilter.peekNext().match()) {
             // needs to be made visible
             COMPLETE_DELETE
 
@@ -1005,7 +1008,7 @@
     } else {
       // Currently hidden
       if (changeType != Narrow) {
-        if (prefilter.peekNext().match(newCompletion)) {
+        if (prefilter.peekNext().match()) {
           // needs to be made visible
           COMPLETE_DELETE
 
@@ -1716,19 +1719,17 @@
   return matchFilters;
 }
 
-bool KateCompletionModel::Item::match(const QString& newCompletion)
+bool KateCompletionModel::Item::match()
 {
-  // Hehe, everything matches nothing! (ie. everything matches a blank string)
-  if (newCompletion.isEmpty())
-    return true;
-
   // Check to see if the item is matched by the current completion string
   QModelIndex sourceIndex = m_sourceRow.second.sibling(m_sourceRow.second.row(), CodeCompletionModel::Name);
 
-  QString match = newCompletion;
-  if (match.isEmpty())
-    match = model->currentCompletion();
+  QString match = model->currentCompletion(m_sourceRow.first);
 
+   // Hehe, everything matches nothing! (ie. everything matches a blank string)
+   if (match.isEmpty())
+     return true;
+
   matchCompletion = m_nameColumn.startsWith(match, model->matchCaseSensitivity());
   return matchCompletion;
 }
@@ -1827,9 +1828,9 @@
   return m_sourceRow;
 }
 
-const QString & KateCompletionModel::currentCompletion( ) const
+QString KateCompletionModel::currentCompletion( KTextEditor::CodeCompletionModel* model ) const
 {
-  return m_currentMatch;
+  return m_currentMatch.value(model);
 }
 
 Qt::CaseSensitivity KateCompletionModel::matchCaseSensitivity( ) const
@@ -1887,6 +1888,8 @@
   if (!model || m_completionModels.contains(model))
     return;
 
+  m_currentMatch.remove(model);
+
   clearGroups();
 
   model->disconnect(this);
@@ -1979,6 +1982,8 @@
 
   m_completionModels.clear();
 
+  m_currentMatch.clear();
+
   clearGroups();
 
   reset();
Index: kate/completion/katecompletionmodel.h
===================================================================
--- kate/completion/katecompletionmodel.h	(Revision 884497)
+++ kate/completion/katecompletionmodel.h	(Arbeitskopie)
@@ -61,8 +61,8 @@
     KateView* view() const;
     KateCompletionWidget* widget() const;
 
-    const QString& currentCompletion() const;
-    void setCurrentCompletion(const QString& completion);
+    QString currentCompletion(KTextEditor::CodeCompletionModel* model) const;
+    void setCurrentCompletion(KTextEditor::CodeCompletionModel* model, const QString& completion);
 
     Qt::CaseSensitivity matchCaseSensitivity() const;
     void setMatchCaseSensitivity( Qt::CaseSensitivity cs );
@@ -209,7 +209,7 @@
         bool isMatching() const;
 
         bool filter();
-        bool match(const QString& newCompletion = QString());
+        bool match();
 
         const ModelRow& sourceRow() const;
 
@@ -293,7 +293,7 @@
     };
 
 
-    void changeCompletions(Group* g, const QString& newCompletion, changeTypes changeType);
+    void changeCompletions(Group* g, changeTypes changeType);
 
     void deleteRows(Group* g, QMutableListIterator<Item>& filtered, int countBackwards, int startRow);
     void addRows(Group* g, QMutableListIterator<Item>& filtered, int startRow, const QList<Item>& newItems);
@@ -314,7 +314,7 @@
     // ### Runtime state
     // General
     QList<KTextEditor::CodeCompletionModel*> m_completionModels;
-    QString m_currentMatch;
+    QMap<KTextEditor::CodeCompletionModel*, QString> m_currentMatch;
     Qt::CaseSensitivity m_matchCaseSensitivity;
 
     // Column merging
Index: kate/completion/katecompletionwidget.cpp
===================================================================
--- kate/completion/katecompletionwidget.cpp	(Revision 884497)
+++ kate/completion/katecompletionwidget.cpp	(Arbeitskopie)
@@ -56,7 +56,6 @@
 KateCompletionWidget::KateCompletionWidget(KateView* parent)
   : QFrame(parent, Qt::ToolTip)
   , m_presentationModel(new KateCompletionModel(this))
-  , m_completionRange(0L)
   , m_entryList(new KateCompletionTree(this))
   , m_argumentHintModel(new KateArgumentHintModel(this))
   , m_argumentHintTree(new KateArgumentHintTree(this))
@@ -202,7 +201,12 @@
     return;
   }
 
-  kDebug(13035) << word << " " << model;
+  QList<KTextEditor::CodeCompletionModel*> models;
+  if (model) {
+    models << model;
+  } else {
+    models = m_sourceModels;
+  }
 
   if (!m_filterInstalled) {
     if (!QApplication::activeWindow()) {
@@ -217,32 +221,14 @@
   if (isCompletionActive())
     abortCompletion();
 
-  m_completionRange = view()->doc()->smartManager()->newSmartRange(word);
-  m_completionRange->setInsertBehavior(KTextEditor::SmartRange::ExpandRight | KTextEditor::SmartRange::ExpandLeft);
-  if(!m_completionRange->isValid()) {
-    kWarning(13035) << "Could not construct valid smart-range from" << word << "instead got" << *m_completionRange;
-    abortCompletion();
-    return;
-  }
+  m_presentationModel->setCompletionModels(models);
 
-  connect(m_completionRange->smartStart().notifier(), SIGNAL(characterDeleted(KTextEditor::SmartCursor*, bool)), SLOT(startCharacterDeleted(KTextEditor::SmartCursor*, bool)));
-
-  cursorPositionChanged();
-
-  if (model)
+  foreach (KTextEditor::CodeCompletionModel* model, models) {
+    connect(model, SIGNAL(modifyCompletionRange(KTextEditor::Range, QRegExp)), SLOT(modifyCompletionRange(KTextEditor::Range, QRegExp)));
     model->completionInvoked(view(), word, invocationType);
-  else
-    foreach (KTextEditor::CodeCompletionModel* model, m_sourceModels)
-      model->completionInvoked(view(), word, invocationType);
-
-  kDebug( 13035 ) << "msdofjdsoifdsflkdsjf";
-  if (model)
-    m_presentationModel->setCompletionModel(model);
-  else
-    m_presentationModel->setCompletionModels(m_sourceModels);
-
-  if (!m_presentationModel->completionModels().isEmpty()) {
-    m_presentationModel->setCurrentCompletion(view()->doc()->text(KTextEditor::Range(m_completionRange->start(), view()->cursorPosition())));
+    if (!m_completionRanges.contains(model)) { //completionInvoked might emit modifyCompletionRange
+      completionRangeChanged(model, word);
+    }
   }
 
   connect(this->model(), SIGNAL(contentGeometryChanged()), this, SLOT(modelContentChanged()));
@@ -250,6 +236,40 @@
   modelContentChanged();
 }
 
+void KateCompletionWidget::modifyCompletionRange(const KTextEditor::Range& word, const QRegExp& allowedText)
+{
+  KTextEditor::CodeCompletionModel* model = qobject_cast<KTextEditor::CodeCompletionModel*>(sender());
+  Q_ASSERT(model);
+  kDebug() << model << word << allowedText;
+  m_allowedText[model] = allowedText;
+  completionRangeChanged(model, word);
+}
+
+void KateCompletionWidget::completionRangeChanged(KTextEditor::CodeCompletionModel* model, const KTextEditor::Range& word)
+{
+  if (m_completionRanges.contains(model)) {
+    if (*m_completionRanges[model] == word) {
+      kDebug() << "ignoring, range not changed";
+      return;
+    }
+    delete m_completionRanges[model];
+  }
+
+  m_completionRanges[model] = view()->doc()->smartManager()->newSmartRange(word);
+  m_completionRanges[model]->setInsertBehavior(KTextEditor::SmartRange::ExpandRight | KTextEditor::SmartRange::ExpandLeft);
+  if(!m_completionRanges[model]->isValid()) {
+    kWarning(13035) << "Could not construct valid smart-range from" << word << "instead got" << *m_completionRanges[model];
+    abortCompletion();
+    return;
+  }
+  connect(m_completionRanges[model]->smartStart().notifier(), SIGNAL(characterDeleted(KTextEditor::SmartCursor*, bool)),
+            SLOT(startCharacterDeleted(KTextEditor::SmartCursor*, bool)));
+
+  cursorPositionChanged();
+
+  m_presentationModel->setCurrentCompletion(model, view()->doc()->text(KTextEditor::Range(m_completionRanges[model]->start(), view()->cursorPosition())));
+}
+
 void KateCompletionWidget::updateAndShow()
 {
   setUpdatesEnabled(false);
@@ -285,7 +305,10 @@
     return false;
 //   kDebug() << "updating from" << geometry() << m_entryList->geometry();
 
-  QPoint cursorPosition = view()->cursorToCoordinate(m_completionRange->start());
+  if (!completionRange()) {
+    return false;
+  }
+  QPoint cursorPosition = view()->cursorToCoordinate(completionRange()->start());
   if (cursorPosition == QPoint(-1,-1)) {
     // Start of completion range is now off-screen -> abort
     abortCompletion();
@@ -403,23 +426,33 @@
 
   KTextEditor::Cursor cursor = view()->cursorPosition();
 
-  if (m_completionRange->start() > cursor || m_completionRange->end() < cursor)
-    return abortCompletion();
+  foreach (KateSmartRange* range, m_completionRanges) {
+    if (range->start() > cursor || range->end() < cursor)
+      return abortCompletion();
+  }
 
-  QString currentCompletion = view()->doc()->text(KTextEditor::Range(m_completionRange->start(), view()->cursorPosition()));
+  QMapIterator<KTextEditor::CodeCompletionModel*, KateSmartRange*> i(m_completionRanges);
+  while (i.hasNext()) {
+      i.next();
+      QString currentCompletion = view()->doc()->text(KTextEditor::Range(i.value()->start(), view()->cursorPosition()));
 
-  // FIXME - allow client to specify this?
-  static QRegExp allowedText("^(\\w*)");
-  if (!allowedText.exactMatch(currentCompletion))
-    return abortCompletion();
+      QRegExp allowedText("^(\\w*)");
+      if (m_allowedText.contains(i.key())) {
+        allowedText = m_allowedText[i.key()];
+      }
+      kDebug() << i.key() << i.value() << currentCompletion << allowedText;
+      if (!allowedText.exactMatch(currentCompletion))
+        return abortCompletion();
 
-  m_presentationModel->setCurrentCompletion(currentCompletion);
+      m_presentationModel->setCurrentCompletion(i.key(), currentCompletion);
+  }
+
   m_entryList->scheduleUpdate();
 }
 
 bool KateCompletionWidget::isCompletionActive( ) const
 {
-  return m_completionRange && isVisible();
+  return !m_completionRanges.isEmpty() && isVisible();
 }
 
 void KateCompletionWidget::abortCompletion( )
@@ -435,9 +468,6 @@
   if(isVisible())
     hide();
 
-  delete m_completionRange;
-  m_completionRange = 0L;
-
   if (wasActive)
     view()->sendCompletionAborted();
 }
@@ -446,6 +476,8 @@
   m_presentationModel->clearCompletionModels();
   m_argumentHintTree->clearCompletion();
   m_argumentHintModel->clear();
+  qDeleteAll(m_completionRanges);
+  m_completionRanges.clear();
 }
 
 bool KateCompletionWidget::embeddedWidgetAccept() {
@@ -491,8 +523,6 @@
     return abortCompletion();
   }
 
-  KTextEditor::Cursor start = m_completionRange->start();
-
   // encapsulate all editing as being from the code completion, and undo-able in one step.
   view()->doc()->editStart(true, Kate::CodeCompletionEdit);
 
@@ -501,17 +531,19 @@
 
   KTextEditor::CodeCompletionModel2* model2 = dynamic_cast<KTextEditor::CodeCompletionModel2*>(model);
 
+  KTextEditor::Cursor start = m_completionRanges[model]->start();
+
   //editStart locks the smart-mutex, but it must not be locked when calling external functions,
   //else we may get deadlock-issues.
   view()->doc()->smartMutex()->unlock();
   
   if(model2)
-    model2->executeCompletionItem2(view()->document(), *m_completionRange, toExecute);
+    model2->executeCompletionItem2(view()->document(), *m_completionRanges[model], toExecute);
   else if(toExecute.parent().isValid())
     //The normale CodeCompletionInterface cannot handle feedback for hierarchical models, so just do the replacement
-    view()->document()->replaceText(*m_completionRange, model->data(toExecute.sibling(toExecute.row(), KTextEditor::CodeCompletionModel::Name)).toString());
+    view()->document()->replaceText(*m_completionRanges[model], model->data(toExecute.sibling(toExecute.row(), KTextEditor::CodeCompletionModel::Name)).toString());
   else
-    model->executeCompletionItem(view()->document(), *m_completionRange, toExecute.row());
+    model->executeCompletionItem(view()->document(), *m_completionRanges[model], toExecute.row());
   
   //Relock, because editEnd expects it to be locked
   view()->doc()->smartMutex()->lock();
@@ -547,11 +579,20 @@
     abortCompletion();
 }
 
-KateSmartRange * KateCompletionWidget::completionRange( ) const
+KateSmartRange * KateCompletionWidget::completionRange(KTextEditor::CodeCompletionModel* model) const
 {
-  return m_completionRange;
+  if (!model) {
+    if (m_sourceModels.isEmpty()) return 0;
+    model = m_sourceModels.first();
+  }
+  return m_completionRanges[model];
 }
 
+QMap<KTextEditor::CodeCompletionModel*, KateSmartRange*> KateCompletionWidget::completionRanges( ) const
+{
+  return m_completionRanges;
+}
+
 void KateCompletionWidget::modelReset( )
 {
   setUpdatesEnabled(false);
Index: kate/completion/katecompletionwidget.h
===================================================================
--- kate/completion/katecompletionwidget.h	(Revision 884497)
+++ kate/completion/katecompletionwidget.h	(Arbeitskopie)
@@ -83,7 +83,8 @@
     int automaticInvocationDelay() const;
     void setAutomaticInvocationDelay(int delay);
     
-    KateSmartRange* completionRange() const;
+    KateSmartRange* completionRange(KTextEditor::CodeCompletionModel* model = 0) const;
+    QMap<KTextEditor::CodeCompletionModel*, KateSmartRange*> completionRanges( ) const;
 
     // Navigation
     void pageDown();
@@ -144,6 +145,7 @@
     void startCharacterDeleted(KTextEditor::SmartCursor* cursor, bool deletedBefore);
     void rowsInserted(const QModelIndex& parent, int row, int rowEnd);
     void viewFocusOut();
+    void modifyCompletionRange(const KTextEditor::Range& word, const QRegExp& allowedText);
   private:
     void updateAndShow();
     void updateArgumentHintGeometry();
@@ -153,11 +155,13 @@
     //Switch cursor between argument-hint list / completion-list
     void switchList();
     KTextEditor::Range determineRange() const;
+    void completionRangeChanged(KTextEditor::CodeCompletionModel*, const KTextEditor::Range& word);
 
     QList<KTextEditor::CodeCompletionModel*> m_sourceModels;
     KateCompletionModel* m_presentationModel;
 
-    KateSmartRange* m_completionRange;
+    QMap<KTextEditor::CodeCompletionModel*, KateSmartRange*> m_completionRanges;
+    QMap<KTextEditor::CodeCompletionModel*, QRegExp> m_allowedText;
     KTextEditor::Cursor m_lastCursorPosition;
 
     KateCompletionTree* m_entryList;
