Giter VIP home page Giter VIP logo

marker's Introduction

Marker is the easiest way to match and mark strings for colorful terminal outputs.

marker

Marker is built for easily match and mark strings for colorful terminal outputs. You can match your strings with built-in matchers or easily implement a custom matcher for your usecase. Marker uses fatih/color for colorizing terminal output.

Installation

go get github.com/cyucelen/marker

Basic Usage

Marker has very simple and extensible way to get your strings colorful and brilliant!

Example

aristotleQuote := "The more you know, the more you realize you don't know."
emphasized := marker.Mark(aristotleQuote, marker.MatchAll("know"), color.New(color.FgRed))
fmt.Println(emphasized)

Table of Contents


Mark Your Log Stream

You may want to instrument a logger such that any output coming from it is colorized in the expected manner. marker contains functionality which can be easily integrated with Golang's log or any interface that supports io.Writer.

stdoutMarker := marker.NewStdoutMarker()
markRules := []marker.MarkRule{
  {marker.MatchBracketSurrounded(), color.New(color.FgBlue)},
  {marker.MatchAll("marker"), color.New(color.FgRed)},
}

stdoutMarker.AddRules(markRules)
logger := log.New(stdoutMarker, "", 0)

logger.Println("[INFO] marker is working as expected")

Custom io.Writer out for log interface

marker also allows you to specify the io.Writer that you want to send output to. This is useful if the logger is writing to somewhere other than stdout like a file.

f, _ := os.Create("/tmp/awesome.log")
w := bufio.NewWriter(f)

writeMarker := marker.NewWriteMarker(w)

markRules := []marker.MarkRule{
  {marker.MatchBracketSurrounded(), blueFg},
  {marker.MatchAll("marker"), magentaFg},
}

writeMarker.AddRules(markRules)

logger := log.New(writeMarker, "", 0)
logger.Println("[INFO] colorful logs even in files, marker to mark them all!")

w.Flush()
f.Close()

output := catFile("/tmp/awesome.log") // $ cat /tmp/awesome.log
fmt.Print(output)


Matchers

MatchAll

aristotleQuote := "The more you know, the more you realize you don't know."
emphasized := marker.Mark(aristotleQuote, marker.MatchAll("know"), color.New(color.FgRed))
fmt.Println(emphasized)

MatchN

boringLog := "[INFO] Nobody wants to read pale [INFO] tags."
brilliantLog := marker.Mark(boringLog, marker.MatchN("[INFO]", 1), color.New(color.FgBlue))
fmt.Println(brilliantLog)

MatchRegexp

rhyme := "I scream, you all scream, we all scream for ice cream."
r, _ := regexp.Compile("([a-z]?cream)")
careAboutCream := marker.Mark(rhyme, marker.MatchRegexp(r), color.New(color.FgYellow))
fmt.Println(careAboutCream)

MatchSurrounded

sentence := "I pull out things surrounded by abcWHOA COLORSdef"
markedSurrounded := marker.Mark(sentence, marker.MatchSurrounded("abc", "def"), color.New(color.FgMagenta))
fmt.Println(markedSurrounded)

MatchBracketSurrounded

sentence = "[INFO] This is what log lines look like"
markedSurrounded = marker.Mark(sentence, marker.MatchBracketSurrounded(), color.New(color.FgRed))
fmt.Println(markedSurrounded)

MatchParensSurrounded

sentence = "[ERROR] This is what (parens) lines look like"
markedSurrounded = marker.Mark(sentence, marker.MatchParensSurrounded(), color.New(color.FgBlue))
fmt.Println(markedSurrounded)

MatchTimestamp

MatchTimestamp can be used for matching the timestamps fits the layouts in Golang's time.

All possible formats can be found here.

  goodOldTimes := "2006-01-02T15:04:05Z07:00 [INFO] Loading King of Fighters '97 ROM"
  timestampMarked := marker.Mark(goodOldTimes, marker.MatchTimestamp(time.RFC3339), color.New(color.FgBlue))
  fmt.Println(timestampMarked)


Builder way

If you want to mark different patterns in the same string, marker builder is neater way to do this.

rhyme := "I scream, you all scream, we all scream for ice cream."
b := &marker.MarkBuilder{}
r, _ := regexp.Compile("([a-z]?cream)")

markedWithBuilder := b.SetString(rhyme).
  Mark(marker.MatchN("for ice", 1), color.New(color.FgRed)).
  Mark(marker.MatchAll("all"), color.New(color.FgMagenta)).
  Mark(marker.MatchRegexp(r), color.New(color.FgYellow)).
  Build()

fmt.Println(markedWithBuilder)


Writing your custom Matcher

As you see in above examples, Mark function takes an MatcherFunc to match the patterns in given string and colorize them. A Matcher is a simple closure that returns a MatcherFunc to be called by Mark function to get Match information to put colorized versions of patterns into template.

Lets write our own custom Matcher that matches first encounter of given pattern.

Example

  func MatchFirst(pattern string) marker.MatcherFunc {
    return func(str string) marker.Match {
      return marker.Match{
        // replace first matching pattern with %s
        Template: strings.Replace(str, pattern, "%s", 1),
        // patterns to be colorized by Mark, in order
        Patterns: []string{pattern},
      }
    }
  }

