Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

pretty.go 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. package pretty
  2. import (
  3. "sort"
  4. )
  5. // Options is Pretty options
  6. type Options struct {
  7. // Width is an max column width for single line arrays
  8. // Default is 80
  9. Width int
  10. // Prefix is a prefix for all lines
  11. // Default is an empty string
  12. Prefix string
  13. // Indent is the nested indentation
  14. // Default is two spaces
  15. Indent string
  16. // SortKeys will sort the keys alphabetically
  17. // Default is false
  18. SortKeys bool
  19. }
  20. // DefaultOptions is the default options for pretty formats.
  21. var DefaultOptions = &Options{Width: 80, Prefix: "", Indent: " ", SortKeys: false}
  22. // Pretty converts the input json into a more human readable format where each
  23. // element is on it's own line with clear indentation.
  24. func Pretty(json []byte) []byte { return PrettyOptions(json, nil) }
  25. // PrettyOptions is like Pretty but with customized options.
  26. func PrettyOptions(json []byte, opts *Options) []byte {
  27. if opts == nil {
  28. opts = DefaultOptions
  29. }
  30. buf := make([]byte, 0, len(json))
  31. if len(opts.Prefix) != 0 {
  32. buf = append(buf, opts.Prefix...)
  33. }
  34. buf, _, _, _ = appendPrettyAny(buf, json, 0, true,
  35. opts.Width, opts.Prefix, opts.Indent, opts.SortKeys,
  36. 0, 0, -1)
  37. if len(buf) > 0 {
  38. buf = append(buf, '\n')
  39. }
  40. return buf
  41. }
  42. // Ugly removes insignificant space characters from the input json byte slice
  43. // and returns the compacted result.
  44. func Ugly(json []byte) []byte {
  45. buf := make([]byte, 0, len(json))
  46. return ugly(buf, json)
  47. }
  48. // UglyInPlace removes insignificant space characters from the input json
  49. // byte slice and returns the compacted result. This method reuses the
  50. // input json buffer to avoid allocations. Do not use the original bytes
  51. // slice upon return.
  52. func UglyInPlace(json []byte) []byte { return ugly(json, json) }
  53. func ugly(dst, src []byte) []byte {
  54. dst = dst[:0]
  55. for i := 0; i < len(src); i++ {
  56. if src[i] > ' ' {
  57. dst = append(dst, src[i])
  58. if src[i] == '"' {
  59. for i = i + 1; i < len(src); i++ {
  60. dst = append(dst, src[i])
  61. if src[i] == '"' {
  62. j := i - 1
  63. for ; ; j-- {
  64. if src[j] != '\\' {
  65. break
  66. }
  67. }
  68. if (j-i)%2 != 0 {
  69. break
  70. }
  71. }
  72. }
  73. }
  74. }
  75. }
  76. return dst
  77. }
  78. func appendPrettyAny(buf, json []byte, i int, pretty bool, width int, prefix, indent string, sortkeys bool, tabs, nl, max int) ([]byte, int, int, bool) {
  79. for ; i < len(json); i++ {
  80. if json[i] <= ' ' {
  81. continue
  82. }
  83. if json[i] == '"' {
  84. return appendPrettyString(buf, json, i, nl)
  85. }
  86. if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' {
  87. return appendPrettyNumber(buf, json, i, nl)
  88. }
  89. if json[i] == '{' {
  90. return appendPrettyObject(buf, json, i, '{', '}', pretty, width, prefix, indent, sortkeys, tabs, nl, max)
  91. }
  92. if json[i] == '[' {
  93. return appendPrettyObject(buf, json, i, '[', ']', pretty, width, prefix, indent, sortkeys, tabs, nl, max)
  94. }
  95. switch json[i] {
  96. case 't':
  97. return append(buf, 't', 'r', 'u', 'e'), i + 4, nl, true
  98. case 'f':
  99. return append(buf, 'f', 'a', 'l', 's', 'e'), i + 5, nl, true
  100. case 'n':
  101. return append(buf, 'n', 'u', 'l', 'l'), i + 4, nl, true
  102. }
  103. }
  104. return buf, i, nl, true
  105. }
  106. type pair struct {
  107. kstart, kend int
  108. vstart, vend int
  109. }
  110. type byKeyVal struct {
  111. sorted bool
  112. json []byte
  113. pairs []pair
  114. }
  115. func (arr *byKeyVal) Len() int {
  116. return len(arr.pairs)
  117. }
  118. func (arr *byKeyVal) Less(i, j int) bool {
  119. key1 := arr.json[arr.pairs[i].kstart+1 : arr.pairs[i].kend-1]
  120. key2 := arr.json[arr.pairs[j].kstart+1 : arr.pairs[j].kend-1]
  121. if string(key1) < string(key2) {
  122. return true
  123. }
  124. if string(key1) > string(key2) {
  125. return false
  126. }
  127. return arr.pairs[i].vstart < arr.pairs[j].vstart
  128. }
  129. func (arr *byKeyVal) Swap(i, j int) {
  130. arr.pairs[i], arr.pairs[j] = arr.pairs[j], arr.pairs[i]
  131. arr.sorted = true
  132. }
  133. func appendPrettyObject(buf, json []byte, i int, open, close byte, pretty bool, width int, prefix, indent string, sortkeys bool, tabs, nl, max int) ([]byte, int, int, bool) {
  134. var ok bool
  135. if width > 0 {
  136. if pretty && open == '[' && max == -1 {
  137. // here we try to create a single line array
  138. max := width - (len(buf) - nl)
  139. if max > 3 {
  140. s1, s2 := len(buf), i
  141. buf, i, _, ok = appendPrettyObject(buf, json, i, '[', ']', false, width, prefix, "", sortkeys, 0, 0, max)
  142. if ok && len(buf)-s1 <= max {
  143. return buf, i, nl, true
  144. }
  145. buf = buf[:s1]
  146. i = s2
  147. }
  148. } else if max != -1 && open == '{' {
  149. return buf, i, nl, false
  150. }
  151. }
  152. buf = append(buf, open)
  153. i++
  154. var pairs []pair
  155. if open == '{' && sortkeys {
  156. pairs = make([]pair, 0, 8)
  157. }
  158. var n int
  159. for ; i < len(json); i++ {
  160. if json[i] <= ' ' {
  161. continue
  162. }
  163. if json[i] == close {
  164. if pretty {
  165. if open == '{' && sortkeys {
  166. buf = sortPairs(json, buf, pairs)
  167. }
  168. if n > 0 {
  169. nl = len(buf)
  170. if buf[nl-1] == ' ' {
  171. buf[nl-1] = '\n'
  172. } else {
  173. buf = append(buf, '\n')
  174. }
  175. }
  176. if buf[len(buf)-1] != open {
  177. buf = appendTabs(buf, prefix, indent, tabs)
  178. }
  179. }
  180. buf = append(buf, close)
  181. return buf, i + 1, nl, open != '{'
  182. }
  183. if open == '[' || json[i] == '"' {
  184. if n > 0 {
  185. buf = append(buf, ',')
  186. if width != -1 && open == '[' {
  187. buf = append(buf, ' ')
  188. }
  189. }
  190. var p pair
  191. if pretty {
  192. nl = len(buf)
  193. if buf[nl-1] == ' ' {
  194. buf[nl-1] = '\n'
  195. } else {
  196. buf = append(buf, '\n')
  197. }
  198. if open == '{' && sortkeys {
  199. p.kstart = i
  200. p.vstart = len(buf)
  201. }
  202. buf = appendTabs(buf, prefix, indent, tabs+1)
  203. }
  204. if open == '{' {
  205. buf, i, nl, _ = appendPrettyString(buf, json, i, nl)
  206. if sortkeys {
  207. p.kend = i
  208. }
  209. buf = append(buf, ':')
  210. if pretty {
  211. buf = append(buf, ' ')
  212. }
  213. }
  214. buf, i, nl, ok = appendPrettyAny(buf, json, i, pretty, width, prefix, indent, sortkeys, tabs+1, nl, max)
  215. if max != -1 && !ok {
  216. return buf, i, nl, false
  217. }
  218. if pretty && open == '{' && sortkeys {
  219. p.vend = len(buf)
  220. if p.kstart > p.kend || p.vstart > p.vend {
  221. // bad data. disable sorting
  222. sortkeys = false
  223. } else {
  224. pairs = append(pairs, p)
  225. }
  226. }
  227. i--
  228. n++
  229. }
  230. }
  231. return buf, i, nl, open != '{'
  232. }
  233. func sortPairs(json, buf []byte, pairs []pair) []byte {
  234. if len(pairs) == 0 {
  235. return buf
  236. }
  237. vstart := pairs[0].vstart
  238. vend := pairs[len(pairs)-1].vend
  239. arr := byKeyVal{false, json, pairs}
  240. sort.Stable(&arr)
  241. if !arr.sorted {
  242. return buf
  243. }
  244. nbuf := make([]byte, 0, vend-vstart)
  245. for i, p := range pairs {
  246. nbuf = append(nbuf, buf[p.vstart:p.vend]...)
  247. if i < len(pairs)-1 {
  248. nbuf = append(nbuf, ',')
  249. nbuf = append(nbuf, '\n')
  250. }
  251. }
  252. return append(buf[:vstart], nbuf...)
  253. }
  254. func appendPrettyString(buf, json []byte, i, nl int) ([]byte, int, int, bool) {
  255. s := i
  256. i++
  257. for ; i < len(json); i++ {
  258. if json[i] == '"' {
  259. var sc int
  260. for j := i - 1; j > s; j-- {
  261. if json[j] == '\\' {
  262. sc++
  263. } else {
  264. break
  265. }
  266. }
  267. if sc%2 == 1 {
  268. continue
  269. }
  270. i++
  271. break
  272. }
  273. }
  274. return append(buf, json[s:i]...), i, nl, true
  275. }
  276. func appendPrettyNumber(buf, json []byte, i, nl int) ([]byte, int, int, bool) {
  277. s := i
  278. i++
  279. for ; i < len(json); i++ {
  280. if json[i] <= ' ' || json[i] == ',' || json[i] == ':' || json[i] == ']' || json[i] == '}' {
  281. break
  282. }
  283. }
  284. return append(buf, json[s:i]...), i, nl, true
  285. }
  286. func appendTabs(buf []byte, prefix, indent string, tabs int) []byte {
  287. if len(prefix) != 0 {
  288. buf = append(buf, prefix...)
  289. }
  290. if len(indent) == 2 && indent[0] == ' ' && indent[1] == ' ' {
  291. for i := 0; i < tabs; i++ {
  292. buf = append(buf, ' ', ' ')
  293. }
  294. } else {
  295. for i := 0; i < tabs; i++ {
  296. buf = append(buf, indent...)
  297. }
  298. }
  299. return buf
  300. }
  301. // Style is the color style
  302. type Style struct {
  303. Key, String, Number [2]string
  304. True, False, Null [2]string
  305. Escape [2]string
  306. Append func(dst []byte, c byte) []byte
  307. }
  308. func hexp(p byte) byte {
  309. switch {
  310. case p < 10:
  311. return p + '0'
  312. default:
  313. return (p - 10) + 'a'
  314. }
  315. }
  316. // TerminalStyle is for terminals
  317. var TerminalStyle *Style
  318. func init() {
  319. TerminalStyle = &Style{
  320. Key: [2]string{"\x1B[94m", "\x1B[0m"},
  321. String: [2]string{"\x1B[92m", "\x1B[0m"},
  322. Number: [2]string{"\x1B[93m", "\x1B[0m"},
  323. True: [2]string{"\x1B[96m", "\x1B[0m"},
  324. False: [2]string{"\x1B[96m", "\x1B[0m"},
  325. Null: [2]string{"\x1B[91m", "\x1B[0m"},
  326. Escape: [2]string{"\x1B[35m", "\x1B[0m"},
  327. Append: func(dst []byte, c byte) []byte {
  328. if c < ' ' && (c != '\r' && c != '\n' && c != '\t' && c != '\v') {
  329. dst = append(dst, "\\u00"...)
  330. dst = append(dst, hexp((c>>4)&0xF))
  331. return append(dst, hexp((c)&0xF))
  332. }
  333. return append(dst, c)
  334. },
  335. }
  336. }
  337. // Color will colorize the json. The style parma is used for customizing
  338. // the colors. Passing nil to the style param will use the default
  339. // TerminalStyle.
  340. func Color(src []byte, style *Style) []byte {
  341. if style == nil {
  342. style = TerminalStyle
  343. }
  344. apnd := style.Append
  345. if apnd == nil {
  346. apnd = func(dst []byte, c byte) []byte {
  347. return append(dst, c)
  348. }
  349. }
  350. type stackt struct {
  351. kind byte
  352. key bool
  353. }
  354. var dst []byte
  355. var stack []stackt
  356. for i := 0; i < len(src); i++ {
  357. if src[i] == '"' {
  358. key := len(stack) > 0 && stack[len(stack)-1].key
  359. if key {
  360. dst = append(dst, style.Key[0]...)
  361. } else {
  362. dst = append(dst, style.String[0]...)
  363. }
  364. dst = apnd(dst, '"')
  365. esc := false
  366. uesc := 0
  367. for i = i + 1; i < len(src); i++ {
  368. if src[i] == '\\' {
  369. if key {
  370. dst = append(dst, style.Key[1]...)
  371. } else {
  372. dst = append(dst, style.String[1]...)
  373. }
  374. dst = append(dst, style.Escape[0]...)
  375. dst = apnd(dst, src[i])
  376. esc = true
  377. if i+1 < len(src) && src[i+1] == 'u' {
  378. uesc = 5
  379. } else {
  380. uesc = 1
  381. }
  382. } else if esc {
  383. dst = apnd(dst, src[i])
  384. if uesc == 1 {
  385. esc = false
  386. dst = append(dst, style.Escape[1]...)
  387. if key {
  388. dst = append(dst, style.Key[0]...)
  389. } else {
  390. dst = append(dst, style.String[0]...)
  391. }
  392. } else {
  393. uesc--
  394. }
  395. } else {
  396. dst = apnd(dst, src[i])
  397. }
  398. if src[i] == '"' {
  399. j := i - 1
  400. for ; ; j-- {
  401. if src[j] != '\\' {
  402. break
  403. }
  404. }
  405. if (j-i)%2 != 0 {
  406. break
  407. }
  408. }
  409. }
  410. if esc {
  411. dst = append(dst, style.Escape[1]...)
  412. } else if key {
  413. dst = append(dst, style.Key[1]...)
  414. } else {
  415. dst = append(dst, style.String[1]...)
  416. }
  417. } else if src[i] == '{' || src[i] == '[' {
  418. stack = append(stack, stackt{src[i], src[i] == '{'})
  419. dst = apnd(dst, src[i])
  420. } else if (src[i] == '}' || src[i] == ']') && len(stack) > 0 {
  421. stack = stack[:len(stack)-1]
  422. dst = apnd(dst, src[i])
  423. } else if (src[i] == ':' || src[i] == ',') && len(stack) > 0 && stack[len(stack)-1].kind == '{' {
  424. stack[len(stack)-1].key = !stack[len(stack)-1].key
  425. dst = apnd(dst, src[i])
  426. } else {
  427. var kind byte
  428. if (src[i] >= '0' && src[i] <= '9') || src[i] == '-' {
  429. kind = '0'
  430. dst = append(dst, style.Number[0]...)
  431. } else if src[i] == 't' {
  432. kind = 't'
  433. dst = append(dst, style.True[0]...)
  434. } else if src[i] == 'f' {
  435. kind = 'f'
  436. dst = append(dst, style.False[0]...)
  437. } else if src[i] == 'n' {
  438. kind = 'n'
  439. dst = append(dst, style.Null[0]...)
  440. } else {
  441. dst = apnd(dst, src[i])
  442. }
  443. if kind != 0 {
  444. for ; i < len(src); i++ {
  445. if src[i] <= ' ' || src[i] == ',' || src[i] == ':' || src[i] == ']' || src[i] == '}' {
  446. i--
  447. break
  448. }
  449. dst = apnd(dst, src[i])
  450. }
  451. if kind == '0' {
  452. dst = append(dst, style.Number[1]...)
  453. } else if kind == 't' {
  454. dst = append(dst, style.True[1]...)
  455. } else if kind == 'f' {
  456. dst = append(dst, style.False[1]...)
  457. } else if kind == 'n' {
  458. dst = append(dst, style.Null[1]...)
  459. }
  460. }
  461. }
  462. }
  463. return dst
  464. }
  465. // Spec strips out comments and trailing commas and convert the input to a
  466. // valid JSON per the official spec: https://tools.ietf.org/html/rfc8259
  467. //
  468. // The resulting JSON will always be the same length as the input and it will
  469. // include all of the same line breaks at matching offsets. This is to ensure
  470. // the result can be later processed by a external parser and that that
  471. // parser will report messages or errors with the correct offsets.
  472. func Spec(src []byte) []byte {
  473. return spec(src, nil)
  474. }
  475. // SpecInPlace is the same as Spec, but this method reuses the input json
  476. // buffer to avoid allocations. Do not use the original bytes slice upon return.
  477. func SpecInPlace(src []byte) []byte {
  478. return spec(src, src)
  479. }
  480. func spec(src, dst []byte) []byte {
  481. dst = dst[:0]
  482. for i := 0; i < len(src); i++ {
  483. if src[i] == '/' {
  484. if i < len(src)-1 {
  485. if src[i+1] == '/' {
  486. dst = append(dst, ' ', ' ')
  487. i += 2
  488. for ; i < len(src); i++ {
  489. if src[i] == '\n' {
  490. dst = append(dst, '\n')
  491. break
  492. } else if src[i] == '\t' || src[i] == '\r' {
  493. dst = append(dst, src[i])
  494. } else {
  495. dst = append(dst, ' ')
  496. }
  497. }
  498. continue
  499. }
  500. if src[i+1] == '*' {
  501. dst = append(dst, ' ', ' ')
  502. i += 2
  503. for ; i < len(src)-1; i++ {
  504. if src[i] == '*' && src[i+1] == '/' {
  505. dst = append(dst, ' ', ' ')
  506. i++
  507. break
  508. } else if src[i] == '\n' || src[i] == '\t' ||
  509. src[i] == '\r' {
  510. dst = append(dst, src[i])
  511. } else {
  512. dst = append(dst, ' ')
  513. }
  514. }
  515. continue
  516. }
  517. }
  518. }
  519. dst = append(dst, src[i])
  520. if src[i] == '"' {
  521. for i = i + 1; i < len(src); i++ {
  522. dst = append(dst, src[i])
  523. if src[i] == '"' {
  524. j := i - 1
  525. for ; ; j-- {
  526. if src[j] != '\\' {
  527. break
  528. }
  529. }
  530. if (j-i)%2 != 0 {
  531. break
  532. }
  533. }
  534. }
  535. } else if src[i] == '}' || src[i] == ']' {
  536. for j := len(dst) - 2; j >= 0; j-- {
  537. if dst[j] <= ' ' {
  538. continue
  539. }
  540. if dst[j] == ',' {
  541. dst[j] = ' '
  542. }
  543. break
  544. }
  545. }
  546. }
  547. return dst
  548. }