mirror of https://github.com/go-gitea/gitea.git
Fix material icon & diff highlight (#33844)
parent
c102492e5a
commit
657239b480
|
@ -18,13 +18,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type materialIconRulesData struct {
|
type materialIconRulesData struct {
|
||||||
IconDefinitions map[string]*struct {
|
|
||||||
IconPath string `json:"iconPath"`
|
|
||||||
} `json:"iconDefinitions"`
|
|
||||||
FileNames map[string]string `json:"fileNames"`
|
FileNames map[string]string `json:"fileNames"`
|
||||||
FolderNames map[string]string `json:"folderNames"`
|
FolderNames map[string]string `json:"folderNames"`
|
||||||
FileExtensions map[string]string `json:"fileExtensions"`
|
FileExtensions map[string]string `json:"fileExtensions"`
|
||||||
LanguageIDs map[string]string `json:"languageIds"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type MaterialIconProvider struct {
|
type MaterialIconProvider struct {
|
||||||
|
@ -36,6 +32,7 @@ type MaterialIconProvider struct {
|
||||||
var materialIconProvider MaterialIconProvider
|
var materialIconProvider MaterialIconProvider
|
||||||
|
|
||||||
func DefaultMaterialIconProvider() *MaterialIconProvider {
|
func DefaultMaterialIconProvider() *MaterialIconProvider {
|
||||||
|
materialIconProvider.once.Do(materialIconProvider.loadData)
|
||||||
return &materialIconProvider
|
return &materialIconProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,8 +85,6 @@ func (m *MaterialIconProvider) renderFileIconSVG(ctx reqctx.RequestContext, name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MaterialIconProvider) FileIcon(ctx reqctx.RequestContext, entry *git.TreeEntry) template.HTML {
|
func (m *MaterialIconProvider) FileIcon(ctx reqctx.RequestContext, entry *git.TreeEntry) template.HTML {
|
||||||
m.once.Do(m.loadData)
|
|
||||||
|
|
||||||
if m.rules == nil {
|
if m.rules == nil {
|
||||||
return BasicThemeIcon(entry)
|
return BasicThemeIcon(entry)
|
||||||
}
|
}
|
||||||
|
@ -101,7 +96,7 @@ func (m *MaterialIconProvider) FileIcon(ctx reqctx.RequestContext, entry *git.Tr
|
||||||
return svg.RenderHTML("octicon-file-symlink-file") // TODO: find some better icons for them
|
return svg.RenderHTML("octicon-file-symlink-file") // TODO: find some better icons for them
|
||||||
}
|
}
|
||||||
|
|
||||||
name := m.findIconName(entry)
|
name := m.findIconNameByGit(entry)
|
||||||
if name == "folder" {
|
if name == "folder" {
|
||||||
// the material icon pack's "folder" icon doesn't look good, so use our built-in one
|
// the material icon pack's "folder" icon doesn't look good, so use our built-in one
|
||||||
return svg.RenderHTML("material-folder-generic")
|
return svg.RenderHTML("material-folder-generic")
|
||||||
|
@ -112,34 +107,23 @@ func (m *MaterialIconProvider) FileIcon(ctx reqctx.RequestContext, entry *git.Tr
|
||||||
return svg.RenderHTML("octicon-file")
|
return svg.RenderHTML("octicon-file")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MaterialIconProvider) findIconName(entry *git.TreeEntry) string {
|
func (m *MaterialIconProvider) FindIconName(name string, isDir bool) string {
|
||||||
if entry.IsSubModule() {
|
|
||||||
return "folder-git"
|
|
||||||
}
|
|
||||||
|
|
||||||
iconsData := m.rules
|
iconsData := m.rules
|
||||||
fileName := path.Base(entry.Name())
|
fileNameLower := strings.ToLower(path.Base(name))
|
||||||
|
if isDir {
|
||||||
if entry.IsDir() {
|
if s, ok := iconsData.FolderNames[fileNameLower]; ok {
|
||||||
if s, ok := iconsData.FolderNames[fileName]; ok {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
if s, ok := iconsData.FolderNames[strings.ToLower(fileName)]; ok {
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
return "folder"
|
return "folder"
|
||||||
}
|
}
|
||||||
|
|
||||||
if s, ok := iconsData.FileNames[fileName]; ok {
|
if s, ok := iconsData.FileNames[fileNameLower]; ok {
|
||||||
return s
|
|
||||||
}
|
|
||||||
if s, ok := iconsData.FileNames[strings.ToLower(fileName)]; ok {
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := len(fileName) - 1; i >= 0; i-- {
|
for i := len(fileNameLower) - 1; i >= 0; i-- {
|
||||||
if fileName[i] == '.' {
|
if fileNameLower[i] == '.' {
|
||||||
ext := fileName[i+1:]
|
ext := fileNameLower[i+1:]
|
||||||
if s, ok := iconsData.FileExtensions[ext]; ok {
|
if s, ok := iconsData.FileExtensions[ext]; ok {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -148,3 +132,10 @@ func (m *MaterialIconProvider) findIconName(entry *git.TreeEntry) string {
|
||||||
|
|
||||||
return "file"
|
return "file"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MaterialIconProvider) findIconNameByGit(entry *git.TreeEntry) string {
|
||||||
|
if entry.IsSubModule() {
|
||||||
|
return "folder-git"
|
||||||
|
}
|
||||||
|
return m.FindIconName(entry.Name(), entry.IsDir())
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package fileicon_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
"code.gitea.io/gitea/modules/fileicon"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
unittest.MainTest(m, &unittest.TestOptions{FixtureFiles: []string{}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindIconName(t *testing.T) {
|
||||||
|
unittest.PrepareTestEnv(t)
|
||||||
|
p := fileicon.DefaultMaterialIconProvider()
|
||||||
|
assert.Equal(t, "php", p.FindIconName("foo.php", false))
|
||||||
|
assert.Equal(t, "php", p.FindIconName("foo.PHP", false))
|
||||||
|
}
|
|
@ -65,7 +65,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
|
||||||
log.Debug("missing commit for %s", entry.Name())
|
log.Debug("missing commit for %s", entry.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the entry if a submodule add a submodule file for this
|
// If the entry is a submodule add a submodule file for this
|
||||||
if entry.IsSubModule() {
|
if entry.IsSubModule() {
|
||||||
subModuleURL := ""
|
subModuleURL := ""
|
||||||
var fullPath string
|
var fullPath string
|
||||||
|
@ -85,8 +85,8 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the commit for the treePath itself (see above). We basically
|
// Retrieve the commit for the treePath itself (see above). We basically
|
||||||
// get it for free during the tree traversal and it's used for listing
|
// get it for free during the tree traversal, and it's used for listing
|
||||||
// pages to display information about newest commit for a given path.
|
// pages to display information about the newest commit for a given path.
|
||||||
var treeCommit *Commit
|
var treeCommit *Commit
|
||||||
var ok bool
|
var ok bool
|
||||||
if treePath == "" {
|
if treePath == "" {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -900,7 +900,6 @@ func ExcerptBlob(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
section := &gitdiff.DiffSection{
|
section := &gitdiff.DiffSection{
|
||||||
FileName: filePath,
|
FileName: filePath,
|
||||||
Name: filePath,
|
|
||||||
}
|
}
|
||||||
if direction == "up" && (idxLeft-lastLeft) > chunkSize {
|
if direction == "up" && (idxLeft-lastLeft) > chunkSize {
|
||||||
idxLeft -= chunkSize
|
idxLeft -= chunkSize
|
||||||
|
|
|
@ -78,7 +78,7 @@ const (
|
||||||
type DiffLine struct {
|
type DiffLine struct {
|
||||||
LeftIdx int // line number, 1-based
|
LeftIdx int // line number, 1-based
|
||||||
RightIdx int // line number, 1-based
|
RightIdx int // line number, 1-based
|
||||||
Match int // line number, 1-based
|
Match int // the diff matched index. -1: no match. 0: plain and no need to match. >0: for add/del, "Lines" slice index of the other side
|
||||||
Type DiffLineType
|
Type DiffLineType
|
||||||
Content string
|
Content string
|
||||||
Comments issues_model.CommentList // related PR code comments
|
Comments issues_model.CommentList // related PR code comments
|
||||||
|
@ -203,12 +203,20 @@ func getLineContent(content string, locale translation.Locale) DiffInline {
|
||||||
type DiffSection struct {
|
type DiffSection struct {
|
||||||
file *DiffFile
|
file *DiffFile
|
||||||
FileName string
|
FileName string
|
||||||
Name string
|
|
||||||
Lines []*DiffLine
|
Lines []*DiffLine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (diffSection *DiffSection) GetLine(idx int) *DiffLine {
|
||||||
|
if idx <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return diffSection.Lines[idx]
|
||||||
|
}
|
||||||
|
|
||||||
// GetLine gets a specific line by type (add or del) and file line number
|
// GetLine gets a specific line by type (add or del) and file line number
|
||||||
func (diffSection *DiffSection) GetLine(lineType DiffLineType, idx int) *DiffLine {
|
// This algorithm is not quite right.
|
||||||
|
// Actually now we have "Match" field, it is always right, so use it instead in new GetLine
|
||||||
|
func (diffSection *DiffSection) getLineLegacy(lineType DiffLineType, idx int) *DiffLine { //nolint:unused
|
||||||
var (
|
var (
|
||||||
difference = 0
|
difference = 0
|
||||||
addCount = 0
|
addCount = 0
|
||||||
|
@ -279,7 +287,7 @@ func (diffSection *DiffSection) getLineContentForRender(lineIdx int, diffLine *D
|
||||||
if setting.Git.DisableDiffHighlight {
|
if setting.Git.DisableDiffHighlight {
|
||||||
return template.HTML(html.EscapeString(diffLine.Content[1:]))
|
return template.HTML(html.EscapeString(diffLine.Content[1:]))
|
||||||
}
|
}
|
||||||
h, _ = highlight.Code(diffSection.Name, fileLanguage, diffLine.Content[1:])
|
h, _ = highlight.Code(diffSection.FileName, fileLanguage, diffLine.Content[1:])
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,20 +300,31 @@ func (diffSection *DiffSection) getDiffLineForRender(diffLineType DiffLineType,
|
||||||
highlightedLeftLines, highlightedRightLines = diffSection.file.highlightedLeftLines, diffSection.file.highlightedRightLines
|
highlightedLeftLines, highlightedRightLines = diffSection.file.highlightedLeftLines, diffSection.file.highlightedRightLines
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lineHTML template.HTML
|
||||||
hcd := newHighlightCodeDiff()
|
hcd := newHighlightCodeDiff()
|
||||||
var diff1, diff2, lineHTML template.HTML
|
if diffLineType == DiffLinePlain {
|
||||||
if leftLine != nil {
|
// left and right are the same, no need to do line-level diff
|
||||||
diff1 = diffSection.getLineContentForRender(leftLine.LeftIdx, leftLine, fileLanguage, highlightedLeftLines)
|
if leftLine != nil {
|
||||||
lineHTML = util.Iif(diffLineType == DiffLinePlain, diff1, "")
|
lineHTML = diffSection.getLineContentForRender(leftLine.LeftIdx, leftLine, fileLanguage, highlightedLeftLines)
|
||||||
}
|
} else if rightLine != nil {
|
||||||
if rightLine != nil {
|
lineHTML = diffSection.getLineContentForRender(rightLine.RightIdx, rightLine, fileLanguage, highlightedRightLines)
|
||||||
diff2 = diffSection.getLineContentForRender(rightLine.RightIdx, rightLine, fileLanguage, highlightedRightLines)
|
}
|
||||||
lineHTML = util.Iif(diffLineType == DiffLinePlain, diff2, "")
|
} else {
|
||||||
}
|
var diff1, diff2 template.HTML
|
||||||
if diffLineType != DiffLinePlain {
|
if leftLine != nil {
|
||||||
// it seems that Gitea doesn't need the line wrapper of Chroma, so do not add them back
|
diff1 = diffSection.getLineContentForRender(leftLine.LeftIdx, leftLine, fileLanguage, highlightedLeftLines)
|
||||||
// if the line wrappers are still needed in the future, it can be added back by "diffLineWithHighlightWrapper(hcd.lineWrapperTags. ...)"
|
}
|
||||||
lineHTML = hcd.diffLineWithHighlight(diffLineType, diff1, diff2)
|
if rightLine != nil {
|
||||||
|
diff2 = diffSection.getLineContentForRender(rightLine.RightIdx, rightLine, fileLanguage, highlightedRightLines)
|
||||||
|
}
|
||||||
|
if diff1 != "" && diff2 != "" {
|
||||||
|
// if only some parts of a line are changed, highlight these changed parts as "deleted/added".
|
||||||
|
lineHTML = hcd.diffLineWithHighlight(diffLineType, diff1, diff2)
|
||||||
|
} else {
|
||||||
|
// if left is empty or right is empty (a line is fully deleted or added), then we do not need to diff anymore.
|
||||||
|
// the tmpl code already adds background colors for these cases.
|
||||||
|
lineHTML = util.Iif(diffLineType == DiffLineDel, diff1, diff2)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return DiffInlineWithUnicodeEscape(lineHTML, locale)
|
return DiffInlineWithUnicodeEscape(lineHTML, locale)
|
||||||
}
|
}
|
||||||
|
@ -317,10 +336,10 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine, loc
|
||||||
case DiffLineSection:
|
case DiffLineSection:
|
||||||
return getLineContent(diffLine.Content[1:], locale)
|
return getLineContent(diffLine.Content[1:], locale)
|
||||||
case DiffLineAdd:
|
case DiffLineAdd:
|
||||||
compareDiffLine := diffSection.GetLine(DiffLineDel, diffLine.RightIdx)
|
compareDiffLine := diffSection.GetLine(diffLine.Match)
|
||||||
return diffSection.getDiffLineForRender(DiffLineAdd, compareDiffLine, diffLine, locale)
|
return diffSection.getDiffLineForRender(DiffLineAdd, compareDiffLine, diffLine, locale)
|
||||||
case DiffLineDel:
|
case DiffLineDel:
|
||||||
compareDiffLine := diffSection.GetLine(DiffLineAdd, diffLine.LeftIdx)
|
compareDiffLine := diffSection.GetLine(diffLine.Match)
|
||||||
return diffSection.getDiffLineForRender(DiffLineDel, diffLine, compareDiffLine, locale)
|
return diffSection.getDiffLineForRender(DiffLineDel, diffLine, compareDiffLine, locale)
|
||||||
default: // Plain
|
default: // Plain
|
||||||
// TODO: there was an "if" check: `if diffLine.Content >strings.IndexByte(" +-", diffLine.Content[0]) > -1 { ... } else { ... }`
|
// TODO: there was an "if" check: `if diffLine.Content >strings.IndexByte(" +-", diffLine.Content[0]) > -1 { ... } else { ... }`
|
||||||
|
@ -383,15 +402,22 @@ type DiffLimitedContent struct {
|
||||||
|
|
||||||
// GetTailSectionAndLimitedContent creates a fake DiffLineSection if the last section is not the end of the file
|
// GetTailSectionAndLimitedContent creates a fake DiffLineSection if the last section is not the end of the file
|
||||||
func (diffFile *DiffFile) GetTailSectionAndLimitedContent(leftCommit, rightCommit *git.Commit) (_ *DiffSection, diffLimitedContent DiffLimitedContent) {
|
func (diffFile *DiffFile) GetTailSectionAndLimitedContent(leftCommit, rightCommit *git.Commit) (_ *DiffSection, diffLimitedContent DiffLimitedContent) {
|
||||||
if len(diffFile.Sections) == 0 || leftCommit == nil || diffFile.Type != DiffFileChange || diffFile.IsBin || diffFile.IsLFSFile {
|
var leftLineCount, rightLineCount int
|
||||||
|
diffLimitedContent = DiffLimitedContent{}
|
||||||
|
if diffFile.IsBin || diffFile.IsLFSFile {
|
||||||
|
return nil, diffLimitedContent
|
||||||
|
}
|
||||||
|
if (diffFile.Type == DiffFileDel || diffFile.Type == DiffFileChange) && leftCommit != nil {
|
||||||
|
leftLineCount, diffLimitedContent.LeftContent = getCommitFileLineCountAndLimitedContent(leftCommit, diffFile.OldName)
|
||||||
|
}
|
||||||
|
if (diffFile.Type == DiffFileAdd || diffFile.Type == DiffFileChange) && rightCommit != nil {
|
||||||
|
rightLineCount, diffLimitedContent.RightContent = getCommitFileLineCountAndLimitedContent(rightCommit, diffFile.OldName)
|
||||||
|
}
|
||||||
|
if len(diffFile.Sections) == 0 || diffFile.Type != DiffFileChange {
|
||||||
return nil, diffLimitedContent
|
return nil, diffLimitedContent
|
||||||
}
|
}
|
||||||
|
|
||||||
lastSection := diffFile.Sections[len(diffFile.Sections)-1]
|
lastSection := diffFile.Sections[len(diffFile.Sections)-1]
|
||||||
lastLine := lastSection.Lines[len(lastSection.Lines)-1]
|
lastLine := lastSection.Lines[len(lastSection.Lines)-1]
|
||||||
leftLineCount, leftContent := getCommitFileLineCountAndLimitedContent(leftCommit, diffFile.Name)
|
|
||||||
rightLineCount, rightContent := getCommitFileLineCountAndLimitedContent(rightCommit, diffFile.Name)
|
|
||||||
diffLimitedContent = DiffLimitedContent{LeftContent: leftContent, RightContent: rightContent}
|
|
||||||
if leftLineCount <= lastLine.LeftIdx || rightLineCount <= lastLine.RightIdx {
|
if leftLineCount <= lastLine.LeftIdx || rightLineCount <= lastLine.RightIdx {
|
||||||
return nil, diffLimitedContent
|
return nil, diffLimitedContent
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ func (hcd *highlightCodeDiff) diffLineWithHighlightWrapper(lineWrapperTags []str
|
||||||
|
|
||||||
dmp := defaultDiffMatchPatch()
|
dmp := defaultDiffMatchPatch()
|
||||||
diffs := dmp.DiffMain(convertedCodeA, convertedCodeB, true)
|
diffs := dmp.DiffMain(convertedCodeA, convertedCodeB, true)
|
||||||
diffs = dmp.DiffCleanupEfficiency(diffs)
|
diffs = dmp.DiffCleanupSemantic(diffs)
|
||||||
|
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,16 @@ func TestDiffWithHighlight(t *testing.T) {
|
||||||
assert.Equal(t, `x <span class="k"><span class="added-code">bar</span></span> y`, string(outAdd))
|
assert.Equal(t, `x <span class="k"><span class="added-code">bar</span></span> y`, string(outAdd))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("CleanUp", func(t *testing.T) {
|
||||||
|
hcd := newHighlightCodeDiff()
|
||||||
|
codeA := template.HTML(`<span class="cm>this is a comment</span>`)
|
||||||
|
codeB := template.HTML(`<span class="cm>this is updated comment</span>`)
|
||||||
|
outDel := hcd.diffLineWithHighlight(DiffLineDel, codeA, codeB)
|
||||||
|
assert.Equal(t, `<span class="cm>this is <span class="removed-code">a</span> comment</span>`, string(outDel))
|
||||||
|
outAdd := hcd.diffLineWithHighlight(DiffLineAdd, codeA, codeB)
|
||||||
|
assert.Equal(t, `<span class="cm>this is <span class="added-code">updated</span> comment</span>`, string(outAdd))
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("OpenCloseTags", func(t *testing.T) {
|
t.Run("OpenCloseTags", func(t *testing.T) {
|
||||||
hcd := newHighlightCodeDiff()
|
hcd := newHighlightCodeDiff()
|
||||||
hcd.placeholderTokenMap['O'], hcd.placeholderTokenMap['C'] = "<span>", "</span>"
|
hcd.placeholderTokenMap['O'], hcd.placeholderTokenMap['C'] = "<span>", "</span>"
|
||||||
|
|
|
@ -47,7 +47,6 @@ func TestGetDiffPreview(t *testing.T) {
|
||||||
Sections: []*gitdiff.DiffSection{
|
Sections: []*gitdiff.DiffSection{
|
||||||
{
|
{
|
||||||
FileName: "README.md",
|
FileName: "README.md",
|
||||||
Name: "",
|
|
||||||
Lines: []*gitdiff.DiffLine{
|
Lines: []*gitdiff.DiffLine{
|
||||||
{
|
{
|
||||||
LeftIdx: 0,
|
LeftIdx: 0,
|
||||||
|
|
|
@ -63,8 +63,18 @@ async function processMaterialFileIcons() {
|
||||||
}
|
}
|
||||||
fs.writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-svgs.json`, import.meta.url)), JSON.stringify(svgSymbols, null, 2));
|
fs.writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-svgs.json`, import.meta.url)), JSON.stringify(svgSymbols, null, 2));
|
||||||
|
|
||||||
const iconRules = await readFile(fileURLToPath(new URL(`../node_modules/material-icon-theme/dist/material-icons.json`, import.meta.url)));
|
const iconRulesJson = await readFile(fileURLToPath(new URL(`../node_modules/material-icon-theme/dist/material-icons.json`, import.meta.url)));
|
||||||
const iconRulesPretty = JSON.stringify(JSON.parse(iconRules), null, 2);
|
const iconRules = JSON.parse(iconRulesJson);
|
||||||
|
// The rules are from VSCode material-icon-theme, we need to adjust them to our needs
|
||||||
|
// 1. We only use lowercase filenames to match (it should be good enough for most cases and more efficient)
|
||||||
|
// 2. We do not have a "Language ID" system: https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers
|
||||||
|
// * So we just treat the "Language ID" as file extension, it is not always true, but it is good enough for most cases.
|
||||||
|
delete iconRules.iconDefinitions;
|
||||||
|
for (const [k, v] of Object.entries(iconRules.fileNames)) iconRules.fileNames[k.toLowerCase()] = v;
|
||||||
|
for (const [k, v] of Object.entries(iconRules.folderNames)) iconRules.folderNames[k.toLowerCase()] = v;
|
||||||
|
for (const [k, v] of Object.entries(iconRules.fileExtensions)) iconRules.fileExtensions[k.toLowerCase()] = v;
|
||||||
|
for (const [k, v] of Object.entries(iconRules.languageIds)) iconRules.fileExtensions[k.toLowerCase()] = v;
|
||||||
|
const iconRulesPretty = JSON.stringify(iconRules, null, 2);
|
||||||
fs.writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-rules.json`, import.meta.url)), iconRulesPretty);
|
fs.writeFileSync(fileURLToPath(new URL(`../options/fileicon/material-icon-rules.json`, import.meta.url)), iconRulesPretty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue