initial commit

This commit is contained in:
mikhail "synzr" 2025-12-25 01:37:49 +05:00
commit 9d20827c46
2469 changed files with 470994 additions and 0 deletions

246
src/tabcompletion.cpp Normal file
View 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);
}