Lines of code - Golang
Tags: go, tutorial, opensource, programming
Published: 2021-11-10 20:58:09

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.