Repository: pterm/pterm (go)

Issue:
PrefixPrinter: Expose call stack number
Hi!
Great project!
As part of another CLI project I am working on I have created [plogr](https://github.com/ccremer/plogr), which is a pterm implementation for the [logr](https://github.com/go-logr/logr) logging API.

I like how the `ShowLineNumber` in the PrefixPrinter shows the file and line where e.g. `Println` has been called. However, when this `Println` call is nested, then it shows the wrong file number due to `3` being hardcoded here:

https://github.com/pterm/pterm/blob/bbbae943b9e6640563f75e50b9878591e4a498bb/prefix_printer.go#L185

In the mentioned plogr project, this always is something like

```go
	sink := plogr.NewPtermSink()
	sink.ErrorPrinter = *pterm.Error.WithShowLineNumber(true)
	logger := logr.New(sink)
	logger.WithName("manager").Error(errors.New("an error"), "Error message")
```

```console
  ERROR    (manager) Error message (error="an error")
└ (/home/chris/Documents/source/ccremer/plogr/sink.go:87)
```
Displaying the source file and line number of the logr implementation isn't helpful. 

Idea: Add an offset to the PrefixPrinter (e.g. `ShowLineNumberOffset`, name debatable) with default being `0`. It gets added to the hardcoded `3` without breaking changes. So the internal usage is something like

```go
	_, fileName, line, _ := runtime.Caller(3+p.ShowLineNumberOffset)
```
That way, when configuring the prefix printers, one can give an offset of e.g. `3`, totalling to 6, which in my case would be the actual call to `Error`.

Pull request:
Added `LineNumberOffset` to `PrefixPrinter`
### Description
Added `LineNumberOffset` to `PrefixPrinter`.

### Scope
> What is affected by this pull request?

- [ ] Bug Fix
- [x] New Feature
- [ ] Documentation
- [ ] Other

### Related Issue
Fixes #256 


### To-Do Checklist
- [x] I tested my changes
- [x] I have commented every method that I created/changed
- [ ] I updated the examples to fit with my changes
- [x] I have added tests for my newly created methods


Patch:
diff --git a/docs/docs/printer/prefix.md b/docs/docs/printer/prefix.md
index d35b5cd6..f8d0381b 100644
--- a/docs/docs/printer/prefix.md
+++ b/docs/docs/printer/prefix.md
@@ -62,6 +62,7 @@ pterm.Fatal.WithOptionName(option).WithOptionName2(option2).Println("Hello, Worl
 |[Prefix](https://pkg.go.dev/github.com/pterm/pterm#PrefixPrinter.WithPrefix)|[Prefix](https://pkg.go.dev/github.com/pterm/pterm#Prefix)|
 |[Scope](https://pkg.go.dev/github.com/pterm/pterm#PrefixPrinter.WithPrefix)|[Scope](https://pkg.go.dev/github.com/pterm/pterm#Scope)|
 |[ShowLineNumber](https://pkg.go.dev/github.com/pterm/pterm#PrefixPrinter.WithShowLineNumber)|bool|
+|[LineNumberOffset](https://pkg.go.dev/github.com/pterm/pterm#PrefixPrinter.WithLineNumberOffset)|int|
 
 ### Output functions
 
diff --git a/prefix_printer.go b/prefix_printer.go
index 77b73d90..fc7469de 100644
--- a/prefix_printer.go
+++ b/prefix_printer.go
@@ -84,11 +84,12 @@ var (
 
 // PrefixPrinter is the printer used to print a Prefix.
 type PrefixPrinter struct {
-	Prefix         Prefix
-	Scope          Scope
-	MessageStyle   *Style
-	Fatal          bool
-	ShowLineNumber bool
+	Prefix           Prefix
+	Scope            Scope
+	MessageStyle     *Style
+	Fatal            bool
+	ShowLineNumber   bool
+	LineNumberOffset int
 	// If Debugger is true, the printer will only print if PrintDebugMessages is set to true.
 	// You can change PrintDebugMessages with EnableDebugMessages and DisableDebugMessages, or by setting the variable itself.
 	Debugger bool
@@ -135,6 +136,14 @@ func (p PrefixPrinter) WithDebugger(b ...bool) *PrefixPrinter {
 	return &p
 }
 
+// WithLineNumberOffset can be used to exclude a specific amount of calls in the call stack.
+// If you make a wrapper function for example, you can set this to one.
+// The printed line number will then be the line number where your wrapper function is called.
+func (p PrefixPrinter) WithLineNumberOffset(offset int) *PrefixPrinter {
+	p.LineNumberOffset = offset
+	return &p
+}
+
 // Sprint formats using the default formats for its operands and returns the resulting string.
 // Spaces are added between operands when neither is a string.
 func (p *PrefixPrinter) Sprint(a ...interface{}) string {
@@ -182,7 +191,7 @@ func (p *PrefixPrinter) Sprint(a ...interface{}) string {
 		}
 	}
 
-	_, fileName, line, _ := runtime.Caller(3)
+	_, fileName, line, _ := runtime.Caller(3 + p.LineNumberOffset)
 
 	if p.ShowLineNumber {
 		ret += FgGray.Sprint("\n└ " + fmt.Sprintf("(%s:%d)\n", fileName, line))


Test patch:
diff --git a/prefix_printer_test.go b/prefix_printer_test.go
index bf9915b0..e9c6a8d1 100644
--- a/prefix_printer_test.go
+++ b/prefix_printer_test.go
@@ -387,3 +387,13 @@ func TestPrefixPrinter_SprintflnWithoutDebugger(t *testing.T) {
 		})
 	}
 }
+
+func TestPrefixPrinter_WithLineNumberOffset(t *testing.T) {
+	for _, p := range prefixPrinters {
+		t.Run("", func(t *testing.T) {
+			p2 := p.WithLineNumberOffset(1337)
+
+			testza.AssertEqual(t, 1337, p2.LineNumberOffset)
+		})
+	}
+}