From e1b90212e4709cfb4de823e6e47655cf6d4f86b0 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 29 Jun 2024 17:37:18 +0200 Subject: [PATCH 1/3] Use stable version of fabric (#31526) Fabric 6 is [now stable](https://github.com/fabricjs/fabric.js/releases/tag/v6.0.0-rc5), use it. (cherry picked from commit 5821d22891cb3aa1e1c9590d8b921728b4969c5f) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 926c4a4a30..e5d29a06bb 100644 --- a/Makefile +++ b/Makefile @@ -981,7 +981,7 @@ generate-gomock: .PHONY: generate-images generate-images: | node_modules - npm install --no-save fabric@6.0.0-beta20 imagemin-zopfli@7 + npm install --no-save fabric@6 imagemin-zopfli@7 node tools/generate-images.js $(TAGS) .PHONY: generate-manpage From f92591b8256a03864e1ac56119175461f7879c8b Mon Sep 17 00:00:00 2001 From: charles <30816317+charles7668@users.noreply.github.com> Date: Sun, 30 Jun 2024 07:23:47 +0800 Subject: [PATCH 2/3] Fix markdown preview $$ support (#31514) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #31481 currently `$$A + B$$ test` will ignore text after $$ block test text ![圖片](https://github.com/go-gitea/gitea/assets/30816317/39b2974b-c0b6-48a0-87d0-5f4a13615eed) before fix ![圖片](https://github.com/go-gitea/gitea/assets/30816317/15469e4c-474d-4128-b46f-d6cadaafbd68) after fix ![圖片](https://github.com/go-gitea/gitea/assets/30816317/c1025eef-177f-4ade-988f-510e7039f3f9) github display ![圖片](https://github.com/go-gitea/gitea/assets/30816317/97cd1e10-ac94-4899-86d8-8e359ef1d694) (cherry picked from commit f0033051d5ce07f5a18d2aacef6bfdca5fc69014) --- modules/markup/markdown/markdown_test.go | 8 +++++ modules/markup/markdown/math/block_parser.go | 6 ++++ .../markup/markdown/math/inline_block_node.go | 31 +++++++++++++++++++ modules/markup/markdown/math/inline_parser.go | 30 +++++++++++++++--- .../markup/markdown/math/inline_renderer.go | 7 ++++- modules/markup/markdown/math/math.go | 3 +- 6 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 modules/markup/markdown/math/inline_block_node.go diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 68428552c4..f21c571b7f 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -552,6 +552,14 @@ func TestMathBlock(t *testing.T) { "$a$ ($b$) [$c$] {$d$}", `

a (b) [$c$] {$d$}

` + nl, }, + { + "$$a$$ test", + `

a test

` + nl, + }, + { + "test $$a$$", + `

test a

` + nl, + }, } for _, test := range testcases { diff --git a/modules/markup/markdown/math/block_parser.go b/modules/markup/markdown/math/block_parser.go index f3262c82c0..527df84975 100644 --- a/modules/markup/markdown/math/block_parser.go +++ b/modules/markup/markdown/math/block_parser.go @@ -47,6 +47,12 @@ func (b *blockParser) Open(parent ast.Node, reader text.Reader, pc parser.Contex } idx := bytes.Index(line[pos+2:], endBytes) if idx >= 0 { + // for case $$ ... $$ any other text + for i := pos + idx + 4; i < len(line); i++ { + if line[i] != ' ' && line[i] != '\n' { + return nil, parser.NoChildren + } + } segment.Stop = segment.Start + idx + 2 reader.Advance(segment.Len() - 1) segment.Start += 2 diff --git a/modules/markup/markdown/math/inline_block_node.go b/modules/markup/markdown/math/inline_block_node.go new file mode 100644 index 0000000000..c92d0c8d84 --- /dev/null +++ b/modules/markup/markdown/math/inline_block_node.go @@ -0,0 +1,31 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package math + +import ( + "github.com/yuin/goldmark/ast" +) + +// InlineBlock represents inline math e.g. $$...$$ +type InlineBlock struct { + Inline +} + +// InlineBlock implements InlineBlock. +func (n *InlineBlock) InlineBlock() {} + +// KindInlineBlock is the kind for math inline block +var KindInlineBlock = ast.NewNodeKind("MathInlineBlock") + +// Kind returns KindInlineBlock +func (n *InlineBlock) Kind() ast.NodeKind { + return KindInlineBlock +} + +// NewInlineBlock creates a new ast math inline block node +func NewInlineBlock() *InlineBlock { + return &InlineBlock{ + Inline{}, + } +} diff --git a/modules/markup/markdown/math/inline_parser.go b/modules/markup/markdown/math/inline_parser.go index 614cf329af..b11195d551 100644 --- a/modules/markup/markdown/math/inline_parser.go +++ b/modules/markup/markdown/math/inline_parser.go @@ -21,11 +21,20 @@ var defaultInlineDollarParser = &inlineParser{ end: []byte{'$'}, } +var defaultDualDollarParser = &inlineParser{ + start: []byte{'$', '$'}, + end: []byte{'$', '$'}, +} + // NewInlineDollarParser returns a new inline parser func NewInlineDollarParser() parser.InlineParser { return defaultInlineDollarParser } +func NewInlineDualDollarParser() parser.InlineParser { + return defaultDualDollarParser +} + var defaultInlineBracketParser = &inlineParser{ start: []byte{'\\', '('}, end: []byte{'\\', ')'}, @@ -38,7 +47,7 @@ func NewInlineBracketParser() parser.InlineParser { // Trigger triggers this parser on $ or \ func (parser *inlineParser) Trigger() []byte { - return parser.start[0:1] + return parser.start } func isPunctuation(b byte) bool { @@ -88,7 +97,11 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser. break } suceedingCharacter := line[pos] - if !isPunctuation(suceedingCharacter) && !(suceedingCharacter == ' ') && !isBracket(suceedingCharacter) { + // check valid ending character + if !isPunctuation(suceedingCharacter) && + !(suceedingCharacter == ' ') && + !(suceedingCharacter == '\n') && + !isBracket(suceedingCharacter) { return nil } if line[ender-1] != '\\' { @@ -101,12 +114,21 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser. block.Advance(opener) _, pos := block.Position() - node := NewInline() + var node ast.Node + if parser == defaultDualDollarParser { + node = NewInlineBlock() + } else { + node = NewInline() + } segment := pos.WithStop(pos.Start + ender - opener) node.AppendChild(node, ast.NewRawTextSegment(segment)) block.Advance(ender - opener + len(parser.end)) - trimBlock(node, block) + if parser == defaultDualDollarParser { + trimBlock(&(node.(*InlineBlock)).Inline, block) + } else { + trimBlock(node.(*Inline), block) + } return node } diff --git a/modules/markup/markdown/math/inline_renderer.go b/modules/markup/markdown/math/inline_renderer.go index b4e9ade0ae..96848099cc 100644 --- a/modules/markup/markdown/math/inline_renderer.go +++ b/modules/markup/markdown/math/inline_renderer.go @@ -21,7 +21,11 @@ func NewInlineRenderer() renderer.NodeRenderer { func (r *InlineRenderer) renderInline(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { if entering { - _, _ = w.WriteString(``) + extraClass := "" + if _, ok := n.(*InlineBlock); ok { + extraClass = "display " + } + _, _ = w.WriteString(``) for c := n.FirstChild(); c != nil; c = c.NextSibling() { segment := c.(*ast.Text).Segment value := util.EscapeHTML(segment.Value(source)) @@ -43,4 +47,5 @@ func (r *InlineRenderer) renderInline(w util.BufWriter, source []byte, n ast.Nod // RegisterFuncs registers the renderer for inline math nodes func (r *InlineRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { reg.Register(KindInline, r.renderInline) + reg.Register(KindInlineBlock, r.renderInline) } diff --git a/modules/markup/markdown/math/math.go b/modules/markup/markdown/math/math.go index 8a50753574..3d9f376bc6 100644 --- a/modules/markup/markdown/math/math.go +++ b/modules/markup/markdown/math/math.go @@ -96,7 +96,8 @@ func (e *Extension) Extend(m goldmark.Markdown) { util.Prioritized(NewInlineBracketParser(), 501), } if e.parseDollarInline { - inlines = append(inlines, util.Prioritized(NewInlineDollarParser(), 501)) + inlines = append(inlines, util.Prioritized(NewInlineDollarParser(), 503), + util.Prioritized(NewInlineDualDollarParser(), 502)) } m.Parser().AddOptions(parser.WithInlineParsers(inlines...)) From 33f9fb815097f2c179f31892a940e5e0231bb435 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 4 Jul 2024 20:57:11 +0200 Subject: [PATCH 3/3] Fix slow patch checking with commits that add or remove many files (#31548) Running git update-index for every individual file is slow, so add and remove everything with a single git command. When such a big commit lands in the default branch, it could cause PR creation and patch checking for all open PRs to be slow, or time out entirely. For example, a commit that removes 1383 files was measured to take more than 60 seconds and timed out. With this change checking took about a second. This is related to #27967, though this will not help with commits that change many lines in few files. (cherry picked from commit b88e5fc72d99e9d4a0aa9c13f70e0a9e967fe057) --- modules/git/repo_index.go | 35 +++++++++++++++++++++++++++-------- services/pull/patch.go | 29 +++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/modules/git/repo_index.go b/modules/git/repo_index.go index 6aaab242c1..8390570098 100644 --- a/modules/git/repo_index.go +++ b/modules/git/repo_index.go @@ -104,11 +104,8 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error { buffer := new(bytes.Buffer) for _, file := range filenames { if file != "" { - buffer.WriteString("0 ") - buffer.WriteString(objectFormat.EmptyObjectID().String()) - buffer.WriteByte('\t') - buffer.WriteString(file) - buffer.WriteByte('\000') + // using format: mode SP type SP sha1 TAB path + buffer.WriteString("0 blob " + objectFormat.EmptyObjectID().String() + "\t" + file + "\000") } } return cmd.Run(&RunOpts{ @@ -119,11 +116,33 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error { }) } +type IndexObjectInfo struct { + Mode string + Object ObjectID + Filename string +} + +// AddObjectsToIndex adds the provided object hashes to the index at the provided filenames +func (repo *Repository) AddObjectsToIndex(objects ...IndexObjectInfo) error { + cmd := NewCommand(repo.Ctx, "update-index", "--add", "--replace", "-z", "--index-info") + stdout := new(bytes.Buffer) + stderr := new(bytes.Buffer) + buffer := new(bytes.Buffer) + for _, object := range objects { + // using format: mode SP type SP sha1 TAB path + buffer.WriteString(object.Mode + " blob " + object.Object.String() + "\t" + object.Filename + "\000") + } + return cmd.Run(&RunOpts{ + Dir: repo.Path, + Stdin: bytes.NewReader(buffer.Bytes()), + Stdout: stdout, + Stderr: stderr, + }) +} + // AddObjectToIndex adds the provided object hash to the index at the provided filename func (repo *Repository) AddObjectToIndex(mode string, object ObjectID, filename string) error { - cmd := NewCommand(repo.Ctx, "update-index", "--add", "--replace", "--cacheinfo").AddDynamicArguments(mode, object.String(), filename) - _, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path}) - return err + return repo.AddObjectsToIndex(IndexObjectInfo{Mode: mode, Object: object, Filename: filename}) } // WriteTree writes the current index as a tree to the object db and returns its hash diff --git a/services/pull/patch.go b/services/pull/patch.go index 12b79a0625..e90b4bdbbe 100644 --- a/services/pull/patch.go +++ b/services/pull/patch.go @@ -128,7 +128,7 @@ func (e *errMergeConflict) Error() string { return fmt.Sprintf("conflict detected at: %s", e.filename) } -func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, gitRepo *git.Repository) error { +func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, filesToRemove *[]string, filesToAdd *[]git.IndexObjectInfo) error { log.Trace("Attempt to merge:\n%v", file) switch { @@ -142,14 +142,13 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g } // Not a genuine conflict and we can simply remove the file from the index - return gitRepo.RemoveFilesFromIndex(file.stage1.path) + *filesToRemove = append(*filesToRemove, file.stage1.path) + return nil case file.stage1 == nil && file.stage2 != nil && (file.stage3 == nil || file.stage2.SameAs(file.stage3)): // 2. Added in ours but not in theirs or identical in both // // Not a genuine conflict just add to the index - if err := gitRepo.AddObjectToIndex(file.stage2.mode, git.MustIDFromString(file.stage2.sha), file.stage2.path); err != nil { - return err - } + *filesToAdd = append(*filesToAdd, git.IndexObjectInfo{Mode: file.stage2.mode, Object: git.MustIDFromString(file.stage2.sha), Filename: file.stage2.path}) return nil case file.stage1 == nil && file.stage2 != nil && file.stage3 != nil && file.stage2.sha == file.stage3.sha && file.stage2.mode != file.stage3.mode: // 3. Added in both with the same sha but the modes are different @@ -160,7 +159,8 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g // 4. Added in theirs but not ours: // // Not a genuine conflict just add to the index - return gitRepo.AddObjectToIndex(file.stage3.mode, git.MustIDFromString(file.stage3.sha), file.stage3.path) + *filesToAdd = append(*filesToAdd, git.IndexObjectInfo{Mode: file.stage3.mode, Object: git.MustIDFromString(file.stage3.sha), Filename: file.stage3.path}) + return nil case file.stage1 == nil: // 5. Created by new in both // @@ -221,7 +221,8 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g return err } hash = strings.TrimSpace(hash) - return gitRepo.AddObjectToIndex(file.stage2.mode, git.MustIDFromString(hash), file.stage2.path) + *filesToAdd = append(*filesToAdd, git.IndexObjectInfo{Mode: file.stage2.mode, Object: git.MustIDFromString(hash), Filename: file.stage2.path}) + return nil default: if file.stage1 != nil { return &errMergeConflict{file.stage1.path} @@ -245,6 +246,9 @@ func AttemptThreeWayMerge(ctx context.Context, gitPath string, gitRepo *git.Repo return false, nil, fmt.Errorf("unable to run read-tree -m! Error: %w", err) } + var filesToRemove []string + var filesToAdd []git.IndexObjectInfo + // Then we use git ls-files -u to list the unmerged files and collate the triples in unmergedfiles unmerged := make(chan *unmergedFile) go unmergedFiles(ctx, gitPath, unmerged) @@ -270,7 +274,7 @@ func AttemptThreeWayMerge(ctx context.Context, gitPath string, gitRepo *git.Repo } // OK now we have the unmerged file triplet attempt to merge it - if err := attemptMerge(ctx, file, gitPath, gitRepo); err != nil { + if err := attemptMerge(ctx, file, gitPath, &filesToRemove, &filesToAdd); err != nil { if conflictErr, ok := err.(*errMergeConflict); ok { log.Trace("Conflict: %s in %s", conflictErr.filename, description) conflict = true @@ -283,6 +287,15 @@ func AttemptThreeWayMerge(ctx context.Context, gitPath string, gitRepo *git.Repo return false, nil, err } } + + // Add and remove files in one command, as this is slow with many files otherwise + if err := gitRepo.RemoveFilesFromIndex(filesToRemove...); err != nil { + return false, nil, err + } + if err := gitRepo.AddObjectsToIndex(filesToAdd...); err != nil { + return false, nil, err + } + return conflict, conflictedFiles, nil }