turbo-editors/turbo-corepublic Fork 0
v1.0.0
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

yaml_block.go · 84 lines · 2.7 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 20h ago1package syntax
2
3// Block scalars: the one construct in YAML whose extent is decided by
4// indentation rather than by a delimiter, and the one every CI file uses.
5
6// yamlCarry is what a line leaves open for the next.
7//
8// Only a block scalar does. It is the one construct in YAML whose extent is
9// decided by *indentation* rather than by a delimiter: everything indented
10// further than the key that opened it belongs to it, and the first line that is
11// not ends it. So the carry holds that key's indentation, and whether one is
12// open at all — a depth of zero is a real indentation, not an absence.
13type yamlCarry struct {
14 inBlock bool
15 // keyIndent is the column the key that opened the block starts at. A line
16 // indented further is inside the block.
17 keyIndent int
18 // seenBody is false until the block's first content line, whose indentation
19 // is not yet known. YAML lets a block be written at any deeper indent, so
20 // the first line establishes it rather than a fixed offset doing so.
21 seenBody bool
22}
23
24// continueBlockScalar colours a line belonging to an open block scalar, and
25// reports whether the block swallowed it.
26//
27// A blank line inside a block belongs to the block whatever its indentation:
28// YAML keeps empty lines in a literal scalar, and treating one as the end would
29// cut a shell script in a CI file in half at its first paragraph break.
30func continueBlockScalar(s *LineScanner, carry yamlCarry) (bool, yamlCarry) {
31 if s.Len() == 0 {
32 return true, carry
33 }
34
35 indent := leadingSpaces(s.line)
36 if indent == s.Len() { // a line of nothing but spaces
37 return true, carry
38 }
39
40 if !carry.seenBody {
41 // The first content line fixes the block's own indentation. It only
42 // counts as the body if it is indented past the key.
43 if indent <= carry.keyIndent {
44 return false, yamlCarry{}
45 }
46 carry.seenBody = true
47 carry.keyIndent = indent - 1 // anything at or past `indent` is inside
48 }
49 if indent <= carry.keyIndent {
50 return false, yamlCarry{}
51 }
52
53 s.TakeRest(ClassString)
54 return true, carry
55}
56
57// opensBlockScalar reports whether what is left of the line is a `|` or `>`
58// header, with its optional chomping and indentation indicators.
59func opensBlockScalar(s *LineScanner) bool {
60 if r := s.Peek(0); r != '|' && r != '>' {
61 return false
62 }
63 for at := 1; s.Pos()+at < s.Len(); at++ {
64 switch s.Peek(at) {
65 case '-', '+', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ':
66 continue
67 case '#':
68 return true // a trailing comment still leaves the block open
69 default:
70 return false
71 }
72 }
73 return true
74}
75
76// leadingSpaces returns how many spaces a line starts with.
77func leadingSpaces(line []rune) int {
78 for at, r := range line {
79 if r != ' ' {
80 return at
81 }
82 }
83 return len(line)
84}