File indexing completed on 2024-04-28 05:49:36
0001 /* This file is part of the KDE project 0002 SPDX-FileCopyrightText: 2015 Milian Wolff <mail@milianw.de> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include <KTextEditor/Cursor> 0010 0011 #include <QDir> 0012 #include <QRegularExpression> 0013 #include <QString> 0014 #include <QUrl> 0015 #include <QUrlQuery> 0016 0017 /** 0018 * Represents a file to be opened, consisting of its URL and the cursor to jump to. 0019 */ 0020 class UrlInfo 0021 { 0022 public: 0023 /** 0024 * Parses a file path argument and determines its line number and column and full path, 0025 * we use absolute file paths because we will e.g. pass this over dbus to other processes. 0026 * 0027 * @param path path passed on e.g. command line to parse into an URL 0028 */ 0029 UrlInfo(QString path) 0030 : cursor(KTextEditor::Cursor::invalid()) 0031 { 0032 QString currentDirPath = QDir::current().absolutePath(); 0033 if (!currentDirPath.endsWith(QLatin1Char('/'))) { 0034 currentDirPath += QLatin1Char('/'); 0035 } 0036 0037 // QDir::isAbsolutePath()/absoluteFilePath() treat paths starting with ':' as Qt 0038 // Resource (qrc) paths, and consider them absolute 0039 if (!path.startsWith(QLatin1Char(':')) && QDir::isAbsolutePath(path)) { 0040 if (QFile::exists(path)) { // Existing absolute path, no cursor can be detected 0041 url = QUrl::fromLocalFile(path); 0042 return; 0043 } 0044 } else { 0045 // Relative path, maybe starting with ':'; we concatenate the absolute path manually 0046 QString absolutePath = currentDirPath + path; 0047 0048 if (QFile::exists(absolutePath)) { // Existing absolute path, no cursor can be detected 0049 url = QUrl::fromLocalFile(absolutePath); 0050 return; 0051 } 0052 } 0053 0054 /** 0055 * ok, the path as is, is no existing file, now, cut away :xx:yy stuff as cursor 0056 * this will make test:50 to test with line 50 0057 */ 0058 const auto match = QRegularExpression(QStringLiteral(":(\\d+)(?::(\\d+))?:?$")).match(path); 0059 if (match.isValid()) { 0060 /** 0061 * cut away the line/column specification from the path 0062 */ 0063 path.chop(match.capturedLength()); 0064 0065 /** 0066 * After cutting the line/column part, if the file exists make "path" absolute. 0067 * Note that we can't rely on QUrl::fromUserInput() because of paths starting with 0068 * ':', see comment above about QDir::isAbsolutePath(). 0069 */ 0070 const QString absolutePath = currentDirPath + path; 0071 if (QFile::exists(absolutePath)) { 0072 path = absolutePath; 0073 } 0074 0075 /** 0076 * set right cursor position 0077 * don't use an invalid column when the line is valid 0078 */ 0079 const int line = match.captured(1).toInt() - 1; 0080 const int column = qMax(0, match.captured(2).toInt() - 1); 0081 cursor.setPosition(line, column); 0082 } 0083 0084 /** 0085 * Construct url: "path" has already been made absolute above. 0086 * This should work with: 0087 * - local paths, "/path/to/somefile" becomes file:///path/to/some/file 0088 * - file: urls, file:///path/to/some/file 0089 * - remote urls, e.g. sftp://1.2.3.4:22/path/to/some/file 0090 */ 0091 url = QUrl::fromUserInput(path, currentDirPath, QUrl::AssumeLocalFile); 0092 0093 /** 0094 * Set cursor position if we can extract from URL query string 0095 */ 0096 if (url.hasQuery()) { 0097 QUrlQuery urlQuery(url); 0098 QString lineStr = urlQuery.queryItemValue(QStringLiteral("line")); 0099 QString columnStr = urlQuery.queryItemValue(QStringLiteral("column")); 0100 0101 int line = 0; 0102 int column = 0; 0103 bool setCursor = false; 0104 0105 if (!lineStr.isEmpty()) { 0106 line = lineStr.toInt(); 0107 line > 0 && line--; 0108 setCursor = true; 0109 } 0110 0111 if (!columnStr.isEmpty()) { 0112 column = columnStr.toInt(); 0113 column > 0 && column--; 0114 setCursor = true; 0115 } 0116 0117 if (setCursor) { 0118 cursor.setPosition(line, column); 0119 } 0120 } 0121 } 0122 0123 /** 0124 * url computed out of the passed path 0125 */ 0126 QUrl url; 0127 0128 /** 0129 * initial cursor position, if any found inside the path as line/column specification at the end 0130 */ 0131 KTextEditor::Cursor cursor; 0132 };