From 5754b7d09fdfe2fdd0f7c7368e17fc1267f23392 Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Tue, 10 Oct 2017 09:58:19 +0200 Subject: [PATCH 1/5] Android: Fix Sdk manager system environment Android native tools fail if JAVA_HOME environment variable is not defined Task-number: QTCREATORBUG-19072 Change-Id: I3db910b34d9bdd9ebc9ba052b5300ecf5ef3ce15 Reviewed-by: BogDan Vatra --- src/plugins/android/androidconfigurations.cpp | 14 ++++++++ src/plugins/android/androidconfigurations.h | 2 ++ src/plugins/android/androidsdkmanager.cpp | 27 ++++++++------- src/plugins/android/androidtoolmanager.cpp | 34 ++++++------------- src/plugins/android/androidtoolmanager.h | 5 ++- 5 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index a44f605780e..39480e9a2c4 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -1070,6 +1071,19 @@ bool AndroidConfigurations::force32bitEmulator() return m_instance->m_force32bit; } +QProcessEnvironment AndroidConfigurations::toolsEnvironment(const AndroidConfig &config) +{ + Environment env = Environment::systemEnvironment(); + Utils::FileName jdkLocation = config.openJDKLocation(); + if (!jdkLocation.isEmpty()) { + env.set("JAVA_HOME", jdkLocation.toUserOutput()); + Utils::FileName binPath = jdkLocation; + binPath.appendPath("bin"); + env.prependOrSetPath(binPath.toUserOutput()); + } + return env.toProcessEnvironment(); +} + /** * Workaround for '????????????' serial numbers * @return ("-d") for buggy devices, ("-s", ) for normal diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 4565d5e3635..7424be1d14e 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -204,6 +205,7 @@ public: static void removeOldToolChains(); static void updateAutomaticKitList(); static bool force32bitEmulator(); + static QProcessEnvironment toolsEnvironment(const AndroidConfig &config); signals: void updated(); diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index 4adf95401ea..dd3895f507f 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -129,13 +129,14 @@ void watcherDeleter(QFutureWatcher *watcher) Runs the \c sdkmanger tool with arguments \a args. Returns \c true if the command is successfully executed. Output is copied into \a output. The function blocks the calling thread. */ -static bool sdkManagerCommand(const Utils::FileName &toolPath, const QStringList &args, +static bool sdkManagerCommand(const AndroidConfig &config, const QStringList &args, QString *output, int timeout = sdkManagerCmdTimeoutS) { SynchronousProcess proc; + proc.setProcessEnvironment(AndroidConfigurations::toolsEnvironment(config)); proc.setTimeoutS(timeout); proc.setTimeOutMessageBoxEnabled(true); - SynchronousProcessResponse response = proc.run(toolPath.toString(), args); + SynchronousProcessResponse response = proc.run(config.sdkManagerToolPath().toString(), args); if (output) *output = response.allOutput(); return response.result == SynchronousProcessResponse::Finished; @@ -147,13 +148,14 @@ static bool sdkManagerCommand(const Utils::FileName &toolPath, const QStringList to cancel signal emmitted by \a sdkManager and kill the commands. The command is also killed after the lapse of \a timeout seconds. The function blocks the calling thread. */ -static void sdkManagerCommand(const Utils::FileName &toolPath, const QStringList &args, +static void sdkManagerCommand(const AndroidConfig &config, const QStringList &args, AndroidSdkManager &sdkManager, SdkCmdFutureInterface &fi, AndroidSdkManager::OperationOutput &output, double progressQuota, bool interruptible = true, int timeout = sdkManagerOperationTimeoutS) { int offset = fi.progressValue(); SynchronousProcess proc; + proc.setProcessEnvironment(AndroidConfigurations::toolsEnvironment(config)); bool assertionFound = false; proc.setStdErrBufferedSignalsEnabled(true); proc.setStdOutBufferedSignalsEnabled(true); @@ -173,7 +175,7 @@ static void sdkManagerCommand(const Utils::FileName &toolPath, const QStringList QObject::connect(&sdkManager, &AndroidSdkManager::cancelActiveOperations, &proc, &SynchronousProcess::terminate); } - SynchronousProcessResponse response = proc.run(toolPath.toString(), args); + SynchronousProcessResponse response = proc.run(config.sdkManagerToolPath().toString(), args); if (assertionFound) { output.success = false; output.stdOutput = response.stdOut(); @@ -769,7 +771,7 @@ void AndroidSdkManagerPrivate::reloadSdkPackages() QString packageListing; QStringList args({"--list", "--verbose"}); args << m_config.sdkManagerToolArgs(); - if (sdkManagerCommand(m_config.sdkManagerToolPath(), args, &packageListing)) { + if (sdkManagerCommand(m_config, args, &packageListing)) { SdkManagerOutputParser parser(m_allPackages); parser.parsePackageListing(packageListing); } @@ -797,7 +799,7 @@ void AndroidSdkManagerPrivate::updateInstalled(SdkCmdFutureInterface &fi) QStringList args("--update"); args << m_config.sdkManagerToolArgs(); if (!fi.isCanceled()) - sdkManagerCommand(m_config.sdkManagerToolPath(), args, m_sdkManager, fi, result, 100); + sdkManagerCommand(m_config, args, m_sdkManager, fi, result, 100); else qCDebug(sdkManagerLog) << "Update: Operation cancelled before start"; @@ -826,12 +828,10 @@ void AndroidSdkManagerPrivate::update(SdkCmdFutureInterface &fi, const QStringLi result.stdOutput = QString("%1 %2").arg(isInstall ? installTag : uninstallTag) .arg(packagePath); fi.reportResult(result); - if (fi.isCanceled()) { + if (fi.isCanceled()) qCDebug(sdkManagerLog) << args << "Update: Operation cancelled before start"; - } else { - sdkManagerCommand(m_config.sdkManagerToolPath(), args, m_sdkManager, fi, result, - progressQuota, isInstall); - } + else + sdkManagerCommand(m_config, args, m_sdkManager, fi, result, progressQuota, isInstall); currentProgress += progressQuota; fi.setProgressValue(currentProgress); if (result.stdError.isEmpty() && !result.success) @@ -869,7 +869,7 @@ void AndroidSdkManagerPrivate::checkPendingLicense(SdkCmdFutureInterface &fi) result.type = AndroidSdkManager::LicenseCheck; QStringList args("--licenses"); if (!fi.isCanceled()) - sdkManagerCommand(m_config.sdkManagerToolPath(), args, m_sdkManager, fi, result, 100.0); + sdkManagerCommand(m_config, args, m_sdkManager, fi, result, 100.0); else qCDebug(sdkManagerLog) << "Update: Operation cancelled before start"; @@ -884,6 +884,7 @@ void AndroidSdkManagerPrivate::getPendingLicense(SdkCmdFutureInterface &fi) AndroidSdkManager::OperationOutput result; result.type = AndroidSdkManager::LicenseWorkflow; QtcProcess licenseCommand; + licenseCommand.setProcessEnvironment(AndroidConfigurations::toolsEnvironment(m_config)); bool reviewingLicenses = false; licenseCommand.setCommand(m_config.sdkManagerToolPath().toString(), {"--licenses"}); if (Utils::HostOsInfo::isWindowsHost()) @@ -987,7 +988,7 @@ void AndroidSdkManagerPrivate::parseCommonArguments(QFutureInterface &f { QString argumentDetails; QString output; - sdkManagerCommand(m_config.sdkManagerToolPath(), QStringList("--help"), &output); + sdkManagerCommand(m_config, QStringList("--help"), &output); bool foundTag = false; for (const QString& line : output.split('\n')) { if (fi.isCanceled()) diff --git a/src/plugins/android/androidtoolmanager.cpp b/src/plugins/android/androidtoolmanager.cpp index fc214ab1139..c50124ce2c4 100644 --- a/src/plugins/android/androidtoolmanager.cpp +++ b/src/plugins/android/androidtoolmanager.cpp @@ -58,11 +58,11 @@ public: output. */ static bool androidToolCommand(Utils::FileName toolPath, const QStringList &args, - const Environment &environment, QString *output) + const QProcessEnvironment &environment, QString *output) { QString androidToolPath = toolPath.toString(); SynchronousProcess proc; - proc.setProcessEnvironment(environment.toProcessEnvironment()); + proc.setProcessEnvironment(environment); SynchronousProcessResponse response = proc.runBlocking(androidToolPath, args); if (response.result == SynchronousProcessResponse::Finished) { if (output) @@ -103,7 +103,7 @@ SdkPlatformList AndroidToolManager::availableSdkPlatforms(bool *ok) const SdkPlatformList list; QString targetListing; if (androidToolCommand(m_config.androidToolPath(), QStringList({"list", "target"}), - androidToolEnvironment(), &targetListing)) { + AndroidConfigurations::toolsEnvironment(m_config), &targetListing)) { m_parser->parseTargetListing(targetListing, m_config.sdkLocation(), list); success = true; } else { @@ -124,14 +124,15 @@ void AndroidToolManager::launchAvdManager() const QFuture AndroidToolManager::createAvd(CreateAvdInfo info) const { return Utils::runAsync(&AndroidToolManager::createAvdImpl, info, - m_config.androidToolPath(), androidToolEnvironment()); + m_config.androidToolPath(), + AndroidConfigurations::toolsEnvironment(m_config)); } bool AndroidToolManager::removeAvd(const QString &name) const { SynchronousProcess proc; proc.setTimeoutS(5); - proc.setProcessEnvironment(androidToolEnvironment().toProcessEnvironment()); + proc.setProcessEnvironment(AndroidConfigurations::toolsEnvironment(m_config)); SynchronousProcessResponse response = proc.runBlocking(m_config.androidToolPath().toString(), QStringList({"delete", "avd", "-n", name})); @@ -142,27 +143,14 @@ QFuture AndroidToolManager::androidVirtualDevicesFuture() { return Utils::runAsync(&AndroidToolManager::androidVirtualDevices, m_config.androidToolPath(), m_config.sdkLocation(), - androidToolEnvironment()); -} - -Environment AndroidToolManager::androidToolEnvironment() const -{ - Environment env = Environment::systemEnvironment(); - Utils::FileName jdkLocation = m_config.openJDKLocation(); - if (!jdkLocation.isEmpty()) { - env.set(QLatin1String("JAVA_HOME"), jdkLocation.toUserOutput()); - Utils::FileName binPath = jdkLocation; - binPath.appendPath(QLatin1String("bin")); - env.prependOrSetPath(binPath.toUserOutput()); - } - return env; + AndroidConfigurations::toolsEnvironment(m_config)); } CreateAvdInfo AndroidToolManager::createAvdImpl(CreateAvdInfo info, FileName androidToolPath, - Environment env) + QProcessEnvironment env) { QProcess proc; - proc.setProcessEnvironment(env.toProcessEnvironment()); + proc.setProcessEnvironment(env); QStringList arguments; arguments << QLatin1String("create") << QLatin1String("avd") << QLatin1String("-t") << AndroidConfig::apiLevelNameFor(info.sdkPlatform) @@ -212,11 +200,11 @@ CreateAvdInfo AndroidToolManager::createAvdImpl(CreateAvdInfo info, FileName and AndroidDeviceInfoList AndroidToolManager::androidVirtualDevices(const Utils::FileName &androidTool, const FileName &sdkLocationPath, - const Environment &environment) + const QProcessEnvironment &env) { AndroidDeviceInfoList devices; QString output; - if (!androidToolCommand(androidTool, QStringList({"list", "avd"}), environment, &output)) + if (!androidToolCommand(androidTool, QStringList({"list", "avd"}), env, &output)) return devices; QStringList avds = output.split('\n'); diff --git a/src/plugins/android/androidtoolmanager.h b/src/plugins/android/androidtoolmanager.h index 61f7018bf92..0e2fb5bc400 100644 --- a/src/plugins/android/androidtoolmanager.h +++ b/src/plugins/android/androidtoolmanager.h @@ -57,12 +57,11 @@ public: // Helper methods private: - Utils::Environment androidToolEnvironment() const; static CreateAvdInfo createAvdImpl(CreateAvdInfo info, Utils::FileName androidToolPath, - Utils::Environment env); + QProcessEnvironment env); static AndroidDeviceInfoList androidVirtualDevices(const Utils::FileName &androidTool, const Utils::FileName &sdkLlocationPath, - const Utils::Environment &environment); + const QProcessEnvironment &env); private: const AndroidConfig &m_config; std::unique_ptr m_parser; From fa43c0d2b9874e96de446683c326f201a01c3134 Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Thu, 12 Oct 2017 10:03:13 +0200 Subject: [PATCH 2/5] Android: Fix a possible race condition in SDK manager QFutureWatcher connections are made after calling setFuture. This can lead to race condition Task-number: QTCREATORBUG-19082 Change-Id: I87379c2b14c722cf4d4a9a374bd1ac1e72b52d5c Reviewed-by: BogDan Vatra --- src/plugins/android/androidsdkmanagerwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/android/androidsdkmanagerwidget.cpp b/src/plugins/android/androidsdkmanagerwidget.cpp index 7ffa294e318..11877efdfe8 100644 --- a/src/plugins/android/androidsdkmanagerwidget.cpp +++ b/src/plugins/android/androidsdkmanagerwidget.cpp @@ -323,7 +323,6 @@ void AndroidSdkManagerWidget::addPackageFuture(const QFuture; - m_currentOperation->setFuture(future); connect(m_currentOperation, &QFutureWatcher::resultReadyAt, this, &AndroidSdkManagerWidget::onOperationResult); @@ -334,6 +333,7 @@ void AndroidSdkManagerWidget::addPackageFuture(const QFutureoperationProgress->setValue(value); }); + m_currentOperation->setFuture(future); } else { qCDebug(androidSdkMgrUiLog) << "Operation canceled/finished before adding to the queue"; if (m_sdkManager->isBusy()) { From 5d5d0497e5c0f73ac2094ec6a6b9076a1f0be1f9 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Wed, 11 Oct 2017 05:28:41 +0300 Subject: [PATCH 3/5] Git: Use C locale when parsing the command output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTCREATORBUG-19017 Change-Id: Ib77d66e22d227d43245d352905f9b095f7d0f42b Reviewed-by: André Hartmann --- src/plugins/git/gitclient.cpp | 6 ++++-- src/plugins/git/mergetool.cpp | 4 ++++ src/plugins/vcsbase/vcsbaseplugin.cpp | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index f2cdc4750d1..c72ab5c9e8c 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -1758,7 +1758,8 @@ bool GitClient::cleanList(const QString &workingDirectory, const QString &module const QString directory = workingDirectory + '/' + modulePath; const QStringList arguments = {"clean", "--dry-run", flag}; - const SynchronousProcessResponse resp = vcsFullySynchronousExec(directory, arguments); + const SynchronousProcessResponse resp = vcsFullySynchronousExec(directory, arguments, + VcsCommand::ForceCLocale); if (resp.result != SynchronousProcessResponse::Finished) { msgCannotRun(arguments, directory, resp.stdErr(), errorMessage); return false; @@ -2995,7 +2996,8 @@ bool GitClient::synchronousStashList(const QString &workingDirectory, QListclear(); const QStringList arguments = {"stash", "list", noColorOption}; - const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, arguments); + const SynchronousProcessResponse resp = vcsFullySynchronousExec(workingDirectory, arguments, + VcsCommand::ForceCLocale); if (resp.result != SynchronousProcessResponse::Finished) { msgCannotRun(arguments, workingDirectory, resp.stdErr(), errorMessage); return false; diff --git a/src/plugins/git/mergetool.cpp b/src/plugins/git/mergetool.cpp index 58b19b02f8a..84cfea4dd12 100644 --- a/src/plugins/git/mergetool.cpp +++ b/src/plugins/git/mergetool.cpp @@ -54,8 +54,12 @@ bool MergeTool::start(const QString &workingDirectory, const QStringList &files) { QStringList arguments; arguments << "mergetool" << "-y" << files; + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("LANG", "C"); + env.insert("LANGUAGE", "C"); m_process = new QProcess(this); m_process->setWorkingDirectory(workingDirectory); + m_process->setProcessEnvironment(env); const Utils::FileName binary = GitPlugin::client()->vcsBinary(); VcsOutputWindow::appendCommand(workingDirectory, binary, arguments); m_process->start(binary.toString(), arguments); diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index acc3e312ad1..ddb85144eae 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -786,8 +786,10 @@ void VcsBasePlugin::setProcessEnvironment(QProcessEnvironment *e, bool forceCLocale, const QString &sshPromptBinary) { - if (forceCLocale) + if (forceCLocale) { e->insert("LANG", "C"); + e->insert("LANGUAGE", "C"); + } if (!sshPromptBinary.isEmpty()) e->insert("SSH_ASKPASS", sshPromptBinary); } From 7643b2ccdc9999f181d235a70172cad0ddae7967 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 12 Oct 2017 12:07:29 +0200 Subject: [PATCH 4/5] File System pane: Add item for opening project file as project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default "open" action was changed (in 3c988e5a0d4befa92107fa853583a64c9ea03914) to open project files in the editor, so add an explicit action for opening them as a project. Change-Id: I34ac1e25e249bafeea6659b0f40130d43454bbef Reviewed-by: André Hartmann --- .../projectexplorer/foldernavigationwidget.cpp | 15 ++++++++++++--- src/plugins/projectexplorer/projectexplorer.cpp | 10 ++++++++++ src/plugins/projectexplorer/projectexplorer.h | 6 +++++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/plugins/projectexplorer/foldernavigationwidget.cpp b/src/plugins/projectexplorer/foldernavigationwidget.cpp index 4a003ba0283..9e0150a58cc 100644 --- a/src/plugins/projectexplorer/foldernavigationwidget.cpp +++ b/src/plugins/projectexplorer/foldernavigationwidget.cpp @@ -324,19 +324,26 @@ void FolderNavigationWidget::contextMenuEvent(QContextMenuEvent *ev) const bool hasCurrentItem = current.isValid(); QAction *actionOpenFile = nullptr; QAction *actionOpenProjects = nullptr; + QAction *actionOpenAsProject = nullptr; + const Utils::FileName filePath = hasCurrentItem ? Utils::FileName::fromString( + m_fileSystemModel->filePath(current)) + : Utils::FileName(); if (hasCurrentItem) { const QString fileName = m_fileSystemModel->fileName(current); - if (m_fileSystemModel->isDir(current)) + if (m_fileSystemModel->isDir(current)) { actionOpenProjects = menu.addAction(tr("Open Project in \"%1\"").arg(fileName)); - else + } else { actionOpenFile = menu.addAction(tr("Open \"%1\"").arg(fileName)); + if (ProjectExplorerPlugin::isProjectFile(Utils::FileName::fromString(fileName))) + actionOpenAsProject = menu.addAction(tr("Open Project \"%1\"").arg(fileName)); + } } // we need dummy DocumentModel::Entry with absolute file path in it // to get EditorManager::addNativeDirAndOpenWithActions() working Core::DocumentModel::Entry fakeEntry; Core::IDocument document; - document.setFilePath(Utils::FileName::fromString(m_fileSystemModel->filePath(current))); + document.setFilePath(filePath); fakeEntry.document = &document; Core::EditorManager::addNativeDirAndOpenWithActions(&menu, &fakeEntry); @@ -347,6 +354,8 @@ void FolderNavigationWidget::contextMenuEvent(QContextMenuEvent *ev) ev->accept(); if (action == actionOpenFile) openItem(current); + else if (action == actionOpenAsProject) + ProjectExplorerPlugin::openProject(filePath.toString()); else if (action == actionOpenProjects) openProjectsInDirectory(current); } diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 118d8f37b94..1353f2dec5c 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -3534,6 +3534,16 @@ QStringList ProjectExplorerPlugin::projectFilePatterns() return patterns; } +bool ProjectExplorerPlugin::isProjectFile(const Utils::FileName &filePath) +{ + Utils::MimeType mt = Utils::mimeTypeForFile(filePath.toString()); + for (const QString &mime : dd->m_projectCreators.keys()) { + if (mt.inherits(mime)) + return true; + } + return false; +} + void ProjectExplorerPlugin::openOpenProjectDialog() { const QString path = DocumentManager::useProjectsDirectory() diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index 2ffb0d200d0..39cd4e736b3 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -43,7 +43,10 @@ class IMode; class Id; } // namespace Core -namespace Utils { class ProcessHandle; } +namespace Utils { +class ProcessHandle; +class FileName; +} namespace ProjectExplorer { class RunControl; @@ -132,6 +135,7 @@ public: // internal public for FlatModel static void renameFile(Node *node, const QString &newFilePath); static QStringList projectFilePatterns(); + static bool isProjectFile(const Utils::FileName &filePath); static QList > recentProjects(); static bool canRunStartupProject(Core::Id runMode, QString *whyNot = nullptr); From 02b5426b8e223baf6815de936bccc99d44d74e3c Mon Sep 17 00:00:00 2001 From: Viktor Kireev Date: Tue, 3 Oct 2017 19:17:02 +0300 Subject: [PATCH 5/5] Beautifier: Fix text selection for the Uncrustify Extension of the selection of the text to full lines does not work correctly if the selection is performed from the top to the bottom. Change-Id: I13a1bf9d6e92ebbbfd4f8190fb626dd3aca74686 Reviewed-by: David Schulz --- src/plugins/beautifier/uncrustify/uncrustify.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/beautifier/uncrustify/uncrustify.cpp b/src/plugins/beautifier/uncrustify/uncrustify.cpp index b47672bc5e0..0f00d5fc698 100644 --- a/src/plugins/beautifier/uncrustify/uncrustify.cpp +++ b/src/plugins/beautifier/uncrustify/uncrustify.cpp @@ -138,10 +138,13 @@ void Uncrustify::formatSelectedText() if (tc.hasSelection()) { // Extend selection to full lines const int posSelectionEnd = tc.selectionEnd(); + tc.setPosition(tc.selectionStart()); tc.movePosition(QTextCursor::StartOfLine); const int startPos = tc.position(); tc.setPosition(posSelectionEnd); - tc.movePosition(QTextCursor::EndOfLine); + // Don't extend the selection if the cursor is at the start of the line + if (tc.positionInBlock() > 0) + tc.movePosition(QTextCursor::EndOfLine); const int endPos = tc.position(); m_beautifierPlugin->formatCurrentFile(command(cfgFileName, true), startPos, endPos); } else if (m_settings->formatEntireFileFallback()) {