mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	Add support for rendering terminal output with colors (#19497)
This commit is contained in:
		
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							@@ -15,6 +15,7 @@ require (
 | 
			
		||||
	github.com/PuerkitoBio/goquery v1.8.0
 | 
			
		||||
	github.com/alecthomas/chroma v0.10.0
 | 
			
		||||
	github.com/blevesearch/bleve/v2 v2.3.2
 | 
			
		||||
	github.com/buildkite/terminal-to-html/v3 v3.6.1
 | 
			
		||||
	github.com/caddyserver/certmagic v0.16.1
 | 
			
		||||
	github.com/chi-middleware/proxy v1.1.1
 | 
			
		||||
	github.com/denisenkom/go-mssqldb v0.12.0
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								go.sum
									
									
									
									
									
								
							@@ -265,6 +265,8 @@ github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl
 | 
			
		||||
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
 | 
			
		||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
 | 
			
		||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
 | 
			
		||||
github.com/buildkite/terminal-to-html/v3 v3.6.1 h1:yHS+GXsPDXevb67YXjkVwZ4tolDCgPYa9RVOrzHlgGE=
 | 
			
		||||
github.com/buildkite/terminal-to-html/v3 v3.6.1/go.mod h1:g0ME1XqbkBSgXR9YmlIHcJIjzaMyWW+HbsG0rPb5puo=
 | 
			
		||||
github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw=
 | 
			
		||||
github.com/caddyserver/certmagic v0.16.1 h1:rdSnjcUVJojmL4M0efJ+yHXErrrijS4YYg3FuwRdJkI=
 | 
			
		||||
github.com/caddyserver/certmagic v0.16.1/go.mod h1:jKQ5n+ViHAr6DbPwEGLTSM2vDwTO6EvCKBblBRUvvuQ=
 | 
			
		||||
@@ -1499,6 +1501,7 @@ github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
 | 
			
		||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 | 
			
		||||
github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw=
 | 
			
		||||
github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 | 
			
		||||
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
 | 
			
		||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 | 
			
		||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
 | 
			
		||||
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								main.go
									
									
									
									
									
								
							@@ -18,6 +18,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
 | 
			
		||||
	// register supported doc types
 | 
			
		||||
	_ "code.gitea.io/gitea/modules/markup/console"
 | 
			
		||||
	_ "code.gitea.io/gitea/modules/markup/csv"
 | 
			
		||||
	_ "code.gitea.io/gitea/modules/markup/markdown"
 | 
			
		||||
	_ "code.gitea.io/gitea/modules/markup/orgmode"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										95
									
								
								modules/markup/console/console.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								modules/markup/console/console.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package console
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"io"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/markup"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
 | 
			
		||||
	trend "github.com/buildkite/terminal-to-html/v3"
 | 
			
		||||
	"github.com/go-enry/go-enry/v2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MarkupName describes markup's name
 | 
			
		||||
var MarkupName = "console"
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	markup.RegisterRenderer(Renderer{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Renderer implements markup.Renderer
 | 
			
		||||
type Renderer struct{}
 | 
			
		||||
 | 
			
		||||
// Name implements markup.Renderer
 | 
			
		||||
func (Renderer) Name() string {
 | 
			
		||||
	return MarkupName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NeedPostProcess implements markup.Renderer
 | 
			
		||||
func (Renderer) NeedPostProcess() bool { return false }
 | 
			
		||||
 | 
			
		||||
// Extensions implements markup.Renderer
 | 
			
		||||
func (Renderer) Extensions() []string {
 | 
			
		||||
	return []string{".sh-session"}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SanitizerRules implements markup.Renderer
 | 
			
		||||
func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule {
 | 
			
		||||
	return []setting.MarkupSanitizerRule{
 | 
			
		||||
		{Element: "span", AllowAttr: "class", Regexp: regexp.MustCompile(`^term-((fg[ix]?|bg)\d+|container)$`)},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SanitizerDisabled disabled sanitize if return true
 | 
			
		||||
func (Renderer) SanitizerDisabled() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CanRender implements markup.RendererContentDetector
 | 
			
		||||
func (Renderer) CanRender(filename string, input io.Reader) bool {
 | 
			
		||||
	buf, err := io.ReadAll(input)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	if enry.GetLanguage(filepath.Base(filename), buf) != enry.OtherLanguage {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return bytes.ContainsRune(buf, '\x1b')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 = trend.Render(buf)
 | 
			
		||||
	buf = bytes.ReplaceAll(buf, []byte("\n"), []byte(`<br>`))
 | 
			
		||||
	_, err = output.Write(buf)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Render renders terminal colors to HTML with all specific handling stuff.
 | 
			
		||||
func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
 | 
			
		||||
	if ctx.Type == "" {
 | 
			
		||||
		ctx.Type = MarkupName
 | 
			
		||||
	}
 | 
			
		||||
	return markup.Render(ctx, input, output)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RenderString renders terminal colors in string to HTML with all specific handling stuff and return string
 | 
			
		||||
func RenderString(ctx *markup.RenderContext, content string) (string, error) {
 | 
			
		||||
	var buf strings.Builder
 | 
			
		||||
	if err := Render(ctx, strings.NewReader(content), &buf); err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return buf.String(), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								modules/markup/console/console_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								modules/markup/console/console_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package console
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/markup"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestRenderConsole(t *testing.T) {
 | 
			
		||||
	var render Renderer
 | 
			
		||||
	kases := map[string]string{
 | 
			
		||||
		"\x1b[37m\x1b[40mnpm\x1b[0m \x1b[0m\x1b[32minfo\x1b[0m \x1b[0m\x1b[35mit worked if it ends with\x1b[0m ok": "<span class=\"term-fg37 term-bg40\">npm</span> <span class=\"term-fg32\">info</span> <span class=\"term-fg35\">it worked if it ends with</span> ok",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for k, v := range kases {
 | 
			
		||||
		var buf strings.Builder
 | 
			
		||||
		canRender := render.CanRender("test", strings.NewReader(k))
 | 
			
		||||
		assert.True(t, canRender)
 | 
			
		||||
 | 
			
		||||
		err := render.Render(&markup.RenderContext{}, strings.NewReader(k), &buf)
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.EqualValues(t, v, buf.String())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
package markup
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
@@ -93,6 +94,12 @@ type Renderer interface {
 | 
			
		||||
	Render(ctx *RenderContext, input io.Reader, output io.Writer) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RendererContentDetector detects if the content can be rendered
 | 
			
		||||
// by specified renderer
 | 
			
		||||
type RendererContentDetector interface {
 | 
			
		||||
	CanRender(filename string, input io.Reader) bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	extRenderers = make(map[string]Renderer)
 | 
			
		||||
	renderers    = make(map[string]Renderer)
 | 
			
		||||
@@ -117,6 +124,20 @@ func GetRendererByType(tp string) Renderer {
 | 
			
		||||
	return renderers[tp]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DetectRendererType detects the markup type of the content
 | 
			
		||||
func DetectRendererType(filename string, input io.Reader) string {
 | 
			
		||||
	buf, err := io.ReadAll(input)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	for _, renderer := range renderers {
 | 
			
		||||
		if detector, ok := renderer.(RendererContentDetector); ok && detector.CanRender(filename, bytes.NewReader(buf)) {
 | 
			
		||||
			return renderer.Name()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Render renders markup file to HTML with all specific handling stuff.
 | 
			
		||||
func Render(ctx *RenderContext, input io.Reader, output io.Writer) error {
 | 
			
		||||
	if ctx.Type != "" {
 | 
			
		||||
 
 | 
			
		||||
@@ -509,6 +509,13 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
 | 
			
		||||
		ctx.Data["ReadmeExist"] = readmeExist
 | 
			
		||||
 | 
			
		||||
		markupType := markup.Type(blob.Name())
 | 
			
		||||
		// If the markup is detected by custom markup renderer it should not be reset later on
 | 
			
		||||
		// to not pass it down to the render context.
 | 
			
		||||
		detected := false
 | 
			
		||||
		if markupType == "" {
 | 
			
		||||
			detected = true
 | 
			
		||||
			markupType = markup.DetectRendererType(blob.Name(), bytes.NewReader(buf))
 | 
			
		||||
		}
 | 
			
		||||
		if markupType != "" {
 | 
			
		||||
			ctx.Data["HasSourceRenderedToggle"] = true
 | 
			
		||||
		}
 | 
			
		||||
@@ -517,8 +524,12 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
 | 
			
		||||
			ctx.Data["IsMarkup"] = true
 | 
			
		||||
			ctx.Data["MarkupType"] = markupType
 | 
			
		||||
			var result strings.Builder
 | 
			
		||||
			if !detected {
 | 
			
		||||
				markupType = ""
 | 
			
		||||
			}
 | 
			
		||||
			err := markup.Render(&markup.RenderContext{
 | 
			
		||||
				Ctx:       ctx,
 | 
			
		||||
				Type:      markupType,
 | 
			
		||||
				Filename:  blob.Name(),
 | 
			
		||||
				URLPrefix: path.Dir(treeLink),
 | 
			
		||||
				Metas:     ctx.Repo.Repository.ComposeDocumentMetas(),
 | 
			
		||||
 
 | 
			
		||||
@@ -58,6 +58,9 @@
 | 
			
		||||
  --color-secondary-alpha-70: #dededeb3;
 | 
			
		||||
  --color-secondary-alpha-80: #dededecc;
 | 
			
		||||
  --color-secondary-alpha-90: #dededee1;
 | 
			
		||||
  /* console colors */
 | 
			
		||||
  --color-console-fg: #ffffff;
 | 
			
		||||
  --color-console-bg: #171717;
 | 
			
		||||
  /* colors */
 | 
			
		||||
  --color-red: #db2828;
 | 
			
		||||
  --color-orange: #f2711c;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										299
									
								
								web_src/less/console/console.less
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								web_src/less/console/console.less
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,299 @@
 | 
			
		||||
// Based on https://github.com/buildkite/terminal-to-html/blob/697ff23bd8dc48b9d23f11f259f5256dae2455f0/assets/terminal.css
 | 
			
		||||
 | 
			
		||||
.console {
 | 
			
		||||
  background: var(--color-console-bg);
 | 
			
		||||
  color: var(--color-console-fg);
 | 
			
		||||
  font-family: var(--fonts-monospace);
 | 
			
		||||
  border-radius: 5px;
 | 
			
		||||
  word-break: break-word;
 | 
			
		||||
  overflow-wrap: break-word;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.console img { max-width: 100%; }
 | 
			
		||||
 | 
			
		||||
.console a {
 | 
			
		||||
  color: inherit;
 | 
			
		||||
  text-decoration: underline;
 | 
			
		||||
  text-decoration-style: dashed;
 | 
			
		||||
}
 | 
			
		||||
.console a:hover { color: var(--color-primary); }
 | 
			
		||||
 | 
			
		||||
@keyframes blink-animation {
 | 
			
		||||
  to {
 | 
			
		||||
    visibility: hidden;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.term-fg2 { color: #838887; } /* faint (decreased intensity) - same as gray really */
 | 
			
		||||
.term-fg3 { font-style: italic; } /* italic */
 | 
			
		||||
.term-fg4 { text-decoration: underline; } /* underline */
 | 
			
		||||
.term-fg5 { animation: blink-animation 1s steps(3, start) infinite; } /* blink */
 | 
			
		||||
.term-fg9 { text-decoration: line-through; } /* crossed-out */
 | 
			
		||||
 | 
			
		||||
.term-fg30 { color: #666666; } /* black (but we can't use black, so a diff color) */
 | 
			
		||||
.term-fg31 { color: #ff7070; } /* red */
 | 
			
		||||
.term-fg32 { color: #b0f986; } /* green */
 | 
			
		||||
.term-fg33 { color: #c6c502; } /* yellow */
 | 
			
		||||
.term-fg34 { color: #8db7e0; } /* blue */
 | 
			
		||||
.term-fg35 { color: #f271fb; } /* magenta */
 | 
			
		||||
.term-fg36 { color: #6bf7ff; } /* cyan */
 | 
			
		||||
 | 
			
		||||
/* high intense colors */
 | 
			
		||||
.term-fgi1 { color: #5ef765; }
 | 
			
		||||
.term-fgi90 { color: #838887; } /* grey */
 | 
			
		||||
.term-fgi91 { color: #ff3333; } /* red */
 | 
			
		||||
.term-fgi92 { color: #00ff00; } /* green */
 | 
			
		||||
.term-fgi93 { color: #fffc67; } /* yellow */
 | 
			
		||||
.term-fgi94 { color: #6871ff; } /* blue */
 | 
			
		||||
.term-fgi95 { color: #ff76ff; } /* magenta */
 | 
			
		||||
.term-fgi96 { color: #60fcff; } /* cyan */
 | 
			
		||||
 | 
			
		||||
/* background colors */
 | 
			
		||||
.term-bg40 { background: #676767; } /* grey */
 | 
			
		||||
.term-bg41 { background: #ff4343; } /* red */
 | 
			
		||||
.term-bg42 { background: #99ff5f; } /* green */
 | 
			
		||||
 | 
			
		||||
/* custom foreground/background combos for readability */
 | 
			
		||||
.term-fg31.term-bg40 { color: #f8a39f; }
 | 
			
		||||
 | 
			
		||||
/* xterm colors */
 | 
			
		||||
.term-fgx16 { color: #000000; }
 | 
			
		||||
.term-fgx17 { color: #00005f; }
 | 
			
		||||
.term-fgx18 { color: #000087; }
 | 
			
		||||
.term-fgx19 { color: #0000af; }
 | 
			
		||||
.term-fgx20 { color: #0000d7; }
 | 
			
		||||
.term-fgx21 { color: #0000ff; }
 | 
			
		||||
.term-fgx22 { color: #005f00; }
 | 
			
		||||
.term-fgx23 { color: #005f5f; }
 | 
			
		||||
.term-fgx24 { color: #005f87; }
 | 
			
		||||
.term-fgx25 { color: #005faf; }
 | 
			
		||||
.term-fgx26 { color: #005fd7; }
 | 
			
		||||
.term-fgx27 { color: #005fff; }
 | 
			
		||||
.term-fgx28 { color: #008700; }
 | 
			
		||||
.term-fgx29 { color: #00875f; }
 | 
			
		||||
.term-fgx30 { color: #008787; }
 | 
			
		||||
.term-fgx31 { color: #0087af; }
 | 
			
		||||
.term-fgx32 { color: #0087d7; }
 | 
			
		||||
.term-fgx33 { color: #0087ff; }
 | 
			
		||||
.term-fgx34 { color: #00af00; }
 | 
			
		||||
.term-fgx35 { color: #00af5f; }
 | 
			
		||||
.term-fgx36 { color: #00af87; }
 | 
			
		||||
.term-fgx37 { color: #00afaf; }
 | 
			
		||||
.term-fgx38 { color: #00afd7; }
 | 
			
		||||
.term-fgx39 { color: #00afff; }
 | 
			
		||||
.term-fgx40 { color: #00d700; }
 | 
			
		||||
.term-fgx41 { color: #00d75f; }
 | 
			
		||||
.term-fgx42 { color: #00d787; }
 | 
			
		||||
.term-fgx43 { color: #00d7af; }
 | 
			
		||||
.term-fgx44 { color: #00d7d7; }
 | 
			
		||||
.term-fgx45 { color: #00d7ff; }
 | 
			
		||||
.term-fgx46 { color: #00ff00; }
 | 
			
		||||
.term-fgx47 { color: #00ff5f; }
 | 
			
		||||
.term-fgx48 { color: #00ff87; }
 | 
			
		||||
.term-fgx49 { color: #00ffaf; }
 | 
			
		||||
.term-fgx50 { color: #00ffd7; }
 | 
			
		||||
.term-fgx51 { color: #00ffff; }
 | 
			
		||||
.term-fgx52 { color: #5f0000; }
 | 
			
		||||
.term-fgx53 { color: #5f005f; }
 | 
			
		||||
.term-fgx54 { color: #5f0087; }
 | 
			
		||||
.term-fgx55 { color: #5f00af; }
 | 
			
		||||
.term-fgx56 { color: #5f00d7; }
 | 
			
		||||
.term-fgx57 { color: #5f00ff; }
 | 
			
		||||
.term-fgx58 { color: #5f5f00; }
 | 
			
		||||
.term-fgx59 { color: #5f5f5f; }
 | 
			
		||||
.term-fgx60 { color: #5f5f87; }
 | 
			
		||||
.term-fgx61 { color: #5f5faf; }
 | 
			
		||||
.term-fgx62 { color: #5f5fd7; }
 | 
			
		||||
.term-fgx63 { color: #5f5fff; }
 | 
			
		||||
.term-fgx64 { color: #5f8700; }
 | 
			
		||||
.term-fgx65 { color: #5f875f; }
 | 
			
		||||
.term-fgx66 { color: #5f8787; }
 | 
			
		||||
.term-fgx67 { color: #5f87af; }
 | 
			
		||||
.term-fgx68 { color: #5f87d7; }
 | 
			
		||||
.term-fgx69 { color: #5f87ff; }
 | 
			
		||||
.term-fgx70 { color: #5faf00; }
 | 
			
		||||
.term-fgx71 { color: #5faf5f; }
 | 
			
		||||
.term-fgx72 { color: #5faf87; }
 | 
			
		||||
.term-fgx73 { color: #5fafaf; }
 | 
			
		||||
.term-fgx74 { color: #5fafd7; }
 | 
			
		||||
.term-fgx75 { color: #5fafff; }
 | 
			
		||||
.term-fgx76 { color: #5fd700; }
 | 
			
		||||
.term-fgx77 { color: #5fd75f; }
 | 
			
		||||
.term-fgx78 { color: #5fd787; }
 | 
			
		||||
.term-fgx79 { color: #5fd7af; }
 | 
			
		||||
.term-fgx80 { color: #5fd7d7; }
 | 
			
		||||
.term-fgx81 { color: #5fd7ff; }
 | 
			
		||||
.term-fgx82 { color: #5fff00; }
 | 
			
		||||
.term-fgx83 { color: #5fff5f; }
 | 
			
		||||
.term-fgx84 { color: #5fff87; }
 | 
			
		||||
.term-fgx85 { color: #5fffaf; }
 | 
			
		||||
.term-fgx86 { color: #5fffd7; }
 | 
			
		||||
.term-fgx87 { color: #5fffff; }
 | 
			
		||||
.term-fgx88 { color: #870000; }
 | 
			
		||||
.term-fgx89 { color: #87005f; }
 | 
			
		||||
.term-fgx90 { color: #870087; }
 | 
			
		||||
.term-fgx91 { color: #8700af; }
 | 
			
		||||
.term-fgx92 { color: #8700d7; }
 | 
			
		||||
.term-fgx93 { color: #8700ff; }
 | 
			
		||||
.term-fgx94 { color: #875f00; }
 | 
			
		||||
.term-fgx95 { color: #875f5f; }
 | 
			
		||||
.term-fgx96 { color: #875f87; }
 | 
			
		||||
.term-fgx97 { color: #875faf; }
 | 
			
		||||
.term-fgx98 { color: #875fd7; }
 | 
			
		||||
.term-fgx99 { color: #875fff; }
 | 
			
		||||
.term-fgx100 { color: #878700; }
 | 
			
		||||
.term-fgx101 { color: #87875f; }
 | 
			
		||||
.term-fgx102 { color: #878787; }
 | 
			
		||||
.term-fgx103 { color: #8787af; }
 | 
			
		||||
.term-fgx104 { color: #8787d7; }
 | 
			
		||||
.term-fgx105 { color: #8787ff; }
 | 
			
		||||
.term-fgx106 { color: #87af00; }
 | 
			
		||||
.term-fgx107 { color: #87af5f; }
 | 
			
		||||
.term-fgx108 { color: #87af87; }
 | 
			
		||||
.term-fgx109 { color: #87afaf; }
 | 
			
		||||
.term-fgx110 { color: #87afd7; }
 | 
			
		||||
.term-fgx111 { color: #87afff; }
 | 
			
		||||
.term-fgx112 { color: #87d700; }
 | 
			
		||||
.term-fgx113 { color: #87d75f; }
 | 
			
		||||
.term-fgx114 { color: #87d787; }
 | 
			
		||||
.term-fgx115 { color: #87d7af; }
 | 
			
		||||
.term-fgx116 { color: #87d7d7; }
 | 
			
		||||
.term-fgx117 { color: #87d7ff; }
 | 
			
		||||
.term-fgx118 { color: #87ff00; }
 | 
			
		||||
.term-fgx119 { color: #87ff5f; }
 | 
			
		||||
.term-fgx120 { color: #87ff87; }
 | 
			
		||||
.term-fgx121 { color: #87ffaf; }
 | 
			
		||||
.term-fgx122 { color: #87ffd7; }
 | 
			
		||||
.term-fgx123 { color: #87ffff; }
 | 
			
		||||
.term-fgx124 { color: #af0000; }
 | 
			
		||||
.term-fgx125 { color: #af005f; }
 | 
			
		||||
.term-fgx126 { color: #af0087; }
 | 
			
		||||
.term-fgx127 { color: #af00af; }
 | 
			
		||||
.term-fgx128 { color: #af00d7; }
 | 
			
		||||
.term-fgx129 { color: #af00ff; }
 | 
			
		||||
.term-fgx130 { color: #af5f00; }
 | 
			
		||||
.term-fgx131 { color: #af5f5f; }
 | 
			
		||||
.term-fgx132 { color: #af5f87; }
 | 
			
		||||
.term-fgx133 { color: #af5faf; }
 | 
			
		||||
.term-fgx134 { color: #af5fd7; }
 | 
			
		||||
.term-fgx135 { color: #af5fff; }
 | 
			
		||||
.term-fgx136 { color: #af8700; }
 | 
			
		||||
.term-fgx137 { color: #af875f; }
 | 
			
		||||
.term-fgx138 { color: #af8787; }
 | 
			
		||||
.term-fgx139 { color: #af87af; }
 | 
			
		||||
.term-fgx140 { color: #af87d7; }
 | 
			
		||||
.term-fgx141 { color: #af87ff; }
 | 
			
		||||
.term-fgx142 { color: #afaf00; }
 | 
			
		||||
.term-fgx143 { color: #afaf5f; }
 | 
			
		||||
.term-fgx144 { color: #afaf87; }
 | 
			
		||||
.term-fgx145 { color: #afafaf; }
 | 
			
		||||
.term-fgx146 { color: #afafd7; }
 | 
			
		||||
.term-fgx147 { color: #afafff; }
 | 
			
		||||
.term-fgx148 { color: #afd700; }
 | 
			
		||||
.term-fgx149 { color: #afd75f; }
 | 
			
		||||
.term-fgx150 { color: #afd787; }
 | 
			
		||||
.term-fgx151 { color: #afd7af; }
 | 
			
		||||
.term-fgx152 { color: #afd7d7; }
 | 
			
		||||
.term-fgx153 { color: #afd7ff; }
 | 
			
		||||
.term-fgx154 { color: #afff00; }
 | 
			
		||||
.term-fgx155 { color: #afff5f; }
 | 
			
		||||
.term-fgx156 { color: #afff87; }
 | 
			
		||||
.term-fgx157 { color: #afffaf; }
 | 
			
		||||
.term-fgx158 { color: #afffd7; }
 | 
			
		||||
.term-fgx159 { color: #afffff; }
 | 
			
		||||
.term-fgx160 { color: #d70000; }
 | 
			
		||||
.term-fgx161 { color: #d7005f; }
 | 
			
		||||
.term-fgx162 { color: #d70087; }
 | 
			
		||||
.term-fgx163 { color: #d700af; }
 | 
			
		||||
.term-fgx164 { color: #d700d7; }
 | 
			
		||||
.term-fgx165 { color: #d700ff; }
 | 
			
		||||
.term-fgx166 { color: #d75f00; }
 | 
			
		||||
.term-fgx167 { color: #d75f5f; }
 | 
			
		||||
.term-fgx168 { color: #d75f87; }
 | 
			
		||||
.term-fgx169 { color: #d75faf; }
 | 
			
		||||
.term-fgx170 { color: #d75fd7; }
 | 
			
		||||
.term-fgx171 { color: #d75fff; }
 | 
			
		||||
.term-fgx172 { color: #d78700; }
 | 
			
		||||
.term-fgx173 { color: #d7875f; }
 | 
			
		||||
.term-fgx174 { color: #d78787; }
 | 
			
		||||
.term-fgx175 { color: #d787af; }
 | 
			
		||||
.term-fgx176 { color: #d787d7; }
 | 
			
		||||
.term-fgx177 { color: #d787ff; }
 | 
			
		||||
.term-fgx178 { color: #d7af00; }
 | 
			
		||||
.term-fgx179 { color: #d7af5f; }
 | 
			
		||||
.term-fgx180 { color: #d7af87; }
 | 
			
		||||
.term-fgx181 { color: #d7afaf; }
 | 
			
		||||
.term-fgx182 { color: #d7afd7; }
 | 
			
		||||
.term-fgx183 { color: #d7afff; }
 | 
			
		||||
.term-fgx184 { color: #d7d700; }
 | 
			
		||||
.term-fgx185 { color: #d7d75f; }
 | 
			
		||||
.term-fgx186 { color: #d7d787; }
 | 
			
		||||
.term-fgx187 { color: #d7d7af; }
 | 
			
		||||
.term-fgx188 { color: #d7d7d7; }
 | 
			
		||||
.term-fgx189 { color: #d7d7ff; }
 | 
			
		||||
.term-fgx190 { color: #d7ff00; }
 | 
			
		||||
.term-fgx191 { color: #d7ff5f; }
 | 
			
		||||
.term-fgx192 { color: #d7ff87; }
 | 
			
		||||
.term-fgx193 { color: #d7ffaf; }
 | 
			
		||||
.term-fgx194 { color: #d7ffd7; }
 | 
			
		||||
.term-fgx195 { color: #d7ffff; }
 | 
			
		||||
.term-fgx196 { color: #ff0000; }
 | 
			
		||||
.term-fgx197 { color: #ff005f; }
 | 
			
		||||
.term-fgx198 { color: #ff0087; }
 | 
			
		||||
.term-fgx199 { color: #ff00af; }
 | 
			
		||||
.term-fgx200 { color: #ff00d7; }
 | 
			
		||||
.term-fgx201 { color: #ff00ff; }
 | 
			
		||||
.term-fgx202 { color: #ff5f00; }
 | 
			
		||||
.term-fgx203 { color: #ff5f5f; }
 | 
			
		||||
.term-fgx204 { color: #ff5f87; }
 | 
			
		||||
.term-fgx205 { color: #ff5faf; }
 | 
			
		||||
.term-fgx206 { color: #ff5fd7; }
 | 
			
		||||
.term-fgx207 { color: #ff5fff; }
 | 
			
		||||
.term-fgx208 { color: #ff8700; }
 | 
			
		||||
.term-fgx209 { color: #ff875f; }
 | 
			
		||||
.term-fgx210 { color: #ff8787; }
 | 
			
		||||
.term-fgx211 { color: #ff87af; }
 | 
			
		||||
.term-fgx212 { color: #ff87d7; }
 | 
			
		||||
.term-fgx213 { color: #ff87ff; }
 | 
			
		||||
.term-fgx214 { color: #ffaf00; }
 | 
			
		||||
.term-fgx215 { color: #ffaf5f; }
 | 
			
		||||
.term-fgx216 { color: #ffaf87; }
 | 
			
		||||
.term-fgx217 { color: #ffafaf; }
 | 
			
		||||
.term-fgx218 { color: #ffafd7; }
 | 
			
		||||
.term-fgx219 { color: #ffafff; }
 | 
			
		||||
.term-fgx220 { color: #ffd700; }
 | 
			
		||||
.term-fgx221 { color: #ffd75f; }
 | 
			
		||||
.term-fgx222 { color: #ffd787; }
 | 
			
		||||
.term-fgx223 { color: #ffd7af; }
 | 
			
		||||
.term-fgx224 { color: #ffd7d7; }
 | 
			
		||||
.term-fgx225 { color: #ffd7ff; }
 | 
			
		||||
.term-fgx226 { color: #ffff00; }
 | 
			
		||||
.term-fgx227 { color: #ffff5f; }
 | 
			
		||||
.term-fgx228 { color: #ffff87; }
 | 
			
		||||
.term-fgx229 { color: #ffffaf; }
 | 
			
		||||
.term-fgx230 { color: #ffffd7; }
 | 
			
		||||
.term-fgx231 { color: #ffffff; }
 | 
			
		||||
.term-fgx232 { color: #080808; }
 | 
			
		||||
.term-fgx233 { color: #121212; }
 | 
			
		||||
.term-fgx234 { color: #1c1c1c; }
 | 
			
		||||
.term-fgx235 { color: #262626; }
 | 
			
		||||
.term-fgx236 { color: #303030; }
 | 
			
		||||
.term-fgx237 { color: #3a3a3a; }
 | 
			
		||||
.term-fgx238 { color: #444444; }
 | 
			
		||||
.term-fgx239 { color: #4e4e4e; }
 | 
			
		||||
.term-fgx240 { color: #585858; }
 | 
			
		||||
.term-fgx241 { color: #626262; }
 | 
			
		||||
.term-fgx242 { color: #6c6c6c; }
 | 
			
		||||
.term-fgx243 { color: #767676; }
 | 
			
		||||
.term-fgx244 { color: #808080; }
 | 
			
		||||
.term-fgx245 { color: #8a8a8a; }
 | 
			
		||||
.term-fgx246 { color: #949494; }
 | 
			
		||||
.term-fgx247 { color: #9e9e9e; }
 | 
			
		||||
.term-fgx248 { color: #a8a8a8; }
 | 
			
		||||
.term-fgx249 { color: #b2b2b2; }
 | 
			
		||||
.term-fgx250 { color: #bcbcbc; }
 | 
			
		||||
.term-fgx251 { color: #c6c6c6; }
 | 
			
		||||
.term-fgx252 { color: #d0d0d0; }
 | 
			
		||||
.term-fgx253 { color: #dadada; }
 | 
			
		||||
.term-fgx254 { color: #e4e4e4; }
 | 
			
		||||
.term-fgx255 { color: #eeeeee; }
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
@import "./chroma/light.less";
 | 
			
		||||
@import "./codemirror/base.less";
 | 
			
		||||
@import "./codemirror/light.less";
 | 
			
		||||
@import "./console/console.less";
 | 
			
		||||
 | 
			
		||||
@import "_svg";
 | 
			
		||||
@import "_tribute";
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user