File indexing completed on 2024-05-12 04:37:47

0001 /*
0002     SPDX-FileCopyrightText: 2008 David Nolden <david.nolden.kdevelop@art-master.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #ifndef KDEVPLATFORM_CODEREPRESENTATION_H
0008 #define KDEVPLATFORM_CODEREPRESENTATION_H
0009 
0010 #include <language/languageexport.h>
0011 #include <serialization/indexedstring.h>
0012 
0013 #include <KTextEditor/ConfigInterface>
0014 #include <KTextEditor/Document>
0015 
0016 #include <memory>
0017 
0018 class QString;
0019 
0020 namespace KTextEditor {
0021 class Range;
0022 }
0023 
0024 namespace KDevelop {
0025 struct KDevEditingTransaction;
0026 
0027 class IndexedString;
0028 
0029 //NOTE: this is ugly, but otherwise kate might remove tabs again :-/
0030 // see also: https://bugs.kde.org/show_bug.cgi?id=291074
0031 struct EditorDisableReplaceTabs
0032 {
0033     explicit EditorDisableReplaceTabs(KTextEditor::Document* document) : m_iface(qobject_cast<KTextEditor::ConfigInterface*>(
0034                 document))
0035         , m_count(0)
0036     {
0037         ++m_count;
0038         if (m_count > 1)
0039             return;
0040         if (m_iface) {
0041             m_oldReplaceTabs = m_iface->configValue(configKey());
0042             m_iface->setConfigValue(configKey(), false);
0043         }
0044     }
0045 
0046     ~EditorDisableReplaceTabs()
0047     {
0048         --m_count;
0049         if (m_count > 0)
0050             return;
0051 
0052         Q_ASSERT(m_count == 0);
0053 
0054         if (m_iface)
0055             m_iface->setConfigValue(configKey(), m_oldReplaceTabs);
0056     }
0057 
0058     inline QString configKey() const
0059     {
0060         return QStringLiteral("replace-tabs");
0061     }
0062 
0063 private:
0064     Q_DISABLE_COPY(EditorDisableReplaceTabs)
0065 
0066     KTextEditor::ConfigInterface* m_iface;
0067     int m_count;
0068     QVariant m_oldReplaceTabs;
0069 };
0070 
0071 struct KDevEditingTransaction
0072 {
0073     explicit KDevEditingTransaction(KTextEditor::Document* document)
0074         : edit(document)
0075         , disableReplaceTabs(document)
0076     {}
0077     // NOTE: It's important to close the transaction first and only then destroy the EditorDisableReplaceTabs. Otherwise we hit asserts in KTextEditor.
0078     KTextEditor::Document::EditingTransaction edit;
0079     EditorDisableReplaceTabs disableReplaceTabs;
0080     using Ptr = std::unique_ptr<KDevEditingTransaction>;
0081 };
0082 
0083 /**
0084  * Allows getting code-lines conveniently, either through an open editor, or from a disk-loaded file.
0085  */
0086 class KDEVPLATFORMLANGUAGE_EXPORT CodeRepresentation
0087     : public QSharedData
0088 {
0089 public:
0090     virtual ~CodeRepresentation()
0091     {
0092     }
0093     virtual QString line(int line) const = 0;
0094     virtual int lines() const = 0;
0095     virtual QString text() const = 0;
0096     virtual QString rangeText(const KTextEditor::Range& range) const;
0097     /**
0098      * Search for the given identifier in the document, and returns all ranges
0099      * where it was found.
0100      * @param identifier The identifier to search for
0101      * @param surroundedByBoundary Whether only matches that are surrounded by typical word-boundaries
0102      *                             should be acceded. Everything except letters, numbers, and the _ character
0103      *                             counts as word boundary.
0104      * */
0105     virtual QVector<KTextEditor::Range> grep(const QString& identifier, bool surroundedByBoundary = true) const = 0;
0106     /**
0107      * Overwrites the text in the file with the new given one
0108      *
0109      * @return true on success
0110      */
0111     virtual bool setText(const QString&) = 0;
0112     /** @return true if this representation represents an actual file on disk */
0113     virtual bool fileExists() const = 0;
0114 
0115     /**
0116      * Can be used for example from tests to disallow on-disk changes. When such a change is done, an assertion is triggered.
0117      * You should enable this within tests, unless you really want to work on the disk.
0118      */
0119     static void setDiskChangesForbidden(bool changesForbidden);
0120 
0121     /**
0122      * Returns the specified name as a url for artificial source code
0123      * suitable for code being inserted into the parser
0124      */
0125     static QString artificialPath(const QString& name);
0126 
0127     using Ptr = QExplicitlySharedDataPointer<CodeRepresentation>;
0128 };
0129 
0130 class KDEVPLATFORMLANGUAGE_EXPORT DynamicCodeRepresentation
0131     : public CodeRepresentation
0132 {
0133 public:
0134     /** Used to group edit-history together. Call this optionally before a bunch
0135      *  of replace() calls, to group them together. */
0136     virtual KDevEditingTransaction::Ptr makeEditTransaction() = 0;
0137     virtual bool replace(const KTextEditor::Range& range, const QString& oldText,
0138                          const QString& newText, bool ignoreOldText = false) = 0;
0139 
0140     using Ptr = QExplicitlySharedDataPointer<DynamicCodeRepresentation>;
0141 };
0142 
0143 /**
0144  * Creates a code-representation for the given url, that allows conveniently accessing its data. Returns zero on failure.
0145  */
0146 KDEVPLATFORMLANGUAGE_EXPORT CodeRepresentation::Ptr createCodeRepresentation(const IndexedString& url);
0147 
0148 /**
0149  * @return true if an artificial code representation already exists for the specified URL
0150  */
0151 KDEVPLATFORMLANGUAGE_EXPORT bool artificialCodeRepresentationExists(const IndexedString& url);
0152 
0153 /**
0154  *   Allows inserting artificial source-code into the code-representation and parsing framework.
0155  *  The source-code logically represents a file.
0156  *
0157  *  The artificial code is automatically removed when the object is destroyed.
0158  */
0159 class KDEVPLATFORMLANGUAGE_EXPORT InsertArtificialCodeRepresentation
0160     : public QSharedData
0161 {
0162 public:
0163     /**
0164      * Inserts an artificial source-code representation with filename @p file and the contents @p text
0165      * If @p file is not an absolute path or url, it will be made absolute using the CodeRepresentation::artificialUrl()
0166      * function, while ensuring that the name is unique.
0167      */
0168     InsertArtificialCodeRepresentation(const IndexedString& file, const QString& text);
0169     ~InsertArtificialCodeRepresentation();
0170     InsertArtificialCodeRepresentation(const InsertArtificialCodeRepresentation&) = delete;
0171     InsertArtificialCodeRepresentation& operator=(const InsertArtificialCodeRepresentation&) = delete;
0172 
0173     void setText(const QString& text);
0174     QString text() const;
0175     /**
0176      * Returns the file-name for this code-representation.
0177      */
0178     IndexedString file();
0179 
0180 private:
0181     IndexedString m_file;
0182 };
0183 
0184 using InsertArtificialCodeRepresentationPointer = QExplicitlySharedDataPointer<InsertArtificialCodeRepresentation>;
0185 }
0186 
0187 #endif