Skip to content

Commit 485e955

Browse files
committed
Initial implementation of bookmarks
Toggle on the left, find next with F3
1 parent 8438552 commit 485e955

File tree

2 files changed

+137
-2
lines changed

2 files changed

+137
-2
lines changed

app/src/cc/arduino/view/preferences/Preferences.java

+9
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ private void initComponents() {
130130
checkboxesContainer = new javax.swing.JPanel();
131131
displayLineNumbersBox = new javax.swing.JCheckBox();
132132
enableCodeFoldingBox = new javax.swing.JCheckBox();
133+
enableBookmarks = new javax.swing.JCheckBox();
133134
verifyUploadBox = new javax.swing.JCheckBox();
134135
externalEditorBox = new javax.swing.JCheckBox();
135136
cacheCompiledCore = new javax.swing.JCheckBox();
@@ -256,6 +257,9 @@ public void mouseEntered(java.awt.event.MouseEvent evt) {
256257
enableCodeFoldingBox.setText(tr("Enable Code Folding"));
257258
checkboxesContainer.add(enableCodeFoldingBox);
258259

260+
enableBookmarks.setText(tr("Enable Bookmarks"));
261+
checkboxesContainer.add(enableBookmarks);
262+
259263
verifyUploadBox.setText(tr("Verify code after upload"));
260264
checkboxesContainer.add(verifyUploadBox);
261265

@@ -728,6 +732,7 @@ private void autoScaleCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//
728732
private javax.swing.JLabel comboWarningsLabel;
729733
private javax.swing.JCheckBox displayLineNumbersBox;
730734
private javax.swing.JCheckBox enableCodeFoldingBox;
735+
private javax.swing.JCheckBox enableBookmarks;
731736
private javax.swing.JButton extendedAdditionalUrlFieldWindow;
732737
private javax.swing.JCheckBox externalEditorBox;
733738
private javax.swing.JCheckBox cacheCompiledCore;
@@ -828,6 +833,8 @@ private void savePreferencesData() {
828833

829834
PreferencesData.setBoolean("editor.code_folding", enableCodeFoldingBox.isSelected());
830835

836+
PreferencesData.setBoolean("editor.bookmarks", enableBookmarks.isSelected());
837+
831838
PreferencesData.setBoolean("upload.verify", verifyUploadBox.isSelected());
832839

833840
PreferencesData.setBoolean("editor.save_on_verify", saveVerifyUploadBox.isSelected());
@@ -902,6 +909,8 @@ private void showPreferencesData() {
902909

903910
enableCodeFoldingBox.setSelected(PreferencesData.getBoolean("editor.code_folding"));
904911

912+
enableBookmarks.setSelected(PreferencesData.getBoolean("editor.bookmarks"));
913+
905914
verifyUploadBox.setSelected(PreferencesData.getBoolean("upload.verify"));
906915

907916
externalEditorBox.setSelected(PreferencesData.getBoolean("editor.external"));

app/src/processing/app/EditorTab.java

+128-2
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,28 @@
2828

2929
import java.awt.BorderLayout;
3030
import java.awt.Font;
31+
import java.awt.Toolkit;
3132
import java.awt.event.ActionEvent;
3233
import java.awt.event.ActionListener;
34+
import java.awt.event.InputEvent;
35+
import java.awt.event.KeyEvent;
3336
import java.awt.event.MouseWheelListener;
3437
import java.awt.event.MouseWheelEvent;
3538

3639
import java.io.IOException;
3740

3841
import javax.swing.Action;
3942
import javax.swing.BorderFactory;
43+
import javax.swing.Icon;
44+
import javax.swing.InputMap;
45+
import javax.swing.JComponent;
4046
import javax.swing.JMenuItem;
4147
import javax.swing.JPanel;
4248
import javax.swing.JPopupMenu;
49+
import javax.swing.KeyStroke;
50+
import javax.swing.SwingUtilities;
4351
import javax.swing.ToolTipManager;
52+
import javax.swing.UIManager;
4453
import javax.swing.border.MatteBorder;
4554
import javax.swing.event.PopupMenuEvent;
4655
import javax.swing.event.PopupMenuListener;
@@ -52,6 +61,8 @@
5261

5362
import static java.nio.file.StandardWatchEventKinds.*;
5463
import java.nio.file.WatchService;
64+
import java.util.ArrayList;
65+
import java.util.List;
5566
import java.nio.file.WatchKey;
5667
import java.nio.file.WatchEvent;
5768
import java.nio.file.FileSystems;
@@ -62,15 +73,23 @@
6273
import org.fife.ui.autocomplete.AutoCompletion;
6374
import org.fife.ui.autocomplete.DefaultCompletionProvider;
6475
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
76+
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
6577
import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaEditorKit;
6678
import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
6779
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;
6884
import org.fife.ui.rtextarea.RTextScrollPane;
85+
import org.fife.ui.rtextarea.RecordableTextAction;
6986

7087
import cc.arduino.UpdatableBoardsLibsFakeURLsHandler;
7188
import cc.arduino.autocomplete.ClangCompletionProvider;
89+
import cc.arduino.autocomplete.CompletionType;
7290
import cc.arduino.autocomplete.CompletionsRenderer;
7391
import processing.app.helpers.DocumentTextChangeListener;
92+
import processing.app.helpers.PreferencesMap;
7493
import processing.app.syntax.ArduinoTokenMakerFactory;
7594
import processing.app.syntax.PdeKeywords;
7695
import processing.app.syntax.SketchTextArea;
@@ -154,6 +173,8 @@ private RSyntaxDocument createDocument(String contents) {
154173
return document;
155174
}
156175

176+
public static final String rtaNextBookmarkAction = "RTA.NextBookmarkAction";
177+
157178
private RTextScrollPane createScrollPane(SketchTextArea textArea) throws IOException {
158179
RTextScrollPane scrollPane = new RTextScrollPane(textArea, true);
159180
scrollPane.setBorder(new MatteBorder(0, 6, 0, 0, Theme.getColor("editor.bgcolor")));
@@ -162,13 +183,118 @@ private RTextScrollPane createScrollPane(SketchTextArea textArea) throws IOExcep
162183
scrollPane.setIconRowHeaderEnabled(false);
163184

164185
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+
167196
gutter.setIconRowHeaderInheritsGutterBackground(true);
168197

169198
return scrollPane;
170199
}
171200

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+
172298
private SketchTextArea createTextArea(RSyntaxDocument document)
173299
throws IOException {
174300
final SketchTextArea textArea = new SketchTextArea(document, editor.base.getPdeKeywords());

0 commit comments

Comments
 (0)