在SBT中构建递归依赖文件名解析器

时间:2018-05-19 06:28:13

标签: scala sbt

我正在尝试做一些在概念上非常简单的事情,为接受现有目录名称的输入任务构建Parser[File]

解析器将从一个基目录构建(默认情况下它将是用户的主目录),它将在子目录上完成选项卡,然后在子子目录等上递归选项卡完成。

我有一个几乎的实现。它正确地解析任何深度的现有子目录。然而,令我困惑的是,标签完成仅适用于顶层。解析引擎可以区分递归子目录中的不完整和无效输入(它只在没有可能的完成时打印{invalid input}),但它不打印子目录示例完成,或者tab-complete部分输入的目录,在顶部下方水平。对于递归子目录解析器,examples集是正确的(根据一些println调试),但是完成引擎似乎忽略它们。

我玩过token(...)分词的不同位置,但这似乎并不重要。

这是我的实施:

private val fsep = File.separator

private val thisDot = "."
private val upDot   = ".."

private [sbtethereum] def genDirectoryParser( file : File, acceptNewFiles : Boolean ) : Parser[File] = {
  token( Space.* ) ~> token( _genDirectoryParser( file, acceptNewFiles ) )
}

private def _genDirectoryParser( file : File, acceptNewFiles : Boolean ) : Parser[File] = {
  def parsersFromMap( m : immutable.TreeMap[String,File] ) : immutable.Seq[Parser[File]] = {
    immutable.Seq.empty[Parser[File]] ++ m.map { case ( input, f ) => literal( input ).flatMap( _ => _genDirectoryParser( f, acceptNewFiles ) ) }
  }

  if (!file.exists() || !file.isDirectory() || !file.canRead() ) {
    failure( s"'${file.getPath} must exist, and be a readable directory." )
  }
  else {
    val baseParser = Space.*.map( _ => file )
    val subdirs = file.list.map( new File( file, _ ) ).filter( _.isDirectory ).map( _.getName )
    val subdirsMap = immutable.TreeMap.empty[String,File] ++ subdirs.map( name => Tuple2( name + fsep, new File( file, name ) ) )
    val subdirParsers = parsersFromMap( subdirsMap )
    val roots = File.listRoots
    val rootsMap = immutable.TreeMap.empty[String,File] ++ roots.map( r => Tuple2( r.getAbsolutePath, r ) )
    val rootParsers = parsersFromMap( rootsMap )
    val dotsMap = immutable.TreeMap( (thisDot + fsep) -> file, (upDot + fsep) -> file.getParentFile )
    val dotsParsers = parsersFromMap( dotsMap )

    val examples = immutable.TreeSet.empty[String] ++ subdirsMap.keySet ++ rootsMap.keySet ++ dotsMap.keySet

    val residualParser = if ( acceptNewFiles ) {
      def okChar( c : Char ) = ( c >= 48 && c < 58 ) || ( c >= 65 && c < 123 ) || (".-_".indexOf(c) >= 0)
      val fileChar = charClass( okChar, "Acceptable filename characters" )
      fileChar.+.map( chars => new File( file, chars.mkString ) )
    }
    else {
      failure( "Not an existing directory" )
    }

    ( (subdirParsers ++ rootParsers ++ dotsParsers :+ residualParser).foldLeft( baseParser ){ ( last, next ) => last | next } ).examples( examples, !acceptNewFiles )
  }
}

我的实现比我描述的稍微复杂一些。它还接受文件系统根以及“点”路径元素(whatever/../whatever等)之类的东西,并且可以选择接受新文件的名称。但我不认为这些皱纹可能与依赖解析器的非完成有很大关系。 (我错了吗?)

感谢您的帮助!

0 个答案:

没有答案