1 // This module defines interface to the QsciAPIs class.
2 //
3 // Copyright (c) 2021 Riverbank Computing Limited <info@riverbankcomputing.com>
4 //
5 // This file is part of QScintilla.
6 //
7 // This file may be used under the terms of the GNU General Public License
8 // version 3.0 as published by the Free Software Foundation and appearing in
9 // the file LICENSE included in the packaging of this file.  Please review the
10 // following information to ensure the GNU General Public License version 3.0
11 // requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 //
13 // If you do not wish to use this file under the terms of the GPL version 3.0
14 // then you may purchase a commercial license.  For more information contact
15 // info@riverbankcomputing.com.
16 //
17 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 
20 
21 #ifndef QSCIAPIS_H
22 #define QSCIAPIS_H
23 
24 #include <QList>
25 #include <QObject>
26 #include <QPair>
27 #include <QStringList>
28 
29 #include <Qsci/qsciabstractapis.h>
30 #include <Qsci/qsciglobal.h>
31 #include <Qsci/qsciscintilla.h>
32 
33 
34 class QsciAPIsPrepared;
35 class QsciAPIsWorker;
36 class QsciLexer;
37 
38 
39 //! \brief The QsciAPIs class provies an implementation of the textual API
40 //! information used in call tips and for auto-completion.
41 //!
42 //! Raw API information is read from one or more files.  Each API function is
43 //! described by a single line of text comprising the function's name, followed
44 //! by the function's optional comma separated parameters enclosed in
45 //! parenthesis, and finally followed by optional explanatory text.
46 //!
47 //! A function name may be followed by a `?' and a number.  The number is used
48 //! by auto-completion to display a registered QPixmap with the function name.
49 //!
50 //! All function names are used by auto-completion, but only those that include
51 //! function parameters are used in call tips.
52 //!
53 //! QScintilla only deals with prepared API information and not the raw
54 //! information described above.  This is done so that large APIs can be
55 //! handled while still being responsive to user input.  The conversion of raw
56 //! information to prepared information is time consuming (think tens of
57 //! seconds) and implemented in a separate thread.  Prepared information can
58 //! be quickly saved to and loaded from files.  Such files are portable between
59 //! different architectures.
60 //!
61 //! QScintilla based applications that want to support large APIs would
62 //! normally provide the user with the ability to specify a set of, possibly
63 //! project specific, raw API files and convert them to prepared files that are
64 //! loaded quickly when the application is invoked.
65 class QSCINTILLA_EXPORT QsciAPIs : public QsciAbstractAPIs
66 {
67     Q_OBJECT
68 
69 public:
70     //! Constructs a QsciAPIs instance attached to lexer \a lexer.  \a lexer
71     //! becomes the instance's parent object although the instance can also be
72     //! subsequently attached to other lexers.
73     QsciAPIs(QsciLexer *lexer);
74 
75     //! Destroy the QsciAPIs instance.
76     virtual ~QsciAPIs();
77 
78     //! Add the single raw API entry \a entry to the current set.
79     //!
80     //! \sa clear(), load(), remove()
81     void add(const QString &entry);
82 
83     //! Deletes all raw API information.
84     //!
85     //! \sa add(), load(), remove()
86     void clear();
87 
88     //! Load the API information from the file named \a filename, adding it to
89     //! the current set.  Returns true if successful, otherwise false.
90     bool load(const QString &filename);
91 
92     //! Remove the single raw API entry \a entry from the current set.
93     //!
94     //! \sa add(), clear(), load()
95     void remove(const QString &entry);
96 
97     //! Convert the current raw API information to prepared API information.
98     //! This is implemented by a separate thread.
99     //!
100     //! \sa cancelPreparation()
101     void prepare();
102 
103     //! Cancel the conversion of the current raw API information to prepared
104     //! API information.
105     //!
106     //! \sa prepare()
107     void cancelPreparation();
108 
109     //! Return the default name of the prepared API information file.  It is
110     //! based on the name of the associated lexer and in the directory defined
111     //! by the QSCIDIR environment variable.  If the environment variable isn't
112     //! set then $HOME/.qsci is used.
113     QString defaultPreparedName() const;
114 
115     //! Check to see is a prepared API information file named \a filename
116     //! exists.  If \a filename is empty then the value returned by
117     //! defaultPreparedName() is used.  Returns true if successful, otherwise
118     //! false.
119     //!
120     //! \sa defaultPreparedName()
121     bool isPrepared(const QString &filename = QString()) const;
122 
123     //! Load the prepared API information from the file named \a filename.  If
124     //! \a filename is empty then a name is constructed based on the name of
125     //! the associated lexer and saved in the directory defined by the QSCIDIR
126     //! environment variable.  If the environment variable isn't set then
127     //! $HOME/.qsci is used.  Returns true if successful, otherwise false.
128     bool loadPrepared(const QString &filename = QString());
129 
130     //! Save the prepared API information to the file named \a filename.  If
131     //! \a filename is empty then a name is constructed based on the name of
132     //! the associated lexer and saved in the directory defined by the QSCIDIR
133     //! environment variable.  If the environment variable isn't set then
134     //! $HOME/.qsci is used.  Returns true if successful, otherwise false.
135     bool savePrepared(const QString &filename = QString()) const;
136 
137     //! \reimp
138     virtual void updateAutoCompletionList(const QStringList &context,
139             QStringList &list);
140 
141     //! \reimp
142     virtual void autoCompletionSelected(const QString &sel);
143 
144     //! \reimp
145     virtual QStringList callTips(const QStringList &context, int commas,
146             QsciScintilla::CallTipsStyle style, QList<int> &shifts);
147 
148     //! \internal Reimplemented to receive termination events from the worker
149     //! thread.
150     virtual bool event(QEvent *e);
151 
152     //! Return a list of the installed raw API file names for the associated
153     //! lexer.
154     QStringList installedAPIFiles() const;
155 
156 signals:
157     //! This signal is emitted when the conversion of raw API information to
158     //! prepared API information has been cancelled.
159     //!
160     //! \sa apiPreparationFinished(), apiPreparationStarted()
161     void apiPreparationCancelled();
162 
163     //! This signal is emitted when the conversion of raw API information to
164     //! prepared API information starts and can be used to give some visual
165     //! feedback to the user.
166     //!
167     //! \sa apiPreparationCancelled(), apiPreparationFinished()
168     void apiPreparationStarted();
169 
170     //! This signal is emitted when the conversion of raw API information to
171     //! prepared API information has finished.
172     //!
173     //! \sa apiPreparationCancelled(), apiPreparationStarted()
174     void apiPreparationFinished();
175 
176 private:
177     friend class QsciAPIsPrepared;
178     friend class QsciAPIsWorker;
179 
180     // This indexes a word in a set of raw APIs.  The first part indexes the
181     // entry in the set, the second part indexes the word within the entry.
182     typedef QPair<quint32, quint32> WordIndex;
183 
184     // This is a list of word indexes.
185     typedef QList<WordIndex> WordIndexList;
186 
187     QsciAPIsWorker *worker;
188     QStringList old_context;
189     QStringList::const_iterator origin;
190     int origin_len;
191     QString unambiguous_context;
192     QStringList apis;
193     QsciAPIsPrepared *prep;
194 
195     static bool enoughCommas(const QString &s, int commas);
196 
197     QStringList positionOrigin(const QStringList &context, QString &path);
198     bool originStartsWith(const QString &path, const QString &wsep);
199     const WordIndexList *wordIndexOf(const QString &word) const;
200     void lastCompleteWord(const QString &word, QStringList &with_context,
201             bool &unambig);
202     void lastPartialWord(const QString &word, QStringList &with_context,
203             bool &unambig);
204     void addAPIEntries(const WordIndexList &wl, bool complete,
205             QStringList &with_context, bool &unambig);
206     QString prepName(const QString &filename, bool mkpath = false) const;
207     void deleteWorker();
208 
209     QsciAPIs(const QsciAPIs &);
210     QsciAPIs &operator=(const QsciAPIs &);
211 };
212 
213 #endif
214