File indexing completed on 2024-05-12 15:45:39
0001 /* 0002 SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de> 0003 SPDX-FileCopyrightText: 2005-2006 Hamish Rodda <rodda@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #ifndef KTEXTEDITOR_CODECOMPLETIONMODEL_H 0009 #define KTEXTEDITOR_CODECOMPLETIONMODEL_H 0010 0011 #include <QModelIndex> 0012 #include <ktexteditor/range.h> 0013 #include <ktexteditor_export.h> 0014 0015 namespace KTextEditor 0016 { 0017 class Document; 0018 class View; 0019 0020 /** 0021 * \class CodeCompletionModel codecompletionmodel.h <KTextEditor/CodeCompletionModel> 0022 * 0023 * \short An item model for providing code completion, and meta information for 0024 * enhanced presentation. 0025 * 0026 * \section compmodel_intro Introduction 0027 * 0028 * The CodeCompletionModel is the actual workhorse to provide code completions 0029 * in a KTextEditor::View. It is meant to be used in conjunction with the 0030 * CodeCompletionInterface. The CodeCompletionModel is not meant to be used as 0031 * is. Rather you need to implement a subclass of CodeCompletionModel to actually 0032 * generate completions appropriate for your type of Document. 0033 * 0034 * \section compmodel_implementing Implementing a CodeCompletionModel 0035 * 0036 * The CodeCompletionModel is a QAbstractItemModel, and can be subclassed in the 0037 * same way. It provides default implementations of several members, however, so 0038 * in most cases (if your completions are essentially a non-hierarchical, flat list 0039 * of matches) you will only need to overload few virtual functions. 0040 * 0041 * \section compmodel_flatlist Implementing a CodeCompletionModel for a flat list 0042 * 0043 * For the simple case of a flat list of completions, you will need to: 0044 * - Implement completionInvoked() to actually generate/update the list of completion 0045 * matches 0046 * - implement itemData() (or QAbstractItemModel::data()) to return the information that 0047 * should be displayed for each match. 0048 * - use setRowCount() to reflect the number of matches. 0049 * 0050 * \section compmodel_roles_columns Columns and roles 0051 * 0052 * \todo document the meaning and usage of the columns and roles used by the 0053 * CodeCompletionInterface 0054 * 0055 * \section compmodel_usage Using the new CodeCompletionModel 0056 * 0057 * To start using your CodeCompletionModel, refer to CodeCompletionInterface. 0058 * 0059 * \section compmodel_controller ControllerInterface to get more control 0060 * 0061 * To have more control over code completion implement 0062 * CodeCompletionModelControllerInterface in your CodeCompletionModel. 0063 * 0064 * \see CodeCompletionInterface, CodeCompletionModelControllerInterface 0065 * @author Hamish Rodda <rodda@kde.org> 0066 */ 0067 class KTEXTEDITOR_EXPORT CodeCompletionModel : public QAbstractItemModel 0068 { 0069 Q_OBJECT 0070 0071 public: 0072 explicit CodeCompletionModel(QObject *parent); 0073 ~CodeCompletionModel() override; 0074 0075 enum Columns { 0076 Prefix = 0, 0077 /// Icon representing the type of completion. We have a separate icon field 0078 /// so that names remain aligned where only some completions have icons, 0079 /// and so that they can be rearranged by the user. 0080 Icon, 0081 Scope, 0082 Name, 0083 Arguments, 0084 Postfix 0085 }; 0086 static const int ColumnCount = Postfix + 1; 0087 0088 /// @see CompletionProperties 0089 enum CompletionProperty { 0090 NoProperty = 0x0, 0091 FirstProperty = 0x1, 0092 0093 // Access specifiers - no more than 1 per item 0094 Public = 0x1, 0095 Protected = 0x2, 0096 Private = 0x4, 0097 0098 // Extra access specifiers - any number per item 0099 Static = 0x8, 0100 Const = 0x10, 0101 0102 // Type - no more than 1 per item (except for Template) 0103 Namespace = 0x20, 0104 Class = 0x40, 0105 Struct = 0x80, 0106 Union = 0x100, 0107 Function = 0x200, 0108 Variable = 0x400, 0109 Enum = 0x800, 0110 Template = 0x1000, 0111 TypeAlias = 0x2000, 0112 0113 // Special attributes - any number per item 0114 Virtual = 0x4000, 0115 Override = 0x8000, 0116 Inline = 0x10000, 0117 Friend = 0x20000, 0118 Signal = 0x40000, 0119 Slot = 0x80000, 0120 0121 // Scope - no more than 1 per item 0122 LocalScope = 0x100000, 0123 NamespaceScope = 0x200000, 0124 GlobalScope = 0x400000, 0125 0126 // Keep this in sync so the code knows when to stop 0127 LastProperty = GlobalScope 0128 }; 0129 /// Stores a combination of #CompletionProperty values. 0130 Q_DECLARE_FLAGS(CompletionProperties, CompletionProperty) 0131 0132 /// @see HighlightMethods 0133 enum HighlightMethod { NoHighlighting = 0x0, InternalHighlighting = 0x1, CustomHighlighting = 0x2 }; 0134 /// Stores a combination of #HighlightMethod values. 0135 Q_DECLARE_FLAGS(HighlightMethods, HighlightMethod) 0136 0137 /// Meta information is passed through extra {Qt::ItemDataRole}s. 0138 /// This information should be returned when requested on the Name column. 0139 enum ExtraItemDataRoles { 0140 /// The model should return a set of CompletionProperties. 0141 CompletionRole = Qt::UserRole, 0142 0143 /// The model should return an index to the scope 0144 /// -1 represents no scope 0145 /// \todo how to sort scope? 0146 ScopeIndex, 0147 0148 /** 0149 * If requested, your model should try to determine whether the 0150 * completion in question is a suitable match for the context (ie. 0151 * is accessible, exported, + returns the data type required). 0152 * 0153 * The returned data should ideally be matched against the argument-hint context 0154 * set earlier by SetMatchContext. 0155 * 0156 * Return an integer value that should be positive if the completion is suitable, 0157 * and zero if the completion is not suitable. The value should be between 0 an 10, where 0158 * 10 means perfect match. 0159 * 0160 * Return QVariant::Invalid if you are unable to determine this. 0161 */ 0162 MatchQuality, 0163 0164 /** 0165 * Is requested before MatchQuality(..) is requested. The item on which this is requested 0166 * is an argument-hint item(@see ArgumentHintDepth). When this role is requested, the item should 0167 * be noted, and whenever MatchQuality is requested, it should be computed by matching the item given 0168 * with MatchQuality into the context chosen by SetMatchContext. 0169 * 0170 * Feel free to ignore this, but ideally you should return QVariant::Invalid to make clear that your model does not support this. 0171 * */ 0172 SetMatchContext, 0173 0174 /** 0175 * Define which highlighting method will be used: 0176 * - QVariant::Invalid - allows the editor to choose (usually internal highlighting) 0177 * - QVariant::Integer - highlight as specified by HighlightMethods. 0178 */ 0179 HighlightingMethod, 0180 0181 /** 0182 * Allows an item to provide custom highlighting. Return a 0183 * QList\<QVariant\> in the following format: 0184 * - int startColumn (where 0 = start of the completion entry) 0185 * - int endColumn (note: not length) 0186 * - QTextFormat attribute (note: attribute may be a KTextEditor::Attribute, as it is a child class) 0187 * If the attribute is invalid, and the item is an argument-hint, the text will be drawn with 0188 * a background-color depending on match-quality, or yellow. 0189 * You can use that to mark the actual arguments that are matched in an argument-hint. 0190 * 0191 * Repeat this triplet as many times as required, however each column must be >= the previous, 0192 * and startColumn != endColumn. 0193 */ 0194 CustomHighlight, 0195 0196 /** 0197 * Returns the inheritance depth of the completion. For example, a completion 0198 * which comes from the base class would have depth 0, one from a parent class 0199 * would have depth 1, one from that class' parent 2, etc. you can use this to 0200 * symbolize the general distance of a completion-item from a user. It will be used 0201 * for sorting. 0202 */ 0203 InheritanceDepth, 0204 0205 /** 0206 * This allows items in the completion-list to be expandable. If a model returns an QVariant bool value 0207 * that evaluates to true, the completion-widget will draw a handle to expand the item, and will also make 0208 * that action accessible through keyboard. 0209 */ 0210 IsExpandable, 0211 /** 0212 * After a model returned true for a row on IsExpandable, the row may be expanded by the user. 0213 * When this happens, ExpandingWidget is requested. 0214 * 0215 * The model may return two types of values: 0216 * QWidget*: 0217 * If the model returns a QVariant of type QWidget*, the code-completion takes over the given widget 0218 * and embeds it into the completion-list under the completion-item. The widget will be automatically deleted at some point. 0219 * The completion-widget will use the height of the widget as a hint for its preferred size, but it will 0220 * resize the widget at will. 0221 * QString: 0222 * If the mode returns a QVariant of type QString, it will create a small html-widget showing the given html-code, 0223 * and embed it into the completion-list under the completion-item. 0224 * 0225 * @warning 0226 * @code 0227 * QWidget* widget; 0228 * return QVariant(widget); 0229 * @endcode 0230 * Will not work correctly! 0231 * Use the following instead.: 0232 * @code 0233 * QVariant v; 0234 * v.setValue<QWidget*>(widget); 0235 * return v; 0236 * @endcode 0237 * 0238 * */ 0239 ExpandingWidget, 0240 /** 0241 * Whenever an item is selected, this will be requested from the underlying model. 0242 * It may be used as a simple notification that the item was selected. 0243 * 0244 * Above that, the model may return a QString, which then should then contain html-code. A html-widget 0245 * will then be displayed as a one- or two-liner under the currently selected item(it will be partially expanded) 0246 * */ 0247 ItemSelected, 0248 0249 /**Is this completion-item an argument-hint? 0250 * The model should return an integral positive number if the item is an argument-hint, and QVariant() or 0 if it is not one. 0251 * 0252 * The returned depth-integer is important for sorting and matching. 0253 * Example: 0254 * "otherFunction(function1(function2(" 0255 * all functions named function2 should have ArgumentHintDepth 1, all functions found for function1 should have ArgumentHintDepth 2, 0256 * and all functions named otherFunction should have ArgumentHintDepth 3 0257 * 0258 * Later, a completed item may then be matched with the first argument of function2, the return-type of function2 with the first 0259 * argument-type of function1, and the return-type of function1 with the argument-type of otherFunction. 0260 * 0261 * If the model returns a positive value on this role for a row, the content will be treated specially: 0262 * - It will be shown in a separate argument-hint list 0263 * - It will be sorted by Argument-hint depth 0264 * - Match-qualities will be illustrated by differently highlighting the matched argument if possible 0265 * The argument-hint list strings will be built from all source-model, with a little special behavior: 0266 * Prefix - Should be all text of the function-signature up to left of the matched argument of the function 0267 * Name - Should be the type and name of the function's matched argument. This part will be highlighted differently depending on the match-quality 0268 * Suffix - Should be all the text of the function-signature behind the matched argument 0269 * 0270 * Example: You are matching a function with signature "void test(int param1, int param2)", and you are matching the first argument. 0271 * The model should then return: 0272 * Prefix: "void test(" 0273 * Name: "int param1" 0274 * Suffix: ", int param2)" 0275 * 0276 * If you don't use the highlighting, matching, etc. you can also return the columns in the usual way. 0277 * */ 0278 ArgumentHintDepth, 0279 0280 /** 0281 * This will be requested for each item to ask whether it should be included in computing a best-matches list. 0282 * If you return a valid positive integer n here, the n best matches will be listed at top of the completion-list separately. 0283 * 0284 * This is expensive because all items of the whole completion-list will be tested for their matching-quality, with each of the level 1 0285 * argument-hints. 0286 * 0287 * For that reason the end-user should be able to disable this feature. 0288 */ 0289 BestMatchesCount, 0290 0291 /** 0292 * The following three enumeration-values are only used on expanded completion-list items that contain an expanding-widget(@see ExpandingWidget) 0293 * 0294 * You can use them to allow the user to interact with the widget by keyboard. 0295 * 0296 * AccessibilityNext will be requested on an item if it is expanded, contains an expanding-widget, and the user triggers a special navigation 0297 * short-cut to go to navigate to the next position within the expanding-widget(if applicable). 0298 * 0299 * Return QVariant(true) if the input was used. 0300 * */ 0301 AccessibilityNext, 0302 /** 0303 * AccessibilityPrevious will be requested on an item if it is expanded, contains an expanding-widget, and the user triggers a special navigation 0304 * short-cut to go to navigate to the previous position within the expanding-widget(if applicable). 0305 * 0306 * Return QVariant(true) if the input was used. 0307 * */ 0308 AccessibilityPrevious, 0309 /** 0310 * AccessibilityAccept will be requested on an item if it is expanded, contains an expanding-widget, and the user triggers a special 0311 * shortcut to trigger the action associated with the position within the expanding-widget the user has navigated to using AccessibilityNext and 0312 * AccessibilityPrevious. 0313 * 0314 * This should return QVariant(true) if an action was triggered, else QVariant(false) or QVariant(). 0315 * */ 0316 AccessibilityAccept, 0317 0318 /** 0319 * Using this Role, it is possible to greatly optimize the time needed to process very long completion-lists. 0320 * 0321 * In the completion-list, the items are usually ordered by some properties like argument-hint depth, 0322 * inheritance-depth and attributes. Kate usually has to query the completion-models for these values 0323 * for each item in the completion-list in order to extract the argument-hints and correctly sort the 0324 * completion-list. However, with a very long completion-list, only a very small fraction of the items is actually 0325 * visible. 0326 * 0327 * By using a tree structure you can give the items in a grouped order to kate, so it does not need to look at each 0328 * item and query data in order to initially show the completion-list. 0329 * 0330 * This is how it works: 0331 * - You create a tree-structure for your items 0332 * - Every inner node of the tree defines one attribute value that all sub-nodes have in common. 0333 * - When the inner node is queried for GroupRole, it should return the "ExtraItemDataRoles" that all sub-nodes have in common 0334 * - When the inner node is then queried for that exact role, it should return that value. 0335 * - No other queries will be done to inner nodes. 0336 * - Every leaf node stands for an actual item in the completion list. 0337 * 0338 * The recommended grouping order is: Argument-hint depth, inheritance depth, attributes. 0339 * 0340 * This role can also be used to define completely custom groups, bypassing the editors builtin grouping: 0341 * - Return Qt::DisplayRole when GroupRole is requested 0342 * - Return the label text of the group when Qt::DisplayRole 0343 * - Optional: Return an integer sorting-value when InheritanceDepth is requested. This number will 0344 * be used to determine the order of the groups. The order of the builtin groups is: 0345 * 1 = Best Matches, 100 = Local Scope, 200 = Public, 300 = Protected, 400 = Private, 500 = Namespace, 600 = Global 0346 * You can pick any arbitrary number to position your group relative to these builtin groups. 0347 * */ 0348 GroupRole, 0349 0350 /** 0351 * Return a nonzero value here to enforce sorting the item at the end of the list. 0352 */ 0353 UnimportantItemRole, 0354 0355 LastExtraItemDataRole 0356 }; 0357 0358 void setRowCount(int rowCount); 0359 0360 enum InvocationType { AutomaticInvocation, UserInvocation, ManualInvocation }; 0361 0362 /** 0363 * This function is responsible to generating / updating the list of current 0364 * completions. The default implementation does nothing. 0365 * 0366 * When implementing this function, remember to call setRowCount() (or implement 0367 * rowCount()), and to generate the appropriate change notifications (for instance 0368 * by calling QAbstractItemModel::reset()). 0369 * @param view The view to generate completions for 0370 * @param range The range of text to generate completions for 0371 * @param invocationType How the code completion was triggered 0372 * */ 0373 virtual void completionInvoked(KTextEditor::View *view, const KTextEditor::Range &range, InvocationType invocationType); 0374 0375 /** 0376 * This function is responsible for inserting a selected completion into the 0377 * view. The default implementation replaces the text that the completions 0378 * were based on with the Qt::DisplayRole of the Name column of the given match. 0379 * 0380 * @param view the view to insert the completion into 0381 * @param word the Range that the completions are based on (what the user entered 0382 * so far) 0383 * @param index identifies the completion match to insert 0384 * */ 0385 virtual void executeCompletionItem(KTextEditor::View *view, const Range &word, const QModelIndex &index) const; 0386 0387 // Reimplementations 0388 /** 0389 * Reimplemented from QAbstractItemModel::columnCount(). The default implementation 0390 * returns ColumnCount for all indices. 0391 * */ 0392 int columnCount(const QModelIndex &parent = QModelIndex()) const override; 0393 /** 0394 * Reimplemented from QAbstractItemModel::index(). The default implementation 0395 * returns a standard QModelIndex as long as the row and column are valid. 0396 * */ 0397 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; 0398 /** 0399 * Reimplemented from QAbstractItemModel::itemData(). The default implementation 0400 * returns a map with the QAbstractItemModel::data() for all roles that are used 0401 * by the CodeCompletionInterface. You will need to reimplement either this 0402 * function or QAbstractItemModel::data() in your CodeCompletionModel. 0403 * */ 0404 QMap<int, QVariant> itemData(const QModelIndex &index) const override; 0405 /** 0406 * Reimplemented from QAbstractItemModel::parent(). The default implementation 0407 * returns an invalid QModelIndex for all items. This is appropriate for 0408 * non-hierarchical / flat lists of completions. 0409 * */ 0410 QModelIndex parent(const QModelIndex &index) const override; 0411 /** 0412 * Reimplemented from QAbstractItemModel::rowCount(). The default implementation 0413 * returns the value set by setRowCount() for invalid (toplevel) indices, and 0 0414 * for all other indices. This is appropriate for non-hierarchical / flat lists 0415 * of completions 0416 * */ 0417 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0418 0419 /** 0420 * This function returns true if the model needs grouping, otherwise false. 0421 * The default is false if not changed via setHasGroups(). 0422 */ 0423 bool hasGroups() const; 0424 0425 Q_SIGNALS: 0426 0427 /** 0428 * Emit this if the code-completion for this model was invoked, some time is needed in order to get the data, 0429 * and the model is reset once the data is available. 0430 * 0431 * This only has an effect if emitted from within completionInvoked(..). 0432 * 0433 * This prevents the code-completion list from showing until this model is reset, 0434 * so there is no annoying flashing in the user-interface resulting from other models 0435 * supplying their data earlier. 0436 * 0437 * @note The implementation may choose to show the completion-list anyway after some timeout 0438 * 0439 * @warning If you emit this, you _must_ also reset the model at some point, 0440 * else the code-completion will be completely broken to the user. 0441 * Consider that there may always be additional completion-models apart from yours. 0442 * 0443 * @since 4.3 0444 */ 0445 void waitForReset(); 0446 0447 /** 0448 * Internal 0449 */ 0450 void hasGroupsChanged(KTextEditor::CodeCompletionModel *model, bool hasGroups); 0451 0452 protected: 0453 void setHasGroups(bool hasGroups); 0454 0455 private: 0456 class CodeCompletionModelPrivate *const d; 0457 }; 0458 0459 Q_DECLARE_OPERATORS_FOR_FLAGS(CodeCompletionModel::CompletionProperties) 0460 Q_DECLARE_OPERATORS_FOR_FLAGS(CodeCompletionModel::HighlightMethods) 0461 0462 } 0463 0464 #endif // KTEXTEDITOR_CODECOMPLETIONMODEL_H