1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
3  * http://www.gnu.org/licenses/lgpl-3.0.html
4  */
5 
6 #ifndef CCMANAGER_H
7 #define CCMANAGER_H
8 
9 #include "manager.h"
10 
11 #ifndef CB_PRECOMP
12     #include <wx/timer.h>
13     #include "cbplugin.h"
14 #endif
15 
16 class UnfocusablePopupWindow;
17 class wxHtmlLinkEvent;
18 class wxHtmlWindow;
19 class wxListEvent;
20 class wxListView;
21 class wxScintillaEvent;
22 
23 /** Code Completion Plugin Manager
24  *
25  * This class manages all kinds of code completion plugins. For example, the native C/C++ code
26  * completion plugin, the Fortran code completion plugin and Python code completion plugin.
27  * The ccmanager asks some informations from the managed ccplugins. The major value passes from the
28  * ccmanager and the ccplugins are CCCallTip and CCToken.
29  *
30  * The CCToken is needed when ccmanager needs to fill a code suggestion list, it is the ccplugin's
31  * duty to supply a collection of CCTokens.
32  *
33  * When user is entering some function call statement, CCCallTip is used to show the function
34  * information, and especially it can highlight the current function argument.
35  *
36  * Another kind of tip is the tooltip, this is the tip window shown when mouse hover on a specified
37  * token(such as variable token), ccmanager queries this information by asking CCToken information
38  * from ccplugin.
39  *
40  * Note: Under Windows, scroll events are always directed to the window in focus, making it
41  * difficult to scroll the autocomplete list and the doxygen popup with the mouse.  So, under
42  * Windows we catch scroll requests to the cbStyledTextCtrl, and run them through
43  * CCManager::OnPopupScroll(). This filters the event, and if the mouse is over the autocomplete
44  * list or the doxygen popup, the scroll event is instead sent there (and skipped for the editor
45  * window).
46  */
47 class DLLIMPORT CCManager : public Mgr<CCManager>, wxEvtHandler
48 {
49     public:
50         friend class Mgr<CCManager>;
51         friend class Manager; // give Manager access to our private members
52 
53         /** Get the ccPlugin instant for the cbEditor.
54          *
55          * If the editor opened a c/c++ file, then it returns the native c/c++ ccPlugin.
56          * @param ed input editor, uses active editor if one is not passed; has (minimal) cache optimization
57          */
58         cbCodeCompletionPlugin* GetProviderFor(cbEditor* ed = nullptr);
59 
60         /** Register a new set of characters that, when typed, invoke calltip requests.
61          *
62          * Use this if the default set is not appropriate.
63          */
64         void RegisterCallTipChars(const wxString& chars, cbCodeCompletionPlugin* registrant);
65 
66 
67         /** Register a new set of characters that, when typed, auto-launch codecomplete requests.
68          *
69          * Use this if the default set is not appropriate.
70          */
71         void RegisterAutoLaunchChars(const wxString& chars, cbCodeCompletionPlugin* registrant);
72 
73         /** Let CCManager know that new results are available from cbCodeCompletionPlugin::GetDocumentation(). */
74         void NotifyDocumentation();
75         /** Let CCManager know that a change (e.g. active lexer is switched) may invalidate cached active ccPlugin. */
76         void NotifyPluginStatus();
77 
78         /** If for some reason you *need* to use wxScintilla::AutoCompShow(), call this instead so CCManager does not step on you. */
79         void InjectAutoCompShow(int lenEntered, const wxString& itemList);
80 
81         /** Used by cbStyledTextCtrl to process ArrowUp and ArrowDown key press.
82          *
83          * This is not intended to be called by ccPlugins.
84          */
85         bool ProcessArrow(int key);
86 
87         /** Called after env settings have changed, so the changes can be applied. */
88         void UpdateEnvSettings();
89     private:
90         CCManager();
91         ~CCManager() override;
92 
93         /** Event handler to list the suggestion, when a user press Ctrl-space (by default). */
94         void OnCompleteCode(CodeBlocksEvent& event);
95 
96         /** Event handler to avoid tooltips getting stuck active. */
97         void OnDeactivateApp(CodeBlocksEvent& event);
98         /** Event handler to avoid tooltips getting stuck active. */
99         void OnDeactivateEd(CodeBlocksEvent& event);
100         /** Event handler to avoid tooltips getting stuck active. */
101         void OnEditorOpen(CodeBlocksEvent& event);
102         /** Event handler to avoid tooltips getting stuck active. */
103         void OnEditorClose(CodeBlocksEvent& event);
104 
105         /** Hook to the editor.
106          *
107          * This is used so that we know some specific chars were entered, then we can decide
108          * whether it time to show a calltip or suggestion list.
109          */
110         void OnEditorHook(cbEditor* ed, wxScintillaEvent& event);
111 
112         /** Mouse hover event. */
113         void OnEditorTooltip(CodeBlocksEvent& event);
114 
115         /** Event handler to show the call tip, when user press Ctrl-Shift-Space. */
116         void OnShowCallTip(CodeBlocksEvent& event);
117 
118         /** Event handler to show documentation, when user changes autocomplete selection. */
119         void OnAutocompleteSelect(wxListEvent& event);
120 
121         /** Event handler to tear down documentation, when autocomplete closes. */
122         void OnAutocompleteHide(wxShowEvent& event);
123 
124         /** Defer showing the calltip to avoid a crash issue.
125          *
126          * Launching this event directly seems to be a candidate for race condition
127          * and crash in OnShowCallTip() so we attempt to serialize it.
128          */
129         void OnDeferredCallTipShow(wxCommandEvent& event);
130 
131         /** Defer canceling the calltip to avoid a crash issue. @see CCManager::OnDeferredCallTipShow */
132         void OnDeferredCallTipCancel(wxCommandEvent& event);
133 
134 #ifdef __WXMSW__
135         /** Intercept cbStyledTextCtrl scroll events and forward to autocomplete/documentation popups. */
136         void OnPopupScroll(wxMouseEvent& event);
137 #endif // __WXMSW__
138 
139         /** A link is clicked in the document window. */
140         void OnHtmlLink(wxHtmlLinkEvent& event);
141 
142         /** Grouped event handler for several timers. */
143         void OnTimer(wxTimerEvent& event);
144 
145         /** Handle the CC related menu click. */
146         void OnMenuSelect(wxCommandEvent& event);
147 
148         /** CC launched in the same state as last run, display via cached data. */
149         void DoBufferedCC(cbStyledTextCtrl* stc);
150 
151         /** Hide the documentation popup. */
152         void DoHidePopup();
153 
154         /** Show the documentation popup. */
155         void DoShowDocumentation(cbEditor* ed);
156 
157         /** Update which tip to show next and where to show it. */
158         void DoUpdateCallTip(cbEditor* ed);
159 
160         /** User click the next or previous small button of the tip window. */
161         enum Direction { Previous, Next };
162 
163         /**Switch the tip window to the next item. */
164         void AdvanceTip(Direction direction);
165 
166         /** Format tips by breaking long lines at (hopefully) logical places. */
167         void DoShowTips(const wxStringVec& tips, cbStyledTextCtrl* stc, int pos, int argsPos, int hlStart, int hlEnd);
168 
169         /** Code completion as just insert some text in the editor, ask the smart indent plugin to adjust the indent. */
170         void CallSmartIndentCCDone(cbEditor* ed);
171 
172         typedef std::map< cbCodeCompletionPlugin*, std::set<wxChar> > CCPluginCharMap;
173         CCPluginCharMap m_CallTipChars;    //!< Chars each plugin is interested in for calltip state.
174         CCPluginCharMap m_AutoLaunchChars; //!< Chars each plugin is interested in for autocomplete.
175         int m_EditorHookID;
176         int m_AutocompPosition;  //!< Location of caret when autocomplete timer starts, if caret is still there, launch autocomplete.
177         int m_CallTipActive;     //!< Is CCManager currently displaying a calltip, and if so, where.
178         int m_LastAutocompIndex; //!< Index of currently selected entry in autocomplete popup.
179         int m_LastTipPos;        //!< Last location a tool/call tip was displayed.
180         int m_WindowBound;       //!< Right-most boundary the documentation popup is allowed to stretch to.
181         bool m_OwnsAutocomp;     //!< Do we control the current autocomplete popup?
182         typedef std::vector<cbCodeCompletionPlugin::CCCallTip> CallTipVec;
183         CallTipVec m_CallTips;   //!< Cached calltips
184         CallTipVec::const_iterator m_CurCallTip;   //!< Remember current choice.
185         std::map<int, size_t> m_CallTipChoiceDict; //!< Remember past choices.
186         std::map<int, size_t> m_CallTipFuzzyChoiceDict; //!< Remember past choices based on prefix.
187         wxTimer m_CallTipTimer;
188         wxTimer m_AutoLaunchTimer;
189         wxTimer m_AutocompSelectTimer;
190         wxSize m_DocSize; //!< Size of the documentation popup.
191         wxPoint m_DocPos; //!< Location of the documentation popup.
192 
193 #ifdef __WXMSW__
194         /** a handle to the autocomplete list window created by (wx)scintilla, needed under Windows
195          * to determine its dimensions (so the scroll event can be sent to it, if relevant)
196          */
197         wxListView* m_pAutocompPopup;
198 #endif // __WXMSW__
199 
200         cbEditor* m_pLastEditor; //!< Last editor operated on.
201         cbCodeCompletionPlugin* m_pLastCCPlugin; //!< The plugin handling m_pLastEditor.
202 
203         /** Container for documentation popup.
204          * the window for the doxygen popup, with properties so it is always on top,
205          * but cannot be focused.
206          */
207         UnfocusablePopupWindow* m_pPopup;
208 
209         /** Documentation popup.
210          * it is the rendered doxygen documentation to display in the popup
211          */
212         wxHtmlWindow* m_pHtml;
213 
214         struct LastACLaunchState
215         {
initLastACLaunchState216             void init(int caret, int token, int zoom)
217             {
218                 caretStart = caret;
219                 tokenStart = token;
220                 editorZoom = zoom;
221             }
222 
223             int caretStart;
224             int tokenStart;
225             int editorZoom;
226         };
227 
228         LastACLaunchState m_LastACLaunchState;
229 
230         /** Cached autocomplete list.
231          * It is the data CCManager uses to populate the (wx)scintilla autocomplete list window
232          */
233         std::vector<cbCodeCompletionPlugin::CCToken> m_AutocompTokens;
234 };
235 
236 #endif // CCMANAGER_H
237