<commit_before>// Copyright 2014 Square Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*
Package squalor provides SQL utility routines, such as validation of
models against table schemas, marshalling and unmarshalling of model
structs into table rows and programmatic construction of SQL
statements.

Limitations

While squalor uses the database/sql package, the SQL it utilizes is
MySQL specific (e.g. REPLACE, INSERT ON DUPLICATE KEY UPDATE, etc).

Model Binding and Validation

Given a simple table definition:

    CREATE TABLE users (
      id   bigint       PRIMARY KEY NOT NULL,
      name varchar(767) NOT NULL,
      INDEX (id, name)
    )

And a model for a row of the table:

    type User struct {
      ID   int64  `db:"id"`
      Name string `db:"name"`
    }

The BindModel method will validate that the model and the table
definition are compatible. For example, it would be an error for the
User.ID field to have the type string.

    users, err := db.BindModel("users", User{})

The table definition is loaded from the database allowing custom
checks such as verifying the existence of indexes.

    if users.GetKey("id") == nil {
        // The index ("id") does not exist!
    }
    if users.GetKey("id", "name") == nil {
        // The index ("id", "name") does not exist!
    }

Custom Types

While fields are often primitive types such as int64 or string, it is
sometimes desirable to use a custom type. This can be accomplished by
having the type implement the sql.Scanner and driver.Valuer
interfaces. For example, you might create a GzippedText type which
automatically compresses the value when it is written to the database
and uncompressed when it is read:

    type GzippedText []byte
    func (g GzippedText) Value() (driver.Value, error) {
        buf := &bytes.Buffer{}
        w := gzip.NewWriter(buf)
        defer w.Close()
        w.Write(g)
        return buf.Bytes(), nil
    }
    func (g *GzippedText) Scan(src interface{}) error {
        var source []byte
        switch t := src.(type) {
        case string:
            source = []byte(t)
        case []byte:
            source = t
        default:
            return errors.New("Incompatible type for GzippedText")
        }
        reader, err := gzip.NewReader(bytes.NewReader(source))
        defer reader.Close()
        b, err := ioutil.ReadAll(reader)
        if err != nil {
            return err
        }
        *g = GzippedText(b)
        return nil
    }

Insert

The Insert method is used to insert one or more rows in a table.

    err := db.Insert(User{ID:42, Name:"Peter Mattis"})

You can pass either a struct or a pointer to a struct.

    err := db.Insert(&User{ID:43, Name:"Spencer Kimball"})

Multiple rows can be inserted at once. Doing so offers convenience and
performance.

    err := db.Insert(&User{ID:42, Name:"Peter Mattis"},
        &User{ID:43, Name:"Spencer Kimball"})

When multiple rows are batch inserted the returned error corresponds
to the first SQL error encountered which may make it impossible to
determine which row caused the error. If the rows correspond to
different tables the order of insertion into the tables is
undefined. If you care about the order of insertion into multiple
tables and determining which row is causing an insertion error,
structure your calls to Insert appropriately (i.e. insert into a
single table or insert a single row).

After a successful insert on a table with an auto increment primary
key, the auto increment will be set back in the corresponding field of
the object. For example, if the user table was defined as:

    CREATE TABLE users (
      id   bigint       PRIMARY KEY AUTO INCREMENT NOT NULL,
      name varchar(767) NOT NULL,
      INDEX (id, name)
    )

Then we could create a new user by doing:

    u := &User{Name:"Peter Mattis"}
    err := db.Insert(u)
    if err != nil {
        ...
    }
    // u.ID will be correctly populated at this point

Replace

The Replace method replaces a row in table, either inserting the row
if it doesn't exist, or deleting and then inserting the row. See the
MySQL docs for the difference between REPLACE, UPDATE and INSERT ON
DUPLICATE KEY UPDATE (Upsert).

    err := db.Replace(&User{ID:42, Name:"Peter Mattis"})

Update

The Update method updates a row in a table, returning the number of
rows modified.

    count, err := db.Update(&User{ID:42, Name:"Peter Mattis"})

Upsert

The Upsert method inserts or updates a row.

    err := db.Upsert(&User{ID:42, Name:"Peter Mattis"})

Get

The Get method retrieves a single row by primary key and binds the
result columns to a struct.

    user := &User{}
    err := db.Get(user, 42)
    // Returns an error if user 42 cannot be found.

Delete

The delete method deletes rows by primary key.

   err := db.Delete(&User{ID:42})

See the documentation for DB.Delete for performance limitations when
batch deleting multiple rows from a table with a primary key composed
of multiple columns.

Programmatic SQL Construction

Programmatic construction of SQL queries prohibits SQL injection
attacks while keeping query construction both readable and similar to
SQL itself. Support is provided for most of the SQL DML (data
manipulation language), though the constructed queries are targetted
to MySQL.

    q := users.Select("*").Where(users.C("id").Eq(foo))
    // q.String() == "SELECT `users`.* FROM users WHERE `users`.`id` = 'foo'"
    var results []User
    err := db.Select(&results, q)

DB provides wrappers for the sql.Query and sql.QueryRow
interfaces. The Rows struct returned from Query has an additional
StructScan method for binding the columns for a row result to a
struct.

    rows, err := db.Query(q)
    if err != nil {
      return err
    }
    defer rows.Close()
    for rows.Next() {
      u := User{}
      if err := rows.StructScan(&u); err != nil {
        return err
      }
      // Process u
    }

QueryRow can be used to easily query and scan a single value:

    var count int
    err := db.QueryRow(users.Select(users.C("id").Count())).Scan(&count)

Performance

In addition to the convenience of inserting, deleting and updating
table rows using a struct, attention has been paid to
performance. Since squalor is carefully constructing the SQL queries
for insertion, deletion and update, it eschews the use of placeholders
in favor of properly escaping values in the query. With the Go MySQL
drivers, this saves a roundtrip to the database for each query because
queries with placeholders must be prepared before being executed.

Marshalling and unmarshalling of data from structs utilizes
reflection, but care is taken to minimize the use of reflection in
order to improve performance. For example, reflection data for models
is cached when the model is bound to a table.

Batch operations are utilized when possible. The Delete, Insert,
Replace, Update and Upsert operations will perform multiple operations
per SQL statement. This can provide an order of magnitude speed
improvement over performing the mutations one row at a time due to
minimizing the network overhead.
*/
package squalor
<commit_msg>Remove reference to defunct String()<commit_after>// Copyright 2014 Square Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*
Package squalor provides SQL utility routines, such as validation of
models against table schemas, marshalling and unmarshalling of model
structs into table rows and programmatic construction of SQL
statements.

Limitations

While squalor uses the database/sql package, the SQL it utilizes is
MySQL specific (e.g. REPLACE, INSERT ON DUPLICATE KEY UPDATE, etc).

Model Binding and Validation

Given a simple table definition:

    CREATE TABLE users (
      id   bigint       PRIMARY KEY NOT NULL,
      name varchar(767) NOT NULL,
      INDEX (id, name)
    )

And a model for a row of the table:

    type User struct {
      ID   int64  `db:"id"`
      Name string `db:"name"`
    }

The BindModel method will validate that the model and the table
definition are compatible. For example, it would be an error for the
User.ID field to have the type string.

    users, err := db.BindModel("users", User{})

The table definition is loaded from the database allowing custom
checks such as verifying the existence of indexes.

    if users.GetKey("id") == nil {
        // The index ("id") does not exist!
    }
    if users.GetKey("id", "name") == nil {
        // The index ("id", "name") does not exist!
    }

Custom Types

While fields are often primitive types such as int64 or string, it is
sometimes desirable to use a custom type. This can be accomplished by
having the type implement the sql.Scanner and driver.Valuer
interfaces. For example, you might create a GzippedText type which
automatically compresses the value when it is written to the database
and uncompressed when it is read:

    type GzippedText []byte
    func (g GzippedText) Value() (driver.Value, error) {
        buf := &bytes.Buffer{}
        w := gzip.NewWriter(buf)
        defer w.Close()
        w.Write(g)
        return buf.Bytes(), nil
    }
    func (g *GzippedText) Scan(src interface{}) error {
        var source []byte
        switch t := src.(type) {
        case string:
            source = []byte(t)
        case []byte:
            source = t
        default:
            return errors.New("Incompatible type for GzippedText")
        }
        reader, err := gzip.NewReader(bytes.NewReader(source))
        defer reader.Close()
        b, err := ioutil.ReadAll(reader)
        if err != nil {
            return err
        }
        *g = GzippedText(b)
        return nil
    }

Insert

The Insert method is used to insert one or more rows in a table.

    err := db.Insert(User{ID:42, Name:"Peter Mattis"})

You can pass either a struct or a pointer to a struct.

    err := db.Insert(&User{ID:43, Name:"Spencer Kimball"})

Multiple rows can be inserted at once. Doing so offers convenience and
performance.

    err := db.Insert(&User{ID:42, Name:"Peter Mattis"},
        &User{ID:43, Name:"Spencer Kimball"})

When multiple rows are batch inserted the returned error corresponds
to the first SQL error encountered which may make it impossible to
determine which row caused the error. If the rows correspond to
different tables the order of insertion into the tables is
undefined. If you care about the order of insertion into multiple
tables and determining which row is causing an insertion error,
structure your calls to Insert appropriately (i.e. insert into a
single table or insert a single row).

After a successful insert on a table with an auto increment primary
key, the auto increment will be set back in the corresponding field of
the object. For example, if the user table was defined as:

    CREATE TABLE users (
      id   bigint       PRIMARY KEY AUTO INCREMENT NOT NULL,
      name varchar(767) NOT NULL,
      INDEX (id, name)
    )

Then we could create a new user by doing:

    u := &User{Name:"Peter Mattis"}
    err := db.Insert(u)
    if err != nil {
        ...
    }
    // u.ID will be correctly populated at this point

Replace

The Replace method replaces a row in table, either inserting the row
if it doesn't exist, or deleting and then inserting the row. See the
MySQL docs for the difference between REPLACE, UPDATE and INSERT ON
DUPLICATE KEY UPDATE (Upsert).

    err := db.Replace(&User{ID:42, Name:"Peter Mattis"})

Update

The Update method updates a row in a table, returning the number of
rows modified.

    count, err := db.Update(&User{ID:42, Name:"Peter Mattis"})

Upsert

The Upsert method inserts or updates a row.

    err := db.Upsert(&User{ID:42, Name:"Peter Mattis"})

Get

The Get method retrieves a single row by primary key and binds the
result columns to a struct.

    user := &User{}
    err := db.Get(user, 42)
    // Returns an error if user 42 cannot be found.

Delete

The delete method deletes rows by primary key.

   err := db.Delete(&User{ID:42})

See the documentation for DB.Delete for performance limitations when
batch deleting multiple rows from a table with a primary key composed
of multiple columns.

Programmatic SQL Construction

Programmatic construction of SQL queries prohibits SQL injection
attacks while keeping query construction both readable and similar to
SQL itself. Support is provided for most of the SQL DML (data
manipulation language), though the constructed queries are targetted
to MySQL.

    q := users.Select("*").Where(users.C("id").Eq(foo))
    // squalor.Serialize(q) == "SELECT `users`.* FROM users WHERE `users`.`id` = 'foo'", nil
    var results []User
    err := db.Select(&results, q)

DB provides wrappers for the sql.Query and sql.QueryRow
interfaces. The Rows struct returned from Query has an additional
StructScan method for binding the columns for a row result to a
struct.

    rows, err := db.Query(q)
    if err != nil {
      return err
    }
    defer rows.Close()
    for rows.Next() {
      u := User{}
      if err := rows.StructScan(&u); err != nil {
        return err
      }
      // Process u
    }

QueryRow can be used to easily query and scan a single value:

    var count int
    err := db.QueryRow(users.Select(users.C("id").Count())).Scan(&count)

Performance

In addition to the convenience of inserting, deleting and updating
table rows using a struct, attention has been paid to
performance. Since squalor is carefully constructing the SQL queries
for insertion, deletion and update, it eschews the use of placeholders
in favor of properly escaping values in the query. With the Go MySQL
drivers, this saves a roundtrip to the database for each query because
queries with placeholders must be prepared before being executed.

Marshalling and unmarshalling of data from structs utilizes
reflection, but care is taken to minimize the use of reflection in
order to improve performance. For example, reflection data for models
is cached when the model is bound to a table.

