View Javadoc
1   /*
2    * Copyright (c) 2020 bahlef.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v2.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v20.html
7    * Contributors:
8    * bahlef - initial API and implementation and/or initial documentation
9    */
10  package de.funfried.netbeans.plugins.external.formatter.java.palantir;
11  
12  import java.util.SortedSet;
13  import java.util.prefs.Preferences;
14  
15  import javax.swing.text.BadLocationException;
16  import javax.swing.text.Document;
17  import javax.swing.text.StyledDocument;
18  
19  import org.apache.commons.lang3.tuple.Pair;
20  import org.netbeans.api.annotations.common.CheckForNull;
21  import org.netbeans.api.annotations.common.NonNull;
22  import org.netbeans.api.editor.guards.GuardedSectionManager;
23  import org.netbeans.api.project.Project;
24  import org.openide.util.NbBundle;
25  import org.openide.util.lookup.ServiceProvider;
26  
27  import com.palantir.javaformat.java.JavaFormatterOptions;
28  
29  import de.funfried.netbeans.plugins.external.formatter.FormatterService;
30  import de.funfried.netbeans.plugins.external.formatter.MimeType;
31  import de.funfried.netbeans.plugins.external.formatter.exceptions.FormattingFailedException;
32  import de.funfried.netbeans.plugins.external.formatter.java.base.AbstractJavaFormatterService;
33  import de.funfried.netbeans.plugins.external.formatter.java.palantir.ui.PalantirJavaFormatterOptionsPanel;
34  import de.funfried.netbeans.plugins.external.formatter.ui.options.FormatterOptionsPanel;
35  import de.funfried.netbeans.plugins.external.formatter.ui.options.Settings;
36  
37  /**
38   * Palantir implementation of the {@link AbstractJavaFormatterService}.
39   *
40   * @author bahlef
41   */
42  @NbBundle.Messages({
43  		"FormatterName=Palantir Java Code Formatter"
44  })
45  @ServiceProvider(service = FormatterService.class, position = 2000)
46  public class PalantirJavaFormatterService extends AbstractJavaFormatterService<PalantirFormatJob> {
47  	/** The ID of this formatter service. */
48  	public static final String ID = "palantir-java-formatter";
49  
50  	/** * The {@link PalantirJavaFormatterWrapper} implementation. */
51  	private final PalantirJavaFormatterWrapper formatter = new PalantirJavaFormatterWrapper();
52  
53  	/**
54  	 * {@inheritDoc}
55  	 */
56  	@Override
57  	public boolean canHandle(Document document) {
58  		// Cannot handle guarded blocks properly due to a bug in the Google Java Code Formatter:
59  		// https://github.com/google/google-java-format/issues/433
60  		if (document instanceof StyledDocument) {
61  			StyledDocument styledDoc = (StyledDocument) document;
62  
63  			if (GuardedSectionManager.getInstance(styledDoc) != null) {
64  				return false;
65  			}
66  		}
67  
68  		return super.canHandle(document);
69  	}
70  
71  	/**
72  	 * {@inheritDoc}
73  	 */
74  	@NonNull
75  	@Override
76  	public String getDisplayName() {
77  		return NbBundle.getMessage(PalantirJavaFormatterService.class, "FormatterName");
78  	}
79  
80  	/**
81  	 * {@inheritDoc}
82  	 */
83  	@NonNull
84  	@Override
85  	public String getId() {
86  		return ID;
87  	}
88  
89  	/**
90  	 * {@inheritDoc}
91  	 */
92  	@Override
93  	public FormatterOptionsPanel createOptionsPanel(Project project) {
94  		return new PalantirJavaFormatterOptionsPanel(project);
95  	}
96  
97  	/**
98  	 * {@inheritDoc}
99  	 */
100 	@CheckForNull
101 	@Override
102 	public Integer getContinuationIndentSize(Document document) {
103 		if (document == null) {
104 			return null;
105 		}
106 
107 		Integer ret = null;
108 
109 		Preferences preferences = Settings.getActivePreferences(document);
110 		if (isUseFormatterIndentationSettings(preferences)) {
111 			ret = 8;
112 		}
113 
114 		return ret;
115 	}
116 
117 	/**
118 	 * {@inheritDoc}
119 	 */
120 	@CheckForNull
121 	@Override
122 	public Integer getIndentSize(Document document) {
123 		if (document == null) {
124 			return null;
125 		}
126 
127 		Integer ret = null;
128 
129 		Preferences preferences = Settings.getActivePreferences(document);
130 		if (isUseFormatterIndentationSettings(preferences)) {
131 			ret = 4;
132 		}
133 
134 		return ret;
135 	}
136 
137 	/**
138 	 * {@inheritDoc}
139 	 */
140 	@CheckForNull
141 	@Override
142 	public Integer getRightMargin(Document document) {
143 		if (document == null) {
144 			return null;
145 		}
146 
147 		return JavaFormatterOptions.Style.PALANTIR.maxLineLength();
148 	}
149 
150 	/**
151 	 * {@inheritDoc}
152 	 */
153 	@Override
154 	protected PalantirFormatJob getFormatJob(StyledDocument document, SortedSet<Pair<Integer, Integer>> changedElements) {
155 		return new PalantirFormatJob(document, formatter, changedElements);
156 	}
157 
158 	/**
159 	 * {@inheritDoc}
160 	 */
161 	@CheckForNull
162 	@Override
163 	public Integer getSpacesPerTab(Document document) {
164 		if (document == null) {
165 			return null;
166 		}
167 
168 		Integer ret = null;
169 
170 		Preferences preferences = Settings.getActivePreferences(document);
171 		if (isUseFormatterIndentationSettings(preferences)) {
172 			if (!isExpandTabToSpaces(document, preferences) && preferences.getBoolean(Settings.OVERRIDE_TAB_SIZE, true)) {
173 				ret = preferences.getInt(Settings.OVERRIDE_TAB_SIZE_VALUE, 4);
174 			} else {
175 				ret = 4;
176 			}
177 		}
178 
179 		return ret;
180 	}
181 
182 	/**
183 	 * {@inheritDoc}
184 	 */
185 	@CheckForNull
186 	@Override
187 	public Boolean isExpandTabToSpaces(Document document) {
188 		if (document == null) {
189 			return null;
190 		}
191 
192 		return isExpandTabToSpaces(document, Settings.getActivePreferences(document));
193 	}
194 
195 	private Boolean isExpandTabToSpaces(Document document, Preferences preferences) {
196 		if (document == null || preferences == null) {
197 			return null;
198 		}
199 
200 		Boolean ret = null;
201 
202 		if (isUseFormatterIndentationSettings(preferences)) {
203 			ret = true;
204 		}
205 
206 		return ret;
207 	}
208 
209 	/**
210 	 * Returns {@code true} if using the formatter indentation settings from the external
211 	 * formatter is activated, otherwise {@code false}.
212 	 *
213 	 * @param prefs the {@link Preferences} where to check
214 	 *
215 	 * @return {@code true} if using the formatter indentation settings from the external
216 	 *         formatter is activated, otherwise {@code false}
217 	 */
218 	private boolean isUseFormatterIndentationSettings(Preferences prefs) {
219 		return prefs.getBoolean(Settings.ENABLE_USE_OF_INDENTATION_SETTINGS, true);
220 	}
221 
222 	/**
223 	 * {@inheritDoc}
224 	 */
225 	@Override
226 	@CheckForNull
227 	public Boolean organizeImports(StyledDocument document, boolean afterFixImports) throws BadLocationException {
228 		if (!canHandle(document)) {
229 			throw new FormattingFailedException("The file type '" + MimeType.getMimeTypeAsString(document) + "' is not supported");
230 		}
231 
232 		getFormatJob(document, null).organizeImports();
233 
234 		return true;
235 	}
236 }