Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
2.6 KiB
99 lines
2.6 KiB
// Copyright 2014 Oleku Konko All rights reserved. |
|
// Use of this source code is governed by a MIT |
|
// license that can be found in the LICENSE file. |
|
|
|
// This module is a Table Writer API for the Go Programming Language. |
|
// The protocols were written in pure Go and works on windows and unix systems |
|
|
|
package tablewriter |
|
|
|
import ( |
|
"math" |
|
"strings" |
|
|
|
"github.com/mattn/go-runewidth" |
|
) |
|
|
|
var ( |
|
nl = "\n" |
|
sp = " " |
|
) |
|
|
|
const defaultPenalty = 1e5 |
|
|
|
// Wrap wraps s into a paragraph of lines of length lim, with minimal |
|
// raggedness. |
|
func WrapString(s string, lim int) ([]string, int) { |
|
words := strings.Split(strings.Replace(s, nl, sp, -1), sp) |
|
var lines []string |
|
max := 0 |
|
for _, v := range words { |
|
max = runewidth.StringWidth(v) |
|
if max > lim { |
|
lim = max |
|
} |
|
} |
|
for _, line := range WrapWords(words, 1, lim, defaultPenalty) { |
|
lines = append(lines, strings.Join(line, sp)) |
|
} |
|
return lines, lim |
|
} |
|
|
|
// WrapWords is the low-level line-breaking algorithm, useful if you need more |
|
// control over the details of the text wrapping process. For most uses, |
|
// WrapString will be sufficient and more convenient. |
|
// |
|
// WrapWords splits a list of words into lines with minimal "raggedness", |
|
// treating each rune as one unit, accounting for spc units between adjacent |
|
// words on each line, and attempting to limit lines to lim units. Raggedness |
|
// is the total error over all lines, where error is the square of the |
|
// difference of the length of the line and lim. Too-long lines (which only |
|
// happen when a single word is longer than lim units) have pen penalty units |
|
// added to the error. |
|
func WrapWords(words []string, spc, lim, pen int) [][]string { |
|
n := len(words) |
|
|
|
length := make([][]int, n) |
|
for i := 0; i < n; i++ { |
|
length[i] = make([]int, n) |
|
length[i][i] = runewidth.StringWidth(words[i]) |
|
for j := i + 1; j < n; j++ { |
|
length[i][j] = length[i][j-1] + spc + runewidth.StringWidth(words[j]) |
|
} |
|
} |
|
nbrk := make([]int, n) |
|
cost := make([]int, n) |
|
for i := range cost { |
|
cost[i] = math.MaxInt32 |
|
} |
|
for i := n - 1; i >= 0; i-- { |
|
if length[i][n-1] <= lim { |
|
cost[i] = 0 |
|
nbrk[i] = n |
|
} else { |
|
for j := i + 1; j < n; j++ { |
|
d := lim - length[i][j-1] |
|
c := d*d + cost[j] |
|
if length[i][j-1] > lim { |
|
c += pen // too-long lines get a worse penalty |
|
} |
|
if c < cost[i] { |
|
cost[i] = c |
|
nbrk[i] = j |
|
} |
|
} |
|
} |
|
} |
|
var lines [][]string |
|
i := 0 |
|
for i < n { |
|
lines = append(lines, words[i:nbrk[i]]) |
|
i = nbrk[i] |
|
} |
|
return lines |
|
} |
|
|
|
// getLines decomposes a multiline string into a slice of strings. |
|
func getLines(s string) []string { |
|
return strings.Split(s, nl) |
|
}
|
|
|