Convert Figma logo to code with AI

peterh logoliner

Pure Go line editor with history, inspired by linenoise

1,043
132
1,043
17

Top Related Projects

Readline is a pure go(golang) implementation for GNU-Readline kind library

Building powerful interactive prompts in Go, inspired by python-prompt-toolkit.

Interactive prompt for command-line applications

4,082

A golang library for building interactive and accessible prompts with full support for windows and posix terminals.

1,676

Library for creating interactive cli applications.

9,827

Minimalist Go package aimed at creating Console User Interfaces.

Quick Overview

Liner is a Go library that provides a line editor with history and readline-like functionality. It's designed to be a more feature-rich alternative to the standard Go readline package, offering advanced editing capabilities and customization options for command-line interfaces.

Pros

  • Supports advanced line editing features like history navigation, tab completion, and multi-line editing
  • Provides a flexible API for customizing behavior and appearance
  • Compatible with Windows, macOS, and Linux
  • Actively maintained and regularly updated

Cons

  • May have a steeper learning curve compared to the standard Go readline package
  • Limited documentation and examples available
  • Potential performance overhead for simple use cases
  • Dependency on external terminal libraries may complicate cross-platform development

Code Examples

  1. Basic usage:
package main

import (
    "fmt"
    "github.com/peterh/liner"
)

func main() {
    line := liner.NewLiner()
    defer line.Close()

    if name, err := line.Prompt("Enter your name: "); err == nil {
        fmt.Printf("Hello, %s!\n", name)
    }
}
  1. Using history:
package main

import (
    "github.com/peterh/liner"
    "os"
)

func main() {
    line := liner.NewLiner()
    defer line.Close()

    line.SetCtrlCAborts(true)

    if f, err := os.Open("history.txt"); err == nil {
        line.ReadHistory(f)
        f.Close()
    }

    for {
        if input, err := line.Prompt("> "); err == nil {
            line.AppendHistory(input)
            // Process input here
        } else {
            break
        }
    }

    if f, err := os.Create("history.txt"); err == nil {
        line.WriteHistory(f)
        f.Close()
    }
}
  1. Implementing tab completion:
package main

import (
    "github.com/peterh/liner"
    "strings"
)

func main() {
    line := liner.NewLiner()
    defer line.Close()

    line.SetCompleter(func(line string) (c []string) {
        commands := []string{"help", "quit", "status"}
        for _, n := range commands {
            if strings.HasPrefix(n, strings.ToLower(line)) {
                c = append(c, n)
            }
        }
        return
    })

    // Use the line editor with tab completion
}

Getting Started

To use Liner in your Go project, follow these steps:

  1. Install the package:

    go get github.com/peterh/liner
    
  2. Import the package in your Go code:

    import "github.com/peterh/liner"
    
  3. Create a new liner instance and use it to prompt for input:

    line := liner.NewLiner()
    defer line.Close()
    
    input, err := line.Prompt("Enter command: ")
    if err == nil {
        // Process input
    }
    
  4. Customize the liner instance as needed, adding features like history, tab completion, or multi-line editing based on your requirements.

Competitor Comparisons

Readline is a pure go(golang) implementation for GNU-Readline kind library

Pros of readline

  • More feature-rich, including support for multi-line editing and custom key bindings
  • Better performance, especially for large histories
  • More actively maintained with regular updates and bug fixes

Cons of readline

  • Larger codebase and more complex to integrate
  • May have compatibility issues with some terminal emulators
  • Requires cgo, which can complicate cross-compilation

Code comparison

liner:

line, err := liner.NewLiner()
defer line.Close()
input, err := line.Prompt("Enter input: ")

readline:

rl, err := readline.New("> ")
defer rl.Close()
line, err := rl.Readline()

Summary

Both liner and readline are Go libraries for handling interactive command-line input. readline offers more advanced features and better performance, making it suitable for complex CLI applications. However, liner is simpler to integrate and doesn't require cgo, which can be advantageous for certain projects. The choice between the two depends on the specific requirements of your application, such as feature needs, performance considerations, and cross-compilation requirements.

Building powerful interactive prompts in Go, inspired by python-prompt-toolkit.

Pros of go-prompt

  • More feature-rich with advanced completion and suggestion capabilities
  • Supports multi-line input and syntax highlighting
  • Offers a more modern and customizable user interface

Cons of go-prompt

  • Higher memory usage and performance overhead
  • More complex to implement and configure
  • Less suitable for simple command-line applications

Code Comparison

liner:

line, err := liner.Prompt("> ")
if err != nil {
    fmt.Println("Error:", err)
    return
}

go-prompt:

p := prompt.New(
    executor,
    completer,
    prompt.OptionPrefix("> "),
)
p.Run()

Key Differences

  • liner is lightweight and focuses on basic line editing functionality
  • go-prompt provides a more comprehensive prompt experience with advanced features
  • liner is better suited for simple CLI tools, while go-prompt excels in interactive applications

Use Cases

  • Choose liner for basic command-line interfaces with minimal requirements
  • Opt for go-prompt when building interactive shells or complex CLI applications

Community and Maintenance

  • liner has been around longer and has a stable API
  • go-prompt is actively maintained with regular updates and new features

Performance Considerations

  • liner has lower memory footprint and faster startup times
  • go-prompt offers better performance for complex autocompletion scenarios

Interactive prompt for command-line applications

Pros of promptui

  • More feature-rich with support for various input types (select, confirm, password)
  • Offers customizable styling and theming options
  • Provides built-in validation and transformation of user input

Cons of promptui

  • Larger and more complex codebase, potentially harder to integrate
  • May have a steeper learning curve for basic use cases
  • Slower development and fewer recent updates compared to liner

Code Comparison

liner:

line, err := liner.Prompt("Enter your name: ")
if err != nil {
    // Handle error
}
fmt.Printf("Hello, %s!\n", line)

promptui:

prompt := promptui.Prompt{
    Label: "Enter your name",
}
result, err := prompt.Run()
if err != nil {
    // Handle error
}
fmt.Printf("Hello, %s!\n", result)

Summary

liner is a simpler, lightweight library focused on line editing functionality, while promptui offers a more comprehensive set of features for building interactive command-line interfaces. liner may be preferable for basic input needs, while promptui shines in scenarios requiring more advanced user interactions and customization. The choice between the two depends on the specific requirements of your project and the level of complexity you're willing to manage.

4,082

A golang library for building interactive and accessible prompts with full support for windows and posix terminals.

Pros of Survey

  • More feature-rich, offering various question types (input, select, confirm, etc.)
  • Supports complex survey flows with conditional questions and validation
  • Better suited for creating interactive CLI applications with multi-step prompts

Cons of Survey

  • Heavier and more complex to set up for simple input scenarios
  • May have a steeper learning curve for basic use cases
  • Potentially slower for single-line input operations

Code Comparison

Survey:

prompt := &survey.Input{
    Message: "Enter your name:",
}
survey.AskOne(prompt, &name)

Liner:

line := liner.NewLiner()
defer line.Close()
name, _ := line.Prompt("Enter your name: ")

Summary

Survey is a more comprehensive solution for creating interactive command-line interfaces with various question types and complex flows. It's ideal for applications requiring multi-step user input or surveys.

Liner, on the other hand, is a simpler library focused on providing readline-like functionality. It's more lightweight and straightforward for basic input scenarios but lacks the advanced features of Survey.

Choose Survey for complex CLI applications with diverse input requirements, and Liner for simpler projects needing basic line editing and history functionality.

1,676

Library for creating interactive cli applications.

Pros of ishell

  • Provides a more comprehensive framework for building interactive shells
  • Offers built-in support for command suggestions and auto-completion
  • Includes features like command history and customizable prompts out-of-the-box

Cons of ishell

  • May be overkill for simpler line editing needs
  • Has a steeper learning curve due to its more extensive API
  • Potentially higher memory footprint for basic use cases

Code Comparison

ishell example:

shell := ishell.New()
shell.AddCmd(&ishell.Cmd{
    Name: "greet",
    Help: "greet user",
    Func: func(c *ishell.Context) {
        c.Println("Hello!")
    },
})
shell.Run()

liner example:

line := liner.NewLiner()
defer line.Close()
for {
    if input, err := line.Prompt("> "); err == nil {
        fmt.Println("You entered:", input)
    }
}

ishell provides a more structured approach to building interactive shells with built-in command handling, while liner focuses on basic line editing functionality. ishell is better suited for complex CLI applications, whereas liner is more appropriate for simpler input scenarios or as a building block for custom shell implementations.

9,827

Minimalist Go package aimed at creating Console User Interfaces.

