Skip to content

Commit

Permalink
Better selection of for expr body, skip guards, skip block val/fun bo…
Browse files Browse the repository at this point in the history
…dy, tweak parser to match scalac.
  • Loading branch information
mdr committed Feb 7, 2011
1 parent 148576f commit 47702c1
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 13 deletions.
33 changes: 21 additions & 12 deletions scalariform/src/main/scala/scalariform/astselect/AstSelector.scala
Expand Up @@ -31,19 +31,18 @@ object AstSelector {
classOf[FunDefOrDcl],
classOf[ParenArgumentExprs],
classOf[GeneralTokens],
classOf[Guard],
classOf[ParamClause],
classOf[ParamClauses],
classOf[PatDefOrDcl],
classOf[ProcFunBody],
classOf[Template],
classOf[TemplateBody],
classOf[TemplateParents],
classOf[TypeDefOrDcl],
classOf[TypeExprElement],
classOf[TypeParamClause])

private val nonSelectableChildParentNodes: Set[(Class[_], Class[_])] =
Set(
(classOf[BlockExpr], classOf[MatchExpr]))
}

class AstSelector(source: String) {
Expand All @@ -53,7 +52,7 @@ class AstSelector(source: String) {
private val compilationUnit = new ScalaParser(tokens.toArray).compilationUnitOrScript()

def expandSelection(initialSelection: Range): Option[Range] =
expandToToken(initialSelection) orElse expandToEnclosingAst(compilationUnit, initialSelection, parent = None)
expandToToken(initialSelection) orElse expandToEnclosingAst(compilationUnit, initialSelection, enclosingNodes = Nil)

private def expandToToken(initialSelection: Range): Option[Range] = {
val Range(offset, length) = initialSelection
Expand All @@ -76,22 +75,32 @@ class AstSelector(source: String) {
isLiteral || isKeyword || isComment || isId || (selectableXmls contains tokenType)
}

private def expandToEnclosingAst(node: AstNode, initialSelection: Range, parent: Option[AstNode]): Option[Range] =
private def expandToEnclosingAst(node: AstNode, initialSelection: Range, enclosingNodes: List[AstNode]): Option[Range] =
node.rangeOpt flatMap { nodeRange
for {
childNode node.immediateChildren
descendantRange expandToEnclosingAst(childNode, initialSelection, parent = Some(node))
descendantRange expandToEnclosingAst(childNode, initialSelection, enclosingNodes = node :: enclosingNodes)
} return Some(descendantRange)
if (nodeRange.contains(initialSelection) && nodeRange.length > initialSelection.length && isSelectableAst(node, parent))
if (nodeRange.contains(initialSelection) && nodeRange.length > initialSelection.length && isSelectableAst(node, enclosingNodes))
Some(nodeRange)
else
None
}

private def isSelectableAst(node: AstNode, parentOpt: Option[AstNode]) =
if (nonSelectableAstNodes contains node.getClass)
false
else
!(parentOpt exists { parent nonSelectableChildParentNodes contains (node.getClass, parent.getClass) })
private def isSelectableAst(node: AstNode, enclosingNodes: List[AstNode]) = {
// println((node:: enclosingNodes) map (_.getClass.getSimpleName) mkString " ")
(node :: enclosingNodes) match {
case n1 :: n2 :: _ if n1.isInstanceOf[BlockExpr] && n2.isInstanceOf[MatchExpr] false

case n1 :: n2 :: n3 :: _ if n1.isInstanceOf[BlockExpr] && n2.isInstanceOf[Expr] && n3.isInstanceOf[ForExpr] false
case n1 :: n2 :: _ if n1.isInstanceOf[Expr] && n2.isInstanceOf[ForExpr] false

case n1 :: n2 :: n3 :: _ if n1.isInstanceOf[BlockExpr] && n2.isInstanceOf[Expr] && n3.isInstanceOf[ExprFunBody] false
case n1 :: n2 :: _ if n1.isInstanceOf[Expr] && n2.isInstanceOf[ExprFunBody] false

case n1 :: n2 :: _ if n1.isInstanceOf[BlockExpr] && n2.isInstanceOf[ProcFunBody] false

case _ !(nonSelectableAstNodes contains node.getClass)
}
}
}
Expand Up @@ -827,7 +827,7 @@ class ScalaParser(tokens: Array[Token]) {
CaseClause(CasePattern(caseToken, pattern_, guardOption, arrow), blockStatSeq_)
}
if (caseClauses_.isEmpty)
throw new ScalaParserException("No case clauses found")
accept(CASE)
CaseClauses(caseClauses_)
}

Expand Down
Expand Up @@ -161,6 +161,22 @@ class AstSelectorTest extends FlatSpec with ShouldMatchers {
" $ " ~
" $$$$$$$$$$ "

" for (a ← b) { c } " ~
" $ " ~
" $$$$$$$$$$$$$$$$$ "

" for (a <- b if c) {} " ~
" $ " ~
" $$$$$$$$$$$ "

" def a = { b } " ~
" $ " ~
" $$$$$$$$$$$$$ "

" def a { b } " ~
" $ " ~
" $$$$$$$$$$$ "

private def findSelectionRange(s: String): Range = {
val barLocation = s indexOf '|'
if (barLocation >= 0)
Expand Down

0 comments on commit 47702c1

Please sign in to comment.