28
28
29
29
import java .awt .BorderLayout ;
30
30
import java .awt .Font ;
31
+ import java .awt .Toolkit ;
31
32
import java .awt .event .ActionEvent ;
32
33
import java .awt .event .ActionListener ;
34
+ import java .awt .event .InputEvent ;
35
+ import java .awt .event .KeyEvent ;
33
36
import java .awt .event .MouseWheelListener ;
34
37
import java .awt .event .MouseWheelEvent ;
35
38
36
39
import java .io .IOException ;
37
40
38
41
import javax .swing .Action ;
39
42
import javax .swing .BorderFactory ;
43
+ import javax .swing .Icon ;
44
+ import javax .swing .InputMap ;
45
+ import javax .swing .JComponent ;
40
46
import javax .swing .JMenuItem ;
41
47
import javax .swing .JPanel ;
42
48
import javax .swing .JPopupMenu ;
49
+ import javax .swing .KeyStroke ;
50
+ import javax .swing .SwingUtilities ;
43
51
import javax .swing .ToolTipManager ;
52
+ import javax .swing .UIManager ;
44
53
import javax .swing .border .MatteBorder ;
45
54
import javax .swing .event .PopupMenuEvent ;
46
55
import javax .swing .event .PopupMenuListener ;
52
61
53
62
import static java .nio .file .StandardWatchEventKinds .*;
54
63
import java .nio .file .WatchService ;
64
+ import java .util .ArrayList ;
65
+ import java .util .List ;
55
66
import java .nio .file .WatchKey ;
56
67
import java .nio .file .WatchEvent ;
57
68
import java .nio .file .FileSystems ;
62
73
import org .fife .ui .autocomplete .AutoCompletion ;
63
74
import org .fife .ui .autocomplete .DefaultCompletionProvider ;
64
75
import org .fife .ui .rsyntaxtextarea .RSyntaxDocument ;
76
+ import org .fife .ui .rsyntaxtextarea .RSyntaxTextArea ;
65
77
import org .fife .ui .rsyntaxtextarea .RSyntaxTextAreaEditorKit ;
66
78
import org .fife .ui .rsyntaxtextarea .RSyntaxUtilities ;
67
79
import org .fife .ui .rtextarea .Gutter ;
80
+ import org .fife .ui .rtextarea .GutterIconInfo ;
81
+ import org .fife .ui .rtextarea .RTADefaultInputMap ;
82
+ import org .fife .ui .rtextarea .RTextArea ;
83
+ import org .fife .ui .rtextarea .RTextAreaEditorKit ;
68
84
import org .fife .ui .rtextarea .RTextScrollPane ;
85
+ import org .fife .ui .rtextarea .RecordableTextAction ;
69
86
70
87
import cc .arduino .UpdatableBoardsLibsFakeURLsHandler ;
71
88
import cc .arduino .autocomplete .ClangCompletionProvider ;
89
+ import cc .arduino .autocomplete .CompletionType ;
72
90
import cc .arduino .autocomplete .CompletionsRenderer ;
73
91
import processing .app .helpers .DocumentTextChangeListener ;
92
+ import processing .app .helpers .PreferencesMap ;
74
93
import processing .app .syntax .ArduinoTokenMakerFactory ;
75
94
import processing .app .syntax .PdeKeywords ;
76
95
import processing .app .syntax .SketchTextArea ;
@@ -154,6 +173,8 @@ private RSyntaxDocument createDocument(String contents) {
154
173
return document ;
155
174
}
156
175
176
+ public static final String rtaNextBookmarkAction = "RTA.NextBookmarkAction" ;
177
+
157
178
private RTextScrollPane createScrollPane (SketchTextArea textArea ) throws IOException {
158
179
RTextScrollPane scrollPane = new RTextScrollPane (textArea , true );
159
180
scrollPane .setBorder (new MatteBorder (0 , 6 , 0 , 0 , Theme .getColor ("editor.bgcolor" )));
@@ -162,13 +183,118 @@ private RTextScrollPane createScrollPane(SketchTextArea textArea) throws IOExcep
162
183
scrollPane .setIconRowHeaderEnabled (false );
163
184
164
185
Gutter gutter = scrollPane .getGutter ();
165
- gutter .setBookmarkingEnabled (false );
166
- //gutter.setBookmarkIcon(CompletionsRenderer.getIcon(CompletionType.TEMPLATE));
186
+
187
+ if (PreferencesData .getBoolean ("editor.bookmarks" )) {
188
+ gutter .setBookmarkingEnabled (true );
189
+ gutter .setBookmarkIcon (CompletionsRenderer .getIcon (CompletionType .FUNCTION ));
190
+ InputMap map = SwingUtilities .getUIInputMap (textArea , JComponent .WHEN_FOCUSED );
191
+ NextBookmarkAction action = new NextBookmarkAction (rtaNextBookmarkAction );
192
+ map .put (KeyStroke .getKeyStroke (KeyEvent .VK_F3 , 0 ), action );
193
+ SwingUtilities .replaceUIInputMap (textArea ,JComponent .WHEN_FOCUSED ,map );
194
+ }
195
+
167
196
gutter .setIconRowHeaderInheritsGutterBackground (true );
168
197
169
198
return scrollPane ;
170
199
}
171
200
201
+ public class GutterIconInfoTabs {
202
+ GutterIconInfo bookmark ;
203
+ SketchFile file ;
204
+ RTextArea textArea ;
205
+
206
+ public String toString ( ) {
207
+ return "File:" + file .getFileName () + " -- Line:" + bookmark .getMarkedOffset ();
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Action that moves the caret to the next bookmark.
213
+ */
214
+ public class NextBookmarkAction extends RecordableTextAction {
215
+
216
+ public NextBookmarkAction (String name ) {
217
+ super (name );
218
+ }
219
+
220
+ @ Override
221
+ public void actionPerformedImpl (ActionEvent e , RTextArea textArea ) {
222
+
223
+ Gutter gutter = RSyntaxUtilities .getGutter (textArea );
224
+
225
+ List <GutterIconInfoTabs > bookmarks = new ArrayList <GutterIconInfoTabs >();
226
+
227
+ try {
228
+
229
+ for (EditorTab tab : editor .getTabs ()) {
230
+ gutter = RSyntaxUtilities .getGutter (tab .getTextArea ());
231
+
232
+ if (gutter !=null ) {
233
+ GutterIconInfo [] tabBookmarks = gutter .getBookmarks ();
234
+ for (GutterIconInfo element : tabBookmarks ) {
235
+ GutterIconInfoTabs bookmark = new GutterIconInfoTabs ();
236
+ bookmark .file = tab .getSketchFile ();
237
+ bookmark .bookmark = element ;
238
+ bookmark .textArea = tab .getTextArea ();
239
+ bookmarks .add (bookmark );
240
+ }
241
+ }
242
+ }
243
+
244
+ if (bookmarks .size ()==0 ) {
245
+ UIManager .getLookAndFeel ().
246
+ provideErrorFeedback (textArea );
247
+ return ;
248
+ }
249
+
250
+ GutterIconInfoTabs moveTo = null ;
251
+ int curLine = textArea .getCaretLineNumber ();
252
+
253
+ for (int i =0 ; i <bookmarks .size (); i ++) {
254
+ GutterIconInfo bookmark = bookmarks .get (i ).bookmark ;
255
+ int offs = bookmark .getMarkedOffset ();
256
+ int line = 0 ;
257
+ int curTabIndex = editor .getCurrentTabIndex ();
258
+ int bookmarkTabIndex = editor .findTabIndex (bookmarks .get (i ).file );
259
+ if (curTabIndex == bookmarkTabIndex ) {
260
+ line = textArea .getLineOfOffset (offs );
261
+ }
262
+ if ((curTabIndex == bookmarkTabIndex && line >curLine ) || (curTabIndex < bookmarkTabIndex )) {
263
+ moveTo = bookmarks .get (i );
264
+ break ;
265
+ }
266
+ }
267
+ if (moveTo ==null ) { // Loop back to beginning
268
+ moveTo = bookmarks .get (0 );
269
+ }
270
+
271
+ editor .selectTab (editor .findTabIndex (moveTo .file ));
272
+
273
+ int offs = moveTo .bookmark .getMarkedOffset ();
274
+ if (moveTo .textArea instanceof RSyntaxTextArea ) {
275
+ RSyntaxTextArea rsta = (RSyntaxTextArea )moveTo .textArea ;
276
+ if (rsta .isCodeFoldingEnabled ()) {
277
+ rsta .getFoldManager ().
278
+ ensureOffsetNotInClosedFold (offs );
279
+ }
280
+ }
281
+ int line = moveTo .textArea .getLineOfOffset (offs );
282
+ offs = moveTo .textArea .getLineStartOffset (line );
283
+ moveTo .textArea .setCaretPosition (offs );
284
+
285
+ } catch (BadLocationException ble ) { // Never happens
286
+ UIManager .getLookAndFeel ().
287
+ provideErrorFeedback (textArea );
288
+ ble .printStackTrace ();
289
+ }
290
+ }
291
+
292
+ @ Override
293
+ public String getMacroID () {
294
+ return getName ();
295
+ }
296
+ }
297
+
172
298
private SketchTextArea createTextArea (RSyntaxDocument document )
173
299
throws IOException {
174
300
final SketchTextArea textArea = new SketchTextArea (document , editor .base .getPdeKeywords ());
0 commit comments