diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index e462df7..e77df91 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -7,7 +7,7 @@ on: [ push, pull_request ] env: PLUGIN_NAME: QNVim - QT_VERSION: 5.15.2 + QT_VERSION: 6.2.4 CMAKE_VERSION: 3.22.4 NINJA_VERSION: 1.10.1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6303c2c..d9304c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,6 @@ if (MSVC) endif() find_package(QtCreator REQUIRED COMPONENTS Core) -find_package(Qt5 COMPONENTS Widgets Network REQUIRED) +find_package(Qt6 REQUIRED COMPONENTS Widgets Network) add_subdirectory(src) diff --git a/external/qtcreator/version.cmake b/external/qtcreator/version.cmake index 0159d1a..26ceed4 100644 --- a/external/qtcreator/version.cmake +++ b/external/qtcreator/version.cmake @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: None # SPDX-License-Identifier: MIT -set(QT_CREATOR_VERSION "5.0.2") +set(QT_CREATOR_VERSION "6.0.2") set(QT_CREATOR_SNAPSHOT "") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6099921..9c9ec3e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,7 @@ add_qtc_plugin(QNVim QtCreator::TextEditor QtCreator::ProjectExplorer DEPENDS - Qt5::Widgets + Qt::Widgets QtCreator::ExtensionSystem QtCreator::Utils neovim-qt diff --git a/src/QNVim.json.in b/src/QNVim.json.in index bf1b907..2be3422 100644 --- a/src/QNVim.json.in +++ b/src/QNVim.json.in @@ -1,11 +1,10 @@ { \"Name\" : \"QNVim\", - \"Version\" : \"1.2.1\", - \"CompatVersion\" : \"0.4.0\", + \"Version\" : \"6.0.2_1\", \"Vendor\" : \"Sassan Haradji\", \"Copyright\" : \"(C) Sassan Haradji\", \"License\" : \"MIT\", \"Description\" : \"Neovim Backend for Qt Creator\", - \"Url\" : \"\", + \"Url\" : \"https://github.com/sassanh/qnvim\", $$dependencyList } diff --git a/src/qnvimplugin.cpp b/src/qnvimplugin.cpp index f5c91f1..a92550a 100644 --- a/src/qnvimplugin.cpp +++ b/src/qnvimplugin.cpp @@ -14,16 +14,21 @@ #include #include #include + #include #include #include + #include #include + #include #include #include #include #include +#include + #include #include #include @@ -129,20 +134,28 @@ void QNVimPlugin::syncSelectionToVim(Core::IEditor *editor) { auto textEditor = qobject_cast(editor->widget()); QString text = textEditor->toPlainText(); - auto cursor = textEditor->hasBlockSelection() ? textEditor->blockSelection() : textEditor->textCursor(); - int cursorPosition = cursor.position(); - int anchorPosition = cursor.anchor(); - int line, col, vLine, vCol; - if (anchorPosition == cursorPosition) - return; + auto mtc = textEditor->multiTextCursor(); + int line, col, vLine, vCol; QString visualCommand; - if (textEditor->hasBlockSelection()) { - line = QStringView(text).left(cursorPosition).count('\n') + 1; - col = text.left(cursorPosition).section('\n', -1).length() + 1; - vLine = QStringView(text).left(anchorPosition).count('\n') + 1; - vCol = text.left(anchorPosition).section('\n', -1).length() + 1; + if (mtc.hasMultipleCursors()) { + auto mainCursor = mtc.mainCursor(); + + // We should always use main cursor pos here, + // because it is the cursor user controls with hjkl + auto nvimPos = mainCursor.position(); + + // NOTE: Theoretically, it is not alwaus the case, + // that the main cursor is at the ends of mtc array, + // but for creating our own block selections it works + auto lastCursor = mainCursor == *mtc.begin() ? *(mtc.end() - 1) : *mtc.begin(); + auto nvimAnchor = lastCursor.anchor(); + + line = QStringView(text).left(nvimPos).count('\n') + 1; + col = text.left(nvimPos).section('\n', -1).length() + 1; + vLine = QStringView(text).left(nvimAnchor).count('\n') + 1; + vCol = text.left(nvimAnchor).section('\n', -1).length() + 1; if (vCol < col) --col; @@ -153,6 +166,13 @@ void QNVimPlugin::syncSelectionToVim(Core::IEditor *editor) { } else if (mMode == "V") { return; } else { + auto cursor = textEditor->textCursor(); + int cursorPosition = cursor.position(); + int anchorPosition = cursor.anchor(); + + if (anchorPosition == cursorPosition) + return; + if (anchorPosition < cursorPosition) --cursorPosition; else @@ -231,52 +251,79 @@ void QNVimPlugin::syncCursorFromVim(const QVariantList &pos, const QVariantList mVCursor.setY(vLine); mVCursor.setX(vCol); - int a = QString("\n" + mText).section('\n', 0, vLine - 1).length() + vCol - 1; - int p = QString("\n" + mText).section('\n', 0, line - 1).length() + col - 1; + int anchor = QString("\n" + mText).section('\n', 0, vLine - 1).length() + vCol - 1; + int position = QString("\n" + mText).section('\n', 0, line - 1).length() + col - 1; if (mMode == "V") { - if (a < p) { - a = QString("\n" + mText).section('\n', 0, vLine - 1).length(); - p = QString("\n" + mText).section('\n', 0, line).length() - 1; + if (anchor < position) { + anchor = QString("\n" + mText).section('\n', 0, vLine - 1).length(); + position = QString("\n" + mText).section('\n', 0, line).length() - 1; } else { - a = QString("\n" + mText).section('\n', 0, vLine).length() - 1; - p = QString("\n" + mText).section('\n', 0, line - 1).length(); + anchor = QString("\n" + mText).section('\n', 0, vLine).length() - 1; + position = QString("\n" + mText).section('\n', 0, line - 1).length(); } QTextCursor cursor = textEditor->textCursor(); - cursor.setPosition(a); - cursor.setPosition(p, QTextCursor::KeepAnchor); + cursor.setPosition(anchor); + cursor.setPosition(position, QTextCursor::KeepAnchor); if (textEditor->textCursor().anchor() != cursor.anchor() or textEditor->textCursor().position() != cursor.position()) textEditor->setTextCursor(cursor); } else if (mMode == "v") { - if (a > p) - ++a; + if (anchor > position) + ++anchor; else - ++p; + ++position; QTextCursor cursor = textEditor->textCursor(); - cursor.setPosition(a); - cursor.setPosition(p, QTextCursor::KeepAnchor); + cursor.setPosition(anchor); + cursor.setPosition(position, QTextCursor::KeepAnchor); if (textEditor->textCursor().anchor() != cursor.anchor() or textEditor->textCursor().position() != cursor.position()) textEditor->setTextCursor(cursor); - } else if (mMode == "\x16") { + } else if (mMode == "\x16") { // VISUAL BLOCK if (vCol > col) - ++a; + ++anchor; else - ++p; + ++position; - QTextCursor cursor = textEditor->textCursor(); - cursor.setPosition(a); - cursor.setPosition(p, QTextCursor::KeepAnchor); - textEditor->setBlockSelection(cursor); + auto document = textEditor->textCursor().document(); + const auto& tabs = textEditor->textDocument()->tabSettings(); + + const auto firstBlock = document->findBlock(anchor); + const auto lastBlock = document->findBlock(position); + const auto localAnchor = tabs.columnAt(firstBlock.text(), anchor - firstBlock.position()); + const auto localPos = tabs.columnAt(lastBlock.text(), position - lastBlock.position()); + + // Get next block no matter the direction of selection + auto after = [&](const auto& block) { + if (anchor < position) + return block.next(); + else + return block.previous(); + }; + + auto mtc = Utils::MultiTextCursor(); + for (auto curBlock = firstBlock; curBlock != after(lastBlock); curBlock = after(curBlock)) { + auto newCursor = QTextCursor(curBlock); + + auto anchorBoundOffset = tabs.positionAtColumn(curBlock.text(), localAnchor); + auto newCursorAnchor = curBlock.position() + anchorBoundOffset; + newCursor.setPosition(newCursorAnchor); + + auto posBoundOffset = tabs.positionAtColumn(curBlock.text(), localPos); + auto newCursorPosition = curBlock.position() + posBoundOffset; + newCursor.setPosition(newCursorPosition, QTextCursor::KeepAnchor); + + mtc.addCursor(newCursor); + } + textEditor->setMultiTextCursor(mtc); } else { QTextCursor cursor = textEditor->textCursor(); cursor.clearSelection(); - cursor.setPosition(p); + cursor.setPosition(position); if (textEditor->textCursor().position() != cursor.position() or textEditor->textCursor().hasSelection()) @@ -689,8 +736,7 @@ void QNVimPlugin::editorOpened(Core::IEditor *editor) { Core::IDocument *document = editor->document(); - connect( - document, &Core::IDocument::contentsChanged, this, [=]() { + connect(document, &Core::IDocument::contentsChanged, this, [=]() { auto buffer = mBuffers[editor]; QString bufferType = mBufferType[buffer]; if (!mEditors.contains(buffer) or (bufferType != "acwrite" and !bufferType.isEmpty())) @@ -698,8 +744,7 @@ void QNVimPlugin::editorOpened(Core::IEditor *editor) { syncToVim(editor); }, Qt::QueuedConnection); - connect( - textEditor, &TextEditor::TextEditorWidget::cursorPositionChanged, this, [=]() { + connect(textEditor, &TextEditor::TextEditorWidget::cursorPositionChanged, this, [=]() { if (Core::EditorManager::currentEditor() != editor) return; QString newText = textEditor->toPlainText(); @@ -708,8 +753,7 @@ void QNVimPlugin::editorOpened(Core::IEditor *editor) { syncCursorToVim(editor); }, Qt::QueuedConnection); - connect( - textEditor, &TextEditor::TextEditorWidget::selectionChanged, this, [=]() { + connect(textEditor, &TextEditor::TextEditorWidget::selectionChanged, this, [=]() { if (Core::EditorManager::currentEditor() != editor) return; QString newText = textEditor->toPlainText(); @@ -718,7 +762,8 @@ void QNVimPlugin::editorOpened(Core::IEditor *editor) { syncSelectionToVim(editor); }, Qt::QueuedConnection); - connect(textEditor->textDocument(), &TextEditor::TextDocument::fontSettingsChanged, this, &QNVimPlugin::updateCursorSize); + connect(textEditor->textDocument(), &TextEditor::TextDocument::fontSettingsChanged, + this, &QNVimPlugin::updateCursorSize); } mSettingBufferFromVim = 0;