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