mirror of https://github.com/status-im/NimYAML.git
Presenter: Let user decide about newline style
* Added PresentationOptions object; merged PresentationStyle, indentationStep and NewLineStyle in it * Updated signatures of relevant procs * Implemented user-defined newline style in presenter
This commit is contained in:
parent
349cb19912
commit
46913867e2
|
@ -189,16 +189,16 @@ proc serialize*(doc: YamlDocument, tagLib: TagLibrary, a: AnchorStyle = asTidy):
|
||||||
result = initYamlStream(backend)
|
result = initYamlStream(backend)
|
||||||
|
|
||||||
proc dumpDOM*(doc: YamlDocument, target: Stream,
|
proc dumpDOM*(doc: YamlDocument, target: Stream,
|
||||||
style: PresentationStyle = psDefault,
|
anchorStyle: AnchorStyle = asTidy,
|
||||||
anchorStyle: AnchorStyle = asTidy, indentationStep: int = 2)
|
options: PresentationOptions = defaultPresentationOptions)
|
||||||
{.raises: [YamlPresenterJsonError, YamlPresenterOutputError].} =
|
{.raises: [YamlPresenterJsonError, YamlPresenterOutputError].} =
|
||||||
## Dump a YamlDocument as YAML character stream.
|
## Dump a YamlDocument as YAML character stream.
|
||||||
var
|
var
|
||||||
tagLib = initExtendedTagLibrary()
|
tagLib = initExtendedTagLibrary()
|
||||||
events = serialize(doc, tagLib,
|
events = serialize(doc, tagLib,
|
||||||
if style == psJson: asNone else: anchorStyle)
|
if options.style == psJson: asNone else: anchorStyle)
|
||||||
try:
|
try:
|
||||||
present(events, target, tagLib, style, indentationStep)
|
present(events, target, tagLib, options)
|
||||||
except YamlStreamError:
|
except YamlStreamError:
|
||||||
# serializing object does not raise any errors, so we can ignore this
|
# serializing object does not raise any errors, so we can ignore this
|
||||||
assert false, "Can never happen"
|
assert false, "Can never happen"
|
|
@ -16,6 +16,12 @@ type
|
||||||
ScalarStyle = enum
|
ScalarStyle = enum
|
||||||
sLiteral, sFolded, sPlain, sDoubleQuoted
|
sLiteral, sFolded, sPlain, sDoubleQuoted
|
||||||
|
|
||||||
|
proc defineOptions*(style: PresentationStyle = psDefault,
|
||||||
|
indentationStep: int = 2, newlines:
|
||||||
|
NewLineStyle = nlOSDefault): PresentationOptions =
|
||||||
|
result = PresentationOptions(style: style, indentationStep: indentationStep,
|
||||||
|
newlines: newlines)
|
||||||
|
|
||||||
proc inspect(scalar: string, indentation: int,
|
proc inspect(scalar: string, indentation: int,
|
||||||
words, lines: var seq[tuple[start, finish: int]]):
|
words, lines: var seq[tuple[start, finish: int]]):
|
||||||
ScalarStyle {.raises: [].} =
|
ScalarStyle {.raises: [].} =
|
||||||
|
@ -89,7 +95,8 @@ proc inspect(scalar: string, indentation: int,
|
||||||
elif canUsePlain: result = sPlain
|
elif canUsePlain: result = sPlain
|
||||||
else: result = sDoubleQuoted
|
else: result = sDoubleQuoted
|
||||||
|
|
||||||
proc writeDoubleQuoted(scalar: string, s: Stream, indentation: int)
|
proc writeDoubleQuoted(scalar: string, s: Stream, indentation: int,
|
||||||
|
newline: string)
|
||||||
{.raises: [YamlPresenterOutputError].} =
|
{.raises: [YamlPresenterOutputError].} =
|
||||||
var curPos = indentation
|
var curPos = indentation
|
||||||
try:
|
try:
|
||||||
|
@ -97,7 +104,8 @@ proc writeDoubleQuoted(scalar: string, s: Stream, indentation: int)
|
||||||
curPos.inc()
|
curPos.inc()
|
||||||
for c in scalar:
|
for c in scalar:
|
||||||
if curPos == 79:
|
if curPos == 79:
|
||||||
s.write("\\\l")
|
s.write('\\')
|
||||||
|
s.write(newline)
|
||||||
s.write(repeat(' ', indentation))
|
s.write(repeat(' ', indentation))
|
||||||
curPos = indentation
|
curPos = indentation
|
||||||
if c == ' ':
|
if c == ' ':
|
||||||
|
@ -155,14 +163,14 @@ proc writeDoubleQuotedJson(scalar: string, s: Stream)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
proc writeLiteral(scalar: string, indentation, indentStep: int, s: Stream,
|
proc writeLiteral(scalar: string, indentation, indentStep: int, s: Stream,
|
||||||
lines: seq[tuple[start, finish: int]])
|
lines: seq[tuple[start, finish: int]], newline: string)
|
||||||
{.raises: [YamlPresenterOutputError].} =
|
{.raises: [YamlPresenterOutputError].} =
|
||||||
try:
|
try:
|
||||||
s.write('|')
|
s.write('|')
|
||||||
if scalar[^1] != '\l': s.write('-')
|
if scalar[^1] != '\l': s.write('-')
|
||||||
if scalar[0] in [' ', '\t']: s.write($indentStep)
|
if scalar[0] in [' ', '\t']: s.write($indentStep)
|
||||||
for line in lines:
|
for line in lines:
|
||||||
s.write('\l')
|
s.write(newline)
|
||||||
s.write(repeat(' ', indentation + indentStep))
|
s.write(repeat(' ', indentation + indentStep))
|
||||||
if line.finish >= line.start:
|
if line.finish >= line.start:
|
||||||
s.write(scalar[line.start .. line.finish])
|
s.write(scalar[line.start .. line.finish])
|
||||||
|
@ -173,18 +181,18 @@ proc writeLiteral(scalar: string, indentation, indentStep: int, s: Stream,
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
proc writeFolded(scalar: string, indentation, indentStep: int, s: Stream,
|
proc writeFolded(scalar: string, indentation, indentStep: int, s: Stream,
|
||||||
words: seq[tuple[start, finish: int]])
|
words: seq[tuple[start, finish: int]], newline: string)
|
||||||
{.raises: [YamlPresenterOutputError].} =
|
{.raises: [YamlPresenterOutputError].} =
|
||||||
try:
|
try:
|
||||||
s.write("|-")
|
s.write("|-")
|
||||||
var curPos = 80
|
var curPos = 80
|
||||||
for word in words:
|
for word in words:
|
||||||
if word.start > 0 and scalar[word.start - 1] == '\l':
|
if word.start > 0 and scalar[word.start - 1] == '\l':
|
||||||
s.write("\l\l")
|
s.write(newline & newline)
|
||||||
s.write(repeat(' ', indentation + indentStep))
|
s.write(repeat(' ', indentation + indentStep))
|
||||||
curPos = indentation + indentStep
|
curPos = indentation + indentStep
|
||||||
elif curPos + (word.finish - word.start) > 80:
|
elif curPos + (word.finish - word.start) > 80:
|
||||||
s.write('\l')
|
s.write(newline)
|
||||||
s.write(repeat(' ', indentation + indentStep))
|
s.write(repeat(' ', indentation + indentStep))
|
||||||
curPos = indentation + indentStep
|
curPos = indentation + indentStep
|
||||||
else:
|
else:
|
||||||
|
@ -207,12 +215,12 @@ template safeWrite(s: string or char) {.dirty.} =
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
proc startItem(target: Stream, style: PresentationStyle, indentation: int,
|
proc startItem(target: Stream, style: PresentationStyle, indentation: int,
|
||||||
state: var DumperState, isObject: bool)
|
state: var DumperState, isObject: bool, newline: string)
|
||||||
{.raises: [YamlPresenterOutputError].} =
|
{.raises: [YamlPresenterOutputError].} =
|
||||||
try:
|
try:
|
||||||
case state
|
case state
|
||||||
of dBlockMapValue:
|
of dBlockMapValue:
|
||||||
target.write('\l')
|
target.write(newline)
|
||||||
target.write(repeat(' ', indentation))
|
target.write(repeat(' ', indentation))
|
||||||
if isObject or style == psCanonical:
|
if isObject or style == psCanonical:
|
||||||
target.write("? ")
|
target.write("? ")
|
||||||
|
@ -222,7 +230,7 @@ proc startItem(target: Stream, style: PresentationStyle, indentation: int,
|
||||||
of dBlockInlineMap:
|
of dBlockInlineMap:
|
||||||
state = dBlockImplicitMapKey
|
state = dBlockImplicitMapKey
|
||||||
of dBlockExplicitMapKey:
|
of dBlockExplicitMapKey:
|
||||||
target.write('\l')
|
target.write(newline)
|
||||||
target.write(repeat(' ', indentation))
|
target.write(repeat(' ', indentation))
|
||||||
target.write(": ")
|
target.write(": ")
|
||||||
state = dBlockMapValue
|
state = dBlockMapValue
|
||||||
|
@ -231,14 +239,14 @@ proc startItem(target: Stream, style: PresentationStyle, indentation: int,
|
||||||
state = dBlockMapValue
|
state = dBlockMapValue
|
||||||
of dFlowExplicitMapKey:
|
of dFlowExplicitMapKey:
|
||||||
if style != psMinimal:
|
if style != psMinimal:
|
||||||
target.write('\l')
|
target.write(newline)
|
||||||
target.write(repeat(' ', indentation))
|
target.write(repeat(' ', indentation))
|
||||||
target.write(": ")
|
target.write(": ")
|
||||||
state = dFlowMapValue
|
state = dFlowMapValue
|
||||||
of dFlowMapValue:
|
of dFlowMapValue:
|
||||||
if (isObject and style != psMinimal) or
|
if (isObject and style != psMinimal) or
|
||||||
style in [psJson, psCanonical]:
|
style in [psJson, psCanonical]:
|
||||||
target.write(",\l" & repeat(' ', indentation))
|
target.write(',' & newline & repeat(' ', indentation))
|
||||||
if style == psJson:
|
if style == psJson:
|
||||||
state = dFlowImplicitMapKey
|
state = dFlowImplicitMapKey
|
||||||
else:
|
else:
|
||||||
|
@ -253,7 +261,7 @@ proc startItem(target: Stream, style: PresentationStyle, indentation: int,
|
||||||
of dFlowMapStart:
|
of dFlowMapStart:
|
||||||
if (isObject and style != psMinimal) or
|
if (isObject and style != psMinimal) or
|
||||||
style in [psJson, psCanonical]:
|
style in [psJson, psCanonical]:
|
||||||
target.write("\l" & repeat(' ', indentation))
|
target.write(newline & repeat(' ', indentation))
|
||||||
if style == psJson:
|
if style == psJson:
|
||||||
state = dFlowImplicitMapKey
|
state = dFlowImplicitMapKey
|
||||||
else:
|
else:
|
||||||
|
@ -265,7 +273,7 @@ proc startItem(target: Stream, style: PresentationStyle, indentation: int,
|
||||||
target.write(": ")
|
target.write(": ")
|
||||||
state = dFlowMapValue
|
state = dFlowMapValue
|
||||||
of dBlockSequenceItem:
|
of dBlockSequenceItem:
|
||||||
target.write('\l')
|
target.write(newline)
|
||||||
target.write(repeat(' ', indentation))
|
target.write(repeat(' ', indentation))
|
||||||
target.write("- ")
|
target.write("- ")
|
||||||
of dFlowSequenceStart:
|
of dFlowSequenceStart:
|
||||||
|
@ -273,7 +281,7 @@ proc startItem(target: Stream, style: PresentationStyle, indentation: int,
|
||||||
of psMinimal, psDefault:
|
of psMinimal, psDefault:
|
||||||
discard
|
discard
|
||||||
of psCanonical, psJson:
|
of psCanonical, psJson:
|
||||||
target.write('\l')
|
target.write(newline)
|
||||||
target.write(repeat(' ', indentation))
|
target.write(repeat(' ', indentation))
|
||||||
of psBlockOnly:
|
of psBlockOnly:
|
||||||
discard # can never happen
|
discard # can never happen
|
||||||
|
@ -283,7 +291,7 @@ proc startItem(target: Stream, style: PresentationStyle, indentation: int,
|
||||||
of psMinimal, psDefault:
|
of psMinimal, psDefault:
|
||||||
target.write(", ")
|
target.write(", ")
|
||||||
of psCanonical, psJson:
|
of psCanonical, psJson:
|
||||||
target.write(",\l")
|
target.write(',' & newline)
|
||||||
target.write(repeat(' ', indentation))
|
target.write(repeat(' ', indentation))
|
||||||
of psBlockOnly:
|
of psBlockOnly:
|
||||||
discard # can never happen
|
discard # can never happen
|
||||||
|
@ -327,24 +335,24 @@ proc writeTagAndAnchor(target: Stream, tag: TagId, tagLib: TagLibrary,
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
|
proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
|
||||||
style: PresentationStyle = psDefault,
|
options: PresentationOptions = defaultPresentationOptions) =
|
||||||
indentationStep: int = 2) =
|
|
||||||
var
|
var
|
||||||
indentation = 0
|
indentation = 0
|
||||||
levels = newSeq[DumperState]()
|
levels = newSeq[DumperState]()
|
||||||
cached = initQueue[YamlStreamEvent]()
|
cached = initQueue[YamlStreamEvent]()
|
||||||
|
let newline = if options.newlines == nlLF: "\l"
|
||||||
|
elif options.newlines == nlCRLF: "\c\l" else: "\n"
|
||||||
while cached.len > 0 or not s.finished():
|
while cached.len > 0 or not s.finished():
|
||||||
let item = if cached.len > 0: cached.dequeue else: s.next()
|
let item = if cached.len > 0: cached.dequeue else: s.next()
|
||||||
case item.kind
|
case item.kind
|
||||||
of yamlStartDocument:
|
of yamlStartDocument:
|
||||||
if style != psJson:
|
if options.style != psJson:
|
||||||
# TODO: tag directives
|
# TODO: tag directives
|
||||||
try:
|
try:
|
||||||
target.write("%YAML 1.2\l")
|
target.write("%YAML 1.2" & newline)
|
||||||
if tagLib.secondaryPrefix != yamlTagRepositoryPrefix:
|
if tagLib.secondaryPrefix != yamlTagRepositoryPrefix:
|
||||||
target.write("%TAG !! " &
|
target.write("%TAG !! " &
|
||||||
tagLib.secondaryPrefix & '\l')
|
tagLib.secondaryPrefix & newline)
|
||||||
target.write("--- ")
|
target.write("--- ")
|
||||||
except:
|
except:
|
||||||
var e = newException(YamlPresenterOutputError, "")
|
var e = newException(YamlPresenterOutputError, "")
|
||||||
|
@ -352,16 +360,16 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
|
||||||
raise e
|
raise e
|
||||||
of yamlScalar:
|
of yamlScalar:
|
||||||
if levels.len == 0:
|
if levels.len == 0:
|
||||||
if style != psJson:
|
if options.style != psJson:
|
||||||
safeWrite('\l')
|
safeWrite(newline)
|
||||||
else:
|
else:
|
||||||
startItem(target, style, indentation, levels[levels.high],
|
startItem(target, options.style, indentation,
|
||||||
false)
|
levels[levels.high], false, newline)
|
||||||
if style != psJson:
|
if options.style != psJson:
|
||||||
writeTagAndAnchor(target,
|
writeTagAndAnchor(target,
|
||||||
item.scalarTag, tagLib, item.scalarAnchor)
|
item.scalarTag, tagLib, item.scalarAnchor)
|
||||||
|
|
||||||
if style == psJson:
|
if options.style == psJson:
|
||||||
let hint = guessType(item.scalarContent)
|
let hint = guessType(item.scalarContent)
|
||||||
if item.scalarTag in [yTagQuestionMark, yTagBoolean] and
|
if item.scalarTag in [yTagQuestionMark, yTagBoolean] and
|
||||||
hint in [yTypeBoolTrue, yTypeBoolFalse]:
|
hint in [yTypeBoolTrue, yTypeBoolFalse]:
|
||||||
|
@ -384,26 +392,28 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
|
||||||
safeWrite(item.scalarContent)
|
safeWrite(item.scalarContent)
|
||||||
else:
|
else:
|
||||||
writeDoubleQuotedJson(item.scalarContent, target)
|
writeDoubleQuotedJson(item.scalarContent, target)
|
||||||
elif style == psCanonical:
|
elif options.style == psCanonical:
|
||||||
writeDoubleQuoted(item.scalarContent, target,
|
writeDoubleQuoted(item.scalarContent, target,
|
||||||
indentation + indentationStep)
|
indentation + options.indentationStep,
|
||||||
|
newline)
|
||||||
else:
|
else:
|
||||||
var words, lines = newSeq[tuple[start, finish: int]]()
|
var words, lines = newSeq[tuple[start, finish: int]]()
|
||||||
case item.scalarContent.inspect(indentation + indentationStep,
|
case item.scalarContent.inspect(
|
||||||
words, lines)
|
indentation + options.indentationStep, words, lines)
|
||||||
of sLiteral: writeLiteral(item.scalarContent, indentation,
|
of sLiteral: writeLiteral(item.scalarContent, indentation,
|
||||||
indentationStep, target, lines)
|
options.indentationStep, target, lines, newline)
|
||||||
of sFolded: writeFolded(item.scalarContent, indentation,
|
of sFolded: writeFolded(item.scalarContent, indentation,
|
||||||
indentationStep, target, words)
|
options.indentationStep, target, words, newline)
|
||||||
of sPlain: safeWrite(item.scalarContent)
|
of sPlain: safeWrite(item.scalarContent)
|
||||||
of sDoubleQuoted: writeDoubleQuoted(item.scalarContent, target,
|
of sDoubleQuoted: writeDoubleQuoted(item.scalarContent, target,
|
||||||
indentation + indentationStep)
|
indentation + options.indentationStep, newline)
|
||||||
of yamlAlias:
|
of yamlAlias:
|
||||||
if style == psJson:
|
if options.style == psJson:
|
||||||
raise newException(YamlPresenterJsonError,
|
raise newException(YamlPresenterJsonError,
|
||||||
"Alias not allowed in JSON output")
|
"Alias not allowed in JSON output")
|
||||||
assert levels.len > 0
|
assert levels.len > 0
|
||||||
startItem(target, style, indentation, levels[levels.high], false)
|
startItem(target, options.style, indentation, levels[levels.high],
|
||||||
|
false, newline)
|
||||||
try:
|
try:
|
||||||
target.write('*')
|
target.write('*')
|
||||||
target.write(cast[byte]('a') + cast[byte](item.aliasTarget))
|
target.write(cast[byte]('a') + cast[byte](item.aliasTarget))
|
||||||
|
@ -413,7 +423,7 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
|
||||||
raise e
|
raise e
|
||||||
of yamlStartSequence:
|
of yamlStartSequence:
|
||||||
var nextState: DumperState
|
var nextState: DumperState
|
||||||
case style
|
case options.style
|
||||||
of psDefault:
|
of psDefault:
|
||||||
var length = 0
|
var length = 0
|
||||||
while true:
|
while true:
|
||||||
|
@ -445,33 +455,34 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
|
||||||
|
|
||||||
if levels.len == 0:
|
if levels.len == 0:
|
||||||
if nextState == dBlockSequenceItem:
|
if nextState == dBlockSequenceItem:
|
||||||
if style != psJson:
|
if options.style != psJson:
|
||||||
writeTagAndAnchor(target,
|
writeTagAndAnchor(target,
|
||||||
item.seqTag, tagLib, item.seqAnchor)
|
item.seqTag, tagLib, item.seqAnchor)
|
||||||
else:
|
else:
|
||||||
if style != psJson:
|
if options.style != psJson:
|
||||||
writeTagAndAnchor(target,
|
writeTagAndAnchor(target,
|
||||||
item.seqTag, tagLib, item.seqAnchor)
|
item.seqTag, tagLib, item.seqAnchor)
|
||||||
safeWrite('\l')
|
safeWrite(newline)
|
||||||
indentation += indentationStep
|
indentation += options.indentationStep
|
||||||
else:
|
else:
|
||||||
startItem(target, style, indentation, levels[levels.high], true)
|
startItem(target, options.style, indentation,
|
||||||
if style != psJson:
|
levels[levels.high], true, newline)
|
||||||
|
if options.style != psJson:
|
||||||
writeTagAndAnchor(target,
|
writeTagAndAnchor(target,
|
||||||
item.seqTag, tagLib, item.seqAnchor)
|
item.seqTag, tagLib, item.seqAnchor)
|
||||||
indentation += indentationStep
|
indentation += options.indentationStep
|
||||||
|
|
||||||
if nextState == dFlowSequenceStart:
|
if nextState == dFlowSequenceStart:
|
||||||
safeWrite('[')
|
safeWrite('[')
|
||||||
if levels.len > 0 and style in [psJson, psCanonical] and
|
if levels.len > 0 and options.style in [psJson, psCanonical] and
|
||||||
levels[levels.high] in
|
levels[levels.high] in
|
||||||
[dBlockExplicitMapKey, dBlockMapValue,
|
[dBlockExplicitMapKey, dBlockMapValue,
|
||||||
dBlockImplicitMapKey, dBlockSequenceItem]:
|
dBlockImplicitMapKey, dBlockSequenceItem]:
|
||||||
indentation += indentationStep
|
indentation += options.indentationStep
|
||||||
levels.add(nextState)
|
levels.add(nextState)
|
||||||
of yamlStartMap:
|
of yamlStartMap:
|
||||||
var nextState: DumperState
|
var nextState: DumperState
|
||||||
case style
|
case options.style
|
||||||
of psDefault:
|
of psDefault:
|
||||||
type MapParseState = enum
|
type MapParseState = enum
|
||||||
mpInitial, mpKey, mpValue, mpNeedBlock
|
mpInitial, mpKey, mpValue, mpNeedBlock
|
||||||
|
@ -503,50 +514,50 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
|
||||||
nextState = dBlockMapValue
|
nextState = dBlockMapValue
|
||||||
if levels.len == 0:
|
if levels.len == 0:
|
||||||
if nextState == dBlockMapValue:
|
if nextState == dBlockMapValue:
|
||||||
if style != psJson:
|
if options.style != psJson:
|
||||||
writeTagAndAnchor(target,
|
writeTagAndAnchor(target,
|
||||||
item.mapTag, tagLib, item.mapAnchor)
|
item.mapTag, tagLib, item.mapAnchor)
|
||||||
else:
|
else:
|
||||||
if style != psJson:
|
if options.style != psJson:
|
||||||
safeWrite('\l')
|
safeWrite(newline)
|
||||||
writeTagAndAnchor(target,
|
writeTagAndAnchor(target,
|
||||||
item.mapTag, tagLib, item.mapAnchor)
|
item.mapTag, tagLib, item.mapAnchor)
|
||||||
indentation += indentationStep
|
indentation += options.indentationStep
|
||||||
else:
|
else:
|
||||||
if nextState in [dBlockMapValue, dBlockImplicitMapKey]:
|
if nextState in [dBlockMapValue, dBlockImplicitMapKey]:
|
||||||
startItem(target, style, indentation, levels[levels.high],
|
startItem(target, options.style, indentation,
|
||||||
true)
|
levels[levels.high], true, newline)
|
||||||
if style != psJson:
|
if options.style != psJson:
|
||||||
writeTagAndAnchor(target,
|
writeTagAndAnchor(target,
|
||||||
item.mapTag, tagLib, item.mapAnchor)
|
item.mapTag, tagLib, item.mapAnchor)
|
||||||
else:
|
else:
|
||||||
startItem(target, style, indentation, levels[levels.high],
|
startItem(target, options.style, indentation,
|
||||||
true)
|
levels[levels.high], true, newline)
|
||||||
if style != psJson:
|
if options.style != psJson:
|
||||||
writeTagAndAnchor(target,
|
writeTagAndAnchor(target,
|
||||||
item.mapTag, tagLib, item.mapAnchor)
|
item.mapTag, tagLib, item.mapAnchor)
|
||||||
indentation += indentationStep
|
indentation += options.indentationStep
|
||||||
|
|
||||||
if nextState == dFlowMapStart:
|
if nextState == dFlowMapStart:
|
||||||
safeWrite('{')
|
safeWrite('{')
|
||||||
if levels.len > 0 and style in [psJson, psCanonical] and
|
if levels.len > 0 and options.style in [psJson, psCanonical] and
|
||||||
levels[levels.high] in
|
levels[levels.high] in
|
||||||
[dBlockExplicitMapKey, dBlockMapValue,
|
[dBlockExplicitMapKey, dBlockMapValue,
|
||||||
dBlockImplicitMapKey, dBlockSequenceItem]:
|
dBlockImplicitMapKey, dBlockSequenceItem]:
|
||||||
indentation += indentationStep
|
indentation += options.indentationStep
|
||||||
levels.add(nextState)
|
levels.add(nextState)
|
||||||
|
|
||||||
of yamlEndSequence:
|
of yamlEndSequence:
|
||||||
assert levels.len > 0
|
assert levels.len > 0
|
||||||
case levels.pop()
|
case levels.pop()
|
||||||
of dFlowSequenceItem:
|
of dFlowSequenceItem:
|
||||||
case style
|
case options.style
|
||||||
of psDefault, psMinimal, psBlockOnly:
|
of psDefault, psMinimal, psBlockOnly:
|
||||||
safeWrite(']')
|
safeWrite(']')
|
||||||
of psJson, psCanonical:
|
of psJson, psCanonical:
|
||||||
indentation -= indentationStep
|
indentation -= options.indentationStep
|
||||||
try:
|
try:
|
||||||
target.write('\l')
|
target.write(newline)
|
||||||
target.write(repeat(' ', indentation))
|
target.write(repeat(' ', indentation))
|
||||||
target.write(']')
|
target.write(']')
|
||||||
except:
|
except:
|
||||||
|
@ -558,29 +569,29 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
|
||||||
dBlockImplicitMapKey, dBlockSequenceItem]:
|
dBlockImplicitMapKey, dBlockSequenceItem]:
|
||||||
continue
|
continue
|
||||||
of dFlowSequenceStart:
|
of dFlowSequenceStart:
|
||||||
if levels.len > 0 and style in [psJson, psCanonical] and
|
if levels.len > 0 and options.style in [psJson, psCanonical] and
|
||||||
levels[levels.high] in
|
levels[levels.high] in
|
||||||
[dBlockExplicitMapKey, dBlockMapValue,
|
[dBlockExplicitMapKey, dBlockMapValue,
|
||||||
dBlockImplicitMapKey, dBlockSequenceItem]:
|
dBlockImplicitMapKey, dBlockSequenceItem]:
|
||||||
indentation -= indentationStep
|
indentation -= options.indentationStep
|
||||||
safeWrite(']')
|
safeWrite(']')
|
||||||
of dBlockSequenceItem:
|
of dBlockSequenceItem:
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
assert false
|
assert false
|
||||||
indentation -= indentationStep
|
indentation -= options.indentationStep
|
||||||
of yamlEndMap:
|
of yamlEndMap:
|
||||||
assert levels.len > 0
|
assert levels.len > 0
|
||||||
let level = levels.pop()
|
let level = levels.pop()
|
||||||
case level
|
case level
|
||||||
of dFlowMapValue:
|
of dFlowMapValue:
|
||||||
case style
|
case options.style
|
||||||
of psDefault, psMinimal, psBlockOnly:
|
of psDefault, psMinimal, psBlockOnly:
|
||||||
safeWrite('}')
|
safeWrite('}')
|
||||||
of psJson, psCanonical:
|
of psJson, psCanonical:
|
||||||
indentation -= indentationStep
|
indentation -= options.indentationStep
|
||||||
try:
|
try:
|
||||||
target.write('\l')
|
target.write(newline)
|
||||||
target.write(repeat(' ', indentation))
|
target.write(repeat(' ', indentation))
|
||||||
target.write('}')
|
target.write('}')
|
||||||
except:
|
except:
|
||||||
|
@ -592,29 +603,29 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
|
||||||
dBlockImplicitMapKey, dBlockSequenceItem]:
|
dBlockImplicitMapKey, dBlockSequenceItem]:
|
||||||
continue
|
continue
|
||||||
of dFlowMapStart:
|
of dFlowMapStart:
|
||||||
if levels.len > 0 and style in [psJson, psCanonical] and
|
if levels.len > 0 and options.style in [psJson, psCanonical] and
|
||||||
levels[levels.high] in
|
levels[levels.high] in
|
||||||
[dBlockExplicitMapKey, dBlockMapValue,
|
[dBlockExplicitMapKey, dBlockMapValue,
|
||||||
dBlockImplicitMapKey, dBlockSequenceItem]:
|
dBlockImplicitMapKey, dBlockSequenceItem]:
|
||||||
indentation -= indentationStep
|
indentation -= options.indentationStep
|
||||||
safeWrite('}')
|
safeWrite('}')
|
||||||
of dBlockMapValue, dBlockInlineMap:
|
of dBlockMapValue, dBlockInlineMap:
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
assert false
|
assert false
|
||||||
indentation -= indentationStep
|
indentation -= options.indentationStep
|
||||||
of yamlEndDocument:
|
of yamlEndDocument:
|
||||||
if finished(s): break
|
if finished(s): break
|
||||||
safeWrite("...\l")
|
safeWrite("..." & newline)
|
||||||
|
|
||||||
proc transform*(input: Stream, output: Stream, style: PresentationStyle,
|
proc transform*(input: Stream, output: Stream,
|
||||||
indentationStep: int = 2) =
|
options: PresentationOptions = defaultPresentationOptions) =
|
||||||
var
|
var
|
||||||
taglib = initExtendedTagLibrary()
|
taglib = initExtendedTagLibrary()
|
||||||
parser = newYamlParser(tagLib)
|
parser = newYamlParser(tagLib)
|
||||||
events = parser.parse(input)
|
events = parser.parse(input)
|
||||||
try:
|
try:
|
||||||
if style == psCanonical:
|
if options.style == psCanonical:
|
||||||
var specificTagEvents = iterator(): YamlStreamEvent =
|
var specificTagEvents = iterator(): YamlStreamEvent =
|
||||||
for e in events:
|
for e in events:
|
||||||
var event = e
|
var event = e
|
||||||
|
@ -647,10 +658,9 @@ proc transform*(input: Stream, output: Stream, style: PresentationStyle,
|
||||||
event.scalarTag = yTagString
|
event.scalarTag = yTagString
|
||||||
yield event
|
yield event
|
||||||
var s = initYamlStream(specificTagEvents)
|
var s = initYamlStream(specificTagEvents)
|
||||||
present(s, output, tagLib, style,
|
present(s, output, tagLib, options)
|
||||||
indentationStep)
|
|
||||||
else:
|
else:
|
||||||
present(events, output, tagLib, style, indentationStep)
|
present(events, output, tagLib, options)
|
||||||
except YamlStreamError:
|
except YamlStreamError:
|
||||||
var e = getCurrentException()
|
var e = getCurrentException()
|
||||||
while e.parent of YamlStreamError: e = e.parent
|
while e.parent of YamlStreamError: e = e.parent
|
||||||
|
|
|
@ -635,13 +635,14 @@ proc represent*[T](value: T, ts: TagStyle = tsRootOnly,
|
||||||
else:
|
else:
|
||||||
result = initYamlStream(objStream)
|
result = initYamlStream(objStream)
|
||||||
|
|
||||||
proc dump*[K](value: K, target: Stream, style: PresentationStyle = psDefault,
|
proc dump*[K](value: K, target: Stream, tagStyle: TagStyle = tsRootOnly,
|
||||||
tagStyle: TagStyle = tsRootOnly,
|
anchorStyle: AnchorStyle = asTidy,
|
||||||
anchorStyle: AnchorStyle = asTidy, indentationStep: int = 2) =
|
options: PresentationOptions = defaultPresentationOptions) =
|
||||||
var events = represent(value, if style == psCanonical: tsAll else: tagStyle,
|
var events = represent(value,
|
||||||
if style == psJson: asNone else: anchorStyle)
|
if options.style == psCanonical: tsAll else: tagStyle,
|
||||||
|
if options.style == psJson: asNone else: anchorStyle)
|
||||||
try:
|
try:
|
||||||
present(events, target, serializationTagLibrary, style, indentationStep)
|
present(events, target, serializationTagLibrary, options)
|
||||||
except YamlStreamError:
|
except YamlStreamError:
|
||||||
# serializing object does not raise any errors, so we can ignore this
|
# serializing object does not raise any errors, so we can ignore this
|
||||||
assert false, "Can never happen"
|
assert false, "Can never happen"
|
|
@ -55,6 +55,11 @@ proc newNode(v: string): ref Node =
|
||||||
result.next = nil
|
result.next = nil
|
||||||
|
|
||||||
suite "Serialization":
|
suite "Serialization":
|
||||||
|
setup:
|
||||||
|
let
|
||||||
|
blockOnly = defineOptions(style=psBlockOnly)
|
||||||
|
|
||||||
|
|
||||||
test "Serialization: Load string sequence":
|
test "Serialization: Load string sequence":
|
||||||
let input = newStringStream(" - a\n - b")
|
let input = newStringStream(" - a\n - b")
|
||||||
var result: seq[string]
|
var result: seq[string]
|
||||||
|
@ -66,7 +71,7 @@ suite "Serialization":
|
||||||
test "Serialization: Represent string sequence":
|
test "Serialization: Represent string sequence":
|
||||||
var input = @["a", "b"]
|
var input = @["a", "b"]
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, psBlockOnly, tsNone)
|
dump(input, output, tsNone, asTidy, blockOnly)
|
||||||
assertStringEqual "%YAML 1.2\n--- \n- a\n- b", output.data
|
assertStringEqual "%YAML 1.2\n--- \n- a\n- b", output.data
|
||||||
|
|
||||||
test "Serialization: Load Table[int, string]":
|
test "Serialization: Load Table[int, string]":
|
||||||
|
@ -82,7 +87,7 @@ suite "Serialization":
|
||||||
input[23] = "dreiundzwanzig"
|
input[23] = "dreiundzwanzig"
|
||||||
input[42] = "zweiundvierzig"
|
input[42] = "zweiundvierzig"
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, psBlockOnly, tsNone)
|
dump(input, output, tsNone, asTidy, blockOnly)
|
||||||
assertStringEqual(
|
assertStringEqual(
|
||||||
"%YAML 1.2\n--- \n23: dreiundzwanzig\n42: zweiundvierzig",
|
"%YAML 1.2\n--- \n23: dreiundzwanzig\n42: zweiundvierzig",
|
||||||
output.data)
|
output.data)
|
||||||
|
@ -100,7 +105,7 @@ suite "Serialization":
|
||||||
let input = @[@[1.int32, 2.int32, 3.int32], @[4.int32, 5.int32],
|
let input = @[@[1.int32, 2.int32, 3.int32], @[4.int32, 5.int32],
|
||||||
@[6.int32]]
|
@[6.int32]]
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, psDefault, tsNone)
|
dump(input, output, tsNone)
|
||||||
assertStringEqual "%YAML 1.2\n--- \n- [1, 2, 3]\n- [4, 5]\n- [6]",
|
assertStringEqual "%YAML 1.2\n--- \n- [1, 2, 3]\n- [4, 5]\n- [6]",
|
||||||
output.data
|
output.data
|
||||||
|
|
||||||
|
@ -116,7 +121,7 @@ suite "Serialization":
|
||||||
test "Serialization: Represent Enum":
|
test "Serialization: Represent Enum":
|
||||||
let input = @[tlRed, tlGreen, tlYellow]
|
let input = @[tlRed, tlGreen, tlYellow]
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, psBlockOnly, tsNone)
|
dump(input, output, tsNone, asTidy, blockOnly)
|
||||||
assertStringEqual "%YAML 1.2\n--- \n- tlRed\n- tlGreen\n- tlYellow",
|
assertStringEqual "%YAML 1.2\n--- \n- tlRed\n- tlGreen\n- tlYellow",
|
||||||
output.data
|
output.data
|
||||||
|
|
||||||
|
@ -131,7 +136,7 @@ suite "Serialization":
|
||||||
test "Serialization: Represent Tuple":
|
test "Serialization: Represent Tuple":
|
||||||
let input = (str: "value", i: 42.int32, b: true)
|
let input = (str: "value", i: 42.int32, b: true)
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, psDefault, tsNone)
|
dump(input, output, tsNone)
|
||||||
assertStringEqual "%YAML 1.2\n--- \nstr: value\ni: 42\nb: y",
|
assertStringEqual "%YAML 1.2\n--- \nstr: value\ni: 42\nb: y",
|
||||||
output.data
|
output.data
|
||||||
|
|
||||||
|
@ -146,7 +151,7 @@ suite "Serialization":
|
||||||
test "Serialization: Represent custom object":
|
test "Serialization: Represent custom object":
|
||||||
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
|
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, psBlockOnly, tsNone)
|
dump(input, output, tsNone, asTidy, blockOnly)
|
||||||
assertStringEqual(
|
assertStringEqual(
|
||||||
"%YAML 1.2\n--- \nfirstnamechar: P\nsurname: Pan\nage: 12",
|
"%YAML 1.2\n--- \nfirstnamechar: P\nsurname: Pan\nage: 12",
|
||||||
output.data)
|
output.data)
|
||||||
|
@ -162,7 +167,7 @@ suite "Serialization":
|
||||||
test "Serialization: Represent sequence with explicit tags":
|
test "Serialization: Represent sequence with explicit tags":
|
||||||
let input = @["one", "two"]
|
let input = @["one", "two"]
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, psBlockOnly, tsAll)
|
dump(input, output, tsAll, asTidy, blockOnly)
|
||||||
assertStringEqual("%YAML 1.2\n--- !nim:system:seq(" &
|
assertStringEqual("%YAML 1.2\n--- !nim:system:seq(" &
|
||||||
"tag:yaml.org,2002:str) \n- !!str one\n- !!str two",
|
"tag:yaml.org,2002:str) \n- !!str one\n- !!str two",
|
||||||
output.data)
|
output.data)
|
||||||
|
@ -179,7 +184,7 @@ suite "Serialization":
|
||||||
test "Serialization: Represent custom object with explicit root tag":
|
test "Serialization: Represent custom object with explicit root tag":
|
||||||
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
|
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, psBlockOnly, tsRootOnly)
|
dump(input, output, tsRootOnly, asTidy, blockOnly)
|
||||||
assertStringEqual("%YAML 1.2\n" &
|
assertStringEqual("%YAML 1.2\n" &
|
||||||
"--- !nim:custom:Person \nfirstnamechar: P\nsurname: Pan\nage: 12",
|
"--- !nim:custom:Person \nfirstnamechar: P\nsurname: Pan\nage: 12",
|
||||||
output.data)
|
output.data)
|
||||||
|
@ -193,7 +198,7 @@ suite "Serialization":
|
||||||
b.next = c
|
b.next = c
|
||||||
c.next = a
|
c.next = a
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(a, output, psBlockOnly, tsRootOnly)
|
dump(a, output, tsRootOnly, asTidy, blockOnly)
|
||||||
assertStringEqual """%YAML 1.2
|
assertStringEqual """%YAML 1.2
|
||||||
--- !example.net:Node &a
|
--- !example.net:Node &a
|
||||||
value: a
|
value: a
|
||||||
|
@ -252,7 +257,7 @@ next:
|
||||||
input.add(new string)
|
input.add(new string)
|
||||||
input[1][] = "~"
|
input[1][] = "~"
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, psBlockOnly, tsRootOnly)
|
dump(input, output, tsRootOnly, asTidy, blockOnly)
|
||||||
assertStringEqual "%YAML 1.2\n--- !nim:system:seq(tag:yaml.org,2002:str) \n- !!null ~\n- !!str ~",
|
assertStringEqual "%YAML 1.2\n--- !nim:system:seq(tag:yaml.org,2002:str) \n- !!null ~\n- !!str ~",
|
||||||
output.data
|
output.data
|
||||||
|
|
||||||
|
@ -267,7 +272,7 @@ next:
|
||||||
test "Serialization: Custom representObject":
|
test "Serialization: Custom representObject":
|
||||||
let input = @[1.BetterInt, 9998887.BetterInt, 98312.BetterInt]
|
let input = @[1.BetterInt, 9998887.BetterInt, 98312.BetterInt]
|
||||||
var output = newStringStream()
|
var output = newStringStream()
|
||||||
dump(input, output, psBlockOnly, tsAll)
|
dump(input, output, tsAll, asTidy, blockOnly)
|
||||||
assertStringEqual """%YAML 1.2
|
assertStringEqual """%YAML 1.2
|
||||||
--- !nim:system:seq(test:BetterInt)
|
--- !nim:system:seq(test:BetterInt)
|
||||||
- !test:BetterInt 1
|
- !test:BetterInt 1
|
||||||
|
|
44
yaml.nim
44
yaml.nim
|
@ -205,6 +205,22 @@ type
|
||||||
## object is referenced again afterwards
|
## object is referenced again afterwards
|
||||||
asNone, asTidy, asAlways
|
asNone, asTidy, asAlways
|
||||||
|
|
||||||
|
NewLineStyle* = enum
|
||||||
|
## What kind of newline sequence is used when presenting.
|
||||||
|
##
|
||||||
|
## - ``nlLF``: Use a single linefeed char as newline.
|
||||||
|
## - ``nlCRLF``: Use a sequence of carriage return and linefeed as
|
||||||
|
## newline.
|
||||||
|
## - ``nlOSDefault``: Use the target operation system's default newline
|
||||||
|
## sequence (CRLF on Windows, LF everywhere else).
|
||||||
|
nlLF, nlCRLF, nlOSDefault
|
||||||
|
|
||||||
|
PresentationOptions* = object
|
||||||
|
## Options for generating a YAML character stream
|
||||||
|
style*: PresentationStyle
|
||||||
|
indentationStep*: int
|
||||||
|
newlines*: NewLineStyle
|
||||||
|
|
||||||
RefNodeData = object
|
RefNodeData = object
|
||||||
p: pointer
|
p: pointer
|
||||||
count: int
|
count: int
|
||||||
|
@ -361,6 +377,10 @@ const
|
||||||
|
|
||||||
yamlTagRepositoryPrefix* = "tag:yaml.org,2002:"
|
yamlTagRepositoryPrefix* = "tag:yaml.org,2002:"
|
||||||
|
|
||||||
|
defaultPresentationOptions* =
|
||||||
|
PresentationOptions(style: psDefault, indentationStep: 2,
|
||||||
|
newlines: nlOSDefault)
|
||||||
|
|
||||||
# interface
|
# interface
|
||||||
|
|
||||||
proc `==`*(left: YamlStreamEvent, right: YamlStreamEvent): bool {.raises: [].}
|
proc `==`*(left: YamlStreamEvent, right: YamlStreamEvent): bool {.raises: [].}
|
||||||
|
@ -495,6 +515,13 @@ proc getLineContent*(p: YamlParser, marker: bool = true): string {.raises: [].}
|
||||||
proc parse*(p: YamlParser, s: Stream): YamlStream {.raises: [].}
|
proc parse*(p: YamlParser, s: Stream): YamlStream {.raises: [].}
|
||||||
## Parse the given stream as YAML character stream.
|
## Parse the given stream as YAML character stream.
|
||||||
|
|
||||||
|
proc defineOptions*(style: PresentationStyle = psDefault,
|
||||||
|
indentationStep: int = 2, newlines:
|
||||||
|
NewLineStyle = nlOSDefault): PresentationOptions
|
||||||
|
{.raises: [].}
|
||||||
|
## Define a set of options for presentation. Convenience proc that requires
|
||||||
|
## you to only set those values that should not equal the default.
|
||||||
|
|
||||||
proc constructJson*(s: var YamlStream): seq[JsonNode]
|
proc constructJson*(s: var YamlStream): seq[JsonNode]
|
||||||
{.raises: [YamlConstructionError, YamlStreamError].}
|
{.raises: [YamlConstructionError, YamlStreamError].}
|
||||||
## Construct an in-memory JSON tree from a YAML event stream. The stream may
|
## Construct an in-memory JSON tree from a YAML event stream. The stream may
|
||||||
|
@ -516,15 +543,14 @@ proc loadToJson*(s: Stream): seq[JsonNode] {.raises: [].}
|
||||||
## from a YAML character stream.
|
## from a YAML character stream.
|
||||||
|
|
||||||
proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
|
proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary,
|
||||||
style: PresentationStyle = psDefault,
|
options: PresentationOptions = defaultPresentationOptions)
|
||||||
indentationStep: int = 2) {.raises: [YamlPresenterJsonError,
|
{.raises: [YamlPresenterJsonError, YamlPresenterOutputError,
|
||||||
YamlPresenterOutputError,
|
|
||||||
YamlStreamError].}
|
YamlStreamError].}
|
||||||
## Convert ``s`` to a YAML character stream and write it to ``target``.
|
## Convert ``s`` to a YAML character stream and write it to ``target``.
|
||||||
|
|
||||||
proc transform*(input: Stream, output: Stream, style: PresentationStyle,
|
proc transform*(input: Stream, output: Stream,
|
||||||
indentationStep: int = 2) {.raises: [IOError, YamlParserError,
|
options: PresentationOptions = defaultPresentationOptions)
|
||||||
YamlPresenterJsonError,
|
{.raises: [IOError, YamlParserError, YamlPresenterJsonError,
|
||||||
YamlPresenterOutputError].}
|
YamlPresenterOutputError].}
|
||||||
## Parser ``input`` as YAML character stream and then dump it to ``output``
|
## Parser ``input`` as YAML character stream and then dump it to ``output``
|
||||||
## while resolving non-specific tags to the ones in the YAML core tag
|
## while resolving non-specific tags to the ones in the YAML core tag
|
||||||
|
@ -564,9 +590,9 @@ proc represent*[T](value: T, ts: TagStyle = tsRootOnly,
|
||||||
a: AnchorStyle = asTidy): YamlStream {.raises: [].}
|
a: AnchorStyle = asTidy): YamlStream {.raises: [].}
|
||||||
## Represents a Nim value as ``YamlStream``
|
## Represents a Nim value as ``YamlStream``
|
||||||
|
|
||||||
proc dump*[K](value: K, target: Stream, style: PresentationStyle = psDefault,
|
proc dump*[K](value: K, target: Stream, tagStyle: TagStyle = tsRootOnly,
|
||||||
tagStyle: TagStyle = tsRootOnly,
|
anchorStyle: AnchorStyle = asTidy,
|
||||||
anchorStyle: AnchorStyle = asTidy, indentationStep: int = 2)
|
options: PresentationOptions = defaultPresentationOptions)
|
||||||
{.raises: [YamlPresenterJsonError, YamlPresenterOutputError].}
|
{.raises: [YamlPresenterJsonError, YamlPresenterOutputError].}
|
||||||
## Dump a Nim value as YAML character stream.
|
## Dump a Nim value as YAML character stream.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue