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: | 734 / 1411 |
| Version history: | 41 change(s) |
| Referenced in: | [show references] |