~shulhan/asciidoctor-go

ref: v0.1.0 asciidoctor-go/cell_format.go -rw-r--r-- 2.2 KiB
4c1ded16Shulhan Release asciidoctor-go v0.1.0 (2021-03-06) 4 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright 2020, Shulhan <ms@kilabit.info>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package asciidoctor

import (
	"strconv"

	"github.com/shuLhan/share/lib/ascii"
)

type cellFormat struct {
	ndupCol  int
	nspanCol int
	nspanRow int
	alignHor int
	alignVer int
	style    int
}

//
// parseCellFormat parse the cell format and return it.
// In case one of the character is not a valid format, it will return nil,
// considering the whole raw string as not cell format.
//
func parseCellFormat(raw string) (cf *cellFormat) {
	var (
		x     int
		n     int
		isDot bool
	)
	if len(raw) == 0 {
		return nil
	}

	cf = &cellFormat{}
	if ascii.IsDigit(raw[0]) {
		n, raw = parseCellFormatDigits(raw)
		if len(raw) == 0 {
			return nil
		}
		if raw[0] == '*' {
			cf.ndupCol = n
			x = 1
		} else if raw[0] == '+' {
			cf.nspanCol = n
			x = 1
		} else if raw[0] == '.' {
			cf.nspanCol = n
			n, raw = parseCellFormatDigits(raw[1:])
			if n == 0 {
				// Invalid format, there should be digits
				// after '.'
				return nil
			}
			if raw[0] != '+' {
				return nil
			}
			x = 1
			cf.nspanRow = n
		} else {
			return nil
		}
	}
	for ; x < len(raw); x++ {
		switch raw[x] {
		case '.':
			isDot = true
		case '<':
			if isDot {
				cf.alignVer = colAlignTop
				isDot = false
			} else {
				cf.alignHor = colAlignTop
			}
		case '^':
			if isDot {
				cf.alignVer = colAlignMiddle
				isDot = false
			} else {
				cf.alignHor = colAlignMiddle
			}
		case '>':
			if isDot {
				cf.alignVer = colAlignBottom
				isDot = false
			} else {
				cf.alignHor = colAlignBottom
			}
		case 'a', 'e', 'h', 'l', 'm', 's', 'v':
			cf.style = _colStyles[raw[x]]
		default:
			if isDot && ascii.IsDigit(raw[x]) {
				n, raw = parseCellFormatDigits(raw[x:])
				if len(raw) == 0 {
					return nil
				}
				if raw[0] != '+' {
					return nil
				}
				cf.nspanRow = n
				x = 0
				isDot = false
				continue
			}
			return nil
		}
	}
	return cf
}

func parseCellFormatDigits(s string) (n int, rest string) {
	var (
		x int
		b []byte
	)
	for ; x < len(s); x++ {
		if !ascii.IsDigit(s[x]) {
			break
		}
		b = append(b, s[x])
	}
	n, _ = strconv.Atoi(string(b))
	rest = s[x:]
	return n, rest
}