package main import ( "fmt" "io" "log" "os" "golang.org/x/text/transform" ) // 输出索引 type OutputIndex struct { groups []IndexGroup style *OutputStyle option *OutputOptions } func NewOutputIndex(input *InputIndex, option *OutputOptions, style *OutputStyle) *OutputIndex { sorter := NewIndexSorter(option.sort) outindex := sorter.SortIndex(input, style, option) outindex.style = style outindex.option = option return outindex } // 按格式输出索引项 // suffix_2p, suffix_3p, suffix_mp 暂未实现 // line_max, indent_space, indent_length 未实现 func (o *OutputIndex) Output(option *OutputOptions) { var writer io.WriteCloser if o.option.output == "" { writer = os.Stdout } else { var err error writer, err = os.Create(o.option.output) if err != nil { log.Fatalln(err) } defer writer.Close() } writer = transform.NewWriter(writer, option.encoder) fmt.Fprint(writer, o.style.preamble) first_group := true for _, group := range o.groups { if group.items == nil { continue } if first_group { first_group = false } else { fmt.Fprint(writer, o.style.group_skip) } if o.style.headings_flag != 0 { fmt.Fprintf(writer, "%s%s%s", o.style.heading_prefix, group.name, o.style.heading_suffix) } for i, item := range group.items { // debug.Println(i, item) // 如果修改一下 OutputStyle 的数据结构,容易改成任意层的索引 switch item.level { case 0: fmt.Fprintf(writer, "%s%s", o.style.item_0, item.text) writePage(writer, 0, item.page, o.style) case 1: if last := group.items[i-1]; last.level == 0 { if last.page != nil { fmt.Fprint(writer, o.style.item_01) } else { fmt.Fprint(writer, o.style.item_x1) } } else { fmt.Fprint(writer, o.style.item_1) } fmt.Fprint(writer, item.text) writePage(writer, 1, item.page, o.style) case 2: if last := group.items[i-1]; last.level == 1 { if last.page != nil { fmt.Fprint(writer, o.style.item_12) } else { fmt.Fprint(writer, o.style.item_x2) } } else { fmt.Fprint(writer, o.style.item_2) } fmt.Fprint(writer, item.text) writePage(writer, 2, item.page, o.style) default: log.Printf("索引项“%s”层次数过深,忽略此项\n", item.text) } } } fmt.Fprint(writer, o.style.postamble) } func writePage(out io.Writer, level int, pageranges []PageRange, style *OutputStyle) { if pageranges == nil { return } switch level { case 0: fmt.Fprint(out, style.delim_0) case 1: fmt.Fprint(out, style.delim_1) case 2: fmt.Fprint(out, style.delim_2) } for i, p := range pageranges { if i > 0 { fmt.Fprint(out, style.delim_n) } p.Write(out, style) } if len(pageranges) != 0 { fmt.Fprint(out, style.delim_t) } } // 一个输出项目组 type IndexGroup struct { name string items []IndexItem } // 一个输出项,包括级别、文字、一系列页码区间 type IndexItem struct { level int text string page []PageRange } // 用于输出的页码区间 type PageRange struct { begin *Page end *Page } func (p *PageRange) Diff() int { return p.end.Diff(p.begin) } // 输出页码区间 func (p *PageRange) Write(out io.Writer, style *OutputStyle) { var rangestr string switch { // 单页 case p.Diff() == 0: rangestr = p.begin.String() // 由单页合并得到的两页的区间,且未设置 suffix_2p,视为独立的两页 case p.begin.rangetype == PAGE_NORMAL && p.end.rangetype == PAGE_NORMAL && p.Diff() == 1 && style.suffix_2p == "": rangestr = p.begin.String() + style.delim_n + p.end.String() // 两页的区间,设置了 suffix_2p case p.Diff() == 1 && style.suffix_2p != "": rangestr = p.begin.String() + style.suffix_2p // 三页的区间,设置了 suffix_3p case p.Diff() == 2 && style.suffix_3p != "": rangestr = p.begin.String() + style.suffix_3p // 三页或更长的区间,设置了 suffix_mp case p.Diff() >= 2 && style.suffix_mp != "": rangestr = p.begin.String() + style.suffix_mp // 普通的区间 default: rangestr = p.begin.String() + style.delim_r + p.end.String() } // encap 只看区间头,对不完全区间可能不总正确 if p.begin.encap == "" { fmt.Fprint(out, rangestr) } else { fmt.Fprint(out, style.encap_prefix, p.begin.encap, style.encap_infix, rangestr, style.encap_suffix) } }