Uses 2597K of libraries. Click here for Pure Java version (28892L/158K).
1 | !7 |
2 | |
3 | // TODO: use central transpiler |
4 | |
5 | set flag bindLiveValueListenerToComponent_debug. |
6 | //set flag addMenu_debug. |
7 | |
8 | cmodule2 SFEditor {
|
9 | // What are we editing? |
10 | O editing; // File or snippet ID |
11 | S remoteText; |
12 | Int snippetType; |
13 | |
14 | S savedText; |
15 | int caretPos; |
16 | int fontSize = 16; |
17 | S fontID = /*#1400030*/#1400031; |
18 | S snippetTitle; |
19 | switchable bool alwaysTranspileHere = true; |
20 | |
21 | transient EditorFrame2 e; |
22 | transient SimpleLiveValue<O> lvEditing; |
23 | transient AutoCompletion autoCompletion; |
24 | transient ReliableSingleThread rstAutoComplete = dm_rst(this, r installAutoComplete); |
25 | transient bool installAutoComplete_first; |
26 | transient Set<S> autoComplete_lastSet; |
27 | transient int autoCompleteRefreshDelay = 1000; |
28 | transient JFastLogView_noWrap transpilationErrorBox; |
29 | transient ReliableSingleThread persistLater = rstWithDelay(10.0, r persistMe); |
30 | transient JButton saveAndTranspileButton; |
31 | |
32 | !include #1016117 // setAndSave etc. |
33 | |
34 | bool warnOnDelete() { ret neq(e.getText(), unnull(remoteText)); }
|
35 | |
36 | void reset {
|
37 | cleanMeUp(); |
38 | autoCompletion = null; |
39 | autoComplete_lastSet = null; |
40 | start(); |
41 | } |
42 | |
43 | void start() swing {
|
44 | temp enter(); |
45 | installAutoComplete_first = true; |
46 | lvEditing = dm_fieldLiveValue('editing);
|
47 | |
48 | e = new EditorFrame2; |
49 | e._setFont(deriveFont(loadFont(fontID), e._getFont().getSize())); |
50 | e._setFontSize(fontSize); |
51 | main.onChangeAndNow(e.textArea, rstAutoComplete); |
52 | |
53 | // Register Ctrl+S |
54 | e.textArea.getInputMap().put(ctrlKeyStroke(KeyEvent.VK_S), |
55 | abstractAction("Save", rThread { saveThen(null) }));
|
56 | |
57 | e.setText(savedText); |
58 | load('caretPos);
|
59 | setCaretPosition(e.textArea, caretPos); |
60 | } |
61 | |
62 | visual e.panel; |
63 | |
64 | enhanceFrame {
|
65 | e.prepareFrame(f/JInternalFrame); |
66 | minimalFrameSize(f/JInternalFrame, 400, 400); |
67 | reload(); |
68 | makeMenus(f); |
69 | awtCalcEvery(f/JInternalFrame.getRootPane(), 1000, r update); |
70 | onPossiblyInternalFrameDeactivated(f/JInternalFrame.getRootPane(), r fullUpdate); |
71 | } |
72 | |
73 | void makeMenus(Container f) {
|
74 | if (f == null) ret; |
75 | bool wasEmpty = countComponents(getMenuBar(f)) < 2; // Search menu is added somewhere else |
76 | //print("Components in menu: " + getComponents(getMenuBar(f)));
|
77 | |
78 | addMenu(f, "&View", |
79 | "Bigger font", r { e._setFontSize(setAndSave(fontSize := e._getFontSize()+1)) },
|
80 | "Smaller font", r { e._setFontSize(setAndSave(fontSize := max(1, e._getFontSize()-1))) },
|
81 | "---", |
82 | "Show snippet in browser", rThread showInBrowser); |
83 | |
84 | addMenu(f, "&New", |
85 | "New text", r newText, |
86 | "New window", rThread { dm_showNewModule(dm_moduleLibID()) });
|
87 | |
88 | addMenu(f, "&Load", "Load snippet...", r {
|
89 | selectSnippetID(voidfunc(S snippetID) { _loadSnippet(snippetID) });
|
90 | }, "Load file...", r {
|
91 | selectFile("File to load", voidfunc(File f) { _loadFile(f) });
|
92 | }, "Reload", r-thread { // TODO: single thread
|
93 | if (editing != null) {
|
94 | reload(); |
95 | main setText(e.textArea, remoteText); |
96 | } |
97 | }); |
98 | |
99 | // There is a weird bug that breaks the bindToComponent magic |
100 | LiveValue<S> lvSaveCmd = mapLiveValue(func(O editing) -> S {
|
101 | editing instanceof S ? "Save snippet " + editing |
102 | : editing instanceof File ? "Save file " + f2s((File) editing) |
103 | : "{Save}" }, S.class, lvEditing);
|
104 | |
105 | addMenu(f, "&Save", |
106 | lvSaveCmd, rThread { saveThen(null) },
|
107 | "Save as snippet...", r saveAsSnippet, |
108 | "Save as file...", r saveAsFile, |
109 | "Rename snippet...", rThread renameTheSnippet); |
110 | |
111 | addMenu(f, "&Transpile", |
112 | "Save & Quick Transpile", r { transpile(false) },
|
113 | "Save & Medium Transpile", r { transpile(true) },
|
114 | "---", |
115 | "Show transpilation", r showTranspilation); |
116 | |
117 | //print("Editing: " + editing);
|
118 | |
119 | addMenu(f, "&Activate", |
120 | eq(snippetType, snippetType_JavaXDesktop()) ? "Run" : null, rThread runIt, |
121 | isString(editing) ? "Load Module" : null, rThread _loadModule, |
122 | isString(editing) ? "Reload Module" : null, rThread _reloadModule, |
123 | haveMuricaPassword() ? "Reload on server" : null, rThread _butterReload, |
124 | haveMuricaPassword() ? "Transpile quick & reload on server" : null, rThread { transpileAndButterReload(false) },
|
125 | haveMuricaPassword() ? "Transpile medium & reload on server" : null, rThread { transpileAndButterReload(true) });
|
126 | |
127 | if (wasEmpty) {
|
128 | // add horizontal spacer so icons end up on the right |
129 | addToContainer(getMenuBar(f), Box.createHorizontalGlue()); |
130 | |
131 | // Save & medium transpile icon |
132 | addToContainer(getMenuBar(f), |
133 | jbutton("Save", rThread { saveThen(null) }),
|
134 | setToolTip("Save & medium-transpile",
|
135 | setBorderPainted(false, |
136 | saveAndTranspileButton = jimagebutton(#1102952, rThread { transpile(true) }))) |
137 | ); |
138 | } |
139 | } |
140 | |
141 | void reload {
|
142 | if (editing instanceof S) _loadSnippet_noSet((S) editing); |
143 | else if (editing instanceof File) _loadFile_noSet((File) editing); |
144 | } |
145 | |
146 | void update { update(internalFrameActive(e.panel)); }
|
147 | void fullUpdate { update(true); }
|
148 | void update(bool full) {
|
149 | if (e == null) ret; // e.g. if this instance was made by dm_originalFieldValues |
150 | |
151 | S text = e.getText(); |
152 | int cp = getCaretPosition(e.textArea); |
153 | if (neq(savedText, text)) {
|
154 | setAndSave(savedText := text); |
155 | setAndSave(caretPos := cp); |
156 | } else if (cp != caretPos) {
|
157 | caretPos = cp; |
158 | persistLater.trigger(); |
159 | } |
160 | |
161 | if (!full) ret; |
162 | S status = remoteText != null && neq(remoteText, text) ? "Changes. " : ""; |
163 | Pair<Int, S> p = testBracketHygieneExt(text); |
164 | status += p == null ? "Hygienic" : p.b; |
165 | silentStatus(trim(status)); |
166 | } |
167 | |
168 | void status(S s) { silentStatus(infoBoxAndReturn(s)); }
|
169 | void silentStatus(S s) { e.setStatus(s); }
|
170 | |
171 | void saveThen(Runnable next) {
|
172 | fS text = dropCarriageReturn(getText()); |
173 | if (editing cast S) {
|
174 | status("Saving snippet...");
|
175 | thread {
|
176 | fS page = editSnippet(editing, text); |
177 | remoteText = text; // TODO: check save result |
178 | status("Saved snippet: " + page);
|
179 | callF(next); |
180 | } |
181 | } else if (editing cast File) {
|
182 | status("Saving file...");
|
183 | thread {
|
184 | saveTextFile(editing, text); |
185 | remoteText = text; |
186 | status("Saved file");
|
187 | callF(next); |
188 | } |
189 | } |
190 | } |
191 | |
192 | void renameTheSnippet enter {
|
193 | if (!editing instanceof S) |
194 | ret with infoBox("Not editing a snippet");
|
195 | S snippetID = cast editing; |
196 | inputText("Rename snippet " + snippetID, snippetTitle(snippetID), voidfunc(S name) {
|
197 | renameSnippet(snippetID, snippetTitle = name); |
198 | setModuleName("Editing: " + snippetID + " - " + quote(snippetTitle));
|
199 | }); |
200 | } |
201 | |
202 | void _butterReload() {
|
203 | time { butterReload((S) editing); }
|
204 | infoBox("Reloaded in " + lastTiming_format100ms());
|
205 | } |
206 | |
207 | void transpileAndButterReload(bool medium) {
|
208 | transpile(medium, onSuccess := r _butterReload); |
209 | } |
210 | |
211 | void transpile(bool medium, O... _) { saveThen(r { _transpile(medium, _) }); }
|
212 | |
213 | void _transpile(bool medium, O... _) {
|
214 | optPar Runnable onSuccess; |
215 | status("Transpiling...");
|
216 | //jdisable(btnEleuReload); |
217 | |
218 | S toTranspile = or(mainTranspilationSnippetFromSrc(getText()), (S) editing); |
219 | S msg = "Transpiling " + toTranspile + "..."; |
220 | infoBox(msg); |
221 | thread msg {
|
222 | try {
|
223 | Pair<Bool, S> p; |
224 | {
|
225 | temp tempDisableButton(saveAndTranspileButton); |
226 | p = transpileHereOrOnServer(toTranspile, medium, alwaysHere := alwaysTranspileHere); |
227 | } |
228 | |
229 | awt {
|
230 | if (p.a) {
|
231 | status("Transpiled OK!");
|
232 | hideWindow(transpilationErrorBox); |
233 | transpilationErrorBox = null; |
234 | callFInNewThread(onSuccess); |
235 | } else {
|
236 | S text = htmlDecode(htmlDecode(p.b)); /// XXX |
237 | status("Transpilation error. " + text);
|
238 | bool first = transpilationErrorBox == null; |
239 | transpilationErrorBox = maximizeFrame(scrollAllTheWayDown(showText_fast_noWrap(transpilationErrorBox, "Transpilation Error", text))); |
240 | if (first) {
|
241 | setFrameIcon(#1101268, transpilationErrorBox); |
242 | addButtonsToWindow(transpilationErrorBox, "Medium transpile", r { _transpile(true) });
|
243 | } |
244 | } |
245 | } |
246 | } catch print e {
|
247 | status("Transpilation problem. " + e);
|
248 | } |
249 | //jenable(btnEleuReload); |
250 | } |
251 | } |
252 | |
253 | void _loadSnippet(S snippetID) enter {
|
254 | _loadSnippet_noSet(snippetID); |
255 | e.textArea.setText(remoteText); |
256 | } |
257 | |
258 | void _loadSnippet_noSet(S snippetID) {
|
259 | remoteText = loadSnippet(snippetID); |
260 | setField(snippetType := getSnippetType(snippetID)); |
261 | setAndSave('editing, snippetID);
|
262 | setModuleName("Editing: " + snippetID + " - " + quote(snippetTitle = snippetTitle(snippetID)));
|
263 | print("_loadSnippet_noSet: Making menus for " + dm_frame() + " of " + className(dm_vis()));
|
264 | makeMenus(dm_frame()); |
265 | } |
266 | |
267 | void _loadFile(File f) {
|
268 | _loadFile_noSet(f); |
269 | e.textArea.setText(remoteText); |
270 | } |
271 | |
272 | void _loadFile_noSet(File f) {
|
273 | remoteText = loadTextFile(f); |
274 | setField(snippetType := null); |
275 | setAndSave('editing, f);
|
276 | setModuleName("Editing: " + f2s(f));
|
277 | makeMenus(dm_frame()); |
278 | } |
279 | |
280 | void newText {
|
281 | setAndSave(editing := null); |
282 | remoteText = null; |
283 | setField(snippetType := null); |
284 | S lastText = e.getText(); |
285 | if (nempty(lastText)) logQuotedWithDate("saved-texts.log", lastText);
|
286 | e.setText("");
|
287 | setModuleName(programTitle()); |
288 | } |
289 | |
290 | void cleanMeUp {
|
291 | update(false); |
292 | } |
293 | |
294 | void installAutoComplete {
|
295 | if (installAutoComplete_first) installAutoComplete_first = false; |
296 | else sleep(autoCompleteRefreshDelay); // don't update too often |
297 | |
298 | //temp tempMiniLoadingAnim(); |
299 | |
300 | Set<S> set = concatListsToSet(allJavaKeywords(), standardFunctionNames(), deepWords(getText()), deepWords(snippetTitle)); |
301 | |
302 | if (eq(set, autoComplete_lastSet)) ret; |
303 | autoComplete_lastSet = set; |
304 | |
305 | final new DefaultCompletionProvider provider; |
306 | provider.addCompletions(map(func(S s) -> Completion { new BasicCompletion(provider, s) }, set));
|
307 | |
308 | swing {
|
309 | if (autoCompletion == null) {
|
310 | (autoCompletion = new AutoCompletion(provider)).install(e.textArea); |
311 | call(autoCompletion, 'setHideOnCompletionProviderChange, false); |
312 | } else |
313 | autoCompletion.setCompletionProvider(provider); |
314 | } |
315 | } |
316 | |
317 | void newWindow {
|
318 | copyFields(this, new SFEditor(), 'fontSize).start(); |
319 | } |
320 | |
321 | void runIt {
|
322 | if (editing instanceof S) |
323 | nohupJavax((S) editing); |
324 | } |
325 | |
326 | void saveAsSnippet {
|
327 | JTextField tfTitle = jtextfield(snippetTitle); |
328 | JComboBox cbType = jComboBox_javaxTypes(); |
329 | JCheckBox cbPublic = jCheckBox("Public", true);
|
330 | |
331 | renameSubmitButton("Create snippet", showFormTitled("Save as new snippet",
|
332 | "Title:", tfTitle, |
333 | "Type:", cbType, |
334 | "", cbPublic, |
335 | r-thread {
|
336 | loading {
|
337 | int type = parseFirstInt(getSelectedItem(cbType)); |
338 | S title = getTextTrim(tfTitle); |
339 | S snippetID = createSnippet(getText(), title, type, isChecked(cbPublic)); |
340 | _loadSnippet_noSet(snippetID); |
341 | } |
342 | })); |
343 | } |
344 | |
345 | void saveAsFile {
|
346 | inputFilePath("Save as...", optCast(File, editing), voidfunc(File f) {
|
347 | saveTextFile(f, getText()); |
348 | _loadFile_noSet(f); |
349 | }); |
350 | } |
351 | |
352 | S getText() { ret e.getText(); }
|
353 | |
354 | void _reloadModule enter {
|
355 | dm_reloadAllModulesWithSnippetID((S) editing); |
356 | } |
357 | |
358 | void _loadModule enter {
|
359 | dm_addDynamicModuleDialog2((S) editing); |
360 | } |
361 | |
362 | S snippetID() { ret optCast S(editing); }
|
363 | |
364 | void showTranspilation enter {
|
365 | if (snippetID() == null) ret; |
366 | showText("Transpilation of " + snippetID(),
|
367 | getServerTranspiledWithoutLibs(snippetID())); |
368 | } |
369 | |
370 | void showInBrowser {
|
371 | if (snippetID() == null) ret; |
372 | openInBrowser(snippetLink(snippetID())); |
373 | } |
374 | |
375 | // API |
376 | |
377 | void setText(S text) enter {
|
378 | e.textArea.setText(text); |
379 | } |
380 | } |
Began life as a copy of #1015563
download show line numbers debug dex old transpilations
Travelled to 17 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, hpgrupgrauku, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv
No comments. add comment
| Snippet ID: | #1016118 |
| Snippet name: | Code Editor [edits snippets and files] |
| Eternal ID of this version: | #1016118/114 |
| Text MD5: | 4b2f9396554283499d5676e9678f5e6e |
| Transpilation MD5: | df51796755f586a85e1e8106f4ed2e5e |
| Author: | stefan |
| Category: | javax / gui |
| Type: | JavaX source code (Dynamic Module) |
| Public (visible to everyone): | Yes |
| Archived (hidden from active list): | No |
| Created/modified: | 2022-02-26 17:15:17 |
| Source code size: | 12366 bytes / 380 lines |
| Pitched / IR pitched: | No / No |
| Views / Downloads: | 1114 / 14237 |
| Version history: | 113 change(s) |
| Referenced in: | [show references] |