Configurable, extensible, interactive line reader

Overview

linefeed

linefeed is a configurable, concurrent, extensible, interactive input reader for Unix terminals and Windows console.

API Documentation

linefeed follows the paradigm of GNU Readline, binding key sequences to commands that modify input state. linefeed supports many GNU Readline commands. However, linefeed does not implement all commands supported by GNU Readline. If there's a command you want to be implemented, file an issue!

linefeed also interprets GNU Readline inputrc configuration files. First, it will check for a filename in the environment variable INPUTRC. Then, on Unix, it will check $HOME/.inputrc or /etc/inputrc; while, on Windows, it will check %APPDATA%\linefeed\inputrc. Only the first of these that is present is parsed and evaluated.

Building

To include linefeed in your project, add the following to your Cargo.toml:

[dependencies]
linefeed = "0.6"

Demo

The linefeed project contains a demo program for testing functionality. To run the demo, run the following from a clone of the linefeed project:

cargo run --example demo

License

linefeed is distributed under the terms of both the MIT license and the Apache License (Version 2.0).

See LICENSE-APACHE and LICENSE-MIT for details.

Comments
  • No way to get a reader.term from outside

    No way to get a reader.term from outside

    Hi! Thanks for the project, it has a much more useful API then others similar libs have. I can adjust almost anything to my purpose, although I can't use a term which is captured by Reader. Can we make it public?

    The use case would be for defining Function printing some text after the prompt and refreshing an input line. It may be the function which is printing hints for the argument under cursor. Now there's only one way to implement this logic — through LogSender, but it prints line before the prompt and avoids a terminal escapes. I want to make function which would works just like completer it would seems prettier.

    Following changes are resolving the problem:

    • Implement term_mut and (for symmetry) term:
    impl<Term: Terminal> Reader<Term> {
        // ...
        /// Returns a mutable reference to `Term`.
        pub fn term_mut(&mut self) -> &mut Term { &mut self.term }
        /// Returns a immutable reference to `Term`.
        pub fn term(&self) -> &Term { &self.term }
        // ...
    }
    
    • Make method draw_prompt of Reader public (or create similar method called refresh_line):
    impl<Term: Terminal> Reader<Term> {
        // ...
        pub fn draw_prompt(&mut self) -> io::Result<()> { /* ... */ }
        // ...
    }
    

    Or maybe there's some purpose why the Term's hidden?

    opened by survived 14
  • Question - binding history-search-backward?

    Question - binding history-search-backward?

    Hi, I'm using linefeed to implement the history-search-backward in bash. Say I have this in history:

    $ echo foo
    $ ls src/
    $ echo bar
    

    Then, in shell, I type:

    $ ec<UP>
    

    and I should get echo bar in command line. I have this implemented here.

    However, after echo bar shows up, a second <UP> key should fetch echo foo, (didn't get this implemented). Any suggestions to implement the second <UP> key bindings?

    opened by mitnk 12
  • Add a mechanism to interrupt `Reader::read_line` without user input.

    Add a mechanism to interrupt `Reader::read_line` without user input.

    Currently only user input, or an operating system specific signal can interrupt a running Reader::read_line call.

    This is not sufficient for concurrent applications that may need to terminate due to reasons other than user input on terminal.

    opened by Lymia 10
  • Access to the input when Signal happened.

    Access to the input when Signal happened.

    Hello, i'm writing a program with a REPL interface. So i give linefeed a test and it looks nice!

    However I've met with a problem: I want to simulate the Node.js style Ctrl-C handling: only erase current input if the input's not empty, prompt for first key-press and exit for the second when input is not.

    Currently linefeed can give Ctrl-C as an Interrupt Signal, without any indication on whether user has input something.

    opened by crlf0710 8
  • Stuck while do path completion with too many files

    Stuck while do path completion with too many files

    $ cd linefeed/
    $ mkdir tmp
    $ python
    >>> for i in range(1000):
    >>>     open('./tmp/f-{}.txt'.format(i), 'wb').close()
    >>>
    >>> exit()
    

    now we have 1000 files under ./tmp/

    $ cargo run --example path_completion
    path> ./tmp/f-<TAB><TAB>
    

    Now we stuck in path completing.

    opened by mitnk 7
  • Issues found after the Reader rewrite

    Issues found after the Reader rewrite

    1. Methods set_history_size() and history_size are missing

    2. Both reader.rs and interface.rs has a set_prompt; and the color escape sequences seems not work any more.

    3. issue #38 still not fixed

    opened by mitnk 6
  • Print immediately from a LogSender if read_line() call is not in progress

    Print immediately from a LogSender if read_line() call is not in progress

    This is again because I'm making a log logger that outputs without messing up linefeed, and would also be a breaking change.

    Since LogSender writes only actually get written during read_line, something like the following has unintuitive (albeit documented) behavior:

    fn main() {
        let mut reader = Reader::new("...").unwrap();
        logger::init(reader.get_log_sender()).unwrap();
        loop {
            let n: usize = match reader.read_line().unwrap() {
                ReadResult::Input(s) => s.parse().unwrap(),
                _ => unimplemented!(),
            };
            
            let out = (0..n).into_par_iter()
                .map(process)
                .sum();
            println!("Got {}", out);
        }
    }
    
    fn process(x: usize) -> usize {
        info!("About to process {}", x);
        // pretend this is work-intensive enough that rayon actually parallelizes
        // it, so we actually need the LogSender
        x + 1
    }
    

    One would expect that the output would look like:

    About to process 0
    About to process 1
    About to process 2
    About to process 3
    Got 10
    

    But instead, you get:

    Got 10
    About to process 0
    About to process 1
    About to process 2
    About to process 3
    

    since the LogSender-sent messages aren't printed until the next call to read_line.

    Something (that I now realize won't work) would be to change the _send_counter in LogSender to be Arc<Mutex<()>>, and lock it whenever in read_line or printing directly from LogSender? Then if LogSender can't lock it, it'll send the messages via the channel.

    There's a data race there, though, if Reader has the lock, LogSender checks for the lock and fails to acquire it, and Reader drops it and exits before LogSender finishes sending the message on the Sender<String>. If you can think of a way to implement this that doesn't have the race, I'd be happy to write the actual code.

    opened by remexre 6
  • Ability of Telling if User Changed Buffer when Editing History Items

    Ability of Telling if User Changed Buffer when Editing History Items

    Say we have following 3 history items:

    $ echo 123
    $ echo 222
    $ echo 135
    

    Let's fetch back echo 123 this way:

    $ echo<UP>  # and now "echo 135" shows up
    # let's edit the buffer to "echo 1" from "echo 135", and then up:
    $ echo 1<UP> # and now "echo 123" shows up. (wanted result, but linefeed may not able to do this)
    

    I'm not sure linefeed is able to tell if the "echo 1" was edited by user, and want to "search history further with it". With reader.buffer() and reader.backup_buffer(), we cannot do it, because when we hit UP on "echo 1" as above, buffer is "echo 1" and backup_buffer is "echo" - It cannot tell whether user want to search till "echo 222" or "echo 123".

    opened by mitnk 6
  • Looping History with Unicode Items

    Looping History with Unicode Items

    When adding history and fetch them back with Ctrl+P, Unicode item would result wrong buffer rendering.

    demo $ echo hi
    hi
    demo $ ls 世界
    ls: 世界: No such file or directory
    demo $ echo yoo
    yoo
    

    Then, let's fetch items back with Ctrl+P:

    demo $ echo yoo       # <-- first `Ctrl+P` got "echo yoo", good!
    demo $ ls 世界      # <-- second, we got "ls 世界", good!
    demo $ lsecho hi    # <-- now a third `Ctrl+P` fetched something weird
    

    Though, when you hit ENTER now, you will get output "hi", which means this is only a rendering issue. It is actually "echo hi" in buffer, not "lsecho hi".

    opened by mitnk 6
  • Move to winapi 0.3

    Move to winapi 0.3

    The winapi crate has been on 0.3 for a while, which offers much better compile times for most code bases since you can pick to compile and bind against just the win32 modules you'll be using.

    opened by Lokathor 5
  • Fix ioctl() call compilation error for freebsd

    Fix ioctl() call compilation error for freebsd

    This is a temporary fix to https://github.com/rust-lang/libc/pull/704 and fixes #12.

    May want to remove when rust libc accepts https://github.com/rust-lang/libc/pull/704.

    opened by gchers 5
  • Support for arbitrary streams for input/output

    Support for arbitrary streams for input/output

    It seems that linefeed currently only supports standard input/output. Goose will accept connections via telnet and expose a command line interface, which allows users to control their load tests. We would like to use linefeed to improve the UX of the said command line, but we would need to be able to wire it into a TCP stream instead of stdin/stdout.

    I would like to propose to make it possible to wire linefeed into an arbitrary input/output stream. This approach would allow us to achieve what we want while also opening a lot of other possibilities for the library.

    Is this something that would be considered? Are there any plans to do that already?

    opened by slashrsm 0
  • Linefeed Repo Maintaining

    Linefeed Repo Maintaining

    Hello there @murarth Our team has been using your linefeed library in our project and while its very good, it does have some bugs (seemingly centered around Windows machines) and would like to help resolve them, if you would be kind enough to provide some attention to this.

    Our developers and users do enjoy the functionality that linefeed gives you, but these flaws certainly spoil the overall image of it. Also I’m convinced that our users would be of a similar mind.

    I do see some of our issues are outlined on open Issue cards, so we will do our best to summarize below.

    1. Windows specific from what we can see - the terminal’s cursor stays statically printed on the screen at a certain line although we’ve already moved to another line (one or far away) with an active cursor, blinking. After you reset the terminal or scroll out of the area and come back then, you cannot see it anymore as the inner area of the terminal window has been re-rendered. I assume that it’s something to do with what you’re doing with hiding and showing the cursor (for example, at on our test, we saw some suspicious escape sequences in the output, which was supposed to be blank string; this pointed us to that thought too).

    2. Again mainly Windows, as far as we know - certain machines (the latest or modern Windows distributions) we experience unpleasantly slow backspacing. It’s most noticeable if you have long sequence of chars at the command line and you want to delete a bigger amount of them. If you just press backspace for a whole you will see that although you draw your finger back the cursor continue going back deleting some more characters. In this way you cannot control how many characters should be deleted exactly.

    3. Its preferred to give our users possibility to use some of those standard key combinations meant to tell to carry out certain action. For example, we’d like to have ctrl+c working. However, despite your library contains API for handling signals, these signals turn out unresponsive in the end. And this time it seems like it groups all platforms together (Linux, Windows, Mac) in this matter. Note: ctrl+d is the only signal that can be currently handled.

    opened by kauri-hero 2
  • Ctrl+C stops working even if I ask linefeed not to touch signals

    Ctrl+C stops working even if I ask linefeed not to touch signals

    Even after editor.lock_reader().set_catch_signals(false); it still blocks Ctrl+C from existing the application.

    And I still see rt_sigaction(SIGINT, {s... in strace output.

    Trying to turn off catching signals actually makes it not to exit on SIGQUIT as well.

    opened by vi 0
  • Idle timeout

    Idle timeout

    Would it be possible to add an idle timeout to the terminal? If the user did not type any key for a certain duration, then read_line() could return ReadResult::TimedOut.

    opened by thyagarajan-balakrishnan 0
  • "The handle is invalid" running inside Cygwin on Windows 10

    Hi, this combination might be out of scope but I can spend some time helping diagnose it.

    Compiling in Windows 10, the program runs fine under PowerShell and CMD.EXE, but crashes when run from the Cygwin console:

    $ cargo run
       Compiling lf v0.1.0 (C:\cygwin\home\user\linefeed-crash)
    warning: variable does not need to be mutable
      --> src\main.rs:13:7
       |
    13 |   let mut reader = Interface::new("my-application")?;
       |       ----^^^^^^
       |       |
       |       help: remove this `mut`
       |
       = note: `#[warn(unused_mut)]` on by default
    
    warning: 1 warning emitted
    
        Finished dev [unoptimized + debuginfo] target(s) in 11.76s
         Running `target\debug\lf.exe`
    Hello, world!
    Error: Os { code: 6, kind: Other, message: "The handle is invalid." }
    
    $
    

    The error happens on line 13 of the attached file: let mut reader = Interface::new("my-application")?; main.rs.txt

    Is this a known issue?

    opened by AlbertoGP 2
Owner
Murarth
Murarth
An interactive cheatsheet tool for the command-line

navi An interactive cheatsheet tool for the command-line. navi allows you to browse through cheatsheets (that you may write yourself or download from

Denis Isidoro 12.2k Dec 30, 2022
Coinlive is an interactive command line tool that displays live cryptocurrency prices.

Coinlive is an interactive command line tool that displays live cryptocurrency prices. It can also display simple historical price charts.

Mayer Analytics 9 Dec 7, 2022
ruborute is an interactive command-line tool to get asphyxia@sdvx gaming data.

ruborute Are you 暴龍天 ?. The ruborute is an interactive command-line tool to get asphyxia@sdvx gaming data. asphyxia-core/plugins: https://github.com/a

RinChanNOW! 9 Sep 28, 2022
Non-interactive nREPL client for shell scripts and command-line

nreplops-tool (nr) nreplops-tool (nr) is a non-interactive nREPL client designed to be used in shell scripts and on the command-line. Early α warning:

Matti Hänninen 3 Jul 1, 2022
A toolkit for building your own interactive command-line tools in Rust

promkit A toolkit for building your own interactive command-line tools in Rust, utilizing crossterm. Getting Started Put the package in your Cargo.tom

null 70 Dec 18, 2022
A simple, lightweight and extensible command line argument parser for rust codebases

A simple, lightweight and extensible command line argument parser for rust codebases. This crate aims to provide you with an easy-to-use and extensibl

Victor Ndaba 20 Nov 12, 2022
📰 A terminal feed reader with a fancy ui

tuifeed Developed by @veeso Current version: 0.1.1 (17/11/2021) ~ A terminal news feed reader with a fancy ui ~ tuifeed About tuifeed ?? Features ?? G

Christian Visintin 55 Jan 5, 2023
A blazingly fast rust-based bionic reader for blazingly fast reading within a terminal console 🦀

This Rust-based CLI tool reads text and returns it back in bionic reading format for blazingly fast loading and even faster reading! Bionic reading is

Ismet Handzic 5 Aug 5, 2023
Rust low-level minimalist APNG writer and PNG reader with just a few dependencies with all possible formats coverage (including HDR).

project Wiki https://github.com/js29a/micro_png/wiki at glance use micro_png::*; fn main() { // load an image let image = read_png("tmp/test.

jacek SQ6KBQ 8 Aug 30, 2023
A TUI feed reader for RSS, Atom, and (aspirationally) Podcasts

moccasin A TUI feed reader for RSS, Atom, and (eventually) Podcasts. VIM keybindings. Ranger-inspired interface. Configurable. Installation cargo inst

Tobias Fried 6 Sep 5, 2023
Monorepo for dprint—a pluggable and configurable code formatting platform

dprint Monorepo for dprint—a pluggable and configurable code formatting platform. This project is under active early development. I recommend you chec

null 1.7k Jan 8, 2023
Easy configurable tmux display-menu

tmux-easy-menu Easy configurable tmux display-menu Setup cargo build And run with ./target/debug/tmux-menu show --menu {path-to-your-config} Configu

null 18 Jan 23, 2023
Uses the cardano mini-protocols to receive every block and transaction, and save them to a configurable destination

cardano-slurp Connects to one or more cardano-node's, streams all available transactions, and saves them to disk (or to S3) in raw cbor format. Usage

Pi Lanningham 16 Jan 31, 2023
⚡️(cd with env) Is a configurable cd wrapper that lets you define your environment per directory.

⚡️cdwe (cd with env) A simple configurable cd wrapper that provides powerful utilities for customizing your envionment per directory. (For ZSH / BASH

teo 20 Aug 6, 2023
Simple OpenAI CLI wrapper written in Rust, feat. configurable prompts and models

Quick Start git clone https://github.com/ryantinder/ask-rs cd ask cargo install --path . Example ask tell me about the Lockheed Martin SR71 >> The Loc

Ryan Tinder 3 Aug 9, 2023
Create, reorder, group, and focus workspaces easily in i3. Fully configurable with enhanced polybar modules.

Create, reorder, group, and focus workspaces fast and easily in i3. Features Focus Mode: Eliminate Distractions Enable Focus Mode: Use groups and focu

i3-wsman 15 Sep 2, 2023
Configurable, smart and fast CSS/SCSS/Sass/Less formatter.

?? Malva Malva is a configurable, smart and fast CSS/SCSS/Sass/Less formatter. Why? Configurable Malva is configurable. It provides several configurat

Pig Fang 20 Oct 27, 2023
Configurable HTML/Vue/Svelte/Jinja/Twig formatter, with dprint integration.

markup_fmt markup_fmt is a configurable HTML/Vue/Svelte/Jinja/Twig formatter. Notes for Vue and Svelte Users This formatter provides some options such

Pig Fang 17 Nov 15, 2023
Calc: A fully-featured minimalistic configurable calculator written in Rust

Calc Calc: A fully-featured minimalistic configurable rust calculator Install You can install the latest version from source git clone https://github.

Charlotte Thomas 4 Nov 15, 2023