Batch operations are utilized when possible. The Delete, Insert,
Replace, Update and Upsert operations will perform multiple operations
per SQL statement. This can provide an order of magnitude speed
improvement over performing the mutations one row at a time due to
minimizing the network overhead.
*/
package squalor
<|endoftext|>


<commit_before>// Copyright 2014 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

// orm提供了一个相对统一的数据库操作，目前内置了对部分数据库的支持，
// 用户可以通过实现自定义来实现对特定数据库的支持。
//
// 支持的数据库：
//  1. sqlite3: github.com/mattn/go-sqlite3
//  2. mysql:   github.com/go-sql-driver/mysql
//  3. postgres:github.com/lib/pq
// 其它数据库，用户可以通过实现orm/core.Dialect接口，
// 然后调用orm/dialect.Register()注册来实现支持。
//
// 初始化：
//
// 默认情况下，orm包并不会加载任何数据库的实例。所以想要用哪个数据库，需要手动初始化：
//  // 加载dialect管理包
//  import github.com/issue9/orm/dialect
//
//  // 加载数据库驱动
//  import _ github.com/mattn/go-sqlite3
//
//  // 向orm/dialect包注册dialect
//  dialect.Register("sqlite3", &dialect.Sqlite3{})
//
//  // 之后可以调用db1的各类方法操作数据库
//  db1 := orm.New("sqlite3", "./db1", "db1", "prefix_")
//
// Model:
//  type User struct {
//      // 对应表中的id字段，为自增列，从0开始
//      Id          int64      `orm:"name(id);ai(0);"`
//      // 对应表中的first_name字段，为索引index_name的一部分
//      FirstName   string     `orm:"name(first_name);index(index_name)"`
//      LastName    string     `orm:"name(first_name);index(index_name)"`
//  }
//
//  // 通过orm/core.Metaer接口，指定表的额外数据。若不需要，可不用实现该接口
//  func(u *User) Meta() string {
//      return "name(user);engine(innodb);charset(utf-8)"
//  }
// 通过struct tag可以直接将一个结构体定义为一个数据表结构，
// struct tag的语法结构，如上面代码所示，目前支持以下的struct tag：
//
//  name(fieldName): 将当前的字段映射到数据表中的fieldName字段。
//
//  len(l1, l2): 指定字段的长度，比如mysql中的int(5),varchar(255),double(1,2),
//  仅部分数据库支持，比如sqlite3不支持该属性。
//
//  nullable: 相当于定义表结构时的NULL，建议尽量少用该属性，若非用不可的话，
//  与之对应的Go属性必须声明为NullString之类的结构。
//
//  pk: 主键，支持联合主键，给多个字段加上pk的struct tag即可。
//
//  ai(start,step): 自增，若指定了自增列，则将自动取消其它的pk设置。
//  start,step指定了自增列的起始值及步长，但并不是所有的数据库都支持。
//
//  unique(index_name): 唯一索引，支持联合索引，index_name为约束名，
//  会将index_name为一样的字段定义为一个联合索引。
//
//  index(index_name): 普通的关键字索引，同unique一样会将名称相同的索引定义为一个联合索引。
//
//  default(value): 指定默认值。相当于定义表结构时的DEFAULT。
//
//  fk(fk_name,refTable,refColName,updateRule,deleteRule):
//  定义物理外键，最少需要指定fk_name,refTabl,refColName三个值。
//  分别对应约束名，引用的表和引用的字段，updateRule,deleteRule，
//  在不指定的情况下，使用数据库的默认值。
//
// 关于core.Metaer接口。
//
// 在go不能将struct tag作用于结构体，所以为了指定一些表级别的属性，
// 只能通过接口的方式指定，然后在接口方法中返回一段类似于struct tag的字符串，
// 以达到相同的目的。
// 当然在go中receive区分值类型和指针类型，所以指定接口时，需要注意这个情况。
//
//
//
// 如何使用：
//
// Create:
// 可以通过Engine.Create()或是Tx.Create()创建一张表。
//  // 创建或是更新表
//  e.Create(&User{})
//  // 创建或是更新多个表
//  e.Create([]*User{&User{},&Email{}})
//
// Update:
//  // 将id为1的记录的FirstName更改为abc
//  e.Update(&User{Id:1,FirstName:"abc"})
//  e.Where("id=?", 1).Add("FirstName", "abc").Update()
//  e.Where("id=?").Columns("FirstName").Update("abc", 1)
//
// Delete:
//  // 删除id为1的记录
//  e.Delete(&User{Id:1})
//  e.Where("id=?").Delte(1)
//  e.Where("id=?", 1).Delete()
//
// Insert:
//  // 一次性插入一条数据
//  e.Insert(&User{Id:1,FirstName:"abc"})
//  // 一次性插入多条数据
//  e.Insert([]*User{&User{Id:1,FirstName:"abc"},&User{Id:1,FirstName:"abc"}})
//
// Select:
//  // 导出id=1的数据
//  m, err := e.Where("id=?", 1).FetchMap()
//  // 导出id<5的所有数据
//  m, err := e.Where("id<?", 1).FetchMaps(5)
//
// 事务：
//
// 默认的Engine是不支持事务的，若需要事务支持，则需要调用Engine.Begin()
// 返回事务对象Tx，当然并不是所有的数据库都支持事务操作的。
// Tx拥有与Engine相似的接口。
package orm

// 版本号
const Version = "0.2.2.141230"
<commit_msg>更新部分文档<commit_after>// Copyright 2014 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

// orm提供了一个相对统一的数据库操作，目前内置了对部分数据库的支持，
// 用户可以通过实现自定义来实现对特定数据库的支持。
//
// 支持的数据库：
//  1. sqlite3: github.com/mattn/go-sqlite3
//  2. mysql:   github.com/go-sql-driver/mysql
//  3. postgres:github.com/lib/pq
// 其它数据库，用户可以通过实现orm/core.Dialect接口，
// 然后调用orm/dialect.Register()注册来实现支持。
//
// 初始化：
//
// 默认情况下，orm包并不会加载任何数据库的实例。所以想要用哪个数据库，需要手动初始化：
//  import (
//      github.com/issue9/orm/dialect  // 加载dialect管理包
//      _ github.com/mattn/go-sqlite3  // 加载数据库驱动
//  )
//
//  // 向orm/dialect包注册dialect
//  dialect.Register("sqlite3", &dialect.Sqlite3{})
//
//  // 初始化一个Engine，表前缀为prefix_
//  db1 := orm.New("sqlite3", "./db1", "db1", "prefix_")
//
//  // 另一个Engine
//  db2 := orm.New("sqlite3", "./db2", "db2", "db2_")
//
// Model:
//  type User struct {
//      Id          int64      `orm:"name(id);ai(0);"`
//      FirstName   string     `orm:"name(first_name);index(index_name)"`
//      LastName    string     `orm:"name(first_name);index(index_name)"`
//  }
//
//  // 通过orm/core.Metaer接口，指定表的额外数据。若不需要，可不用实现该接口
//  func(u *User) Meta() string {
//      return "name(user);engine(innodb);charset(utf-8)"
//  }
// 通过struct tag可以直接将一个结构体定义为一个数据表结构，
// struct tag的语法结构，如上面代码所示，目前支持以下的struct tag：
//
//  name(fieldName): 将当前的字段映射到数据表中的fieldName字段。
//
//  len(l1, l2): 指定字段的长度，比如mysql中的int(5),varchar(255),double(1,2),
//  仅部分数据库支持，比如sqlite3不支持该属性。
//
//  nullable: 相当于定义表结构时的NULL，建议尽量少用该属性，若非用不可的话，
//  与之对应的Go属性必须声明为NullString之类的结构。
//
//  pk: 主键，支持联合主键，给多个字段加上pk的struct tag即可。
//
//  ai(start,step): 自增，若指定了自增列，则将自动取消其它的pk设置。
//  start,step指定了自增列的起始值及步长，但并不是所有的数据库都支持。
//
//  unique(index_name): 唯一索引，支持联合索引，index_name为约束名，
//  会将index_name为一样的字段定义为一个联合索引。
//
//  index(index_name): 普通的关键字索引，同unique一样会将名称相同的索引定义为一个联合索引。
//
//  default(value): 指定默认值。相当于定义表结构时的DEFAULT。
//
//  fk(fk_name,refTable,refColName,updateRule,deleteRule):
//  定义物理外键，最少需要指定fk_name,refTabl,refColName三个值。
//  分别对应约束名，引用的表和引用的字段，updateRule,deleteRule，
//  在不指定的情况下，使用数据库的默认值。
//
// 关于core.Metaer接口。
//
// 在go不能将struct tag作用于结构体，所以为了指定一些表级别的属性，
// 只能通过接口的形式，然后在接口方法中返回一段类似于struct tag的字符串，
// 以达到相同的目的。
// 当然在go中receive区分值类型和指针类型，所以指定接口时，需要注意这个情况。
//
//
// 如何使用：
//
// Create:
// 可以通过Engine.Create()或是Tx.Create()创建一张表。
//  // 创建或是更新表
//  e.Create(&User{})
//  // 创建或是更新多个表
//  e.Create([]*User{&User{},&Email{}})
//
// Update:
//  // 将id为1的记录的FirstName更改为abc
//  e.Update(&User{Id:1,FirstName:"abc"})
//  e.Where("id=?", 1).Add("FirstName", "abc").Update()
//  e.Where("id=?").Columns("FirstName").Update("abc", 1)
//
// Delete:
//  // 删除id为1的记录
//  e.Delete(&User{Id:1})
//  e.Where("id=?").Delte(1)
//  e.Where("id=?", 1).Delete()
//
// Insert:
//  // 一次性插入一条数据
//  e.Insert(&User{Id:1,FirstName:"abc"})
//  // 一次性插入多条数据
//  e.Insert([]*User{&User{Id:1,FirstName:"abc"},&User{Id:1,FirstName:"abc"}})
//
// Select:
//  // 导出id=1的数据
//  m, err := e.Where("id=?", 1).FetchMap()
//  // 导出id<5的所有数据
//  m, err := e.Where("id<?", 1).FetchMaps(5)
//
//
// 事务：
//
// 默认的Engine是不支持事务的，若需要事务支持，则需要调用Engine.Begin()
// 返回事务对象Tx，当然并不是所有的数据库都支持事务操作的。
// Tx拥有与Engine相似的接口。
package orm

// 版本号
const Version = "0.2.2.141230"
<|endoftext|>


<commit_before>// Copyright 2014 The gocui Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package gocui allows to create console user interfaces.

Create a new GUI:

	g := gocui.NewGui()
	if err := g.Init(); err != nil {
		// handle error
	}
	defer g.Close()

	// Set layout and key bindings
	// ...

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		// handle error
	}

Set the layout function:

	g.SetLayout(fcn)

On each iteration of the GUI's main loop, the "layout function" is executed.
These layout functions can be used to set-up and update the application's main
views, being possible to freely switch between them. Also, it is important to
mention that a main loop iteration is executed on each reported event
(key-press, mouse event, window resize, etc).

GUIs are composed by Views, you can think of it as buffers. Views implement the
io.ReadWriter interface, so you can just write to them if you want to modify
their content. The same is valid for reading.

Create and initialize a view with absolute coordinates:

	if v, err := g.SetView("viewname", 2, 2, 22, 7); err != nil {
		if err != gocui.ErrUnknownView {
			// handle error
		}
		fmt.Fprintln(v, "This is a new view")
		// ...
	}

Views can also be created using relative coordinates:

	maxX, maxY := g.Size()
	if v, err := g.SetView("viewname", maxX/2-30, maxY/2, maxX/2+30, maxY/2+2); err != nil {
		// ...
	}

IMPORTANT: Views can only be created, destroyed or updated in two ways: from a
layout funcion or via *Gui.Execute(). The reason for this is that it allows
gocui to be conccurent-safe. So, if you want to update your GUI from a
goroutine, you must use *Gui.Execute(). For example:

	g.Execute(func(g *gocui.Gui) error {
		v, err := g.View("viewname")
		if err != nil {
			// handle error
		}
		v.Clear()
		fmt.Fprintln(v, "Writing from different goroutines")
		return nil
	})

Configure keybindings:

	if err := g.SetKeybinding("viewname", gocui.KeyEnter, gocui.ModNone, fcn); err != nil {
		// handle error
	}

gocui implements full mouse support that can be enabled with:

	g.Mouse = true

Mouse events are handled like any other keybinding:

	if err := g.SetKeybinding("viewname", gocui.MouseLeft, gocui.ModNone, fcn); err != nil {
		// handle error
	}

