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