Skip to content

Commit 132de74

Browse files
committed
Add the ability to manually format Javascript code (#87)
Signed-off-by: sbraconnier <simonbraconnier@gmail.com>
1 parent 7c53aef commit 132de74

File tree

9 files changed

+4202
-2486
lines changed

9 files changed

+4202
-2486
lines changed

client/src/com/mirth/connect/client/ui/components/rsta/MirthRSyntaxTextArea.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import com.mirth.connect.client.ui.components.rsta.actions.ExpandFoldAction;
6363
import com.mirth.connect.client.ui.components.rsta.actions.FindNextAction;
6464
import com.mirth.connect.client.ui.components.rsta.actions.FindReplaceAction;
65+
import com.mirth.connect.client.ui.components.rsta.actions.FormatCodeAction;
6566
import com.mirth.connect.client.ui.components.rsta.actions.GoToMatchingBracketAction;
6667
import com.mirth.connect.client.ui.components.rsta.actions.HorizontalPageAction;
6768
import com.mirth.connect.client.ui.components.rsta.actions.InsertBreakAction;
@@ -127,6 +128,9 @@ public class MirthRSyntaxTextArea extends RSyntaxTextArea implements MirthTextIn
127128
private CustomJCheckBoxMenuItem showWhitespaceMenuItem;
128129
private CustomJCheckBoxMenuItem showLineEndingsMenuItem;
129130
private CustomJCheckBoxMenuItem wrapLinesMenuItem;
131+
private JMenu codeMenu;
132+
private CustomMenuItem formatCodeMenuItem;
133+
private CustomMenuItem toggleCommentMenuItem;
130134
private JMenu macroMenu;
131135
private CustomMenuItem beginMacroMenuItem;
132136
private CustomMenuItem endMacroMenuItem;
@@ -228,6 +232,9 @@ public void keyPressed(KeyEvent e) {
228232
showWhitespaceMenuItem = new CustomJCheckBoxMenuItem(this, new ShowWhitespaceAction(this), ActionInfo.DISPLAY_SHOW_WHITESPACE);
229233
showLineEndingsMenuItem = new CustomJCheckBoxMenuItem(this, new ShowLineEndingsAction(this), ActionInfo.DISPLAY_SHOW_LINE_ENDINGS);
230234
wrapLinesMenuItem = new CustomJCheckBoxMenuItem(this, new WrapLinesAction(this), ActionInfo.DISPLAY_WRAP_LINES);
235+
codeMenu = new JMenu("Code");
236+
formatCodeMenuItem = new CustomMenuItem(this, new FormatCodeAction(this), ActionInfo.FORMAT_CODE);
237+
toggleCommentMenuItem = new CustomMenuItem(this, new ToggleCommentAction(this), ActionInfo.TOGGLE_COMMENT);
231238
macroMenu = new JMenu("Macro");
232239
beginMacroMenuItem = new CustomMenuItem(this, new BeginMacroAction(), ActionInfo.MACRO_BEGIN);
233240
endMacroMenuItem = new CustomMenuItem(this, new EndMacroAction(), ActionInfo.MACRO_END);
@@ -239,7 +246,8 @@ public void keyPressed(KeyEvent e) {
239246
getActionMap().put(ActionInfo.DELETE_LINE.getActionMapKey(), new DeleteLineAction());
240247
getActionMap().put(ActionInfo.JOIN_LINE.getActionMapKey(), new JoinLineAction());
241248
getActionMap().put(ActionInfo.GO_TO_MATCHING_BRACKET.getActionMapKey(), new GoToMatchingBracketAction());
242-
getActionMap().put(ActionInfo.TOGGLE_COMMENT.getActionMapKey(), new ToggleCommentAction());
249+
getActionMap().put(ActionInfo.FORMAT_CODE.getActionMapKey(), new FormatCodeAction(this));
250+
getActionMap().put(ActionInfo.TOGGLE_COMMENT.getActionMapKey(), new ToggleCommentAction(this));
243251
getActionMap().put(ActionInfo.DOCUMENT_START.getActionMapKey(), new DocumentStartAction(false));
244252
getActionMap().put(ActionInfo.DOCUMENT_SELECT_START.getActionMapKey(), new DocumentStartAction(true));
245253
getActionMap().put(ActionInfo.DOCUMENT_END.getActionMapKey(), new DocumentEndAction(false));
@@ -489,6 +497,11 @@ protected JPopupMenu createPopupMenu() {
489497
menu.add(displayMenu);
490498
menu.addSeparator();
491499

500+
codeMenu.add(formatCodeMenuItem);
501+
codeMenu.add(toggleCommentMenuItem);
502+
menu.add(codeMenu);
503+
menu.addSeparator();
504+
492505
macroMenu.add(beginMacroMenuItem);
493506
macroMenu.add(endMacroMenuItem);
494507
macroMenu.add(playbackMacroMenuItem);
@@ -514,6 +527,8 @@ protected void configurePopupMenu(JPopupMenu popupMenu) {
514527
findNextMenuItem.setEnabled(findNextMenuItem.getAction().isEnabled() && CollectionUtils.isNotEmpty(rstaPreferences.getFindReplaceProperties().getFindHistory()));
515528
clearMarkedOccurrencesMenuItem.setEnabled(clearMarkedOccurrencesMenuItem.getAction().isEnabled() && canType && ((RSyntaxTextAreaHighlighter) getHighlighter()).getMarkAllHighlightCount() > 0);
516529
foldingMenu.setEnabled(getFoldManager().isCodeFoldingSupportedAndEnabled());
530+
formatCodeMenuItem.setEnabled(formatCodeMenuItem.getAction().isEnabled());
531+
toggleCommentMenuItem.setEnabled(toggleCommentMenuItem.getAction().isEnabled());
517532
beginMacroMenuItem.setEnabled(!isRecordingMacro());
518533
endMacroMenuItem.setEnabled(isRecordingMacro());
519534
playbackMacroMenuItem.setEnabled(!isRecordingMacro() && getCurrentMacro() != null);
@@ -533,6 +548,8 @@ protected void configurePopupMenu(JPopupMenu popupMenu) {
533548
collapseAllFoldsMenuItem.updateAccelerator();
534549
collapseAllCommentFoldsMenuItem.updateAccelerator();
535550
expandAllFoldsMenuItem.updateAccelerator();
551+
formatCodeMenuItem.updateAccelerator();
552+
toggleCommentMenuItem.updateAccelerator();
536553
beginMacroMenuItem.updateAccelerator();
537554
endMacroMenuItem.updateAccelerator();
538555
playbackMacroMenuItem.updateAccelerator();

client/src/com/mirth/connect/client/ui/components/rsta/MirthRSyntaxTextArea.properties

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ TOGGLE_COMMENT.Name=Toggle Comment
118118
TOGGLE_COMMENT.Desc=Comments / uncomments the current selected line(s).
119119
TOGGLE_COMMENT.Toggle=false
120120

121+
FORMAT_CODE.Mnemonic=F
122+
FORMAT_CODE.Name=Format
123+
FORMAT_CODE.Desc=Format the current script / selected line(s).
124+
FORMAT_CODE.Toggle=false
125+
121126
VIEW_USER_API.Mnemonic=V
122127
VIEW_USER_API.Name=View User API
123128
VIEW_USER_API.Desc=Opens up the User API Javadoc in a browser.

client/src/com/mirth/connect/client/ui/components/rsta/RSTAPreferences.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ private void setDefaultKeyStrokeMap() {
234234
putKeyStroke(ActionInfo.FOLD_EXPAND_ALL, KeyEvent.VK_MULTIPLY, defaultModifier);
235235
putKeyStroke(ActionInfo.GO_TO_MATCHING_BRACKET, KeyEvent.VK_OPEN_BRACKET, defaultModifier);
236236
putKeyStroke(ActionInfo.TOGGLE_COMMENT, KeyEvent.VK_SLASH, defaultModifier);
237+
putKeyStroke(ActionInfo.FORMAT_CODE, KeyEvent.VK_F, ctrl + shift);
237238
putKeyStroke(ActionInfo.AUTO_COMPLETE, KeyEvent.VK_SPACE, ctrl);
238239

239240
if (isOSX) {

client/src/com/mirth/connect/client/ui/components/rsta/actions/ActionInfo.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public enum ActionInfo {
4040
DISPLAY_WRAP_LINES ("mirth-wrap-lines"),
4141
GO_TO_MATCHING_BRACKET (RSyntaxTextAreaEditorKit.rstaGoToMatchingBracketAction),
4242
TOGGLE_COMMENT (RSyntaxTextAreaEditorKit.rstaToggleCommentAction),
43+
FORMAT_CODE ("mirth-format-code"),
4344
VIEW_USER_API ("mirth-view-user-api"),
4445
AUTO_COMPLETE ("AutoComplete"),
4546
DOCUMENT_START (DefaultEditorKit.beginAction),
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Copyright (c) Mirth Corporation. All rights reserved.
3+
*
4+
* http://www.mirthcorp.com
5+
*
6+
* The software in this package is published under the terms of the MPL license a copy of which has
7+
* been included with this distribution in the LICENSE.txt file.
8+
*/
9+
10+
package com.mirth.connect.client.ui.components.rsta.actions;
11+
12+
import java.awt.event.ActionEvent;
13+
14+
import javax.swing.UIManager;
15+
import javax.swing.text.BadLocationException;
16+
import javax.swing.text.Caret;
17+
import javax.swing.text.Element;
18+
19+
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
20+
21+
import com.mirth.connect.client.ui.components.rsta.MirthRSyntaxTextArea;
22+
import com.mirth.connect.util.JavaScriptSharedUtil;
23+
24+
public class FormatCodeAction extends MirthRecordableTextAction {
25+
26+
public FormatCodeAction(MirthRSyntaxTextArea textArea) {
27+
super(textArea, ActionInfo.FORMAT_CODE);
28+
}
29+
30+
@Override
31+
public void actionPerformedImpl(ActionEvent evt) {
32+
33+
if (!textArea.isEditable() || !textArea.isEnabled()) {
34+
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
35+
return;
36+
}
37+
38+
Caret c = textArea.getCaret();
39+
int start = Math.min(c.getDot(), c.getMark());
40+
int end = Math.max(c.getDot(), c.getMark());
41+
if (start == end) {
42+
formatAll();
43+
} else {
44+
formatRange(start, end);
45+
}
46+
47+
}
48+
49+
@Override
50+
public boolean isEnabled() {
51+
return textArea.isEditable() && textArea.isEnabled();
52+
}
53+
54+
private void formatAll() {
55+
56+
String code = textArea.getText();
57+
formatAndReplace(code, 0, code.length());
58+
}
59+
60+
private void formatRange(int start, int end) {
61+
62+
// We want to format all the lines of the selection (not only the selected text)
63+
64+
try {
65+
RSyntaxDocument doc = (RSyntaxDocument) textArea.getDocument();
66+
Element map = doc.getDefaultRootElement();
67+
68+
// Get the lines indexes from the selected text indexes.
69+
int startLine = map.getElementIndex(start);
70+
int endLine = map.getElementIndex(end);
71+
72+
int replaceRangeStart = 0;
73+
int replaceRangeEnd = 0;
74+
75+
// Build a string from the selected lines.
76+
StringBuilder sb = new StringBuilder();
77+
for (int line = startLine; line <= endLine; line++) {
78+
Element elem = map.getElement(line);
79+
80+
int startOffset = elem.getStartOffset();
81+
int endOffset = elem.getEndOffset() - 1;
82+
83+
// Save the start index of the first line for the final replacement.
84+
if (line == startLine) {
85+
replaceRangeStart = startOffset;
86+
}
87+
88+
// Save the end index of the last line for the final replacement.
89+
if (line == endLine) {
90+
replaceRangeEnd = endOffset;
91+
}
92+
93+
sb.append(doc.getText(startOffset, endOffset - startOffset + 1));
94+
}
95+
96+
// Format the code and replace the selected lines.
97+
formatAndReplace(sb.toString(), replaceRangeStart, replaceRangeEnd);
98+
99+
} catch (BadLocationException ble) {
100+
ble.printStackTrace();
101+
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
102+
}
103+
}
104+
105+
private void formatAndReplace(String code, int start, int end) {
106+
107+
String formattedCode = JavaScriptSharedUtil.prettyPrint(code);
108+
textArea.replaceRange(formattedCode, start, end);
109+
textArea.setCaretPosition(start);
110+
}
111+
}

client/src/com/mirth/connect/client/ui/components/rsta/actions/ToggleCommentAction.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,16 @@
1313

1414
public class ToggleCommentAction extends org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaEditorKit.ToggleCommentAction {
1515

16-
public ToggleCommentAction() {
16+
protected MirthRSyntaxTextArea textArea;
17+
18+
public ToggleCommentAction(MirthRSyntaxTextArea textArea) {
1719
setProperties(MirthRSyntaxTextArea.getResourceBundle(), ActionInfo.TOGGLE_COMMENT.toString());
20+
21+
this.textArea = textArea;
22+
}
23+
24+
@Override
25+
public boolean isEnabled() {
26+
return textArea.isEditable() && textArea.isEnabled();
1827
}
1928
}

server/src/com/mirth/connect/util/JavaScriptSharedUtil.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,14 +196,14 @@ public static String prettyPrint(String script) {
196196
private static ScriptableObject getFormatterScope() {
197197
Context context = getGlobalContextForValidation();
198198
InputStream is = null;
199-
199+
200200
try {
201-
is = JavaScriptSharedUtil.class.getResourceAsStream("beautify-1.6.8.js");
201+
is = JavaScriptSharedUtil.class.getResourceAsStream("beautify-1.15.3.js");
202202
String script = IOUtils.toString(is);
203203
ScriptableObject scope = context.initStandardObjects();
204204
context.evaluateString(scope, "var global = {};", UUID.randomUUID().toString(), 1, null);
205205
context.evaluateString(scope, script, UUID.randomUUID().toString(), 1, null);
206-
context.evaluateString(scope, "var opts = { 'e4x': true };", UUID.randomUUID().toString(), 1, null);
206+
context.evaluateString(scope, "var opts = { 'e4x': true, 'indent_with_tabs': true };", UUID.randomUUID().toString(), 1, null);
207207
return scope;
208208
} catch (Exception e) {
209209
logger.error("Failed to load beautify library.");

0 commit comments

Comments
 (0)