diff --git a/kioclient/kioclient.h b/kioclient/kioclient.h --- a/kioclient/kioclient.h +++ b/kioclient/kioclient.h @@ -23,7 +23,6 @@ #include class QCommandLineParser; -class QUrl; class KJob; namespace KIO { class Job; } @@ -44,7 +43,7 @@ void slotDialogCanceled(); private: - bool kde_open( const QUrl& url, const QString& mimeType, bool allowExec ); + bool kde_open( const QString& url, const QString& mimeType, bool allowExec); bool doCopy( const QStringList& urls ); bool doMove( const QStringList& urls ); bool doList( const QStringList& urls ); diff --git a/kioclient/kioclient.cpp b/kioclient/kioclient.cpp --- a/kioclient/kioclient.cpp +++ b/kioclient/kioclient.cpp @@ -18,6 +18,7 @@ #include "kioclient.h" #include "kio_version.h" +#include "urlinfo.h" #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #include bool ClientApp::m_ok = true; @@ -195,10 +197,19 @@ } #ifndef KIOCORE_ONLY -bool ClientApp::kde_open(const QUrl& url, const QString& mimeType, bool allowExec) +bool ClientApp::kde_open(const QString& url, const QString& mimeType, bool allowExec) { + UrlInfo info(url); + + if(!info.atStart()) { + QUrlQuery q; + q.addQueryItem(QStringLiteral("line"), QString::number(info.line)); + q.addQueryItem(QStringLiteral("column"), QString::number(info.column)); + info.url.setQuery(q); + } + if ( mimeType.isEmpty() ) { - KRun * run = new KRun( url, nullptr ); + KRun * run = new KRun( info.url, nullptr ); run->setRunExecutables(allowExec); #if KIO_VERSION >= QT_VERSION_CHECK(5,55,0) @@ -209,7 +220,7 @@ qApp->exec(); return !krun_has_error; } else { - return KRun::runUrl(url, mimeType, nullptr, KRun::RunFlags(KRun::RunExecutables)); + return KRun::runUrl(info.url, mimeType, nullptr, KRun::RunFlags(KRun::RunExecutables)); } } #endif @@ -299,7 +310,7 @@ #endif #ifdef KIOCLIENT_AS_KDEOPEN - return kde_open(makeURL(parser.positionalArguments().at(0)), QString(), false); + return kde_open(parser.positionalArguments().at(0), QString(), false); #elif defined(KIOCLIENT_AS_KDECP5) checkArgumentCount(argc, 2, 0); return doCopy(parser.positionalArguments()); @@ -341,7 +352,7 @@ else if ( command ==QLatin1String( "exec") ) { checkArgumentCount(argc, 2, 3); - return kde_open( makeURL(parser.positionalArguments()[1]), + return kde_open( parser.positionalArguments()[1], argc == 3 ? parser.positionalArguments().last() : QString(), true ); } diff --git a/kioclient/urlinfo.h b/kioclient/urlinfo.h new file mode 100644 --- /dev/null +++ b/kioclient/urlinfo.h @@ -0,0 +1,108 @@ +/* This file is part of the KDE project + Copyright (C) 2015 Milian Wolff + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#ifndef URLINFO_H +#define URLINFO_H + +#include +#include +#include +#include + +/** + * Represents a file to be opened, consisting of its URL and the cursor to jump to. + */ +class UrlInfo +{ +public: + /** + * Parses an argument and determines its line number and column and full path + * @param pathOrUrl path passed on e.g. command line to parse into an URL or just an URL + */ + UrlInfo(const QString& pathOrUrl) + : line(0), column(0) + { + /** + * first try: just check if the path is an existing file + */ + if (QFile::exists(pathOrUrl)) { + /** + * create absolute file path, we will e.g. pass this over dbus to other processes + * and then we are done, no cursor can be detected here! + */ + url = QUrl::fromLocalFile(QDir::current().absoluteFilePath(pathOrUrl)); + return; + } + + /** + * ok, the path as is, is no existing file, now, cut away :xx:yy stuff as cursor + * this will make test:50 to test with line 50 + */ + QString pathOrUrl2 = pathOrUrl; + const auto match = QRegularExpression(QStringLiteral(":(\\d+)(?::(\\d+))?:?$")).match(pathOrUrl2); + if (match.isValid()) { + /** + * cut away the line/column specification from the path + */ + pathOrUrl2.chop(match.capturedLength()); + + /** + * set right cursor position + */ + line = match.capturedRef(1).toUInt(); + column = match.capturedRef(2).toUInt(); + } + + /** + * construct url: + * - make relative paths absolute using the current working directory + * - do not prefer local file, to be able to open things like foo.com in browser + */ + url = QUrl::fromUserInput(pathOrUrl2, QDir::currentPath(), QUrl::DefaultResolution); + + /** + * in some cases, this will fail, e.g. if you have line/column specs like test.c:10:1 + * => fallback: assume a local file and just convert it to an url + */ + if (!url.isValid()) { + /** + * create absolute file path, we will e.g. pass this over dbus to other processes + */ + url = QUrl::fromLocalFile(QDir::current().absoluteFilePath(pathOrUrl2)); + } + } + + bool atStart() const { + return (line == 0 || line == 1 ) + && (column == 0 || column == 1); + } + + /** + * url computed out of the passed path or URL + */ + QUrl url; + + /** + * initial cursor position, if any found inside the path as line/column specification at the end + */ + unsigned line, column; +}; + +#endif // URLINFO_H