From 3e9ed4eac6a953b2616bcf129b515a857271acdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Sat, 29 Sep 2018 21:42:23 +0200 Subject: xgbgen: process elements Most of XCB documentation now ends up in Go sources, although the end result is of mixed quality. --- nexgb/xgbgen/translation.go | 111 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 91 insertions(+), 20 deletions(-) (limited to 'nexgb/xgbgen/translation.go') diff --git a/nexgb/xgbgen/translation.go b/nexgb/xgbgen/translation.go index 62fe9db..534a3d4 100644 --- a/nexgb/xgbgen/translation.go +++ b/nexgb/xgbgen/translation.go @@ -7,13 +7,11 @@ the XML type into our "better" representation. i.e., the representation of Fields and Expressions is just too general. We end up losing a lot of the advantages of static typing if we keep the types that encoding/xml forces us into. - -Please see 'representation.go' for the type definitions that we're -translating to. */ import ( "log" + "regexp" "strconv" "strings" ) @@ -138,12 +136,10 @@ func (x *XMLEvent) Translate() *Event { Number: x.Number, NoSequence: x.NoSequence, Fields: make([]Field, 0, len(x.Fields)), + Doc: x.Doc.Translate(), } for _, field := range x.Fields { - if field.XMLName.Local == "doc" { - continue - } - ev.Fields = append(ev.Fields, field.Translate(ev)) + ev.Fields = append(ev.Fields, field.Translate(ev, &ev.Doc)) } return ev } @@ -163,7 +159,7 @@ func (x *XMLError) Translate() *Error { Fields: make([]Field, len(x.Fields)), } for i, field := range x.Fields { - err.Fields[i] = field.Translate(err) + err.Fields[i] = field.Translate(err, nil) } return err } @@ -176,13 +172,82 @@ func (x *XMLErrorCopy) Translate() *ErrorCopy { } } +// XCB documentation is positively stuffed with TODOs. We'd like to make it +// look a bit less shitty, so remove those as they don't convey information. +// +// ^TODO +// ^TODO: +// ^TODO: question? +// ^TODO: Some words +// ^TODO: some words +// ^TODO: some words with full stop. +// ^TODO: some words with full stop. and a question? +// ... (TODO), +// ... (TODO). +// ... (TODO: a question?). +// ... TODO: a question? +// ... (word TODO) ... +var todoRE = regexp.MustCompile(`(?m:^TODO.*| \([^)]*TODO[^)]*\)| TODO:.*)`) +var paraRE = regexp.MustCompile(`\n{3,}`) + +var backticksRE = regexp.MustCompile("`(?:xcb_|XCB_)?(.*?)(?:_t)?`") + +// fixDocumentation tries to translate XCB documentation to match XGB. +// Note that blocks only appear in xproto, so this doesn't have that much +// of a value--users still need to read Xlib or X11 protocol docs. +// Despite that, it's better to have something than nothing. +// +// We don't attempt to add proper prefixes to enum values or guess at +// specific XCB_NONE types (the latter is undecidable). +// +// We can't decide whether `fields_len` should be converted to len(Fields) +// or FieldsLen because e.g. StringLen is retained in ImageText8/16 but +// PointsLen is implied by the length of the Points slice in PolyLine. +func fixDocumentation(xcb string) string { + last, result := 0, make([]byte, 0, len(xcb)) + for _, m := range backticksRE.FindAllStringSubmatchIndex(xcb, -1) { + result = append(result, xcb[last:m[0]]...) + inner := xcb[m[2]:m[3]] + last = m[1] + + // Do not convert atom names to identifiers, mainly _NET_WM_*. + if strings.Contains(inner, "WM_") { + result = append(result, inner...) + } else { + result = append(result, splitAndTitle(inner)...) + } + } + result = todoRE.ReplaceAllLiteral(append(result, xcb[last:]...), nil) + result = paraRE.ReplaceAllLiteral(result, []byte("\n\n")) + return strings.TrimSpace(string(result)) +} + +func (x *XMLDoc) Translate() Doc { + if x == nil { + return Doc{} + } + d := Doc{ + Brief: fixDocumentation(x.Brief), + Description: fixDocumentation(x.Description), + Fields: make(map[string]string), + Errors: make(map[string]string), + } + for _, x := range x.Fields { + d.Fields[x.Name] = fixDocumentation(x.Description) + } + for _, x := range x.Errors { + d.Errors[x.Type] = fixDocumentation(x.Description) + } + return d +} + func (x *XMLStruct) Translate() *Struct { s := &Struct{ xmlName: x.Name, Fields: make([]Field, len(x.Fields)), } for i, field := range x.Fields { - s.Fields[i] = field.Translate(s) + s.Fields[i] = field.Translate(s, nil) } return s } @@ -193,7 +258,7 @@ func (x *XMLUnion) Translate() *Union { Fields: make([]Field, len(x.Fields)), } for i, field := range x.Fields { - u.Fields[i] = field.Translate(u) + u.Fields[i] = field.Translate(u, nil) } return u } @@ -205,12 +270,13 @@ func (x *XMLRequest) Translate() *Request { Combine: x.Combine, Fields: make([]Field, 0, len(x.Fields)), Reply: x.Reply.Translate(), + Doc: x.Doc.Translate(), } for _, field := range x.Fields { - if field.XMLName.Local == "doc" || field.XMLName.Local == "fd" { + if field.XMLName.Local == "fd" { continue } - r.Fields = append(r.Fields, field.Translate(r)) + r.Fields = append(r.Fields, field.Translate(r, &r.Doc)) } // Address bug (or legacy code) in QueryTextExtents. @@ -236,12 +302,13 @@ func (x *XMLReply) Translate() *Reply { r := &Reply{ Fields: make([]Field, 0, len(x.Fields)), + Doc: x.Doc.Translate(), } for _, field := range x.Fields { - if field.XMLName.Local == "doc" || field.XMLName.Local == "fd" { + if field.XMLName.Local == "fd" { continue } - r.Fields = append(r.Fields, field.Translate(r)) + r.Fields = append(r.Fields, field.Translate(r, &r.Doc)) } return r } @@ -320,7 +387,7 @@ func (x *XMLExpression) Translate() Expression { panic("unreachable") } -func (x *XMLField) Translate(parent interface{}) Field { +func (x *XMLField) Translate(parent interface{}, doc *Doc) Field { switch x.XMLName.Local { case "pad": return &PadField{ @@ -331,6 +398,7 @@ func (x *XMLField) Translate(parent interface{}) Field { s := &SingleField{ xmlName: x.Name, Type: newTranslation(x.Type), + Comment: doc.DescribeField(x.Name), } return s case "list": @@ -352,16 +420,19 @@ func (x *XMLField) Translate(parent interface{}) Field { } case "valueparam": return &ValueField{ - Parent: parent, - MaskType: newTranslation(x.ValueMaskType), - MaskName: x.ValueMaskName, - ListName: x.ValueListName, + Parent: parent, + MaskType: newTranslation(x.ValueMaskType), + MaskName: x.ValueMaskName, + ListName: x.ValueListName, + MaskComment: doc.DescribeField(x.ValueMaskName), + ListComment: doc.DescribeField(x.ValueListName), } case "switch": swtch := &SwitchField{ Name: x.Name, Expr: x.Expr.Translate(), Bitcases: make([]*Bitcase, len(x.Bitcases)), + Comment: doc.DescribeField(x.Name), } for i, bitcase := range x.Bitcases { swtch.Bitcases[i] = bitcase.Translate() @@ -381,7 +452,7 @@ func (x *XMLBitcase) Translate() *Bitcase { Fields: make([]Field, len(x.Fields)), } for i, field := range x.Fields { - b.Fields[i] = field.Translate(b) + b.Fields[i] = field.Translate(b, nil) } return b } -- cgit v1.2.3