1// This file is part of SmallBASIC
2//
3// Copyright(C) 2001-2020 Chris Warren-Smith.
4//
5// This program is distributed under the terms of the GPL v2.0 or later
6// Download the GNU Public License (GPL) from www.gnu.org
7//
8
9#ifndef TEXTEDIT_H
10#define TEXTEDIT_H
11
12#define STB_TEXTEDIT_CHARTYPE char
13#define STB_TEXTEDIT_UNDOCHARCOUNT 5000
14#define MARGIN_CHARS 4
15#define MAX_MARKERS 10
16
17#include <config.h>
18#include <stdlib.h>
19#include <string.h>
20#include <ctype.h>
21#include "lib/stb/stb_textedit.h"
22#include "ui/inputs.h"
23#include "ui/theme.h"
24#include "common/smbas.h"
25#include "common/keymap.h"
26
27struct TextEditInput;
28
29struct StackTraceNode {
30 StackTraceNode(const char *keyword, int type, int line)
31 : _keyword(keyword), _type(type), _line(line) {}
32 virtual ~StackTraceNode() {}
33 const char *_keyword;
34 int _type;
35 int _line;
36};
37
38typedef strlib::List<StackTraceNode *> StackTrace;
39
40struct EditBuffer {
41 char *_buffer;
42 int _len;
43 int _size;
44 int _lines;
45 TextEditInput *_in;
46
47 EditBuffer(TextEditInput *in, const char *text);
48 virtual ~EditBuffer();
49
50 void append(const char *text, int len) { insertChars(_len, text, len); }
51 void append(const char *text) { insertChars(_len, text, strlen(text)); }
52 void clear();
53 int countNewlines(const char *text, int num);
54 int deleteChars(int pos, int num);
55 char getChar(int pos);
56 int insertChars(int pos, const char *text, int num);
57 int lineCount();
58 void removeTrailingSpaces(STB_TexteditState *state);
59 char *textRange(int start, int end);
60};
61
62struct TextEditInput : public FormEditInput {
63 TextEditInput(const char *text, int chW, int chH, int x, int y, int w, int h);
64 virtual ~TextEditInput();
65
66 void append(const char *text, int len) { _buf.append(text, len); }
67 void completeWord(const char *word);
68 const char *completeKeyword(int index);
69 void draw(int x, int y, int w, int h, int chw);
70 bool edit(int key, int screenWidth, int charWidth);
71 bool find(const char *word, bool next);
72 int getCursorPos() const { return _state.cursor; }
73 int getCol() const { return _cursorCol; }
74 int getRow() const { return _cursorRow + 1; }
75 int getPageRows() const { return _height / _charHeight; }
76 int getLines() { return _buf.lineCount(); }
77 int getMarginWidth() { return _marginWidth; }
78 void getSelectionCounts(int *lines, int *chars);
79 int getSelectionRow();
80 int getSelectionStart() { return _state.select_start; }
81 int getScroll() const { return _scroll; }
82 const char *getText() const { return _buf._buffer; }
83 char *getTextSelection(bool selectAll);
84 int getTextLength() const { return _buf._len; }
85 int *getMarkers();
86 void gotoLine(const char *buffer);
87 void reload(const char *text);
88 bool save(const char *filePath);
89 void setCursor(int pos);
90 void setCursorPos(int pos);
91 void setCursorRow(int row);
92 void setLineNumbers() { _marginWidth = 1 + (_charWidth * MARGIN_CHARS); }
93 void setText(const char *text) { _buf.clear(); _buf.append(text); }
94 void setTheme(EditTheme *theme) { _theme = theme; }
95 void clicked(int x, int y, bool pressed);
96 void updateField(var_p_t form);
97 bool updateUI(var_p_t form, var_p_t field);
98 bool selected(MAPoint2d pt, int scrollX, int scrollY, bool &redraw);
99 int padding(bool) const { return 0; }
100 void layout(StbTexteditRow *row, int start_i) const;
101 int charWidth(int k, int i) const;
102 char *copy(bool cut);
103 void paste(const char *text);
104 void selectAll();
105 bool isDirty() { return _dirty && _state.undostate.undo_point > 0; }
106 void setDirty(bool dirty) { _dirty = dirty; }
107 void layout(int w, int h);
108 const char *getNodeId();
109 char *getWordBeforeCursor();
110 bool replaceNext(const char *text, bool skip);
111 int getCompletions(StringList *list, int max);
112 void selectNavigate(bool up);
113 EditTheme *getTheme() { return _theme; }
114
115protected:
116 enum SyntaxState {
117 kReset = 0,
118 kComment,
119 kText,
120 kCommand,
121 kStatement,
122 kDigit,
123 };
124
125 void dragPage(int y, bool &redraw);
126 void drawText(int x, int y, const char *str, int length, SyntaxState &state);
127 void calcMargin();
128 void changeCase();
129 void cycleTheme();
130 void drawLineNumber(int x, int y, int row, bool selected);
131 void editDeleteLine();
132 void editEnter();
133 void editTab();
134 bool endStatement(const char *buf);
135 void findMatchingBrace();
136 int getCursorRow();
137 uint32_t getHash(const char *str, int offs, int &count);
138 int getIndent(char *spaces, int len, int pos);
139 int getLineChars(StbTexteditRow *row, int pos);
140 char *getSelection(int *start, int *end);
141 void gotoNextMarker();
142 void killWord();
143 void lineNavigate(bool lineDown);
144 char *lineText(int pos);
145 int lineEnd(int pos) { return linePos(pos, true); }
146 int linePos(int pos, bool end, bool excludeBreak=true);
147 int lineStart(int pos) { return linePos(pos, false); }
148 bool matchCommand(uint32_t hash);
149 bool matchStatement(uint32_t hash);
150 void pageNavigate(bool pageDown, bool shift);
151 void removeTrailingSpaces();
152 void selectWord();
153 void setColor(SyntaxState &state);
154 void toggleMarker();
155 void updateScroll();
156 int wordEnd();
157 int wordStart();
158
159 EditBuffer _buf;
160 STB_TexteditState _state;
161 EditTheme *_theme;
162 int _charWidth;
163 int _charHeight;
164 int _marginWidth;
165 int _scroll;
166 int _cursorCol;
167 int _cursorRow;
168 int _cursorLine;
169 int _indentLevel;
170 int _matchingBrace;
171 int _ptY;
172 int _pressTick;
173 int _xmargin;
174 int _ymargin;
175 bool _bottom;
176 bool _dirty;
177};
178
179struct TextEditHelpWidget : public TextEditInput {
180 TextEditHelpWidget(TextEditInput *editor, int chW, int chH, bool overlay=true);
181 virtual ~TextEditHelpWidget();
182
183 enum HelpMode {
184 kNone,
185 kHelp,
186 kHelpKeyword,
187 kCompletion,
188 kOutline,
189 kSearch,
190 kEnterReplace,
191 kEnterReplaceWith,
192 kReplace,
193 kReplaceDone,
194 kGotoLine,
195 kMessage,
196 kLineEdit,
197 kStacktrace
198 };
199
200 void clicked(int x, int y, bool pressed);
201 void createCompletionHelp();
202 void createGotoLine();
203 void createHelp();
204 void createLineEdit(const char *value);
205 void createKeywordIndex();
206 void createMessage() { reset(kMessage); }
207 void createOutline();
208 void createSearch(bool replace);
209 void createStackTrace(const char *error, int line, StackTrace &trace);
210 void draw(int x, int y, int w, int h, int chw);
211 bool edit(int key, int screenWidth, int charWidth);
212 void paste(const char *text);
213 bool isDrawTop() { return true; }
214 void reset(HelpMode mode);
215 void cancelMode() { _mode = kNone; }
216 bool closeOnEnter() const;
217 bool searchMode() const { return _mode >= kSearch && _mode <= kReplaceDone; }
218 void layout(int w, int h);
219 bool lineEditMode() const { return _mode == kLineEdit; }
220 bool messageMode() const { return _mode == kMessage; }
221 bool replaceMode() const { return _mode == kReplace; }
222 bool replaceModeWith() const { return _mode == kEnterReplaceWith; }
223 bool replaceDoneMode() const { return _mode == kReplaceDone; }
224 bool selected(MAPoint2d pt, int scrollX, int scrollY, bool &redraw);
225 void showPopup(int cols, int rows);
226 void showSidebar();
227 void toggleKeyword();
228
229private:
230 void completeLine(int pos);
231 void completeWord(int pos);
232 void createPackageIndex();
233
234 HelpMode _mode;
235 strlib::List<int *> _outline;
236 TextEditInput *_editor;
237 const char *_openPackage;
238 int _openKeyword;
239 enum Layout {
240 kLine,
241 kSidebar,
242 kPopup,
243 } _layout;
244};
245
246#define STB_TEXTEDIT_STRING EditBuffer
247#define STB_TEXTEDIT_K_LEFT SB_KEY_LEFT
248#define STB_TEXTEDIT_K_RIGHT SB_KEY_RIGHT
249#define STB_TEXTEDIT_K_UP SB_KEY_UP
250#define STB_TEXTEDIT_K_DOWN SB_KEY_DOWN
251#define STB_TEXTEDIT_K_LINESTART SB_KEY_HOME
252#define STB_TEXTEDIT_K_LINEEND SB_KEY_END
253#define STB_TEXTEDIT_K_DELETE SB_KEY_DELETE
254#define STB_TEXTEDIT_K_BACKSPACE SB_KEY_BACKSPACE
255#define STB_TEXTEDIT_K_TEXTSTART SB_KEY_CTRL(SB_KEY_HOME)
256#define STB_TEXTEDIT_K_TEXTEND SB_KEY_CTRL(SB_KEY_END)
257#define STB_TEXTEDIT_K_UNDO SB_KEY_CTRL('z')
258#define STB_TEXTEDIT_K_REDO SB_KEY_CTRL('y')
259#define STB_TEXTEDIT_K_INSERT SB_KEY_INSERT
260#define STB_TEXTEDIT_K_WORDLEFT SB_KEY_CTRL(SB_KEY_LEFT)
261#define STB_TEXTEDIT_K_WORDRIGHT SB_KEY_CTRL(SB_KEY_RIGHT)
262#define STB_TEXTEDIT_K_PGUP SB_KEY_PGUP
263#define STB_TEXTEDIT_K_PGDOWN SB_KEY_PGDN
264#define STB_TEXTEDIT_NEWLINE '\n'
265#define STB_TEXTEDIT_K_CONTROL SB_KEY_CTRL(0)
266#define STB_TEXTEDIT_K_SHIFT SB_KEY_SHIFT(0)
267#define STB_TEXTEDIT_GETWIDTH_NEWLINE 0.0f
268#define STB_TEXTEDIT_KEYTOTEXT(k) k
269#define STB_TEXTEDIT_STRINGLEN(o) o->_len
270#define STB_TEXTEDIT_GETCHAR(o,i) o->getChar(i)
271#define STB_TEXTEDIT_GETWIDTH(o,n,i) o->_in->charWidth(n, i)
272#define STB_TEXTEDIT_LAYOUTROW(r,o,n) o->_in->layout(r, n)
273#define STB_TEXTEDIT_DELETECHARS(o,i,n) o->deleteChars(i, n)
274#define STB_TEXTEDIT_INSERTCHARS(o,i,c,n) o->insertChars(i, c, n)
275
276#endif
277
278