* Server-side syntax hilighting for all code This PR does a few things: * Remove all traces of highlight.js * Use chroma library to provide fast syntax hilighting directly on the server * Provide syntax hilighting for diffs * Re-style both unified and split diffs views * Add custom syntax hilighting styling for both regular and arc-green Fixes #7729 Fixes #10157 Fixes #11825 Fixes #7728 Fixes #3872 Fixes #3682 And perhaps gets closer to #9553 * fix line marker * fix repo search * Fix single line select * properly load settings * npm uninstall highlight.js * review suggestion * code review * forgot to call function * fix test * Apply suggestions from code review suggestions from @silverwind thanks Co-authored-by: silverwind <me@silverwind.io> * code review * copy/paste error * Use const for highlight size limit * Update web_src/less/_repository.less Co-authored-by: Lauris BH <lauris@nix.lv> * update size limit to 1MB and other styling tweaks * fix highlighting for certain diff sections * fix test * add worker back as suggested Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Lauris BH <lauris@nix.lv>
		
			
				
	
	
		
			178 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			178 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| package regexp2
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"errors"
 | |
| 
 | |
| 	"github.com/dlclark/regexp2/syntax"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	replaceSpecials     = 4
 | |
| 	replaceLeftPortion  = -1
 | |
| 	replaceRightPortion = -2
 | |
| 	replaceLastGroup    = -3
 | |
| 	replaceWholeString  = -4
 | |
| )
 | |
| 
 | |
| // MatchEvaluator is a function that takes a match and returns a replacement string to be used
 | |
| type MatchEvaluator func(Match) string
 | |
| 
 | |
| // Three very similar algorithms appear below: replace (pattern),
 | |
| // replace (evaluator), and split.
 | |
| 
 | |
| // Replace Replaces all occurrences of the regex in the string with the
 | |
| // replacement pattern.
 | |
| //
 | |
| // Note that the special case of no matches is handled on its own:
 | |
| // with no matches, the input string is returned unchanged.
 | |
| // The right-to-left case is split out because StringBuilder
 | |
| // doesn't handle right-to-left string building directly very well.
 | |
