initial commit
This commit is contained in:
commit
9d20827c46
2469 changed files with 470994 additions and 0 deletions
246
src/tabcompletion.cpp
Normal file
246
src/tabcompletion.cpp
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2008 Justin Karneges, Martin Hostettler
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Generic tab completion support code.
|
||||
|
||||
#include <QDebug>
|
||||
#include "tabcompletion.h"
|
||||
|
||||
TabCompletion::TabCompletion(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
typingStatus_ = Typing_Normal;
|
||||
textEdit_ = 0;
|
||||
}
|
||||
|
||||
|
||||
TabCompletion::~TabCompletion()
|
||||
{
|
||||
}
|
||||
|
||||
void TabCompletion::setTextEdit(QTextEdit* textEdit) {
|
||||
textEdit_ = textEdit;
|
||||
|
||||
QColor mleBackground(textEdit_->palette().color(QPalette::Active, QPalette::Base));
|
||||
|
||||
if (mleBackground.value() < 128) {
|
||||
highlight_ = mleBackground.lighter(125);
|
||||
} else {
|
||||
highlight_ = mleBackground.darker(125);
|
||||
}
|
||||
}
|
||||
|
||||
QTextEdit* TabCompletion::getTextEdit() {
|
||||
return textEdit_;
|
||||
}
|
||||
|
||||
|
||||
void TabCompletion::highlight(bool set) {
|
||||
Q_UNUSED(set);
|
||||
/*
|
||||
if (set) {
|
||||
QTextEdit::ExtraSelection es;
|
||||
es.cursor = replacementCursor_;
|
||||
es.format.setBackground(highlight_);
|
||||
textEdit_->setExtraSelections(QList<QTextEdit::ExtraSelection>() << es);
|
||||
} else {
|
||||
if (textEdit_) textEdit_->setExtraSelections(QList<QTextEdit::ExtraSelection>());
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void TabCompletion::moveCursorToOffset(QTextCursor &cur, int offset, QTextCursor::MoveMode mode) {
|
||||
cur.movePosition(QTextCursor::Start, mode);
|
||||
for (int i = 0; i < offset; i++) { // some sane limit on iterations
|
||||
if (cur.position() >= offset) break; // done our work
|
||||
if (!cur.movePosition(QTextCursor::NextCharacter, mode)) break; // failed?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Find longest common (case insensitive) prefix of \a list.
|
||||
*/
|
||||
QString TabCompletion::longestCommonPrefix(QStringList list) {
|
||||
QString candidate = list.first().toLower();
|
||||
int len = candidate.length();
|
||||
while (len > 0) {
|
||||
bool found = true;
|
||||
foreach(QString str, list) {
|
||||
if (str.left(len).toLower() != candidate) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
|
||||
--len;
|
||||
candidate = candidate.left(len);
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
|
||||
void TabCompletion::setup(QString text, int pos, int &start, int &end) {
|
||||
if (text.isEmpty() || pos==0) {
|
||||
atStart_ = true;
|
||||
toComplete_ = "";
|
||||
start = 0;
|
||||
end = 0;
|
||||
return;
|
||||
}
|
||||
end = pos;
|
||||
int i;
|
||||
for (i = pos - 1; i > 0; --i) {
|
||||
if (text[i].isSpace()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!text[i].isSpace()) {
|
||||
atStart_ = true;
|
||||
start = 0;
|
||||
} else {
|
||||
atStart_ = false;
|
||||
start = i+1;
|
||||
}
|
||||
toComplete_ = text.mid(start, end-start);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QString TabCompletion::suggestCompletion(bool *replaced) {
|
||||
|
||||
suggestedCompletion_ = possibleCompletions();
|
||||
suggestedIndex_ = -1;
|
||||
|
||||
QString newText;
|
||||
if (suggestedCompletion_.count() == 1) {
|
||||
*replaced = true;
|
||||
newText = suggestedCompletion_.first();
|
||||
} else if (suggestedCompletion_.count() > 1) {
|
||||
newText = longestCommonPrefix(suggestedCompletion_);
|
||||
if (newText.isEmpty()) {
|
||||
return toComplete_; // FIXME is this right?
|
||||
}
|
||||
|
||||
typingStatus_ = Typing_MultipleSuggestions;
|
||||
// TODO: display a tooltip that will contain all suggestedCompletion
|
||||
*replaced = true;
|
||||
}
|
||||
|
||||
|
||||
return newText;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TabCompletion::reset() {
|
||||
typingStatus_ = Typing_Normal;
|
||||
highlight(false);
|
||||
}
|
||||
|
||||
/** Handle tab completion.
|
||||
* User interface uses a dual model, first tab completes upto the
|
||||
* longest common (case insensitiv) match, further tabbing cycles through all
|
||||
* possible completions. When doing a tab completion without something to complete
|
||||
* possibly offers a special guess first.
|
||||
*/
|
||||
void TabCompletion::tryComplete() {
|
||||
switch (typingStatus_) {
|
||||
case Typing_Normal:
|
||||
typingStatus_ = Typing_TabPressed;
|
||||
break;
|
||||
case Typing_TabPressed:
|
||||
typingStatus_ = Typing_TabbingCompletions;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
QString newText;
|
||||
bool replaced = false;
|
||||
|
||||
if (typingStatus_ == Typing_MultipleSuggestions) {
|
||||
if (!suggestedCompletion_.isEmpty()) {
|
||||
suggestedIndex_++;
|
||||
if (suggestedIndex_ >= (int)suggestedCompletion_.count()) {
|
||||
suggestedIndex_ = 0;
|
||||
}
|
||||
newText = suggestedCompletion_[suggestedIndex_];
|
||||
replaced = true;
|
||||
}
|
||||
} else {
|
||||
QTextCursor cursor = textEdit_->textCursor();
|
||||
QString wholeText = textEdit_->toPlainText();
|
||||
|
||||
int begin, end;
|
||||
setup(wholeText, cursor.position(), begin, end);
|
||||
replacementCursor_ = QTextCursor(textEdit_->document());
|
||||
moveCursorToOffset(replacementCursor_, begin);
|
||||
moveCursorToOffset(replacementCursor_, end, QTextCursor::KeepAnchor);
|
||||
|
||||
if (toComplete_.isEmpty() && typingStatus_ == Typing_TabbingCompletions) {
|
||||
typingStatus_ = Typing_MultipleSuggestions;
|
||||
|
||||
QString guess;
|
||||
suggestedCompletion_ = allChoices(guess);
|
||||
|
||||
if ( !guess.isEmpty() ) {
|
||||
suggestedIndex_ = -1;
|
||||
newText = guess;
|
||||
replaced = true;
|
||||
} else if (!suggestedCompletion_.isEmpty()) {
|
||||
suggestedIndex_ = 0;
|
||||
newText = suggestedCompletion_.first();
|
||||
replaced = true;
|
||||
}
|
||||
} else {
|
||||
newText = suggestCompletion(&replaced);
|
||||
}
|
||||
}
|
||||
|
||||
if (replaced) {
|
||||
textEdit_->setUpdatesEnabled(false);
|
||||
|
||||
int start = qMin(replacementCursor_.anchor(), replacementCursor_.position());
|
||||
|
||||
replacementCursor_.beginEditBlock();
|
||||
replacementCursor_.insertText(newText);
|
||||
replacementCursor_.endEditBlock();
|
||||
|
||||
QTextCursor newPos(replacementCursor_);
|
||||
|
||||
moveCursorToOffset(replacementCursor_, start, QTextCursor::KeepAnchor);
|
||||
|
||||
|
||||
newPos.clearSelection();
|
||||
|
||||
textEdit_->setTextCursor(newPos);
|
||||
|
||||
textEdit_->setUpdatesEnabled(true);
|
||||
textEdit_->viewport()->update();
|
||||
}
|
||||
highlight(typingStatus_ == Typing_MultipleSuggestions);
|
||||
}
|
||||
|
||||
Reference in a new issue