Pros of gocui

  • Provides a full-featured text-based user interface (TUI) framework
  • Supports multiple views and layouts for complex terminal applications
  • Offers event-driven programming with customizable keybindings

Cons of gocui

  • Steeper learning curve due to more complex API
  • Heavier resource usage for simple command-line interfaces
  • Less suitable for basic line editing tasks

Code Comparison

gocui example:

g, err := gocui.NewGui(gocui.OutputNormal)
if err != nil {
    log.Panicln(err)
}
defer g.Close()

g.SetManagerFunc(layout)

liner example:

line := liner.NewLiner()
defer line.Close()

name, err := line.Prompt("What is your name? ")
if err != nil {
    log.Print("Error reading line: ", err)
}

Summary

gocui is a comprehensive TUI framework suitable for building complex terminal applications with multiple views and layouts. It offers more flexibility but requires more setup and resources. liner, on the other hand, is a simpler library focused on providing line editing capabilities for command-line interfaces. It's easier to use for basic input tasks but lacks the advanced features of gocui.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Liner

Liner is a command line editor with history. It was inspired by linenoise; everything Unix-like is a VT100 (or is trying very hard to be). If your terminal is not pretending to be a VT100, change it. Liner also support Windows.

Liner is intended for use by cross-platform applications. Therefore, the decision was made to write it in pure Go, avoiding cgo, for ease of cross compilation. Furthermore, features only supported on some platforms have been intentionally omitted. For example, Ctrl-Z is "suspend" on Unix, but "EOF" on Windows. In the interest of making an application behave the same way on every supported platform, Ctrl-Z is ignored by Liner.

Liner is released under the X11 license (which is similar to the new BSD license).

Line Editing

The following line editing commands are supported on platforms and terminals that Liner supports:

KeystrokeAction
Ctrl-A, HomeMove cursor to beginning of line
Ctrl-E, EndMove cursor to end of line
Ctrl-B, LeftMove cursor one character left
Ctrl-F, RightMove cursor one character right
Ctrl-Left, Alt-BMove cursor to previous word
Ctrl-Right, Alt-FMove cursor to next word
Ctrl-D, Del(if line is not empty) Delete character under cursor
Ctrl-D(if line is empty) End of File - usually quits application
Ctrl-CReset input (create new empty prompt)
Ctrl-LClear screen (line is unmodified)
Ctrl-TTranspose previous character with current character
Ctrl-H, BackSpaceDelete character before cursor
Ctrl-W, Alt-BackSpaceDelete word leading up to cursor
Alt-DDelete word following cursor
Ctrl-KDelete from cursor to end of line
Ctrl-UDelete from start of line to cursor
Ctrl-P, UpPrevious match from history
Ctrl-N, DownNext match from history
Ctrl-RReverse Search history (Ctrl-S forward, Ctrl-G cancel)
Ctrl-YPaste from Yank buffer (Alt-Y to paste next yank instead)
TabNext completion
Shift-Tab(after Tab) Previous completion

Note that "Previous" and "Next match from history" will retain the part of the line that the user has already typed, similar to zsh's "up-line-or-beginning-search" (which is the default on some systems) or bash's "history-search-backward" (which is my preferred behaviour, but does not appear to be the default Up keybinding on any system).

Getting started

package main

import (
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/peterh/liner"
)

var (
	history_fn = filepath.Join(os.TempDir(), ".liner_example_history")
	names      = []string{"john", "james", "mary", "nancy"}
)

func main() {
	line := liner.NewLiner()
	defer line.Close()

	line.SetCtrlCAborts(true)

	line.SetCompleter(func(line string) (c []string) {
		for _, n := range names {
			if strings.HasPrefix(n, strings.ToLower(line)) {
				c = append(c, n)
			}
		}
		return
	})

	if f, err := os.Open(history_fn); err == nil {
		line.ReadHistory(f)
		f.Close()
	}

	if name, err := line.Prompt("What is your name? "); err == nil {
		log.Print("Got: ", name)
		line.AppendHistory(name)
	} else if err == liner.ErrPromptAborted {
		log.Print("Aborted")
	} else {
		log.Print("Error reading line: ", err)
	}

	if f, err := os.Create(history_fn); err != nil {
		log.Print("Error writing history file: ", err)
	} else {
		line.WriteHistory(f)
		f.Close()
	}
}

For documentation, see http://godoc.org/github.com/peterh/liner