是否可以编写命令来支持多行参数,即其中包含新行,如heredocs? [英] Can commands be written to support multi-line arguments, i.e. with new lines in them, as heredocs?

查看:47
本文介绍了是否可以编写命令来支持多行参数,即其中包含新行,如heredocs?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何编写支持带有换行符的参数作为 heredocs 的 sbt 命令?

How might one write a sbt command that supports arguments with newlines in them as heredocs?

我想要一个 sbt 命令,用户可以在其中粘贴多行文本块,然后将其处理/转换为其他内容.目前的实验似乎表明 sbt 会在遇到换行符后立即尝试解析命令.

I'd like to have an sbt command where the user can paste a multi-line block of text that is then processed/converted into something else. Experiments so far seem to indicate that sbt attempts to parse the command immediately after a newline is encountered.

注意:这只是解释所需 SBT 功能的一个用例.我寻找其他机制来处理 SBT 中的 pom.xml 文件;相反,如何实现具有多行参数的自定义命令.

Note: this is just a use case to explain the desired SBT functionality. I am not looking for other mechanisms to process pom.xml files in SBT; rather, how one implements a custom command that has multi-line arguments.

假设我希望用户能够将来自 Maven POM 文件的 XML 代码片段粘贴到 SBT REPL 中,并将所有依赖项转换为 SBT 语法.如果 XML 代码都在一行中,这里有一个实现:

Suppose I'd like the ability for the user to paste a fragment of XML code from a Maven POM file into the SBT REPL and have it convert all the dependencies into SBT syntax. Here's an implementation that works if the XML code is all on a single line:

// NB: Requires SBT >= 0.13.5
package pomhelpers

import sbt._
import Keys._
import sbt.complete.Parser
import sbt.complete.DefaultParsers._
/** 
 * Plugin to install an SBT command to assist in converting Maven dependency syntax
 * to SBT DSL.
 */
object ExtractMvnDependencies extends AutoPlugin {
    override def trigger = allRequirements
    override lazy val projectSettings = Seq(commands ++= Seq(pomLibs2Sbt))

    val Pom2SbtCommand = "pom2sbt"
    val Pom2SbtHelp = "<pom-xml-fragment>"

    // **How should this be constructed to handle mult-line inputs?**
    val MultiLineCommandInputParser: Parser[String] =  
        OptSpace ~> (StringBasic | StringVerbatim)

    lazy val pomLibs2Sbt = Command(
        Pom2SbtCommand, 
        Help((Pom2SbtCommand, Pom2SbtHelp)))(_ => MultiLineCommandInputParser) { (state , xmlFrag) =>

        val sbtdeps = pomXml2SbtDsl(xmlFrag)
        println(sbtdeps.mkString("\n"))
        state
    }


    /** Convert POM string to SBT form. */
    private def pomXml2SbtDsl(xmlFrag: String): Seq[String] = {
        import scala.xml._
        val deps = XML.loadString(xmlFrag) \\ "dependency"
        deps map ((dependency) => {
            val coords = Seq("groupId", "artifactId", "version", "scope")
            val coordParts = coords.map(coord => (dependency \ coord).text.trim).filter(_.nonEmpty)
            coordParts.mkString("\"", "\" % \"", "\"")
        })
    }
}

安装此插件后,您可以在 SBT REPL 中运行以下内容:

With this plugin installed, one can run the following in the SBT REPL:

pom2sbt "<dependency><groupId>org.foo</groupId><artifactId>megalib</artifactId><version>1.1.1</version></dependency>"

pom2sbt """<dependency><groupId>org.foo</groupId><artifactId>megalib</artifactId><version>1.1.1</version></dependency>"""

并得到:

"org.foo" % "megalib" % "1.1.1"

哪个是正确的输出,但重新格式化输入字符串以适合一行会破坏大部分实用程序的好处.

Which is the correct output, but reformatting the input string to fit on one line defeats most of the utility benefit.

所需的功能是(在这种情况下,在一般的多行命令参数情况下)键入 pom2sbt """,粘贴整个多行文本块,以 """,并对整个命令进行 SBT 延迟解析,直到关闭 heredoc 分隔符,如下所示:

The desired capability is to (in this case, and in the general multi-line command argument case) type pom2sbt """, paste the whole multi-line text block, end with """, and have SBT delay parsing of the whole command until the closing heredoc delimiter, like this:

pom2sbt """<dependency>
<groupId>org.foo</groupId>
<artifactId>megalib</artifactId>
<version>1.1.1</version>
</dependency>"""

然而,即使在示例代码中使用 StringVerbatim 解析器时,SBT 也会在第一个换行符后给您一个解析错误:

However, even when using the StringVerbatim parser as in the example code, SBT gives you a parse error after the first newline:

> pom2sbt """<dependency>
[error] Expected '"""'
[error] pom2sbt """<dependency>
[error]                        ^
>     <groupId>org.foo</groupId>
[error] Expected symbol
[error] < usage:
[error] 
[error] 
[error] More command help available using 'help <command>' for:
[error]   <
...

推荐答案

我怀疑这里的问题是命令行处理程序(使用 jline)过早地将命令行值传递给 sbt.在 Unix 上,您需要转义新行以避免 shell 执行命令,我认为这里也会发生同样的情况.

I suspect the issue here is with the command line handler (using jline) passing command line values to sbt too prematurely. On Unixes you need to escape the new line to avoid the shell to execute a command and I think the same happens here.

我不知道是否有办法避免执行模式并进入多行模式.我也不认为 sbt 提供该功能.

I don't know if there's a way to avoid the execution mode and enter multiline one, though. I also don't think that sbt offers the feature.

经过进一步调查,LineReader 揭示了所有的行处理.我对它在 sbt 中的使用方式的理解告诉我,在输入按键或特殊值之前,无法指示 sbt 继续读取行.

Upon closer investigation, LineReader reveals all the line handling. My understanding of how it's used in sbt tells me that there's no way to instruct sbt to keep reading lines until a keystroke or a special value gets entered.

shell 内部命令执行实例化 FullReader 的工作,然后读取行以便在代码中查看它,该代码是机器实例化的地方.

The shell internal command does the job of instantiating FullReader and then reading lines so to see it in the code that's where the machinery gets instantiated.

这篇关于是否可以编写命令来支持多行参数,即其中包含新行,如heredocs?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