By default, gocui provides a basic edition mode. This mode can be extended
and customized creating a new Editor and assigning it to *Gui.Editor:

	type Editor interface {
		Edit(v *View, key Key, ch rune, mod Modifier)
	}

DefaultEditor can be taken as example to create your own custom Editor:

	var DefaultEditor Editor = EditorFunc(simpleEditor)

	func simpleEditor(v *View, key Key, ch rune, mod Modifier) {
		switch {
		case ch != 0 && mod == 0:
			v.EditWrite(ch)
		case key == KeySpace:
			v.EditWrite(' ')
		case key == KeyBackspace || key == KeyBackspace2:
			v.EditDelete(true)
		// ...
		}
	}

For more information, see the examples in folder "_examples/".
*/
package gocui
<commit_msg>Minor fixes in doc<commit_after>// Copyright 2014 The gocui Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package gocui allows to create console user interfaces.

Create a new GUI:

	g := gocui.NewGui()
	if err := g.Init(); err != nil {
		// handle error
	}
	defer g.Close()

	// Set layout and key bindings
	// ...

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		// handle error
	}

Set the layout function:

	g.SetLayout(fcn)

On each iteration of the GUI's main loop, the "layout function" is executed.
These layout functions can be used to set-up and update the application's main
views, being possible to freely switch between them. Also, it is important to
mention that a main loop iteration is executed on each reported event
(key-press, mouse event, window resize, etc).

GUIs are composed by Views, you can think of it as buffers. Views implement the
io.ReadWriter interface, so you can just write to them if you want to modify
their content. The same is valid for reading.

Create and initialize a view with absolute coordinates:

	if v, err := g.SetView("viewname", 2, 2, 22, 7); err != nil {
		if err != gocui.ErrUnknownView {
			// handle error
		}
		fmt.Fprintln(v, "This is a new view")
		// ...
	}

Views can also be created using relative coordinates:

	maxX, maxY := g.Size()
	if v, err := g.SetView("viewname", maxX/2-30, maxY/2, maxX/2+30, maxY/2+2); err != nil {
		// ...
	}

Configure keybindings:

	if err := g.SetKeybinding("viewname", gocui.KeyEnter, gocui.ModNone, fcn); err != nil {
		// handle error
	}

gocui implements full mouse support that can be enabled with:

	g.Mouse = true

Mouse events are handled like any other keybinding:

	if err := g.SetKeybinding("viewname", gocui.MouseLeft, gocui.ModNone, fcn); err != nil {
		// handle error
	}

IMPORTANT: Views can only be created, destroyed or updated in three ways: from
layout funcions, from keybinding callbacks or via *Gui.Execute(). The reason
for this is that it allows gocui to be conccurent-safe. So, if you want to
update your GUI from a goroutine, you must use *Gui.Execute(). For example:

	g.Execute(func(g *gocui.Gui) error {
		v, err := g.View("viewname")
		if err != nil {
			// handle error
		}
		v.Clear()
		fmt.Fprintln(v, "Writing from different goroutines")
		return nil
	})

By default, gocui provides a basic edition mode. This mode can be extended
and customized creating a new Editor and assigning it to *Gui.Editor:

	type Editor interface {
		Edit(v *View, key Key, ch rune, mod Modifier)
	}

DefaultEditor can be taken as example to create your own custom Editor:

	var DefaultEditor Editor = EditorFunc(simpleEditor)

	func simpleEditor(v *View, key Key, ch rune, mod Modifier) {
		switch {
		case ch != 0 && mod == 0:
			v.EditWrite(ch)
		case key == KeySpace:
			v.EditWrite(' ')
		case key == KeyBackspace || key == KeyBackspace2:
			v.EditDelete(true)
		// ...
		}
	}

For more information, see the examples in folder "_examples/".
*/
package gocui
<|endoftext|>


<commit_before>/*
Package jpegsegs reads and writes JPEG markers and segment data. The
segment data isn't decoded but could be further processed to extract
or modify metadata in formats such as Exif and XMP.

Example programs are in the repository:

jpegsegsprint prints the markers and segment lengths for a JPEG file, up to th start of scan (SOS) marker.

jpegsegscopy makes an unmodified copy of a JPEG file.

jpegsegsstrip makes a copy of a JPEG file with all COM, APP and JPG segments removed.

*/
package jpegsegs
<commit_msg>fix a typo<commit_after>/*
Package jpegsegs reads and writes JPEG markers and segment data. The
segment data isn't decoded but could be further processed to extract
or modify metadata in formats such as Exif and XMP.

Example programs are in the repository:

jpegsegsprint prints the markers and segment lengths for a JPEG file, up to the start of scan (SOS) marker.

jpegsegscopy makes an unmodified copy of a JPEG file.

jpegsegsstrip makes a copy of a JPEG file with all COM, APP and JPG segments removed.

*/
package jpegsegs
<|endoftext|>


<commit_before>/*
Package dsl contains the main Pact DSL used in the Consumer
collaboration test cases, and Provider contract test verification.

Consumer tests

Consumer side Pact testing is an isolated test that ensures a given component
is able to collaborate with another (remote) component. Pact will automatically
start a Mock server in the background that will act as the collaborators' test
double.

This implies that any interactions expected on the Mock server will be validated,
meaning a test will fail if all interactions were not completed, or if unexpected
interactions were found:

A typical consumer-side test would look something like this:

	func TestLogin(t *testing.T) {

		// Create Pact, connecting to local Daemon
		// Ensure the port matches the daemon port!
		pact := &Pact{
			Port:     6666,
			Consumer: "My Consumer",
			Provider: "My Provider",
		}
		// Shuts down Mock Service when done
		defer pact.Teardown()

		// Pass in your test case as a function to Verify()
		var test = func() error {
			_, err := http.Get("http://localhost:8000/")
			return err
		}

		// Set up our interactions. Note we have multiple in this test case!
		pact.
			AddInteraction().
			Given("User Matt exists"). // Provider State
			UponReceiving("A request to login"). // Test Case Name
			WithRequest(&Request{
				Method: "GET",
				Path:   "/login",
			}).
			WillRespondWith(&Response{
				Status: 200,
			})

		// Run the test and verify the interactions.
		err := pact.Verify(test)
		if err != nil {
			t.Fatalf("Error on Verify: %v", err)
		}
	}

If this test completed successfully, a Pact file should have been written to
./pacts/my_consumer-my_provider.json containing all of the interactions
expected to occur between the Consumer and Provider.

Provider tests

Provider side Pact testing, involves verifying that the contract - the Pact file
- can be satisfied by the Provider.

A typical Provider side test would like something like:

	func TestProvider_PactContract(t *testing.T) {
		go startMyAPI("http://localhost:8000")

		response := pact.VerifyProvider(&types.VerifyRequest{
			ProviderBaseURL:        "http://localhost:8000",
			PactURLs:               []string{"./pacts/my_consumer-my_provider.json"},
			ProviderStatesURL:      "http://localhost:8000/states",
			ProviderStatesSetupURL: "http://localhost:8000/setup",
		})

		if response.ExitCode != 0 {
			t.Fatalf("Got non-zero exit code '%d', expected 0", response.ExitCode)
		}
	}

Note that `PactURLs` can be a list of local pact files or remote based
urls (possibly from a Pact Broker
- http://docs.pact.io/documentation/sharings_pacts.html).

Pact reads the specified pact files (from remote or local sources) and replays
the interactions against a running Provider. If all of the interactions are met
we can say that both sides of the contract are satisfied and the test passes.

Matching - Consumer Tests

In addition to verbatim value matching, you have 3 useful matching functions
in the `dsl` package that can increase expressiveness and reduce brittle test
cases.

	Term(example, matcher)	tells Pact that the value should match using a given regular expression, using `example` in mock responses. `example` must be a string.
	Like(content)		tells Pact that the value itself is not important, as long as the element _type_ (valid JSON number, string, object etc.) itself matches.
	EachLike(content, min)	tells Pact that the value should be an array type, consisting of elements like those passed in. `min` must be >= 1. `content` may be a valid JSON value: e.g. strings, numbers and objects.

Here is a complex example that shows how all 3 terms can be used together:

	jumper := Like(`"jumper"`)
	shirt := Like(`"shirt"`)
	tag := EachLike(fmt.Sprintf(`[%s, %s]`, jumper, shirt), 2)
	size := Like(10)
	colour := Term("red", "red|green|blue")

	match := formatJSON(
		EachLike(
			EachLike(
				fmt.Sprintf(
					`{
						"size": %s,
						"colour": %s,
						"tag": %s
					}`, size, colour, tag),
				1),
			1))

This example will result in a response body from the mock server that looks like:
	[
	  [
	    {
	      "size": 10,
	      "colour": "red",
	      "tag": [
	        [
	          "jumper",
	          "shirt"
	        ],
	        [
	          "jumper",
	          "shirt"
	        ]
	      ]
	    }
	  ]
	]

See the examples in the dsl package and the matcher tests
(https://github.com/pact-foundation/pact-go/blob/master/dsl/matcher_test.go)
for more matching examples.

NOTE: You will need to use valid Ruby regular expressions
(http://ruby-doc.org/core-2.1.5/Regexp.html) and double escape backslashes.

Read more about flexible matching (https://github.com/realestate-com-au/pact/wiki/Regular-expressions-and-type-matching-with-Pact.

Publishing Pacts to a Broker and Tagging Pacts

See the Pact Broker (http://docs.pact.io/documentation/sharings_pacts.html)
documentation for more details on the Broker and this article
(http://rea.tech/enter-the-pact-matrix-or-how-to-decouple-the-release-cycles-of-your-microservices/)
on how to make it work for you.

Using the Pact Broker with Basic authentication

The following flags are required to use basic authentication when
publishing or retrieving Pact files to/from a Pact Broker:

	BrokerUsername	the username for Pact Broker basic authentication.
	BrokerPassword	the password for Pact Broker basic authentication.

Output Logging

Pact Go uses a simple log utility (logutils - https://github.com/hashicorp/logutils)
to filter log messages. The CLI already contains flags to manage this,
should you want to control log level in your tests, you can set it like so:

	pact := &Pact{
	  ...
		LogLevel: "DEBUG", // One of DEBUG, INFO, ERROR, NONE
	}
*/
package main
<commit_msg>docs(godoc): update main preamble<commit_after>/*
Pact Go enables consumer driven contract testing, providing a mock service and
DSL for the consumer project, and interaction playback and verification
for the service provider project.

Consumer tests

Consumer side Pact testing is an isolated test that ensures a given component
is able to collaborate with another (remote) component. Pact will automatically
start a Mock server in the background that will act as the collaborators' test
double.

This implies that any interactions expected on the Mock server will be validated,
meaning a test will fail if all interactions were not completed, or if unexpected
interactions were found:

A typical consumer-side test would look something like this:

	func TestLogin(t *testing.T) {

		// Create Pact, connecting to local Daemon
		// Ensure the port matches the daemon port!
		pact := &Pact{
			Port:     6666,
			Consumer: "My Consumer",
			Provider: "My Provider",
		}
		// Shuts down Mock Service when done
		defer pact.Teardown()

		// Pass in your test case as a function to Verify()
		var test = func() error {
			_, err := http.Get("http://localhost:8000/")
			return err
		}

		// Set up our interactions. Note we have multiple in this test case!
		pact.
			AddInteraction().
			Given("User Matt exists"). // Provider State
			UponReceiving("A request to login"). // Test Case Name
			WithRequest(&Request{
				Method: "GET",
				Path:   "/login",
			}).
			WillRespondWith(&Response{
				Status: 200,
			})

		// Run the test and verify the interactions.
		err := pact.Verify(test)
		if err != nil {
			t.Fatalf("Error on Verify: %v", err)
		}
	}

If this test completed successfully, a Pact file should have been written to
./pacts/my_consumer-my_provider.json containing all of the interactions
expected to occur between the Consumer and Provider.

Provider tests

Provider side Pact testing, involves verifying that the contract - the Pact file
- can be satisfied by the Provider.

A typical Provider side test would like something like:

	func TestProvider_PactContract(t *testing.T) {
		go startMyAPI("http://localhost:8000")

		response := pact.VerifyProvider(&types.VerifyRequest{
			ProviderBaseURL:        "http://localhost:8000",
			PactURLs:               []string{"./pacts/my_consumer-my_provider.json"},
			ProviderStatesURL:      "http://localhost:8000/states",
			ProviderStatesSetupURL: "http://localhost:8000/setup",
		})

		if response.ExitCode != 0 {
			t.Fatalf("Got non-zero exit code '%d', expected 0", response.ExitCode)
		}
	}

Note that `PactURLs` can be a list of local pact files or remote based
urls (possibly from a Pact Broker
- http://docs.pact.io/documentation/sharings_pacts.html).

Pact reads the specified pact files (from remote or local sources) and replays
the interactions against a running Provider. If all of the interactions are met
we can say that both sides of the contract are satisfied and the test passes.

Matching - Consumer Tests

In addition to verbatim value matching, you have 3 useful matching functions
in the `dsl` package that can increase expressiveness and reduce brittle test
cases.

	Term(example, matcher)	tells Pact that the value should match using a given regular expression, using `example` in mock responses. `example` must be a string.
	Like(content)		tells Pact that the value itself is not important, as long as the element _type_ (valid JSON number, string, object etc.) itself matches.
	EachLike(content, min)	tells Pact that the value should be an array type, consisting of elements like those passed in. `min` must be >= 1. `content` may be a valid JSON value: e.g. strings, numbers and objects.

Here is a complex example that shows how all 3 terms can be used together:

	jumper := Like(`"jumper"`)
	shirt := Like(`"shirt"`)
	tag := EachLike(fmt.Sprintf(`[%s, %s]`, jumper, shirt), 2)
	size := Like(10)
	colour := Term("red", "red|green|blue")

	match := formatJSON(
		EachLike(
			EachLike(
				fmt.Sprintf(
					`{
						"size": %s,
						"colour": %s,
						"tag": %s
					}`, size, colour, tag),
				1),
			1))

This example will result in a response body from the mock server that looks like:
	[
	  [
	    {
	      "size": 10,
	      "colour": "red",
	      "tag": [
	        [
	          "jumper",
	          "shirt"
	        ],
	        [
	          "jumper",
	          "shirt"
	        ]
	      ]
	    }
	  ]
	]

See the examples in the dsl package and the matcher tests
(https://github.com/pact-foundation/pact-go/blob/master/dsl/matcher_test.go)
for more matching examples.

NOTE: You will need to use valid Ruby regular expressions
(http://ruby-doc.org/core-2.1.5/Regexp.html) and double escape backslashes.

Read more about flexible matching (https://github.com/realestate-com-au/pact/wiki/Regular-expressions-and-type-matching-with-Pact.

Publishing Pacts to a Broker and Tagging Pacts

See the Pact Broker (http://docs.pact.io/documentation/sharings_pacts.html)
documentation for more details on the Broker and this article
(http://rea.tech/enter-the-pact-matrix-or-how-to-decouple-the-release-cycles-of-your-microservices/)
on how to make it work for you.

Using the Pact Broker with Basic authentication

The following flags are required to use basic authentication when
publishing or retrieving Pact files to/from a Pact Broker:

	BrokerUsername	the username for Pact Broker basic authentication.
	BrokerPassword	the password for Pact Broker basic authentication.

Output Logging

Pact Go uses a simple log utility (logutils - https://github.com/hashicorp/logutils)
to filter log messages. The CLI already contains flags to manage this,
should you want to control log level in your tests, you can set it like so:

	pact := &Pact{
	  ...
		LogLevel: "DEBUG", // One of DEBUG, INFO, ERROR, NONE
	}
*/
package main
<|endoftext|>


