Skip to content

Commit e196ecf

Browse files
authored
Merge pull request #145 from webratio/pr/format-on-save
Format on Save
2 parents f461d66 + cceac34 commit e196ecf

16 files changed

+520
-49
lines changed

eclipse/jsdt/ts.eclipse.ide.jsdt.ui/src/ts/eclipse/ide/jsdt/internal/ui/editor/TypeScriptDocumentProvider.java

Lines changed: 143 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,53 @@
77
*
88
* Contributors:
99
* Angelo Zerr <[email protected]> - initial API and implementation
10+
* Lorenzo Dalla Vecchia <[email protected]> - added save actions
1011
*/
1112
package ts.eclipse.ide.jsdt.internal.ui.editor;
1213

14+
import java.lang.reflect.InvocationTargetException;
15+
import java.util.ArrayList;
16+
import java.util.List;
17+
18+
import org.eclipse.core.resources.IFile;
19+
import org.eclipse.core.resources.IProject;
20+
import org.eclipse.core.resources.ProjectScope;
21+
import org.eclipse.core.resources.ResourcesPlugin;
1322
import org.eclipse.core.runtime.CoreException;
23+
import org.eclipse.core.runtime.IProgressMonitor;
24+
import org.eclipse.core.runtime.IStatus;
25+
import org.eclipse.core.runtime.NullProgressMonitor;
26+
import org.eclipse.core.runtime.Status;
27+
import org.eclipse.core.runtime.SubMonitor;
28+
import org.eclipse.core.runtime.preferences.DefaultScope;
29+
import org.eclipse.core.runtime.preferences.InstanceScope;
30+
import org.eclipse.jface.preference.IPreferenceStore;
1431
import org.eclipse.jface.text.IDocument;
32+
import org.eclipse.ltk.core.refactoring.Change;
33+
import org.eclipse.ltk.core.refactoring.CompositeChange;
34+
import org.eclipse.ltk.core.refactoring.IUndoManager;
35+
import org.eclipse.ltk.core.refactoring.PerformChangeOperation;
36+
import org.eclipse.ltk.core.refactoring.RefactoringCore;
37+
import org.eclipse.ltk.core.refactoring.TextFileChange;
38+
import org.eclipse.ui.IFileEditorInput;
1539
import org.eclipse.ui.editors.text.ForwardingDocumentProvider;
1640
import org.eclipse.ui.editors.text.TextFileDocumentProvider;
41+
import org.eclipse.ui.preferences.ScopedPreferenceStore;
42+
import org.eclipse.ui.texteditor.ChainedPreferenceStore;
1743
import org.eclipse.ui.texteditor.IDocumentProvider;
1844
import org.eclipse.wst.jsdt.internal.ui.javaeditor.JavaDocumentSetupParticipant;
1945
import org.eclipse.wst.jsdt.ui.text.IJavaScriptPartitions;
2046

47+
import ts.client.CodeEdit;
48+
import ts.eclipse.ide.core.TypeScriptCorePlugin;
49+
import ts.eclipse.ide.core.resources.IIDETypeScriptFile;
50+
import ts.eclipse.ide.core.resources.IIDETypeScriptProject;
51+
import ts.eclipse.ide.core.utils.DocumentUtils;
52+
import ts.eclipse.ide.core.utils.TypeScriptResourceUtil;
53+
import ts.eclipse.ide.jsdt.internal.ui.JSDTTypeScriptUIPlugin;
54+
import ts.eclipse.ide.ui.TypeScriptUIPlugin;
55+
import ts.eclipse.ide.ui.preferences.TypeScriptUIPreferenceConstants;
56+
2157
public class TypeScriptDocumentProvider extends TextFileDocumentProvider {
2258

2359
public TypeScriptDocumentProvider() {
@@ -26,11 +62,115 @@ public TypeScriptDocumentProvider() {
2662
new JavaDocumentSetupParticipant(), provider);
2763
setParentDocumentProvider(provider);
2864
}
29-
65+
3066
@Override
3167
protected DocumentProviderOperation createSaveOperation(Object element, IDocument document, boolean overwrite)
3268
throws CoreException {
33-
// TODO Auto-generated method stub
34-
return super.createSaveOperation(element, document, overwrite);
69+
final DocumentProviderOperation delegate = super.createSaveOperation(element, document, overwrite);
70+
return new DocumentProviderOperation() {
71+
@Override
72+
protected void execute(IProgressMonitor monitor) throws CoreException {
73+
SubMonitor progress = SubMonitor.convert(monitor, 10);
74+
75+
// Retrieve the file that is being saved
76+
IFile file = getFile(element);
77+
if (file == null) {
78+
return;
79+
}
80+
IPreferenceStore preferenceStore = createProjectSpecificPreferenceStore(file.getProject());
81+
boolean runSaveActions = preferenceStore
82+
.getBoolean(TypeScriptUIPreferenceConstants.EDITOR_SAVE_ACTIONS);
83+
84+
try {
85+
delegate.run(progress.newChild(8));
86+
if (runSaveActions) {
87+
try {
88+
performSaveActions(file, document, progress.newChild(2), preferenceStore);
89+
} catch (Exception e) {
90+
JSDTTypeScriptUIPlugin.log(e);
91+
}
92+
} else {
93+
progress.setWorkRemaining(0);
94+
}
95+
} catch (InterruptedException e) {
96+
Thread.currentThread().interrupt();
97+
} catch (InvocationTargetException e) {
98+
throw new CoreException(
99+
new Status(IStatus.ERROR, TypeScriptCorePlugin.PLUGIN_ID, "Error while saving " + file, e));
100+
}
101+
}
102+
};
103+
}
104+
105+
private void performSaveActions(IFile file, IDocument document, IProgressMonitor monitor,
106+
IPreferenceStore preferenceStore) {
107+
boolean runFormat = preferenceStore.getBoolean(TypeScriptUIPreferenceConstants.EDITOR_SAVE_ACTIONS_FORMAT);
108+
SubMonitor progress = SubMonitor.convert(monitor, (runFormat ? 10 : 0));
109+
if (!runFormat) {
110+
return;
111+
}
112+
113+
IUndoManager manager = RefactoringCore.getUndoManager();
114+
115+
CompositeChange saveActionsChange = new CompositeChange("Save Actions");
116+
List<Change> undoChanges = new ArrayList<>();
117+
boolean success = false;
118+
try {
119+
manager.aboutToPerformChange(saveActionsChange);
120+
121+
// Format the file contents
122+
if (runFormat) {
123+
TextFileChange change = new TextFileChange("Format", file);
124+
try {
125+
IIDETypeScriptProject tsProject = TypeScriptResourceUtil.getTypeScriptProject(file.getProject());
126+
final IIDETypeScriptFile tsFile = tsProject.openFile(file, document);
127+
List<CodeEdit> codeEdits = tsFile.format(0, document.getLength()).get();
128+
change.setEdit(DocumentUtils.toTextEdit(codeEdits, document));
129+
change.initializeValidationData(new NullProgressMonitor());
130+
PerformChangeOperation performChangeOperation = new PerformChangeOperation(change);
131+
ResourcesPlugin.getWorkspace().run(performChangeOperation, progress.newChild(10));
132+
Change undoChange = performChangeOperation.getUndoChange();
133+
if (undoChange != null) {
134+
undoChanges.add(undoChange);
135+
}
136+
} catch (Exception e) {
137+
JSDTTypeScriptUIPlugin.log(e);
138+
}
139+
}
140+
141+
success = true;
142+
} finally {
143+
manager.changePerformed(saveActionsChange, success);
144+
}
145+
146+
// Add an undo change if possible
147+
if (!undoChanges.isEmpty()) {
148+
manager.addUndo(saveActionsChange.getName(), new CompositeChange(saveActionsChange.getName(),
149+
undoChanges.toArray(new Change[undoChanges.size()])));
150+
}
151+
}
152+
153+
private static IPreferenceStore createProjectSpecificPreferenceStore(IProject project) {
154+
List<IPreferenceStore> stores = new ArrayList<IPreferenceStore>();
155+
if (project != null) {
156+
stores.add(new EclipsePreferencesAdapter(new ProjectScope(project), TypeScriptUIPlugin.PLUGIN_ID));
157+
stores.add(new EclipsePreferencesAdapter(new ProjectScope(project), TypeScriptCorePlugin.PLUGIN_ID));
158+
}
159+
stores.add(new ScopedPreferenceStore(InstanceScope.INSTANCE, TypeScriptUIPlugin.PLUGIN_ID));
160+
stores.add(new ScopedPreferenceStore(InstanceScope.INSTANCE, TypeScriptCorePlugin.PLUGIN_ID));
161+
stores.add(new ScopedPreferenceStore(DefaultScope.INSTANCE, TypeScriptUIPlugin.PLUGIN_ID));
162+
stores.add(new ScopedPreferenceStore(DefaultScope.INSTANCE, TypeScriptCorePlugin.PLUGIN_ID));
163+
return new ChainedPreferenceStore(stores.toArray(new IPreferenceStore[stores.size()]));
164+
}
165+
166+
private IFile getFile(Object element) {
167+
return getFile(getFileInfo(element));
168+
}
169+
170+
private IFile getFile(FileInfo fileInfo) {
171+
if (fileInfo != null && fileInfo.fElement instanceof IFileEditorInput) {
172+
return ((IFileEditorInput) fileInfo.fElement).getFile();
173+
}
174+
return null;
35175
}
36176
}

