mirror of
				https://gitea.com/gitea/tea.git
				synced 2025-10-31 09:15:26 +01:00 
			
		
		
		
	Add commands for reviews (#315)
add interactive `tea pr review` it's amazingly simple vendor gitea.com/noerw/unidiff-comments add `tea pr lgtm|reject` shorthands vendor slimmed down diff parser review diff: default to true if users want a shortcut, they can use lgtm or reject subcmds `tea pr approve`: accept optional comment Co-authored-by: Norwin Roosen <git@nroo.de> Reviewed-on: https://gitea.com/gitea/tea/pulls/315 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-by: 6543 <6543@obermui.de> Co-Authored-By: Norwin <noerw@noreply.gitea.io> Co-Committed-By: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
		
							
								
								
									
										459
									
								
								vendor/gitea.com/noerw/unidiff-comments/changeset_reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										459
									
								
								vendor/gitea.com/noerw/unidiff-comments/changeset_reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,459 @@ | ||||
| package unidiff | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"gitea.com/noerw/unidiff-comments/types" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	stateStartOfDiff       = "stateStartOfDiff" | ||||
| 	stateDiffHeader        = "stateDiffHeader" | ||||
| 	stateHunkHeader        = "stateHunkHeader" | ||||
| 	stateHunkBody          = "stateHunkBody" | ||||
| 	stateComment           = "stateComment" | ||||
| 	stateCommentDelim      = "stateCommentDelim" | ||||
| 	stateCommentHeader     = "stateCommentHeader" | ||||
| 	stateDiffComment       = "stateDiffComment" | ||||
| 	stateDiffCommentDelim  = "stateDiffCommentDelim" | ||||
| 	stateDiffCommentHeader = "stateDiffCommentHeader" | ||||
|  | ||||
| 	ignorePrefix = "###" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	reDiffHeader = regexp.MustCompile( | ||||
| 		`^--- |^\+\+\+ `) | ||||
|  | ||||
| 	reGitDiffHeader = regexp.MustCompile( | ||||
| 		`^diff |^index `) | ||||
|  | ||||
| 	reFromFile = regexp.MustCompile( | ||||
| 		`^--- (\S+)(\s+(.*))`) | ||||
|  | ||||
| 	reToFile = regexp.MustCompile( | ||||
| 		`^\+\+\+ (\S+)(\s+(.*))`) | ||||
|  | ||||
| 	reHunk = regexp.MustCompile( | ||||
| 		`^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@`) | ||||
|  | ||||
| 	reSegmentContext = regexp.MustCompile( | ||||
| 		`^ `) | ||||
|  | ||||
| 	reSegmentAdded = regexp.MustCompile( | ||||
| 		`^\+`) | ||||
|  | ||||
| 	reSegmentRemoved = regexp.MustCompile( | ||||
| 		`^-`) | ||||
|  | ||||
| 	reCommentDelim = regexp.MustCompile( | ||||
| 		`^#\s+---`) | ||||
|  | ||||
| 	reCommentHeader = regexp.MustCompile( | ||||
| 		`^#\s+\[(\d+)@(\d+)\]\s+\|([^|]+)\|(.*)`) | ||||
|  | ||||
| 	reCommentText = regexp.MustCompile( | ||||
| 		`^#(\s*)(.*)\s*`) | ||||
|  | ||||
| 	reIndent = regexp.MustCompile( | ||||
| 		`^#(\s+)`) | ||||
|  | ||||
| 	reEmptyLine = regexp.MustCompile( | ||||
| 		`^\n$`) | ||||
|  | ||||
| 	reIgnoredLine = regexp.MustCompile( | ||||
| 		`^` + ignorePrefix) | ||||
| ) | ||||
|  | ||||
| type parser struct { | ||||
| 	state      string | ||||
| 	changeset  types.Changeset | ||||
| 	diff       *types.Diff | ||||
| 	hunk       *types.Hunk | ||||
| 	segment    *types.Segment | ||||
| 	comment    *types.Comment | ||||
| 	line       *types.Line | ||||
| 	lineNumber int | ||||
|  | ||||
| 	segmentType  string | ||||
| 	commentsList []*types.Comment | ||||
| } | ||||
|  | ||||
| type Error struct { | ||||
| 	LineNumber int | ||||
| 	Message    string | ||||
| } | ||||
|  | ||||
| func (err Error) Error() string { | ||||
| 	return fmt.Sprintf("line %d: %s", err.LineNumber, err.Message) | ||||
| } | ||||
|  | ||||
| func ReadChangeset(r io.Reader) (types.Changeset, error) { | ||||
| 	buffer := bufio.NewReader(r) | ||||
|  | ||||
| 	current := parser{} | ||||
| 	current.state = stateStartOfDiff | ||||
|  | ||||
| 	for { | ||||
| 		current.lineNumber++ | ||||
|  | ||||
| 		line, err := buffer.ReadString('\n') | ||||
| 		if err != nil { | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		if reIgnoredLine.MatchString(line) { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		err = current.switchState(line) | ||||
| 		if err != nil { | ||||
| 			return current.changeset, err | ||||
| 		} | ||||
|  | ||||
| 		err = current.createNodes(line) | ||||
| 		if err != nil { | ||||
| 			return current.changeset, err | ||||
| 		} | ||||
|  | ||||
| 		err = current.locateNodes(line) | ||||
| 		if err != nil { | ||||
| 			return current.changeset, err | ||||
| 		} | ||||
|  | ||||
| 		err = current.parseLine(line) | ||||
| 		if err != nil { | ||||
| 			return current.changeset, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, comment := range current.commentsList { | ||||
| 		comment.Text = strings.TrimSpace(comment.Text) | ||||
| 	} | ||||
|  | ||||
| 	return current.changeset, nil | ||||
| } | ||||
|  | ||||
| func (current *parser) switchState(line string) error { | ||||
| 	inComment := false | ||||
|  | ||||
| 	switch current.state { | ||||
| 	case stateStartOfDiff: | ||||
| 		switch { | ||||
| 		case reDiffHeader.MatchString(line), reGitDiffHeader.MatchString(line): | ||||
| 			current.state = stateDiffHeader | ||||
| 		case reCommentText.MatchString(line): | ||||
| 			inComment = true | ||||
| 		case reEmptyLine.MatchString(line): | ||||
| 			// body intentionally left empty | ||||
| 		default: | ||||
| 			return Error{ | ||||
| 				current.lineNumber, | ||||
| 				"expected diff header, but none found", | ||||
| 			} | ||||
| 		} | ||||
| 	case stateDiffHeader: | ||||
| 		switch { | ||||
| 		case reHunk.MatchString(line): | ||||
| 			current.state = stateHunkHeader | ||||
| 		} | ||||
| 	case stateDiffComment, stateDiffCommentDelim, stateDiffCommentHeader: | ||||
| 		switch { | ||||
| 		case reDiffHeader.MatchString(line), reGitDiffHeader.MatchString(line): | ||||
| 			current.state = stateDiffHeader | ||||
| 		case reCommentText.MatchString(line): | ||||
| 			inComment = true | ||||
| 		case reEmptyLine.MatchString(line): | ||||
| 			current.state = stateStartOfDiff | ||||
| 		} | ||||
| 	case stateHunkHeader: | ||||
| 		current.state = stateHunkBody | ||||
| 		fallthrough | ||||
| 	case stateHunkBody, stateComment, stateCommentDelim, stateCommentHeader: | ||||
| 		switch { | ||||
| 		case reSegmentContext.MatchString(line): | ||||
| 			current.state = stateHunkBody | ||||
| 			current.segmentType = types.SegmentTypeContext | ||||
| 		case reSegmentRemoved.MatchString(line): | ||||
| 			current.state = stateHunkBody | ||||
| 			current.segmentType = types.SegmentTypeRemoved | ||||
| 		case reSegmentAdded.MatchString(line): | ||||
| 			current.state = stateHunkBody | ||||
| 			current.segmentType = types.SegmentTypeAdded | ||||
| 		case reHunk.MatchString(line): | ||||
| 			current.state = stateHunkHeader | ||||
| 		case reCommentText.MatchString(line): | ||||
| 			inComment = true | ||||
| 		case reGitDiffHeader.MatchString(line): | ||||
| 			current.state = stateDiffHeader | ||||
| 			current.diff = nil | ||||
| 			current.hunk = nil | ||||
| 			current.segment = nil | ||||
| 			current.line = nil | ||||
| 		case reEmptyLine.MatchString(line): | ||||
| 			current.state = stateStartOfDiff | ||||
| 			current.diff = nil | ||||
| 			current.hunk = nil | ||||
| 			current.segment = nil | ||||
| 			current.line = nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if !inComment { | ||||
| 		current.comment = nil | ||||
| 	} else { | ||||
| 		switch current.state { | ||||
| 		case stateStartOfDiff: | ||||
| 			fallthrough | ||||
| 		case stateDiffComment, stateDiffCommentDelim, stateDiffCommentHeader: | ||||
| 			switch { | ||||
| 			case reCommentDelim.MatchString(line): | ||||
| 				current.state = stateDiffCommentDelim | ||||
| 			case reCommentHeader.MatchString(line): | ||||
| 				current.state = stateDiffCommentHeader | ||||
| 			case reCommentText.MatchString(line): | ||||
| 				current.state = stateDiffComment | ||||
| 			} | ||||
| 		case stateHunkBody: | ||||
| 			fallthrough | ||||
| 		case stateComment, stateCommentDelim, stateCommentHeader: | ||||
| 			switch { | ||||
| 			case reCommentDelim.MatchString(line): | ||||
| 				current.state = stateCommentDelim | ||||
| 			case reCommentHeader.MatchString(line): | ||||
| 				current.state = stateCommentHeader | ||||
| 			case reCommentText.MatchString(line): | ||||
| 				current.state = stateComment | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Uncomment for debug state switching | ||||
| 	// fmt.Printf("%20s : %#v\n", current.state, line) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (current *parser) createNodes(line string) error { | ||||
| 	switch current.state { | ||||
| 	case stateDiffComment: | ||||
| 		if current.comment != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		fallthrough | ||||
| 	case stateDiffCommentDelim, stateDiffCommentHeader: | ||||
| 		current.comment = &types.Comment{} | ||||
| 		fallthrough | ||||
| 	case stateDiffHeader: | ||||
| 		if current.diff == nil { | ||||
| 			current.diff = &types.Diff{} | ||||
| 			current.changeset.Diffs = append(current.changeset.Diffs, | ||||
| 				current.diff) | ||||
| 		} | ||||
| 	case stateHunkHeader: | ||||
| 		current.hunk = &types.Hunk{} | ||||
| 		current.segment = &types.Segment{} | ||||
| 	case stateCommentDelim, stateCommentHeader: | ||||
| 		current.comment = &types.Comment{} | ||||
| 	case stateComment: | ||||
| 		if current.comment == nil { | ||||
| 			current.comment = &types.Comment{} | ||||
| 		} | ||||
| 	case stateHunkBody: | ||||
| 		if current.segment.Type != current.segmentType { | ||||
| 			current.segment = &types.Segment{Type: current.segmentType} | ||||
| 			current.hunk.Segments = append(current.hunk.Segments, | ||||
| 				current.segment) | ||||
| 		} | ||||
|  | ||||
| 		current.line = &types.Line{} | ||||
| 		current.segment.Lines = append(current.segment.Lines, current.line) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (current *parser) locateNodes(line string) error { | ||||
| 	switch current.state { | ||||
| 	case stateComment, stateDiffComment: | ||||
| 		current.locateComment(line) | ||||
| 	case stateHunkBody: | ||||
| 		current.locateLine(line) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (current *parser) locateComment(line string) error { | ||||
| 	if current.comment.Parented || strings.TrimSpace(line) == "#" { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	current.commentsList = append(current.commentsList, current.comment) | ||||
| 	current.comment.Parented = true | ||||
|  | ||||
| 	if current.hunk != nil { | ||||
| 		current.comment.Anchor.LineType = current.segment.Type | ||||
| 		current.comment.Anchor.Line = current.segment.GetLineNum(current.line) | ||||
| 		current.comment.Anchor.Path = current.diff.Destination.ToString | ||||
| 		current.comment.Anchor.SrcPath = current.diff.Source.ToString | ||||
| 	} | ||||
|  | ||||
| 	current.comment.Indent = getIndentSize(line) | ||||
|  | ||||
| 	parent := current.findParentComment(current.comment) | ||||
| 	if parent != nil { | ||||
| 		parent.Comments = append(parent.Comments, current.comment) | ||||
| 	} else { | ||||
| 		if current.line != nil { | ||||
| 			current.diff.LineComments = append(current.diff.LineComments, | ||||
| 				current.comment) | ||||
| 			current.line.Comments = append(current.line.Comments, | ||||
| 				current.comment) | ||||
| 		} else { | ||||
| 			current.diff.FileComments = append(current.diff.FileComments, | ||||
| 				current.comment) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (current *parser) locateLine(line string) error { | ||||
| 	sourceOffset := current.hunk.SourceLine - 1 | ||||
| 	destinationOffset := current.hunk.DestinationLine - 1 | ||||
| 	if len(current.hunk.Segments) > 1 { | ||||
| 		prevSegment := current.hunk.Segments[len(current.hunk.Segments)-2] | ||||
| 		lastLine := prevSegment.Lines[len(prevSegment.Lines)-1] | ||||
| 		sourceOffset = lastLine.Source | ||||
| 		destinationOffset = lastLine.Destination | ||||
| 	} | ||||
| 	hunkLength := int64(len(current.segment.Lines)) | ||||
| 	switch current.segment.Type { | ||||
| 	case types.SegmentTypeContext: | ||||
| 		current.line.Source = sourceOffset + hunkLength | ||||
| 		current.line.Destination = destinationOffset + hunkLength | ||||
| 	case types.SegmentTypeAdded: | ||||
| 		current.line.Source = sourceOffset | ||||
| 		current.line.Destination = destinationOffset + hunkLength | ||||
| 	case types.SegmentTypeRemoved: | ||||
| 		current.line.Source = sourceOffset + hunkLength | ||||
| 		current.line.Destination = destinationOffset | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (current *parser) parseLine(line string) error { | ||||
| 	switch current.state { | ||||
| 	case stateDiffHeader: | ||||
| 		current.parseDiffHeader(line) | ||||
| 	case stateHunkHeader: | ||||
| 		current.parseHunkHeader(line) | ||||
| 	case stateHunkBody: | ||||
| 		current.parseHunkBody(line) | ||||
| 	case stateComment, stateDiffComment: | ||||
| 		current.parseComment(line) | ||||
| 	case stateCommentHeader, stateDiffCommentHeader: | ||||
| 		current.parseCommentHeader(line) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (current *parser) parseDiffHeader(line string) error { | ||||
| 	switch { | ||||
| 	case reFromFile.MatchString(line): | ||||
| 		matches := reFromFile.FindStringSubmatch(line) | ||||
| 		current.changeset.Path = matches[1] | ||||
| 		current.diff.Source.ToString = matches[1] | ||||
| 		current.changeset.FromHash = matches[3] | ||||
| 		current.diff.Attributes.FromHash = []string{matches[3]} | ||||
| 	case reToFile.MatchString(line): | ||||
| 		matches := reToFile.FindStringSubmatch(line) | ||||
| 		current.diff.Destination.ToString = matches[1] | ||||
| 		current.changeset.ToHash = matches[3] | ||||
| 		current.diff.Attributes.ToHash = []string{matches[3]} | ||||
| 	default: | ||||
| 		return Error{ | ||||
| 			current.lineNumber, | ||||
| 			"expected diff header, but not found", | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (current *parser) parseHunkHeader(line string) error { | ||||
| 	matches := reHunk.FindStringSubmatch(line) | ||||
| 	current.hunk.SourceLine, _ = strconv.ParseInt(matches[1], 10, 64) | ||||
| 	current.hunk.SourceSpan, _ = strconv.ParseInt(matches[3], 10, 64) | ||||
| 	current.hunk.DestinationLine, _ = strconv.ParseInt(matches[4], 10, 64) | ||||
| 	current.hunk.DestinationSpan, _ = strconv.ParseInt(matches[6], 10, 64) | ||||
| 	current.diff.Hunks = append(current.diff.Hunks, current.hunk) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (current *parser) parseHunkBody(line string) error { | ||||
| 	current.line.Line = line[1 : len(line)-1] | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (current *parser) parseCommentHeader(line string) error { | ||||
| 	matches := reCommentHeader.FindStringSubmatch(line) | ||||
| 	current.comment.Author.DisplayName = strings.TrimSpace(matches[3]) | ||||
| 	current.comment.Id, _ = strconv.ParseInt(matches[1], 10, 64) | ||||
| 	updatedDate, _ := time.ParseInLocation(time.ANSIC, | ||||
| 		strings.TrimSpace(matches[4]), | ||||
| 		time.Local) | ||||
| 	current.comment.UpdatedDate = types.UnixTimestamp(updatedDate.Unix() * 1000) | ||||
|  | ||||
| 	version, _ := strconv.ParseInt(matches[2], 10, 64) | ||||
| 	current.comment.Version = int(version) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (current *parser) parseComment(line string) error { | ||||
| 	matches := reCommentText.FindStringSubmatch(line) | ||||
| 	if len(matches[1]) < current.comment.Indent { | ||||
| 		return Error{ | ||||
| 			LineNumber: current.lineNumber, | ||||
| 			Message: fmt.Sprintf( | ||||
| 				"unexpected indent, should be at least: %d", | ||||
| 				current.comment.Indent, | ||||
| 			), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	indentedLine := matches[1][current.comment.Indent:] + matches[2] | ||||
| 	current.comment.Text += "\n" + indentedLine | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (current *parser) findParentComment(comment *types.Comment) *types.Comment { | ||||
| 	for i := len(current.commentsList) - 1; i >= 0; i-- { | ||||
| 		c := current.commentsList[i] | ||||
| 		if comment.Indent > c.Indent { | ||||
| 			return c | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func getIndentSize(line string) int { | ||||
| 	matches := reIndent.FindStringSubmatch(line) | ||||
| 	if len(matches) == 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
|  | ||||
| 	return len(matches[1]) | ||||
| } | ||||
							
								
								
									
										5
									
								
								vendor/gitea.com/noerw/unidiff-comments/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/gitea.com/noerw/unidiff-comments/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| module gitea.com/noerw/unidiff-comments | ||||
|  | ||||
| go 1.15 | ||||
|  | ||||
| require github.com/seletskiy/tplutil v0.0.0-20200921103632-f880f6245597 | ||||
							
								
								
									
										2
									
								
								vendor/gitea.com/noerw/unidiff-comments/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								vendor/gitea.com/noerw/unidiff-comments/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| github.com/seletskiy/tplutil v0.0.0-20200921103632-f880f6245597 h1:nZY1S2jo+VtDrUfjO9XYI137O41hhRkxZNV5Fb5ixCA= | ||||
| github.com/seletskiy/tplutil v0.0.0-20200921103632-f880f6245597/go.mod h1:F8CBHSOjnzjx9EeXyWJTAzJyVxN+Y8JH2WjLMn4utiw= | ||||
							
								
								
									
										47
									
								
								vendor/gitea.com/noerw/unidiff-comments/types/changeset.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								vendor/gitea.com/noerw/unidiff-comments/types/changeset.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| package types | ||||
|  | ||||
| type Changeset struct { | ||||
| 	FromHash   string | ||||
| 	ToHash     string | ||||
| 	Path       string | ||||
| 	Whitespace string | ||||
| 	Diffs      []*Diff | ||||
| } | ||||
|  | ||||
| func (r Changeset) ForEachComment(callback func(*Diff, *Comment, *Comment)) { | ||||
| 	for _, diff := range r.Diffs { | ||||
| 		stack := make([]*Comment, 0) | ||||
| 		parents := make(map[*Comment]*Comment) | ||||
| 		stack = append(stack, diff.FileComments...) | ||||
| 		stack = append(stack, diff.LineComments...) | ||||
| 		pos := 0 | ||||
|  | ||||
| 		for pos < len(stack) { | ||||
| 			comment := stack[pos] | ||||
|  | ||||
| 			if comment.Comments != nil { | ||||
| 				stack = append(stack, comment.Comments...) | ||||
| 				for _, c := range comment.Comments { | ||||
| 					parents[c] = comment | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			callback(diff, comment, parents[comment]) | ||||
|  | ||||
| 			pos++ | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (r Changeset) ForEachLine( | ||||
| 	callback func(*Diff, *Hunk, *Segment, *Line) error, | ||||
| ) error { | ||||
| 	for _, diff := range r.Diffs { | ||||
| 		err := diff.ForEachLine(callback) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										121
									
								
								vendor/gitea.com/noerw/unidiff-comments/types/comment.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								vendor/gitea.com/noerw/unidiff-comments/types/comment.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| package types | ||||
|  | ||||
| import ( | ||||
| 	"regexp" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type UnixTimestamp int | ||||
|  | ||||
| func (u UnixTimestamp) String() string { | ||||
| 	return time.Unix(int64(u/1000), 0).Format(time.ANSIC) | ||||
| } | ||||
|  | ||||
| type Comment struct { | ||||
| 	Id          int64 | ||||
| 	Version     int | ||||
| 	Text        string | ||||
| 	CreatedDate UnixTimestamp | ||||
| 	UpdatedDate UnixTimestamp | ||||
| 	Comments    CommentsTree | ||||
| 	Author      struct { | ||||
| 		Name         string | ||||
| 		EmailAddress string | ||||
| 		Id           int | ||||
| 		DisplayName  string | ||||
| 		Active       bool | ||||
| 		Slug         string | ||||
| 		Type         string | ||||
| 	} | ||||
|  | ||||
| 	Anchor CommentAnchor | ||||
|  | ||||
| 	PermittedOperations struct { | ||||
| 		Editable  bool | ||||
| 		Deletable bool | ||||
| 	} | ||||
|  | ||||
| 	Indent   int | ||||
| 	Parented bool | ||||
| } | ||||
|  | ||||
| type CommentAnchor struct { | ||||
| 	FromHash string | ||||
| 	ToHash   string | ||||
| 	Line     int64  `json:"line"` | ||||
| 	LineType string `json:"lineType"` | ||||
| 	Path     string `json:"path"` | ||||
| 	SrcPath  string `json:"srcPath"` | ||||
| 	FileType string `json:"fileType"` | ||||
| } | ||||
|  | ||||
| type CommentsTree []*Comment | ||||
|  | ||||
| //const replyIndent = "    " | ||||
|  | ||||
| var begOfLineRe = regexp.MustCompile("(?m)^") | ||||
|  | ||||
| //func (c Comment) String() string { | ||||
| //    comments, _ := commentTpl.Execute(c) | ||||
|  | ||||
| //    for _, reply := range c.Comments { | ||||
| //        comments += reply.AsReply() | ||||
| //    } | ||||
|  | ||||
| //    return comments | ||||
| //} | ||||
|  | ||||
| //func (c Comment) AsReply() string { | ||||
| //    return begOfLineRe.ReplaceAllString( | ||||
| //        commentSpacing+c.String(), | ||||
| //        replyIndent, | ||||
| //    ) | ||||
| //} | ||||
|  | ||||
| var reWhiteSpace = regexp.MustCompile(`\s+`) | ||||
|  | ||||
| func (c Comment) Short(length int) string { | ||||
| 	sticked := []rune(reWhiteSpace.ReplaceAllString(c.Text, " ")) | ||||
|  | ||||
| 	if len(sticked) > length { | ||||
| 		return string(sticked[:length]) + "..." | ||||
| 	} else { | ||||
| 		return string(sticked) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| const ignorePrefix = "###" | ||||
|  | ||||
| var reBeginningOfLine = regexp.MustCompile(`(?m)^`) | ||||
| var reIgnorePrefixSpace = regexp.MustCompile("(?m)^" + ignorePrefix + " $") | ||||
|  | ||||
| func Note(String string) string { | ||||
| 	return reIgnorePrefixSpace.ReplaceAllString( | ||||
| 		reBeginningOfLine.ReplaceAllString(String, ignorePrefix+" "), | ||||
| 		ignorePrefix) | ||||
| } | ||||
|  | ||||
| //const commentSpacing = "\n\n" | ||||
| //const commentPrefix = "# " | ||||
|  | ||||
| //func (comments CommentsTree) String() string { | ||||
| //    res := "" | ||||
|  | ||||
| //    if len(comments) > 0 { | ||||
| //        res = "---" + commentSpacing | ||||
| //    } | ||||
|  | ||||
| //    for i, comment := range comments { | ||||
| //        res += comment.String() | ||||
| //        if i < len(comments)-1 { | ||||
| //            res += commentSpacing | ||||
| //        } | ||||
| //    } | ||||
|  | ||||
| //    if len(comments) > 0 { | ||||
| //        return danglingSpacesRe.ReplaceAllString( | ||||
| //            begOfLineRe.ReplaceAllString(res, "# "), "") | ||||
| //    } else { | ||||
| //        return "" | ||||
| //    } | ||||
| //} | ||||
							
								
								
									
										61
									
								
								vendor/gitea.com/noerw/unidiff-comments/types/diff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								vendor/gitea.com/noerw/unidiff-comments/types/diff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| package types | ||||
|  | ||||
| type Diff struct { | ||||
| 	Truncated bool | ||||
| 	Source    struct { | ||||
| 		Parent   string | ||||
| 		Name     string | ||||
| 		ToString string | ||||
| 	} | ||||
| 	Destination struct { | ||||
| 		Parent   string | ||||
| 		Name     string | ||||
| 		ToString string | ||||
| 	} | ||||
| 	Hunks []*Hunk | ||||
|  | ||||
| 	FileComments CommentsTree | ||||
| 	LineComments CommentsTree | ||||
|  | ||||
| 	Note string | ||||
|  | ||||
| 	// Lists made only for Stash API compatibility. | ||||
| 	// TODO: move it to `ash`. | ||||
| 	Attributes struct { | ||||
| 		FromHash []string | ||||
| 		ToHash   []string | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (d Diff) GetHashFrom() string { | ||||
| 	if len(d.Attributes.FromHash) > 0 { | ||||
| 		return d.Attributes.FromHash[0] | ||||
| 	} else { | ||||
| 		return "???" | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (d Diff) GetHashTo() string { | ||||
| 	if len(d.Attributes.ToHash) > 0 { | ||||
| 		return d.Attributes.ToHash[0] | ||||
| 	} else { | ||||
| 		return "???" | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (d Diff) ForEachLine( | ||||
| 	callback func(*Diff, *Hunk, *Segment, *Line) error, | ||||
| ) error { | ||||
| 	for _, hunk := range d.Hunks { | ||||
| 		for _, segment := range hunk.Segments { | ||||
| 			for _, line := range segment.Lines { | ||||
| 				err := callback(&d, hunk, segment, line) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										10
									
								
								vendor/gitea.com/noerw/unidiff-comments/types/hunk.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/gitea.com/noerw/unidiff-comments/types/hunk.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| package types | ||||
|  | ||||
| type Hunk struct { | ||||
| 	SourceLine      int64 | ||||
| 	SourceSpan      int64 | ||||
| 	DestinationLine int64 | ||||
| 	DestinationSpan int64 | ||||
| 	Truncated       bool | ||||
| 	Segments        []*Segment | ||||
| } | ||||
							
								
								
									
										29
									
								
								vendor/gitea.com/noerw/unidiff-comments/types/line.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/gitea.com/noerw/unidiff-comments/types/line.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| package types | ||||
|  | ||||
| import "regexp" | ||||
|  | ||||
| type Line struct { | ||||
| 	Destination    int64 | ||||
| 	Source         int64 | ||||
| 	Line           string | ||||
| 	Truncated      bool | ||||
| 	ConflictMarker string | ||||
| 	CommentIds     []int64 | ||||
| 	Comments       CommentsTree | ||||
| } | ||||
|  | ||||
| var danglingSpacesRe = regexp.MustCompile("(?m) +$") | ||||
|  | ||||
| //var lineTpl = tplutil.SparseTemplate("line", ` | ||||
| //{{.Line}} | ||||
|  | ||||
| //{{if .Comments}} | ||||
| //    {{"\n"}} | ||||
| //    {{.Comments}} | ||||
| //{{end}} | ||||
| //`) | ||||
|  | ||||
| //func (l Line) String() string { | ||||
| //    result, _ := lineTpl.Execute(l) | ||||
| //    return result | ||||
| //} | ||||
							
								
								
									
										39
									
								
								vendor/gitea.com/noerw/unidiff-comments/types/segment.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/gitea.com/noerw/unidiff-comments/types/segment.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| package types | ||||
|  | ||||
| const ( | ||||
| 	SegmentTypeContext = "CONTEXT" | ||||
| 	SegmentTypeRemoved = "REMOVED" | ||||
| 	SegmentTypeAdded   = "ADDED" | ||||
| ) | ||||
|  | ||||
| type Segment struct { | ||||
| 	Type      string | ||||
| 	Truncated bool | ||||
| 	Lines     []*Line | ||||
| } | ||||
|  | ||||
| func (s Segment) TextPrefix() string { | ||||
| 	switch s.Type { | ||||
| 	case SegmentTypeAdded: | ||||
| 		return "+" | ||||
| 	case SegmentTypeRemoved: | ||||
| 		return "-" | ||||
| 	case SegmentTypeContext: | ||||
| 		return " " | ||||
| 	default: | ||||
| 		return "?" | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s Segment) GetLineNum(l *Line) int64 { | ||||
| 	switch s.Type { | ||||
| 	case SegmentTypeContext: | ||||
| 		fallthrough | ||||
| 	case SegmentTypeRemoved: | ||||
| 		return l.Source | ||||
| 	case SegmentTypeAdded: | ||||
| 		return l.Destination | ||||
| 	} | ||||
|  | ||||
| 	return 0 | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Norwin
					Norwin