66
|
1 package gcss
|
|
2
|
|
3 import (
|
|
4 "fmt"
|
|
5 "strings"
|
|
6 )
|
|
7
|
|
8 const unicodeSpace = 32
|
|
9
|
|
10 const indentTop = 0
|
|
11
|
|
12 // line represents a line of codes.
|
|
13 type line struct {
|
|
14 no int
|
|
15 s string
|
|
16 indent int
|
|
17 }
|
|
18
|
|
19 // isEmpty returns true if the line's s is zero value.
|
|
20 func (ln *line) isEmpty() bool {
|
|
21 return strings.TrimSpace(ln.s) == ""
|
|
22 }
|
|
23
|
|
24 // isTopIndent returns true if the line's indent is the top level.
|
|
25 func (ln *line) isTopIndent() bool {
|
|
26 return ln.indent == indentTop
|
|
27 }
|
|
28
|
|
29 // childOf returns true if the line is a child of the parent.
|
|
30 func (ln *line) childOf(parent element) (bool, error) {
|
|
31 var ok bool
|
|
32 var err error
|
|
33
|
|
34 switch pIndent := parent.Base().ln.indent; {
|
|
35 case ln.indent == pIndent+1:
|
|
36 ok = true
|
|
37 case ln.indent > pIndent+1:
|
|
38 err = fmt.Errorf("indent is invalid [line: %d]", ln.no)
|
|
39 }
|
|
40
|
|
41 return ok, err
|
|
42 }
|
|
43
|
|
44 // isDeclaration returns true if the line is a declaration.
|
|
45 func (ln *line) isDeclaration() bool {
|
|
46 _, _, err := declarationPV(ln)
|
|
47 return err == nil
|
|
48 }
|
|
49
|
|
50 // isAtRule returns true if the line is an at-rule.
|
|
51 func (ln *line) isAtRule() bool {
|
|
52 return strings.HasPrefix(strings.TrimSpace(ln.s), atMark)
|
|
53 }
|
|
54
|
|
55 // isVariable returns true if the line is a variable.
|
|
56 func (ln *line) isVariable() bool {
|
|
57 if !ln.isTopIndent() {
|
|
58 return false
|
|
59 }
|
|
60
|
|
61 _, _, err := variableNV(ln)
|
|
62
|
|
63 return err == nil
|
|
64 }
|
|
65
|
|
66 // isMixinDeclaration returns true if the line is a mixin declaration.
|
|
67 func (ln *line) isMixinDeclaration() bool {
|
|
68 if !ln.isTopIndent() {
|
|
69 return false
|
|
70 }
|
|
71
|
|
72 _, _, err := mixinNP(ln, true)
|
|
73
|
|
74 return err == nil
|
|
75 }
|
|
76
|
|
77 // isMixinInvocation returns true if the line is a mixin invocation.
|
|
78 func (ln *line) isMixinInvocation() bool {
|
|
79 if ln.isTopIndent() {
|
|
80 return false
|
|
81 }
|
|
82
|
|
83 _, _, err := mixinNP(ln, false)
|
|
84
|
|
85 return err == nil
|
|
86 }
|
|
87
|
|
88 // isComment returns true if the line is a comment.
|
|
89 func (ln *line) isComment() bool {
|
|
90 return strings.HasPrefix(strings.TrimSpace(ln.s), doubleSlash)
|
|
91 }
|
|
92
|
|
93 // newLine creates and returns a line.
|
|
94 func newLine(no int, s string) *line {
|
|
95 return &line{
|
|
96 no: no,
|
|
97 s: s,
|
|
98 indent: indent(s),
|
|
99 }
|
|
100 }
|
|
101
|
|
102 // indent returns the string's indent.
|
|
103 func indent(s string) int {
|
|
104 var i int
|
|
105
|
|
106 for _, b := range s {
|
|
107 if b != unicodeSpace {
|
|
108 break
|
|
109 }
|
|
110 i++
|
|
111 }
|
|
112
|
|
113 return i / 2
|
|
114 }
|