<commit_before>/*
Package dotquote serializes data into the "dotquote" format.

The "dotquote" format is a more human-readable for a list of namespaced key-valued pairs.

The "dotquote" format is also useful for fitting your entire data on a single line of text.

Example

	"app"."name"="myapi" "app"."build"."number"="23" "apple"="one" "banana"="two" "cherry"="three" "trace"."id"="DtehCQqBnw93Tw4h"

The example dotquote line could have been generated by the following code:

	m := map[string]interface{}{
		"app":map[string]interface{}{
			"name":"myapi",
			"build":map[string]interface{
				"number":23,
			},
		},
		"apple":"one",
		"banana":"two",
		"cherry":"three",
		"trace":map[string]interface{}{
			"id":"DtehCQqBnw93Tw4h",
		},
	}

	var p []byte
	p = dotquote.AppendMap(p, m)
*/
package dotquote
<commit_msg>add some more docs<commit_after>/*
Package dotquote serializes data into the "dotquote" format.

The "dotquote" format is a more human-readable for a list of namespaced key-valued pairs.

The "dotquote" format is also useful for fitting your entire data on a single line of text.

Example

	"app"."name"="myapi" "app"."build"."number"="23" "apple"="one" "banana"="two" "cherry"="three" "trace"."id"="DtehCQqBnw93Tw4h"

The example dotquote line could have been generated by the following code:

	m := map[string]interface{}{
		"app":map[string]interface{}{
			"name":"myapi",
			"build":map[string]interface{
				"number":23,
			},
		},
		"apple":"one",
		"banana":"two",
		"cherry":"three",
		"trace":map[string]interface{}{
			"id":"DtehCQqBnw93Tw4h",
		},
	}

	var p []byte
	p = dotquote.AppendMap(p, m)

Alternatively, it that example dotquote line could have been generated by the following code:

	var p []byte

	p = dotquote.AppendString(p, "myapi", "app", "name")
	p = dotquote.AppendString(p, "23",    "app", "build", "number")
	p = dotquote.AppendString(p, "one",   "apple")
	p = dotquote.AppendString(p, "two",   "banana")
	p = dotquote.AppendString(p, "three", "cherry")
	p = dotquote.AppendString(p, "DtehCQqBnw93Tw4h", "trace", "id")
*/
package dotquote
<|endoftext|>


<commit_before>package lmdb

/*
#include <stdlib.h>
#include <stdio.h>
#include "lmdb.h"
*/
import "C"

import (
	"errors"
	"fmt"
	"os"
	"runtime"
	"unsafe"
)

// success is a value returned from the LMDB API to indicate a successful call.
// The functions in this API this behavior and its use is not required.
const success = C.MDB_SUCCESS

const (
	// Flags for Env.Open.
	//
	// See mdb_env_open
	FixedMap    = C.MDB_FIXEDMAP   // Danger zone. Map memory at a fixed address.
	NoSubdir    = C.MDB_NOSUBDIR   // Argument to Open is a file, not a directory.
	Readonly    = C.MDB_RDONLY     // Used in several functions to denote an object as readonly.
	WriteMap    = C.MDB_WRITEMAP   // Use a writable memory map.
	NoMetaSync  = C.MDB_NOMETASYNC // Don't fsync metapage after commit.
	NoSync      = C.MDB_NOSYNC     // Don't fsync after commit.
	MapAsync    = C.MDB_MAPASYNC   // Flush asynchronously when using the WriteMap flag.
	NoTLS       = C.MDB_NOTLS      // Danger zone. Tie reader locktable slots to Txn objects instead of threads.
	NoLock      = C.MDB_NOLOCK     // Danger zone. LMDB does not use any locks. All transactions must serialize.
	NoReadahead = C.MDB_NORDAHEAD  // Disable readahead. Requires OS support.
	NoMemInit   = C.MDB_NOMEMINIT  // Disable LMDB memory initialization.
)

// DBI is a handle for a database in an Env.
//
// See MDB_dbi
type DBI C.MDB_dbi

// Env is opaque structure for a database environment.  A DB environment
// supports multiple databases, all residing in the same shared-memory map.
//
// See MDB_env.
type Env struct {
	_env *C.MDB_env
}

// NewEnv allocates and initializes a new Env.
//
// See mdb_env_create.
func NewEnv() (*Env, error) {
	var _env *C.MDB_env
	ret := C.mdb_env_create(&_env)
	if ret != success {
		return nil, errno(ret)
	}
	return &Env{_env}, nil
}

// Open an environment handle. If this function fails Close() must be called to
// discard the Env handle.  Open passes flags|NoTLS to mdb_env_open.
//
// See mdb_env_open.
func (env *Env) Open(path string, flags uint, mode os.FileMode) error {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	ret := C.mdb_env_open(env._env, cpath, C.uint(NoTLS|flags), C.mdb_mode_t(mode))
	return errno(ret)
}

// Close shuts down the environment and releases the memory map.
//
// See mdb_env_close.
func (env *Env) Close() error {
	if env._env == nil {
		return errors.New("Environment already closed")
	}
	C.mdb_env_close(env._env)
	env._env = nil
	return nil
}

// Copy copies the data in env to an environment at path.
//
// See mdb_env_copy.
func (env *Env) Copy(path string) error {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	ret := C.mdb_env_copy(env._env, cpath)
	return errno(ret)
}

// CopyFlag copies the data in env to an environment at path created with flags.
//
// See mdb_env_copy2.
func (env *Env) CopyFlag(path string, flags uint) error {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	ret := C.mdb_env_copy2(env._env, cpath, C.uint(flags))
	return errno(ret)
}

// Statistics for a database in the environment
//
// See MDB_stat.
type Stat struct {
	PSize         uint   // Size of a database page. This is currently the same for all databases.
	Depth         uint   // Depth (height) of the B-tree
	BranchPages   uint64 // Number of internal (non-leaf) pages
	LeafPages     uint64 // Number of leaf pages
	OverflowPages uint64 // Number of overflow pages
	Entries       uint64 // Number of data items
}

// Stat returns statistics about the environment.
//
// See mdb_env_stat.
func (env *Env) Stat() (*Stat, error) {
	var _stat C.MDB_stat
	ret := C.mdb_env_stat(env._env, &_stat)
	if ret != success {
		return nil, errno(ret)
	}
	stat := Stat{PSize: uint(_stat.ms_psize),
		Depth:         uint(_stat.ms_depth),
		BranchPages:   uint64(_stat.ms_branch_pages),
		LeafPages:     uint64(_stat.ms_leaf_pages),
		OverflowPages: uint64(_stat.ms_overflow_pages),
		Entries:       uint64(_stat.ms_entries)}
	return &stat, nil
}

// Information about the environment.
//
// See MDB_envinfo.
type EnvInfo struct {
	MapSize    int64 // Size of the data memory map
	LastPNO    int64 // ID of the last used page
	LastTxnID  int64 // ID of the last committed transaction
	MaxReaders uint  // maximum number of threads for the environment
	NumReaders uint  // maximum number of threads used in the environment
}

// Info returns information about the environment.
//
// See mdb_env_info.
func (env *Env) Info() (*EnvInfo, error) {
	var _info C.MDB_envinfo
	ret := C.mdb_env_info(env._env, &_info)
	if ret != success {
		return nil, errno(ret)
	}
	info := EnvInfo{
		MapSize:    int64(_info.me_mapsize),
		LastPNO:    int64(_info.me_last_pgno),
		LastTxnID:  int64(_info.me_last_txnid),
		MaxReaders: uint(_info.me_maxreaders),
		NumReaders: uint(_info.me_numreaders),
	}
	return &info, nil
}

// Sync flushes buffers to disk.
//
// See mdb_env_sync.
func (env *Env) Sync(force bool) error {
	ret := C.mdb_env_sync(env._env, cbool(force))
	return errno(ret)
}

// SetFlags enables/disables flags in the environment.
//
// See mdb_env_set_flags.
func (env *Env) SetFlags(flags uint, onoff int) error {
	ret := C.mdb_env_set_flags(env._env, C.uint(flags), C.int(onoff))
	return errno(ret)
}

// Flags returns the flags set in the environment.
//
// See mdb_env_get_flags.
func (env *Env) Flags() (uint, error) {
	var _flags C.uint
	ret := C.mdb_env_get_flags(env._env, &_flags)
	if ret != success {
		return 0, errno(ret)
	}
	return uint(_flags), nil
}

// Path returns the path argument passed to Open.  Path returns an error if the
// Env was not opened previously.  Calling Path on a closed Env has undefined
// results.
//
// See mdb_env_path.
func (env *Env) Path() (string, error) {
	var path string
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	ret := C.mdb_env_get_path(env._env, &cpath)
	if ret != success {
		return "", errno(ret)
	}
	if cpath == nil {
		return "", fmt.Errorf("not open")
	}
	return C.GoString(cpath), nil
}

// SetMapSize sets the size of the environment memory map.
//
// See mdb_env_set_map_size.
func (env *Env) SetMapSize(size int64) error {
	if size < 0 {
		return fmt.Errorf("negative size")
	}
	ret := C.mdb_env_set_mapsize(env._env, C.size_t(size))
	return errno(ret)
}

