Created
August 3, 2015 07:11
-
-
Save bodhi/bdf49c39a258649de8f5 to your computer and use it in GitHub Desktop.
FRP version of https://gist.github.com/bodhi/1d748f4f4999f769b6aa
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"fmt" | |
"os" | |
"regexp" | |
"strconv" | |
"strings" | |
) | |
type word string | |
type line string | |
// reads lines from input, emits each line on returned channel | |
func readLines(input *bufio.Reader) <-chan line { | |
output := make(chan line) | |
go func() { | |
defer close(output) | |
var ( | |
next string | |
err error | |
) | |
for err == nil { | |
next, err = input.ReadString('\n') | |
next = strings.Trim(next, " \n") | |
// fmt.Printf("line: '%s'\n", next) | |
output <- line(next) | |
} | |
}() | |
return output | |
} | |
// ingests lines, emits words | |
func splitIntoWords(input <-chan line) <-chan word { | |
output := make(chan word) | |
go func() { | |
defer close(output) | |
splitter := regexp.MustCompile(`[\s\n]+`) | |
for line := range input { | |
for _, w := range splitter.Split(string(line), -1) { | |
// fmt.Printf("\tword: '%s'\n", w) | |
if w != "" { | |
output <- word(w) | |
} | |
} | |
} | |
}() | |
return output | |
} | |
// ingests words, buffers and emits lines with len(line) < columnWidth if possible | |
// (words longer than columnWidth prevent a guarantee) | |
func fillWords(columnWidth uint64, input <-chan word) <-chan line { | |
output := make(chan line) | |
go func() { | |
defer close(output) | |
firstWord, ok := <-input | |
if !ok { | |
return | |
} | |
buffer := []string{string(firstWord)} | |
for w := range input { | |
newBuffer := append(buffer, string(w)) | |
// fmt.Printf("\t\tbuffer: %v <- %s\n", buffer, w) | |
if uint64(len(strings.Join(newBuffer, " "))) > columnWidth { | |
fullLine := strings.Join(buffer, " ") | |
output <- line(fullLine) | |
buffer = []string{string(w)} | |
} else { | |
buffer = newBuffer | |
} | |
} | |
if len(buffer) > 0 { | |
// fmt.Printf("\t\tlast buffer: '%v' %d\n", buffer, len(buffer)) | |
output <- line(strings.Join(buffer, " ")) | |
} | |
}() | |
return output | |
} | |
// ingests words, buffers and emits lines with len(line) < columnWidth if possible | |
// (words longer than columnWidth prevent a guarantee) | |
func fillWordsAppend(columnWidth uint64, input <-chan word) <-chan line { | |
output := make(chan line) | |
go func() { | |
defer close(output) | |
buffer, ok := <-input | |
if !ok { // upstream already gave up! lets give up too | |
return | |
} | |
for w := range input { | |
// fmt.Printf("\t\tbuffer: %v <- %s\n", buffer, w) | |
if uint64(len(buffer)+1+len(w)) > columnWidth { | |
output <- line(buffer) | |
buffer = w | |
} else { | |
buffer += " " + w | |
} | |
} | |
if len(buffer) > 0 { | |
// fmt.Printf("\t\tlast buffer: '%v' %d\n", buffer, len(buffer)) | |
output <- line(buffer) | |
} | |
}() | |
return output | |
} | |
// prints ingested lines to stdout | |
func writeLines(input <-chan line) <-chan struct{} { | |
output := make(chan struct{}) | |
go func() { | |
defer close(output) | |
for line := range input { | |
fmt.Println(line) | |
} | |
}() | |
return output | |
} | |
func main() { | |
columnWidth, _ := strconv.ParseUint(os.Args[1], 10, 8) | |
input := bufio.NewReader(os.Stdin) | |
<-writeLines(fillWords(columnWidth, splitIntoWords(readLines(input)))) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment