github.com/vipcoin-gold/reviewdog@v1.0.2/service/commentutil/code_fence.go (about)

     1  package commentutil
     2  
     3  import "io"
     4  
     5  // GetCodeFenceLength returns the length of a code fence needed to wrap code.
     6  // A test suggestion that uses four backticks w/o code fence block.
     7  // Fixes: https://github.com/reviewdog/reviewdog/issues/999
     8  //
     9  // Code fenced blocks are supported by GitHub Flavor Markdown.
    10  // A code fence is typically three backticks.
    11  //
    12  //     ```
    13  //     code
    14  //     ```
    15  //
    16  // However, we sometimes need more backticks.
    17  // https://docs.github.com/en/github/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#fenced-code-blocks
    18  //
    19  // > To display triple backticks in a fenced code block, wrap them inside quadruple backticks.
    20  // >
    21  // >     ````
    22  // >     ```
    23  // >     Look! You can see my backticks.
    24  // >     ```
    25  // >     ````
    26  func GetCodeFenceLength(code string) int {
    27  	backticks := countBackticks(code) + 1
    28  	if backticks < 3 {
    29  		// At least three backticks are required.
    30  		// https://github.github.com/gfm/#fenced-code-blocks
    31  		// > A code fence is a sequence of at least three consecutive backtick characters (`) or tildes (~). (Tildes and backticks cannot be mixed.)
    32  		backticks = 3
    33  	}
    34  	return backticks
    35  }
    36  
    37  // WriteCodeFence writes a code fence to w.
    38  func WriteCodeFence(w io.Writer, length int) error {
    39  	if w, ok := w.(io.ByteWriter); ok {
    40  		// use WriteByte instead of Write to avoid memory allocation.
    41  		for i := 0; i < length; i++ {
    42  			if err := w.WriteByte('`'); err != nil {
    43  				return err
    44  			}
    45  		}
    46  		return nil
    47  	}
    48  
    49  	buf := make([]byte, length)
    50  	for i := range buf {
    51  		buf[i] = '`'
    52  	}
    53  	_, err := w.Write(buf)
    54  	return err
    55  }
    56  
    57  // find code fences in s, and returns the maximum length of them.
    58  func countBackticks(s string) int {
    59  	inBackticks := true
    60  
    61  	var count int
    62  	var maxCount int
    63  	for _, r := range s {
    64  		if inBackticks {
    65  			if r == '`' {
    66  				count++
    67  			} else {
    68  				inBackticks = false
    69  				if count > maxCount {
    70  					maxCount = count
    71  				}
    72  				count = 0
    73  			}
    74  		}
    75  		if r == '\n' {
    76  			inBackticks = true
    77  			count = 0
    78  		}
    79  	}
    80  	if count > maxCount {
    81  		maxCount = count
    82  	}
    83  	return maxCount
    84  }