mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-13 20:15:22 +02:00
Bug 496249: Tags for disabling/enabling CDT code formatter
Change-Id: I4389c61612da6a4ee0011a49d6aeed7b52152436 Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
This commit is contained in:
parent
f60bbf25dd
commit
a6d06902b1
11 changed files with 484 additions and 7 deletions
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
||||||
Bundle-ManifestVersion: 2
|
Bundle-ManifestVersion: 2
|
||||||
Bundle-Name: %pluginName
|
Bundle-Name: %pluginName
|
||||||
Bundle-SymbolicName: org.eclipse.cdt.core; singleton:=true
|
Bundle-SymbolicName: org.eclipse.cdt.core; singleton:=true
|
||||||
Bundle-Version: 6.6.100.qualifier
|
Bundle-Version: 6.7.0.qualifier
|
||||||
Bundle-Activator: org.eclipse.cdt.core.CCorePlugin
|
Bundle-Activator: org.eclipse.cdt.core.CCorePlugin
|
||||||
Bundle-Vendor: %providerName
|
Bundle-Vendor: %providerName
|
||||||
Bundle-Localization: plugin
|
Bundle-Localization: plugin
|
||||||
|
|
|
@ -91,6 +91,38 @@ public class DefaultCodeFormatterConstants {
|
||||||
*/
|
*/
|
||||||
public static final String FALSE = "false"; //$NON-NLS-1$
|
public static final String FALSE = "false"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* FORMATTER / Formatter on tag format option
|
||||||
|
* - option id: "org.eclipse.cdt.core.formatter.comment_formatter_on_tag"
|
||||||
|
* - default: @formatter:on
|
||||||
|
* </pre>
|
||||||
|
* @see CCorePlugin#FORMAT_ON_TAG
|
||||||
|
* @since 6.7
|
||||||
|
*/
|
||||||
|
public static final String FORMATTER_COMMENT_ON_TAG = CCorePlugin.PLUGIN_ID + ".formatter.comment_formatter_on_tag"; //$NON-NLS-1$
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* FORMATTER / Formatter off tag format option
|
||||||
|
* - option id: "org.eclipse.cdt.core.formatter.comment_formatter_off_tag"
|
||||||
|
* - default: @formatter:off
|
||||||
|
* </pre>
|
||||||
|
* @see CCorePlugin#FORMAT_OFF_TAG
|
||||||
|
* @since 6.7
|
||||||
|
*/
|
||||||
|
public static final String FORMATTER_COMMENT_OFF_TAG = CCorePlugin.PLUGIN_ID
|
||||||
|
+ ".formatter.comment_formatter_off_tag"; //$NON-NLS-1$
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* FORMATTER / Formatter on tag format option
|
||||||
|
* - option id: "org.eclipse.cdt.core.formatter.use_comment_formatter_tag"
|
||||||
|
* - default: true
|
||||||
|
* </pre>
|
||||||
|
* @since 6.7
|
||||||
|
*/
|
||||||
|
public static final String FORMATTER_USE_COMMENT_TAG = CCorePlugin.PLUGIN_ID
|
||||||
|
+ ".formatter.use_comment_formatter_tag"; //$NON-NLS-1$
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * <pre>
|
// * <pre>
|
||||||
// * FORMATTER / Option to align type members of a type declaration on column
|
// * FORMATTER / Option to align type members of a type declaration on column
|
||||||
|
@ -2484,6 +2516,21 @@ public class DefaultCodeFormatterConstants {
|
||||||
*/
|
*/
|
||||||
public static final int WRAP_ONE_PER_LINE = 3;
|
public static final int WRAP_ONE_PER_LINE = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* FORMATTER / Default formatter on tag
|
||||||
|
* </pre>
|
||||||
|
* @since 6.7
|
||||||
|
*/
|
||||||
|
public static final String FORMATTER_ON_TAG = "@formatter:on"; //$NON-NLS-1$
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* FORMATTER / Default formatter off tag
|
||||||
|
* </pre>
|
||||||
|
* @since 6.7
|
||||||
|
*/
|
||||||
|
public static final String FORMATTER_OFF_TAG = "@formatter:off"; //$NON-NLS-1$
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Private constants.
|
* Private constants.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -264,6 +264,12 @@ public class DefaultCodeFormatterOptions {
|
||||||
public boolean use_tabs_only_for_leading_indentations;
|
public boolean use_tabs_only_for_leading_indentations;
|
||||||
public int initial_indentation_level;
|
public int initial_indentation_level;
|
||||||
public String line_separator;
|
public String line_separator;
|
||||||
|
/** @since 6.7 */
|
||||||
|
public String comment_formatter_on_tag;
|
||||||
|
/** @since 6.7 */
|
||||||
|
public String comment_formatter_off_tag;
|
||||||
|
/** @since 6.7 */
|
||||||
|
public boolean use_fomatter_comment_tag;
|
||||||
|
|
||||||
private DefaultCodeFormatterOptions() {
|
private DefaultCodeFormatterOptions() {
|
||||||
// cannot be instantiated
|
// cannot be instantiated
|
||||||
|
@ -282,6 +288,11 @@ public class DefaultCodeFormatterOptions {
|
||||||
|
|
||||||
public Map<String, String> getMap() {
|
public Map<String, String> getMap() {
|
||||||
Map<String, String> options = new HashMap<>();
|
Map<String, String> options = new HashMap<>();
|
||||||
|
options.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_ON_TAG, comment_formatter_on_tag);
|
||||||
|
options.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_OFF_TAG, comment_formatter_off_tag);
|
||||||
|
options.put(DefaultCodeFormatterConstants.FORMATTER_USE_COMMENT_TAG,
|
||||||
|
this.use_fomatter_comment_tag ? DefaultCodeFormatterConstants.TRUE
|
||||||
|
: DefaultCodeFormatterConstants.FALSE);
|
||||||
// options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_ALLOCATION_EXPRESSION, getAlignment(this.alignment_for_arguments_in_allocation_expression));
|
// options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_ALLOCATION_EXPRESSION, getAlignment(this.alignment_for_arguments_in_allocation_expression));
|
||||||
options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION,
|
options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION,
|
||||||
getAlignment(this.alignment_for_arguments_in_method_invocation));
|
getAlignment(this.alignment_for_arguments_in_method_invocation));
|
||||||
|
@ -2025,10 +2036,25 @@ public class DefaultCodeFormatterOptions {
|
||||||
this.tab_char = MIXED;
|
this.tab_char = MIXED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
final Object formatterCommentOnTag = settings.get(DefaultCodeFormatterConstants.FORMATTER_COMMENT_ON_TAG);
|
||||||
|
if (formatterCommentOnTag != null) {
|
||||||
|
this.comment_formatter_on_tag = (String) formatterCommentOnTag;
|
||||||
|
}
|
||||||
|
final Object formatterCommentOffTag = settings.get(DefaultCodeFormatterConstants.FORMATTER_COMMENT_OFF_TAG);
|
||||||
|
if (formatterCommentOffTag != null) {
|
||||||
|
this.comment_formatter_off_tag = (String) formatterCommentOffTag;
|
||||||
|
}
|
||||||
|
final Object useFormatterCommentTag = settings.get(DefaultCodeFormatterConstants.FORMATTER_USE_COMMENT_TAG);
|
||||||
|
if (useFormatterCommentTag != null) {
|
||||||
|
this.use_fomatter_comment_tag = DefaultCodeFormatterConstants.TRUE.equals(useFormatterCommentTag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDefaultSettings() {
|
public void setDefaultSettings() {
|
||||||
// this.alignment_for_arguments_in_allocation_expression = Alignment.M_COMPACT_SPLIT;
|
// this.alignment_for_arguments_in_allocation_expression = Alignment.M_COMPACT_SPLIT;
|
||||||
|
this.comment_formatter_on_tag = DefaultCodeFormatterConstants.FORMATTER_ON_TAG;
|
||||||
|
this.comment_formatter_off_tag = DefaultCodeFormatterConstants.FORMATTER_OFF_TAG;
|
||||||
|
this.use_fomatter_comment_tag = true;
|
||||||
this.alignment_for_arguments_in_method_invocation = Alignment.M_COMPACT_SPLIT;
|
this.alignment_for_arguments_in_method_invocation = Alignment.M_COMPACT_SPLIT;
|
||||||
this.alignment_for_assignment = Alignment.M_COMPACT_SPLIT;
|
this.alignment_for_assignment = Alignment.M_COMPACT_SPLIT;
|
||||||
this.alignment_for_base_clause_in_type_declaration = Alignment.M_NEXT_PER_LINE_SPLIT;
|
this.alignment_for_base_clause_in_type_declaration = Alignment.M_NEXT_PER_LINE_SPLIT;
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTBreakStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTBreakStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTCaseStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTCaseStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
|
import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTComment;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
|
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
|
import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
|
||||||
|
@ -438,7 +439,8 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
|
||||||
|
|
||||||
localScanner.setSource(compilationUnitSource);
|
localScanner.setSource(compilationUnitSource);
|
||||||
scribe.initializeScanner(compilationUnitSource);
|
scribe.initializeScanner(compilationUnitSource);
|
||||||
scribe.setSkipPositions(collectInactiveCodePositions(unit));
|
scribe.setSkipInactivePositions(collectInactiveCodePositions(unit));
|
||||||
|
scribe.setSkipForbiddenPositions(collectNoFormatCodePositions(unit));
|
||||||
|
|
||||||
fStatus = new MultiStatus(CCorePlugin.PLUGIN_ID, 0, "Formatting problem(s) in '" + unit.getFilePath() + "'", //$NON-NLS-1$//$NON-NLS-2$
|
fStatus = new MultiStatus(CCorePlugin.PLUGIN_ID, 0, "Formatting problem(s) in '" + unit.getFilePath() + "'", //$NON-NLS-1$//$NON-NLS-2$
|
||||||
null);
|
null);
|
||||||
|
@ -4465,6 +4467,64 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect source positions of no-format sections in the given translation unit.
|
||||||
|
*
|
||||||
|
* @param translationUnit the {@link IASTTranslationUnit}, may be <code>null</code>
|
||||||
|
* @return a {@link List} of {@link Position}s
|
||||||
|
*/
|
||||||
|
private List<Position> collectNoFormatCodePositions(IASTTranslationUnit translationUnit) {
|
||||||
|
if (translationUnit == null || !this.preferences.use_fomatter_comment_tag) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
String fileName = translationUnit.getFilePath();
|
||||||
|
if (fileName == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<Position> positions = new ArrayList<>();
|
||||||
|
int inactiveCodeStart = -1;
|
||||||
|
boolean inInactiveCode = false;
|
||||||
|
|
||||||
|
IASTComment[] commentsStmts = translationUnit.getComments();
|
||||||
|
|
||||||
|
for (IASTComment commentStmt : commentsStmts) {
|
||||||
|
IASTComment statement = commentStmt;
|
||||||
|
if (!statement.isPartOfTranslationUnitFile()) {
|
||||||
|
// comment is from a different file
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
IASTNodeLocation nodeLocation = statement.getFileLocation();
|
||||||
|
if (nodeLocation == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String comment = new String(statement.getComment());
|
||||||
|
/**
|
||||||
|
* According to JDT formatter rules, we need to evaluate the latest tag if both
|
||||||
|
* are defined at the same time in the comment.
|
||||||
|
*/
|
||||||
|
int offPos = comment.lastIndexOf(this.preferences.comment_formatter_off_tag);
|
||||||
|
int onPos = comment.lastIndexOf(this.preferences.comment_formatter_on_tag);
|
||||||
|
if (offPos != -1 && offPos > onPos) {
|
||||||
|
if (!inInactiveCode) {
|
||||||
|
inactiveCodeStart = nodeLocation.getNodeOffset();
|
||||||
|
inInactiveCode = true;
|
||||||
|
}
|
||||||
|
} else if (onPos != -1 && onPos > offPos) {
|
||||||
|
if (inInactiveCode) {
|
||||||
|
int inactiveCodeEnd = nodeLocation.getNodeOffset();
|
||||||
|
positions.add(new Position(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart));
|
||||||
|
}
|
||||||
|
inInactiveCode = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inInactiveCode) {
|
||||||
|
positions.add(new Position(inactiveCodeStart, translationUnit.getFileLocation().getNodeLength()));
|
||||||
|
inInactiveCode = false;
|
||||||
|
}
|
||||||
|
return positions;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect source positions of preprocessor-hidden branches
|
* Collect source positions of preprocessor-hidden branches
|
||||||
* in the given translation unit.
|
* in the given translation unit.
|
||||||
|
|
|
@ -88,7 +88,14 @@ public class Scribe {
|
||||||
private int textRegionStart;
|
private int textRegionStart;
|
||||||
public int scannerEndPosition;
|
public int scannerEndPosition;
|
||||||
|
|
||||||
private List<Position> fSkipPositions = Collections.emptyList();
|
/**
|
||||||
|
* It keeps the list of inactive region.
|
||||||
|
*/
|
||||||
|
private List<Position> fSkipInactivePositions = Collections.emptyList();
|
||||||
|
/**
|
||||||
|
* It keeps the list of no-format region.
|
||||||
|
*/
|
||||||
|
private List<Position> fSkipForbiddenPositions = Collections.emptyList();
|
||||||
|
|
||||||
private boolean skipOverInactive;
|
private boolean skipOverInactive;
|
||||||
|
|
||||||
|
@ -667,11 +674,20 @@ public class Scribe {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the positions where we don't want to perform any check
|
||||||
|
* @param list The list of positions
|
||||||
|
*/
|
||||||
|
public void setSkipForbiddenPositions(List<Position> list) {
|
||||||
|
if (list != null)
|
||||||
|
fSkipForbiddenPositions = list;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param list
|
* @param list
|
||||||
*/
|
*/
|
||||||
public void setSkipPositions(List<Position> list) {
|
public void setSkipInactivePositions(List<Position> list) {
|
||||||
fSkipPositions = list;
|
fSkipInactivePositions = list;
|
||||||
skipOverInactive = !list.isEmpty();
|
skipOverInactive = !list.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1283,12 +1299,26 @@ public class Scribe {
|
||||||
return hasWhitespace;
|
return hasWhitespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param offset
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean isForbidden(int offset) {
|
||||||
|
for (Iterator<Position> iter = fSkipForbiddenPositions.iterator(); iter.hasNext();) {
|
||||||
|
Position pos = iter.next();
|
||||||
|
if (pos.includes(offset)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param offset
|
* @param offset
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Position getInactivePosAt(int offset) {
|
private Position getInactivePosAt(int offset) {
|
||||||
for (Iterator<Position> iter = fSkipPositions.iterator(); iter.hasNext();) {
|
for (Iterator<Position> iter = fSkipInactivePositions.iterator(); iter.hasNext();) {
|
||||||
Position pos = iter.next();
|
Position pos = iter.next();
|
||||||
if (pos.includes(offset)) {
|
if (pos.includes(offset)) {
|
||||||
return pos;
|
return pos;
|
||||||
|
@ -2037,7 +2067,7 @@ public class Scribe {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean shouldSkip(int offset) {
|
boolean shouldSkip(int offset) {
|
||||||
return offset >= fSkipStartOffset && offset < fSkipEndOffset;
|
return ((offset >= fSkipStartOffset && offset < fSkipEndOffset) || isForbidden(offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
void skipRange(int offset, int endOffset) {
|
void skipRange(int offset, int endOffset) {
|
||||||
|
|
|
@ -3563,4 +3563,44 @@ public class CodeFormatterTest extends BaseUITestCase {
|
||||||
public void testAttributedNamedScopedEnumDeclaration_Bug535256_4() throws Exception {
|
public void testAttributedNamedScopedEnumDeclaration_Bug535256_4() throws Exception {
|
||||||
assertFormatterResult();
|
assertFormatterResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////@formatter:off
|
||||||
|
//int
|
||||||
|
//main(){
|
||||||
|
//return
|
||||||
|
//0
|
||||||
|
//;}
|
||||||
|
////@formatter:on
|
||||||
|
|
||||||
|
////@formatter:off
|
||||||
|
//int
|
||||||
|
//main(){
|
||||||
|
//return
|
||||||
|
//0
|
||||||
|
//;}
|
||||||
|
////@formatter:on
|
||||||
|
public void testOnOffTags() throws Exception {
|
||||||
|
fOptions.put(DefaultCodeFormatterConstants.FORMATTER_USE_COMMENT_TAG, true);
|
||||||
|
fOptions.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_ON_TAG, "@formatter:on");
|
||||||
|
fOptions.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_OFF_TAG, "@formatter:off");
|
||||||
|
assertFormatterResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
////@formatter:off
|
||||||
|
// void this_line_intentionally_indented() {
|
||||||
|
// int x;
|
||||||
|
// }
|
||||||
|
////@formatter:on
|
||||||
|
|
||||||
|
////@formatter:off
|
||||||
|
// void this_line_intentionally_indented() {
|
||||||
|
// int x;
|
||||||
|
// }
|
||||||
|
////@formatter:on
|
||||||
|
public void testOnOffTagsDoesNotChangeFirstLineIndent() throws Exception {
|
||||||
|
fOptions.put(DefaultCodeFormatterConstants.FORMATTER_USE_COMMENT_TAG, true);
|
||||||
|
fOptions.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_ON_TAG, "@formatter:on");
|
||||||
|
fOptions.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_OFF_TAG, "@formatter:off");
|
||||||
|
assertFormatterResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -369,6 +369,7 @@ final class FormatterMessages extends NLS {
|
||||||
public static String ModifyDialog_tabpage_braces_title;
|
public static String ModifyDialog_tabpage_braces_title;
|
||||||
public static String ModifyDialog_tabpage_indentation_title;
|
public static String ModifyDialog_tabpage_indentation_title;
|
||||||
public static String ModifyDialog_tabpage_whitespace_title;
|
public static String ModifyDialog_tabpage_whitespace_title;
|
||||||
|
public static String ModifyDialog_tabpage_formatter_tag_title;
|
||||||
// public static String ModifyDialog_tabpage_blank_lines_title;
|
// public static String ModifyDialog_tabpage_blank_lines_title;
|
||||||
public static String ModifyDialog_tabpage_new_lines_title;
|
public static String ModifyDialog_tabpage_new_lines_title;
|
||||||
public static String ModifyDialog_tabpage_control_statements_title;
|
public static String ModifyDialog_tabpage_control_statements_title;
|
||||||
|
@ -402,6 +403,15 @@ final class FormatterMessages extends NLS {
|
||||||
|
|
||||||
public static String CPreview_formatter_exception;
|
public static String CPreview_formatter_exception;
|
||||||
|
|
||||||
|
public static String FormatterModifyDialog_offOn_preview_header;
|
||||||
|
public static String FormatterModifyDialog_offOn_description;
|
||||||
|
public static String FormatterModifyDialog_offOn_pref_enable;
|
||||||
|
public static String FormatterModifyDialog_offOn_pref_off_tag;
|
||||||
|
public static String FormatterModifyDialog_offOn_pref_on_tag;
|
||||||
|
public static String FormatterModifyDialog_offOn_error_startsWithWhitespace;
|
||||||
|
public static String FormatterModifyDialog_offOn_error_endsWithWhitespace;
|
||||||
|
public static String FormatterModifyDialog_offOn_error_empty;
|
||||||
|
|
||||||
private FormatterMessages() {
|
private FormatterMessages() {
|
||||||
// Do not instantiate
|
// Do not instantiate
|
||||||
}
|
}
|
||||||
|
|
|
@ -433,6 +433,7 @@ ModifyDialog_tabpage_new_lines_title=New &Lines
|
||||||
ModifyDialog_tabpage_control_statements_title=Con&trol Statements
|
ModifyDialog_tabpage_control_statements_title=Con&trol Statements
|
||||||
ModifyDialog_tabpage_line_wrapping_title=Line Wra&pping
|
ModifyDialog_tabpage_line_wrapping_title=Line Wra&pping
|
||||||
ModifyDialog_tabpage_comments_title=Co&mments
|
ModifyDialog_tabpage_comments_title=Co&mments
|
||||||
|
ModifyDialog_tabpage_formatter_tag_title=Off/On Tags
|
||||||
|
|
||||||
ModifyDialog_dialog_title=Profile ''{0}''
|
ModifyDialog_dialog_title=Profile ''{0}''
|
||||||
ModifyDialog_apply_button=Apply
|
ModifyDialog_apply_button=Apply
|
||||||
|
@ -476,3 +477,12 @@ CPreview_formatter_exception=The formatter threw an unhandled exception while fo
|
||||||
|
|
||||||
ProfileConfigurationBlock_load_profile_wrong_profile_message=Import failed. This is not a valid profile: Expected ''{0}'' but encountered ''{1}''.
|
ProfileConfigurationBlock_load_profile_wrong_profile_message=Import failed. This is not a valid profile: Expected ''{0}'' but encountered ''{1}''.
|
||||||
FormatterTabPage_ShowInvisibleCharacters_label=Show &invisible characters
|
FormatterTabPage_ShowInvisibleCharacters_label=Show &invisible characters
|
||||||
|
|
||||||
|
FormatterModifyDialog_offOn_preview_header=Off/On tags
|
||||||
|
FormatterModifyDialog_offOn_description=Off/On tags can be used in any comments to turn the formatter off and on in a source file.\n- At the beginning of each file, the formatter is enabled.\n- Each time the formatter sees an off tag, it disables formatting for that comment and the source after it.\n- Each time the formatter sees an on tag, it enables formatting for the source after that comment.\n
|
||||||
|
FormatterModifyDialog_offOn_pref_enable=Enable Off/On tags
|
||||||
|
FormatterModifyDialog_offOn_pref_off_tag=Off tag:
|
||||||
|
FormatterModifyDialog_offOn_pref_on_tag=On tag:
|
||||||
|
FormatterModifyDialog_offOn_error_startsWithWhitespace=This value must not start with a white space.
|
||||||
|
FormatterModifyDialog_offOn_error_endsWithWhitespace=This value must not end with a white space.
|
||||||
|
FormatterModifyDialog_offOn_error_empty=This value must not be empty.
|
||||||
|
|
|
@ -38,5 +38,6 @@ public class FormatterModifyDialog extends ModifyDialog {
|
||||||
new ControlStatementsTabPage(this, values));
|
new ControlStatementsTabPage(this, values));
|
||||||
addTabPage(FormatterMessages.ModifyDialog_tabpage_line_wrapping_title, new LineWrappingTabPage(this, values));
|
addTabPage(FormatterMessages.ModifyDialog_tabpage_line_wrapping_title, new LineWrappingTabPage(this, values));
|
||||||
addTabPage(FormatterMessages.ModifyDialog_tabpage_comments_title, new CommentsTabPage(this, values));
|
addTabPage(FormatterMessages.ModifyDialog_tabpage_comments_title, new CommentsTabPage(this, values));
|
||||||
|
addTabPage(FormatterMessages.ModifyDialog_tabpage_formatter_tag_title, new FormatterTagTabPage(this, values));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2019 Marco Stornelli
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.preferences.formatter;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Observable;
|
||||||
|
import java.util.Observer;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.formatter.DefaultCodeFormatterConstants;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Group;
|
||||||
|
|
||||||
|
public class FormatterTagTabPage extends FormatterTabPage {
|
||||||
|
|
||||||
|
private final String PREVIEW = createPreviewHeader(FormatterMessages.FormatterModifyDialog_offOn_preview_header)
|
||||||
|
+ "void method1() { doSomething(); }\n\n// @formatter:off\n" //$NON-NLS-1$
|
||||||
|
+ "void method2() { doSomething(); }\n// @formatter:on\n\n" //$NON-NLS-1$
|
||||||
|
+ "void method3() { doSomething(); }\n\n" //$NON-NLS-1$
|
||||||
|
+ "/* @formatter:off */\n\nvoid\nfoo()\n;"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
private StringPreference fOnTag;
|
||||||
|
private StringPreference fOffTag;
|
||||||
|
private CheckboxPreference fUseTag;
|
||||||
|
private TranslationUnitPreview fPreview;
|
||||||
|
|
||||||
|
public FormatterTagTabPage(IModificationListener modifyListener, Map<String, String> workingValues) {
|
||||||
|
super(modifyListener, workingValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initializePage() {
|
||||||
|
fPreview.setPreviewText(PREVIEW);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doUpdatePreview() {
|
||||||
|
super.doUpdatePreview();
|
||||||
|
fPreview.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doCreatePreferences(Composite composite, int numColumns) {
|
||||||
|
final Group generalGroup = createGroup(numColumns, composite,
|
||||||
|
FormatterMessages.ModifyDialog_tabpage_formatter_tag_title);
|
||||||
|
createLabel(numColumns, generalGroup, FormatterMessages.FormatterModifyDialog_offOn_description);
|
||||||
|
fUseTag = createCheckboxPref(generalGroup, numColumns,
|
||||||
|
FormatterMessages.FormatterModifyDialog_offOn_pref_enable,
|
||||||
|
DefaultCodeFormatterConstants.FORMATTER_USE_COMMENT_TAG, FALSE_TRUE);
|
||||||
|
fUseTag.addObserver(new Observer() {
|
||||||
|
@Override
|
||||||
|
public void update(Observable arg0, Object arg1) {
|
||||||
|
fOnTag.setEnabled(fUseTag.getChecked());
|
||||||
|
fOffTag.setEnabled(fUseTag.getChecked());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
PreferenceValidator validator = new PreferenceValidator() {
|
||||||
|
@Override
|
||||||
|
public String validate(String value) {
|
||||||
|
if (value != null && !value.isEmpty()) {
|
||||||
|
if (Character.isWhitespace(value.charAt(0))) {
|
||||||
|
return FormatterMessages.FormatterModifyDialog_offOn_error_startsWithWhitespace;
|
||||||
|
} else if (Character.isWhitespace(value.charAt(value.length() - 1))) {
|
||||||
|
return FormatterMessages.FormatterModifyDialog_offOn_error_endsWithWhitespace;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return FormatterMessages.FormatterModifyDialog_offOn_error_empty;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fOffTag = createStringPref(generalGroup, numColumns, FormatterMessages.FormatterModifyDialog_offOn_pref_off_tag,
|
||||||
|
DefaultCodeFormatterConstants.FORMATTER_COMMENT_OFF_TAG);
|
||||||
|
fOffTag.setValidator(validator);
|
||||||
|
fOnTag = createStringPref(generalGroup, numColumns, FormatterMessages.FormatterModifyDialog_offOn_pref_on_tag,
|
||||||
|
DefaultCodeFormatterConstants.FORMATTER_COMMENT_ON_TAG);
|
||||||
|
fOnTag.setValidator(validator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CPreview doCreateCPreview(Composite parent) {
|
||||||
|
fPreview = new TranslationUnitPreview(fWorkingValues, parent);
|
||||||
|
return fPreview;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -68,6 +68,18 @@ public abstract class ModifyDialogTabPage implements IModifyDialogTabPage {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference validator
|
||||||
|
*/
|
||||||
|
interface PreferenceValidator {
|
||||||
|
/**
|
||||||
|
* Validate callback
|
||||||
|
* @param value The value to be checked
|
||||||
|
* @return String error or null otherwise
|
||||||
|
*/
|
||||||
|
String validate(String value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base class of all Preference classes. A preference class provides a wrapper
|
* The base class of all Preference classes. A preference class provides a wrapper
|
||||||
* around one or more SWT widgets and handles the input of values for some key.
|
* around one or more SWT widgets and handles the input of values for some key.
|
||||||
|
@ -77,6 +89,7 @@ public abstract class ModifyDialogTabPage implements IModifyDialogTabPage {
|
||||||
private final Map<String, String> fPreferences;
|
private final Map<String, String> fPreferences;
|
||||||
private boolean fEnabled;
|
private boolean fEnabled;
|
||||||
private String fKey;
|
private String fKey;
|
||||||
|
private PreferenceValidator fValidator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Preference.
|
* Create a new Preference.
|
||||||
|
@ -143,6 +156,22 @@ public abstract class ModifyDialogTabPage implements IModifyDialogTabPage {
|
||||||
* of this object has changed (enabled, key, ...).
|
* of this object has changed (enabled, key, ...).
|
||||||
*/
|
*/
|
||||||
protected abstract void updateWidget();
|
protected abstract void updateWidget();
|
||||||
|
|
||||||
|
public void setValidator(PreferenceValidator validator) {
|
||||||
|
fValidator = validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if preference is valid according to its validator
|
||||||
|
* @param value The preference value
|
||||||
|
* @return Null if valid, the error string otherwise
|
||||||
|
*/
|
||||||
|
protected String isValid(String value) {
|
||||||
|
if (fValidator != null) {
|
||||||
|
return fValidator.validate(value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -318,6 +347,126 @@ public abstract class ModifyDialogTabPage implements IModifyDialogTabPage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper around a textfied
|
||||||
|
*/
|
||||||
|
protected final class StringPreference extends Preference {
|
||||||
|
|
||||||
|
private final Label fLabel;
|
||||||
|
private final Text fText;
|
||||||
|
|
||||||
|
protected String fSelected;
|
||||||
|
protected String fOldSelected;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new NumberPreference.
|
||||||
|
* @param composite The composite on which the SWT widgets are added.
|
||||||
|
* @param numColumns The number of columns in the composite's GridLayout.
|
||||||
|
* @param preferences The map to store the values.
|
||||||
|
* @param key The key to store the values.
|
||||||
|
* @param text The label text for this Preference.
|
||||||
|
*/
|
||||||
|
public StringPreference(Composite composite, int numColumns, Map<String, String> preferences, String key,
|
||||||
|
String text) {
|
||||||
|
super(preferences, key);
|
||||||
|
|
||||||
|
fLabel = createLabel(numColumns - 1, composite, text, GridData.FILL_HORIZONTAL);
|
||||||
|
fText = new Text(composite, SWT.SINGLE | SWT.BORDER | SWT.LEFT);
|
||||||
|
fText.setFont(composite.getFont());
|
||||||
|
|
||||||
|
fText.setLayoutData(
|
||||||
|
createGridData(1, GridData.HORIZONTAL_ALIGN_END, fPixelConverter.convertWidthInCharsToPixels(20)));
|
||||||
|
|
||||||
|
updateWidget();
|
||||||
|
|
||||||
|
fText.addFocusListener(new FocusListener() {
|
||||||
|
@Override
|
||||||
|
public void focusGained(FocusEvent e) {
|
||||||
|
StringPreference.this.focusGained();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void focusLost(FocusEvent e) {
|
||||||
|
StringPreference.this.focusLost();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fText.addModifyListener(new ModifyListener() {
|
||||||
|
@Override
|
||||||
|
public void modifyText(ModifyEvent e) {
|
||||||
|
fieldModified();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private IStatus createErrorStatus(String error) {
|
||||||
|
return new Status(IStatus.ERROR, CUIPlugin.getPluginId(), 0, Messages.format(error), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void focusGained() {
|
||||||
|
fOldSelected = fSelected;
|
||||||
|
fText.setSelection(0, fText.getCharCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void focusLost() {
|
||||||
|
updateStatus(null);
|
||||||
|
final String input = fText.getText();
|
||||||
|
if (validInput(input) != null)
|
||||||
|
fSelected = fOldSelected;
|
||||||
|
else
|
||||||
|
fSelected = input;
|
||||||
|
if (fSelected != fOldSelected) {
|
||||||
|
saveSelected();
|
||||||
|
fText.setText(fSelected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fieldModified() {
|
||||||
|
final String trimInput = fText.getText().trim();
|
||||||
|
final String error = validInput(fText.getText());
|
||||||
|
|
||||||
|
updateStatus(error == null ? null : createErrorStatus(error));
|
||||||
|
|
||||||
|
if (error == null) {
|
||||||
|
if (fSelected.equals(trimInput)) {
|
||||||
|
fSelected = trimInput;
|
||||||
|
saveSelected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String validInput(String input) {
|
||||||
|
return isValid(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveSelected() {
|
||||||
|
getPreferences().put(getKey(), fSelected);
|
||||||
|
setChanged();
|
||||||
|
notifyObservers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateWidget() {
|
||||||
|
final boolean hasKey = getKey() != null;
|
||||||
|
|
||||||
|
fLabel.setEnabled(hasKey && getEnabled());
|
||||||
|
fText.setEnabled(hasKey && getEnabled());
|
||||||
|
|
||||||
|
if (hasKey) {
|
||||||
|
String s = getPreferences().get(getKey());
|
||||||
|
fSelected = s;
|
||||||
|
fText.setText(s);
|
||||||
|
} else {
|
||||||
|
fText.setText(""); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Control getControl() {
|
||||||
|
return fText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper around a textfied which requests an integer input of a given range.
|
* Wrapper around a textfied which requests an integer input of a given range.
|
||||||
*/
|
*/
|
||||||
|
@ -897,6 +1046,17 @@ public abstract class ModifyDialogTabPage implements IModifyDialogTabPage {
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenience method to create a NumberPreference. The widget is registered as
|
||||||
|
* a potential focus holder, and the default updater is added.
|
||||||
|
*/
|
||||||
|
protected StringPreference createStringPref(Composite composite, int numColumns, String name, String key) {
|
||||||
|
final StringPreference pref = new StringPreference(composite, numColumns, fWorkingValues, key, name);
|
||||||
|
fDefaultFocusManager.add(pref);
|
||||||
|
pref.addObserver(fUpdater);
|
||||||
|
return pref;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convenience method to create a NumberPreference. The widget is registered as
|
* Convenience method to create a NumberPreference. The widget is registered as
|
||||||
* a potential focus holder, and the default updater is added.
|
* a potential focus holder, and the default updater is added.
|
||||||
|
|
Loading…
Add table
Reference in a new issue