// SetMaxReaders sets the maximum number of reader slots in the environment.
//
// See mdb_env_set_max_readers.
func (env *Env) SetMaxReaders(size int) error {
	if size < 0 {
		return fmt.Errorf("negative size")
	}
	ret := C.mdb_env_set_maxreaders(env._env, C.uint(size))
	return errno(ret)
}

// SetMaxDBs sets the maximum number of named databases for the environment.
//
// See mdb_env_set_maxdbs.
func (env *Env) SetMaxDBs(size int) error {
	if size < 0 {
		return fmt.Errorf("negative size")
	}
	ret := C.mdb_env_set_maxdbs(env._env, C.MDB_dbi(size))
	return errno(ret)
}

// BeginTxn is a low-level (potentially dangerous) method to initialize a new
// transaction on env.  BeginTxn does not attempt to serialize operations on
// write transactions to the same OS thread and its use for write transactions
// can cause undefined results without care.
//
// Instead of BeginTxn users should call the View, Update, RunTxn methods.
//
// See mdb_txn_begin.
func (env *Env) BeginTxn(parent *Txn, flags uint) (*Txn, error) {
	return beginTxn(env, parent, flags)
}

// Run creates a new Txn and calls fn with it as an argument.  Run commits the
// transaction if fn returns nil otherwise the transaction is aborted.
//
// Because Run terminates the transaction goroutines should not retain
// references to it after fn returns.  Writable transactions (without the
// Readonly flag) must not be used from any goroutines other than the one
// running fn.
//
// See mdb_txn_begin.
func (env *Env) RunTxn(flags uint, fn TxnOp) error {
	if isReadonly(flags) {
		return env.run(flags, fn)
	}
	return env.runUpdate(flags, fn)
}

// View creates a readonly transaction with a consistent view of the
// environment and passes it to fn.  View terminates its transaction after fn
// returns.  Any error encountered by View is returned.
//
// Any call to Commit, Abort, Reset or Renew on a Txn created by View will
// panic.
func (env *Env) View(fn TxnOp) error {
	return env.run(Readonly, fn)
}

// Update creates a writable transaction and passes it to fn.  Update commits
// the transaction if fn returns without error otherwise Update aborts the
// transaction and returns the error.
//
// The Txn passed to fn must not be used from multiple goroutines, even with
// synchronization.
//
// Any call to Commit, Abort, Reset or Renew on a Txn created by Update will
// panic.
func (env *Env) Update(fn TxnOp) error {
	return env.runUpdate(0, fn)
}

func (env *Env) run(flags uint, fn TxnOp) error {
	txn, err := env.BeginTxn(nil, flags)
	if err != nil {
		return err
	}
	txn.managed = true
	err = fn(txn)
	if err != nil {
		txn.abort()
		return err
	}
	return txn.commit()
}

// runUpdate calls fn with a managed transaction on another goroutine.  The
// transaction runs inside a goroutine so thread locking does not interact
// negatively with other objects which would like to lock their thread.
func (env *Env) runUpdate(flags uint, fn TxnOp) error {
	errc := make(chan error)
	go func() {
		defer close(errc)
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()
		err := env.run(flags, fn)
		if err != nil {
			errc <- err
		}
	}()
	return <-errc
}

// CloseDBI closes the database handle, db.  Normally calling CloseDBI
// explicitly is not necessary.
//
// It is the caller's responsibility to serialize calls to CloseDBI.
//
// See mdb_dbi_close.
func (env *Env) CloseDBI(db DBI) {
	C.mdb_dbi_close(env._env, C.MDB_dbi(db))
}

func isReadonly(flags uint) bool {
	return flags&Readonly != 0
}
<commit_msg>split Env.SetFlags into two methods, Env.SetFlags and Env.UnsetFlags<commit_after>package lmdb

/*
#include <stdlib.h>
#include <stdio.h>
#include "lmdb.h"
*/
import "C"

import (
	"errors"
	"fmt"
	"os"
	"runtime"
	"unsafe"
)

// success is a value returned from the LMDB API to indicate a successful call.
// The functions in this API this behavior and its use is not required.
const success = C.MDB_SUCCESS

const (
	// Flags for Env.Open.
	//
	// See mdb_env_open
	FixedMap    = C.MDB_FIXEDMAP   // Danger zone. Map memory at a fixed address.
	NoSubdir    = C.MDB_NOSUBDIR   // Argument to Open is a file, not a directory.
	Readonly    = C.MDB_RDONLY     // Used in several functions to denote an object as readonly.
	WriteMap    = C.MDB_WRITEMAP   // Use a writable memory map.
	NoMetaSync  = C.MDB_NOMETASYNC // Don't fsync metapage after commit.
	NoSync      = C.MDB_NOSYNC     // Don't fsync after commit.
	MapAsync    = C.MDB_MAPASYNC   // Flush asynchronously when using the WriteMap flag.
	NoTLS       = C.MDB_NOTLS      // Danger zone. Tie reader locktable slots to Txn objects instead of threads.
	NoLock      = C.MDB_NOLOCK     // Danger zone. LMDB does not use any locks. All transactions must serialize.
	NoReadahead = C.MDB_NORDAHEAD  // Disable readahead. Requires OS support.
	NoMemInit   = C.MDB_NOMEMINIT  // Disable LMDB memory initialization.
)

// DBI is a handle for a database in an Env.
//
// See MDB_dbi
type DBI C.MDB_dbi

// Env is opaque structure for a database environment.  A DB environment
// supports multiple databases, all residing in the same shared-memory map.
//
// See MDB_env.
type Env struct {
	_env *C.MDB_env
}

// NewEnv allocates and initializes a new Env.
//
// See mdb_env_create.
func NewEnv() (*Env, error) {
	var _env *C.MDB_env
	ret := C.mdb_env_create(&_env)
	if ret != success {
		return nil, errno(ret)
	}
	return &Env{_env}, nil
}

// Open an environment handle. If this function fails Close() must be called to
// discard the Env handle.  Open passes flags|NoTLS to mdb_env_open.
//
// See mdb_env_open.
func (env *Env) Open(path string, flags uint, mode os.FileMode) error {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	ret := C.mdb_env_open(env._env, cpath, C.uint(NoTLS|flags), C.mdb_mode_t(mode))
	return errno(ret)
}

// Close shuts down the environment and releases the memory map.
//
// See mdb_env_close.
func (env *Env) Close() error {
	if env._env == nil {
		return errors.New("Environment already closed")
	}
	C.mdb_env_close(env._env)
	env._env = nil
	return nil
}

// Copy copies the data in env to an environment at path.
//
// See mdb_env_copy.
func (env *Env) Copy(path string) error {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	ret := C.mdb_env_copy(env._env, cpath)
	return errno(ret)
}

// CopyFlag copies the data in env to an environment at path created with flags.
//
// See mdb_env_copy2.
func (env *Env) CopyFlag(path string, flags uint) error {
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	ret := C.mdb_env_copy2(env._env, cpath, C.uint(flags))
	return errno(ret)
}

// Statistics for a database in the environment
//
// See MDB_stat.
type Stat struct {
	PSize         uint   // Size of a database page. This is currently the same for all databases.
	Depth         uint   // Depth (height) of the B-tree
	BranchPages   uint64 // Number of internal (non-leaf) pages
	LeafPages     uint64 // Number of leaf pages
	OverflowPages uint64 // Number of overflow pages
	Entries       uint64 // Number of data items
}

// Stat returns statistics about the environment.
//
// See mdb_env_stat.
func (env *Env) Stat() (*Stat, error) {
	var _stat C.MDB_stat
	ret := C.mdb_env_stat(env._env, &_stat)
	if ret != success {
		return nil, errno(ret)
	}
	stat := Stat{PSize: uint(_stat.ms_psize),
		Depth:         uint(_stat.ms_depth),
		BranchPages:   uint64(_stat.ms_branch_pages),
		LeafPages:     uint64(_stat.ms_leaf_pages),
		OverflowPages: uint64(_stat.ms_overflow_pages),
		Entries:       uint64(_stat.ms_entries)}
	return &stat, nil
}

// Information about the environment.
//
// See MDB_envinfo.
type EnvInfo struct {
	MapSize    int64 // Size of the data memory map
	LastPNO    int64 // ID of the last used page
	LastTxnID  int64 // ID of the last committed transaction
	MaxReaders uint  // maximum number of threads for the environment
	NumReaders uint  // maximum number of threads used in the environment
}

// Info returns information about the environment.
//
// See mdb_env_info.
func (env *Env) Info() (*EnvInfo, error) {
	var _info C.MDB_envinfo
	ret := C.mdb_env_info(env._env, &_info)
	if ret != success {
		return nil, errno(ret)
	}
	info := EnvInfo{
		MapSize:    int64(_info.me_mapsize),
		LastPNO:    int64(_info.me_last_pgno),
		LastTxnID:  int64(_info.me_last_txnid),
		MaxReaders: uint(_info.me_maxreaders),
		NumReaders: uint(_info.me_numreaders),
	}
	return &info, nil
}

// Sync flushes buffers to disk.  If force is true a synchronous flush occurs
// and ignores any NoSync or MapAsync flag on the environment.
//
// See mdb_env_sync.
func (env *Env) Sync(force bool) error {
	ret := C.mdb_env_sync(env._env, cbool(force))
	return errno(ret)
}

// SetFlags sets flags in the environment.
//
// See mdb_env_set_flags.
func (env *Env) SetFlags(flags uint) error {
	ret := C.mdb_env_set_flags(env._env, C.uint(flags), C.int(1))
	return errno(ret)
}

// UnsetFlags clears flags in the environment.
//
// See mdb_env_set_flags.
func (env *Env) UnsetFlags(flags uint) error {
	ret := C.mdb_env_set_flags(env._env, C.uint(flags), C.int(0))
	return errno(ret)
}

// Flags returns the flags set in the environment.
//
// See mdb_env_get_flags.
func (env *Env) Flags() (uint, error) {
	var _flags C.uint
	ret := C.mdb_env_get_flags(env._env, &_flags)
	if ret != success {
		return 0, errno(ret)
	}
	return uint(_flags), nil
}

// Path returns the path argument passed to Open.  Path returns an error if the
// Env was not opened previously.  Calling Path on a closed Env has undefined
// results.
//
// See mdb_env_path.
func (env *Env) Path() (string, error) {
	var path string
	cpath := C.CString(path)
	defer C.free(unsafe.Pointer(cpath))
	ret := C.mdb_env_get_path(env._env, &cpath)
	if ret != success {
		return "", errno(ret)
	}
	if cpath == nil {
		return "", fmt.Errorf("not open")
	}
	return C.GoString(cpath), nil
}

// SetMapSize sets the size of the environment memory map.
//
// See mdb_env_set_map_size.
func (env *Env) SetMapSize(size int64) error {
	if size < 0 {
		return fmt.Errorf("negative size")
	}
	ret := C.mdb_env_set_mapsize(env._env, C.size_t(size))
	return errno(ret)
}

// SetMaxReaders sets the maximum number of reader slots in the environment.
//
// See mdb_env_set_max_readers.
func (env *Env) SetMaxReaders(size int) error {
	if size < 0 {
		return fmt.Errorf("negative size")
	}
	ret := C.mdb_env_set_maxreaders(env._env, C.uint(size))
	return errno(ret)
}

// SetMaxDBs sets the maximum number of named databases for the environment.
//
// See mdb_env_set_maxdbs.
func (env *Env) SetMaxDBs(size int) error {
	if size < 0 {
		return fmt.Errorf("negative size")
	}
	ret := C.mdb_env_set_maxdbs(env._env, C.MDB_dbi(size))
	return errno(ret)
}

// BeginTxn is a low-level (potentially dangerous) method to initialize a new
// transaction on env.  BeginTxn does not attempt to serialize operations on
// write transactions to the same OS thread and its use for write transactions
// can cause undefined results without care.
//
// Instead of BeginTxn users should call the View, Update, RunTxn methods.
//
// See mdb_txn_begin.
func (env *Env) BeginTxn(parent *Txn, flags uint) (*Txn, error) {
	return beginTxn(env, parent, flags)
}

