Skip to content

Commit

Permalink
Propery handle foot comments ending blocks.
Browse files Browse the repository at this point in the history
This means being able to associate loose comments at the bottom
of the block with the original values that were at the same
indentation level earlier on.

For example, this is now handled properly:

  ka:
    kb:
      kc: vc
      # Foot of kc
    # Foot of kb
  # Foot of ka
  • Loading branch information
niemeyer committed Jul 5, 2019
1 parent 55513ca commit 117fdf0
Show file tree
Hide file tree
Showing 7 changed files with 986 additions and 179 deletions.
25 changes: 23 additions & 2 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,10 @@ func (p *parser) parse() *Node {
case yaml_STREAM_END_EVENT:
// Happens when attempting to decode an empty buffer.
return nil
case yaml_TAIL_COMMENT_EVENT:
panic("internal error: unexpected tail comment event (please report)")
default:
panic("attempted to parse unknown event: " + p.event.typ.String())
panic("internal error: attempted to parse unknown event (please report): " + p.event.typ.String())
}
}

Expand Down Expand Up @@ -256,21 +258,40 @@ func (p *parser) sequence() *Node {

func (p *parser) mapping() *Node {
n := p.node(MappingNode, mapTag, string(p.event.tag), "")
block := true
if p.event.mapping_style()&yaml_FLOW_MAPPING_STYLE != 0 {
block = false
n.Style |= FlowStyle
}
p.anchor(n, p.event.anchor)
p.expect(yaml_MAPPING_START_EVENT)
for p.peek() != yaml_MAPPING_END_EVENT {
k := p.parseChild(n)
if block && k.FootComment != "" {
// Must be a foot comment for the prior value when being dedented.
if len(n.Content) > 2 {
n.Content[len(n.Content)-3].FootComment = k.FootComment
k.FootComment = ""
}
}
v := p.parseChild(n)
if v.FootComment != "" {
if k.FootComment == "" && v.FootComment != "" {
k.FootComment = v.FootComment
v.FootComment = ""
}
if p.peek() == yaml_TAIL_COMMENT_EVENT {
if k.FootComment == "" {
k.FootComment = string(p.event.foot_comment)
}
p.expect(yaml_TAIL_COMMENT_EVENT)
}
}
n.LineComment = string(p.event.line_comment)
n.FootComment = string(p.event.foot_comment)
if n.Style&FlowStyle == 0 && n.FootComment != "" && len(n.Content) > 1 {
n.Content[len(n.Content)-2].FootComment = n.FootComment
n.FootComment = ""
}
p.expect(yaml_MAPPING_END_EVENT)
return n
}
Expand Down
50 changes: 36 additions & 14 deletions emitterc.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,13 +539,15 @@ func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_e
}

if event.typ == yaml_SEQUENCE_END_EVENT {
emitter.flow_level--
emitter.indent = emitter.indents[len(emitter.indents)-1]
emitter.indents = emitter.indents[:len(emitter.indents)-1]
if emitter.canonical && !first {
if emitter.canonical && !first && !trail {
if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
return false
}
}
emitter.flow_level--
emitter.indent = emitter.indents[len(emitter.indents)-1]
emitter.indents = emitter.indents[:len(emitter.indents)-1]
if emitter.column == 0 || emitter.canonical && !first {
if !yaml_emitter_write_indent(emitter) {
return false
}
Expand Down Expand Up @@ -585,15 +587,15 @@ func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_e
return false
}
}
if len(emitter.line_comment) > 0 || len(emitter.foot_comment) > 0 {
if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE)
} else {
emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE)
}
if !yaml_emitter_emit_node(emitter, event, false, true, false, false) {
return false
}
if len(emitter.line_comment) > 0 || len(emitter.foot_comment) > 0 {
if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
return false
}
Expand All @@ -620,13 +622,18 @@ func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_eve
}

