<commit_before>// Package i3barjson provides a Go library for i3bar JSON protocol support.
package i3barjson

import (
	"encoding/json"
	"fmt"
	"io"
)

// Header represents the header of an i3bar message.
type Header struct {
	Version      int  `json:"version"`
	Stop_signal  int  `json:"stop_signal,omitempty"`
	Cont_signal  int  `json:"cont_signal,omitempty"`
	Click_events bool `json:"click_events,omitempty"`
}

// String pretty prints Header objects.
func (d *Header) String() string {
	str, err := json.MarshalIndent(d, "", "    ")
	if err != nil {
		return err.Error()
	}
	return string(str)
}

// Block represents a single block of an i3bar message.
type Block struct {
	Full_text             string `json:"full_text"`
	Short_text            string `json:"short_text,omitempty"`
	Color                 string `json:"color,omitempty"`
	Min_width             string `json:"min_width,omitempty"`
	Align                 string `json:"align,omitempty"`
	Name                  string `json:"name,omitempty"`
	Instance              string `json:"instance,omitempty"`
	Urgent                bool   `json:"urgent,omitempty"`
	Separator             bool   `json:"separator"`
	Separator_block_width int    `json:"separator_block_width,omitempty"`
	Markup                string `json:"markup,omitempty"`
}

// String pretty prints Block objects.
func (d *Block) String() string {
	str, err := json.MarshalIndent(d, "", "    ")
	if err != nil {
		return err.Error()
	}
	return string(str)
}

// StatusLine represents a full i3bar status line.
type StatusLine []*Block

// String pretty prints StatusLine objects.
func (d *StatusLine) String() string {
	str, err := json.MarshalIndent(d, "", "    ")
	if err != nil {
		return err.Error()
	}
	return string(str)
}

// Click represents an i3bar click event.
type Click struct {
	Name     string `json:"name"`
	Instance string `json:"instance"`
	X        int    `json:"x"`
	Y        int    `json:"y"`
	Button   int    `json:"button"`
}

// String pretty prints Click objects.
func (d *Click) String() string {
	str, err := json.MarshalIndent(d, "", "    ")
	if err != nil {
		return err.Error()
	}
	return string(str)
}

// jsonArrayEncoder is an object that streams an infinite JSON array.
type jsonArrayEncoder struct {
	count int
	w     io.Writer
	e     json.Encoder
}

// Encode streams an infinite JSON array.
// Each call adds another element to the array.
func (e *jsonArrayEncoder) Encode(v interface{}) error {
	linePrefix := ","
	if e.count == 0 {
		linePrefix = "["
		e.count++
	}
	_, err := e.w.Write([]byte(linePrefix))
	if err != nil {
		return err
	}

	err = e.e.Encode(v)
	if err != nil {
		return err
	}

	return nil
}

// newJsonArrayEncoder returns a new jsonArrayEncoder that wraps w.
func newJsonArrayEncoder(w io.Writer) *jsonArrayEncoder {
	return &jsonArrayEncoder{0, w, *json.NewEncoder(w)}
}

// Init initializes the i3bar io.
// w is the io.Writer to write to (usually os.Stdout).
// r is the io.Reader to from (usually os.Stdin). TODO: implement
// q is a channel that will be closed when the write loop is finished.
// The returned channel can be used to write status lines to w.
func Init(h *Header, w io.Writer, r io.Reader, q chan bool) (chan StatusLine, error) {
	if w == nil {
		return nil, fmt.Errorf("error: Writer required")
	}
	var jsonWriter = newJsonArrayEncoder(w)
	// TODO: implement read loop
	//var jsonReader *json.Decoder
	if r != nil {
		//jsonReader = json.NewDecoder(r)
	}

	msg, err := json.Marshal(h)
	if err != nil {
		return nil, fmt.Errorf("error: couldn't parse Header")
	}
	_, err = fmt.Fprintln(w, string(msg))
	if err != nil {
		return nil, fmt.Errorf("error: couldn't write to Writer")
	}

	statusChan := make(chan StatusLine)
	go writeLoop(jsonWriter, statusChan, q)
	return statusChan, nil
}

// writeLoop continuosly writes status lines sent over c to e.
// q is closed when there are no more values to read from c.<commit_msg>fixed comment grammar<commit_after>// Package i3barjson provides a Go library for i3bar JSON protocol support.
package i3barjson