// Run creates a new Txn and calls fn with it as an argument.  Run commits the
// transaction if fn returns nil otherwise the transaction is aborted.
//
// Because Run terminates the transaction goroutines should not retain
// references to it after fn returns.  Writable transactions (without the
// Readonly flag) must not be used from any goroutines other than the one
// running fn.
//
// See mdb_txn_begin.
func (env *Env) RunTxn(flags uint, fn TxnOp) error {
	if isReadonly(flags) {
		return env.run(flags, fn)
	}
	return env.runUpdate(flags, fn)
}

// View creates a readonly transaction with a consistent view of the
// environment and passes it to fn.  View terminates its transaction after fn
// returns.  Any error encountered by View is returned.
//
// Any call to Commit, Abort, Reset or Renew on a Txn created by View will
// panic.
func (env *Env) View(fn TxnOp) error {
	return env.run(Readonly, fn)
}

// Update creates a writable transaction and passes it to fn.  Update commits
// the transaction if fn returns without error otherwise Update aborts the
// transaction and returns the error.
//
// The Txn passed to fn must not be used from multiple goroutines, even with
// synchronization.
//
// Any call to Commit, Abort, Reset or Renew on a Txn created by Update will
// panic.
func (env *Env) Update(fn TxnOp) error {
	return env.runUpdate(0, fn)
}

func (env *Env) run(flags uint, fn TxnOp) error {
	txn, err := env.BeginTxn(nil, flags)
	if err != nil {
		return err
	}
	txn.managed = true
	err = fn(txn)
	if err != nil {
		txn.abort()
		return err
	}
	return txn.commit()
}

// runUpdate calls fn with a managed transaction on another goroutine.  The
// transaction runs inside a goroutine so thread locking does not interact
// negatively with other objects which would like to lock their thread.
func (env *Env) runUpdate(flags uint, fn TxnOp) error {
	errc := make(chan error)
	go func() {
		defer close(errc)
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()
		err := env.run(flags, fn)
		if err != nil {
			errc <- err
		}
	}()
	return <-errc
}

// CloseDBI closes the database handle, db.  Normally calling CloseDBI
// explicitly is not necessary.
//
// It is the caller's responsibility to serialize calls to CloseDBI.
//
// See mdb_dbi_close.
func (env *Env) CloseDBI(db DBI) {
	C.mdb_dbi_close(env._env, C.MDB_dbi(db))
}

func isReadonly(flags uint) bool {
	return flags&Readonly != 0
}
<|endoftext|>


<commit_before>package main

import "os"
import "fmt"
import "strings"
import "math/rand"
import "github.com/fatih/color"

func getfles() []func(string) string {
	return []func(string) string {
			func(d string) string {return color.New(color.FgYellow).SprintFunc()(d)},
			func(d string) string {return color.New(color.FgBlue).SprintFunc()(d)},
			func(d string) string {return color.New(color.FgRed).SprintFunc()(d)},
			func(d string) string {return color.New(color.FgYellow).SprintFunc()(d)},
			func(d string) string {return color.New(color.FgMagenta).SprintFunc()(d)},
			func(d string) string {return color.New(color.FgCyan).SprintFunc()(d)},
			func(d string) string {return color.New(color.FgWhite).SprintFunc()(d)},
		}
}

func splitargs() string {
	args := os.Args[1:]
	s := ""

	for i := 0; i < len(args); i++ {
		s += args[i] + " "
	}

	return s
}

func stringtoslice(s string) []string {
	return strings.Split(s, "")
}

func main() {
	flist := getfles()

	argstring := splitargs()
	s := stringtoslice(argstring)
	result := ""

	for i := 0; i < len(s); i++ {
		result += flist[rand.Intn(len(flist))](s[i])
	}

	fmt.Printf(result + "\n")
}
<commit_msg>major code rework for better efficiency<commit_after>package main

import (
	"fmt"
	"math/rand"
	"os"
	"strings"

	"github.com/fatih/color"
)

func getfles() []func(string) string {
	return []func(string) string{
		func(d string) string { return color.New(color.FgYellow).SprintFunc()(d) },
		func(d string) string { return color.New(color.FgBlue).SprintFunc()(d) },
		func(d string) string { return color.New(color.FgRed).SprintFunc()(d) },
		func(d string) string { return color.New(color.FgYellow).SprintFunc()(d) },
		func(d string) string { return color.New(color.FgMagenta).SprintFunc()(d) },
		func(d string) string { return color.New(color.FgCyan).SprintFunc()(d) },
		func(d string) string { return color.New(color.FgWhite).SprintFunc()(d) },
	}
}

func splitargs() string {
	args := os.Args[1:]
	s := ""

	for i := 0; i < len(args); i++ {
		s += args[i] + " "
	}

	return s
}

func stringtoslice(s string) []string {
	return strings.Split(s, "")
}

func main() {
	flist := getfles()

	argstring := splitargs()
	s := stringtoslice(argstring)
	result := ""

	for i := 0; i < len(s); i++ {
		result += flist[rand.Intn(len(flist))](s[i])
	}

	fmt.Printf(result + "\n")
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/signal"
	"strings"
	"unicode/utf8"
)

const (
	VERSION                   = "0.0.1"
	defaultPlaceholder        = "{{}}"
	keyBackspace              = 8
	keyDelete                 = 127
	keyEndOfTransmission      = 4
	keyLineFeed               = 10
	keyCarriageReturn         = 13
	keyEndOfTransmissionBlock = 23
	keyEscape                 = 27
)

var placeholder string

var usage = `fzz allows you to run a command interactively.

Usage:

	fzz command

The command MUST include the placeholder '{{}}'.

Arguments:

	-v		Print version and exit
`

func printUsage() {
	fmt.Printf(usage)
}

func isPipe(f *os.File) bool {
	s, err := f.Stat()
	if err != nil {
		return false
	}

	return s.Mode()&os.ModeNamedPipe != 0
}

func containsPlaceholder(s []string, ph string) bool {
	for _, v := range s {
		if strings.Contains(v, ph) {
			return true
		}
	}
	return false
}

func validPlaceholder(p string) bool {
	return len(p)%2 == 0
}

func removeLastWord(s []byte) []byte {
	fields := bytes.Fields(s)
	if len(fields) > 0 {
		r := bytes.Join(fields[:len(fields)-1], []byte{' '})
		if len(r) > 1 {
			r = append(r, ' ')
		}
		return r
	}
	return []byte{}
}

func removeLastCharacter(s []byte) []byte {
	if len(s) > 1 {
		r, rsize := utf8.DecodeLastRune(s)
		if r == utf8.RuneError {
			return s[:len(s)-1]
		} else {
			return s[:len(s)-rsize]
		}
	} else if len(s) == 1 {
		return nil
	}
	return s
}

func readCharacter(r io.Reader) <-chan []byte {
	ch := make(chan []byte)
	rs := bufio.NewScanner(r)

	go func() {
		rs.Split(bufio.ScanRunes)

		for rs.Scan() {
			b := rs.Bytes()
			ch <- b
		}
	}()

	return ch
}

type Fzz struct {
	tty           *TTY
	printer       *Printer
	stdinbuf      *bytes.Buffer
	currentRunner *Runner
	input         []byte
}

func (fzz *Fzz) Loop() {
	ttych := readCharacter(fzz.tty)

	fzz.tty.resetScreen()
	fzz.tty.printPrompt(fzz.input[:len(fzz.input)])

	for {
		b := <-ttych

		switch b[0] {
		case keyBackspace, keyDelete:
			fzz.input = removeLastCharacter(fzz.input)
		case keyEndOfTransmission, keyLineFeed, keyCarriageReturn:
			if fzz.currentRunner != nil {
				fzz.currentRunner.Wait()
				fzz.tty.resetScreen()
				io.Copy(os.Stdout, fzz.currentRunner.stdoutbuf)
			} else {
				fzz.tty.resetScreen()
			}
			return
		case keyEscape:
			fzz.tty.resetScreen()
			return
		case keyEndOfTransmissionBlock:
			fzz.input = removeLastWord(fzz.input)
		default:
			// TODO: Default is wrong here. Only append printable characters to
			// input
			fzz.input = append(fzz.input, b...)
		}

		fzz.killCurrentRunner()

		fzz.tty.resetScreen()
		fzz.tty.printPrompt(fzz.input[:len(fzz.input)])

		fzz.printer.Reset()

		if len(fzz.input) > 0 {
			fzz.currentRunner = NewRunner(flag.Args(), placeholder, string(fzz.input), fzz.stdinbuf)
			ch, err := fzz.currentRunner.Run()
			if err != nil {
				log.Fatal(err)
			}

			go func(inputlen int) {
				for line := range ch {
					fzz.printer.Print(line)
				}
				fzz.tty.cursorAfterPrompt(inputlen)
			}(utf8.RuneCount(fzz.input))
		}
	}
}

func (fzz *Fzz) killCurrentRunner() {
	if fzz.currentRunner != nil {
		go func(runner *Runner) {
			runner.KillWait()
		}(fzz.currentRunner)
	}
}

func main() {
	flVersion := flag.Bool("v", false, "Print fzz version and quit")
	flag.Usage = printUsage
	flag.Parse()

	if *flVersion {
		fmt.Printf("fzz %s\n", VERSION)
		os.Exit(0)
	}

	if len(flag.Args()) < 2 {
		fmt.Fprintf(os.Stderr, usage)
		os.Exit(1)
	}

	if placeholder = os.Getenv("FZZ_PLACEHOLDER"); placeholder == "" {
		placeholder = defaultPlaceholder
	}

	if !validPlaceholder(placeholder) {
		fmt.Fprintln(os.Stderr, "Placeholder is not valid, needs even number of characters")
		os.Exit(1)
	}

	if !containsPlaceholder(flag.Args(), placeholder) {
		fmt.Fprintln(os.Stderr, "No placeholder in arguments")
		os.Exit(1)
	}

	tty, err := NewTTY()
	if err != nil {
		log.Fatal(err)
	}
	defer tty.resetState()

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		<-c
		tty.resetState()
		os.Exit(1)
	}()
	tty.setSttyState("cbreak", "-echo")

	stdinbuf := bytes.Buffer{}
	if isPipe(os.Stdin) {
		io.Copy(&stdinbuf, os.Stdin)
	}

	printer := NewPrinter(tty, tty.cols, tty.rows-1) // prompt is one row
	fzz := &Fzz{
		printer: printer,
		tty: tty,
		stdinbuf: &stdinbuf,
		input: make([]byte, 0),
	}
	fzz.Loop()
}
<commit_msg>Add placeholder field to Fzz struct<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/signal"
	"strings"
	"unicode/utf8"
)

const (
	VERSION                   = "0.0.1"
	defaultPlaceholder        = "{{}}"
	keyBackspace              = 8
	keyDelete                 = 127
	keyEndOfTransmission      = 4
	keyLineFeed               = 10
	keyCarriageReturn         = 13
	keyEndOfTransmissionBlock = 23
	keyEscape                 = 27
)

var placeholder string

var usage = `fzz allows you to run a command interactively.

Usage:

	fzz command

The command MUST include the placeholder '{{}}'.

Arguments:

	-v		Print version and exit
`

func printUsage() {
	fmt.Printf(usage)
}

func isPipe(f *os.File) bool {
	s, err := f.Stat()
	if err != nil {
		return false
	}

	return s.Mode()&os.ModeNamedPipe != 0
}

func containsPlaceholder(s []string, ph string) bool {
	for _, v := range s {
		if strings.Contains(v, ph) {
			return true
		}
	}
	return false
}

func validPlaceholder(p string) bool {
	return len(p)%2 == 0
}

func removeLastWord(s []byte) []byte {
	fields := bytes.Fields(s)
	if len(fields) > 0 {
		r := bytes.Join(fields[:len(fields)-1], []byte{' '})
		if len(r) > 1 {
			r = append(r, ' ')
		}
		return r
	}
	return []byte{}
}

func removeLastCharacter(s []byte) []byte {
	if len(s) > 1 {
		r, rsize := utf8.DecodeLastRune(s)
		if r == utf8.RuneError {
			return s[:len(s)-1]
		} else {
			return s[:len(s)-rsize]
		}
	} else if len(s) == 1 {
		return nil
	}
	return s
}

func readCharacter(r io.Reader) <-chan []byte {
	ch := make(chan []byte)
	rs := bufio.NewScanner(r)

	go func() {
		rs.Split(bufio.ScanRunes)

		for rs.Scan() {
			b := rs.Bytes()
			ch <- b
		}
	}()

	return ch
}

type Fzz struct {
	tty           *TTY
	printer       *Printer
	stdinbuf      *bytes.Buffer
	currentRunner *Runner
	input         []byte
	placeholder   string
}