You can also check built-in matchers for inspiration.

Contribution

I would like to accept any contributions to make Marker better and feature rich. So feel free to contribute your features(i.e. more Matchers!), improvements and fixes.

Have fun!

marker's People

Contributors

brenol avatar cyucelen avatar dapryor avatar darkclainer avatar dependabot[bot] avatar jnatalzia avatar marco-silveira avatar pelleknaap avatar richardbertozzo avatar srivats1991 avatar yogesh-desai avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

marker's Issues

Create logger functionality

[WIP]

Thinking about this project, it stands to reason that one of the strongest use cases would be for users to colorize their logs for easy reading. With that in mind, the current setup where you create a builder, give it a string, then mark means that there is a decent amount of overhead to integrating it with a logging system.

I was messing around with the testing framework and the fact that the testing instances have a .Log function got me thinking about wrapping marker in a similar way. There could be some CreateLogger which you could pass a builder to (or maybe it is the builder) which then logs in the colorized manner you specify.

Match surrounded characters

Oftentimes in log files, the beginning of the log has certain characters encasing it ex: [INFO]. Create a matcher which takes in surrounding characters and colorizes the encased letters, inclusive of the surrounding characters.

MarkWriter implementation

This is branch of issue #17.

Context

I recap the idea. We want to make wrapper for io.Writer interface, that colorize its input.
For example we want to colorize our log output. If we have this wrapper, we simply do:

log.SetOutput(NewMarkWriter(os.stdout, rules))

I've seen the PR #24 with implementation for such wrapper and I sure it works in that context (for Logger), but can have subtle bugs in others.

Problem

Writing in common can happen in parts. We can write on part of line, than - another. It's undefined how we use io.Writer and this is the reason, why it can not nicely live with Mark.
Mark have some rules, even regex and etc. It need full text to work correctly. Imagine that we writer our line in io.Writer by single byte - Mark will not work. If we match word "sense", and write:

MarkWriter.Write("se")
MarkWriter.Write("nse")

MarkWriter will not match "sense". I hope I made problem clear.

It's not like we can do nothing to mitigate this issue, but the way that I see has its own drawbacks. We can buffer and collect our line of text in MarkWriter until we get some delimiter (newline makes sense). So

MarkWriter.Write("se")
MarkWriter.Write("nse")
MarkWriter.Write(" blabla\n")

now can mark "sense", but will write entire string in it's underlying io.Writer.

And there is another thing - we should implement Close method, that will flush buffer and close underlying Writer (if it can be close of course).

Match time format

Create a matcher which takes one of the time layouts of golang standard time library and matches them in given string.

const (
	ANSIC       = "Mon Jan _2 15:04:05 2006"
	UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
	RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
	RFC822      = "02 Jan 06 15:04 MST"
	RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
	RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
	RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
	RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
	RFC3339     = "2006-01-02T15:04:05Z07:00"
	RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
	Kitchen     = "3:04PM"
	// Handy time stamps.
	Stamp      = "Jan _2 15:04:05"
	StampMilli = "Jan _2 15:04:05.000"
	StampMicro = "Jan _2 15:04:05.000000"
	StampNano  = "Jan _2 15:04:05.000000000"
)

An example:

strWithTimestamp := "Current timestamp is 2019-10-07T23:45:05Z03:00"
match := MatchTimestamp(time.RFC3339)(strWithTimestamp)
// expected match => Match{Template: "Current timestamp is %s", Patterns: []string{"2019-10-07T23:45:05Z03:00"}}

Distinct implementations can be written for each format. We can discuss to split the issue to fine grained pieces on the way with respect to complexity.

Encapsulating the color library inside marker

Marker depends on fatih/color library to colorizing strings for terminal output. Encapsulating the colorizing behavior inside marker library to prevent multiple imports from user side can be beneficial.
I want to discuss the implementation details of this encapsulation and if its overkill and comes with restrictions along with it or not.

Match invalid English words

Given a string we need to match all valid english words that does not have numericals in them. One use case that I can think of is this feature is useful in matching all misspelled english words. For example:

"This word has a singel error"
Ouput : singel

"This word is not a word1"
No words matched here

Variadic Mark function

Create a variadic Mark function that can take an arbitrary number of Matchers and colorizes the matches.

Match days of week

Create a matcher that matches days of week such as:

monday, tuesday...

or with capital first character

Monday, Tuesday..

Find a standard way to create colorized terminal output pictures for README

It is hard to keep the terminal pictures in README file tidy and in order with respect to size, font family, font color, background color, etc.
Want to discuss for finding a standard way that can be used by everbody to create colorful terminal output pictures for our API examples in README file.

There are some possible solutions that comes to my mind:

  • Online IDE outputs
  • Online Terminal Emulators (if there are any)
  • We can find a standard way to create SVGs.
  • https://terminal.sexy/ template

Keeping in touch

Since past two weeks, I feel like we built an awesome synergy among us. I really enjoyed working with you guys, I believe you all valuable and we can learn a lot from each other!

So, i want to discuss about using a platform -like Slack but without limitations- for keeping in touch. By this way, i think, we can develop marker better and faster! I believe communication channel matters for efficiency.

Even we can build new fantastic projects as a team and welcome new comers to our culture we just started to built!

Lets discuss if it is a good idea and which platform should we use.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.