KTextEditor

codecompletionmodel.h
1 /*
2  SPDX-FileCopyrightText: 2007-2008 David Nolden <[email protected]>
3  SPDX-FileCopyrightText: 2005-2006 Hamish Rodda <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #ifndef KTEXTEDITOR_CODECOMPLETIONMODEL_H
9 #define KTEXTEDITOR_CODECOMPLETIONMODEL_H
10 
11 #include <QModelIndex>
12 #include <ktexteditor/range.h>
13 #include <ktexteditor_export.h>
14 
15 namespace KTextEditor
16 {
17 class Document;
18 class View;
19 
20 /**
21  * \class CodeCompletionModel codecompletionmodel.h <KTextEditor/CodeCompletionModel>
22  *
23  * \short An item model for providing code completion, and meta information for
24  * enhanced presentation.
25  *
26  * \section compmodel_intro Introduction
27  *
28  * The CodeCompletionModel is the actual workhorse to provide code completions
29  * in a KTextEditor::View. It is meant to be used in conjunction with the
30  * CodeCompletionInterface. The CodeCompletionModel is not meant to be used as
31  * is. Rather you need to implement a subclass of CodeCompletionModel to actually
32  * generate completions appropriate for your type of Document.
33  *
34  * \section compmodel_implementing Implementing a CodeCompletionModel
35  *
36  * The CodeCompletionModel is a QAbstractItemModel, and can be subclassed in the
37  * same way. It provides default implementations of several members, however, so
38  * in most cases (if your completions are essentially a non-hierarchical, flat list
39  * of matches) you will only need to overload few virtual functions.
40  *
41  * \section compmodel_flatlist Implementing a CodeCompletionModel for a flat list
42  *
43  * For the simple case of a flat list of completions, you will need to:
44  * - Implement completionInvoked() to actually generate/update the list of completion
45  * matches
46  * - implement itemData() (or QAbstractItemModel::data()) to return the information that
47  * should be displayed for each match.
48  * - use setRowCount() to reflect the number of matches.
49  *
50  * \section compmodel_roles_columns Columns and roles
51  *
52  * \todo document the meaning and usage of the columns and roles used by the
53  * CodeCompletionInterface
54  *
55  * \section compmodel_usage Using the new CodeCompletionModel
56  *
57  * To start using your CodeCompletionModel, refer to CodeCompletionInterface.
58  *
59  * \section compmodel_controller ControllerInterface to get more control
60  *
61  * To have more control over code completion implement
62  * CodeCompletionModelControllerInterface in your CodeCompletionModel.
63  *
64  * \see CodeCompletionInterface, CodeCompletionModelControllerInterface
65  * @author Hamish Rodda <[email protected]>
66  */
67 class KTEXTEDITOR_EXPORT CodeCompletionModel : public QAbstractItemModel
68 {
69  Q_OBJECT
70 
71 public:
72  explicit CodeCompletionModel(QObject *parent);
73  ~CodeCompletionModel() override;
74 
75  enum Columns {
76  Prefix = 0,
77  /// Icon representing the type of completion. We have a separate icon field
78  /// so that names remain aligned where only some completions have icons,
79  /// and so that they can be rearranged by the user.
81  Scope,
82  Name,
83  Arguments,
84  Postfix
85  };
86  static const int ColumnCount = Postfix + 1;
87 
88  /// @see CompletionProperties
90  NoProperty = 0x0,
91  FirstProperty = 0x1,
92 
93  // Access specifiers - no more than 1 per item
94  Public = 0x1,
95  Protected = 0x2,
96  Private = 0x4,
97 
98  // Extra access specifiers - any number per item
99  Static = 0x8,
100  Const = 0x10,
101 
102  // Type - no more than 1 per item (except for Template)
103  Namespace = 0x20,
104  Class = 0x40,
105  Struct = 0x80,
106  Union = 0x100,
107  Function = 0x200,
108  Variable = 0x400,
109  Enum = 0x800,
110  Template = 0x1000,
111  TypeAlias = 0x2000,
112 
113  // Special attributes - any number per item
114  Virtual = 0x4000,
115  Override = 0x8000,
116  Inline = 0x10000,
117  Friend = 0x20000,
118  Signal = 0x40000,
119  Slot = 0x80000,
120 
121  // Scope - no more than 1 per item
122  LocalScope = 0x100000,
123  NamespaceScope = 0x200000,
124  GlobalScope = 0x400000,
125 
126  // Keep this in sync so the code knows when to stop
127  LastProperty = GlobalScope
128  };
129  /// Stores a combination of #CompletionProperty values.
131 
132  /// @see HighlightMethods
133  enum HighlightMethod { NoHighlighting = 0x0, InternalHighlighting = 0x1, CustomHighlighting = 0x2 };
134  /// Stores a combination of #HighlightMethod values.
136 
137  /// Meta information is passed through extra {Qt::ItemDataRole}s.
138  /// This information should be returned when requested on the Name column.
140  /// The model should return a set of CompletionProperties.
141  CompletionRole = Qt::UserRole,
142 
143  /// The model should return an index to the scope
144  /// -1 represents no scope
145  /// \todo how to sort scope?
147 
148  /**
149  * If requested, your model should try to determine whether the
150  * completion in question is a suitable match for the context (ie.
151  * is accessible, exported, + returns the data type required).
152  *
153  * The returned data should ideally be matched against the argument-hint context
154  * set earlier by SetMatchContext.
155  *
156  * Return an integer value that should be positive if the completion is suitable,
157  * and zero if the completion is not suitable. The value should be between 0 an 10, where
158  * 10 means perfect match.
159  *
160  * Return QVariant::Invalid if you are unable to determine this.
161  */
163 
164  /**
165  * Is requested before MatchQuality(..) is requested. The item on which this is requested
166  * is an argument-hint item(@see ArgumentHintDepth). When this role is requested, the item should
167  * be noted, and whenever MatchQuality is requested, it should be computed by matching the item given
168  * with MatchQuality into the context chosen by SetMatchContext.
169  *
170  * Feel free to ignore this, but ideally you should return QVariant::Invalid to make clear that your model does not support this.
171  * */
173 
174  /**
175  * Define which highlighting method will be used:
176  * - QVariant::Invalid - allows the editor to choose (usually internal highlighting)
177  * - QVariant::Integer - highlight as specified by HighlightMethods.
178  */
180 
181  /**
182  * Allows an item to provide custom highlighting. Return a
183  * QList<QVariant> in the following format:
184  * - int startColumn (where 0 = start of the completion entry)
185  * - int endColumn (note: not length)
186  * - QTextFormat attribute (note: attribute may be a KTextEditor::Attribute, as it is a child class)
187  * If the attribute is invalid, and the item is an argument-hint, the text will be drawn with
188  * a background-color depending on match-quality, or yellow.
189  * You can use that to mark the actual arguments that are matched in an argument-hint.
190  *
191  * Repeat this triplet as many times as required, however each column must be >= the previous,
192  * and startColumn != endColumn.
193  */
195 
196  /**
197  * Returns the inheritance depth of the completion. For example, a completion
198  * which comes from the base class would have depth 0, one from a parent class
199  * would have depth 1, one from that class' parent 2, etc. you can use this to
200  * symbolize the general distance of a completion-item from a user. It will be used
201  * for sorting.
202  */
204 
205  /**
206  * This allows items in the completion-list to be expandable. If a model returns an QVariant bool value
207  * that evaluates to true, the completion-widget will draw a handle to expand the item, and will also make
208  * that action accessible through keyboard.
209  */
211  /**
212  * After a model returned true for a row on IsExpandable, the row may be expanded by the user.
213  * When this happens, ExpandingWidget is requested.
214  *
215  * The model may return two types of values:
216  * QWidget*:
217  * If the model returns a QVariant of type QWidget*, the code-completion takes over the given widget
218  * and embeds it into the completion-list under the completion-item. The widget will be automatically deleted at some point.
219  * The completion-widget will use the height of the widget as a hint for its preferred size, but it will
220  * resize the widget at will.
221  * QString:
222  * If the mode returns a QVariant of type QString, it will create a small html-widget showing the given html-code,
223  * and embed it into the completion-list under the completion-item.
224  *
225  * @warning
226  * @code
227  * QWidget* widget;
228  * return QVariant(widget);
229  * @endcode
230  * Will not work correctly!
231  * Use the following instead.:
232  * @code
233  * QVariant v;
234  * v.setValue<QWidget*>(widget);
235  * return v;
236  * @endcode
237  *
238  * */
240  /**
241  * Whenever an item is selected, this will be requested from the underlying model.
242  * It may be used as a simple notification that the item was selected.
243  *
244  * Above that, the model may return a QString, which then should then contain html-code. A html-widget
245  * will then be displayed as a one- or two-liner under the currently selected item(it will be partially expanded)
246  * */
248 
249  /**Is this completion-item an argument-hint?
250  * The model should return an integral positive number if the item is an argument-hint, and QVariant() or 0 if it is not one.
251  *
252  * The returned depth-integer is important for sorting and matching.
253  * Example:
254  * "otherFunction(function1(function2("
255  * all functions named function2 should have ArgumentHintDepth 1, all functions found for function1 should have ArgumentHintDepth 2,
256  * and all functions named otherFunction should have ArgumentHintDepth 3
257  *
258  * Later, a completed item may then be matched with the first argument of function2, the return-type of function2 with the first
259  * argument-type of function1, and the return-type of function1 with the argument-type of otherFunction.
260  *
261  * If the model returns a positive value on this role for a row, the content will be treated specially:
262  * - It will be shown in a separate argument-hint list
263  * - It will be sorted by Argument-hint depth
264  * - Match-qualities will be illustrated by differently highlighting the matched argument if possible
265  * The argument-hint list strings will be built from all source-model, with a little special behavior:
266  * Prefix - Should be all text of the function-signature up to left of the matched argument of the function
267  * Name - Should be the type and name of the function's matched argument. This part will be highlighted differently depending on the match-quality
268  * Suffix - Should be all the text of the function-signature behind the matched argument
269  *
270  * Example: You are matching a function with signature "void test(int param1, int param2)", and you are matching the first argument.
271  * The model should then return:
272  * Prefix: "void test("
273  * Name: "int param1"
274  * Suffix: ", int param2)"
275  *
276  * If you don't use the highlighting, matching, etc. you can also return the columns in the usual way.
277  * */
279 
280  /**
281  * This will be requested for each item to ask whether it should be included in computing a best-matches list.
282  * If you return a valid positive integer n here, the n best matches will be listed at top of the completion-list separately.
283  *
284  * This is expensive because all items of the whole completion-list will be tested for their matching-quality, with each of the level 1
285  * argument-hints.
286  *
287  * For that reason the end-user should be able to disable this feature.
288  */
290 
291  /**
292  * The following three enumeration-values are only used on expanded completion-list items that contain an expanding-widget(@see ExpandingWidget)
293  *
294  * You can use them to allow the user to interact with the widget by keyboard.
295  *
296  * AccessibilityNext will be requested on an item if it is expanded, contains an expanding-widget, and the user triggers a special navigation
297  * short-cut to go to navigate to the next position within the expanding-widget(if applicable).
298  *
299  * Return QVariant(true) if the input was used.
300  * */
302  /**
303  * AccessibilityPrevious will be requested on an item if it is expanded, contains an expanding-widget, and the user triggers a special navigation
304  * short-cut to go to navigate to the previous position within the expanding-widget(if applicable).
305  *
306  * Return QVariant(true) if the input was used.
307  * */
309  /**
310  * AccessibilityAccept will be requested on an item if it is expanded, contains an expanding-widget, and the user triggers a special
311  * shortcut to trigger the action associated with the position within the expanding-widget the user has navigated to using AccessibilityNext and
312  * AccessibilityPrevious.
313  *
314  * This should return QVariant(true) if an action was triggered, else QVariant(false) or QVariant().
315  * */
317 
318  /**
319  * Using this Role, it is possible to greatly optimize the time needed to process very long completion-lists.
320  *
321  * In the completion-list, the items are usually ordered by some properties like argument-hint depth,
322  * inheritance-depth and attributes. Kate usually has to query the completion-models for these values
323  * for each item in the completion-list in order to extract the argument-hints and correctly sort the
324  * completion-list. However, with a very long completion-list, only a very small fraction of the items is actually
325  * visible.
326  *
327  * 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
328  * item and query data in order to initially show the completion-list.
329  *
330  * This is how it works:
331  * - You create a tree-structure for your items
332  * - Every inner node of the tree defines one attribute value that all sub-nodes have in common.
333  * - When the inner node is queried for GroupRole, it should return the "ExtraItemDataRoles" that all sub-nodes have in common
334  * - When the inner node is then queried for that exact role, it should return that value.
335  * - No other queries will be done to inner nodes.
336  * - Every leaf node stands for an actual item in the completion list.
337  *
338  * The recommended grouping order is: Argument-hint depth, inheritance depth, attributes.
339  *
340  * This role can also be used to define completely custom groups, bypassing the editors builtin grouping:
341  * - Return Qt::DisplayRole when GroupRole is requested
342  * - Return the label text of the group when Qt::DisplayRole
343  * - Optional: Return an integer sorting-value when InheritanceDepth is requested. This number will
344  * be used to determine the order of the groups. The order of the builtin groups is:
345  * 1 = Best Matches, 100 = Local Scope, 200 = Public, 300 = Protected, 400 = Private, 500 = Namespace, 600 = Global
346  * You can pick any arbitrary number to position your group relative to these builtin groups.
347  * */
349 
350  /**
351  * Return a nonzero value here to enforce sorting the item at the end of the list.
352  */
354 
355  LastExtraItemDataRole
356  };
357 
358  void setRowCount(int rowCount);
359 
360  enum InvocationType { AutomaticInvocation, UserInvocation, ManualInvocation };
361 
362  /**
363  * This function is responsible to generating / updating the list of current
364  * completions. The default implementation does nothing.
365  *
366  * When implementing this function, remember to call setRowCount() (or implement
367  * rowCount()), and to generate the appropriate change notifications (for instance
368  * by calling QAbstractItemModel::reset()).
369  * @param view The view to generate completions for
370  * @param range The range of text to generate completions for
371  * @param invocationType How the code completion was triggered
372  * */
373  virtual void completionInvoked(KTextEditor::View *view, const KTextEditor::Range &range, InvocationType invocationType);
374 
375  /**
376  * This function is responsible for inserting a selected completion into the
377  * view. The default implementation replaces the text that the completions
378  * were based on with the Qt::DisplayRole of the Name column of the given match.
379  *
380  * @param view the view to insert the completion into
381  * @param word the Range that the completions are based on (what the user entered
382  * so far)
383  * @param index identifies the completion match to insert
384  * */
385  virtual void executeCompletionItem(KTextEditor::View *view, const Range &word, const QModelIndex &index) const;
386 
387  // Reimplementations
388  /**
389  * Reimplemented from QAbstractItemModel::columnCount(). The default implementation
390  * returns ColumnCount for all indices.
391  * */
392  int columnCount(const QModelIndex &parent = QModelIndex()) const override;
393  /**
394  * Reimplemented from QAbstractItemModel::index(). The default implementation
395  * returns a standard QModelIndex as long as the row and column are valid.
396  * */
397  QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
398  /**
399  * Reimplemented from QAbstractItemModel::itemData(). The default implementation
400  * returns a map with the QAbstractItemModel::data() for all roles that are used
401  * by the CodeCompletionInterface. You will need to reimplement either this
402  * function or QAbstractItemModel::data() in your CodeCompletionModel.
403  * */
404  QMap<int, QVariant> itemData(const QModelIndex &index) const override;
405  /**
406  * Reimplemented from QAbstractItemModel::parent(). The default implementation
407  * returns an invalid QModelIndex for all items. This is appropriate for
408  * non-hierarchical / flat lists of completions.
409  * */
410  QModelIndex parent(const QModelIndex &index) const override;
411  /**
412  * Reimplemented from QAbstractItemModel::rowCount(). The default implementation
413  * returns the value set by setRowCount() for invalid (toplevel) indices, and 0
414  * for all other indices. This is appropriate for non-hierarchical / flat lists
415  * of completions
416  * */
417  int rowCount(const QModelIndex &parent = QModelIndex()) const override;
418 
419  /**
420  * This function returns true if the model needs grouping, otherwise false.
421  * The default is false if not changed via setHasGroups().
422  */
423  bool hasGroups() const;
424 
425 Q_SIGNALS:
426 
427  /**
428  * Emit this if the code-completion for this model was invoked, some time is needed in order to get the data,
429  * and the model is reset once the data is available.
430  *
431  * This only has an effect if emitted from within completionInvoked(..).
432  *
433  * This prevents the code-completion list from showing until this model is reset,
434  * so there is no annoying flashing in the user-interface resulting from other models
435  * supplying their data earlier.
436  *
437  * @note The implementation may choose to show the completion-list anyway after some timeout
438  *
439  * @warning If you emit this, you _must_ also reset the model at some point,
440  * else the code-completion will be completely broken to the user.
441  * Consider that there may always be additional completion-models apart from yours.
442  *
443  * @since 4.3
444  */
445  void waitForReset();
446 
447  /**
448  * Internal
449  */
450  void hasGroupsChanged(KTextEditor::CodeCompletionModel *model, bool hasGroups);
451 
452 protected:
453  void setHasGroups(bool hasGroups);
454 
455 private:
456  class CodeCompletionModelPrivate *const d;
457 };
458 
459 Q_DECLARE_OPERATORS_FOR_FLAGS(CodeCompletionModel::CompletionProperties)
460 Q_DECLARE_OPERATORS_FOR_FLAGS(CodeCompletionModel::HighlightMethods)
461 
462 }
463 
464 #endif // KTEXTEDITOR_CODECOMPLETIONMODEL_H
@ ExpandingWidget
After a model returned true for a row on IsExpandable, the row may be expanded by the user.
An item model for providing code completion, and meta information for enhanced presentation.
@ AccessibilityNext
The following three enumeration-values are only used on expanded completion-list items that contain a...
UserRole
@ InheritanceDepth
Returns the inheritance depth of the completion.
@ SetMatchContext
Is requested before MatchQuality(..) is requested.
@ BestMatchesCount
This will be requested for each item to ask whether it should be included in computing a best-matches...
QFlags< CompletionProperty > CompletionProperties
Stores a combination of CompletionProperty values.
@ ItemSelected
Whenever an item is selected, this will be requested from the underlying model.
An object representing a section of text, from one Cursor to another.
@ Icon
Icon representing the type of completion.
@ ArgumentHintDepth
Is this completion-item an argument-hint? The model should return an integral positive number if the ...
QFlags< HighlightMethod > HighlightMethods
Stores a combination of HighlightMethod values.
@ IsExpandable
This allows items in the completion-list to be expandable.
@ CustomHighlight
Allows an item to provide custom highlighting.
@ AccessibilityAccept
AccessibilityAccept will be requested on an item if it is expanded, contains an expanding-widget,...
A text widget with KXMLGUIClient that represents a Document.
Definition: view.h:146
Variable for variable expansion.
Definition: variable.h:34
@ ScopeIndex
The model should return an index to the scope -1 represents no scope.
The KTextEditor namespace contains all the public API that is required to use the KTextEditor compone...
Definition: katetextblock.h:22
@ HighlightingMethod
Define which highlighting method will be used:
ExtraItemDataRoles
Meta information is passed through extra {Qt::ItemDataRole}s.
@ AccessibilityPrevious
AccessibilityPrevious will be requested on an item if it is expanded, contains an expanding-widget,...
@ GroupRole
Using this Role, it is possible to greatly optimize the time needed to process very long completion-l...
@ MatchQuality
If requested, your model should try to determine whether the completion in question is a suitable mat...
@ UnimportantItemRole
Return a nonzero value here to enforce sorting the item at the end of the list.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu May 26 2022 03:48:51 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.