func (fzz *Fzz) Loop() {
	ttych := readCharacter(fzz.tty)

	fzz.tty.resetScreen()
	fzz.tty.printPrompt(fzz.input[:len(fzz.input)])

	for {
		b := <-ttych

		switch b[0] {
		case keyBackspace, keyDelete:
			fzz.input = removeLastCharacter(fzz.input)
		case keyEndOfTransmission, keyLineFeed, keyCarriageReturn:
			if fzz.currentRunner != nil {
				fzz.currentRunner.Wait()
				fzz.tty.resetScreen()
				io.Copy(os.Stdout, fzz.currentRunner.stdoutbuf)
			} else {
				fzz.tty.resetScreen()
			}
			return
		case keyEscape:
			fzz.tty.resetScreen()
			return
		case keyEndOfTransmissionBlock:
			fzz.input = removeLastWord(fzz.input)
		default:
			// TODO: Default is wrong here. Only append printable characters to
			// input
			fzz.input = append(fzz.input, b...)
		}

		fzz.killCurrentRunner()

		fzz.tty.resetScreen()
		fzz.tty.printPrompt(fzz.input[:len(fzz.input)])

		fzz.printer.Reset()

		if len(fzz.input) > 0 {
			fzz.currentRunner = NewRunner(flag.Args(), fzz.placeholder, string(fzz.input), fzz.stdinbuf)
			ch, err := fzz.currentRunner.Run()
			if err != nil {
				log.Fatal(err)
			}

			go func(inputlen int) {
				for line := range ch {
					fzz.printer.Print(line)
				}
				fzz.tty.cursorAfterPrompt(inputlen)
			}(utf8.RuneCount(fzz.input))
		}
	}
}

func (fzz *Fzz) killCurrentRunner() {
	if fzz.currentRunner != nil {
		go func(runner *Runner) {
			runner.KillWait()
		}(fzz.currentRunner)
	}
}

func main() {
	flVersion := flag.Bool("v", false, "Print fzz version and quit")
	flag.Usage = printUsage
	flag.Parse()

	if *flVersion {
		fmt.Printf("fzz %s\n", VERSION)
		os.Exit(0)
	}

	if len(flag.Args()) < 2 {
		fmt.Fprintf(os.Stderr, usage)
		os.Exit(1)
	}

	if placeholder = os.Getenv("FZZ_PLACEHOLDER"); placeholder == "" {
		placeholder = defaultPlaceholder
	}

	if !validPlaceholder(placeholder) {
		fmt.Fprintln(os.Stderr, "Placeholder is not valid, needs even number of characters")
		os.Exit(1)
	}

	if !containsPlaceholder(flag.Args(), placeholder) {
		fmt.Fprintln(os.Stderr, "No placeholder in arguments")
		os.Exit(1)
	}

	tty, err := NewTTY()
	if err != nil {
		log.Fatal(err)
	}
	defer tty.resetState()

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		<-c
		tty.resetState()
		os.Exit(1)
	}()
	tty.setSttyState("cbreak", "-echo")

	stdinbuf := bytes.Buffer{}
	if isPipe(os.Stdin) {
		io.Copy(&stdinbuf, os.Stdin)
	}

	printer := NewPrinter(tty, tty.cols, tty.rows-1) // prompt is one row
	fzz := &Fzz{
		printer:     printer,
		tty:         tty,
		stdinbuf:    &stdinbuf,
		input:       make([]byte, 0),
		placeholder: placeholder,
	}
	fzz.Loop()
}
<|endoftext|>


<commit_before>package main

import (
    "flag"
    "fmt"
    "os"
    "regexp"

    customCar    "github.com/jtyr/gbt/gbt/cars/custom"
    dirCar       "github.com/jtyr/gbt/gbt/cars/dir"
    exectimeCar  "github.com/jtyr/gbt/gbt/cars/exectime"
    gitCar       "github.com/jtyr/gbt/gbt/cars/git"
    hostnameCar  "github.com/jtyr/gbt/gbt/cars/hostname"
    osCar        "github.com/jtyr/gbt/gbt/cars/os"
    pyvirtenvCar "github.com/jtyr/gbt/gbt/cars/pyvirtenv"
    signCar      "github.com/jtyr/gbt/gbt/cars/sign"
    statusCar    "github.com/jtyr/gbt/gbt/cars/status"
    timeCar      "github.com/jtyr/gbt/gbt/cars/time"

    "github.com/jtyr/gbt/gbt/core/car"
    "github.com/jtyr/gbt/gbt/core/utils"
)

type Cars interface {
    Init()
    Format() string
    SetParamStr(string, string)
    GetColor(string, bool) string
    DecorateElement(element, bg, fg, fm, text string) string
    GetModel() map[string]car.ModelElement
    GetDisplay() bool
    GetSep() string
    GetWrap() bool
}

func printCars(cars []Cars, right bool) {
    prevBg := "\000"
    prevDisplay := true
    fakeCar := car.Car{}

    separator := utils.GetEnv("GBT_SEPARATOR", "")

    if right {
        separator = utils.GetEnv("GBT_RSEPARATOR", "")
    }

    if ! right && utils.GetEnv("GBT_BEGINNING_TEXT", "") != "" {
        fmt.Print(
            fakeCar.DecorateElement(
                "",
                fakeCar.GetColor(utils.GetEnv("GBT_BEGINNING_BG", "default"), false),
                fakeCar.GetColor(utils.GetEnv("GBT_BEGINNING_FG", "default"), true),
                fakeCar.GetColor(utils.GetEnv("GBT_BEGINNING_FM", "none"), false),
                utils.GetEnv("GBT_BEGINNING_TEXT", "")))
    }

    for _, c := range cars {
        c.Init()

        cModel := c.GetModel()
        cDisplay := c.GetDisplay()
        cSep := c.GetSep()
        cWrap := c.GetWrap()

        if cSep != "\000" {
            separator = cSep
        }

        if cDisplay {
            fmt.Print(fakeCar.GetColor("RESETALL", false))

            if prevBg != "\000" && prevDisplay {
                bg := c.GetColor(cModel["root"].Bg, false)
                fg := c.GetColor(cModel["root"].Bg, true)

                if cWrap {
                    bg = c.GetColor("default", false)
                    fg = c.GetColor("default", true)
                }

                if right {
                    fmt.Print(
                        c.DecorateElement(
                            "",
                            c.GetColor(prevBg, false),
                            fg,
                            "",
                            separator))
                } else {
                    fmt.Print(
                        c.DecorateElement(
                            "",
                            bg,
                            c.GetColor(prevBg, true),
                            "",
                            separator))
                }

                if cWrap {
                    fmt.Print("\n")
                }
            }

            prevBg = cModel["root"].Bg
            prevDisplay = cDisplay

            fmt.Print(c.Format())
        }
    }

    fmt.Print(fakeCar.GetColor("RESETALL", false))
}

func main() {
    var argsHelp, argsVersion, argsRight bool

    flag.BoolVar(&argsHelp, "help", false, "show this help message and exit")
    flag.BoolVar(&argsVersion, "version", false, "show version and exit")
    flag.BoolVar(&argsRight, "right", false, "compose right hand site prompt")
    flag.Parse()

    if argsHelp {
        flag.PrintDefaults()
        os.Exit(0)
    }
    if argsVersion {
        fmt.Println("GBT v1.1.0")
        os.Exit(0)
    }

    carsStr := utils.GetEnv("GBT_CARS", "Status, Os, Hostname, Dir, Git, Sign")

    if argsRight {
        carsStr = utils.GetEnv("GBT_RCARS", "Time")
    }

    reCarSplit := regexp.MustCompile(`\s*,\s*`)
    carsNames := reCarSplit.Split(carsStr, -1)
    carsFactory := map[string]Cars{
        "Custom":    &customCar.Car{},
        "Dir":       &dirCar.Car{},
        "ExecTime":  &exectimeCar.Car{},
        "Git":       &gitCar.Car{},
        "Hostname":  &hostnameCar.Car{},
        "Os":        &osCar.Car{},
        "PyVirtEnv": &pyvirtenvCar.Car{},
        "Sign":      &signCar.Car{},
        "Status":    &statusCar.Car{},
        "Time":      &timeCar.Car{},
    }
    cars := []Cars{}

    for _, cn := range carsNames {
        custom := "\000"

        if len(cn) >= 6 && cn[:6] == "Custom" {
            custom = cn[6:]
            cn = cn[:6]
        }

        if val, ok := carsFactory[cn]; ok {
            if cn == "Status" && len(flag.Args()) > 0 {
                val.SetParamStr("args", flag.Args()[0])
            } else if custom != "\000" {
                val = &customCar.Car{}
                val.SetParamStr("name", custom)
            }

            cars = append(cars, val)
        }
    }

    printCars(cars, argsRight)
}
<commit_msg>Fixing per-car separator issue<commit_after>package main

import (
    "flag"
    "fmt"
    "os"
    "regexp"

    customCar    "github.com/jtyr/gbt/gbt/cars/custom"
    dirCar       "github.com/jtyr/gbt/gbt/cars/dir"
    exectimeCar  "github.com/jtyr/gbt/gbt/cars/exectime"
    gitCar       "github.com/jtyr/gbt/gbt/cars/git"
    hostnameCar  "github.com/jtyr/gbt/gbt/cars/hostname"
    osCar        "github.com/jtyr/gbt/gbt/cars/os"
    pyvirtenvCar "github.com/jtyr/gbt/gbt/cars/pyvirtenv"
    signCar      "github.com/jtyr/gbt/gbt/cars/sign"
    statusCar    "github.com/jtyr/gbt/gbt/cars/status"
    timeCar      "github.com/jtyr/gbt/gbt/cars/time"

    "github.com/jtyr/gbt/gbt/core/car"
    "github.com/jtyr/gbt/gbt/core/utils"
)

type Cars interface {
    Init()
    Format() string
    SetParamStr(string, string)
    GetColor(string, bool) string
    DecorateElement(element, bg, fg, fm, text string) string
    GetModel() map[string]car.ModelElement
    GetDisplay() bool
    GetSep() string
    GetWrap() bool
}

func printCars(cars []Cars, right bool) {
    prevBg := "\000"
    prevDisplay := true
    fakeCar := car.Car{}
    defaultSeparator := utils.GetEnv("GBT_SEPARATOR", "")

    if right {
        defaultSeparator = utils.GetEnv("GBT_RSEPARATOR", "")
    }

    if ! right && utils.GetEnv("GBT_BEGINNING_TEXT", "") != "" {
        fmt.Print(
            fakeCar.DecorateElement(
                "",
                fakeCar.GetColor(utils.GetEnv("GBT_BEGINNING_BG", "default"), false),
                fakeCar.GetColor(utils.GetEnv("GBT_BEGINNING_FG", "default"), true),
                fakeCar.GetColor(utils.GetEnv("GBT_BEGINNING_FM", "none"), false),
                utils.GetEnv("GBT_BEGINNING_TEXT", "")))
    }

    for _, c := range cars {
        c.Init()

        cModel := c.GetModel()
        cDisplay := c.GetDisplay()
        cSep := c.GetSep()
        cWrap := c.GetWrap()

        separator := defaultSeparator

        if cSep != "\000" {
            separator = cSep
        }

        if cDisplay {
            fmt.Print(fakeCar.GetColor("RESETALL", false))

            if prevBg != "\000" && prevDisplay {
                bg := c.GetColor(cModel["root"].Bg, false)
                fg := c.GetColor(cModel["root"].Bg, true)

                if cWrap {
                    bg = c.GetColor("default", false)
                    fg = c.GetColor("default", true)
                }

                if right {
                    fmt.Print(
                        c.DecorateElement(
                            "",
                            c.GetColor(prevBg, false),
                            fg,
                            "",
                            separator))
                } else {
                    fmt.Print(
                        c.DecorateElement(
                            "",
                            bg,
                            c.GetColor(prevBg, true),
                            "",
                            separator))
                }

                if cWrap {
                    fmt.Print("\n")
                }
            }

            prevBg = cModel["root"].Bg
            prevDisplay = cDisplay

            fmt.Print(c.Format())
        }
    }

    fmt.Print(fakeCar.GetColor("RESETALL", false))
}

func main() {
    var argsHelp, argsVersion, argsRight bool

    flag.BoolVar(&argsHelp, "help", false, "show this help message and exit")
    flag.BoolVar(&argsVersion, "version", false, "show version and exit")
    flag.BoolVar(&argsRight, "right", false, "compose right hand site prompt")
    flag.Parse()

    if argsHelp {
        flag.PrintDefaults()
        os.Exit(0)
    }
    if argsVersion {
        fmt.Println("GBT v1.1.0")
        os.Exit(0)
    }

    carsStr := utils.GetEnv("GBT_CARS", "Status, Os, Hostname, Dir, Git, Sign")

    if argsRight {
        carsStr = utils.GetEnv("GBT_RCARS", "Time")
    }

    reCarSplit := regexp.MustCompile(`\s*,\s*`)
    carsNames := reCarSplit.Split(carsStr, -1)
    carsFactory := map[string]Cars{
        "Custom":    &customCar.Car{},
        "Dir":       &dirCar.Car{},
        "ExecTime":  &exectimeCar.Car{},
        "Git":       &gitCar.Car{},
        "Hostname":  &hostnameCar.Car{},
        "Os":        &osCar.Car{},
        "PyVirtEnv": &pyvirtenvCar.Car{},
        "Sign":      &signCar.Car{},
        "Status":    &statusCar.Car{},
        "Time":      &timeCar.Car{},
    }
    cars := []Cars{}

    for _, cn := range carsNames {
        custom := "\000"

        if len(cn) >= 6 && cn[:6] == "Custom" {
            custom = cn[6:]
            cn = cn[:6]
        }

        if val, ok := carsFactory[cn]; ok {
            if cn == "Status" && len(flag.Args()) > 0 {
                val.SetParamStr("args", flag.Args()[0])
            } else if custom != "\000" {
                val = &customCar.Car{}
                val.SetParamStr("name", custom)
            }

            cars = append(cars, val)
        }
    }

    printCars(cars, argsRight)
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package gcm provides send and receive GCM functionality.
package gcm

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/mattn/go-xmpp"
)

const (
	httpAddress = "https://android.googleapis.com/gcm/send"
	xmppHost    = "gcm.googleapis.com"
	xmppPort    = "5235"
	xmppAddress = xmppHost + ":" + xmppPort
)

var (
	// DebugMode determines whether to have verbose logging.
	DebugMode = true
)

func debug(m string, v interface{}) {
	if DebugMode {
		log.Printf(m+":%+v", v)
	}
}

// downstream is a downstream (server -> client) message.
type downstream struct {
	To   string  `json:"to,omitempty"`
	Data Message `json:"data,omitempty"`
}

// upstream is an upstream (client -> server) message.
type upstream struct {
	From string  `json:"from"`
	Data Message `json:"data,omitempty"`
}

// Message is the custom data passed with every GCM message.
type Message map[string]interface{}

// MessageHandler is the type for a function that handles a GCM message.
type MessageHandler func(from string, m Message) error

// Send sends a downstream message to a given device.
func Send(apiKey, to string, m Message) error {
	bs, err := json.Marshal(&downstream{To: to, Data: m})
	if err != nil {
		return fmt.Errorf("error marshalling message>%v", err)
	}
	debug("sending", string(bs))
	req, err := http.NewRequest("POST", httpAddress, bytes.NewReader(bs))
	if err != nil {
		return fmt.Errorf("error creating request>%v", err)
	}
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Authorization", authHeader(apiKey))
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("error making request>%v", err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("error reading body>%v", err)
	}
	debug("response body", string(body))
	return nil
}

// Listen blocks and connects to GCM waiting for messages, calling the handler
// for every "normal" type message.
func Listen(senderId, apiKey string, h MessageHandler) error {
	cl, err := xmpp.NewClient(xmppAddress, xmppUser(senderId), apiKey, DebugMode)
	if err != nil {
		return fmt.Errorf("error connecting client>%v", err)
	}
	for {
		stanza, err := cl.Recv()
		if err != nil {
			// This is likely fatal, so return.
			return fmt.Errorf("error on Recv>%v", err)
		}
		v, ok := stanza.(xmpp.Chat)
		if !ok {
			continue
		}
		switch v.Type {
		case "normal":
			up := &upstream{}
			json.Unmarshal([]byte(v.Other[0]), up)
			go h(up.From, up.Data)
		case "error":
			debug("error response", v)
		}
	}
	return nil
}

// authHeader generates an authorization header value for an api key.
func authHeader(apiKey string) string {
	return fmt.Sprintf("key=%v", apiKey)
}

// xmppUser generates an xmpp username from a sender ID.
func xmppUser(senderId string) string {
	return senderId + "@" + xmppHost
}
<commit_msg>Allow ability to stop the listener.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package gcm provides send and receive GCM functionality.
package gcm

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/mattn/go-xmpp"
)

const (
	httpAddress = "https://android.googleapis.com/gcm/send"
	xmppHost    = "gcm.googleapis.com"
	xmppPort    = "5235"
	xmppAddress = xmppHost + ":" + xmppPort
)

var (
	// DebugMode determines whether to have verbose logging.
	DebugMode = true
)

func debug(m string, v interface{}) {
	if DebugMode {
		log.Printf(m+":%+v", v)
	}
}

// downstream is a downstream (server -> client) message.
type downstream struct {
	To   string  `json:"to,omitempty"`
	Data Message `json:"data,omitempty"`
}

// upstream is an upstream (client -> server) message.
type upstream struct {
	From string  `json:"from"`
	Data Message `json:"data,omitempty"`
}

// Message is the custom data passed with every GCM message.
type Message map[string]interface{}

// StopChannel is a channel type to stop the server.
type StopChannel chan bool

// MessageHandler is the type for a function that handles a GCM message.
type MessageHandler func(from string, m Message) error

// Send sends a downstream message to a given device.
func Send(apiKey, to string, m Message) error {
	bs, err := json.Marshal(&downstream{To: to, Data: m})
	if err != nil {
		return fmt.Errorf("error marshalling message>%v", err)
	}
	debug("sending", string(bs))
	req, err := http.NewRequest("POST", httpAddress, bytes.NewReader(bs))
	if err != nil {
		return fmt.Errorf("error creating request>%v", err)
	}
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Authorization", authHeader(apiKey))
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("error making request>%v", err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("error reading body>%v", err)
	}
	debug("response body", string(body))
	return nil
}

// Listen blocks and connects to GCM waiting for messages, calling the handler
// for every "normal" type message. An optional stop channel can be provided to
// stop listening.
func Listen(senderId, apiKey string, h MessageHandler, stop StopChannel) error {
	cl, err := xmpp.NewClient(xmppAddress, xmppUser(senderId), apiKey, DebugMode)
	if err != nil {
		return fmt.Errorf("error connecting client>%v", err)
	}
	if stop != nil {
		go func() {
			select {
			case <-stop:
				cl.Close()
			}
		}()
	}
	for {
		stanza, err := cl.Recv()
		if err != nil {
			// This is likely fatal, so return.
			return fmt.Errorf("error on Recv>%v", err)
		}
		v, ok := stanza.(xmpp.Chat)
		if !ok {
			continue
		}
		switch v.Type {
		case "normal":
			up := &upstream{}
			json.Unmarshal([]byte(v.Other[0]), up)
			go h(up.From, up.Data)
		case "error":
			debug("error response", v)
		}
	}
	return nil
}

// authHeader generates an authorization header value for an api key.
func authHeader(apiKey string) string {
	return fmt.Sprintf("key=%v", apiKey)
}

// xmppUser generates an xmpp username from a sender ID.
func xmppUser(senderId string) string {
	return senderId + "@" + xmppHost
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package sh

type Token int

const (
	ILLEGAL Token = -iota
	EOF
	COMMENT
	LIT

	IF
	THEN
	ELIF
	ELSE
	FI
	WHILE
	FOR
	IN
	DO
	DONE
	CASE
	ESAC

	AND  // &
	LAND // &&
	OR   // |
	LOR  // ||

	EXP     // $
	LPAREN  // (
	LBRACE  // {
	DLPAREN // ((

	RPAREN     // )
	RBRACE     // }
	DRPAREN    // ))
	SEMICOLON  // ;
	DSEMICOLON // ;;

	RDRIN  // <
	RDROUT // >
	APPEND // >>
)

var tokNames = map[Token]string{
	ILLEGAL: `ILLEGAL`,
	EOF:     `EOF`,
	COMMENT: `comment`,
	LIT:     `literal`,

	IF:    "if",
	THEN:  "then",
	ELIF:  "elif",
	ELSE:  "else",
	FI:    "fi",
	WHILE: "while",
	FOR:   "for",
	IN:    "in",
	DO:    "do",
	DONE:  "done",
	CASE:  "case",
	ESAC:  "esac",

	AND:  "&",
	LAND: "&&",
	OR:   "|",
	LOR:  "||",

	EXP:     ")",
	LPAREN:  "(",
	LBRACE:  "{",
	DLPAREN: "((",

	RPAREN:     ")",
	RBRACE:     "}",
	DRPAREN:    "))",
	SEMICOLON:  ";",
	DSEMICOLON: ";;",

	RDRIN:  "<",
	RDROUT: ">",
	APPEND: ">>",
}

func (t Token) String() string {
	if s, e := tokNames[t]; e {
		return s
	}
	return string(rune(t))
}

func doToken(r rune, readOnly func(rune) bool) Token {
	switch r {
	case '&':
		if readOnly('&') {
			return LAND
		}
		return AND
	case '|':
		if readOnly('|') {
			return LOR
		}
		return OR
	case '(':
		if readOnly('(') {
			return DLPAREN
		}
		return LPAREN
	case '{':
		return LBRACE
	case ')':
		if readOnly(')') {
			return DRPAREN
		}
		return RPAREN
	case '}':
		return RBRACE
	case '$':
		return EXP
	case ';':
		if readOnly(';') {
			return DSEMICOLON
		}
		return SEMICOLON
	case '<':
		return RDRIN
	case '>':
		if readOnly('>') {
			return APPEND
		}
		return RDROUT
	default:
		return Token(r)
	}
}
<commit_msg>Fix EXP string<commit_after>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package sh

type Token int

const (
	ILLEGAL Token = -iota
	EOF
	COMMENT
	LIT

	IF
	THEN
	ELIF
	ELSE
	FI
	WHILE
	FOR
	IN
	DO
	DONE
	CASE
	ESAC

	AND  // &
	LAND // &&
	OR   // |
	LOR  // ||

	EXP     // $
	LPAREN  // (
	LBRACE  // {
	DLPAREN // ((

	RPAREN     // )
	RBRACE     // }
	DRPAREN    // ))
	SEMICOLON  // ;
	DSEMICOLON // ;;

	RDRIN  // <
	RDROUT // >
	APPEND // >>
)

var tokNames = map[Token]string{
	ILLEGAL: `ILLEGAL`,
	EOF:     `EOF`,
	COMMENT: `comment`,
	LIT:     `literal`,

	IF:    "if",
	THEN:  "then",
	ELIF:  "elif",
	ELSE:  "else",
	FI:    "fi",
	WHILE: "while",
	FOR:   "for",
	IN:    "in",
	DO:    "do",
	DONE:  "done",
	CASE:  "case",
	ESAC:  "esac",

	AND:  "&",
	LAND: "&&",
	OR:   "|",
	LOR:  "||",

	EXP:     "$",
	LPAREN:  "(",
	LBRACE:  "{",
	DLPAREN: "((",

	RPAREN:     ")",
	RBRACE:     "}",
	DRPAREN:    "))",
	SEMICOLON:  ";",
	DSEMICOLON: ";;",

	RDRIN:  "<",
	RDROUT: ">",
	APPEND: ">>",
}

func (t Token) String() string {
	if s, e := tokNames[t]; e {
		return s
	}
	return string(rune(t))
}

func doToken(r rune, readOnly func(rune) bool) Token {
	switch r {
	case '&':
		if readOnly('&') {
			return LAND
		}
		return AND
	case '|':
		if readOnly('|') {
			return LOR
		}
		return OR
	case '(':
		if readOnly('(') {
			return DLPAREN
		}
		return LPAREN
	case '{':
		return LBRACE
	case ')':
		if readOnly(')') {
			return DRPAREN
		}
		return RPAREN
	case '}':
		return RBRACE
	case '$':
		return EXP
	case ';':
		if readOnly(';') {
			return DSEMICOLON
		}
		return SEMICOLON
	case '<':
		return RDRIN
	case '>':
		if readOnly('>') {
			return APPEND
		}
		return RDROUT
	default:
		return Token(r)
	}
}
<|endoftext|>