Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add IndentWithTabs preference (closes #17)

  • Loading branch information...
commit 6643714d2ec42dd7e66afc1410e27343ac35964c 1 parent 4d1a1a8
@mdr authored
View
1  CHANGELOG
@@ -7,6 +7,7 @@
* Add SpacesWithinPatternBinders preference (issue #15)
* Add MultilineScaladocCommentsStartOnFirstLine preference (issue #16)
* FIX: infinite loop in lexer on malformed XML processing instructions / unparsed
+* Add IndentWithTabs preference (issue #17)
0.0.9 (26/February/11)
View
27 README.rst
@@ -146,6 +146,7 @@ Usage::
[+|-]formatXml Enable/disable Format XML literals
[+|-]indentLocalDefs Enable/disable Indent local defs an extra level
[+|-]indentPackageBlocks Enable/disable Indent package blocks
+ [+|-]indentWithTabs Enable/disable Use a tab character for indentation
[+|-]multilineScaladocCommentsStartOnFirstLine Enable/disable Start multiline Scaladoc comment body on same line as the opening '/**'
[+|-]preserveDanglingCloseParenthesis Enable/disable Allow a newline before a ')' in an argument expression.
[+|-]preserveSpaceBeforeArguments Enable/disable Preserve a space before a parenthesis argument
@@ -153,7 +154,7 @@ Usage::
[+|-]spaceBeforeColon Enable/disable Add a space before colons
[+|-]spaceInsideBrackets Enable/disable Require a space after '[' and before ']'
[+|-]spaceInsideParentheses Enable/disable Require a space after '(' and before ')'
- [+|-]spacesWithinPatternBinders Enable/disable Add a space around the @ token in pattern binders
+ [+|-]spacesWithinPatternBinders Enable/disable Add a space around the @ token in pattern binders
-alignSingleLineCaseStatements.maxArrowIndent=[1-100] Set Maximum number of spaces inserted before an arrow to align case statements
-indentSpaces=[1-10] Set Number of spaces to use for indentation
@@ -212,6 +213,8 @@ If ``true``, then::
shoeSize: Int,
favoriteColor: java.awt.Color)
+This option is disabled if ``indentWithTabs`` is ``true``.
+
alignSingleLineCaseStatements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -233,12 +236,14 @@ Is reformatted as::
case dd => 3
}
+This option is disabled if ``indentWithTabs`` is ``true``.
+
alignSingleLineCaseStatements.maxArrowIndent
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Default: ``40``
-When using alignSingleLineCaseStatements == true, this is a limit on
+When ``alignSingleLineCaseStatements`` is ``true``, this is a limit on
the number of spaces that can be inserted before an arrow to align it
with other case statements. This can be used to avoid very large gaps,
e.g.::
@@ -248,13 +253,12 @@ e.g.::
case ccc => 2
}
-
compactStringConcatenation
~~~~~~~~~~~~~~~~~~~~~~~~~~
Default: ``false``
-Omit spaces when formatting a '+' operator on String literals". For example, If ``false``, then::
+Omit spaces when formatting a '+' operator on String literals. For example, If ``false``, then::
"Hello " + name + "!"
@@ -356,7 +360,20 @@ indentSpaces
Default: ``2``
-The number of spaces to use for each level of indentation.
+The number of spaces to use for each level of indentation.
+
+This option is ignored if ``indentWithTabs`` is ``true``.
+
+indentWithTabs
+~~~~~~~~~~~~~~
+
+Default: ``false``
+
+Use a tab for each level of indentation. When set to ``true``, this
+ignores any setting given for ``indentSpaces``. In addition, for the
+moment, ``alignSingleLineCaseStatements`` and ``alignParameters``
+options are not supported when indenting with tabs, and XML
+indentation is handled differently.
multilineScaladocCommentsStartOnFirstLine
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
View
10 scalariform.maven-plugin/src/main/java/org/scalariform/ScalariformMojo.java
@@ -68,6 +68,11 @@
/**
* @parameter default-value=false
*/
+ protected int indentWithTabs;
+
+ /**
+ * @parameter default-value=false
+ */
protected int multilineScaladocCommentsStartOnFirstLine;
/**
@@ -116,6 +121,8 @@ public void execute() throws MojoExecutionException {
formatXml,
indentLocalDefs,
indentPackageBlocks,
+ indentSpaces,
+ indentWithTabs,
multilineScaladocCommentsStartOnFirstLine,
preserveDanglingCloseParenthesis,
preserveSpaceBeforeArguments,
@@ -123,8 +130,7 @@ public void execute() throws MojoExecutionException {
spaceBeforeColon,
spacesInsideBrackets,
spacesInsideParentheses,
- spacesWithinPatternBinders,
- indentSpaces);
+ spacesWithinPatternBinders);
}
}
View
8 scalariform.maven-plugin/src/main/scala/org/scalariform/MojoFormatter.scala
@@ -50,6 +50,8 @@ object MojoFormatter {
formatXml: Boolean,
indentLocalDefs: Boolean,
indentPackageBlocks: Boolean,
+ indentSpaces: Int,
+ indentWithTabs: Boolean,
multilineScaladocCommentsStartOnFirstLine: Boolean,
preserveDanglingCloseParenthesis: Boolean,
preserveSpaceBeforeArguments: Boolean,
@@ -57,8 +59,7 @@ object MojoFormatter {
spaceBeforeColon: Boolean,
spacesInsideBrackets: Boolean,
spacesInsideParentheses: Boolean,
- spacesWithinPatternBinders: Boolean,
- indentSpaces: Int) {
+ spacesWithinPatternBinders: Boolean) {
val preferences = FormattingPreferences()
.setPreference(AlignParameters, alignParameters)
@@ -69,6 +70,8 @@ object MojoFormatter {
.setPreference(FormatXml, formatXml)
.setPreference(IndentLocalDefs, indentLocalDefs)
.setPreference(IndentPackageBlocks, indentPackageBlocks)
+ .setPreference(IndentSpaces, indentSpaces)
+ .setPreference(IndentWithTabs, indentWithTabs)
.setPreference(MultilineScaladocCommentsStartOnFirstLine, multilineScaladocCommentsStartOnFirstLine)
.setPreference(PreserveDanglingCloseParenthesis, preserveDanglingCloseParenthesis)
.setPreference(PreserveSpaceBeforeArguments, preserveSpaceBeforeArguments)
@@ -77,7 +80,6 @@ object MojoFormatter {
.setPreference(SpacesInsideParentheses, spacesInsideParentheses)
.setPreference(SpacesInsideBrackets, spacesInsideBrackets)
.setPreference(SpacesWithinPatternBinders, spacesWithinPatternBinders)
- .setPreference(IndentSpaces, indentSpaces)
val files = findScalaFiles(path)
View
2  scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala
@@ -13,7 +13,7 @@ import scala.math.{ max, min }
trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter with HasHiddenTokenInfo with ScalaFormatter
def format(caseClauses: CaseClauses)(implicit formatterState: FormatterState): FormatResult = {
- val clauseGroups = if (formattingPreferences(AlignSingleLineCaseStatements))
+ val clauseGroups = if (formattingPreferences(AlignSingleLineCaseStatements) && !formattingPreferences(IndentWithTabs))
groupClauses(caseClauses)
else
caseClauses.caseClauses.map(Right(_))
View
7 scalariform/src/main/scala/scalariform/formatter/ExprFormatter.scala
@@ -804,12 +804,13 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi
val relativeToken = paramClause.tokens(1) // TODO
var formatResult: FormatResult = NoFormatResult
var paramFormatterState = formatterState
+ val alignParameters = formattingPreferences(AlignParameters) && !formattingPreferences(IndentWithTabs)
for (firstParam firstParamOption) {
val token = implicitOption getOrElse firstParam.firstToken
if (hiddenPredecessors(token).containsNewline) {
formatResult = formatResult.before(token, formatterState.indent(paramIndent).currentIndentLevelInstruction)
- paramFormatterState = if (formattingPreferences(AlignParameters)) formatterState.alignWithToken(relativeToken) else formatterState.indent(paramIndent)
- } else if (containsNewline(firstParam) && formattingPreferences(AlignParameters))
+ paramFormatterState = if (alignParameters) formatterState.alignWithToken(relativeToken) else formatterState.indent(paramIndent)
+ } else if (containsNewline(firstParam) && alignParameters)
paramFormatterState = formatterState.alignWithToken(relativeToken)
formatResult ++= format(firstParam)(paramFormatterState)
}
@@ -817,7 +818,7 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi
for ((comma, param) otherParams) {
val token = param.firstToken
if (hiddenPredecessors(token).containsNewline) {
- paramFormatterState = if (formattingPreferences(AlignParameters)) formatterState.alignWithToken(relativeToken) else formatterState.indent(paramIndent)
+ paramFormatterState = if (alignParameters) formatterState.alignWithToken(relativeToken) else formatterState.indent(paramIndent)
formatResult = formatResult.before(token, paramFormatterState.currentIndentLevelInstruction)
}
formatResult ++= format(param)(paramFormatterState)
View
16 scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala
@@ -132,12 +132,12 @@ abstract class ScalaFormatter extends HasFormattingPreferences with TypeFormatte
}
if (needGapBetweenThisAndPrevious)
builder.append(" ")
- val extraIndentSpaces = comment match {
- case SingleLineComment(_) if nextCommentOption.isDefined || includeBufferBeforeNextToken builder.currentIndentSpaces
- case _ 0
+ val extraIndent = comment match {
+ case SingleLineComment(_) if nextCommentOption.isDefined || includeBufferBeforeNextToken builder.currentIndent
+ case _ ""
}
builder.write(comment.token)
- builder.append(" " * extraIndentSpaces)
+ builder.append(extraIndent)
}
val needGapBetweenThisAndFollowing = cond(comments.lastOption) {
case Some(MultiLineComment(_)) if includeBufferBeforeNextToken true
@@ -163,10 +163,12 @@ abstract class ScalaFormatter extends HasFormattingPreferences with TypeFormatte
else
writeIntertokenCompact()
case PlaceAtColumn(indentLevel, spaces)
+ require(!formattingPreferences(IndentWithTabs))
writeIntertokenCompact()
val indentLength = Spaces(formattingPreferences(IndentSpaces)).length(indentLevel)
builder.append(" " * (indentLength + spaces - builder.currentColumn))
case EnsureNewlineAndIndent(indentLevel, relativeTo)
+ require(!(formattingPreferences(IndentWithTabs) && relativeTo.isDefined))
val baseIndentOption = relativeTo flatMap tokenIndentMap.get
if (hiddenTokens.isEmpty) {
builder.ensureAtBeginningOfLine()
@@ -237,7 +239,7 @@ abstract class ScalaFormatter extends HasFormattingPreferences with TypeFormatte
baseIndent baseIndentOption
n 1 to baseIndent
} builder.append(" ")
- val indentChars = Spaces(formattingPreferences(IndentSpaces)).indent(indentLevel)
+ val indentChars = formattingPreferences.indentStyle.indent(indentLevel)
builder.append(indentChars)
builder
}
@@ -274,13 +276,13 @@ abstract class ScalaFormatter extends HasFormattingPreferences with TypeFormatte
builder.length - pos - 1
}
- def currentIndentSpaces = {
+ def currentIndent = {
val current = currentColumn
val lineStart = builder.length - currentColumn
var pos = lineStart
while (pos < builder.length && builder(pos).isWhitespace)
pos += 1
- pos - lineStart
+ builder.substring(lineStart, pos)
}
def lastCharacter = if (builder.length == 0) None else Some(lastChar)
View
16 scalariform/src/main/scala/scalariform/formatter/XmlFormatter.scala
@@ -11,7 +11,9 @@ trait XmlFormatter { self: HasFormattingPreferences with ExprFormatter with Scal
val XmlExpr(first: XmlContents, otherElements: List[XmlContents]) = xmlExpr
var formatResult: FormatResult = NoFormatResult
formatResult ++= format(first)
- val nestedFormatterState = formatterState.alignWithToken(first.firstToken)
+ val nestedFormatterState =
+ if (formattingPreferences(IndentWithTabs)) formatterState
+ else formatterState.alignWithToken(first.firstToken)
val (contentsFormatResult, multiline) = format(otherElements)(formatterState, nestedFormatterState)
formatResult ++= contentsFormatResult
formatResult
@@ -79,11 +81,17 @@ trait XmlFormatter { self: HasFormattingPreferences with ExprFormatter with Scal
val XmlNonEmptyElement(startTag: XmlStartTag, contents: List[XmlContents], endTag: XmlEndTag) = xmlNonEmpty
var formatResult: FormatResult = NoFormatResult
formatResult ++= format(startTag)
- val nestedFormatterState = formatterState.alignWithToken(startTag.firstToken).indent
+ val nestedFormatterState =
+ if (formattingPreferences(IndentWithTabs)) formatterState.indent
+ else formatterState.alignWithToken(startTag.firstToken).indent
val (contentsFormatResult, multiline) = format(contents)(formatterState, nestedFormatterState)
formatResult ++= contentsFormatResult
- if (multiline)
- formatResult = formatResult.before(endTag.firstToken, formatterState.alignWithToken(startTag.firstToken).currentIndentLevelInstruction)
+ if (multiline) {
+ val instruction =
+ if (formattingPreferences(IndentWithTabs)) formatterState.currentIndentLevelInstruction
+ else formatterState.alignWithToken(startTag.firstToken).currentIndentLevelInstruction
+ formatResult = formatResult.before(endTag.firstToken, instruction)
+ }
formatResult ++= format(endTag)
formatResult
}
View
4 scalariform/src/main/scala/scalariform/formatter/preferences/IFormattingPreferences.scala
@@ -8,6 +8,8 @@ trait IFormattingPreferences {
def preferencesMap: Map[PreferenceDescriptor[_], Any]
+ def indentStyle: IndentStyle
+
}
abstract sealed class IndentStyle {
@@ -34,6 +36,8 @@ class FormattingPreferences(val preferencesMap: Map[PreferenceDescriptor[_], Any
def setPreference[T](preference: PreferenceDescriptor[T], value: T) = new FormattingPreferences(preferencesMap + (preference -> value))
override def toString = getClass.getSimpleName + "(" + preferencesMap + ")"
+
+ val indentStyle = if (this(IndentWithTabs)) Tabs else Spaces(this(IndentSpaces))
}
case object FormattingPreferences extends FormattingPreferences(Map()) {
View
8 scalariform/src/main/scala/scalariform/formatter/preferences/PreferenceDescriptor.scala
@@ -63,7 +63,7 @@ object AllPreferences {
val preferences: List[PreferenceDescriptor[_]] = List(RewriteArrowSymbols, IndentSpaces, SpaceBeforeColon, CompactStringConcatenation,
PreserveSpaceBeforeArguments, AlignParameters, DoubleIndentClassDeclaration, FormatXml, IndentPackageBlocks,
AlignSingleLineCaseStatements, AlignSingleLineCaseStatements.MaxArrowIndent, IndentLocalDefs, PreserveDanglingCloseParenthesis,
- SpaceInsideParentheses, SpaceInsideBrackets, SpacesWithinPatternBinders, MultilineScaladocCommentsStartOnFirstLine)
+ SpaceInsideParentheses, SpaceInsideBrackets, SpacesWithinPatternBinders, MultilineScaladocCommentsStartOnFirstLine, IndentWithTabs)
val preferencesByKey: Map[String, PreferenceDescriptor[_]] = {
var map: Map[String, PreferenceDescriptor[_]] = Map()
@@ -178,3 +178,9 @@ case object MultilineScaladocCommentsStartOnFirstLine extends BooleanPreferenceD
val description = "Start multiline Scaladoc comment body on same line as the opening '/**' "
val defaultValue = false
}
+
+case object IndentWithTabs extends BooleanPreferenceDescriptor {
+ val key = "indentWithTabs"
+ val description = "Use a tab character for indentation"
+ val defaultValue = false
+}
View
66 scalariform/src/main/scala/scalariform/parser/InferredSemicolonScalaParser.scala
@@ -96,26 +96,26 @@ class InferredSemicolonScalaParser(tokens: Array[Token]) {
private def isTemplateIntro: Boolean = currentTokenType match {
case OBJECT | CLASS | TRAIT true
- case CASE if caseObject true
- case CASE if caseClass true
- case _ false
+ case CASE if caseObject true
+ case CASE if caseClass true
+ case _ false
}
private def isDclIntro: Boolean = currentTokenType match {
case VAL | VAR | DEF | TYPE true
- case _ false
+ case _ false
}
private def isDefIntro: Boolean = isTemplateIntro || isDclIntro
private def isNumericLit: Boolean = currentTokenType match {
case INTEGER_LITERAL | FLOATING_POINT_LITERAL true
- case _ false
+ case _ false
}
private def isUnaryOp: Boolean = currentTokenType match {
case MINUS | PLUS | TILDE | EXCLAMATION true
- case _ false
+ case _ false
}
private def isIdent: Boolean = isIdent(currentTokenType)
@@ -146,8 +146,8 @@ class InferredSemicolonScalaParser(tokens: Array[Token]) {
private def isTypeIntroToken(tokenType: TokenType): Boolean = tokenType match {
case THIS | SUPER | USCORE | LPAREN | AT true
- case _ if isIdent(tokenType) true
- case _ false
+ case _ if isIdent(tokenType) true
+ case _ false
}
private def isTypeIntro: Boolean = isTypeIntroToken(currentTokenType)
@@ -464,7 +464,7 @@ class InferredSemicolonScalaParser(tokens: Array[Token]) {
case LBRACE
inBraces(block())
case LPAREN inParens(expr())
- case _ expr
+ case _ expr
}
val catchClauseOption =
if (!CATCH)
@@ -578,7 +578,7 @@ class InferredSemicolonScalaParser(tokens: Array[Token]) {
private def isOpAssignmentName(name: String) = name match {
case "!=" | "<=" | ">=" | "" false
- case _ name.endsWith("=") && !name.startsWith("=") && ScalaOnlyLexer.isOperatorPart(name(0))
+ case _ name.endsWith("=") && !name.startsWith("=") && ScalaOnlyLexer.isOperatorPart(name(0))
}
private def postfixExpr() {
@@ -906,7 +906,7 @@ class InferredSemicolonScalaParser(tokens: Array[Token]) {
if (ownerIsTypeName) {
currentTokenType match {
case VAL | VAR nextToken()
- case _
+ case _
}
}
ident()
@@ -1050,11 +1050,11 @@ class InferredSemicolonScalaParser(tokens: Array[Token]) {
}
private def defOrDcl(localDef: Boolean = false) = currentTokenType match {
- case VAL patDefOrDcl()
- case VAR patDefOrDcl()
- case DEF funDefOrDcl(localDef)
+ case VAL patDefOrDcl()
+ case VAR patDefOrDcl()
+ case DEF funDefOrDcl(localDef)
case TYPE typeDefOrDcl()
- case _ tmplDef()
+ case _ tmplDef()
}
def nonLocalDefOrDcl() {
@@ -1159,12 +1159,12 @@ class InferredSemicolonScalaParser(tokens: Array[Token]) {
private def tmplDef() {
currentTokenType match {
- case TRAIT classDef()
- case CLASS classDef()
- case CASE if lookahead(1) == CLASS classDef()
- case OBJECT objectDef()
+ case TRAIT classDef()
+ case CLASS classDef()
+ case CASE if lookahead(1) == CLASS classDef()
+ case OBJECT objectDef()
case CASE if lookahead(1) == OBJECT objectDef()
- case _ throw new ScalaParserException("expected start of definition, but was " + currentTokenType)
+ case _ throw new ScalaParserException("expected start of definition, but was " + currentTokenType)
}
}
@@ -1448,14 +1448,14 @@ class InferredSemicolonScalaParser(tokens: Array[Token]) {
xmlStartTag(isPattern)
while (!XML_END_OPEN) {
currentTokenType match {
- case XML_START_OPEN xmlElement(isPattern)
- case XML_PCDATA XmlPCDATA(nextToken())
- case XML_COMMENT XmlComment(nextToken())
- case XML_CDATA XmlCDATA(nextToken())
- case XML_UNPARSED XmlUnparsed(nextToken())
+ case XML_START_OPEN xmlElement(isPattern)
+ case XML_PCDATA XmlPCDATA(nextToken())
+ case XML_COMMENT XmlComment(nextToken())
+ case XML_CDATA XmlCDATA(nextToken())
+ case XML_UNPARSED XmlUnparsed(nextToken())
case XML_PROCESSING_INSTRUCTION XmlProcessingInstruction(nextToken())
- case LBRACE xmlEmbeddedScala(isPattern)
- case _ throw new ScalaParserException("Unexpected token in XML: " + currentToken)
+ case LBRACE xmlEmbeddedScala(isPattern)
+ case _ throw new ScalaParserException("Unexpected token in XML: " + currentToken)
}
}
xmlEndTag()
@@ -1468,13 +1468,13 @@ class InferredSemicolonScalaParser(tokens: Array[Token]) {
private def xml(isPattern: Boolean) {
def xmlContent() {
currentTokenType match {
- case XML_START_OPEN xmlElement(isPattern)
- case XML_PCDATA XmlPCDATA(nextToken())
- case XML_COMMENT XmlComment(nextToken())
- case XML_CDATA XmlCDATA(nextToken())
- case XML_UNPARSED XmlUnparsed(nextToken())
+ case XML_START_OPEN xmlElement(isPattern)
+ case XML_PCDATA XmlPCDATA(nextToken())
+ case XML_COMMENT XmlComment(nextToken())
+ case XML_CDATA XmlCDATA(nextToken())
+ case XML_UNPARSED XmlUnparsed(nextToken())
case XML_PROCESSING_INSTRUCTION XmlProcessingInstruction(nextToken())
- case _ throw new ScalaParserException("Expected XML: " + currentToken)
+ case _ throw new ScalaParserException("Expected XML: " + currentToken)
}
xmlContent()
}
View
54 scalariform/src/test/scala/scalariform/formatter/IndentWithTabsTest.scala
@@ -0,0 +1,54 @@
+package scalariform.formatter
+
+import scalariform.parser._
+import scalariform.formatter._
+import scalariform.formatter.preferences._
+
+// format: OFF
+class IndentWithTabsTest extends AbstractFormatterTest {
+
+ implicit val formattingPreferences = FormattingPreferences.setPreference(IndentWithTabs, true)
+
+ """class A {
+ |
+ |def meth() {
+ |
+ |println("42") // wibble
+ |println("wobble")
+ |
+ |}
+ |
+ |}""" ==>
+ """class A {
+ |
+ | def meth() {
+ |
+ | println("42") // wibble
+ | println("wobble")
+ |
+ | }
+ |
+ |}"""
+
+ """val n = 42 +
+ |3""" ==>
+ """val n = 42 +
+ | 3"""
+
+ """val xml = <foo>
+ |bar
+ |</foo>""" ==>
+ """val xml = <foo>
+ | bar
+ |</foo>"""
+
+
+ override val debug = false
+
+ type Result = CompilationUnit
+
+ def parse(parser: ScalaParser) = parser.compilationUnitOrScript
+
+ def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState())
+
+}
Please sign in to comment.
Something went wrong with that request. Please try again.