feat: Adds generate commands that call to pandoc to generate pdf, latex, and html files from a project.

This commit is contained in:
2024-12-13 15:33:20 -05:00
parent d1b3379815
commit 3f56dda568
22 changed files with 606 additions and 57 deletions

View File

@@ -0,0 +1,14 @@
import ArgumentParser
struct GenerateCommand: AsyncParsableCommand {
static let commandName = "generate"
static let configuration = CommandConfiguration(
commandName: commandName,
subcommands: [
GeneratePdfCommand.self,
GenerateLatexCommand.self,
GenerateHtmlCommand.self
]
)
}

View File

@@ -0,0 +1,24 @@
import ArgumentParser
import CliClient
import Dependencies
// TODO: Need to add a step to build prior to generating file.
struct GenerateHtmlCommand: AsyncParsableCommand {
static let commandName = "html"
static let configuration = CommandConfiguration(
commandName: commandName
)
@OptionGroup var globals: GenerateOptions
mutating func run() async throws {
@Dependency(\.cliClient) var cliClient
try await cliClient.runPandocCommand(
globals.pandocOptions(.html),
logging: globals.loggingOptions(commandName: Self.commandName)
)
}
}

View File

@@ -0,0 +1,23 @@
import ArgumentParser
import CliClient
import Dependencies
// TODO: Need to add a step to build prior to generating file.
struct GenerateLatexCommand: AsyncParsableCommand {
static let commandName = "latex"
static let configuration = CommandConfiguration(
commandName: commandName
)
@OptionGroup var globals: GenerateOptions
mutating func run() async throws {
@Dependency(\.cliClient) var cliClient
try await cliClient.runPandocCommand(
globals.pandocOptions(.latex),
logging: globals.loggingOptions(commandName: Self.commandName)
)
}
}

View File

@@ -0,0 +1,87 @@
import ArgumentParser
import CliClient
@dynamicMemberLookup
struct GenerateOptions: ParsableArguments {
@OptionGroup var basic: BasicGlobalOptions
@Option(
name: [.short, .customLong("file")],
help: "Files used to generate the output, can be specified multiple times.",
completion: .file()
)
var files: [String] = []
@Option(
name: [.customShort("H"), .long],
help: "Files to include in the header, can be specified multiple times.",
completion: .file()
)
var includeInHeader: [String] = []
@Flag(
help: "Do not build the project prior to generating the output."
)
var noBuild: Bool = false
@Option(
name: .shortAndLong,
help: "The project directory.",
completion: .directory
)
var projectDirectory: String?
@Option(
name: .shortAndLong,
help: "The output directory",
completion: .directory
)
var outputDirectory: String?
@Option(
name: [.customShort("n"), .customLong("name")],
help: "Name of the output file."
)
var outputFileName: String?
// NOTE: This must be last, both here and in the commands, so if the commands have options of their
// own, they must be declared ahead of using the global options.
@Argument(
help: "Extra arguments / options to pass to the underlying pandoc command."
)
var extraOptions: [String] = []
subscript<T>(dynamicMember keyPath: WritableKeyPath<BasicGlobalOptions, T>) -> T {
get { basic[keyPath: keyPath] }
set { basic[keyPath: keyPath] = newValue }
}
subscript<T>(dynamicMember keyPath: KeyPath<BasicGlobalOptions, T>) -> T {
basic[keyPath: keyPath]
}
}
extension GenerateOptions {
func loggingOptions(commandName: String) -> CliClient.LoggingOptions {
basic.loggingOptions(commandName: commandName)
}
func pandocOptions(
_ fileType: CliClient.PandocOptions.FileType
) -> CliClient.PandocOptions {
.init(
files: files.count > 0 ? files : nil,
includeInHeader: includeInHeader.count > 0 ? includeInHeader : nil,
outputDirectory: outputDirectory,
outputFileName: outputFileName,
outputFileType: fileType,
projectDirectory: projectDirectory,
quiet: basic.quiet,
shell: basic.shell,
shouldBuild: !noBuild
)
}
}

View File

@@ -0,0 +1,32 @@
import ArgumentParser
import CliClient
import Dependencies
// TODO: Need to add a step to build prior to generating file.
struct GeneratePdfCommand: AsyncParsableCommand {
static let commandName = "pdf"
static let configuration = CommandConfiguration(
commandName: commandName
)
@Option(
name: [.customShort("e"), .customLong("engine")],
help: "The pdf engine to use."
)
var pdfEngine: String?
@OptionGroup var globals: GenerateOptions
mutating func run() async throws {
@Dependency(\.cliClient) var cliClient
let output = try await cliClient.runPandocCommand(
globals.pandocOptions(.pdf(engine: pdfEngine)),
logging: globals.loggingOptions(commandName: Self.commandName)
)
print(output)
}
}