192 lines
4.4 KiB
Go
192 lines
4.4 KiB
Go
/*
|
|
* Amsterdam Web Communities System
|
|
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*/
|
|
// The htmlcheck package contains the HTML Checker.
|
|
package htmlcheck
|
|
|
|
import (
|
|
"context"
|
|
_ "embed"
|
|
"math"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// EmoticonDef is a single emoticon definition.
|
|
type EmoticonDef struct {
|
|
Name string `yaml:"name"`
|
|
Patterns []string `yaml:"patterns"`
|
|
Replace string `yaml:"replace"`
|
|
}
|
|
|
|
// EmoticonConfig is the YAML configuration of the emoticons.
|
|
type EmoticonConfig struct {
|
|
PrefixChars string `yaml:"prefixChars"`
|
|
Emoticons []EmoticonDef `yaml:"emoticons"`
|
|
emos map[string]*EmoticonDef
|
|
}
|
|
|
|
// emoticonRewriter is the implementation of rewriter in this file.
|
|
type emoticonRewriter struct {
|
|
config *EmoticonConfig
|
|
prefixChars []byte
|
|
patterns map[string]string
|
|
minLength int
|
|
}
|
|
|
|
//go:embed emoticons.yaml
|
|
var rawEmoConfig []byte
|
|
|
|
// init loads the configuration and registers the rewriters.
|
|
func init() {
|
|
var cfg EmoticonConfig
|
|
if err := yaml.Unmarshal(rawEmoConfig, &cfg); err != nil {
|
|
panic(err)
|
|
}
|
|
cfg.emos = make(map[string]*EmoticonDef)
|
|
for i, def := range cfg.Emoticons {
|
|
cfg.emos[def.Name] = &(cfg.Emoticons[i])
|
|
}
|
|
rw := emoticonRewriter{
|
|
config: &cfg,
|
|
prefixChars: []byte(cfg.PrefixChars),
|
|
patterns: make(map[string]string),
|
|
minLength: math.MaxInt,
|
|
}
|
|
for _, def := range rw.config.Emoticons {
|
|
for _, p := range def.Patterns {
|
|
f := false
|
|
for i := range rw.prefixChars {
|
|
if p[0] == rw.prefixChars[i] {
|
|
f = true
|
|
break
|
|
}
|
|
}
|
|
if f {
|
|
rw.patterns[p] = def.Name
|
|
rw.minLength = min(rw.minLength, len(p))
|
|
}
|
|
}
|
|
}
|
|
rewriterRegistry[rw.Name()] = &rw
|
|
|
|
rw2 := emoticonTagRewriter{
|
|
config: &cfg,
|
|
re: regexp.MustCompile(`^ei:\s*(\w+)(\s*/)?\s*$`),
|
|
}
|
|
rewriterRegistry[rw2.Name()] = &rw2
|
|
}
|
|
|
|
// Name returns the rewriter's name.
|
|
func (rw *emoticonRewriter) Name() string {
|
|
return "emoticon"
|
|
}
|
|
|
|
/* Rewrite rewrites the given string data and adds markup before and after if needed.
|
|
* Parameters:
|
|
* ctx - Standard Go context value.
|
|
* data - The data to be rewritten.
|
|
* svc - Services interface we can use.
|
|
* Returns:
|
|
* Pointer to markup data, or nil.
|
|
*/
|
|
func (rw *emoticonRewriter) Rewrite(ctx context.Context, data string, svc rewriterServices) *markupData {
|
|
pos := math.MaxInt
|
|
for _, c := range rw.prefixChars {
|
|
foo := strings.IndexByte(data, c)
|
|
if foo >= 0 {
|
|
pos = min(pos, foo)
|
|
}
|
|
}
|
|
if pos == math.MaxInt {
|
|
return nil
|
|
}
|
|
didReplace := false
|
|
var output strings.Builder
|
|
work := data
|
|
for pos != math.MaxInt {
|
|
if pos > 0 {
|
|
output.WriteString(work[:pos])
|
|
work = work[pos:]
|
|
}
|
|
looking := true
|
|
if len(work) >= rw.minLength {
|
|
for k, v := range rw.patterns {
|
|
if strings.HasPrefix(work, k) {
|
|
looking = false
|
|
output.WriteString(rw.config.emos[v].Replace)
|
|
work = work[len(k):]
|
|
didReplace = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if looking {
|
|
output.WriteString(work[:1])
|
|
work = work[1:]
|
|
}
|
|
pos = math.MaxInt
|
|
for _, c := range rw.prefixChars {
|
|
foo := strings.IndexByte(work, c)
|
|
if foo >= 0 {
|
|
pos = min(pos, foo)
|
|
}
|
|
}
|
|
}
|
|
if !didReplace {
|
|
return nil
|
|
}
|
|
output.WriteString(work)
|
|
return &markupData{
|
|
beginMarkup: "",
|
|
text: output.String(),
|
|
endMarkup: "",
|
|
rescan: true,
|
|
}
|
|
}
|
|
|
|
// emoticonTagRewriter rewrites emoticon tags.
|
|
type emoticonTagRewriter struct {
|
|
config *EmoticonConfig
|
|
re *regexp.Regexp
|
|
}
|
|
|
|
// Name returns the rewriter's name.
|
|
func (rw *emoticonTagRewriter) Name() string {
|
|
return "emoticon_tag"
|
|
}
|
|
|
|
/* Rewrite rewrites the given string data and adds markup before and after if needed.
|
|
* Parameters:
|
|
* ctx - Standard Go context value.
|
|
* data - The data to be rewritten.
|
|
* svc - Services interface we can use.
|
|
* Returns:
|
|
* Pointer to markup data, or nil.
|
|
*/
|
|
func (rw *emoticonTagRewriter) Rewrite(ctx context.Context, data string, svc rewriterServices) *markupData {
|
|
m := rw.re.FindStringSubmatch(data)
|
|
if m == nil {
|
|
return nil
|
|
}
|
|
d, ok := rw.config.emos[m[1]]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return &markupData{
|
|
beginMarkup: "",
|
|
text: d.Replace,
|
|
endMarkup: "",
|
|
rescan: false,
|
|
}
|
|
}
|