Lines of code - Golang

in hive-192037 •  3 years ago 

Let's make a simple counter to check how many lines of code are in our project.

I want to start with a simple function.

func LineCounter(r string) (int, error) {

    var count int
    rr  := strings.Split(r, "\n")
    var rrr []string
    cc := 0
    comstart := false
    for _, str := range rr {
        if strings.HasPrefix(str, "/*")   {
            comstart = true
            continue
        }
        if strings.Contains(str, "*/") {
            comstart = false
            cc += 1

        }
        if (str != "" && !strings.HasPrefix(str, "//") && !comstart) {
            rrr = append(rrr, str)
        }
    }

    count = len(rrr) - cc

    return count, nil
}

This function takes some text and split all lines by "\n" (newline sign).
We check if 2 things if the line is empty and also if the line is any kind of comment. In golang there is a single-line comment starting with // and also multiline starting with /* and end with */. The function return number of lines or error.

var (
    Info = Teal
    Warn = Yellow
    Fata = Red
  )

  var (
    Black   = Color("\033[1;30m%s\033[0m")
    Red     = Color("\033[1;31m%s\033[0m")
    Green   = Color("\033[1;32m%s\033[0m")
    Yellow  = Color("\033[1;33m%s\033[0m")
    Purple  = Color("\033[1;34m%s\033[0m")
    Magenta = Color("\033[1;35m%s\033[0m")
    Teal    = Color("\033[1;36m%s\033[0m")
    White   = Color("\033[1;37m%s\033[0m")
  )

  func Color(colorString string) func(...interface{}) string {
    sprint := func(args ...interface{}) string {
      return fmt.Sprintf(colorString,
        fmt.Sprint(args...))
    }
    return sprint
  }

This part of the code we use to create colored text doesn't need explanation I guess.

Last but not least we have the main function.

func main() {
    arg := os.Args[1]
    all := 0

    err := filepath.Walk(arg, func(path string, info os.FileInfo, err error) error {
        if err != nil {
            return err
        }
        if (!info.IsDir()  && !strings.Contains(info.Name(), "test") ){
            ext := filepath.Ext(path)


            if ext == ".go" {

            jj, _ := os.ReadFile(path)
            g, _ := LineCounter(string(jj))
            all += g
            var u string
            if g < 200 {
                z := strconv.Itoa(g)
                u = Info(z)
            } 
            if g >= 200 && g < 1000 {
                z := strconv.Itoa(g)
                u = Warn(z)
            }
            if g >= 1000 {
                z := strconv.Itoa(g)
                u = Fata(z)
            }
            fmt.Printf("File %s have %s lines of code \n",path, u)
            }
        }

        return nil
    })
    if err != nil {
        log.Println(err)
    }
    fmt.Println("All lines", all)

}

Here I get my path from the console and go through it recursively checking if the path is not a folder. If the path is not a folder (it is a file) and if the file has ".go" extension. I also check if the filename contains "test" word. I don't want to count test files (In golang test files must contain test after the name).
I add to sum every time when our LineCounter function returns a number. I check if a number of lines are less than 200 converts the number to a string and make it teal, 200-1000 Yellow, and everything more than 1000 is red. I also print every file with a number of lines. And on end, I print the sum of all lines.

Finally our completed code.

package main

import (
    "fmt"
    "log"
    "os"
    "path/filepath"
    "strconv"
    "strings"
)

var (
    Info = Teal
    Warn = Yellow
    Fata = Red
  )

  var (
    Black   = Color("\033[1;30m%s\033[0m")
    Red     = Color("\033[1;31m%s\033[0m")
    Green   = Color("\033[1;32m%s\033[0m")
    Yellow  = Color("\033[1;33m%s\033[0m")
    Purple  = Color("\033[1;34m%s\033[0m")
    Magenta = Color("\033[1;35m%s\033[0m")
    Teal    = Color("\033[1;36m%s\033[0m")
    White   = Color("\033[1;37m%s\033[0m")
  )

  func Color(colorString string) func(...interface{}) string {
    sprint := func(args ...interface{}) string {
      return fmt.Sprintf(colorString,
        fmt.Sprint(args...))
    }
    return sprint
  }

func main() {
    arg := os.Args[1]
    all := 0

    err := filepath.Walk(arg, func(path string, info os.FileInfo, err error) error {
        if err != nil {
            return err
        }
        if (!info.IsDir()  && !strings.Contains(info.Name(), "test") ){
            ext := filepath.Ext(path)


            if ext == ".go" {

            jj, _ := os.ReadFile(path)
            g, _ := LineCounter(string(jj))
            all += g
            var u string
            if g < 200 {
                z := strconv.Itoa(g)
                u = Info(z)
            } 
            if g >= 200 && g < 1000 {
                z := strconv.Itoa(g)
                u = Warn(z)
            }
            if g >= 1000 {
                z := strconv.Itoa(g)
                u = Fata(z)
            }
            fmt.Printf("File %s have %s lines of code \n",path, u)

            }
        }

        return nil
    })
    if err != nil {
        log.Println(err)
    }
    fmt.Println("All lines", all)

}


func LineCounter(r string) (int, error) {

    var count int
    rr  := strings.Split(r, "\n")
    var rrr []string
    cc := 0
    comstart := false
    for _, str := range rr {
        if strings.HasPrefix(str, "/*")   {
            comstart = true
            continue
        }
        if strings.Contains(str, "*/") {
            comstart = false
            cc += 1

        }
        if (str != "" && !strings.HasPrefix(str, "//") && !comstart) {
            rrr = append(rrr, str)
        }
    }

    count = len(rrr) - cc

    return count, nil
}

I hope it will help some of you please tell me how it works and also if it works on Windows systems.

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

go