Stanislav N. aka pztrn
48d43ca097
Pagination now works. Temporary hardcoded 10 pastes per page, will be put in configuration later. Maybe. From now user will receive readable error message if error occured. Started to work on syntax highlighting, tried to make lexers detection work but apparently to no avail.
123 lines
3.1 KiB
Go
123 lines
3.1 KiB
Go
package chroma
|
|
|
|
import (
|
|
"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
|
|
}
|
|
|
|
// A LexerMutator is an additional interface that a Mutator can implement
|
|
// to modify the lexer when it is compiled.
|
|
type LexerMutator interface {
|
|
// 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) }
|
|
|
|
// Mutators applies a set of Mutators in order.
|
|
func Mutators(modifiers ...Mutator) MutatorFunc {
|
|
return func(state *LexerState) error {
|
|
for _, modifier := range modifiers {
|
|
if err := modifier.Mutate(state); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
type includeMutator struct {
|
|
state string
|
|
}
|
|
|
|
// Include the given state.
|
|
func Include(state string) Rule {
|
|
return Rule{Mutator: &includeMutator{state}}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// Push states onto the stack.
|
|
func Push(states ...string) MutatorFunc {
|
|
return func(s *LexerState) error {
|
|
if len(states) == 0 {
|
|
s.Stack = append(s.Stack, s.State)
|
|
} else {
|
|
for _, state := range states {
|
|
if state == "#pop" {
|
|
s.Stack = s.Stack[:len(s.Stack)-1]
|
|
} else {
|
|
s.Stack = append(s.Stack, state)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Pop state from the stack when rule matches.
|
|
func Pop(n int) MutatorFunc {
|
|
return func(state *LexerState) error {
|
|
if len(state.Stack) == 0 {
|
|
return fmt.Errorf("nothing to pop")
|
|
}
|
|
state.Stack = state.Stack[:len(state.Stack)-n]
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Default returns a Rule that applies a set of Mutators.
|
|
func Default(mutators ...Mutator) Rule {
|
|
return Rule{Mutator: Mutators(mutators...)}
|
|
}
|