我正在尝试做一些在概念上非常简单的事情,为接受现有目录名称的输入任务构建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
等)之类的东西,并且可以选择接受新文件的名称。但我不认为这些皱纹可能与依赖解析器的非完成有很大关系。 (我错了吗?)
感谢您的帮助!