نسخ من khaledmahfouz5/Maqtaa
Add binary files support (#503)
هذا الالتزام موجود في:
44
internal/render/csv.go
Normal file
44
internal/render/csv.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/thomiceli/opengist/internal/git"
|
||||
)
|
||||
|
||||
type CSVFile struct {
|
||||
*git.File
|
||||
Type string `json:"type"`
|
||||
Header []string `json:"-"`
|
||||
Rows [][]string `json:"-"`
|
||||
}
|
||||
|
||||
func (r CSVFile) getFile() *git.File {
|
||||
return r.File
|
||||
}
|
||||
|
||||
func renderCsvFile(file *git.File) (*CSVFile, error) {
|
||||
reader := csv.NewReader(strings.NewReader(file.Content))
|
||||
records, err := reader.ReadAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
header := records[0]
|
||||
numColumns := len(header)
|
||||
|
||||
for i := 1; i < len(records); i++ {
|
||||
if len(records[i]) != numColumns {
|
||||
return nil, fmt.Errorf("CSV file has invalid row at index %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
return &CSVFile{
|
||||
File: file,
|
||||
Type: "CSV",
|
||||
Header: header,
|
||||
Rows: records[1:],
|
||||
}, nil
|
||||
}
|
||||
@@ -5,47 +5,44 @@ import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/alecthomas/chroma/v2"
|
||||
"github.com/alecthomas/chroma/v2/formatters/html"
|
||||
"github.com/alecthomas/chroma/v2/lexers"
|
||||
"github.com/alecthomas/chroma/v2/styles"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/thomiceli/opengist/internal/db"
|
||||
"github.com/thomiceli/opengist/internal/git"
|
||||
"path"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type RenderedFile struct {
|
||||
type HighlightedFile struct {
|
||||
*git.File
|
||||
Type string `json:"type"`
|
||||
Lines []string `json:"-"`
|
||||
HTML string `json:"-"`
|
||||
}
|
||||
|
||||
func (r HighlightedFile) getFile() *git.File {
|
||||
return r.File
|
||||
}
|
||||
|
||||
type RenderedGist struct {
|
||||
*db.Gist
|
||||
Lines []string
|
||||
HTML string
|
||||
}
|
||||
|
||||
func HighlightFile(file *git.File) (RenderedFile, error) {
|
||||
func highlightFile(file *git.File) (HighlightedFile, error) {
|
||||
rendered := HighlightedFile{
|
||||
File: file,
|
||||
}
|
||||
if !file.MimeType.IsText() {
|
||||
return rendered, nil
|
||||
}
|
||||
style := newStyle()
|
||||
lexer := newLexer(file.Filename)
|
||||
|
||||
if lexer.Config().Name == "markdown" {
|
||||
return MarkdownFile(file)
|
||||
}
|
||||
if lexer.Config().Name == "XML" && path.Ext(file.Filename) == ".svg" {
|
||||
return RenderSvgFile(file), nil
|
||||
}
|
||||
|
||||
formatter := html.New(html.WithClasses(true), html.PreventSurroundingPre(true))
|
||||
|
||||
rendered := RenderedFile{
|
||||
File: file,
|
||||
}
|
||||
|
||||
iterator, err := lexer.Tokenise(nil, file.Content+"\n")
|
||||
if err != nil {
|
||||
return rendered, err
|
||||
@@ -74,38 +71,6 @@ func HighlightFile(file *git.File) (RenderedFile, error) {
|
||||
return rendered, err
|
||||
}
|
||||
|
||||
func HighlightFiles(files []*git.File) []RenderedFile {
|
||||
const numWorkers = 10
|
||||
jobs := make(chan int, numWorkers)
|
||||
renderedFiles := make([]RenderedFile, len(files))
|
||||
var wg sync.WaitGroup
|
||||
|
||||
worker := func() {
|
||||
for idx := range jobs {
|
||||
rendered, err := HighlightFile(files[idx])
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Error rendering gist preview for " + files[idx].Filename)
|
||||
}
|
||||
renderedFiles[idx] = rendered
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
for i := 0; i < numWorkers; i++ {
|
||||
wg.Add(1)
|
||||
go worker()
|
||||
}
|
||||
|
||||
for i := range files {
|
||||
jobs <- i
|
||||
}
|
||||
close(jobs)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return renderedFiles
|
||||
}
|
||||
|
||||
func HighlightGistPreview(gist *db.Gist) (RenderedGist, error) {
|
||||
rendered := RenderedGist{
|
||||
Gist: gist,
|
||||
@@ -146,18 +111,12 @@ func HighlightGistPreview(gist *db.Gist) (RenderedGist, error) {
|
||||
return rendered, err
|
||||
}
|
||||
|
||||
func RenderSvgFile(file *git.File) RenderedFile {
|
||||
rendered := RenderedFile{
|
||||
func renderSvgFile(file *git.File) HighlightedFile {
|
||||
return HighlightedFile{
|
||||
File: file,
|
||||
HTML: `<img src="data:image/svg+xml;base64,` + base64.StdEncoding.EncodeToString([]byte(file.Content)) + `" />`,
|
||||
Type: "SVG",
|
||||
}
|
||||
|
||||
encoded := base64.StdEncoding.EncodeToString([]byte(file.Content))
|
||||
content := `<img src="data:image/svg+xml;base64,` + encoded + `" />`
|
||||
|
||||
rendered.HTML = content
|
||||
rendered.Type = "SVG"
|
||||
|
||||
return rendered
|
||||
}
|
||||
|
||||
func parseFileTypeName(config chroma.Config) string {
|
||||
|
||||
@@ -2,6 +2,8 @@ package render
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"regexp"
|
||||
|
||||
"github.com/alecthomas/chroma/v2/formatters/html"
|
||||
"github.com/thomiceli/opengist/internal/db"
|
||||
"github.com/thomiceli/opengist/internal/git"
|
||||
@@ -12,7 +14,6 @@ import (
|
||||
"github.com/yuin/goldmark/parser"
|
||||
"github.com/yuin/goldmark/util"
|
||||
"go.abhg.dev/goldmark/mermaid"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func MarkdownGistPreview(gist *db.Gist) (RenderedGist, error) {
|
||||
@@ -27,11 +28,11 @@ func MarkdownGistPreview(gist *db.Gist) (RenderedGist, error) {
|
||||
}, err
|
||||
}
|
||||
|
||||
func MarkdownFile(file *git.File) (RenderedFile, error) {
|
||||
func renderMarkdownFile(file *git.File) (HighlightedFile, error) {
|
||||
var buf bytes.Buffer
|
||||
err := newMarkdownWithSvgExtension().Convert([]byte(file.Content), &buf)
|
||||
|
||||
return RenderedFile{
|
||||
return HighlightedFile{
|
||||
File: file,
|
||||
HTML: buf.String(),
|
||||
Type: "Markdown",
|
||||
|
||||
84
internal/render/render.go
Normal file
84
internal/render/render.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/thomiceli/opengist/internal/git"
|
||||
)
|
||||
|
||||
type RenderedFile interface {
|
||||
getFile() *git.File
|
||||
}
|
||||
|
||||
type NonHighlightedFile struct {
|
||||
*git.File
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
func (r NonHighlightedFile) getFile() *git.File {
|
||||
return r.File
|
||||
}
|
||||
|
||||
func RenderFiles(files []*git.File) []RenderedFile {
|
||||
const numWorkers = 10
|
||||
jobs := make(chan int, numWorkers)
|
||||
renderedFiles := make([]RenderedFile, len(files))
|
||||
var wg sync.WaitGroup
|
||||
|
||||
worker := func() {
|
||||
for idx := range jobs {
|
||||
renderedFiles[idx] = processFile(files[idx])
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
for i := 0; i < numWorkers; i++ {
|
||||
wg.Add(1)
|
||||
go worker()
|
||||
}
|
||||
|
||||
for i := range files {
|
||||
jobs <- i
|
||||
}
|
||||
close(jobs)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return renderedFiles
|
||||
}
|
||||
|
||||
func processFile(file *git.File) RenderedFile {
|
||||
mt := file.MimeType
|
||||
if mt.IsCSV() {
|
||||
rendered, err := renderCsvFile(file)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Error parsing CSV file for " + file.Filename)
|
||||
}
|
||||
return rendered
|
||||
} else if mt.IsText() && filepath.Ext(file.Filename) == ".md" {
|
||||
rendered, err := renderMarkdownFile(file)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Error rendering markdown file for " + file.Filename)
|
||||
}
|
||||
return rendered
|
||||
} else if mt.IsSVG() {
|
||||
rendered := renderSvgFile(file)
|
||||
return rendered
|
||||
} else if mt.CanBeEmbedded() {
|
||||
rendered := NonHighlightedFile{File: file, Type: mt.RenderType()}
|
||||
file.Content = ""
|
||||
return rendered
|
||||
} else if mt.CanBeRendered() {
|
||||
rendered, err := highlightFile(file)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Error rendering gist preview for " + file.Filename)
|
||||
}
|
||||
return rendered
|
||||
} else {
|
||||
rendered := NonHighlightedFile{File: file, Type: mt.RenderType()}
|
||||
file.Content = ""
|
||||
return rendered
|
||||
}
|
||||
}
|
||||
المرجع في مشكلة جديدة
حظر مستخدم