import (
	"encoding/json"
	"fmt"
	"io"
)

// Header represents the header of an i3bar message.
type Header struct {
	Version      int  `json:"version"`
	Stop_signal  int  `json:"stop_signal,omitempty"`
	Cont_signal  int  `json:"cont_signal,omitempty"`
	Click_events bool `json:"click_events,omitempty"`
}

// String pretty prints Header objects.
func (d *Header) String() string {
	str, err := json.MarshalIndent(d, "", "    ")
	if err != nil {
		return err.Error()
	}
	return string(str)
}

// Block represents a single block of an i3bar message.
type Block struct {
	Full_text             string `json:"full_text"`
	Short_text            string `json:"short_text,omitempty"`
	Color                 string `json:"color,omitempty"`
	Min_width             string `json:"min_width,omitempty"`
	Align                 string `json:"align,omitempty"`
	Name                  string `json:"name,omitempty"`
	Instance              string `json:"instance,omitempty"`
	Urgent                bool   `json:"urgent,omitempty"`
	Separator             bool   `json:"separator"`
	Separator_block_width int    `json:"separator_block_width,omitempty"`
	Markup                string `json:"markup,omitempty"`
}

// String pretty prints Block objects.
func (d *Block) String() string {
	str, err := json.MarshalIndent(d, "", "    ")
	if err != nil {
		return err.Error()
	}
	return string(str)
}

// StatusLine represents a full i3bar status line.
type StatusLine []*Block

// String pretty prints StatusLine objects.
func (d *StatusLine) String() string {
	str, err := json.MarshalIndent(d, "", "    ")
	if err != nil {
		return err.Error()
	}
	return string(str)
}

// Click represents an i3bar click event.
type Click struct {
	Name     string `json:"name"`
	Instance string `json:"instance"`
	X        int    `json:"x"`
	Y        int    `json:"y"`
	Button   int    `json:"button"`
}

// String pretty prints Click objects.
func (d *Click) String() string {
	str, err := json.MarshalIndent(d, "", "    ")
	if err != nil {
		return err.Error()
	}
	return string(str)
}

// jsonArrayEncoder is an object that streams an infinite JSON array.
type jsonArrayEncoder struct {
	count int
	w     io.Writer
	e     json.Encoder
}

// Encode streams an infinite JSON array.
// Each call adds another element to the array.
func (e *jsonArrayEncoder) Encode(v interface{}) error {
	linePrefix := ","
	if e.count == 0 {
		linePrefix = "["
		e.count++
	}
	_, err := e.w.Write([]byte(linePrefix))
	if err != nil {
		return err
	}

	err = e.e.Encode(v)
	if err != nil {
		return err
	}

	return nil
}

// newJsonArrayEncoder returns a new jsonArrayEncoder that wraps w.
func newJsonArrayEncoder(w io.Writer) *jsonArrayEncoder {
	return &jsonArrayEncoder{0, w, *json.NewEncoder(w)}
}

// Init initializes the i3bar io.
// w is the io.Writer to write to (usually os.Stdout).
// r is the io.Reader to from (usually os.Stdin) (TODO: implement).
// q is a channel that will be closed when the write loop is finished.
// The returned channel can be used to write status lines to w.
func Init(h *Header, w io.Writer, r io.Reader, q chan bool) (chan StatusLine, error) {
	if w == nil {
		return nil, fmt.Errorf("error: Writer required")
	}
	var jsonWriter = newJsonArrayEncoder(w)
	// TODO: implement read loop
	//var jsonReader *json.Decoder
	if r != nil {
		//jsonReader = json.NewDecoder(r)
	}

	msg, err := json.Marshal(h)
	if err != nil {
		return nil, fmt.Errorf("error: couldn't parse Header")
	}
	_, err = fmt.Fprintln(w, string(msg))
	if err != nil {
		return nil, fmt.Errorf("error: couldn't write to Writer")
	}

	statusChan := make(chan StatusLine)
	go writeLoop(jsonWriter, statusChan, q)
	return statusChan, nil
}

// writeLoop continuosly writes status lines sent over c to e.
// q is closed when there are no more values to read from c.
{'fraction_non_alphanumeric': 0.1207115628970775, 'fraction_numerical': 0.0025412960609911056, 'mean_word_length': 3.1800318640467338, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '57831', 'n_tokens_mistral': 2532, 'n_tokens_neox': 2470, 'n_words': 843}