Uses 2805K of libraries. Click here for Pure Java version (21108L/163K).
1 | concept SFEditor { |
2 | // What are we editing? |
3 | O editing; // File or snippet ID |
4 | S remoteText; |
5 | |
6 | S savedText; |
7 | int caretPos; |
8 | int fontSize = 16; |
9 | S fontID = /*#1400030*/#1400031; |
10 | S snippetTitle; |
11 | |
12 | transient EditorFrame e; |
13 | transient SimpleLiveValue<O> lvEditing; |
14 | transient AutoCompletion autoCompletion; |
15 | transient ReliableSingleThread rstAutoComplete = new(r installAutoComplete); |
16 | transient bool installAutoComplete_first; |
17 | transient Set<S> autoComplete_lastSet; |
18 | transient DynamicHStack smartArea; |
19 | transient int autoCompleteRefreshDelay = 1000; |
20 | transient JTextArea transpilationErrorBox; |
21 | |
22 | !include #1015622 // setAndSave etc. |
23 | |
24 | void reset { |
25 | cleanMeUp(); |
26 | autoCompletion = null; |
27 | autoComplete_lastSet = null; |
28 | start(); |
29 | } |
30 | |
31 | void start { swing { |
32 | installAutoComplete_first = true; |
33 | lvEditing = new SimpleLiveValue(O); |
34 | |
35 | e = new EditorFrame; |
36 | e._setFont(deriveFont(loadFont(fontID), e._getFont().getSize())); |
37 | e._setFontSize(fontSize); |
38 | rstAutoComplete.trigger(); |
39 | onChange(e.textArea, rTrigger(rstAutoComplete)); |
40 | |
41 | addToWindowWithMargin(e, jHigherScrollPane(jfullcenter(smartArea = dynamicHStack()))); |
42 | |
43 | e.setText(savedText); |
44 | load('caretPos); |
45 | setCaretPosition(e.textArea, caretPos); |
46 | showFrame(e); |
47 | frameIcon(e, #1101185 /*#1004655*/); |
48 | addFontChangersToTitleMenu(e, r reset); |
49 | onFrameClosing(e, r { |
50 | if (!cleaningUp()) |
51 | deleteConcept(SFEditor.this); |
52 | }); |
53 | |
54 | addMenu(e, "&New", |
55 | "New text", r newText, |
56 | "New window", r newWindow); |
57 | |
58 | addMenu(e, "&Load", "Load snippet...", r { |
59 | selectSnippetID(voidfunc(S snippetID) { _loadSnippet(snippetID) }); |
60 | }, "Load file...", r { |
61 | selectFile("File to load", voidfunc(File f) { _loadFile(f) }); |
62 | }, "Reload", r-thread { // TODO: single thread |
63 | if (editing != null) { |
64 | reload(); |
65 | setText(e.textArea, remoteText); |
66 | } |
67 | }); |
68 | |
69 | LiveValue<S> lvSaveCmd = mapLiveValue(func(O editing) -> S { |
70 | editing instanceof S ? "Save snippet " + editing |
71 | : editing instanceof File ? "Save file " + f2s((File) editing) |
72 | : "{Save}" }, S.class, lvEditing); |
73 | |
74 | addMenu(e, "&Save", |
75 | lvSaveCmd, r { saveThen(null) }, |
76 | "Save as snippet...", r saveAsSnippet); |
77 | |
78 | addMenu(e, "&Transpile", |
79 | "Save & Quick Transpile", r { transpile(false) }, |
80 | "Save & Medium Transpile", r { transpile(true) }); |
81 | addMenu(e, "&Activate", |
82 | "Run", r runIt, |
83 | "Butter-Reload", r _butterReload); |
84 | |
85 | addMenu(e, "&View", |
86 | "Bigger font", r { e._setFontSize(setAndSave(fontSize := e._getFontSize()+1)) }, |
87 | "Smaller font", r { e._setFontSize(setAndSave(fontSize := max(1, e._getFontSize()-1))) }); |
88 | |
89 | reload(); |
90 | |
91 | awtCalcEvery(e, 1000, r update); |
92 | onFrameDeactivated(e, r fullUpdate); |
93 | } |
94 | } |
95 | |
96 | void reload { |
97 | if (editing instanceof S) _loadSnippet_noSet((S) editing); |
98 | else if (editing instanceof File) _loadFile_noSet((File) editing); |
99 | } |
100 | |
101 | void update { update(windowActive(e)); } |
102 | void fullUpdate { update(true); } |
103 | void update(bool full) { |
104 | S text = e.getText(); |
105 | setAndSaveIfChanged(savedText := text); |
106 | setAndSaveIfChanged(caretPos := getCaretPosition(e.textArea)); |
107 | |
108 | if (!full) ret; |
109 | S status = remoteText != null && neq(remoteText, text) ? "Changes. " : ""; |
110 | Pair<Int, S> p = testBracketHygieneExt(text); |
111 | status += p == null ? "Hygienic" : p.b; |
112 | silentStatus(trim(status)); |
113 | } |
114 | |
115 | void status(S s) { silentStatus(infoBoxAndReturn(s)); } |
116 | void silentStatus(S s) { e.setStatus(s); } |
117 | |
118 | void saveThen(final Runnable next) { |
119 | fS text = getText(); |
120 | if (editing instanceof S) { |
121 | status("Saving snippet..."); |
122 | thread { |
123 | fS page = editSnippet((S) editing, text); |
124 | remoteText = text; // TODO: check save result |
125 | status("Saved snippet: " + page); |
126 | awtCallF(next); |
127 | } |
128 | } else if (editing instanceof File) { |
129 | status("Saving file..."); |
130 | thread { |
131 | saveTextFile((File) editing, text); |
132 | remoteText = text; |
133 | status("Saved file"); |
134 | awtCallF(next); |
135 | } |
136 | } |
137 | } |
138 | |
139 | void _butterReload() { |
140 | time { butterReload((S) editing); } |
141 | infoBox("Reloaded in " + lastTiming_format100ms()); |
142 | } |
143 | |
144 | void transpile(final bool medium) { saveThen(r { _transpile(medium) }); } |
145 | |
146 | void _transpile(bool medium) { |
147 | status("Transpiling..."); |
148 | //jdisable(btnEleuReload); |
149 | |
150 | thread "Transpiling" { |
151 | try { |
152 | transpileOnServerWithErrorWindow((S) editing, medium, r { status("Transpiled OK!") }, |
153 | onError := voidfunc(S error) { |
154 | status("Transpilation error. " + error); |
155 | }); |
156 | } catch print e { |
157 | status("Transpilation problem. " + e); |
158 | } |
159 | //jenable(btnEleuReload); |
160 | } |
161 | } |
162 | |
163 | void _loadSnippet(S snippetID) { |
164 | _loadSnippet_noSet(snippetID); |
165 | e.textArea.setText(remoteText); |
166 | } |
167 | |
168 | void _loadSnippet_noSet(S snippetID) { |
169 | remoteText = loadSnippet(snippetID); |
170 | setAndSave('editing, snippetID); |
171 | lvEditing.set(snippetID); |
172 | frameTitle(e, snippetID + " - " + (snippetTitle = snippetTitle(snippetID))); |
173 | } |
174 | |
175 | void _loadFile(File f) { |
176 | _loadFile_noSet(f); |
177 | e.textArea.setText(remoteText); |
178 | } |
179 | |
180 | void _loadFile_noSet(File f) { |
181 | remoteText = loadTextFile(f); |
182 | setAndSave('editing, f); |
183 | lvEditing.set(f); |
184 | frameTitle(e, f2s(f)); |
185 | } |
186 | |
187 | void newText { |
188 | setAndSave(editing := null); |
189 | lvEditing.set(null); |
190 | remoteText = null; |
191 | S lastText = e.getText(); |
192 | if (nempty(lastText)) logQuotedWithDate("saved-texts.log", lastText); |
193 | e.setText(""); |
194 | frameTitle(e, programTitle()); |
195 | } |
196 | |
197 | void cleanMeUp { |
198 | update(false); |
199 | disposeWindow(e); |
200 | } |
201 | |
202 | void installAutoComplete { |
203 | if (installAutoComplete_first) installAutoComplete_first = false; |
204 | else sleep(autoCompleteRefreshDelay); // don't update too often |
205 | |
206 | //temp tempMiniLoadingAnim(); |
207 | |
208 | Set<S> set = concatListsToSet(allJavaKeywords(), standardFunctionNames(), deepWords(getText()), deepWords(snippetTitle)); |
209 | |
210 | if (eq(set, autoComplete_lastSet)) ret; |
211 | autoComplete_lastSet = set; |
212 | |
213 | final new DefaultCompletionProvider provider; |
214 | provider.addCompletions(map(s -> new BasicCompletion(provider, s), set)); |
215 | |
216 | swing { |
217 | if (autoCompletion == null) { |
218 | (autoCompletion = new AutoCompletion(provider)).install(e.textArea); |
219 | call(autoCompletion, 'setHideOnCompletionProviderChange, false); |
220 | } else |
221 | autoCompletion.setCompletionProvider(provider); |
222 | } |
223 | } |
224 | |
225 | void newWindow { |
226 | copyFields(this, new SFEditor(), 'fontSize).start(); |
227 | } |
228 | |
229 | void runIt { |
230 | if (editing instanceof S) |
231 | nohupJavax((S) editing); |
232 | } |
233 | |
234 | void saveAsSnippet { |
235 | final JTextField tfTitle = jtextfield(); |
236 | final JComboBox cbType = jComboBox_javaxTypes(); |
237 | showFormTitled("Save as new snippet", |
238 | "Title:", tfTitle, |
239 | "Type:", cbType, |
240 | r-thread { |
241 | loading { |
242 | int type = parseFirstInt(getSelectedItem(cbType)); |
243 | S title = getTextTrim(tfTitle); |
244 | S snippetID = createSnippet(getText(), title, type); |
245 | _loadSnippet_noSet(snippetID); |
246 | } |
247 | }); |
248 | } |
249 | |
250 | S getText() { ret e.getText(); } |
251 | } |
Began life as a copy of #1015560
download show line numbers debug dex old transpilations
Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv
No comments. add comment
Snippet ID: | #1015563 |
Snippet name: | SFEditor - Snippet/File Editor |
Eternal ID of this version: | #1015563/42 |
Text MD5: | bead7eaca9502b5e1e68dfa0a67955e6 |
Transpilation MD5: | f25c105af0a32a4dc55c87de62e48d32 |
Author: | stefan |
Category: | javax / gui |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2020-06-14 17:40:35 |
Source code size: | 7520 bytes / 251 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 493 / 1126 |
Version history: | 41 change(s) |
Referenced in: | [show references] |