- implement: refactor in file
This commit is contained in:
parent
1c745871b2
commit
35b7bdb18c
2
NEWS.md
2
NEWS.md
|
@ -8,6 +8,8 @@ Version 0.6.0
|
|||
- add: about dialog
|
||||
- implement: correctly recognize clang (msys2 build)
|
||||
- enhancement: don't add encoding options when using clang to compile (clang only support utf-8)
|
||||
- enhancement: find occurence in project
|
||||
- implement: refactor in file
|
||||
|
||||
Version 0.5.0
|
||||
- enhancement: support C++ using type alias;
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
#include "editor.h"
|
||||
#include "editorlist.h"
|
||||
#include <QFile>
|
||||
#include <QMessageBox>
|
||||
#include "HighlighterManager.h"
|
||||
#include "project.h"
|
||||
|
||||
CppRefacter::CppRefacter(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
@ -30,24 +32,80 @@ bool CppRefacter::findOccurence(Editor *editor, const BufferCoord &pos)
|
|||
if (!statement)
|
||||
return false;
|
||||
|
||||
PSearchResults results = pMainWindow->searchResultModel()->addSearchResults(
|
||||
std::shared_ptr<Project> project = pMainWindow->project();
|
||||
if (editor->inProject() && project) {
|
||||
foreach (const PProjectUnit& unit, project->units()) {
|
||||
if (isCfile(unit->fileName()) || isHfile(unit->fileName())) {
|
||||
findOccurenceInFile(
|
||||
phrase,
|
||||
unit->fileName(),
|
||||
statement,
|
||||
pos.Line,
|
||||
editor->parser());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
findOccurenceInFile(
|
||||
phrase,
|
||||
editor->filename(),
|
||||
pos.Line
|
||||
);
|
||||
|
||||
|
||||
PSearchResultTreeItem item = findOccurenceInFile(
|
||||
editor->filename(),
|
||||
statement,
|
||||
pos.Line,
|
||||
editor->parser());
|
||||
if (item && !(item->results.isEmpty())) {
|
||||
results->results.append(item);
|
||||
}
|
||||
pMainWindow->searchResultModel()->notifySearchResultsUpdated();
|
||||
return true;
|
||||
}
|
||||
|
||||
static QString fullParentName(PStatement statement) {
|
||||
PStatement parent = statement->parentScope.lock();
|
||||
if (parent) {
|
||||
return parent->fullName;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
void CppRefacter::renameSymbol(Editor *editor, const BufferCoord &pos, const QString &word, const QString &newWord)
|
||||
{
|
||||
if (!editor->parser()->freeze())
|
||||
return;
|
||||
auto action = finally([&editor]{
|
||||
editor->parser()->unFreeze();
|
||||
});
|
||||
// get full phrase (such as s.name instead of name)
|
||||
BufferCoord pBeginPos,pEndPos;
|
||||
QString phrase = getWordAtPosition(editor,pos,pBeginPos,pEndPos,Editor::WordPurpose::wpInformation);
|
||||
// Find it's definition
|
||||
PStatement oldStatement = editor->parser()->findStatementOf(
|
||||
editor->filename(),
|
||||
phrase,
|
||||
pos.Line);
|
||||
QString oldScope = fullParentName(oldStatement);
|
||||
// definition of the symbol not found
|
||||
if (!oldStatement)
|
||||
return;
|
||||
// found but not in this file
|
||||
if (editor->filename() != oldStatement->fileName
|
||||
|| editor->filename() != oldStatement->definitionFileName) {
|
||||
QMessageBox::critical(editor,
|
||||
tr("Rename Symbol Error"),
|
||||
tr("Can't rename symbols not defined in this file."));
|
||||
return;
|
||||
}
|
||||
|
||||
QString newPhrase = phrase.mid(0,phrase.length()-word.length()) + newWord;
|
||||
PStatement newStatement = editor->parser()->findStatementOf(
|
||||
editor->filename(),
|
||||
newPhrase,
|
||||
pos.Line);
|
||||
if (newStatement && fullParentName(newStatement) == oldScope) {
|
||||
QMessageBox::critical(editor,
|
||||
tr("Rename Symbol Error"),
|
||||
tr("New symbol already exists!"));
|
||||
return;
|
||||
}
|
||||
renameSymbolInFile(editor->filename(),oldStatement,word,newWord, editor->parser());
|
||||
}
|
||||
|
||||
PSearchResultTreeItem CppRefacter::findOccurenceInFile(
|
||||
const QString &filename,
|
||||
const PStatement &statement,
|
||||
|
@ -114,3 +172,91 @@ PSearchResultTreeItem CppRefacter::findOccurenceInFile(
|
|||
}
|
||||
return parentItem;
|
||||
}
|
||||
|
||||
void CppRefacter::renameSymbolInFile(const QString &filename, const PStatement &statement, const QString &word, const QString &newWord, const PCppParser &parser)
|
||||
{
|
||||
QStringList buffer;
|
||||
SynEdit editor;
|
||||
if (pMainWindow->editorList()->getContentFromOpenedEditor(
|
||||
filename,buffer)){
|
||||
editor.lines()->setContents(buffer);
|
||||
} else {
|
||||
QByteArray encoding;
|
||||
editor.lines()->LoadFromFile(filename,ENCODING_AUTO_DETECT,encoding);
|
||||
}
|
||||
QStringList newContents;
|
||||
editor.setHighlighter(HighlighterManager().getCppHighlighter());
|
||||
int posY = 0;
|
||||
while (posY < editor.lines()->count()) {
|
||||
QString line = editor.lines()->getString(posY);
|
||||
if (line.isEmpty()) {
|
||||
posY++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (posY == 0) {
|
||||
editor.highlighter()->resetState();
|
||||
} else {
|
||||
editor.highlighter()->setState(
|
||||
editor.lines()->ranges(posY-1));
|
||||
}
|
||||
editor.highlighter()->setLine(line,posY);
|
||||
QString newLine;
|
||||
while (!editor.highlighter()->eol()) {
|
||||
int start = editor.highlighter()->getTokenPos() + 1;
|
||||
QString token = editor.highlighter()->getToken();
|
||||
if (token == statement->command) {
|
||||
//same name symbol , test if the same statement;
|
||||
BufferCoord p,pBeginPos,pEndPos;
|
||||
p.Line = posY+1;
|
||||
p.Char = start;
|
||||
QString phrase = getWordAtPosition(&editor, p, pBeginPos,pEndPos,
|
||||
Editor::WordPurpose::wpInformation);
|
||||
PStatement tokenStatement = parser->findStatementOf(
|
||||
filename,
|
||||
phrase, p.Line);
|
||||
if (tokenStatement
|
||||
&& (tokenStatement->line == statement->line)
|
||||
&& (tokenStatement->fileName == statement->fileName)) {
|
||||
token = newWord;
|
||||
}
|
||||
}
|
||||
newLine += token;
|
||||
editor.highlighter()->next();
|
||||
}
|
||||
newContents.append(newLine);
|
||||
posY++;
|
||||
}
|
||||
|
||||
Editor * oldEditor = pMainWindow->editorList()->getOpenedEditorByFilename(filename);
|
||||
if (oldEditor) {
|
||||
oldEditor->selectAll();
|
||||
oldEditor->setSelText(newContents.join(oldEditor->lineBreak()));
|
||||
} else {
|
||||
QByteArray realEncoding;
|
||||
QFile file(filename);
|
||||
editor.lines()->SaveToFile(file,ENCODING_AUTO_DETECT, realEncoding);
|
||||
}
|
||||
}
|
||||
|
||||
void CppRefacter::findOccurenceInFile(
|
||||
const QString& phrase,
|
||||
const QString &filename,
|
||||
const PStatement &statement,
|
||||
int line,
|
||||
const PCppParser &parser)
|
||||
{
|
||||
PSearchResults results = pMainWindow->searchResultModel()->addSearchResults(
|
||||
phrase,
|
||||
filename,
|
||||
line
|
||||
);
|
||||
|
||||
PSearchResultTreeItem item = findOccurenceInFile(
|
||||
filename,
|
||||
statement,
|
||||
parser);
|
||||
if (item && !(item->results.isEmpty())) {
|
||||
results->results.append(item);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,13 +15,26 @@ public:
|
|||
explicit CppRefacter(QObject *parent = nullptr);
|
||||
|
||||
bool findOccurence(Editor * editor, const BufferCoord& pos);
|
||||
|
||||
void renameSymbol(Editor* editor, const BufferCoord& pos, const QString& word, const QString& newWord);
|
||||
signals:
|
||||
private:
|
||||
void findOccurenceInFile(
|
||||
const QString& phrase,
|
||||
const QString& filename,
|
||||
const PStatement& statement,
|
||||
int line,
|
||||
const PCppParser& parser);
|
||||
PSearchResultTreeItem findOccurenceInFile(
|
||||
const QString& filename,
|
||||
const PStatement& statement,
|
||||
const PCppParser& parser);
|
||||
|
||||
void renameSymbolInFile(
|
||||
const QString& filename,
|
||||
const PStatement& statement,
|
||||
const QString& word,
|
||||
const QString& newWord,
|
||||
const PCppParser& parser);
|
||||
};
|
||||
|
||||
#endif // CPPREFACTER_H
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QMimeData>
|
||||
#include <QTranslator>
|
||||
|
@ -114,7 +115,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
ui->menuCode->insertMenu(ui->actionReformat_Code,mMenuInsertCodeSnippet);
|
||||
ui->menuCode->insertSeparator(ui->actionReformat_Code);
|
||||
connect(mMenuInsertCodeSnippet,&QMenu::aboutToShow,
|
||||
this, onShowInsertCodeSnippetMenu);
|
||||
this, &MainWindow::onShowInsertCodeSnippetMenu);
|
||||
|
||||
mCPUDialog = nullptr;
|
||||
|
||||
|
@ -3945,3 +3946,51 @@ void MainWindow::on_actionAbout_triggered()
|
|||
dialog.exec();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::on_actionRename_Symbol_triggered()
|
||||
{
|
||||
Editor * editor = mEditorList->getEditor();
|
||||
if (!editor)
|
||||
return;
|
||||
editor->beginUpdate();
|
||||
// mClassBrowserModel.beginUpdate();
|
||||
QCursor oldCursor = editor->cursor();
|
||||
editor->setCursor(Qt::CursorShape::WaitCursor);
|
||||
auto action = finally([this,oldCursor,editor]{
|
||||
editor->endUpdate();
|
||||
// mClassBrowserModel.EndTreeUpdate;
|
||||
editor->setCursor(oldCursor);
|
||||
});
|
||||
QString word = editor->wordAtCursor();
|
||||
if (word.isEmpty())
|
||||
return;
|
||||
|
||||
// if (!isIdentifier(word)) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (isKeyword(word)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
QString newWord = QInputDialog::getText(editor,
|
||||
tr("Rename Symbol"),
|
||||
tr("New Name"),
|
||||
QLineEdit::Normal,word, &ok);
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
if (word == newWord)
|
||||
return;
|
||||
|
||||
PCppParser parser = editor->parser();
|
||||
BufferCoord oldCaretXY = editor->caretXY();
|
||||
//here we must reparse the file in sync, or rename may fail
|
||||
parser->parseFile(editor->filename(), editor->inProject(), false, false);
|
||||
CppRefacter refactor;
|
||||
refactor.renameSymbol(editor,oldCaretXY,word,newWord);
|
||||
editor->reparse();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -371,6 +371,8 @@ private slots:
|
|||
|
||||
void on_actionAbout_triggered();
|
||||
|
||||
void on_actionRename_Symbol_triggered();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
EditorList *mEditorList;
|
||||
|
|
|
@ -949,10 +949,17 @@
|
|||
</property>
|
||||
<addaction name="actionAbout"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuRefactor">
|
||||
<property name="title">
|
||||
<string>Refactor</string>
|
||||
</property>
|
||||
<addaction name="actionRename_Symbol"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuEdit"/>
|
||||
<addaction name="menuSearch"/>
|
||||
<addaction name="menuCode"/>
|
||||
<addaction name="menuRefactor"/>
|
||||
<addaction name="menuProject"/>
|
||||
<addaction name="menuExecute"/>
|
||||
<addaction name="menuTools"/>
|
||||
|
@ -1780,6 +1787,14 @@
|
|||
<string>About</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRename_Symbol">
|
||||
<property name="text">
|
||||
<string>Rename Symbol</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Shift+F6</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
|
|
@ -2461,6 +2461,9 @@ void SynEdit::doPasteFromClipboard()
|
|||
|
||||
void SynEdit::incPaintLock()
|
||||
{
|
||||
if (mPaintLock==0) {
|
||||
onBeginFirstPaintLock();
|
||||
}
|
||||
mPaintLock ++ ;
|
||||
}
|
||||
|
||||
|
@ -2477,6 +2480,7 @@ void SynEdit::decPaintLock()
|
|||
updateCaret();
|
||||
if (mStatusChanges!=0)
|
||||
doOnStatusChange(mStatusChanges);
|
||||
onEndFirstPaintLock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5256,6 +5260,16 @@ void SynEdit::ExecuteCommand(SynEditorCommand Command, QChar AChar, void *pData)
|
|||
|
||||
}
|
||||
|
||||
void SynEdit::onEndFirstPaintLock()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SynEdit::onBeginFirstPaintLock()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool SynEdit::isIdentChar(const QChar &ch)
|
||||
{
|
||||
if (mHighlighter) {
|
||||
|
|
|
@ -411,6 +411,8 @@ protected:
|
|||
virtual void onProcessCommand(SynEditorCommand Command, QChar AChar, void * pData);
|
||||
virtual void onCommandProcessed(SynEditorCommand Command, QChar AChar, void * pData);
|
||||
virtual void ExecuteCommand(SynEditorCommand Command, QChar AChar, void * pData);
|
||||
virtual void onEndFirstPaintLock();
|
||||
virtual void onBeginFirstPaintLock();
|
||||
|
||||
private:
|
||||
void clearAreaList(SynEditingAreaList areaList);
|
||||
|
|
Loading…
Reference in New Issue