File indexing completed on 2024-04-21 03:57:49

0001 /*
0002     SPDX-FileCopyrightText: 2004, 2010 Joseph Wenninger <jowenn@kde.org>
0003     SPDX-FileCopyrightText: 2009 Milian Wolff <mail@milianw.de>
0004     SPDX-FileCopyrightText: 2014 Sven Brauch <svenbrauch@gmail.com>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #ifndef _KATE_TEMPLATE_HANDLER_H_
0010 #define _KATE_TEMPLATE_HANDLER_H_
0011 
0012 #include <QList>
0013 #include <QObject>
0014 #include <QPointer>
0015 #include <QString>
0016 
0017 #include <katescript.h>
0018 #include <ktexteditor/cursor.h>
0019 
0020 class KateUndoManager;
0021 
0022 namespace KTextEditor
0023 {
0024 class DocumentPrivate;
0025 class ViewPrivate;
0026 class MovingCursor;
0027 class MovingRange;
0028 class View;
0029 }
0030 
0031 /**
0032  * \brief Inserts a template and offers advanced snippet features, like navigation and mirroring.
0033  *
0034  * For each template inserted a new KateTemplateHandler will be created.
0035  *
0036  * The handler has the following features:
0037  *
0038  * \li It inserts the template string into the document at the requested position.
0039  * \li When the template contains at least one variable, the cursor will be placed
0040  *     at the start of the first variable and its range gets selected.
0041  * \li When more than one variable exists,TAB and SHIFT TAB can be used to navigate
0042  *     to the next/previous variable.
0043  * \li When a variable occurs more than once in the template, edits to any of the
0044  *     occurrences will be mirroed to the other ones.
0045  * \li When ESC is pressed, the template handler closes.
0046  * \li When ALT + RETURN is pressed and a \c ${cursor} variable
0047  *     exists in the template,the cursor will be placed there. Else the cursor will
0048  *     be placed at the end of the template.
0049  *
0050  * \author Milian Wolff <mail@milianw.de>
0051  */
0052 
0053 class KateTemplateHandler : public QObject
0054 {
0055     Q_OBJECT
0056 
0057 public:
0058     /**
0059      * Setup the template handler, insert the template string.
0060      *
0061      * NOTE: The handler deletes itself when required, you do not need to
0062      *       keep track of it.
0063      */
0064     KateTemplateHandler(KTextEditor::ViewPrivate *view,
0065                         KTextEditor::Cursor position,
0066                         const QString &templateString,
0067                         const QString &script,
0068                         KateUndoManager *undoManager);
0069 
0070     ~KateTemplateHandler() override;
0071 
0072 protected:
0073     /**
0074      * \brief Provide keyboard interaction for the template handler.
0075      *
0076      * The event filter handles the following shortcuts:
0077      *
0078      * TAB: jump to next editable (i.e. not mirrored) range.
0079      *      NOTE: this prevents indenting via TAB.
0080      * SHIFT + TAB: jump to previous editable (i.e. not mirrored) range.
0081      *      NOTE: this prevents un-indenting via SHIFT + TAB.
0082      * ESC: terminate template handler (only when no completion is active).
0083      * ALT + RETURN: accept template and jump to the end-cursor.
0084      *               if %{cursor} was given in the template, that will be the
0085      *               end-cursor.
0086      *               else just jump to the end of the inserted text.
0087      */
0088     bool eventFilter(QObject *object, QEvent *event) override;
0089 
0090 private:
0091     /**
0092      * Inserts the @p text template at @p position and performs
0093      * all necessary initializations, such as populating default values
0094      * and placing the cursor.
0095      */
0096     void initializeTemplate();
0097 
0098     /**
0099      * Parse @p templateText and populate m_fields.
0100      */
0101     void parseFields(const QString &templateText);
0102 
0103     /**
0104      * Set necessary attributes (esp. background colour) on all moving
0105      * ranges for the fields in m_fields.
0106      */
0107     void setupFieldRanges();
0108 
0109     /**
0110      * Evaluate default values for all fields in m_fields and
0111      * store them in the fields. This updates the @property defaultValue property
0112      * of the TemplateField instances in m_fields from the raw, user-entered
0113      * default value to its evaluated equivalent (e.g. "func()" -> result of function call)
0114      *
0115      * @sa TemplateField
0116      */
0117     void setupDefaultValues();
0118 
0119     /**
0120      * Install an event filter on the filter proxy of \p view for
0121      * navigation between the ranges and terminating the KateTemplateHandler.
0122      *
0123      * \see eventFilter()
0124      */
0125     void setupEventHandler(KTextEditor::View *view);
0126 
0127     /**
0128      * Jumps to the previous editable range. If there is none, wrap and jump to the first range.
0129      *
0130      * \see jumpToNextRange()
0131      */
0132     void jumpToPreviousRange();
0133 
0134     /**
0135      * Jumps to the next editable range. If there is none, wrap and jump to the last range.
0136      *
0137      * \see jumpToPreviousRange()
0138      */
0139     void jumpToNextRange();
0140 
0141     /**
0142      * Helper function for jumpTo{Next,Previous}
0143      * if initial is set to true, assumes the cursor is before the snippet
0144      * and selects the first field
0145      */
0146     void jump(int by, bool initial = false);
0147 
0148     /**
0149      * Jumps to the final cursor position. This is either \p m_finalCursorPosition, or
0150      * if that is not set, the end of \p m_templateRange.
0151      */
0152     void jumpToFinalCursorPosition();
0153 
0154     /**
0155      * Go through all template fields and decide if their moving ranges expand
0156      * when edited at the corners. Expansion is turned off if two fields are
0157      * directly adjacent to avoid overlaps when characters are inserted between
0158      * them.
0159      */
0160     void updateRangeBehaviours();
0161 
0162     /**
0163      * Sort all template fields in m_fields by tab order, which means,
0164      * by range; except for ${cursor} which is always sorted last.
0165      */
0166     void sortFields();
0167 
0168 private Q_SLOTS:
0169     /**
0170      * Saves the range of the inserted template. This is required since
0171      * tabs could get expanded on insert. While we are at it, we can
0172      * use it to auto-indent the code after insert.
0173      */
0174     void slotTemplateInserted(KTextEditor::Document *document, KTextEditor::Range range);
0175 
0176     /**
0177      * Install event filter on new views.
0178      */
0179     void slotViewCreated(KTextEditor::Document *document, KTextEditor::View *view);
0180 
0181     /**
0182      * Update content of all dependent fields, i.e. mirror or script fields.
0183      */
0184     void updateDependentFields(KTextEditor::Document *document, KTextEditor::Range oldRange);
0185 
0186 public:
0187     KTextEditor::ViewPrivate *view() const;
0188     KTextEditor::DocumentPrivate *doc() const;
0189 
0190 private:
0191     /// The view we operate on
0192     KTextEditor::ViewPrivate *m_view;
0193     /// The undo manager associated with our document
0194     KateUndoManager *const m_undoManager;
0195 
0196     // Describes a single template field, e.g. ${foo}.
0197     struct TemplateField {
0198         // up-to-date range for the field
0199         std::shared_ptr<KTextEditor::MovingRange> range;
0200         // contents of the field, i.e. identifier or function to call
0201         QString identifier;
0202         // default value, if applicable; else empty
0203         QString defaultValue;
0204         enum Kind {
0205             Invalid, // not an actual field
0206             Editable, // normal, user-editable field (green by default) [non-dependent field]
0207             Mirror, // field mirroring contents of another field [dependent field]
0208             FunctionCall, // field containing the up-to-date result of a function call [dependent field]
0209             FinalCursorPosition // field marking the final cursor position
0210         };
0211         Kind kind = Invalid;
0212         // true if this field was edited by the user before
0213         bool touched = false;
0214         bool operator==(const TemplateField &other) const
0215         {
0216             return range == other.range;
0217         }
0218     };
0219     // List of all template fields in the inserted snippet. @see sortFields()
0220     QList<TemplateField> m_fields;
0221 
0222     // Get the template field which contains @p range.
0223     const TemplateField fieldForRange(KTextEditor::Range range) const;
0224 
0225     /// Construct a map of master fields and their current value, for use in scripts.
0226     KateScript::FieldMap fieldMap() const;
0227 
0228     /// A range that occupies the whole range of the inserted template.
0229     /// When the an edit happens outside it, the template handler gets closed.
0230     std::shared_ptr<KTextEditor::MovingRange> m_wholeTemplateRange;
0231 
0232     /// Set to true when currently updating dependent fields, to prevent recursion.
0233     bool m_internalEdit;
0234 
0235     /// template script (i.e. javascript stuff), which can be used by the current template
0236     KateScript m_templateScript;
0237 };
0238 
0239 #endif