| func replace(regex *Regexp, data *syntax.ReplacerData, evaluator MatchEvaluator, input string, startAt, count int) (string, error) {
 | |
| 	if count < -1 {
 | |
| 		return "", errors.New("Count too small")
 | |
| 	}
 | |
| 	if count == 0 {
 | |
| 		return "", nil
 | |
| 	}
 | |
| 
 | |
| 	m, err := regex.FindStringMatchStartingAt(input, startAt)
 | |
| 
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 	if m == nil {
 | |
| 		return input, nil
 | |
| 	}
 | |
| 
 | |
| 	buf := &bytes.Buffer{}
 | |
| 	text := m.text
 | |
| 
 | |
| 	if !regex.RightToLeft() {
 | |
| 		prevat := 0
 | |
| 		for m != nil {
 | |
| 			if m.Index != prevat {
 | |
| 				buf.WriteString(string(text[prevat:m.Index]))
 | |
| 			}
 | |
| 			prevat = m.Index + m.Length
 | |
| 			if evaluator == nil {
 | |
| 				replacementImpl(data, buf, m)
 | |
| 			} else {
 | |
| 				buf.WriteString(evaluator(*m))
 | |
| 			}
 | |
| 
 | |
| 			count--
 | |
| 			if count == 0 {
 | |
| 				break
 | |
| 			}
 | |
| 			m, err = regex.FindNextMatch(m)
 | |
| 			if err != nil {
 | |
| 				return "", nil
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if prevat < len(text) {
 | |
| 			buf.WriteString(string(text[prevat:]))
 | |
| 		}
 | |
| 	} else {
 | |
| 		prevat := len(text)
 | |
| 		var al []string
 | |
| 
 | |
| 		for m != nil {
 | |
| 			if m.Index+m.Length != prevat {
 | |
| 				al = append(al, string(text[m.Index+m.Length:prevat]))
 | |
| 			}
 | |
| 			prevat = m.Index
 | |
| 			if evaluator == nil {
 | |
| 				replacementImplRTL(data, &al, m)
 | |
| 			} else {
 | |
| 				al = append(al, evaluator(*m))
 | |
| 			}
 | |
| 
 | |
| 			count--
 | |
| 			if count == 0 {
 | |
| 				break
 | |
| 			}
 | |
| 			m, err = regex.FindNextMatch(m)
 | |
| 			if err != nil {
 | |
| 				return "", nil
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if prevat > 0 {
 | |
| 			buf.WriteString(string(text[:prevat]))
 | |
| 		}
 | |
| 
 | |
| 		for i := len(al) - 1; i >= 0; i-- {
 | |
| 			buf.WriteString(al[i])
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return buf.String(), nil
 | |
| }
 | |
| 
 | |
| // Given a Match, emits into the StringBuilder the evaluated
 | |
| // substitution pattern.
 | |
| func replacementImpl(data *syntax.ReplacerData, buf *bytes.Buffer, m *Match) {
 | |
| 	for _, r := range data.Rules {
 | |
| 
 | |
| 		if r >= 0 { // string lookup
 | |
| 			buf.WriteString(data.Strings[r])
 | |
| 		} else if r < -replaceSpecials { // group lookup
 | |
| 			m.groupValueAppendToBuf(-replaceSpecials-1-r, buf)
 | |
| 		} else {
 | |
| 			switch -replaceSpecials - 1 - r { // special insertion patterns
 | |
| 			case replaceLeftPortion:
 | |
| 				for i := 0; i < m.Index; i++ {
 | |
| 					buf.WriteRune(m.text[i])
 | |
| 				}
 | |
| 			case replaceRightPortion:
 | |
| 				for i := m.Index + m.Length; i < len(m.text); i++ {
 | |
| 					buf.WriteRune(m.text[i])
 | |
| 				}
 | |
| 			case replaceLastGroup:
 | |
| 				m.groupValueAppendToBuf(m.GroupCount()-1, buf)
 | |
| 			case replaceWholeString:
 | |
| 				for i := 0; i < len(m.text); i++ {
 | |
| 					buf.WriteRune(m.text[i])
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func replacementImplRTL(data *syntax.ReplacerData, al *[]string, m *Match) {
 | |
| 	l := *al
 | |
| 	buf := &bytes.Buffer{}
 | |
| 
 | |
| 	for _, r := range data.Rules {
 | |
| 		buf.Reset()
 | |
| 		if r >= 0 { // string lookup
 | |
| 			l = append(l, data.Strings[r])
 | |
| 		} else if r < -replaceSpecials { // group lookup
 | |
| 			m.groupValueAppendToBuf(-replaceSpecials-1-r, buf)
 | |
| 			l = append(l, buf.String())
 | |
| 		} else {
 | |
| 			switch -replaceSpecials - 1 - r { // special insertion patterns
 | |
| 			case replaceLeftPortion:
 | |
| 				for i := 0; i < m.Index; i++ {
 | |
| 					buf.WriteRune(m.text[i])
 | |
| 				}
 | |
| 			case replaceRightPortion:
 | |
| 				for i := m.Index + m.Length; i < len(m.text); i++ {
 | |
| 					buf.WriteRune(m.text[i])
 | |
| 				}
 | |
| 			case replaceLastGroup:
 | |
| 				m.groupValueAppendToBuf(m.GroupCount()-1, buf)
 | |
| 			case replaceWholeString:
 | |
| 				for i := 0; i < len(m.text); i++ {
 | |
| 					buf.WriteRune(m.text[i])
 | |
| 				}
 | |
| 			}
 | |
| 			l = append(l, buf.String())
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	*al = l
 | |
| }
 |