eclipse/ts.eclipse.ide.core/src/ts/eclipse/ide/core/utils/DocumentUtils.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
/**
2+
* Copyright (c) 2015-2016 Angelo ZERR.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Angelo Zerr <[email protected]> - initial API and implementation
10+
* Lorenzo Dalla Vecchia <[email protected]> - made toTextEdit public
11+
*/
112
package ts.eclipse.ide.core.utils;
213

314
import java.util.List;
@@ -67,7 +78,19 @@ public static void applyEdits(IDocument document, List<CodeEdit> codeEdits)
6778
}
6879
}
6980

70-
private static TextEdit toTextEdit(List<CodeEdit> codeEdits, IDocument document) throws TypeScriptException {
81+
/**
82+
* Transforms a list of documents edits into a standard {@link TextEdit}
83+
* object that can be used for more complex operations, such as with the
84+
* refactoring API.
85+
*
86+
* @param codeEdits
87+
* list of TypeScript {@link CodeEdit}.
88+
* @param document
89+
* document to use as context for validating edit positions.
90+
* @return a {@link TextEdit} object.
91+
* @throws TypeScriptException
92+
*/
93+
public static TextEdit toTextEdit(List<CodeEdit> codeEdits, IDocument document) throws TypeScriptException {
7194
MultiTextEdit textEdit = new MultiTextEdit();
7295
for (CodeEdit codeEdit : codeEdits) {
7396
toTextEdit(codeEdit, document, textEdit);

eclipse/ts.eclipse.ide.ui/plugin.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#
88
# Contributors:
99
# Angelo Zerr <[email protected]> - Initial API and implementation
10+
# Lorenzo Dalla Vecchia <[email protected]> - Added save actions
1011
###############################################################################
1112
pluginName=TypeScript - Eclipse - UI IDE
1213
providerName=Angelo ZERR
@@ -29,6 +30,7 @@ EditorPreferencePage.name=Editor
2930
FormatterPreferencePage.name=Formatter
3031
ValidationPreferencePage.name=Validation
3132
TextMatePreferencePage.name=TextMate
33+
SaveActionsPreferencePage.name=Save Actions
3234

3335
# Menu/Commands
3436
TypeScript.root.name=TypeScript

eclipse/ts.eclipse.ide.ui/plugin.xml

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#
1111
# Contributors:
1212
# Angelo Zerr <[email protected]> - Initial API and implementation
13+
# Lorenzo Dalla Vecchia <[email protected]> - Added save actions
1314
###############################################################################
1415
-->
1516
<plugin>
@@ -238,7 +239,13 @@
238239
class="ts.eclipse.ide.internal.ui.preferences.TextMatePreferencePage"
239240
id="ts.eclipse.ide.ui.preference.TextMatePreferencePage"
240241
category="ts.eclipse.ide.ui.preference.EditorPreferencePage">
241-
</page>
242+
</page>
243+
<page
244+
category="ts.eclipse.ide.ui.preference.EditorPreferencePage"
245+
class="ts.eclipse.ide.internal.ui.preferences.SaveActionsPreferencePage"
246+
id="ts.eclipse.ide.ui.preference.SaveActionsPreferencePage"
247+
name="%SaveActionsPreferencePage.name">
248+
</page>
242249
</extension>
243250

244251
<!-- Property Pages -->
@@ -330,7 +337,21 @@
330337
<test property="ts.eclipse.ide.core.isTypeScriptProject" />
331338
</adapt>
332339
</enabledWhen>
333-
</page>
340+
</page>
341+
<page
342+
category="ts.eclipse.ide.ui.property.EditorPreferencePage"
343+
class="ts.eclipse.ide.internal.ui.preferences.SaveActionsPreferencePage"
344+
id="ts.eclipse.ide.ui.property.SaveActionsPreferencePage"
345+
name="%SaveActionsPreferencePage.name">
346+
<enabledWhen>
347+
<adapt
348+
type="org.eclipse.core.resources.IProject">
349+
<test
350+
property="ts.eclipse.ide.core.isTypeScriptProject">
351+
</test>
352+
</adapt>
353+
</enabledWhen>
354+
</page>
334355
</extension>
335356

336357
<!-- Search -->

eclipse/ts.eclipse.ide.ui/src/ts/eclipse/ide/internal/ui/TypeScriptUIMessages.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*
88
* Contributors:
99
* Angelo Zerr <[email protected]> - initial API and implementation
10+
* Lorenzo Dalla Vecchia <[email protected]> - Added save actions
1011
*/
1112
package ts.eclipse.ide.internal.ui;
1213

@@ -95,6 +96,10 @@ public class TypeScriptUIMessages extends NLS {
9596
public static String FormatterConfigurationBlock_formatOptions_placeOpenBraceOnNewLineForFunctions;
9697
public static String FormatterConfigurationBlock_formatOptions_placeOpenBraceOnNewLineForControlBlocks;
9798

99+
// Save actions
100+
public static String SaveActionsPreferencePage_performTheSelectedActionsOnSave;
101+
public static String SaveActionsPreferencePage_formatSourceCode;
102+
98103
public static String ValidationConfigurationBlock_tslintjson_group_label;
99104
public static String ValidationConfigurationBlock_tslintjson_strategy_DisableTslint;
100105
public static String ValidationConfigurationBlock_tslintjson_strategy_UseDefaultTslintJson;

eclipse/ts.eclipse.ide.ui/src/ts/eclipse/ide/internal/ui/TypeScriptUIMessages.properties

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#
88
# Contributors:
99
# Angelo Zerr <[email protected]> - Initial API and implementation
10+
# Lorenzo Dalla Vecchia <[email protected]> - Added save actions
1011
###############################################################################
1112

1213
# Buttons
@@ -79,6 +80,10 @@ FormatterConfigurationBlock_formatOptions_insertSpaceAfterOpeningAndBeforeClosin
7980
FormatterConfigurationBlock_formatOptions_placeOpenBraceOnNewLineForFunctions=Defines whether an open brace is put onto a new line for functions or not.
8081
FormatterConfigurationBlock_formatOptions_placeOpenBraceOnNewLineForControlBlocks=Defines whether an open brace is put onto a new line for control blocks or not.
8182

83+
# Save actions
84+
SaveActionsPreferencePage_performTheSelectedActionsOnSave=Perform the selected actions on save
85+
SaveActionsPreferencePage_formatSourceCode=Format source code
86+
8287
ValidationConfigurationBlock_tslintjson_group_label=Configuration for 'tslint.json'
8388
ValidationConfigurationBlock_tslintjson_strategy_DisableTslint=Disable tslint
8489
ValidationConfigurationBlock_tslintjson_strategy_UseDefaultTslintJson=Use the default 'tslint.json'.

eclipse/ts.eclipse.ide.ui/src/ts/eclipse/ide/internal/ui/preferences/ATAConfigurationBlock.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*
88
* Contributors:
99
* Angelo Zerr <[email protected]> - initial API and implementation
10+
* Lorenzo Dalla Vecchia <[email protected]> - added reconcileControls hook
1011
*/
1112
package ts.eclipse.ide.internal.ui.preferences;
1213

@@ -17,8 +18,6 @@
1718
import org.eclipse.swt.layout.GridLayout;
1819
import org.eclipse.swt.widgets.Button;
1920
import org.eclipse.swt.widgets.Composite;
20-
import org.eclipse.swt.widgets.Control;
21-
import org.eclipse.swt.widgets.Group;
2221
import org.eclipse.swt.widgets.Label;
2322
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
2423

@@ -69,13 +68,7 @@ public void enablePreferenceContent(boolean enable) {
6968
}
7069

7170
@Override
72-
protected Control createContents(Composite parent) {
73-
Composite nodejsComposite = createUI(parent);
74-
validateSettings(null, null, null);
75-
return nodejsComposite;
76-
}
77-
78-
private Composite createUI(Composite parent) {
71+
protected Composite createUI(Composite parent) {
7972
final ScrolledPageContent pageContent = new ScrolledPageContent(parent);
8073
Composite composite = pageContent.getBody();
8174
GridLayout layout = new GridLayout();

eclipse/ts.eclipse.ide.ui/src/ts/eclipse/ide/internal/ui/preferences/AbstractTypeScriptRepositoryConfigurationBlock.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*
88
* Contributors:
99
* Angelo Zerr <[email protected]> - initial API and implementation
10+
* Lorenzo Dalla Vecchia <[email protected]> - added reconcileControls hook
1011
*/
1112
package ts.eclipse.ide.internal.ui.preferences;
1213

@@ -23,7 +24,6 @@
2324
import org.eclipse.swt.widgets.Button;
2425
import org.eclipse.swt.widgets.Combo;
2526
import org.eclipse.swt.widgets.Composite;
26-
import org.eclipse.swt.widgets.Control;
2727
import org.eclipse.swt.widgets.Group;
2828
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
2929

@@ -55,13 +55,7 @@ public AbstractTypeScriptRepositoryConfigurationBlock(IStatusChangeListener cont
5555
}
5656

5757
@Override
58-
protected Control createContents(Composite parent) {
59-
Composite contents = createUI(parent);
60-
validateSettings(null, null, null);
61-
return contents;
62-
}
63-
64-
private Composite createUI(Composite parent) {
58+
protected Composite createUI(Composite parent) {
6559
final ScrolledPageContent pageContent = new ScrolledPageContent(parent);
6660
Composite composite = pageContent.getBody();
6761
GridLayout layout = new GridLayout();

0 commit comments

Comments
 (0)