diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java
index d597698ec95..0bdc326df14 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java
@@ -2128,12 +2128,15 @@ public class CodeFormatterVisitor extends CPPASTVisitor {
// preprocessor directive is from a different file
continue;
}
+ IASTNodeLocation nodeLocation = statement.getFileLocation();
+ if (nodeLocation == null) {
+ continue;
+ }
if (statement instanceof IASTPreprocessorIfStatement) {
IASTPreprocessorIfStatement ifStmt = (IASTPreprocessorIfStatement)statement;
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
if (!ifStmt.taken()) {
if (!inInactiveCode) {
- IASTNodeLocation nodeLocation = ifStmt.getFileLocation();
inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
inInactiveCode = true;
}
@@ -2143,7 +2146,6 @@ public class CodeFormatterVisitor extends CPPASTVisitor {
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
if (!ifdefStmt.taken()) {
if (!inInactiveCode) {
- IASTNodeLocation nodeLocation = ifdefStmt.getFileLocation();
inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
inInactiveCode = true;
}
@@ -2153,7 +2155,6 @@ public class CodeFormatterVisitor extends CPPASTVisitor {
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
if (!ifndefStmt.taken()) {
if (!inInactiveCode) {
- IASTNodeLocation nodeLocation = ifndefStmt.getFileLocation();
inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
inInactiveCode = true;
}
@@ -2161,11 +2162,9 @@ public class CodeFormatterVisitor extends CPPASTVisitor {
} else if (statement instanceof IASTPreprocessorElseStatement) {
IASTPreprocessorElseStatement elseStmt = (IASTPreprocessorElseStatement)statement;
if (!elseStmt.taken() && !inInactiveCode) {
- IASTNodeLocation nodeLocation = elseStmt.getFileLocation();
inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
inInactiveCode = true;
} else if (elseStmt.taken() && inInactiveCode) {
- IASTNodeLocation nodeLocation = elseStmt.getFileLocation();
int inactiveCodeEnd = nodeLocation.getNodeOffset();
positions.add(new Position(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart));
inInactiveCode = false;
@@ -2173,21 +2172,17 @@ public class CodeFormatterVisitor extends CPPASTVisitor {
} else if (statement instanceof IASTPreprocessorElifStatement) {
IASTPreprocessorElifStatement elifStmt = (IASTPreprocessorElifStatement)statement;
if (!elifStmt.taken() && !inInactiveCode) {
- IASTNodeLocation nodeLocation = elifStmt.getFileLocation();
inactiveCodeStart = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
inInactiveCode = true;
} else if (elifStmt.taken() && inInactiveCode) {
- IASTNodeLocation nodeLocation = elifStmt.getFileLocation();
int inactiveCodeEnd = nodeLocation.getNodeOffset();
positions.add(new Position(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart));
inInactiveCode = false;
}
} else if (statement instanceof IASTPreprocessorEndifStatement) {
- IASTPreprocessorEndifStatement endifStmt = (IASTPreprocessorEndifStatement)statement;
try {
boolean wasInInactiveCode = ((Boolean)inactiveCodeStack.pop()).booleanValue();
if (inInactiveCode && !wasInInactiveCode) {
- IASTNodeLocation nodeLocation = endifStmt.getFileLocation();
int inactiveCodeEnd = nodeLocation.getNodeOffset();
positions.add(new Position(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart));
}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InactiveCodeHighlighting.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InactiveCodeHighlighting.java
index 520750da3a7..42ab7f90fd9 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InactiveCodeHighlighting.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InactiveCodeHighlighting.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006 Wind River Systems, Inc. and others.
+ * Copyright (c) 2006, 2007 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -22,7 +22,10 @@ import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextInputListener;
import org.eclipse.jface.text.TypedPosition;
import org.eclipse.swt.widgets.Display;
@@ -52,7 +55,7 @@ import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
* @see LineBackgroundPainter
* @since 4.0
*/
-public class InactiveCodeHighlighting implements ICReconcilingListener {
+public class InactiveCodeHighlighting implements ICReconcilingListener, ITextInputListener {
/**
* Implementation of IRegion
that can be reused
@@ -82,6 +85,7 @@ public class InactiveCodeHighlighting implements ICReconcilingListener {
private CEditor fEditor;
/** The list of currently highlighted positions */
private List fInactiveCodePositions= Collections.EMPTY_LIST;
+ private IDocument fDocument;
/**
* Create a highlighter for the given key.
@@ -134,13 +138,15 @@ public class InactiveCodeHighlighting implements ICReconcilingListener {
assert editor != null && lineBackgroundPainter != null;
fEditor= editor;
fLineBackgroundPainter= lineBackgroundPainter;
- fEditor.addReconcileListener(this);
ICElement cElement= fEditor.getInputCElement();
if (cElement instanceof ITranslationUnit) {
fTranslationUnit = (ITranslationUnit)cElement;
} else {
fTranslationUnit = null;
}
+ fDocument= fEditor.getDocumentProvider().getDocument(fEditor.getEditorInput());
+ fEditor.getViewer().addTextInputListener(this);
+ fEditor.addReconcileListener(this);
}
/**
@@ -159,8 +165,12 @@ public class InactiveCodeHighlighting implements ICReconcilingListener {
}
if (fEditor != null) {
fEditor.removeReconcileListener(this);
+ if (fEditor.getViewer() != null) {
+ fEditor.getViewer().removeTextInputListener(this);
+ }
fEditor= null;
fTranslationUnit= null;
+ fDocument= null;
}
}
@@ -232,13 +242,17 @@ public class InactiveCodeHighlighting implements ICReconcilingListener {
// preprocessor directive is from a different file
continue;
}
+ IASTNodeLocation[] nodeLocations = statement.getNodeLocations();
+ if (nodeLocations.length != 1) {
+ continue;
+ }
+ IASTNodeLocation stmtLocation= nodeLocations[0];
if (statement instanceof IASTPreprocessorIfStatement) {
IASTPreprocessorIfStatement ifStmt = (IASTPreprocessorIfStatement)statement;
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
if (!ifStmt.taken()) {
if (!inInactiveCode) {
- IASTNodeLocation nodeLocation = ifStmt.getNodeLocations()[0];
- inactiveCodeStart = nodeLocation.getNodeOffset();
+ inactiveCodeStart = stmtLocation.getNodeOffset();
inInactiveCode = true;
}
}
@@ -247,8 +261,7 @@ public class InactiveCodeHighlighting implements ICReconcilingListener {
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
if (!ifdefStmt.taken()) {
if (!inInactiveCode) {
- IASTNodeLocation nodeLocation = ifdefStmt.getNodeLocations()[0];
- inactiveCodeStart = nodeLocation.getNodeOffset();
+ inactiveCodeStart = stmtLocation.getNodeOffset();
inInactiveCode = true;
}
}
@@ -257,43 +270,36 @@ public class InactiveCodeHighlighting implements ICReconcilingListener {
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
if (!ifndefStmt.taken()) {
if (!inInactiveCode) {
- IASTNodeLocation nodeLocation = ifndefStmt.getNodeLocations()[0];
- inactiveCodeStart = nodeLocation.getNodeOffset();
+ inactiveCodeStart = stmtLocation.getNodeOffset();
inInactiveCode = true;
}
}
} else if (statement instanceof IASTPreprocessorElseStatement) {
IASTPreprocessorElseStatement elseStmt = (IASTPreprocessorElseStatement)statement;
if (!elseStmt.taken() && !inInactiveCode) {
- IASTNodeLocation nodeLocation = elseStmt.getNodeLocations()[0];
- inactiveCodeStart = nodeLocation.getNodeOffset();
+ inactiveCodeStart = stmtLocation.getNodeOffset();
inInactiveCode = true;
} else if (elseStmt.taken() && inInactiveCode) {
- IASTNodeLocation nodeLocation = elseStmt.getNodeLocations()[0];
- int inactiveCodeEnd = nodeLocation.getNodeOffset();
- positions.add(new HighlightPosition(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart, fHighlightKey));
+ int inactiveCodeEnd = stmtLocation.getNodeOffset();
+ positions.add(createHighlightPosition(inactiveCodeStart, inactiveCodeEnd, false, fHighlightKey));
inInactiveCode = false;
}
} else if (statement instanceof IASTPreprocessorElifStatement) {
IASTPreprocessorElifStatement elifStmt = (IASTPreprocessorElifStatement)statement;
if (!elifStmt.taken() && !inInactiveCode) {
- IASTNodeLocation nodeLocation = elifStmt.getNodeLocations()[0];
- inactiveCodeStart = nodeLocation.getNodeOffset();
+ inactiveCodeStart = stmtLocation.getNodeOffset();
inInactiveCode = true;
} else if (elifStmt.taken() && inInactiveCode) {
- IASTNodeLocation nodeLocation = elifStmt.getNodeLocations()[0];
- int inactiveCodeEnd = nodeLocation.getNodeOffset();
- positions.add(new HighlightPosition(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart, fHighlightKey));
+ int inactiveCodeEnd = stmtLocation.getNodeOffset();
+ positions.add(createHighlightPosition(inactiveCodeStart, inactiveCodeEnd, false, fHighlightKey));
inInactiveCode = false;
}
} else if (statement instanceof IASTPreprocessorEndifStatement) {
- IASTPreprocessorEndifStatement endifStmt = (IASTPreprocessorEndifStatement)statement;
try {
boolean wasInInactiveCode = ((Boolean)inactiveCodeStack.pop()).booleanValue();
if (inInactiveCode && !wasInInactiveCode) {
- IASTNodeLocation nodeLocation = endifStmt.getNodeLocations()[0];
- int inactiveCodeEnd = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
- positions.add(new HighlightPosition(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart, fHighlightKey));
+ int inactiveCodeEnd = stmtLocation.getNodeOffset() + stmtLocation.getNodeLength();
+ positions.add(createHighlightPosition(inactiveCodeStart, inactiveCodeEnd, true, fHighlightKey));
}
inInactiveCode = wasInInactiveCode;
}
@@ -306,4 +312,52 @@ public class InactiveCodeHighlighting implements ICReconcilingListener {
return positions;
}
+ /**
+ * Create a highlight position aligned to start at a line offset. The region's start is
+ * decreased to the line offset, and the end offset decreased to the line start if
+ * inclusive
is false
.
+ *
+ * @param startOffset the start offset of the region to align
+ * @param endOffset the (exclusive) end offset of the region to align
+ * @param inclusive whether the last line should be included or not
+ * @param key the highlight key
+ * @return a position aligned for background highlighting
+ */
+ private HighlightPosition createHighlightPosition(int startOffset, int endOffset, boolean inclusive, String key) {
+ final IDocument document= fDocument;
+ try {
+ if (document != null) {
+ int start= document.getLineOfOffset(startOffset);
+ int end= document.getLineOfOffset(endOffset);
+ startOffset= document.getLineOffset(start);
+ if (!inclusive) {
+ endOffset= document.getLineOffset(end);
+ }
+ }
+ return new HighlightPosition(startOffset, endOffset - startOffset, key);
+
+ } catch (BadLocationException x) {
+ // concurrent modification?
+ return null;
+ }
+ }
+
+ /*
+ * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
+ */
+ public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
+ }
+
+ /*
+ * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
+ */
+ public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
+ fDocument= newInput;
+ if (fEditor != null && fLineBackgroundPainter != null && !fLineBackgroundPainter.isDisposed()) {
+ List newInactiveCodePositions= Collections.EMPTY_LIST;
+ fLineBackgroundPainter.replaceHighlightPositions(fInactiveCodePositions, newInactiveCodePositions);
+ fInactiveCodePositions= newInactiveCodePositions;
+ }
+ }
+
}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/folding/DefaultCFoldingStructureProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/folding/DefaultCFoldingStructureProvider.java
index 76cf0388b7d..47c507c89c4 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/folding/DefaultCFoldingStructureProvider.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/folding/DefaultCFoldingStructureProvider.java
@@ -651,6 +651,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
private static class Branch extends ModifiableRegion {
private boolean fTaken;
+ public boolean fInclusive;
/**
* @param offset
@@ -671,9 +672,6 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
fTaken= taken;
}
- /**
- * @param endOffset
- */
public void setEndOffset(int endOffset) {
setLength(endOffset - getOffset());
}
@@ -681,6 +679,10 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
public boolean taken() {
return fTaken;
}
+
+ public void setInclusive(boolean inclusive) {
+ fInclusive= inclusive;
+ }
}
private final static boolean DEBUG= "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.cdt.ui/debug/folding")); //$NON-NLS-1$//$NON-NLS-2$;
@@ -1162,9 +1164,12 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
Branch branch= (Branch)branchStack.pop();
IASTPreprocessorElseStatement elseStmt = (IASTPreprocessorElseStatement)statement;
branchStack.push(new Branch(stmtLocation.getNodeOffset(), elseStmt.taken()));
- branch.setEndOffset(stmtLocation.getNodeOffset() - 1);
- IRegion converted= converter != null ? converter.historicToActual(branch) : branch;
- branches.add(new Branch(converted.getOffset(), converted.getLength(), branch.taken()));
+ branch.setEndOffset(stmtLocation.getNodeOffset());
+ if (converter != null) {
+ IRegion converted= converter.historicToActual(branch);
+ branch= new Branch(converted.getOffset(), converted.getLength(), branch.taken());
+ }
+ branches.add(branch);
} else if (statement instanceof IASTPreprocessorElifStatement) {
if (branchStack.isEmpty()) {
// #elif without #if
@@ -1173,9 +1178,12 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
Branch branch= (Branch)branchStack.pop();
IASTPreprocessorElifStatement elifStmt = (IASTPreprocessorElifStatement) statement;
branchStack.push(new Branch(stmtLocation.getNodeOffset(), elifStmt.taken()));
- branch.setEndOffset(stmtLocation.getNodeOffset() - 1);
- IRegion converted= converter != null ? converter.historicToActual(branch) : branch;
- branches.add(new Branch(converted.getOffset(), converted.getLength(), branch.taken()));
+ branch.setEndOffset(stmtLocation.getNodeOffset());
+ if (converter != null) {
+ IRegion converted= converter.historicToActual(branch);
+ branch= new Branch(converted.getOffset(), converted.getLength(), branch.taken());
+ }
+ branches.add(branch);
} else if (statement instanceof IASTPreprocessorEndifStatement) {
if (branchStack.isEmpty()) {
// #endif without #if
@@ -1183,13 +1191,17 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
}
Branch branch= (Branch)branchStack.pop();
branch.setEndOffset(stmtLocation.getNodeOffset() + stmtLocation.getNodeLength());
- IRegion converted= converter != null ? converter.historicToActual(branch) : branch;
- branches.add(new Branch(converted.getOffset(), converted.getLength(), branch.taken()));
+ if (converter != null) {
+ IRegion converted= converter.historicToActual(branch);
+ branch= new Branch(converted.getOffset(), converted.getLength(), branch.taken());
+ }
+ branch.setInclusive(true);
+ branches.add(branch);
}
}
for (Iterator iter = branches.iterator(); iter.hasNext(); ) {
Branch branch= (Branch) iter.next();
- IRegion aligned = alignRegion(branch, ctx);
+ IRegion aligned = alignRegion(branch, ctx, branch.fInclusive);
if (aligned != null) {
Position alignedPos= new Position(aligned.getOffset(), aligned.getLength());
ctx.addProjectionRange(new CProjectionAnnotation(!branch.taken() && ctx.collapseInactiveCode(), computeKey(branch, ctx), false), alignedPos);
@@ -1230,10 +1242,10 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
ITypedRegion partition = partitions[i];
boolean singleLine= false;
if (ICPartitions.C_MULTI_LINE_COMMENT.equals(partition.getType())) {
- Position position= createCommentPosition(alignRegion(partition, ctx));
+ Position position= createCommentPosition(alignRegion(partition, ctx, true));
if (position != null) {
if (startLine >= 0 && endLine - startLine >= fMinCommentLines) {
- Position projection = createCommentPosition(alignRegion(commentRange, ctx));
+ Position projection = createCommentPosition(alignRegion(commentRange, ctx, true));
if (projection != null) {
comments.add(new Tuple(new CProjectionAnnotation(collapse, doc.get(projection.offset, Math.min(16, projection.length)), true), projection));
}
@@ -1264,7 +1276,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
}
if (startLine < 0 || lineNr - endLine > 1) {
if (startLine >= 0 && endLine - startLine >= fMinCommentLines) {
- Position projection = createCommentPosition(alignRegion(commentRange, ctx));
+ Position projection = createCommentPosition(alignRegion(commentRange, ctx, true));
if (projection != null) {
comments.add(new Tuple(new CProjectionAnnotation(collapse, doc.get(projection.offset, Math.min(16, projection.length)), true), projection));
}
@@ -1281,7 +1293,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
}
}
if (startLine >= 0 && endLine - startLine >= fMinCommentLines) {
- Position projection = createCommentPosition(alignRegion(commentRange, ctx));
+ Position projection = createCommentPosition(alignRegion(commentRange, ctx, true));
if (projection != null) {
comments.add(new Tuple(new CProjectionAnnotation(collapse, doc.get(projection.offset, Math.min(16, projection.length)), true), projection));
}
@@ -1368,7 +1380,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
IRegion[] regions= computeProjectionRanges((ISourceReference) element, ctx);
if (regions.length > 0) {
- IRegion normalized= alignRegion(regions[regions.length - 1], ctx);
+ IRegion normalized= alignRegion(regions[regions.length - 1], ctx, true);
if (normalized != null) {
Position position= element instanceof IMember ? createMemberPosition(normalized, (IMember) element) : createCommentPosition(normalized);
if (position != null)
@@ -1405,7 +1417,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
/**
* Creates a comment folding position from an
- * {@link #alignRegion(IRegion, DefaultCFoldingStructureProvider.FoldingStructureComputationContext) aligned}
+ * {@link #alignRegion(IRegion, DefaultCFoldingStructureProvider.FoldingStructureComputationContext, boolean) aligned}
* region.
*
* @param aligned an aligned region
@@ -1420,7 +1432,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
/**
* Creates a folding position that remembers its member from an
- * {@link #alignRegion(IRegion, DefaultCFoldingStructureProvider.FoldingStructureComputationContext) aligned}
+ * {@link #alignRegion(IRegion, DefaultCFoldingStructureProvider.FoldingStructureComputationContext, boolean) aligned}
* region.
*
* @param aligned an aligned region
@@ -1445,6 +1457,24 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
* only one line)
*/
protected final IRegion alignRegion(IRegion region, FoldingStructureComputationContext ctx) {
+ return alignRegion(region, ctx, true);
+ }
+
+ /**
+ * Aligns region
to start and end at a line offset. The region's start is
+ * decreased to the next line offset, and the end offset increased to the next line start or the
+ * end of the document. null
is returned if region
is
+ * null
itself or does not comprise at least one line delimiter, as a single line
+ * cannot be folded.
+ *
+ * @param region the region to align, may be null
+ * @param ctx the folding context
+ * @param inclusive include line of end offset
+ * @return a region equal or greater than region
that is aligned with line
+ * offsets, null
if the region is too small to be foldable (e.g. covers
+ * only one line)
+ */
+ protected final IRegion alignRegion(IRegion region, FoldingStructureComputationContext ctx, boolean inclusive) {
if (region == null)
return null;
@@ -1459,11 +1489,14 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
int offset= document.getLineOffset(start);
int endOffset;
- if (document.getNumberOfLines() > end + 1)
- endOffset= document.getLineOffset(end + 1);
- else
- endOffset= document.getLineOffset(end) + document.getLineLength(end);
-
+ if (inclusive) {
+ if (document.getNumberOfLines() > end + 1)
+ endOffset= document.getLineOffset(end + 1);
+ else
+ endOffset= document.getLineOffset(end) + document.getLineLength(end);
+ } else {
+ endOffset= document.getLineOffset(end);
+ }
return new Region(offset, endOffset - offset);
} catch (BadLocationException x) {