Skip to content

Commit

Permalink
Added support for generating SwiftUI Text concatenation variants
Browse files Browse the repository at this point in the history
  • Loading branch information
Obbut committed Jan 10, 2020
1 parent 8042078 commit b4890ae
Showing 1 changed file with 69 additions and 3 deletions.
72 changes: 69 additions & 3 deletions Sources/owowgenerate-ios/Writers/SwiftUICodeWriter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ func makeSwiftUICode(strings: StringsCollection) -> String {
return writer.output
}

private func writeStrings(strings: StringsCollection, writer: inout SwiftCodeWriter) {
fileprivate func writeStrings(strings: StringsCollection, writer: inout SwiftCodeWriter) {
for (name, collection) in strings.subCollections.sorted(by: { $0.key < $1.key }) {
writer.addLine()

Expand All @@ -25,8 +25,6 @@ private func writeStrings(strings: StringsCollection, writer: inout SwiftCodeWri
}

for key in strings.keys {
writer.addDocComment(key.comment)

let memberName = (key.key.split(separator: ".").last ?? "").camelCase(delimiter: "-", upper: false)

if key.placeholders.isEmpty {
Expand All @@ -37,6 +35,7 @@ private func writeStrings(strings: StringsCollection, writer: inout SwiftCodeWri
additionalArguments = ""
}

writer.addDocComment(key.comment)
writer.addLine("static var \(memberName): Text { Text(\"\(key.key)\"\(additionalArguments)) }")
} else {
let parameters = key.placeholders.enumerated().map { index, type in
Expand All @@ -45,11 +44,78 @@ private func writeStrings(strings: StringsCollection, writer: inout SwiftCodeWri

let parameterUsage = key.placeholders.indices.map { "placeholder\($0)" }.joined(separator: ", ")

writer.addDocComment(key.comment)
writer.inBlock("static func \(memberName)(\(parameters)) -> Text") { writer in
writer.addLine("let format = NSLocalizedString(\"\(key.key)\", comment: \(SwiftCodeWriter.makeStringLiteral(key.comment)))")
writer.addLine("let string = String(format: format, \(parameterUsage))")
writer.addLine("return Text(verbatim: string)")
}

if key.placeholders.contains(.object) {
// Generate a variant that works with text concatenation
writeTextConcatenationFunction(writer: &writer, key: key, memberName: memberName)
}
}
}
}

fileprivate func writeTextConcatenationFunction(writer: inout SwiftCodeWriter, key: StringsEntry, memberName: String) {
func makePlaceholder(index: Int) -> String {
"⚠️OWOWGENERATE PLACEHOLDER \(index)⚠️"
}

let parameters = key.placeholders.enumerated().map { index, type in
let parameterType: String
if type == .object {
parameterType = "Text"
} else {
parameterType = type.rawValue
}

return "_ placeholder\(index): \(parameterType)"
}.joined(separator: ", ")

let parameterUsage = key.placeholders.enumerated().map { index, type in
if type == .object {
return SwiftCodeWriter.makeStringLiteral(makePlaceholder(index: index))
} else {
return "placeholder\(index)"
}
}.joined(separator: ", ")

guard let firstTextPlaceholderIndex = key.placeholders.firstIndex(of: .object), let lastTextPlaceholderIndex = key.placeholders.lastIndex(of: .object) else {
fatalError("No object placeholders while writing text concatenation function")
}

writer.addDocComment(key.comment)
writer.inBlock("static func \(memberName)(\(parameters)) -> Text") { writer in
writer.addLine("let format = NSLocalizedString(\"\(key.key)\", comment: \(SwiftCodeWriter.makeStringLiteral(key.comment)))")
writer.addLine("let temporaryString = String(format: format, \(parameterUsage))")

// first placeholder range
writer.inBlock("guard let placeholder\(firstTextPlaceholderIndex)Range = temporaryString.range(of: \(SwiftCodeWriter.makeStringLiteral(makePlaceholder(index: firstTextPlaceholderIndex)))) else") { writer in
writer.addLine("fatalError(\"Placeholder \(firstTextPlaceholderIndex) not found in string\")")
}

writer.addDocComment("Construct the first part of the text view, consisting of the static first portion until the first placeholder + the value for the first placeholder")
writer.addLine("var text = Text(verbatim: String(temporaryString[temporaryString.startIndex..<placeholder\(firstTextPlaceholderIndex)Range.lowerBound])) + placeholder\(firstTextPlaceholderIndex)")

let lastCodeGeneratedPlaceholderNumber = firstTextPlaceholderIndex

if firstTextPlaceholderIndex != lastTextPlaceholderIndex {
for (index, element) in key.placeholders.enumerated() where index > firstTextPlaceholderIndex && element == .object {
let placeholderString = makePlaceholder(index: index)
let placeholderStringLiteral = SwiftCodeWriter.makeStringLiteral(placeholderString)

writer.inBlock("guard let placeholder\(index)Range = temporaryString.range(of: \(placeholderStringLiteral)) else") { writer in
writer.addLine("fatalError(\"Placeholder \(index) not found in string\")")
}

writer.addLine("text = text + Text(verbatim: String(temporaryString[placeholder\(lastCodeGeneratedPlaceholderNumber)Range.upperBound..<placeholder\(index)Range.lowerBound])) + placeholder\(index)")
}
}

writer.addLine("text = text + Text(verbatim: String(temporaryString[placeholder\(lastTextPlaceholderIndex)Range.upperBound..<temporaryString.endIndex]))")
writer.addLine("return text")
}
}

0 comments on commit b4890ae

Please sign in to comment.