mirror of
https://github.com/araddon/dateparse.git
synced 2024-11-10 11:51:54 +08:00
Vendor termtables to fix main.go
Add comment for ParserOption
This commit is contained in:
parent
aca798503a
commit
d7f7267056
9
dateparse/vendor/github.com/apcera/termtables/.travis.yml
generated
vendored
Normal file
9
dateparse/vendor/github.com/apcera/termtables/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.6
|
||||||
|
- 1.7
|
||||||
|
- tip
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go vet $(go list ./...|grep -v "/vendor/")
|
||||||
|
- go test -v -race ./...
|
202
dateparse/vendor/github.com/apcera/termtables/LICENSE
generated
vendored
Normal file
202
dateparse/vendor/github.com/apcera/termtables/LICENSE
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
103
dateparse/vendor/github.com/apcera/termtables/README.md
generated
vendored
Normal file
103
dateparse/vendor/github.com/apcera/termtables/README.md
generated
vendored
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
# Termtables
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/apcera/termtables.svg?branch=master)](https://travis-ci.org/apcera/termtables)
|
||||||
|
|
||||||
|
A [Go](http://golang.org) port of the Ruby library [terminal-tables](https://github.com/visionmedia/terminal-table) for
|
||||||
|
fast and simple ASCII table generation.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get github.com/apcera/termtables
|
||||||
|
```
|
||||||
|
|
||||||
|
## Go Style Documentation
|
||||||
|
|
||||||
|
[http://godoc.org/github.com/apcera/termtables](http://godoc.org/github.com/apcera/termtables)
|
||||||
|
|
||||||
|
## APC Command Line usage
|
||||||
|
|
||||||
|
`--markdown` — output a markdown table, e.g. `apc app list --markdown`
|
||||||
|
|
||||||
|
`--html` — output an html table, e.g. `apc app list --html`
|
||||||
|
|
||||||
|
`--ascii` — output an ascii table, e.g. `apc app list --ascii`
|
||||||
|
|
||||||
|
## Basic Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/apcera/termtables"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
table := termtables.CreateTable()
|
||||||
|
|
||||||
|
table.AddHeaders("Name", "Age")
|
||||||
|
table.AddRow("John", "30")
|
||||||
|
table.AddRow("Sam", 18)
|
||||||
|
table.AddRow("Julie", 20.14)
|
||||||
|
|
||||||
|
fmt.Println(table.Render())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result:
|
||||||
|
|
||||||
|
```
|
||||||
|
+-------+-------+
|
||||||
|
| Name | Age |
|
||||||
|
+-------+-------+
|
||||||
|
| John | 30 |
|
||||||
|
| Sam | 18 |
|
||||||
|
| Julie | 20.14 |
|
||||||
|
+-------+-------+
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Usage
|
||||||
|
|
||||||
|
The package function-call `EnableUTF8()` will cause any tables created after
|
||||||
|
that point to use Unicode box-drawing characters for the table lines.
|
||||||
|
|
||||||
|
Calling `EnableUTF8PerLocale()` uses the C library's locale functionality to
|
||||||
|
determine if the current locale environment variables say that the current
|
||||||
|
character map is UTF-8. If, and only if, so, then `EnableUTF8()` will be
|
||||||
|
called.
|
||||||
|
|
||||||
|
Calling `SetModeHTML(true)` will cause any tables created after that point
|
||||||
|
to be emitted in HTML, while `SetModeMarkdown(true)` will trigger Markdown.
|
||||||
|
Neither should result in changes to later API to get the different results;
|
||||||
|
the primary intended use-case is extracting the same table, but for
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
The table method `.AddSeparator()` inserts a rule line in the output. This
|
||||||
|
only applies in normal terminal output mode.
|
||||||
|
|
||||||
|
The table method `.AddTitle()` adds a title to the table; in terminal output,
|
||||||
|
this is an initial row; in HTML, it's a caption. In Markdown, it's a line of
|
||||||
|
text before the table, prefixed by `Table: `.
|
||||||
|
|
||||||
|
The table method `.SetAlign()` takes an alignment and a column number
|
||||||
|
(indexing starts at 1) and changes all _current_ cells in that column to have
|
||||||
|
the given alignment. It does not change the alignment of cells added to the
|
||||||
|
table after this call. Alignment is only stored on a per-cell basis.
|
||||||
|
|
||||||
|
## Known Issues
|
||||||
|
|
||||||
|
Normal output:
|
||||||
|
|
||||||
|
* `.SetAlign()` does not affect headers.
|
||||||
|
|
||||||
|
Markdown output mode:
|
||||||
|
|
||||||
|
* When emitting Markdown, the column markers are not re-flowed if a vertical
|
||||||
|
bar is an element of a cell, causing an escape to take place; since Markdown
|
||||||
|
is often converted to HTML, this only affects text viewing.
|
||||||
|
* A title in Markdown is not escaped against all possible forms of Markdown
|
||||||
|
markup (to avoid adding a dependency upon a Markdown library, as supported
|
||||||
|
syntax can vary).
|
||||||
|
* Markdown requires headers, so a dummy header will be inserted if needed.
|
||||||
|
* Table alignment is not reflected in Markdown output.
|
168
dateparse/vendor/github.com/apcera/termtables/cell.go
generated
vendored
Normal file
168
dateparse/vendor/github.com/apcera/termtables/cell.go
generated
vendored
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
// Copyright 2012 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
package termtables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
runewidth "github.com/mattn/go-runewidth"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Must match SGR escape sequence, which is "CSI Pm m", where the Control
|
||||||
|
// Sequence Introducer (CSI) is "ESC ["; where Pm is "A multiple numeric
|
||||||
|
// parameter composed of any number of single numeric parameters, separated
|
||||||
|
// by ; character(s). Individual values for the parameters are listed with
|
||||||
|
// Ps" and where Ps is A single (usually optional) numeric parameter,
|
||||||
|
// composed of one of [sic] more digits."
|
||||||
|
//
|
||||||
|
// In practice, the end sequence is usually given as \e[0m but reading that
|
||||||
|
// definition, it's clear that the 0 is optional and some testing confirms
|
||||||
|
// that it is certainly optional with MacOS Terminal 2.3, so we need to
|
||||||
|
// support the string \e[m as a terminator too.
|
||||||
|
colorFilter = regexp.MustCompile(`\033\[(?:\d+(?:;\d+)*)?m`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Cell denotes one cell of a table; it spans one row and a variable number
|
||||||
|
// of columns. A given Cell can only be used at one place in a table; the act
|
||||||
|
// of adding the Cell to the table mutates it with position information, so
|
||||||
|
// do not create one "const" Cell to add it multiple times.
|
||||||
|
type Cell struct {
|
||||||
|
column int
|
||||||
|
formattedValue string
|
||||||
|
alignment *tableAlignment
|
||||||
|
colSpan int
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateCell returns a Cell where the content is the supplied value, with the
|
||||||
|
// optional supplied style (which may be given as nil). The style can include
|
||||||
|
// a non-zero ColSpan to cause the cell to become column-spanning. Changing
|
||||||
|
// the style afterwards will not adjust the column-spanning state of the cell
|
||||||
|
// itself.
|
||||||
|
func CreateCell(v interface{}, style *CellStyle) *Cell {
|
||||||
|
return createCell(0, v, style)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createCell(column int, v interface{}, style *CellStyle) *Cell {
|
||||||
|
cell := &Cell{column: column, formattedValue: renderValue(v), colSpan: 1}
|
||||||
|
if style != nil {
|
||||||
|
cell.alignment = &style.Alignment
|
||||||
|
if style.ColSpan != 0 {
|
||||||
|
cell.colSpan = style.ColSpan
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
// Width returns the width of the content of the cell, measured in runes as best
|
||||||
|
// as possible considering sophisticated Unicode.
|
||||||
|
func (c *Cell) Width() int {
|
||||||
|
return runewidth.StringWidth(filterColorCodes(c.formattedValue))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter out terminal bold/color sequences in a string.
|
||||||
|
// This supports only basic bold/color escape sequences.
|
||||||
|
func filterColorCodes(s string) string {
|
||||||
|
return colorFilter.ReplaceAllString(s, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render returns a string representing the content of the cell, together with
|
||||||
|
// padding (to the widths specified) and handling any alignment.
|
||||||
|
func (c *Cell) Render(style *renderStyle) (buffer string) {
|
||||||
|
// if no alignment is set, import the table's default
|
||||||
|
if c.alignment == nil {
|
||||||
|
c.alignment = &style.Alignment
|
||||||
|
}
|
||||||
|
|
||||||
|
// left padding
|
||||||
|
buffer += strings.Repeat(" ", style.PaddingLeft)
|
||||||
|
|
||||||
|
// append the main value and handle alignment
|
||||||
|
buffer += c.alignCell(style)
|
||||||
|
|
||||||
|
// right padding
|
||||||
|
buffer += strings.Repeat(" ", style.PaddingRight)
|
||||||
|
|
||||||
|
// this handles escaping for, eg, Markdown, where we don't care about the
|
||||||
|
// alignment quite as much
|
||||||
|
if style.replaceContent != nil {
|
||||||
|
buffer = style.replaceContent(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cell) alignCell(style *renderStyle) string {
|
||||||
|
buffer := ""
|
||||||
|
width := style.CellWidth(c.column)
|
||||||
|
|
||||||
|
if c.colSpan > 1 {
|
||||||
|
for i := 1; i < c.colSpan; i++ {
|
||||||
|
w := style.CellWidth(c.column + i)
|
||||||
|
if w == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
width += style.PaddingLeft + w + style.PaddingRight + utf8.RuneCountInString(style.BorderY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch *c.alignment {
|
||||||
|
|
||||||
|
default:
|
||||||
|
buffer += c.formattedValue
|
||||||
|
if l := width - c.Width(); l > 0 {
|
||||||
|
buffer += strings.Repeat(" ", l)
|
||||||
|
}
|
||||||
|
|
||||||
|
case AlignLeft:
|
||||||
|
buffer += c.formattedValue
|
||||||
|
if l := width - c.Width(); l > 0 {
|
||||||
|
buffer += strings.Repeat(" ", l)
|
||||||
|
}
|
||||||
|
|
||||||
|
case AlignRight:
|
||||||
|
if l := width - c.Width(); l > 0 {
|
||||||
|
buffer += strings.Repeat(" ", l)
|
||||||
|
}
|
||||||
|
buffer += c.formattedValue
|
||||||
|
|
||||||
|
case AlignCenter:
|
||||||
|
left, right := 0, 0
|
||||||
|
if l := width - c.Width(); l > 0 {
|
||||||
|
lf := float64(l)
|
||||||
|
left = int(math.Floor(lf / 2))
|
||||||
|
right = int(math.Ceil(lf / 2))
|
||||||
|
}
|
||||||
|
buffer += strings.Repeat(" ", left)
|
||||||
|
buffer += c.formattedValue
|
||||||
|
buffer += strings.Repeat(" ", right)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the raw value as a string depending on the type
|
||||||
|
func renderValue(v interface{}) string {
|
||||||
|
switch vv := v.(type) {
|
||||||
|
case string:
|
||||||
|
return vv
|
||||||
|
case bool:
|
||||||
|
return strconv.FormatBool(vv)
|
||||||
|
case int:
|
||||||
|
return strconv.Itoa(vv)
|
||||||
|
case int64:
|
||||||
|
return strconv.FormatInt(vv, 10)
|
||||||
|
case uint64:
|
||||||
|
return strconv.FormatUint(vv, 10)
|
||||||
|
case float64:
|
||||||
|
return strconv.FormatFloat(vv, 'f', 2, 64)
|
||||||
|
case fmt.Stringer:
|
||||||
|
return vv.String()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v", v)
|
||||||
|
}
|
113
dateparse/vendor/github.com/apcera/termtables/cell_test.go
generated
vendored
Normal file
113
dateparse/vendor/github.com/apcera/termtables/cell_test.go
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// Copyright 2012-2015 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
package termtables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCellRenderString(t *testing.T) {
|
||||||
|
style := &renderStyle{TableStyle: TableStyle{}, cellWidths: map[int]int{}}
|
||||||
|
cell := createCell(0, "foobar", nil)
|
||||||
|
|
||||||
|
output := cell.Render(style)
|
||||||
|
if output != "foobar" {
|
||||||
|
t.Fatal("Unexpected output:", output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCellRenderBool(t *testing.T) {
|
||||||
|
style := &renderStyle{TableStyle: TableStyle{}, cellWidths: map[int]int{}}
|
||||||
|
cell := createCell(0, true, nil)
|
||||||
|
|
||||||
|
output := cell.Render(style)
|
||||||
|
if output != "true" {
|
||||||
|
t.Fatal("Unexpected output:", output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCellRenderInteger(t *testing.T) {
|
||||||
|
style := &renderStyle{TableStyle: TableStyle{}, cellWidths: map[int]int{}}
|
||||||
|
cell := createCell(0, 12345, nil)
|
||||||
|
|
||||||
|
output := cell.Render(style)
|
||||||
|
if output != "12345" {
|
||||||
|
t.Fatal("Unexpected output:", output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCellRenderFloat(t *testing.T) {
|
||||||
|
style := &renderStyle{TableStyle: TableStyle{}, cellWidths: map[int]int{}}
|
||||||
|
cell := createCell(0, 12.345, nil)
|
||||||
|
|
||||||
|
output := cell.Render(style)
|
||||||
|
if output != "12.35" {
|
||||||
|
t.Fatal("Unexpected output:", output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCellRenderPadding(t *testing.T) {
|
||||||
|
style := &renderStyle{TableStyle: TableStyle{PaddingLeft: 3, PaddingRight: 4}, cellWidths: map[int]int{}}
|
||||||
|
|
||||||
|
cell := createCell(0, "foobar", nil)
|
||||||
|
|
||||||
|
output := cell.Render(style)
|
||||||
|
if output != " foobar " {
|
||||||
|
t.Fatal("Unexpected output:", output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type foo struct {
|
||||||
|
v string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *foo) String() string {
|
||||||
|
return f.v
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCellRenderStringerStruct(t *testing.T) {
|
||||||
|
style := &renderStyle{TableStyle: TableStyle{}, cellWidths: map[int]int{}}
|
||||||
|
cell := createCell(0, &foo{v: "bar"}, nil)
|
||||||
|
|
||||||
|
output := cell.Render(style)
|
||||||
|
if output != "bar" {
|
||||||
|
t.Fatal("Unexpected output:", output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type fooString string
|
||||||
|
|
||||||
|
func TestCellRenderGeneric(t *testing.T) {
|
||||||
|
style := &renderStyle{TableStyle: TableStyle{}, cellWidths: map[int]int{}}
|
||||||
|
cell := createCell(0, fooString("baz"), nil)
|
||||||
|
|
||||||
|
output := cell.Render(style)
|
||||||
|
if output != "baz" {
|
||||||
|
t.Fatal("Unexpected output:", output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterColorCodes(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
in string
|
||||||
|
out string
|
||||||
|
}{
|
||||||
|
{"abc", "abc"},
|
||||||
|
{"", ""},
|
||||||
|
{"\033[31m\033[0m", ""},
|
||||||
|
{"a\033[31mb\033[0mc", "abc"},
|
||||||
|
{"\033[31mabc\033[0m", "abc"},
|
||||||
|
{"\033[31mfoo\033[0mbar", "foobar"},
|
||||||
|
{"\033[31mfoo\033[mbar", "foobar"},
|
||||||
|
{"\033[31mfoo\033[0;0mbar", "foobar"},
|
||||||
|
{"\033[31;4mfoo\033[0mbar", "foobar"},
|
||||||
|
{"\033[31;4;43mfoo\033[0mbar", "foobar"},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
got := filterColorCodes(test.in)
|
||||||
|
if got != test.out {
|
||||||
|
t.Errorf("Invalid color-code filter result; expected %q but got %q from input %q",
|
||||||
|
test.out, got, test.in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
107
dateparse/vendor/github.com/apcera/termtables/html.go
generated
vendored
Normal file
107
dateparse/vendor/github.com/apcera/termtables/html.go
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// Copyright 2013 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
package termtables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"html"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type titleStyle int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TitleAsCaption titleStyle = iota
|
||||||
|
TitleAsThSpan
|
||||||
|
)
|
||||||
|
|
||||||
|
// htmlStyleRules defines attributes which we can use, and might be set on a
|
||||||
|
// table by accessors, to influence the type of HTML which is output.
|
||||||
|
type htmlStyleRules struct {
|
||||||
|
title titleStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTML returns an HTML representations of the contents of one row of a table.
|
||||||
|
func (r *Row) HTML(tag string, style *renderStyle) string {
|
||||||
|
attrs := make([]string, len(r.cells))
|
||||||
|
elems := make([]string, len(r.cells))
|
||||||
|
for i := range r.cells {
|
||||||
|
if r.cells[i].alignment != nil {
|
||||||
|
switch *r.cells[i].alignment {
|
||||||
|
case AlignLeft:
|
||||||
|
attrs[i] = " align='left'"
|
||||||
|
case AlignCenter:
|
||||||
|
attrs[i] = " align='center'"
|
||||||
|
case AlignRight:
|
||||||
|
attrs[i] = " align='right'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elems[i] = html.EscapeString(strings.TrimSpace(r.cells[i].Render(style)))
|
||||||
|
}
|
||||||
|
// WAG as to max capacity, plus a bit
|
||||||
|
buf := bytes.NewBuffer(make([]byte, 0, 8192))
|
||||||
|
buf.WriteString("<tr>")
|
||||||
|
for i := range elems {
|
||||||
|
fmt.Fprintf(buf, "<%s%s>%s</%s>", tag, attrs[i], elems[i], tag)
|
||||||
|
}
|
||||||
|
buf.WriteString("</tr>\n")
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateHtmlTitleRow(title interface{}, t *Table, style *renderStyle) string {
|
||||||
|
elContent := html.EscapeString(
|
||||||
|
strings.TrimSpace(CreateCell(t.title, &CellStyle{}).Render(style)),
|
||||||
|
)
|
||||||
|
|
||||||
|
switch style.htmlRules.title {
|
||||||
|
case TitleAsCaption:
|
||||||
|
return "<caption>" + elContent + "</caption>\n"
|
||||||
|
case TitleAsThSpan:
|
||||||
|
return fmt.Sprintf("<tr><th style=\"text-align: center\" colspan=\"%d\">%s</th></tr>\n",
|
||||||
|
style.columns, elContent)
|
||||||
|
default:
|
||||||
|
return "<!-- " + elContent + " -->"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderHTML returns a string representation of a the table, suitable for
|
||||||
|
// inclusion as HTML elsewhere. Primary use-case controlling layout style
|
||||||
|
// is for inclusion into Markdown documents, documenting normal table use.
|
||||||
|
// Thus we leave the padding in place to have columns align when viewed as
|
||||||
|
// plain text and rely upon HTML ignoring extra whitespace.
|
||||||
|
func (t *Table) RenderHTML() (buffer string) {
|
||||||
|
// elements is already populated with row data
|
||||||
|
|
||||||
|
// generate the runtime style
|
||||||
|
style := createRenderStyle(t)
|
||||||
|
style.PaddingLeft = 0
|
||||||
|
style.PaddingRight = 0
|
||||||
|
|
||||||
|
// TODO: control CSS styles to suppress border based upon t.Style.SkipBorder
|
||||||
|
rowsText := make([]string, 0, len(t.elements)+6)
|
||||||
|
|
||||||
|
if t.title != nil || t.headers != nil {
|
||||||
|
rowsText = append(rowsText, "<thead>\n")
|
||||||
|
if t.title != nil {
|
||||||
|
rowsText = append(rowsText, generateHtmlTitleRow(t.title, t, style))
|
||||||
|
}
|
||||||
|
if t.headers != nil {
|
||||||
|
rowsText = append(rowsText, CreateRow(t.headers).HTML("th", style))
|
||||||
|
}
|
||||||
|
rowsText = append(rowsText, "</thead>\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
rowsText = append(rowsText, "<tbody>\n")
|
||||||
|
// loop over the elements and render them
|
||||||
|
for i := range t.elements {
|
||||||
|
if row, ok := t.elements[i].(*Row); ok {
|
||||||
|
rowsText = append(rowsText, row.HTML("td", style))
|
||||||
|
} else {
|
||||||
|
rowsText = append(rowsText, fmt.Sprintf("<!-- unable to render line %d, unhandled type -->\n", i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rowsText = append(rowsText, "</tbody>\n")
|
||||||
|
|
||||||
|
return "<table class=\"termtable\">\n" + strings.Join(rowsText, "") + "</table>\n"
|
||||||
|
}
|
222
dateparse/vendor/github.com/apcera/termtables/html_test.go
generated
vendored
Normal file
222
dateparse/vendor/github.com/apcera/termtables/html_test.go
generated
vendored
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
// Copyright 2013 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
package termtables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateTableHTML(t *testing.T) {
|
||||||
|
expected := "<table class=\"termtable\">\n" +
|
||||||
|
"<thead>\n" +
|
||||||
|
"<tr><th>Name</th><th>Value</th></tr>\n" +
|
||||||
|
"</thead>\n" +
|
||||||
|
"<tbody>\n" +
|
||||||
|
"<tr><td>hey</td><td>you</td></tr>\n" +
|
||||||
|
"<tr><td>ken</td><td>1234</td></tr>\n" +
|
||||||
|
"<tr><td>derek</td><td>3.14</td></tr>\n" +
|
||||||
|
"<tr><td>derek too</td><td>3.15</td></tr>\n" +
|
||||||
|
"</tbody>\n" +
|
||||||
|
"</table>\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.SetModeHTML()
|
||||||
|
|
||||||
|
table.AddHeaders("Name", "Value")
|
||||||
|
table.AddRow("hey", "you")
|
||||||
|
table.AddRow("ken", 1234)
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
|
||||||
|
output := table.Render()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatal(DisplayFailedOutput(output, expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableWithHeaderHTML(t *testing.T) {
|
||||||
|
expected := "<table class=\"termtable\">\n" +
|
||||||
|
"<thead>\n" +
|
||||||
|
"<caption>Example</caption>\n" +
|
||||||
|
"<tr><th>Name</th><th>Value</th></tr>\n" +
|
||||||
|
"</thead>\n" +
|
||||||
|
"<tbody>\n" +
|
||||||
|
"<tr><td>hey</td><td>you</td></tr>\n" +
|
||||||
|
"<tr><td>ken</td><td>1234</td></tr>\n" +
|
||||||
|
"<tr><td>derek</td><td>3.14</td></tr>\n" +
|
||||||
|
"<tr><td>derek too</td><td>3.15</td></tr>\n" +
|
||||||
|
"</tbody>\n" +
|
||||||
|
"</table>\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.SetModeHTML()
|
||||||
|
|
||||||
|
table.AddTitle("Example")
|
||||||
|
table.AddHeaders("Name", "Value")
|
||||||
|
table.AddRow("hey", "you")
|
||||||
|
table.AddRow("ken", 1234)
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
|
||||||
|
output := table.Render()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatal(DisplayFailedOutput(output, expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableTitleWidthAdjustsHTML(t *testing.T) {
|
||||||
|
expected := "<table class=\"termtable\">\n" +
|
||||||
|
"<thead>\n" +
|
||||||
|
"<caption>Example My Foo Bar'd Test</caption>\n" +
|
||||||
|
"<tr><th>Name</th><th>Value</th></tr>\n" +
|
||||||
|
"</thead>\n" +
|
||||||
|
"<tbody>\n" +
|
||||||
|
"<tr><td>hey</td><td>you</td></tr>\n" +
|
||||||
|
"<tr><td>ken</td><td>1234</td></tr>\n" +
|
||||||
|
"<tr><td>derek</td><td>3.14</td></tr>\n" +
|
||||||
|
"<tr><td>derek too</td><td>3.15</td></tr>\n" +
|
||||||
|
"</tbody>\n" +
|
||||||
|
"</table>\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.SetModeHTML()
|
||||||
|
|
||||||
|
table.AddTitle("Example My Foo Bar'd Test")
|
||||||
|
table.AddHeaders("Name", "Value")
|
||||||
|
table.AddRow("hey", "you")
|
||||||
|
table.AddRow("ken", 1234)
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
|
||||||
|
output := table.Render()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatal(DisplayFailedOutput(output, expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableWithNoHeadersHTML(t *testing.T) {
|
||||||
|
expected := "<table class=\"termtable\">\n" +
|
||||||
|
"<tbody>\n" +
|
||||||
|
"<tr><td>hey</td><td>you</td></tr>\n" +
|
||||||
|
"<tr><td>ken</td><td>1234</td></tr>\n" +
|
||||||
|
"<tr><td>derek</td><td>3.14</td></tr>\n" +
|
||||||
|
"<tr><td>derek too</td><td>3.15</td></tr>\n" +
|
||||||
|
"</tbody>\n" +
|
||||||
|
"</table>\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.SetModeHTML()
|
||||||
|
|
||||||
|
table.AddRow("hey", "you")
|
||||||
|
table.AddRow("ken", 1234)
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
|
||||||
|
output := table.Render()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatal(DisplayFailedOutput(output, expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableUnicodeWidthsHTML(t *testing.T) {
|
||||||
|
expected := "<table class=\"termtable\">\n" +
|
||||||
|
"<thead>\n" +
|
||||||
|
"<tr><th>Name</th><th>Cost</th></tr>\n" +
|
||||||
|
"</thead>\n" +
|
||||||
|
"<tbody>\n" +
|
||||||
|
"<tr><td>Currency</td><td>¤10</td></tr>\n" +
|
||||||
|
"<tr><td>US Dollar</td><td>$30</td></tr>\n" +
|
||||||
|
"<tr><td>Euro</td><td>€27</td></tr>\n" +
|
||||||
|
"<tr><td>Thai</td><td>฿70</td></tr>\n" +
|
||||||
|
"</tbody>\n" +
|
||||||
|
"</table>\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.SetModeHTML()
|
||||||
|
table.AddHeaders("Name", "Cost")
|
||||||
|
table.AddRow("Currency", "¤10")
|
||||||
|
table.AddRow("US Dollar", "$30")
|
||||||
|
table.AddRow("Euro", "€27")
|
||||||
|
table.AddRow("Thai", "฿70")
|
||||||
|
|
||||||
|
output := table.Render()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatal(DisplayFailedOutput(output, expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableWithAlignment(t *testing.T) {
|
||||||
|
expected := "<table class=\"termtable\">\n" +
|
||||||
|
"<thead>\n" +
|
||||||
|
"<tr><th>Foo</th><th>Bar</th></tr>\n" +
|
||||||
|
"</thead>\n" +
|
||||||
|
"<tbody>\n" +
|
||||||
|
"<tr><td>humpty</td><td>dumpty</td></tr>\n" +
|
||||||
|
"<tr><td align='right'>r</td><td><- on right</td></tr>\n" +
|
||||||
|
"</tbody>\n" +
|
||||||
|
"</table>\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.SetModeHTML()
|
||||||
|
table.AddHeaders("Foo", "Bar")
|
||||||
|
table.AddRow("humpty", "dumpty")
|
||||||
|
table.AddRow(CreateCell("r", &CellStyle{Alignment: AlignRight}), "<- on right")
|
||||||
|
|
||||||
|
output := table.Render()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatal(DisplayFailedOutput(output, expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableAfterSetAlign(t *testing.T) {
|
||||||
|
expected := "<table class=\"termtable\">\n" +
|
||||||
|
"<thead>\n" +
|
||||||
|
"<tr><th>Alphabetical</th><th>Num</th></tr>\n" +
|
||||||
|
"</thead>\n" +
|
||||||
|
"<tbody>\n" +
|
||||||
|
"<tr><td align='right'>alfa</td><td>1</td></tr>\n" +
|
||||||
|
"<tr><td align='right'>bravo</td><td>2</td></tr>\n" +
|
||||||
|
"<tr><td align='right'>charlie</td><td>3</td></tr>\n" +
|
||||||
|
"</tbody>\n" +
|
||||||
|
"</table>\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.SetModeHTML()
|
||||||
|
table.AddHeaders("Alphabetical", "Num")
|
||||||
|
table.AddRow("alfa", 1)
|
||||||
|
table.AddRow("bravo", 2)
|
||||||
|
table.AddRow("charlie", 3)
|
||||||
|
table.SetAlign(AlignRight, 1)
|
||||||
|
|
||||||
|
output := table.Render()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatal(DisplayFailedOutput(output, expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableWithAltTitleStyle(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"<table class=\"termtable\">\n" +
|
||||||
|
"<thead>\n" +
|
||||||
|
"<tr><th style=\"text-align: center\" colspan=\"3\">Metasyntactic</th></tr>\n" +
|
||||||
|
"<tr><th>Foo</th><th>Bar</th><th>Baz</th></tr>\n" +
|
||||||
|
"</thead>\n" +
|
||||||
|
"<tbody>\n" +
|
||||||
|
"<tr><td>a</td><td>b</td><td>c</td></tr>\n" +
|
||||||
|
"<tr><td>α</td><td>β</td><td>γ</td></tr>\n" +
|
||||||
|
"</tbody>\n" +
|
||||||
|
"</table>\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.SetModeHTML()
|
||||||
|
table.SetHTMLStyleTitle(TitleAsThSpan)
|
||||||
|
table.AddTitle("Metasyntactic")
|
||||||
|
table.AddHeaders("Foo", "Bar", "Baz")
|
||||||
|
table.AddRow("a", "b", "c")
|
||||||
|
table.AddRow("α", "β", "γ")
|
||||||
|
|
||||||
|
output := table.Render()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatal(DisplayFailedOutput(output, expected))
|
||||||
|
}
|
||||||
|
}
|
47
dateparse/vendor/github.com/apcera/termtables/row.go
generated
vendored
Normal file
47
dateparse/vendor/github.com/apcera/termtables/row.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright 2012 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
package termtables
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// A Row represents one row of a Table, consisting of some number of Cell
|
||||||
|
// items.
|
||||||
|
type Row struct {
|
||||||
|
cells []*Cell
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRow returns a Row where the cells are created as needed to hold each
|
||||||
|
// item given; each item can be a Cell or content to go into a Cell created
|
||||||
|
// to hold it.
|
||||||
|
func CreateRow(items []interface{}) *Row {
|
||||||
|
row := &Row{cells: []*Cell{}}
|
||||||
|
for _, item := range items {
|
||||||
|
row.AddCell(item)
|
||||||
|
}
|
||||||
|
return row
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCell adds one item to a row as a new cell, where the item is either a
|
||||||
|
// Cell or content to be put into a cell.
|
||||||
|
func (r *Row) AddCell(item interface{}) {
|
||||||
|
if c, ok := item.(*Cell); ok {
|
||||||
|
c.column = len(r.cells)
|
||||||
|
r.cells = append(r.cells, c)
|
||||||
|
} else {
|
||||||
|
r.cells = append(r.cells, createCell(len(r.cells), item, nil))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render returns a string representing the content of one row of a table, where
|
||||||
|
// the Row contains Cells (not Separators) and the representation includes any
|
||||||
|
// vertical borders needed.
|
||||||
|
func (r *Row) Render(style *renderStyle) string {
|
||||||
|
// pre-render and shove into an array... helps with cleanly adding borders
|
||||||
|
renderedCells := []string{}
|
||||||
|
for _, c := range r.cells {
|
||||||
|
renderedCells = append(renderedCells, c.Render(style))
|
||||||
|
}
|
||||||
|
|
||||||
|
// format final output
|
||||||
|
return style.BorderY + strings.Join(renderedCells, style.BorderY) + style.BorderY
|
||||||
|
}
|
29
dateparse/vendor/github.com/apcera/termtables/row_test.go
generated
vendored
Normal file
29
dateparse/vendor/github.com/apcera/termtables/row_test.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2012-2015 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
package termtables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBasicRowRender(t *testing.T) {
|
||||||
|
row := CreateRow([]interface{}{"foo", "bar"})
|
||||||
|
style := &renderStyle{TableStyle: TableStyle{BorderX: "-", BorderY: "|", BorderI: "+",
|
||||||
|
PaddingLeft: 1, PaddingRight: 1}, cellWidths: map[int]int{0: 3, 1: 3}}
|
||||||
|
|
||||||
|
output := row.Render(style)
|
||||||
|
if output != "| foo | bar |" {
|
||||||
|
t.Fatal("Unexpected output:", output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRowRenderWidthBasedPadding(t *testing.T) {
|
||||||
|
row := CreateRow([]interface{}{"foo", "bar"})
|
||||||
|
style := &renderStyle{TableStyle: TableStyle{BorderX: "-", BorderY: "|", BorderI: "+",
|
||||||
|
PaddingLeft: 1, PaddingRight: 1}, cellWidths: map[int]int{0: 3, 1: 5}}
|
||||||
|
|
||||||
|
output := row.Render(style)
|
||||||
|
if output != "| foo | bar |" {
|
||||||
|
t.Fatal("Unexpected output:", output)
|
||||||
|
}
|
||||||
|
}
|
60
dateparse/vendor/github.com/apcera/termtables/separator.go
generated
vendored
Normal file
60
dateparse/vendor/github.com/apcera/termtables/separator.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// Copyright 2012 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
package termtables
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
type lineType int
|
||||||
|
|
||||||
|
// These lines are for horizontal rules; these indicate desired styling,
|
||||||
|
// but simplistic (pure ASCII) markup characters may end up leaving the
|
||||||
|
// variant lines indistinguishable from LINE_INNER.
|
||||||
|
const (
|
||||||
|
// LINE_INNER *must* be the default; where there are vertical lines drawn
|
||||||
|
// across an inner line, the character at that position should indicate
|
||||||
|
// that the vertical line goes both up and down from this horizontal line.
|
||||||
|
LINE_INNER lineType = iota
|
||||||
|
|
||||||
|
// LINE_TOP has only descenders
|
||||||
|
LINE_TOP
|
||||||
|
|
||||||
|
// LINE_SUBTOP has only descenders in the middle, but goes both up and
|
||||||
|
// down at the far left & right edges.
|
||||||
|
LINE_SUBTOP
|
||||||
|
|
||||||
|
// LINE_BOTTOM has only ascenders.
|
||||||
|
LINE_BOTTOM
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Separator is a horizontal rule line, with associated information which
|
||||||
|
// indicates where in a table it is, sufficient for simple cases to let
|
||||||
|
// clean tables be drawn. If a row-spanning cell is created, then this will
|
||||||
|
// be insufficient: we can get away with hand-waving of "well, it's showing
|
||||||
|
// where the border would be" but a more capable handling will require
|
||||||
|
// structure reworking. Patches welcome.
|
||||||
|
type Separator struct {
|
||||||
|
where lineType
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render returns the string representation of a horizontal rule line in the
|
||||||
|
// table.
|
||||||
|
func (s *Separator) Render(style *renderStyle) string {
|
||||||
|
// loop over getting dashes
|
||||||
|
parts := []string{}
|
||||||
|
for i := 0; i < style.columns; i++ {
|
||||||
|
w := style.PaddingLeft + style.CellWidth(i) + style.PaddingRight
|
||||||
|
parts = append(parts, strings.Repeat(style.BorderX, w))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch s.where {
|
||||||
|
case LINE_TOP:
|
||||||
|
return style.BorderTopLeft + strings.Join(parts, style.BorderTop) + style.BorderTopRight
|
||||||
|
case LINE_SUBTOP:
|
||||||
|
return style.BorderLeft + strings.Join(parts, style.BorderTop) + style.BorderRight
|
||||||
|
case LINE_BOTTOM:
|
||||||
|
return style.BorderBottomLeft + strings.Join(parts, style.BorderBottom) + style.BorderBottomRight
|
||||||
|
case LINE_INNER:
|
||||||
|
return style.BorderLeft + strings.Join(parts, style.BorderI) + style.BorderRight
|
||||||
|
}
|
||||||
|
panic("not reached")
|
||||||
|
}
|
36
dateparse/vendor/github.com/apcera/termtables/straight_separator.go
generated
vendored
Normal file
36
dateparse/vendor/github.com/apcera/termtables/straight_separator.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2012 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
package termtables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A StraightSeparator is a horizontal line with associated information about
|
||||||
|
// what sort of position it takes in the table, so as to control which shapes
|
||||||
|
// will be used where vertical lines are expected to touch this horizontal
|
||||||
|
// line.
|
||||||
|
type StraightSeparator struct {
|
||||||
|
where lineType
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render returns a string representing this separator, with all border
|
||||||
|
// crossings appropriately chosen.
|
||||||
|
func (s *StraightSeparator) Render(style *renderStyle) string {
|
||||||
|
// loop over getting dashes
|
||||||
|
width := 0
|
||||||
|
for i := 0; i < style.columns; i++ {
|
||||||
|
width += style.PaddingLeft + style.CellWidth(i) + style.PaddingRight + utf8.RuneCountInString(style.BorderI)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch s.where {
|
||||||
|
case LINE_TOP:
|
||||||
|
return style.BorderTopLeft + strings.Repeat(style.BorderX, width-1) + style.BorderTopRight
|
||||||
|
case LINE_INNER, LINE_SUBTOP:
|
||||||
|
return style.BorderLeft + strings.Repeat(style.BorderX, width-1) + style.BorderRight
|
||||||
|
case LINE_BOTTOM:
|
||||||
|
return style.BorderBottomLeft + strings.Repeat(style.BorderX, width-1) + style.BorderBottomRight
|
||||||
|
}
|
||||||
|
panic("not reached")
|
||||||
|
}
|
214
dateparse/vendor/github.com/apcera/termtables/style.go
generated
vendored
Normal file
214
dateparse/vendor/github.com/apcera/termtables/style.go
generated
vendored
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
// Copyright 2012-2013 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
package termtables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tableAlignment int
|
||||||
|
|
||||||
|
// These constants control the alignment which should be used when rendering
|
||||||
|
// the content of a cell.
|
||||||
|
const (
|
||||||
|
AlignLeft = tableAlignment(1)
|
||||||
|
AlignCenter = tableAlignment(2)
|
||||||
|
AlignRight = tableAlignment(3)
|
||||||
|
)
|
||||||
|
|
||||||
|
// TableStyle controls styling information for a Table as a whole.
|
||||||
|
//
|
||||||
|
// For the Border rules, only X, Y and I are needed, and all have defaults.
|
||||||
|
// The others will all default to the same as BorderI.
|
||||||
|
type TableStyle struct {
|
||||||
|
SkipBorder bool
|
||||||
|
BorderX string
|
||||||
|
BorderY string
|
||||||
|
BorderI string
|
||||||
|
BorderTop string
|
||||||
|
BorderBottom string
|
||||||
|
BorderRight string
|
||||||
|
BorderLeft string
|
||||||
|
BorderTopLeft string
|
||||||
|
BorderTopRight string
|
||||||
|
BorderBottomLeft string
|
||||||
|
BorderBottomRight string
|
||||||
|
PaddingLeft int
|
||||||
|
PaddingRight int
|
||||||
|
Width int
|
||||||
|
Alignment tableAlignment
|
||||||
|
htmlRules htmlStyleRules
|
||||||
|
}
|
||||||
|
|
||||||
|
// A CellStyle controls all style applicable to one Cell.
|
||||||
|
type CellStyle struct {
|
||||||
|
// Alignment indicates the alignment to be used in rendering the content
|
||||||
|
Alignment tableAlignment
|
||||||
|
|
||||||
|
// ColSpan indicates how many columns this Cell is expected to consume.
|
||||||
|
ColSpan int
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultStyle is a TableStyle which can be used to get some simple
|
||||||
|
// default styling for a table, using ASCII characters for drawing borders.
|
||||||
|
var DefaultStyle = &TableStyle{
|
||||||
|
SkipBorder: false,
|
||||||
|
BorderX: "-", BorderY: "|", BorderI: "+",
|
||||||
|
PaddingLeft: 1, PaddingRight: 1,
|
||||||
|
Width: 80,
|
||||||
|
Alignment: AlignLeft,
|
||||||
|
|
||||||
|
// FIXME: the use of a Width here may interact poorly with a changing
|
||||||
|
// MaxColumns value; we don't set MaxColumns here because the evaluation
|
||||||
|
// order of a var and an init value adds undesired subtlety.
|
||||||
|
}
|
||||||
|
|
||||||
|
type renderStyle struct {
|
||||||
|
cellWidths map[int]int
|
||||||
|
columns int
|
||||||
|
|
||||||
|
// used for markdown rendering
|
||||||
|
replaceContent func(string) string
|
||||||
|
|
||||||
|
TableStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
// setUtfBoxStyle changes the border characters to be suitable for use when
|
||||||
|
// the output stream can render UTF-8 characters.
|
||||||
|
func (s *TableStyle) setUtfBoxStyle() {
|
||||||
|
s.BorderX = "─"
|
||||||
|
s.BorderY = "│"
|
||||||
|
s.BorderI = "┼"
|
||||||
|
s.BorderTop = "┬"
|
||||||
|
s.BorderBottom = "┴"
|
||||||
|
s.BorderLeft = "├"
|
||||||
|
s.BorderRight = "┤"
|
||||||
|
s.BorderTopLeft = "╭"
|
||||||
|
s.BorderTopRight = "╮"
|
||||||
|
s.BorderBottomLeft = "╰"
|
||||||
|
s.BorderBottomRight = "╯"
|
||||||
|
}
|
||||||
|
|
||||||
|
// setAsciiBoxStyle changes the border characters back to their defaults
|
||||||
|
func (s *TableStyle) setAsciiBoxStyle() {
|
||||||
|
s.BorderX = "-"
|
||||||
|
s.BorderY = "|"
|
||||||
|
s.BorderI = "+"
|
||||||
|
s.BorderTop, s.BorderBottom, s.BorderLeft, s.BorderRight = "", "", "", ""
|
||||||
|
s.BorderTopLeft, s.BorderTopRight, s.BorderBottomLeft, s.BorderBottomRight = "", "", "", ""
|
||||||
|
s.fillStyleRules()
|
||||||
|
}
|
||||||
|
|
||||||
|
// fillStyleRules populates members of the TableStyle box-drawing specification
|
||||||
|
// with BorderI as the default.
|
||||||
|
func (s *TableStyle) fillStyleRules() {
|
||||||
|
if s.BorderTop == "" {
|
||||||
|
s.BorderTop = s.BorderI
|
||||||
|
}
|
||||||
|
if s.BorderBottom == "" {
|
||||||
|
s.BorderBottom = s.BorderI
|
||||||
|
}
|
||||||
|
if s.BorderLeft == "" {
|
||||||
|
s.BorderLeft = s.BorderI
|
||||||
|
}
|
||||||
|
if s.BorderRight == "" {
|
||||||
|
s.BorderRight = s.BorderI
|
||||||
|
}
|
||||||
|
if s.BorderTopLeft == "" {
|
||||||
|
s.BorderTopLeft = s.BorderI
|
||||||
|
}
|
||||||
|
if s.BorderTopRight == "" {
|
||||||
|
s.BorderTopRight = s.BorderI
|
||||||
|
}
|
||||||
|
if s.BorderBottomLeft == "" {
|
||||||
|
s.BorderBottomLeft = s.BorderI
|
||||||
|
}
|
||||||
|
if s.BorderBottomRight == "" {
|
||||||
|
s.BorderBottomRight = s.BorderI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createRenderStyle(table *Table) *renderStyle {
|
||||||
|
style := &renderStyle{TableStyle: *table.Style, cellWidths: map[int]int{}}
|
||||||
|
style.TableStyle.fillStyleRules()
|
||||||
|
|
||||||
|
if table.outputMode == outputMarkdown {
|
||||||
|
style.buildReplaceContent(table.Style.BorderY)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: handle actually defined width condition
|
||||||
|
|
||||||
|
// loop over the rows and cells to calculate widths
|
||||||
|
for _, element := range table.elements {
|
||||||
|
// skip separators
|
||||||
|
if _, ok := element.(*Separator); ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate over cells
|
||||||
|
if row, ok := element.(*Row); ok {
|
||||||
|
for i, cell := range row.cells {
|
||||||
|
// FIXME: need to support sizing with colspan handling
|
||||||
|
if cell.colSpan > 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if style.cellWidths[i] < cell.Width() {
|
||||||
|
style.cellWidths[i] = cell.Width()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
style.columns = len(style.cellWidths)
|
||||||
|
|
||||||
|
// calculate actual width
|
||||||
|
width := utf8.RuneCountInString(style.BorderLeft) // start at '1' for left border
|
||||||
|
internalBorderWidth := utf8.RuneCountInString(style.BorderI)
|
||||||
|
|
||||||
|
lastIndex := 0
|
||||||
|
for i, v := range style.cellWidths {
|
||||||
|
width += v + style.PaddingLeft + style.PaddingRight + internalBorderWidth
|
||||||
|
if i > lastIndex {
|
||||||
|
lastIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if internalBorderWidth != utf8.RuneCountInString(style.BorderRight) {
|
||||||
|
width += utf8.RuneCountInString(style.BorderRight) - internalBorderWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
if table.titleCell != nil {
|
||||||
|
titleMinWidth := 0 +
|
||||||
|
table.titleCell.Width() +
|
||||||
|
utf8.RuneCountInString(style.BorderLeft) +
|
||||||
|
utf8.RuneCountInString(style.BorderRight) +
|
||||||
|
style.PaddingLeft +
|
||||||
|
style.PaddingRight
|
||||||
|
|
||||||
|
if width < titleMinWidth {
|
||||||
|
// minWidth must be set to include padding of the title, as required
|
||||||
|
style.cellWidths[lastIndex] += (titleMinWidth - width)
|
||||||
|
width = titleMinWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// right border is covered in loop
|
||||||
|
style.Width = width
|
||||||
|
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
|
||||||
|
// CellWidth returns the width of the cell at the supplied index, where the
|
||||||
|
// width is the number of tty character-cells required to draw the glyphs.
|
||||||
|
func (s *renderStyle) CellWidth(i int) int {
|
||||||
|
return s.cellWidths[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildReplaceContent creates a function closure, with minimal bound lexical
|
||||||
|
// state, which replaces content
|
||||||
|
func (s *renderStyle) buildReplaceContent(bad string) {
|
||||||
|
replacement := fmt.Sprintf("&#x%02x;", bad)
|
||||||
|
s.replaceContent = func(old string) string {
|
||||||
|
return strings.Replace(old, bad, replacement, -1)
|
||||||
|
}
|
||||||
|
}
|
371
dateparse/vendor/github.com/apcera/termtables/table.go
generated
vendored
Normal file
371
dateparse/vendor/github.com/apcera/termtables/table.go
generated
vendored
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
// Copyright 2012-2013 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
package termtables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/apcera/termtables/term"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MaxColumns represents the maximum number of columns that are available for
|
||||||
|
// display without wrapping around the right-hand side of the terminal window.
|
||||||
|
// At program initialization, the value will be automatically set according
|
||||||
|
// to available sources of information, including the $COLUMNS environment
|
||||||
|
// variable and, on Unix, tty information.
|
||||||
|
var MaxColumns = 80
|
||||||
|
|
||||||
|
// Element the interface that can draw a representation of the contents of a
|
||||||
|
// table cell.
|
||||||
|
type Element interface {
|
||||||
|
Render(*renderStyle) string
|
||||||
|
}
|
||||||
|
|
||||||
|
type outputMode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
outputTerminal outputMode = iota
|
||||||
|
outputMarkdown
|
||||||
|
outputHTML
|
||||||
|
)
|
||||||
|
|
||||||
|
// Open question: should UTF-8 become an output mode? It does require more
|
||||||
|
// tracking when resetting, if the locale-enabling had been used.
|
||||||
|
|
||||||
|
var outputsEnabled struct {
|
||||||
|
UTF8 bool
|
||||||
|
HTML bool
|
||||||
|
Markdown bool
|
||||||
|
titleStyle titleStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultOutputMode outputMode = outputTerminal
|
||||||
|
|
||||||
|
// Table represents a terminal table. The Style can be directly accessed
|
||||||
|
// and manipulated; all other access is via methods.
|
||||||
|
type Table struct {
|
||||||
|
Style *TableStyle
|
||||||
|
|
||||||
|
elements []Element
|
||||||
|
headers []interface{}
|
||||||
|
title interface{}
|
||||||
|
titleCell *Cell
|
||||||
|
outputMode outputMode
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableUTF8 will unconditionally enable using UTF-8 box-drawing characters
|
||||||
|
// for any tables created after this call, as the default style.
|
||||||
|
func EnableUTF8() {
|
||||||
|
outputsEnabled.UTF8 = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetModeHTML will control whether or not new tables generated will be in HTML
|
||||||
|
// mode by default; HTML-or-not takes precedence over options which control how
|
||||||
|
// a terminal output will be rendered, such as whether or not to use UTF8.
|
||||||
|
// This affects any tables created after this call.
|
||||||
|
func SetModeHTML(onoff bool) {
|
||||||
|
outputsEnabled.HTML = onoff
|
||||||
|
chooseDefaultOutput()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetModeMarkdown will control whether or not new tables generated will be
|
||||||
|
// in Markdown mode by default. HTML-mode takes precedence.
|
||||||
|
func SetModeMarkdown(onoff bool) {
|
||||||
|
outputsEnabled.Markdown = onoff
|
||||||
|
chooseDefaultOutput()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableUTF8PerLocale will use current locale character map information to
|
||||||
|
// determine if UTF-8 is expected and, if so, is equivalent to EnableUTF8.
|
||||||
|
func EnableUTF8PerLocale() {
|
||||||
|
locale := getLocale()
|
||||||
|
if strings.Contains(locale, "UTF-8") {
|
||||||
|
EnableUTF8()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getLocale returns the current locale name.
|
||||||
|
func getLocale() string {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// TODO: detect windows locale
|
||||||
|
return "US-ASCII"
|
||||||
|
}
|
||||||
|
return unixLocale()
|
||||||
|
}
|
||||||
|
|
||||||
|
// unixLocale returns the locale by checking the $LC_ALL, $LC_CTYPE, and $LANG
|
||||||
|
// environment variables. If none of those are set, it returns "US-ASCII".
|
||||||
|
func unixLocale() string {
|
||||||
|
for _, env := range []string{"LC_ALL", "LC_CTYPE", "LANG"} {
|
||||||
|
if locale := os.Getenv(env); locale != "" {
|
||||||
|
return locale
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "US-ASCII"
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHTMLStyleTitle lets an HTML title output mode be chosen.
|
||||||
|
func SetHTMLStyleTitle(want titleStyle) {
|
||||||
|
outputsEnabled.titleStyle = want
|
||||||
|
}
|
||||||
|
|
||||||
|
// chooseDefaultOutput sets defaultOutputMode based on priority
|
||||||
|
// choosing amongst the options which are enabled. Pros: simpler
|
||||||
|
// encapsulation; cons: setting markdown doesn't disable HTML if
|
||||||
|
// HTML was previously enabled and was later disabled.
|
||||||
|
// This seems fairly reasonable.
|
||||||
|
func chooseDefaultOutput() {
|
||||||
|
if outputsEnabled.HTML {
|
||||||
|
defaultOutputMode = outputHTML
|
||||||
|
} else if outputsEnabled.Markdown {
|
||||||
|
defaultOutputMode = outputMarkdown
|
||||||
|
} else {
|
||||||
|
defaultOutputMode = outputTerminal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Do not enable UTF-8 per locale by default, breaks tests.
|
||||||
|
sz, err := term.GetSize()
|
||||||
|
if err == nil && sz.Columns != 0 {
|
||||||
|
MaxColumns = sz.Columns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTable creates an empty Table using defaults for style.
|
||||||
|
func CreateTable() *Table {
|
||||||
|
t := &Table{elements: []Element{}, Style: DefaultStyle}
|
||||||
|
if outputsEnabled.UTF8 {
|
||||||
|
t.Style.setUtfBoxStyle()
|
||||||
|
}
|
||||||
|
if outputsEnabled.titleStyle != titleStyle(0) {
|
||||||
|
t.Style.htmlRules.title = outputsEnabled.titleStyle
|
||||||
|
}
|
||||||
|
t.outputMode = defaultOutputMode
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSeparator adds a line to the table content, where the line
|
||||||
|
// consists of separator characters.
|
||||||
|
func (t *Table) AddSeparator() {
|
||||||
|
t.elements = append(t.elements, &Separator{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRow adds the supplied items as cells in one row of the table.
|
||||||
|
func (t *Table) AddRow(items ...interface{}) *Row {
|
||||||
|
row := CreateRow(items)
|
||||||
|
t.elements = append(t.elements, row)
|
||||||
|
return row
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTitle supplies a table title, which if present will be rendered as
|
||||||
|
// one cell across the width of the table, as the first row.
|
||||||
|
func (t *Table) AddTitle(title interface{}) {
|
||||||
|
t.title = title
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHeaders supplies column headers for the table.
|
||||||
|
func (t *Table) AddHeaders(headers ...interface{}) {
|
||||||
|
t.headers = append(t.headers, headers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAlign changes the alignment for elements in a column of the table;
|
||||||
|
// alignments are stored with each cell, so cells added after a call to
|
||||||
|
// SetAlign will not pick up the change. Columns are numbered from 1.
|
||||||
|
func (t *Table) SetAlign(align tableAlignment, column int) {
|
||||||
|
if column < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := range t.elements {
|
||||||
|
row, ok := t.elements[i].(*Row)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if column >= len(row.cells) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
row.cells[column-1].alignment = &align
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UTF8Box sets the table style to use UTF-8 box-drawing characters,
|
||||||
|
// overriding all relevant style elements at the time of the call.
|
||||||
|
func (t *Table) UTF8Box() {
|
||||||
|
t.Style.setUtfBoxStyle()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetModeHTML switches this table to be in HTML when rendered; the
|
||||||
|
// default depends upon whether the package function SetModeHTML() has been
|
||||||
|
// called, and with what value. This method forces the feature on for this
|
||||||
|
// table. Turning off involves choosing a different mode, per-table.
|
||||||
|
func (t *Table) SetModeHTML() {
|
||||||
|
t.outputMode = outputHTML
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetModeMarkdown switches this table to be in Markdown mode
|
||||||
|
func (t *Table) SetModeMarkdown() {
|
||||||
|
t.outputMode = outputMarkdown
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetModeTerminal switches this table to be in terminal mode.
|
||||||
|
func (t *Table) SetModeTerminal() {
|
||||||
|
t.outputMode = outputTerminal
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHTMLStyleTitle lets an HTML output mode be chosen; we should rework this
|
||||||
|
// into a more generic and extensible API as we clean up termtables.
|
||||||
|
func (t *Table) SetHTMLStyleTitle(want titleStyle) {
|
||||||
|
t.Style.htmlRules.title = want
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render returns a string representation of a fully rendered table, drawn
|
||||||
|
// out for display, with embedded newlines. If this table is in HTML mode,
|
||||||
|
// then this is equivalent to RenderHTML().
|
||||||
|
func (t *Table) Render() string {
|
||||||
|
// Elements is already populated with row data.
|
||||||
|
switch t.outputMode {
|
||||||
|
case outputTerminal:
|
||||||
|
return t.renderTerminal()
|
||||||
|
case outputMarkdown:
|
||||||
|
return t.renderMarkdown()
|
||||||
|
case outputHTML:
|
||||||
|
return t.RenderHTML()
|
||||||
|
default:
|
||||||
|
panic("unknown output mode set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// renderTerminal returns a string representation of a fully rendered table,
|
||||||
|
// drawn out for display, with embedded newlines.
|
||||||
|
func (t *Table) renderTerminal() string {
|
||||||
|
// Use a placeholder rather than adding titles/headers to the tables
|
||||||
|
// elements or else successive calls will compound them.
|
||||||
|
tt := t.clone()
|
||||||
|
|
||||||
|
// Initial top line.
|
||||||
|
if !tt.Style.SkipBorder {
|
||||||
|
if tt.title != nil && tt.headers == nil {
|
||||||
|
tt.elements = append([]Element{&Separator{where: LINE_SUBTOP}}, tt.elements...)
|
||||||
|
} else if tt.title == nil && tt.headers == nil {
|
||||||
|
tt.elements = append([]Element{&Separator{where: LINE_TOP}}, tt.elements...)
|
||||||
|
} else {
|
||||||
|
tt.elements = append([]Element{&Separator{where: LINE_INNER}}, tt.elements...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have headers, include them.
|
||||||
|
if tt.headers != nil {
|
||||||
|
ne := make([]Element, 2)
|
||||||
|
ne[1] = CreateRow(tt.headers)
|
||||||
|
if tt.title != nil {
|
||||||
|
ne[0] = &Separator{where: LINE_SUBTOP}
|
||||||
|
} else {
|
||||||
|
ne[0] = &Separator{where: LINE_TOP}
|
||||||
|
}
|
||||||
|
tt.elements = append(ne, tt.elements...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a title, write it.
|
||||||
|
if tt.title != nil {
|
||||||
|
// Match changes to this into renderMarkdown too.
|
||||||
|
tt.titleCell = CreateCell(tt.title, &CellStyle{Alignment: AlignCenter, ColSpan: 999})
|
||||||
|
ne := []Element{
|
||||||
|
&StraightSeparator{where: LINE_TOP},
|
||||||
|
CreateRow([]interface{}{tt.titleCell}),
|
||||||
|
}
|
||||||
|
tt.elements = append(ne, tt.elements...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new table from the
|
||||||
|
// generate the runtime style. Must include all cells being printed.
|
||||||
|
style := createRenderStyle(tt)
|
||||||
|
|
||||||
|
// Loop over the elements and render them.
|
||||||
|
b := bytes.NewBuffer(nil)
|
||||||
|
for _, e := range tt.elements {
|
||||||
|
b.WriteString(e.Render(style))
|
||||||
|
b.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add bottom line.
|
||||||
|
if !style.SkipBorder {
|
||||||
|
b.WriteString((&Separator{where: LINE_BOTTOM}).Render(style) + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// renderMarkdown returns a string representation of a table in Markdown
|
||||||
|
// markup format using GitHub Flavored Markdown's notation (since tables
|
||||||
|
// are not in the core Markdown spec).
|
||||||
|
func (t *Table) renderMarkdown() string {
|
||||||
|
// We need ASCII drawing characters; we need a line after the header;
|
||||||
|
// *do* need a header! Do not need to markdown-escape contents of
|
||||||
|
// tables as markdown is ignored in there. Do need to do _something_
|
||||||
|
// with a '|' character shown as a member of a table.
|
||||||
|
|
||||||
|
t.Style.setAsciiBoxStyle()
|
||||||
|
|
||||||
|
firstLines := make([]Element, 0, 2)
|
||||||
|
|
||||||
|
if t.headers == nil {
|
||||||
|
initial := createRenderStyle(t)
|
||||||
|
if initial.columns > 1 {
|
||||||
|
row := CreateRow([]interface{}{})
|
||||||
|
for i := 0; i < initial.columns; i++ {
|
||||||
|
row.AddCell(CreateCell(i+1, &CellStyle{}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
firstLines = append(firstLines, CreateRow(t.headers))
|
||||||
|
// This is a dummy line, swapped out below.
|
||||||
|
firstLines = append(firstLines, firstLines[0])
|
||||||
|
t.elements = append(firstLines, t.elements...)
|
||||||
|
// Generate the runtime style.
|
||||||
|
style := createRenderStyle(t)
|
||||||
|
// We know that the second line is a dummy, we can replace it.
|
||||||
|
mdRow := CreateRow([]interface{}{})
|
||||||
|
for i := 0; i < style.columns; i++ {
|
||||||
|
mdRow.AddCell(CreateCell(strings.Repeat("-", style.cellWidths[i]), &CellStyle{}))
|
||||||
|
}
|
||||||
|
t.elements[1] = mdRow
|
||||||
|
|
||||||
|
b := bytes.NewBuffer(nil)
|
||||||
|
// Comes after style is generated, which must come after all width-affecting
|
||||||
|
// changes are in.
|
||||||
|
if t.title != nil {
|
||||||
|
// Markdown doesn't support titles or column spanning; we _should_
|
||||||
|
// escape the title, but doing that to handle all possible forms of
|
||||||
|
// markup would require a heavy dependency, so we punt.
|
||||||
|
b.WriteString("Table: ")
|
||||||
|
b.WriteString(strings.TrimSpace(CreateCell(t.title, &CellStyle{}).Render(style)))
|
||||||
|
b.WriteString("\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over the elements and render them.
|
||||||
|
for _, e := range t.elements {
|
||||||
|
b.WriteString(e.Render(style))
|
||||||
|
b.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// clone returns a copy of the table with the underlying slices being copied;
|
||||||
|
// the references to the Elements/cells are left as shallow copies.
|
||||||
|
func (t *Table) clone() *Table {
|
||||||
|
tt := &Table{outputMode: t.outputMode, Style: t.Style, title: t.title}
|
||||||
|
if t.headers != nil {
|
||||||
|
tt.headers = make([]interface{}, len(t.headers))
|
||||||
|
copy(tt.headers, t.headers)
|
||||||
|
}
|
||||||
|
if t.elements != nil {
|
||||||
|
tt.elements = make([]Element, len(t.elements))
|
||||||
|
copy(tt.elements, t.elements)
|
||||||
|
}
|
||||||
|
return tt
|
||||||
|
}
|
562
dateparse/vendor/github.com/apcera/termtables/table_test.go
generated
vendored
Normal file
562
dateparse/vendor/github.com/apcera/termtables/table_test.go
generated
vendored
Normal file
@ -0,0 +1,562 @@
|
|||||||
|
// Copyright 2012-2013 Apcera Inc. All rights reserved.
|
||||||
|
package termtables
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func DisplayFailedOutput(actual, expected string) string {
|
||||||
|
return "Output didn't match expected\n\n" +
|
||||||
|
"Actual:\n\n" +
|
||||||
|
actual + "\n" +
|
||||||
|
"Expected:\n\n" +
|
||||||
|
expected
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkRendersTo(t *testing.T, table *Table, expected string) {
|
||||||
|
output := table.Render()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatal(DisplayFailedOutput(output, expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateTable(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+-----------+-------+\n" +
|
||||||
|
"| Name | Value |\n" +
|
||||||
|
"+-----------+-------+\n" +
|
||||||
|
"| hey | you |\n" +
|
||||||
|
"| ken | 1234 |\n" +
|
||||||
|
"| derek | 3.14 |\n" +
|
||||||
|
"| derek too | 3.15 |\n" +
|
||||||
|
"| escaping | rox%% |\n" +
|
||||||
|
"+-----------+-------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
|
||||||
|
table.AddHeaders("Name", "Value")
|
||||||
|
table.AddRow("hey", "you")
|
||||||
|
table.AddRow("ken", 1234)
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
table.AddRow("escaping", "rox%%")
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStyleResets(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+-----------+-------+\n" +
|
||||||
|
"| Name | Value |\n" +
|
||||||
|
"+-----------+-------+\n" +
|
||||||
|
"| hey | you |\n" +
|
||||||
|
"| ken | 1234 |\n" +
|
||||||
|
"| derek | 3.14 |\n" +
|
||||||
|
"| derek too | 3.15 |\n" +
|
||||||
|
"+-----------+-------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.UTF8Box()
|
||||||
|
table.Style.setAsciiBoxStyle()
|
||||||
|
|
||||||
|
table.AddHeaders("Name", "Value")
|
||||||
|
table.AddRow("hey", "you")
|
||||||
|
table.AddRow("ken", 1234)
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableWithHeader(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+-------------------+\n" +
|
||||||
|
"| Example |\n" +
|
||||||
|
"+-----------+-------+\n" +
|
||||||
|
"| Name | Value |\n" +
|
||||||
|
"+-----------+-------+\n" +
|
||||||
|
"| hey | you |\n" +
|
||||||
|
"| ken | 1234 |\n" +
|
||||||
|
"| derek | 3.14 |\n" +
|
||||||
|
"| derek too | 3.15 |\n" +
|
||||||
|
"+-----------+-------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
|
||||||
|
table.AddTitle("Example")
|
||||||
|
table.AddHeaders("Name", "Value")
|
||||||
|
table.AddRow("hey", "you")
|
||||||
|
table.AddRow("ken", 1234)
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTableWithHeaderMultipleTimes ensures that printing a table with headers
|
||||||
|
// multiple times continues to render correctly.
|
||||||
|
func TestTableWithHeaderMultipleTimes(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+-------------------+\n" +
|
||||||
|
"| Example |\n" +
|
||||||
|
"+-----------+-------+\n" +
|
||||||
|
"| Name | Value |\n" +
|
||||||
|
"+-----------+-------+\n" +
|
||||||
|
"| hey | you |\n" +
|
||||||
|
"| ken | 1234 |\n" +
|
||||||
|
"| derek | 3.14 |\n" +
|
||||||
|
"| derek too | 3.15 |\n" +
|
||||||
|
"+-----------+-------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
|
||||||
|
table.AddTitle("Example")
|
||||||
|
table.AddHeaders("Name", "Value")
|
||||||
|
table.AddRow("hey", "you")
|
||||||
|
table.AddRow("ken", 1234)
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableTitleWidthAdjusts(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+---------------------------+\n" +
|
||||||
|
"| Example My Foo Bar'd Test |\n" +
|
||||||
|
"+-----------+---------------+\n" +
|
||||||
|
"| Name | Value |\n" +
|
||||||
|
"+-----------+---------------+\n" +
|
||||||
|
"| hey | you |\n" +
|
||||||
|
"| ken | 1234 |\n" +
|
||||||
|
"| derek | 3.14 |\n" +
|
||||||
|
"| derek too | 3.15 |\n" +
|
||||||
|
"+-----------+---------------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
|
||||||
|
table.AddTitle("Example My Foo Bar'd Test")
|
||||||
|
table.AddHeaders("Name", "Value")
|
||||||
|
table.AddRow("hey", "you")
|
||||||
|
table.AddRow("ken", 1234)
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableHeaderWidthAdjusts(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+---------------+---------------------+\n" +
|
||||||
|
"| Slightly Long | More than 2 columns |\n" +
|
||||||
|
"+---------------+---------------------+\n" +
|
||||||
|
"| a | b |\n" +
|
||||||
|
"+---------------+---------------------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
|
||||||
|
table.AddHeaders("Slightly Long", "More than 2 columns")
|
||||||
|
table.AddRow("a", "b")
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableWithNoHeaders(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+-----------+------+\n" +
|
||||||
|
"| hey | you |\n" +
|
||||||
|
"| ken | 1234 |\n" +
|
||||||
|
"| derek | 3.14 |\n" +
|
||||||
|
"| derek too | 3.15 |\n" +
|
||||||
|
"+-----------+------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
|
||||||
|
table.AddRow("hey", "you")
|
||||||
|
table.AddRow("ken", 1234)
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableUnicodeWidths(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+-----------+------+\n" +
|
||||||
|
"| Name | Cost |\n" +
|
||||||
|
"+-----------+------+\n" +
|
||||||
|
"| Currency | ¤10 |\n" +
|
||||||
|
"| US Dollar | $30 |\n" +
|
||||||
|
"| Euro | €27 |\n" +
|
||||||
|
"| Thai | ฿70 |\n" +
|
||||||
|
"+-----------+------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.AddHeaders("Name", "Cost")
|
||||||
|
table.AddRow("Currency", "¤10")
|
||||||
|
table.AddRow("US Dollar", "$30")
|
||||||
|
table.AddRow("Euro", "€27")
|
||||||
|
table.AddRow("Thai", "฿70")
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableInUTF8(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"╭───────────────────╮\n" +
|
||||||
|
"│ Example │\n" +
|
||||||
|
"├───────────┬───────┤\n" +
|
||||||
|
"│ Name │ Value │\n" +
|
||||||
|
"├───────────┼───────┤\n" +
|
||||||
|
"│ hey │ you │\n" +
|
||||||
|
"│ ken │ 1234 │\n" +
|
||||||
|
"│ derek │ 3.14 │\n" +
|
||||||
|
"│ derek too │ 3.15 │\n" +
|
||||||
|
"│ escaping │ rox%% │\n" +
|
||||||
|
"╰───────────┴───────╯\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.UTF8Box()
|
||||||
|
|
||||||
|
table.AddTitle("Example")
|
||||||
|
table.AddHeaders("Name", "Value")
|
||||||
|
table.AddRow("hey", "you")
|
||||||
|
table.AddRow("ken", 1234)
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
table.AddRow("escaping", "rox%%")
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableUnicodeUTF8AndSGR(t *testing.T) {
|
||||||
|
// at present, this mostly just tests that alignment still works
|
||||||
|
expected := "" +
|
||||||
|
"╭───────────────────────╮\n" +
|
||||||
|
"│ \033[1mFanciness\033[0m │\n" +
|
||||||
|
"├──────────┬────────────┤\n" +
|
||||||
|
"│ \033[31mred\033[0m │ \033[32mgreen\033[0m │\n" +
|
||||||
|
"├──────────┼────────────┤\n" +
|
||||||
|
"│ plain │ text │\n" +
|
||||||
|
"│ Καλημέρα │ κόσμε │\n" +
|
||||||
|
"│ \033[1mvery\033[0m │ \033[4munderlined\033[0m │\n" +
|
||||||
|
"│ a\033[1mb\033[0mc │ \033[45mmagenta\033[0m │\n" +
|
||||||
|
"│ \033[31m→\033[0m │ \033[32m←\033[0m │\n" +
|
||||||
|
"╰──────────┴────────────╯\n"
|
||||||
|
|
||||||
|
sgred := func(in string, sgrPm string) string {
|
||||||
|
return "\033[" + sgrPm + "m" + in + "\033[0m"
|
||||||
|
}
|
||||||
|
bold := func(in string) string { return sgred(in, "1") }
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.UTF8Box()
|
||||||
|
|
||||||
|
table.AddTitle(bold("Fanciness"))
|
||||||
|
table.AddHeaders(sgred("red", "31"), sgred("green", "32"))
|
||||||
|
table.AddRow("plain", "text")
|
||||||
|
table.AddRow("Καλημέρα", "κόσμε") // from http://plan9.bell-labs.com/sys/doc/utf.html
|
||||||
|
table.AddRow(bold("very"), sgred("underlined", "4"))
|
||||||
|
table.AddRow("a"+bold("b")+"c", sgred("magenta", "45"))
|
||||||
|
table.AddRow(sgred("→", "31"), sgred("←", "32"))
|
||||||
|
// TODO: in future, if we start detecting presence of SGR sequences, we
|
||||||
|
// should ensure that the SGR reset is done at the end of the cell content,
|
||||||
|
// so that SGR doesn't "bleed across" (cells or rows). We would then add
|
||||||
|
// tests for that here.
|
||||||
|
//
|
||||||
|
// Of course, at that point, we'd also want to support automatic HTML
|
||||||
|
// styling conversion too, so would need a test for that also.
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableInMarkdown(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"Table: Example\n\n" +
|
||||||
|
"| Name | Value |\n" +
|
||||||
|
"| ----- | ----- |\n" +
|
||||||
|
"| hey | you |\n" +
|
||||||
|
"| a | b | esc |\n" +
|
||||||
|
"| esc | rox%% |\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.SetModeMarkdown()
|
||||||
|
|
||||||
|
table.AddTitle("Example")
|
||||||
|
table.AddHeaders("Name", "Value")
|
||||||
|
table.AddRow("hey", "you")
|
||||||
|
table.AddRow("a | b", "esc")
|
||||||
|
table.AddRow("esc", "rox%%")
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTitleUnicodeWidths(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+-------+\n" +
|
||||||
|
"| ← 5 → |\n" +
|
||||||
|
"+---+---+\n" +
|
||||||
|
"| a | b |\n" +
|
||||||
|
"| c | d |\n" +
|
||||||
|
"| e | 3 |\n" +
|
||||||
|
"+---+---+\n"
|
||||||
|
|
||||||
|
// minimum width for a table of two columns is 9 characters, given
|
||||||
|
// one space of padding, and non-empty tables.
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
|
||||||
|
// We have 4 characters down for left and right columns and padding, so
|
||||||
|
// a width of 5 for us should match the minimum per the columns
|
||||||
|
|
||||||
|
// 5 characters; each arrow is three octets in UTF-8, giving 9 bytes
|
||||||
|
// so, same in character-count-width, longer in bytes
|
||||||
|
table.AddTitle("← 5 →")
|
||||||
|
|
||||||
|
// a single character per cell, here; use ASCII characters
|
||||||
|
table.AddRow("a", "b")
|
||||||
|
table.AddRow("c", "d")
|
||||||
|
table.AddRow("e", 3)
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We identified two error conditions wherein length wrapping would not correctly
|
||||||
|
// wrap width when, for instance, in a two-column table, the longest row in the
|
||||||
|
// right-hand column was not the same as the longest row in the left-hand column.
|
||||||
|
// This tests that we correctly accumulate the maximum width across all rows of
|
||||||
|
// the termtable and adjust width accordingly.
|
||||||
|
func TestTableWidthHandling(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+-----------------------------------------+\n" +
|
||||||
|
"| Example... to Fix My Test |\n" +
|
||||||
|
"+-----------------+-----------------------+\n" +
|
||||||
|
"| hey foo bar baz | you |\n" +
|
||||||
|
"| ken | you should write code |\n" +
|
||||||
|
"| derek | 3.14 |\n" +
|
||||||
|
"| derek too | 3.15 |\n" +
|
||||||
|
"+-----------------+-----------------------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
|
||||||
|
table.AddTitle("Example... to Fix My Test")
|
||||||
|
table.AddRow("hey foo bar baz", "you")
|
||||||
|
table.AddRow("ken", "you should write code")
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
|
||||||
|
output := table.Render()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatal(DisplayFailedOutput(output, expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableWidthHandling_SecondErrorCondition(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+----------------------------------------+\n" +
|
||||||
|
"| Example... to Fix My Test |\n" +
|
||||||
|
"+-----------------+----------------------+\n" +
|
||||||
|
"| hey foo bar baz | you |\n" +
|
||||||
|
"| ken | you should sell cod! |\n" +
|
||||||
|
"| derek | 3.14 |\n" +
|
||||||
|
"| derek too | 3.15 |\n" +
|
||||||
|
"+-----------------+----------------------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
|
||||||
|
table.AddTitle("Example... to Fix My Test")
|
||||||
|
table.AddRow("hey foo bar baz", "you")
|
||||||
|
table.AddRow("ken", "you should sell cod!")
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
|
||||||
|
output := table.Render()
|
||||||
|
if output != expected {
|
||||||
|
t.Fatal(DisplayFailedOutput(output, expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableAlignPostsetting(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+-----------+-------+\n" +
|
||||||
|
"| Name | Value |\n" +
|
||||||
|
"+-----------+-------+\n" +
|
||||||
|
"| hey | you |\n" +
|
||||||
|
"| ken | 1234 |\n" +
|
||||||
|
"| derek | 3.14 |\n" +
|
||||||
|
"| derek too | 3.15 |\n" +
|
||||||
|
"| escaping | rox%% |\n" +
|
||||||
|
"+-----------+-------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
|
||||||
|
table.AddHeaders("Name", "Value")
|
||||||
|
table.AddRow("hey", "you")
|
||||||
|
table.AddRow("ken", 1234)
|
||||||
|
table.AddRow("derek", 3.14)
|
||||||
|
table.AddRow("derek too", 3.1456788)
|
||||||
|
table.AddRow("escaping", "rox%%")
|
||||||
|
|
||||||
|
table.SetAlign(AlignRight, 1)
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableMissingCells(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+----------+---------+---------+\n" +
|
||||||
|
"| Name | Value 1 | Value 2 |\n" +
|
||||||
|
"+----------+---------+---------+\n" +
|
||||||
|
"| hey | you | person |\n" +
|
||||||
|
"| ken | 1234 |\n" +
|
||||||
|
"| escaping | rox%s%% |\n" +
|
||||||
|
"+----------+---------+---------+\n"
|
||||||
|
// FIXME: missing extra cells there
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
|
||||||
|
table.AddHeaders("Name", "Value 1", "Value 2")
|
||||||
|
table.AddRow("hey", "you", "person")
|
||||||
|
table.AddRow("ken", 1234)
|
||||||
|
table.AddRow("escaping", "rox%s%%")
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't yet support combining characters, double-width characters or
|
||||||
|
// anything to do with estimating a tty-style "character width" for what in
|
||||||
|
// Unicode is a grapheme cluster. This disabled test shows what we want
|
||||||
|
// to support, but don't yet.
|
||||||
|
func TestTableWithCombiningChars(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+------+---+\n" +
|
||||||
|
"| noel | 1 |\n" +
|
||||||
|
"| noël | 2 |\n" +
|
||||||
|
"| noël | 3 |\n" +
|
||||||
|
"+------+---+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
|
||||||
|
table.AddRow("noel", "1")
|
||||||
|
table.AddRow("noe\u0308l", "2") // LATIN SMALL LETTER E + COMBINING DIAERESIS
|
||||||
|
table.AddRow("noël", "3") // Hex EB; LATIN SMALL LETTER E WITH DIAERESIS
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
// another unicode length issue
|
||||||
|
func TestTableWithFullwidthChars(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+----------+------------+\n" +
|
||||||
|
"| wide | not really |\n" +
|
||||||
|
"| wide | fullwidth |\n" +
|
||||||
|
"+----------+------------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.AddRow("wide", "not really")
|
||||||
|
table.AddRow("wide", "fullwidth") // FULLWIDTH LATIN SMALL LETTER <X>
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests CJK characters using examples given in issue #33. The examples may not
|
||||||
|
// look like they line up but you can visually confirm its accuracy with a
|
||||||
|
// fmt.Print.
|
||||||
|
func TestCJKChars(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+-------+---------+----------+\n" +
|
||||||
|
"| KeyID | ValueID | ValueCN |\n" +
|
||||||
|
"+-------+---------+----------+\n" +
|
||||||
|
"| 8 | 51 | 精钢 |\n" +
|
||||||
|
"| 8 | 52 | 鳄鱼皮 |\n" +
|
||||||
|
"| 8 | 53 | 镀金皮带 |\n" +
|
||||||
|
"| 8 | 54 | 精钢 |\n" +
|
||||||
|
"+-------+---------+----------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.AddHeaders("KeyID", "ValueID", "ValueCN")
|
||||||
|
table.AddRow("8", 51, "精钢")
|
||||||
|
table.AddRow("8", 52, "鳄鱼皮")
|
||||||
|
table.AddRow("8", 53, "镀金皮带")
|
||||||
|
table.AddRow("8", 54, "精钢")
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
|
||||||
|
expected2 := "" +
|
||||||
|
"+--------------------+----------------------+\n" +
|
||||||
|
"| field | value |\n" +
|
||||||
|
"+--------------------+----------------------+\n" +
|
||||||
|
"| GoodsPropertyKeyID | 9 |\n" +
|
||||||
|
"| MerchantAccountID | 0 |\n" +
|
||||||
|
"| GoodsCategoryCode | 100001 |\n" +
|
||||||
|
"| NameCN | 机芯类型 |\n" +
|
||||||
|
"| NameJP | ムーブメントのタイプ |\n" +
|
||||||
|
"+--------------------+----------------------+\n"
|
||||||
|
table = CreateTable()
|
||||||
|
table.AddHeaders("field", "value")
|
||||||
|
table.AddRow("GoodsPropertyKeyID", 9)
|
||||||
|
table.AddRow("MerchantAccountID", 0)
|
||||||
|
table.AddRow("GoodsCategoryCode", 100001)
|
||||||
|
table.AddRow("NameCN", "机芯类型")
|
||||||
|
table.AddRow("NameJP", "ムーブメントのタイプ")
|
||||||
|
checkRendersTo(t, table, expected2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTableMultipleAddHeader(t *testing.T) {
|
||||||
|
expected := "" +
|
||||||
|
"+--------------+--------+-------+\n" +
|
||||||
|
"| First column | Second | Third |\n" +
|
||||||
|
"+--------------+--------+-------+\n" +
|
||||||
|
"| 2 | 3 | 5 |\n" +
|
||||||
|
"+--------------+--------+-------+\n"
|
||||||
|
|
||||||
|
table := CreateTable()
|
||||||
|
table.AddHeaders("First column", "Second")
|
||||||
|
table.AddHeaders("Third")
|
||||||
|
table.AddRow(2, 3, 5)
|
||||||
|
|
||||||
|
checkRendersTo(t, table, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTestTable() *Table {
|
||||||
|
table := CreateTable()
|
||||||
|
header := []interface{}{}
|
||||||
|
for i := 0; i < 50; i++ {
|
||||||
|
header = append(header, "First Column")
|
||||||
|
}
|
||||||
|
table.AddHeaders(header...)
|
||||||
|
for i := 0; i < 3000; i++ {
|
||||||
|
row := []interface{}{}
|
||||||
|
for i := 0; i < 50; i++ {
|
||||||
|
row = append(row, "First row value")
|
||||||
|
}
|
||||||
|
table.AddRow(row...)
|
||||||
|
}
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkTableRenderTerminal(b *testing.B) {
|
||||||
|
table := createTestTable()
|
||||||
|
table.SetModeTerminal()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
table.Render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkTableRenderMarkdown(b *testing.B) {
|
||||||
|
table := createTestTable()
|
||||||
|
table.SetModeMarkdown()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
table.Render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkTableRenderHTML(b *testing.B) {
|
||||||
|
table := createTestTable()
|
||||||
|
table.SetModeHTML()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
table.Render()
|
||||||
|
}
|
||||||
|
}
|
43
dateparse/vendor/github.com/apcera/termtables/term/env.go
generated
vendored
Normal file
43
dateparse/vendor/github.com/apcera/termtables/term/env.go
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2013 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
package term
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetEnvWindowSize returns the window Size, as determined by process
|
||||||
|
// environment; if either LINES or COLUMNS is present, and whichever is
|
||||||
|
// present is also numeric, the Size will be non-nil. If Size is nil,
|
||||||
|
// there's insufficient data in environ. If one entry is 0, that means
|
||||||
|
// that the environment does not include that data. If a value is
|
||||||
|
// negative, we treat that as an error.
|
||||||
|
func GetEnvWindowSize() *Size {
|
||||||
|
lines := os.Getenv("LINES")
|
||||||
|
columns := os.Getenv("COLUMNS")
|
||||||
|
if lines == "" && columns == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
nLines := 0
|
||||||
|
nColumns := 0
|
||||||
|
var err error
|
||||||
|
if lines != "" {
|
||||||
|
nLines, err = strconv.Atoi(lines)
|
||||||
|
if err != nil || nLines < 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if columns != "" {
|
||||||
|
nColumns, err = strconv.Atoi(columns)
|
||||||
|
if err != nil || nColumns < 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Size{
|
||||||
|
Lines: nLines,
|
||||||
|
Columns: nColumns,
|
||||||
|
}
|
||||||
|
}
|
54
dateparse/vendor/github.com/apcera/termtables/term/getsize.go
generated
vendored
Normal file
54
dateparse/vendor/github.com/apcera/termtables/term/getsize.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2013 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
package term
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Size is the size of a terminal, expressed in character cells, as Lines and
|
||||||
|
// Columns. This might come from environment variables or OS-dependent
|
||||||
|
// resources.
|
||||||
|
type Size struct {
|
||||||
|
Lines int
|
||||||
|
Columns int
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSize will return the terminal window size.
|
||||||
|
//
|
||||||
|
// We prefer environ $LINES/$COLUMNS, then fall back to tty-held information.
|
||||||
|
// We do not support use of termcap/terminfo to derive default size information.
|
||||||
|
func GetSize() (*Size, error) {
|
||||||
|
envSize := GetEnvWindowSize()
|
||||||
|
if envSize != nil && envSize.Lines != 0 && envSize.Columns != 0 {
|
||||||
|
return envSize, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fh, err := os.Open("/dev/tty")
|
||||||
|
if err != nil {
|
||||||
|
// no tty, no point continuing; we only let the environ
|
||||||
|
// avoid an error in this case because if someone has faked
|
||||||
|
// up an environ with LINES/COLUMNS _both_ set, we should let
|
||||||
|
// them
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
size, err := GetTerminalWindowSize(fh)
|
||||||
|
if err != nil {
|
||||||
|
if envSize != nil {
|
||||||
|
return envSize, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if envSize == nil {
|
||||||
|
return size, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if envSize.Lines == 0 {
|
||||||
|
envSize.Lines = size.Lines
|
||||||
|
}
|
||||||
|
if envSize.Columns == 0 {
|
||||||
|
envSize.Columns = size.Columns
|
||||||
|
}
|
||||||
|
return envSize, nil
|
||||||
|
}
|
35
dateparse/vendor/github.com/apcera/termtables/term/sizes_unix.go
generated
vendored
Normal file
35
dateparse/vendor/github.com/apcera/termtables/term/sizes_unix.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2013 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package term
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrGetWinsizeFailed indicates that the system call to extract the size of
|
||||||
|
// a Unix tty from the kernel failed.
|
||||||
|
var ErrGetWinsizeFailed = errors.New("term: syscall.TIOCGWINSZ failed")
|
||||||
|
|
||||||
|
// GetTerminalWindowSize returns the terminal size maintained by the kernel
|
||||||
|
// for a Unix TTY, passed in as an *os.File. This information can be seen
|
||||||
|
// with the stty(1) command, and changes in size (eg, terminal emulator
|
||||||
|
// resized) should trigger a SIGWINCH signal delivery to the foreground process
|
||||||
|
// group at the time of the change, so a long-running process might reasonably
|
||||||
|
// watch for SIGWINCH and arrange to re-fetch the size when that happens.
|
||||||
|
func GetTerminalWindowSize(file *os.File) (*Size, error) {
|
||||||
|
// Based on source from from golang.org/x/crypto/ssh/terminal/util.go
|
||||||
|
var dimensions [4]uint16
|
||||||
|
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, file.Fd(), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Size{
|
||||||
|
Lines: int(dimensions[0]),
|
||||||
|
Columns: int(dimensions[1]),
|
||||||
|
}, nil
|
||||||
|
}
|
57
dateparse/vendor/github.com/apcera/termtables/term/sizes_windows.go
generated
vendored
Normal file
57
dateparse/vendor/github.com/apcera/termtables/term/sizes_windows.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2013 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package term
|
||||||
|
|
||||||
|
// Used when we have no other source for getting platform-specific information
|
||||||
|
// about the terminal sizes available.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Based on source from from golang.org/x/crypto/ssh/terminal/util_windows.go
|
||||||
|
var (
|
||||||
|
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
|
||||||
|
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
short int16
|
||||||
|
word uint16
|
||||||
|
|
||||||
|
coord struct {
|
||||||
|
x short
|
||||||
|
y short
|
||||||
|
}
|
||||||
|
smallRect struct {
|
||||||
|
left short
|
||||||
|
top short
|
||||||
|
right short
|
||||||
|
bottom short
|
||||||
|
}
|
||||||
|
consoleScreenBufferInfo struct {
|
||||||
|
size coord
|
||||||
|
cursorPosition coord
|
||||||
|
attributes word
|
||||||
|
window smallRect
|
||||||
|
maximumWindowSize coord
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetTerminalWindowSize returns the width and height of a terminal in Windows.
|
||||||
|
func GetTerminalWindowSize(file *os.File) (*Size, error) {
|
||||||
|
var info consoleScreenBufferInfo
|
||||||
|
_, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, file.Fd(), uintptr(unsafe.Pointer(&info)), 0)
|
||||||
|
if e != 0 {
|
||||||
|
return nil, error(e)
|
||||||
|
}
|
||||||
|
return &Size{
|
||||||
|
Lines: int(info.size.y),
|
||||||
|
Columns: int(info.size.x),
|
||||||
|
}, nil
|
||||||
|
}
|
22
dateparse/vendor/github.com/apcera/termtables/term/wrapper.go
generated
vendored
Normal file
22
dateparse/vendor/github.com/apcera/termtables/term/wrapper.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2013 Apcera Inc. All rights reserved.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/apcera/termtables/term"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
size, err := term.GetSize()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "failed: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Lines %d Columns %d\n", size.Lines, size.Columns)
|
||||||
|
}
|
21
dateparse/vendor/github.com/apcera/termtables/vendor/github.com/mattn/go-runewidth/LICENSE
generated
vendored
Normal file
21
dateparse/vendor/github.com/apcera/termtables/vendor/github.com/mattn/go-runewidth/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Yasuhiro Matsumoto
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
1223
dateparse/vendor/github.com/apcera/termtables/vendor/github.com/mattn/go-runewidth/runewidth.go
generated
vendored
Normal file
1223
dateparse/vendor/github.com/apcera/termtables/vendor/github.com/mattn/go-runewidth/runewidth.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8
dateparse/vendor/github.com/apcera/termtables/vendor/github.com/mattn/go-runewidth/runewidth_js.go
generated
vendored
Normal file
8
dateparse/vendor/github.com/apcera/termtables/vendor/github.com/mattn/go-runewidth/runewidth_js.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// +build js
|
||||||
|
|
||||||
|
package runewidth
|
||||||
|
|
||||||
|
func IsEastAsian() bool {
|
||||||
|
// TODO: Implement this for the web. Detect east asian in a compatible way, and return true.
|
||||||
|
return false
|
||||||
|
}
|
77
dateparse/vendor/github.com/apcera/termtables/vendor/github.com/mattn/go-runewidth/runewidth_posix.go
generated
vendored
Normal file
77
dateparse/vendor/github.com/apcera/termtables/vendor/github.com/mattn/go-runewidth/runewidth_posix.go
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// +build !windows,!js
|
||||||
|
|
||||||
|
package runewidth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`)
|
||||||
|
|
||||||
|
var mblenTable = map[string]int{
|
||||||
|
"utf-8": 6,
|
||||||
|
"utf8": 6,
|
||||||
|
"jis": 8,
|
||||||
|
"eucjp": 3,
|
||||||
|
"euckr": 2,
|
||||||
|
"euccn": 2,
|
||||||
|
"sjis": 2,
|
||||||
|
"cp932": 2,
|
||||||
|
"cp51932": 2,
|
||||||
|
"cp936": 2,
|
||||||
|
"cp949": 2,
|
||||||
|
"cp950": 2,
|
||||||
|
"big5": 2,
|
||||||
|
"gbk": 2,
|
||||||
|
"gb2312": 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEastAsian(locale string) bool {
|
||||||
|
charset := strings.ToLower(locale)
|
||||||
|
r := reLoc.FindStringSubmatch(locale)
|
||||||
|
if len(r) == 2 {
|
||||||
|
charset = strings.ToLower(r[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasSuffix(charset, "@cjk_narrow") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for pos, b := range []byte(charset) {
|
||||||
|
if b == '@' {
|
||||||
|
charset = charset[:pos]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max := 1
|
||||||
|
if m, ok := mblenTable[charset]; ok {
|
||||||
|
max = m
|
||||||
|
}
|
||||||
|
if max > 1 && (charset[0] != 'u' ||
|
||||||
|
strings.HasPrefix(locale, "ja") ||
|
||||||
|
strings.HasPrefix(locale, "ko") ||
|
||||||
|
strings.HasPrefix(locale, "zh")) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEastAsian return true if the current locale is CJK
|
||||||
|
func IsEastAsian() bool {
|
||||||
|
locale := os.Getenv("LC_CTYPE")
|
||||||
|
if locale == "" {
|
||||||
|
locale = os.Getenv("LANG")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore C locale
|
||||||
|
if locale == "POSIX" || locale == "C" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(locale) > 1 && locale[0] == 'C' && (locale[1] == '.' || locale[1] == '-') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return isEastAsian(locale)
|
||||||
|
}
|
25
dateparse/vendor/github.com/apcera/termtables/vendor/github.com/mattn/go-runewidth/runewidth_windows.go
generated
vendored
Normal file
25
dateparse/vendor/github.com/apcera/termtables/vendor/github.com/mattn/go-runewidth/runewidth_windows.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package runewidth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernel32 = syscall.NewLazyDLL("kernel32")
|
||||||
|
procGetConsoleOutputCP = kernel32.NewProc("GetConsoleOutputCP")
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsEastAsian return true if the current locale is CJK
|
||||||
|
func IsEastAsian() bool {
|
||||||
|
r1, _, _ := procGetConsoleOutputCP.Call()
|
||||||
|
if r1 == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch int(r1) {
|
||||||
|
case 932, 51932, 936, 949, 950:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
13
dateparse/vendor/github.com/apcera/termtables/vendor/manifest
generated
vendored
Normal file
13
dateparse/vendor/github.com/apcera/termtables/vendor/manifest
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"version": 0,
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"importpath": "github.com/mattn/go-runewidth",
|
||||||
|
"repository": "https://github.com/mattn/go-runewidth",
|
||||||
|
"vcs": "git",
|
||||||
|
"revision": "14207d285c6c197daabb5c9793d63e7af9ab2d50",
|
||||||
|
"branch": "master",
|
||||||
|
"notests": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1734,6 +1734,8 @@ type parser struct {
|
|||||||
t *time.Time
|
t *time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParserOption defines a function signature implemented by options
|
||||||
|
// Options defined like this accept the parser and operate on the data within
|
||||||
type ParserOption func(*parser) error
|
type ParserOption func(*parser) error
|
||||||
|
|
||||||
// PreferMonthFirst is an option that allows preferMonthFirst to be changed from its default
|
// PreferMonthFirst is an option that allows preferMonthFirst to be changed from its default
|
||||||
|
Loading…
Reference in New Issue
Block a user