1/*
2 * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17#ifndef EDITOR_H
18#define EDITOR_H
19
20#include <QObject>
21#include <utils.h>
22#include <QTabWidget>
23#include "qsynedit/SynEdit.h"
24#include "colorscheme.h"
25#include "common.h"
26#include "parser/cppparser.h"
27#include "widgets/codecompletionpopup.h"
28#include "widgets/headercompletionpopup.h"
29
30#define USER_CODE_IN_INSERT_POS "%INSERT%"
31#define USER_CODE_IN_REPL_POS_BEGIN "%REPL_BEGIN%"
32#define USER_CODE_IN_REPL_POS_END "%REPL_END%"
33
34struct TabStop {
35 int x;
36 int endX;
37 int y;
38};
39
40using PTabStop = std::shared_ptr<TabStop>;
41
42class SaveException: public std::exception {
43
44public:
45 explicit SaveException(const QString& reason);
46 explicit SaveException(const QString&& reason);
47 // exception interface
48 const QString& reason() const noexcept;
49public:
50 const char *what() const noexcept override;
51private:
52 QString mReason;
53 QByteArray mReasonBuffer;
54};
55
56class Editor : public QSynedit::SynEdit
57{
58 Q_OBJECT
59public:
60 enum class LastSymbolType {
61 Identifier,
62 ScopeResolutionOperator, //'::'
63 ObjectMemberOperator, //'.'
64 PointerMemberOperator, //'->'
65 PointerToMemberOfObjectOperator, //'.*'
66 PointerToMemberOfPointerOperator, //'->*'
67 MatchingBracket,
68 BracketMatched,
69 MatchingParenthesis,
70 ParenthesisMatched,
71 TildeSign, // '~'
72 AsteriskSign, // '*'
73 AmpersandSign, // '&'
74 MatchingAngleQuotation,
75 AngleQuotationMatched,
76 None
77 };
78
79 enum MarginNumber {
80 LineNumberMargin = 0,
81 MarkerMargin = 1,
82 FoldMargin = 2,
83 };
84
85 enum MarkerNumber {
86 BreakpointMarker,
87 ErrorMarker,
88 WarningMarker
89 };
90
91 enum class QuoteStatus {
92 NotQuote,
93 SingleQuote,
94 SingleQuoteEscape,
95 DoubleQuote,
96 DoubleQuoteEscape,
97 RawString,
98 RawStringNoEscape
99 };
100
101 enum class WordPurpose {
102 wpCompletion, // walk backwards over words, array, functions, parents, no forward movement
103 wpEvaluation, // walk backwards over words, array, functions, parents, forwards over words, array
104 wpHeaderCompletion, // walk backwards over path
105 wpHeaderCompletionStart, // walk backwards over path, including start '<' or '"'
106 wpDirective, // preprocessor
107 wpJavadoc, //javadoc
108 wpInformation // walk backwards over words, array, functions, parents, forwards over words
109 };
110
111 enum class TipType {
112 Preprocessor, // cursor hovers above preprocessor line
113 Identifier, // cursor hovers above identifier
114 Selection, // cursor hovers above selection
115 None, // mouseover not allowed
116 Error //Cursor hovers above error line/item;
117 };
118
119 struct SyntaxIssue {
120 int col;
121 int endCol;
122 int startChar;
123 int endChar;
124 CompileIssueType issueType;
125 QString token;
126 QString hint;
127 };
128
129 using PSyntaxIssue = std::shared_ptr<SyntaxIssue>;
130 using SyntaxIssueList = QVector<PSyntaxIssue>;
131 using PSyntaxIssueList = std::shared_ptr<SyntaxIssueList>;
132
133 explicit Editor(QWidget *parent);
134
135 explicit Editor(QWidget *parent, const QString& filename,
136 const QByteArray& encoding,
137 bool inProject, bool isNew,QTabWidget* parentPageControl);
138
139 ~Editor();
140
141 //tell the compiler to prohibit copy/moving editor objects ( we should only use pointers to the editor object)
142 Editor(const Editor&) = delete;
143 Editor(const Editor&&) = delete;
144 Editor& operator=(const Editor&) = delete;
145 Editor& operator=(const Editor&&) = delete;
146
147 const QByteArray& encodingOption() const noexcept;
148 void setEncodingOption(const QByteArray& encoding) noexcept;
149 const QByteArray& fileEncoding() const noexcept;
150 void convertToEncoding(const QByteArray& encoding);
151 const QString& filename() const noexcept;
152
153 bool inProject() const noexcept;
154 bool isNew() const noexcept;
155
156 void loadFile(QString filename = "");
157 void saveFile(QString filename);
158 bool save(bool force=false, bool reparse=true);
159 bool saveAs(const QString& name="", bool fromProject = false);
160 void activate();
161
162 QTabWidget* pageControl() noexcept;
163 void setPageControl(QTabWidget* newPageControl);
164
165 void updateCaption(const QString& newCaption=QString());
166 void applySettings();
167 void applyColorScheme(const QString& schemeName);
168
169 void copyToClipboard() override;
170 void cutToClipboard() override;
171 void copyAsHTML();
172
173 void setCaretPosition(int line,int aChar);
174 void setCaretPositionAndActivate(int line,int aChar);
175
176 void addSyntaxIssues(int line, int startChar, int endChar, CompileIssueType errorType, const QString& hint);
177 void clearSyntaxIssues();
178 void gotoNextSyntaxIssue();
179 void gotoPrevSyntaxIssue();
180 bool hasPrevSyntaxIssue() const;
181 bool hasNextSyntaxIssue() const;
182 PSyntaxIssueList getSyntaxIssuesAtLine(int line);
183 PSyntaxIssue getSyntaxIssueAtPosition(const QSynedit::BufferCoord& pos);
184 int gutterClickedLine() const;
185 void toggleBreakpoint(int line);
186 void clearBreakpoints();
187 bool hasBreakpoint(int line);
188 void addBookmark(int line,const QString& description);
189 void removeBookmark(int line);
190 bool hasBookmark(int line);
191 void clearBookmarks();
192 void removeBreakpointFocus();
193 void modifyBreakpointProperty(int line);
194 void setActiveBreakpointFocus(int Line, bool setFocus=true);
195 QString getPreviousWordAtPositionForSuggestion(const QSynedit::BufferCoord& p);
196 void reformat();
197 void checkSyntaxInBack();
198 void gotoDeclaration(const QSynedit::BufferCoord& pos);
199 void gotoDefinition(const QSynedit::BufferCoord& pos);
200 void reparse();
201 void reparseTodo();
202 void insertString(const QString& value, bool moveCursor);
203 void insertCodeSnippet(const QString& code);
204 void print();
205 void exportAsRTF(const QString& rtfFilename);
206 void exportAsHTML(const QString& htmlFilename);
207 void resetBreakpoints();
208 bool notParsed();
209 void insertLine();
210 void deleteWord();
211 void deleteToWordStart();
212 void deleteToWordEnd();
213 void deleteLine();
214 void duplicateLine();
215 void deleteToEOL();
216 void deleteToBOL();
217
218 QStringList getOwnerExpressionAndMemberAtPositionForCompletion(
219 const QSynedit::BufferCoord& pos,
220 QString& memberOperator,
221 QStringList& memberExpression);
222 QString getWordForCompletionSearch(const QSynedit::BufferCoord& pos,bool permitTilde);
223 QStringList getExpressionAtPosition(
224 const QSynedit::BufferCoord& pos);
225
226 const PCppParser &parser();
227
228 void tab() override;
229signals:
230 void renamed(const QString& oldName, const QString& newName, bool firstSave);
231 void fileSaved(const QString& filename, bool inProject);
232private slots:
233 void onStatusChanged(QSynedit::StatusChanges changes);
234 void onGutterClicked(Qt::MouseButton button, int x, int y, int line);
235 void onTipEvalValueReady(const QString& value);
236 void onLinesDeleted(int first,int count);
237 void onLinesInserted(int first,int count);
238 void onFunctionTipsTimer();
239
240private:
241 bool isBraceChar(QChar ch);
242 void resetBookmarks();
243 QChar getCurrentChar();
244 bool handleSymbolCompletion(QChar key);
245 bool handleParentheseCompletion();
246 bool handleParentheseSkip();
247 bool handleBracketCompletion();
248 bool handleBracketSkip();
249 bool handleMultilineCommentCompletion();
250 bool handleBraceCompletion();
251 bool handleBraceSkip();
252 bool handleSingleQuoteCompletion();
253 bool handleDoubleQuoteCompletion();
254 bool handleGlobalIncludeCompletion();
255 bool handleGlobalIncludeSkip();
256
257 bool handleCodeCompletion(QChar key);
258 void initParser();
259 void undoSymbolCompletion(int pos);
260 QuoteStatus getQuoteStatus();
261
262 void showCompletion(const QString& preWord, bool autoComplete);
263 void showHeaderCompletion(bool autoComplete, bool forceShow=false);
264
265 bool testInFunc(int x,int y);
266
267 void completionInsert(bool appendFunc=false);
268
269 void headerCompletionInsert();
270
271 bool onCompletionKeyPressed(QKeyEvent* event);
272 bool onHeaderCompletionKeyPressed(QKeyEvent* event);
273 bool onCompletionInputMethod(QInputMethodEvent *event);
274
275 TipType getTipType(QPoint point, QSynedit::BufferCoord& pos);
276 void cancelHint();
277 QString getFileHint(const QString& s);
278 QString getParserHint(const QStringList& expression,const QString& s, int line);
279 void showDebugHint(const QString& s,int line);
280 QString getErrorHint(const PSyntaxIssue& issue);
281 QString getHintForFunction(const PStatement& statement,
282 const QString& filename, int line);
283
284 void updateFunctionTip(bool showTip);
285 void clearUserCodeInTabStops();
286 void popUserCodeInTabStops();
287 void onExportedFormatToken(QSynedit::PHighlighter syntaxHighlighter, int Line, int column, const QString& token,
288 QSynedit::PHighlighterAttribute &attr);
289 void onScrollBarValueChanged();
290private:
291 QByteArray mEncodingOption; // the encoding type set by the user
292 QByteArray mFileEncoding; // the real encoding of the file (auto detected)
293 QString mFilename;
294 QTabWidget* mParentPageControl;
295 bool mInProject;
296 bool mIsNew;
297 QMap<int,PSyntaxIssueList> mSyntaxIssues;
298 QColor mSyntaxErrorColor;
299 QColor mSyntaxWarningColor;
300 QColor mActiveBreakpointForegroundColor;
301 QColor mActiveBreakpointBackgroundColor;
302 QColor mBreakpointForegroundColor;
303 QColor mBreakpointBackgroundColor;
304 QColor mCurrentHighlighWordForeground;
305 QColor mCurrentHighlighWordBackground;
306 int mSyntaxErrorLine;
307 int mLineCount;
308 int mGutterClickedLine;
309 QSet<int> mBreakpointLines;
310 QSet<int> mBookmarkLines;
311 int mActiveBreakpointLine;
312 PCppParser mParser;
313 std::shared_ptr<CodeCompletionPopup> mCompletionPopup;
314 std::shared_ptr<HeaderCompletionPopup> mHeaderCompletionPopup;
315 int mLastIdCharPressed;
316 bool mUseCppSyntax;
317 QString mCurrentWord;
318 QString mCurrentDebugTipWord;
319 TipType mCurrentTipType;
320 QString mOldHighlightedWord;
321 QString mCurrentHighlightedWord;
322 QDateTime mHideTime;
323
324 bool mSaving;
325 bool mCurrentLineModified;
326 int mXOffsetSince;
327 int mTabStopBegin;
328 int mTabStopEnd;
329 int mTabStopY;
330 bool mCanAutoSave;
331 QString mLineBeforeTabStop;
332 QString mLineAfterTabStop;
333 QList<PTabStop> mUserCodeInTabStops;
334 QSynedit::BufferCoord mHighlightCharPos1;
335 QSynedit::BufferCoord mHighlightCharPos2;
336 std::shared_ptr<QHash<StatementKind, std::shared_ptr<ColorSchemeItem> > > mStatementColors;
337 QTimer mFunctionTipTimer;
338 int mHoverModifiedLine;
339
340 // QWidget interface
341protected:
342 void wheelEvent(QWheelEvent *event) override;
343 void focusInEvent(QFocusEvent *event) override;
344 void focusOutEvent(QFocusEvent *event) override;
345 void keyPressEvent(QKeyEvent *event) override;
346
347 // SynEdit interface
348protected:
349 void onGutterPaint(QPainter &painter, int aLine, int X, int Y) override;
350 void onGetEditingAreas(int Line, QSynedit::EditingAreaList &areaList) override;
351
352 // SynEdit interface
353protected:
354 bool onGetSpecialLineColors(int Line, QColor &foreground, QColor &backgroundColor) override;
355
356 // SynEdit interface
357protected:
358 void onPreparePaintHighlightToken(int line, int aChar, const QString &token, QSynedit::PHighlighterAttribute attr, QSynedit::FontStyles &style, QColor &foreground, QColor &background) override;
359
360 // QObject interface
361public:
362 bool event(QEvent *event) override;
363
364 // QWidget interface
365 void setInProject(bool newInProject);
366
367 bool useCppSyntax() const;
368 void setUseCppSyntax(bool newUseCppSyntax);
369
370 const std::shared_ptr<QHash<StatementKind, std::shared_ptr<ColorSchemeItem> > > &statementColors() const;
371 void setStatementColors(const std::shared_ptr<QHash<StatementKind, std::shared_ptr<ColorSchemeItem> > > &newStatementColors);
372
373 const QDateTime &hideTime() const;
374 void setHideTime(const QDateTime &newHideTime);
375
376 bool canAutoSave() const;
377 void setCanAutoSave(bool newCanAutoSave);
378
379protected:
380 void mouseReleaseEvent(QMouseEvent *event) override;
381 void inputMethodEvent(QInputMethodEvent *) override;
382 void closeEvent(QCloseEvent *event) override;
383
384 // QWidget interface
385protected:
386 void showEvent(QShowEvent *event) override;
387 void hideEvent(QHideEvent *event) override;
388
389 // QWidget interface
390protected:
391 void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
392};
393
394QString getWordAtPosition(QSynedit::SynEdit* editor,
395 const QSynedit::BufferCoord& p,
396 QSynedit::BufferCoord& pWordBegin,
397 QSynedit::BufferCoord& pWordEnd,
398 Editor::WordPurpose purpose);
399
400
401#endif // EDITOR_H
402