diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-10-25 00:47:47 +0200 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-10-25 00:47:47 +0200 |
| commit | c6cc0108ca7738023b45e0eeac0fa2390532dd93 (patch) | |
| tree | 36890e6cd3091bbab8efbe686cc56f467f645bfd /vendor/github.com/alecthomas/chroma/v2/mutators.go | |
| parent | 0130404a1dc663d4aa68d780c9bcb23a4243e68d (diff) | |
| download | jbmafp-master.tar.gz | |
Diffstat (limited to 'vendor/github.com/alecthomas/chroma/v2/mutators.go')
| -rw-r--r-- | vendor/github.com/alecthomas/chroma/v2/mutators.go | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/vendor/github.com/alecthomas/chroma/v2/mutators.go b/vendor/github.com/alecthomas/chroma/v2/mutators.go new file mode 100644 index 0000000..ae648aa --- /dev/null +++ b/vendor/github.com/alecthomas/chroma/v2/mutators.go @@ -0,0 +1,201 @@ +package chroma + +import ( + "encoding/xml" + "fmt" + "strings" +) + +// A Mutator modifies the behaviour of the lexer. +type Mutator interface { + // Mutate the lexer state machine as it is processing. + Mutate(state *LexerState) error +} + +// SerialisableMutator is a Mutator that can be serialised and deserialised. +type SerialisableMutator interface { + Mutator + MutatorKind() string +} + +// A LexerMutator is an additional interface that a Mutator can implement +// to modify the lexer when it is compiled. +type LexerMutator interface { + // MutateLexer can be implemented to mutate the lexer itself. + // + // Rules are the lexer rules, state is the state key for the rule the mutator is associated with. + MutateLexer(rules CompiledRules, state string, rule int) error +} + +// A MutatorFunc is a Mutator that mutates the lexer state machine as it is processing. +type MutatorFunc func(state *LexerState) error + +func (m MutatorFunc) Mutate(state *LexerState) error { return m(state) } // nolint + +type multiMutator struct { + Mutators []Mutator `xml:"mutator"` +} + +func (m *multiMutator) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + for { + token, err := d.Token() + if err != nil { + return err + } + switch token := token.(type) { + case xml.StartElement: + mutator, err := unmarshalMutator(d, token) + if err != nil { + return err + } + m.Mutators = append(m.Mutators, mutator) + + case xml.EndElement: + return nil + } + } +} + +func (m *multiMutator) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + name := xml.Name{Local: "mutators"} + if err := e.EncodeToken(xml.StartElement{Name: name}); err != nil { + return err + } + for _, m := range m.Mutators { + if err := marshalMutator(e, m); err != nil { + return err + } + } + return e.EncodeToken(xml.EndElement{Name: name}) +} + +func (m *multiMutator) MutatorKind() string { return "multiple" } + +func (m *multiMutator) Mutate(state *LexerState) error { + for _, modifier := range m.Mutators { + if err := modifier.Mutate(state); err != nil { + return err + } + } + return nil +} + +// Mutators applies a set of Mutators in order. +func Mutators(modifiers ...Mutator) Mutator { + return &multiMutator{modifiers} +} + +type includeMutator struct { + State string `xml:"state,attr"` +} + +// Include the given state. +func Include(state string) Rule { + return Rule{Mutator: &includeMutator{state}} +} + +func (i *includeMutator) MutatorKind() string { return "include" } + +func (i *includeMutator) Mutate(s *LexerState) error { + return fmt.Errorf("should never reach here Include(%q)", i.State) +} + +func (i *includeMutator) MutateLexer(rules CompiledRules, state string, rule int) error { + includedRules, ok := rules[i.State] + if !ok { + return fmt.Errorf("invalid include state %q", i.State) + } + rules[state] = append(rules[state][:rule], append(includedRules, rules[state][rule+1:]...)...) + return nil +} + +type combinedMutator struct { + States []string `xml:"state,attr"` +} + +func (c *combinedMutator) MutatorKind() string { return "combined" } + +// Combined creates a new anonymous state from the given states, and pushes that state. +func Combined(states ...string) Mutator { + return &combinedMutator{states} +} + +func (c *combinedMutator) Mutate(s *LexerState) error { + return fmt.Errorf("should never reach here Combined(%v)", c.States) +} + +func (c *combinedMutator) MutateLexer(rules CompiledRules, state string, rule int) error { + name := "__combined_" + strings.Join(c.States, "__") + if _, ok := rules[name]; !ok { + combined := []*CompiledRule{} + for _, state := range c.States { + rules, ok := rules[state] + if !ok { + return fmt.Errorf("invalid combine state %q", state) + } + combined = append(combined, rules...) + } + rules[name] = combined + } + rules[state][rule].Mutator = Push(name) + return nil +} + +type pushMutator struct { + States []string `xml:"state,attr"` +} + +func (p *pushMutator) MutatorKind() string { return "push" } + +func (p *pushMutator) Mutate(s *LexerState) error { + if len(p.States) == 0 { + s.Stack = append(s.Stack, s.State) + } else { + for _, state := range p.States { + if state == "#pop" { + s.Stack = s.Stack[:len(s.Stack)-1] + } else { + s.Stack = append(s.Stack, state) + } + } + } + return nil +} + +// Push states onto the stack. +func Push(states ...string) Mutator { + return &pushMutator{states} +} + +type popMutator struct { + Depth int `xml:"depth,attr"` +} + +func (p *popMutator) MutatorKind() string { return "pop" } + +func (p *popMutator) Mutate(state *LexerState) error { + if len(state.Stack) == 0 { + return fmt.Errorf("nothing to pop") + } + state.Stack = state.Stack[:len(state.Stack)-p.Depth] + return nil +} + +// Pop state from the stack when rule matches. +func Pop(n int) Mutator { + return &popMutator{n} +} + +// Default returns a Rule that applies a set of Mutators. +func Default(mutators ...Mutator) Rule { + return Rule{Mutator: Mutators(mutators...)} +} + +// Stringify returns the raw string for a set of tokens. +func Stringify(tokens ...Token) string { + out := []string{} + for _, t := range tokens { + out = append(out, t.Value) + } + return strings.Join(out, "") +} |
