Files
MokoGitea/modules/markup/console/console.go
T
Jonathan Miller 9a5720e8ad
Universal: PR Check / Build RC Package (pull_request) Blocked by required conditions
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
PR RC Release / Build RC Release (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
chore: rename Go module from git. to code.mokoconsulting.tech (#336)
Full namespace migration: update the Go module path and all import
statements from git.mokoconsulting.tech to code.mokoconsulting.tech.
Also updates all URL references in templates, workflows, configs,
tests, and documentation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 10:28:25 -05:00

84 lines
2.1 KiB
Go

// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package console
import (
"bytes"
"io"
"unicode/utf8"
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/markup"
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/typesniffer"
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util"
trend "github.com/buildkite/terminal-to-html/v3"
)
func init() {
markup.RegisterRenderer(Renderer{})
}
type Renderer struct{}
var _ markup.RendererContentDetector = (*Renderer)(nil)
func (Renderer) Name() string {
return "console"
}
func (Renderer) FileNamePatterns() []string {
return []string{"*.sh-session"}
}
func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule {
return []setting.MarkupSanitizerRule{
{Element: "span", AllowAttr: "class", Regexp: `^term-((fg[ix]?|bg)\d+|container)$`},
}
}
func (Renderer) CanRender(filename string, sniffedType typesniffer.SniffedType, prefetchBuf []byte) bool {
if !sniffedType.IsTextPlain() {
return false
}
s := util.UnsafeBytesToString(prefetchBuf)
rs := []rune(s)
cnt := 0
firstErrPos := -1
isCtrlSep := func(p int) bool {
return p < len(rs) && (rs[p] == ';' || rs[p] == 'm')
}
for i, c := range rs {
if c == 0 {
return false
}
if c == '\x1b' {
match := i+1 < len(rs) && rs[i+1] == '['
if match && (isCtrlSep(i+2) || isCtrlSep(i+3) || isCtrlSep(i+4) || isCtrlSep(i+5)) {
cnt++
}
}
if c == utf8.RuneError && firstErrPos == -1 {
firstErrPos = i
}
}
if firstErrPos != -1 && firstErrPos != len(rs)-1 {
return false
}
return cnt >= 2 // only render it as console output if there are at least two escape sequences
}
// Render renders terminal colors to HTML with all specific handling stuff.
func (Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
buf, err := io.ReadAll(input)
if err != nil {
return err
}
buf = []byte(trend.Render(buf))
buf = bytes.ReplaceAll(buf, []byte("\n"), []byte(`<br>`))
_, err = output.Write(buf)
return err
}