if event.typ == yaml_MAPPING_END_EVENT {
if (emitter.canonical || len(emitter.head_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0) && !first && !trail {
if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
return false
}
}
if !yaml_emitter_process_head_comment(emitter) {
return false
}
emitter.flow_level--
emitter.indent = emitter.indents[len(emitter.indents)-1]
emitter.indents = emitter.indents[:len(emitter.indents)-1]
if emitter.canonical && !first {
if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
return false
}
if !yaml_emitter_write_indent(emitter) {
return false
}
Expand Down Expand Up @@ -654,6 +661,7 @@ func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_eve
if !yaml_emitter_process_head_comment(emitter) {
return false
}

if emitter.column == 0 {
if !yaml_emitter_write_indent(emitter) {
return false
Expand Down Expand Up @@ -693,15 +701,15 @@ func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_e
return false
}
}
if len(emitter.line_comment) > 0 || len(emitter.foot_comment) > 0 {
if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE)
} else {
emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE)
}
if !yaml_emitter_emit_node(emitter, event, false, false, true, false) {
return false
}
if len(emitter.line_comment) > 0 || len(emitter.foot_comment) > 0 {
if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 {
if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) {
return false
}
Expand Down Expand Up @@ -765,16 +773,16 @@ func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_ev
return false
}
}
if !yaml_emitter_process_head_comment(emitter) {
return false
}
if event.typ == yaml_MAPPING_END_EVENT {
emitter.indent = emitter.indents[len(emitter.indents)-1]
emitter.indents = emitter.indents[:len(emitter.indents)-1]
emitter.state = emitter.states[len(emitter.states)-1]
emitter.states = emitter.states[:len(emitter.states)-1]
return true
}
if !yaml_emitter_process_head_comment(emitter) {
return false
}
if !yaml_emitter_write_indent(emitter) {
return false
}
Expand Down Expand Up @@ -1081,9 +1089,20 @@ func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool {

// Write a head comment.
func yaml_emitter_process_head_comment(emitter *yaml_emitter_t) bool {
if len(emitter.tail_comment) > 0 {
if !yaml_emitter_write_indent(emitter) {
return false
}
if !yaml_emitter_write_comment(emitter, emitter.tail_comment) {
return false
}
emitter.tail_comment = emitter.tail_comment[:0]
}

if len(emitter.head_comment) == 0 {
return true
}

space_above := emitter.space_above
if !emitter.indention {
if !put_break(emitter) {
Expand Down Expand Up @@ -1379,6 +1398,9 @@ func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bo
if len(event.foot_comment) > 0 {
emitter.foot_comment = event.foot_comment
}
if len(event.tail_comment) > 0 {
emitter.tail_comment = event.tail_comment
}

switch event.typ {
case yaml_ALIAS_EVENT:
Expand Down
44 changes: 29 additions & 15 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ func (e *encoder) stringv(tag string, in reflect.Value) {
default:
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
}
e.emitScalar(s, "", tag, style, nil, nil, nil)
e.emitScalar(s, "", tag, style, nil, nil, nil, nil)
}

func (e *encoder) boolv(tag string, in reflect.Value) {
Expand All @@ -342,23 +342,23 @@ func (e *encoder) boolv(tag string, in reflect.Value) {
} else {
s = "false"
}
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}

func (e *encoder) intv(tag string, in reflect.Value) {
s := strconv.FormatInt(in.Int(), 10)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}

func (e *encoder) uintv(tag string, in reflect.Value) {
s := strconv.FormatUint(in.Uint(), 10)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}

func (e *encoder) timev(tag string, in reflect.Value) {
t := in.Interface().(time.Time)
s := t.Format(time.RFC3339Nano)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}

func (e *encoder) floatv(tag string, in reflect.Value) {
Expand All @@ -377,14 +377,14 @@ func (e *encoder) floatv(tag string, in reflect.Value) {
case "NaN":
s = ".nan"
}
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil)
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}

func (e *encoder) nilv() {
e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE, nil, nil, nil)
e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil)
}

func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t, head, line, foot []byte) {
func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t, head, line, foot, tail []byte) {
// TODO Kill this function. Replace all initialize calls by their underlining Go literals.
implicit := tag == ""
if !implicit {
Expand All @@ -394,14 +394,15 @@ func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_
e.event.head_comment = head
e.event.line_comment = line
e.event.foot_comment = foot
e.event.tail_comment = tail
e.emit()
}

func (e *encoder) nodev(in reflect.Value) {
e.node(in.Interface().(*Node))
e.node(in.Interface().(*Node), "")
}

func (e *encoder) node(node *Node) {
func (e *encoder) node(node *Node, tail string) {
// If the tag was not explicitly requested, and dropping it won't change the
// implicit tag of the value, don't include it in the presentation.
var tag = node.Tag
Expand Down Expand Up @@ -440,7 +441,7 @@ func (e *encoder) node(node *Node) {
e.event.head_comment = []byte(node.HeadComment)
e.emit()
for _, node := range node.Content {
e.node(node)
e.node(node, "")
}
yaml_document_end_event_initialize(&e.event, true)
e.event.foot_comment = []byte(node.FootComment)
Expand All @@ -455,7 +456,7 @@ func (e *encoder) node(node *Node) {
e.event.head_comment = []byte(node.HeadComment)
e.emit()
for _, node := range node.Content {
e.node(node)
e.node(node, "")
}
e.must(yaml_sequence_end_event_initialize(&e.event))
e.event.line_comment = []byte(node.LineComment)
Expand All @@ -468,15 +469,28 @@ func (e *encoder) node(node *Node) {
style = yaml_FLOW_MAPPING_STYLE
}
yaml_mapping_start_event_initialize(&e.event, []byte(node.Anchor), []byte(tag), tag == "", style)
e.event.tail_comment = []byte(tail)
e.event.head_comment = []byte(node.HeadComment)
e.emit()

// The tail logic below moves the foot comment of prior keys to the following key,
// since the value for each key may be a nested structure and the foot needs to be
// processed only the entirety of the value is streamed. The last tail is processed
// with the mapping end event.
var tail string
for i := 0; i+1 < len(node.Content); i += 2 {
e.node(node.Content[i])
e.node(node.Content[i+1])
k := node.Content[i]
foot := k.FootComment
k.FootComment = ""
e.node(k, tail)
tail = foot

v := node.Content[i+1]
e.node(v, "")
}

yaml_mapping_end_event_initialize(&e.event)
e.event.tail_comment = []byte(tail)
e.event.line_comment = []byte(node.LineComment)
e.event.foot_comment = []byte(node.FootComment)
e.emit()
Expand Down Expand Up @@ -519,6 +533,6 @@ func (e *encoder) node(node *Node) {
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
}

e.emitScalar(value, node.Anchor, tag, style, []byte(node.HeadComment), []byte(node.LineComment), []byte(node.FootComment))
e.emitScalar(value, node.Anchor, tag, style, []byte(node.HeadComment), []byte(node.LineComment), []byte(node.FootComment), []byte(tail))
}
}
Loading

0 comments on commit 117fdf0

Please sign in to comment.