peterh / liner Goto Github PK
View Code? Open in Web Editor NEWPure Go line editor with history, inspired by linenoise
License: MIT License
Pure Go line editor with history, inspired by linenoise
License: MIT License
The Documentation says that in order to move to the prev/next word we need to press the Ctrl + < / Ctrl + > keys. For the mac it seems to be Ctrl + command + arrow key.
Is this expected ?
Thanks
Ik.
Home and end buttons don't seem to do anything. These would be really useful for expediting cursor movement.
That switches Spaces in the OS. Can it be Alt-B/F like in readline?
Maybe this is the default behavior but I'm not sure because I have never seen it before in other programs. When you have a really long line, that is longer than your terminal window, instead of doing word wrap it just scrolls on the same line using {
and }
to signal that some text is missing in some direction.
That works great, but the moment when you go from having a line of the width of your terminal to having a line one char longer, a new line is inserted and the prompt gets redrawned with the {
and then the scrolled part of the line. if you then press backspace then again it prints a new line followed by the previous line (the one without the {
and }
for indicating scrolling).
Maybe it's just me but if it isn't a bug, I think that the whole print in a new line is unnecessary. I'm testing it on Windows 8.1.
For instance, to be used in influxdata/influxdb#4279.
Using PasswordPrompt with SetCtrlCAborts(true) doesn't result in liner.ErrPromptAborted as expected, instead results in an "liner: internal error" error.
I tried to redirect the output of my application to a file and I got an error "standard output is not a terminal" (errNotTerminalOutput) from Prompt()
A couple of options:
Thanks!
-- Raffaele
hi, I try add some color to prompt, but it seems not working properly.
would you please support this?
(*State).Prompt return ErrNotTerminalOutput
when called from called from "eshell" or "shell-mode" in Emacs because it doesn't know how many columns the output is (I believe that's the correct interpretation of https://github.com/peterh/liner/blob/master/input.go#L70, which is where outputRedirected is being set). (*State).promptUnsupported works, though, and if you move the terminalSupported check above the outputRedirected check (https://github.com/peterh/liner/blob/master/line.go#L472), everything works as expected.
Liner is great, thanks for the solid library.
When doing autocomplete I think that the autocomplete should be more similar to the one in bash.
Right now, the behavior is to loop through the slice returned by the complete func. In bash the behavior is, when only one string is returned by the complete function, then it uses it, but when more than one can match then a list is displayed instead of doing the autocomplete. This example shows how bash complete works.
I think a good option would be to include an option to toggle the "type" of complete to use or to make a hybrid of them. When the complete function returns a slice with more than one option, at first imitate bash behavior, (double tab shows a list of the options) and then if you press tab again then start cycling though the slice.
I think this would be particularly good because some times you are not sure which option you want to use and cycling through the options is not as helpful in those cases as seeing all the options at once.
Hello,
Can you please tag and version this project?
I am the Debian Maintainer for liner and versioning would help Debian keep up with development.
Hi,
Is it possible to have the value of the HistoryLimit be exposed ? I wanted to set the limit based on user input.
Thanks
I have some code like this:
for {
prompt := liner.NewLiner()
line, err := prompt.Prompt("> ")
prompt.Close()
if err != nil {
if err == io.EOF {
return
}
log.Print(err)
} else {
parse(line)
}
}
I need to close prompt because parse may need to take over stdin. It seems wasteful to call NewLiner with each iteration; is there interest in adding methods like Start and Stop in addition to Close?
Before I start working on it, I wanted to know if you will be willing to accept a push request implementing a password prompt.
Just a prompt that doesn't supports fancy line editing but by default doesn't print what you are entering, like Unix password prompt. Maybe in windows print * instead of not printing anything.
Just noticed that the home/end do not work on linux. C-a/C-e work ok.
Hi there,
I am working on a simple terminal-based todolist app, and I'm currently focusing on editing a todo. Ideally for editing I would allow the user to edit the existing todo description by showing it on the screen, something like this:
~ todo edit 56
> have lunch with @frank due tomorrow <cursor here>
The user could backspace, etc or edit text on the screen. I've been looking at a few golang libraries that emulate readline but don't quite do exactly what I need above. I am wondering if this is something that I could use liner to do.
It's almost like I need to prompt the user with the exiting todo text, but obviously liner would not allow the user to backspace or use the left arrow key to edit the todo.
Anyways, I know this isn't an issue with liner. I just figured I'd reach out to see if this is something you might be able to point me in the right direction. Thanks so much!
Please create a simple getting started example.
Thank you
Hi we are making use of your liner library in a command line tool we are working. We have noticed that we are getting intermittent crashes with the following stack trace. I was hoping you might be able to shed some light on the problem. Thanks.
pureweb >Exception 0xc0000005 0x1 0xc082063988 0x7720c4d0
PC=0x7720c4d0
signal arrived during cgo execution
syscall.(_Proc).Call(0xc08208bf20, 0xc0820479c0, 0x4, 0x4, 0x1, 0x0, 0x0, 0x0)
c:/go/src/syscall/dll_windows.go:136 +0x5c2
syscall.(_LazyProc).Call(0xc082005ef0, 0xc0820479c0, 0x4, 0x4, 0x1, 0x0, 0x0, 0x
0)
c:/go/src/syscall/dll_windows.go:279 +0x74
github.com/peterh/liner.(_State).readNext(0xc0820680a0, 0x0, 0x0, 0x0, 0x0)
E:/bamboobuilds/PWEB-PMGN-WIN/src/gocode/src/github.com/peterh/liner/inp
ut_windows.go:160 +0x182
github.com/peterh/liner.(_State).Prompt(0xc0820680a0, 0x7787b0, 0x9, 0x0, 0x0, 0
x0, 0x0)
E:/bamboobuilds/PWEB-PMGN-WIN/src/gocode/src/github.com/peterh/liner/lin
e.go:492 +0x358
github.com/gobs/cmd.(*Cmd).CmdLoop(0xc082068000)
E:/bamboobuilds/PWEB-PMGN-WIN/src/gocode/src/github.com/gobs/cmd/cmd.go:
564 +0xb1
main.main()
E:/bamboobuilds/PWEB-PMGN-WIN/src/gocode/src/calgaryscientific.com/purew
eb-cli/main.go:70 +0xaaa
goroutine 5 [syscall, 1110 minutes]:
os/signal.loop()
c:/go/src/os/signal/signal_unix.go:21 +0x26
created by os/signal.init-+1
c:/go/src/os/signal/signal_unix.go:27 +0x3c
goroutine 13 [chan receive, 1110 minutes]:
main.func-+001()
E:/bamboobuilds/PWEB-PMGN-WIN/src/gocode/src/calgaryscientific.com/purew
eb-cli/main.go:57 +0x74
created by main.main
E:/bamboobuilds/PWEB-PMGN-WIN/src/gocode/src/calgaryscientific.com/purew
eb-cli/main.go:62 +0xa30
goroutine 56 [IO wait, 127 minutes]:
net.(_pollDesc).Wait(0xc08207a170, 0x72, 0x0, 0x0)
c:/go/src/net/fd_poll_runtime.go:84 +0x4e
net.(_ioSrv).ExecIO(0xc082040148, 0xc08207a060, 0x75a5b0, 0x7, 0x7f8090, 0x0, 0x
0, 0x0)
c:/go/src/net/fd_windows.go:188 +0x305
net.(_netFD).Read(0xc08207a000, 0xc082011000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
c:/go/src/net/fd_windows.go:470 +0x180
net.(_conn).Read(0xc082040168, 0xc082011000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
c:/go/src/net/net.go:121 +0xe3
net/http.noteEOFReader.Read(0x283998, 0xc082040168, 0xc082028058, 0xc082011000,
0x1000, 0x1000, 0x6bb9a0, 0x0, 0x0)
c:/go/src/net/http/transport.go:1270 +0x75
net/http.(_noteEOFReader).Read(0xc082007480, 0xc082011000, 0x1000, 0x1000, 0xc08
2012000, 0x0, 0x0)
:125 +0xdb
bufio.(_Reader).fill(0xc082042de0)
c:/go/src/bufio/bufio.go:97 +0x1d5
bufio.(_Reader).Peek(0xc082042de0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0)
c:/go/src/bufio/bufio.go:132 +0xf7
net/http.(_persistConn).readLoop(0xc082028000)
c:/go/src/net/http/transport.go:842 +0xab
created by net/http.(*Transport).dialConn
c:/go/src/net/http/transport.go:660 +0xca6
goroutine 57 [select, 127 minutes]:
net/http.(_persistConn).writeLoop(0xc082028000)
c:/go/src/net/http/transport.go:945 +0x424
created by net/http.(_Transport).dialConn
c:/go/src/net/http/transport.go:661 +0xcc3
rax 0x1
rbx 0x1
rcx 0x7746ddda
rdx 0x0
rdi 0x0
rsi 0x0
rbp 0x8f8820
rsp 0x6fcd0
r8 0x6fc98
r9 0x8f8820
r10 0x0
r11 0x246
r12 0xc082063988
r13 0xc0820639ac
r14 0x20
r15 0x10
rip 0x7720c4d0
rflags 0x10246
cs 0x33
fs 0x53
gs 0x2b
Running influx in a docker container, I came across this issue. The terminal configured was extremely basic and apparently had no screen size defined in stty.
`InfluxDB shell version: 0.13.0
panic: runtime error: integer divide by zero
[signal 0x8 code=0x1 addr=0x61f870 pc=0x61f870]
goroutine 1 [running]:
panic(0x786fa0, 0xc82000a060)
/usr/local/go/src/runtime/panic.go:481 +0x3e6
github.com/peterh/liner.(*State).refreshMultiLine(0xc8200823c0, 0xc8200ed410, 0x2, 0x2, 0xc82000b910, 0x1, 0x2, 0x1, 0x0, 0x0)
/root/go/src/github.com/peterh/liner/line.go:159 +0xf0`
influxdb@deis-monitor-influxdb-4qttw:~$ stty -a speed 38400 baud; rows 0; columns 0; line = 0;
$ go run allcomp.go
> [Tab] [Tab]
Display all 101 possibilities? (y or n) [Return]
2016/01/13 19:57:22 liner: internal error
$
I'd expect it to either keep waiting for a y/n press (like it does if you press m for maybe) or take Return to mean the affirmative?
package main
import (
"strings"
"log"
"github.com/peterh/liner"
)
var (
names = []string{
"xxxxx", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10",
"a11", "a12", "a13", "a14", "a15", "a16", "a17", "a18", "a19", "a20",
"a21", "a22", "a23", "a24", "a25", "a26", "a27", "a28", "a29", "a30",
"a31", "a32", "a33", "a34", "a35", "a36", "a37", "a38", "a39", "a40",
"a41", "a42", "a43", "a44", "a45", "a46", "a47", "a48", "a49", "a50",
"a51", "a52", "a53", "a54", "a55", "a56", "a57", "a58", "a59", "a60",
"a61", "a62", "a63", "a64", "a65", "a66", "a67", "a68", "a69", "a70",
"a71", "a72", "a73", "a74", "a75", "a76", "a77", "a78", "a79", "a80",
"a81", "a82", "a83", "a84", "a85", "a86", "a87", "a88", "a89", "a90",
"a91", "a92", "a93", "a94", "a95", "a96", "a97", "a98", "a99", "a100"}
)
func main() {
line := liner.NewLiner()
defer line.Close()
line.SetTabCompletionStyle(liner.TabPrints)
line.SetCompleter(func(line string) (c []string) {
for _, n := range names {
if strings.HasPrefix(n, strings.ToLower(line)) {
c = append(c, n)
}
}
return
})
log.Println(line.Prompt("> "))
}
Hey,
Thanks for this plug in, we use it for some of our admin tools. It's brilliant! I was wondering if you guys had any plans to support word wrap. We sometimes have long strings of json that would be much easier to work with if it didn't trail off the screen.
Thanks!
Jono
Hello,
Currently, the completion seems to work only at the end of the line.
Would it be possible to make it work at current cursor position ?
For an example:
sql> create table test (id int, name text);
sql> select t. from test t;
When the cursor is after the dot, the table columns can be completed.
Regards.
It could be nice to have the hardcoded "^C" print removed when pressing ctrl+c. I would like the decision whether to print out "^C" handed out to the user.
Why is completion not starting from the begining after last element in the list.
I know there is shift tab but this is not how redis-cli or shell works.
It would be very useful to have a callback (or similar) to make it possible to override some key behaviours as well as trap other keys.
For example, I would like to disable Ctrl-L from rewriting the screen empty.
It would also be very useful to be able to trap a key combinations and do other things - for example trap a Ctrl- to make the application do something completely different, and just cancel the prompt at that point.
Probably the same feature could be used for both those, as long as there can be a return value that specifies "do what you would normally do", "ignore this key" or "abort the prompt at this stage".
Steps to reproduce:
At this point navigation of the multi-line item is messed up.
Moreover, if the prompt is already at the bottom of the terminal, the terminal gets messed up as well (cursor blocked at bottom while the lines above it get updated).
Hello,
Thanks for this library.
As noticed in this issue on the go-ethereum project, liner is quite slow in processing the input, which is noticeable when pasting large amounts of data. For example pasting 30KB takes up to 1 minute. In comparison linenoise takes a few seconds.
Maybe the "refresh" functions could be optimized somehow to speed it up?
Each time you call NewLiner after the first time it swallows a character from input when you call Prompt.
Here's an example: https://gist.github.com/larzconwell/9624785
Actual output:
> sdf # Input 'sdf'
s
> df # Input 'sdf'
df
Expected output:
> sdf # Input 'sdf'
sdf
> sdf # Input 'sdf'
sdf
I'd love to be able to do something like
text := "sometext"
line := liner.NewLiner()
line.Prompt("> ", text)
which will make a prompt > sometext
where sometext
is editable.
Is there any way to do this?
Another (last) feature that I think it's missing from liner si searching the history.
Try ctrl+r in bash or zsh to test it, can you think of a simple way to get it working?
-rif
Hi,
I was running the sample example provided and when i resized my screen while typing out the answer, the following happened ->
$ ./temptest
What is your name? ueshaaWhat is your name? {haaWhat is your name? {aWhat is your name? What is your nameWhat is your naWhat iWhat iWhat iWhat iWhat iWhat iWhat iWhat iWhat iWhWhat is your name? uWhat is your name? uWhat is your namWhatWhatWhWhWhatWhat iWhat is yoWhat is your name? uesWhat is yourWhat is your name? uesWhat is What is your nWhat iWhWhWhWhat is your name? ueshaa
Is this a bug ?
Thanks
Ik
Input: enter こんにちは after a call to Prompt, then arrow left and right.
Expected behaviour: the cursor moves by the full width of the character it is moving over.
Actual behavior: the cursor moves by a half character width.
If you hit up a few times to get to a previous item from the history and then move the cursor, up/down (as well as ctrl-p/ctrl-n) no longer do anything.
(In my testing, I did find a case one or two times where it did start working again afterwards in a buggy way for some reason, but mostly it just didn't work. I'm hoping it's easy for you to reproduce.)
I checked that redis-cli doesn't have this problem, so I'm assuming linenoise handles this fine.
When I use color sequences in my prompt string I get problems with any non-printing characters afterwards. For example, if I set my prompt to something like this:
line.Prompt("\x1b[0;32mPrompt>\x1b[0m ")
Whenever I hit "up" to view the history, it prints the string correctly at the beginning of the line but then adds tons of white space to the end it. If I try to erase characters from this, the cursor remains far down the line (after the white space) but the characters do get erased.
So either I misunderstood the \x1b[0m reset code's function or something else is going on I'm unaware of.
Would it possible to have autocompletion for multiple words in the line?
For example:
prompt> get_cost ArticleId=123
to be written like: type ge[TAB] than Ar[TAB]=123 and so on.
If you start liner_test
and type ls ..<tab>
, the program crashes with a panic, due to calling unwrap()
on None
.
Should the tab completion function return control back to the main loop in Prompt if the completer only returns a single completion candidate?
This would be here:
line.go L255-L259
and look something like
head, list, tail := s.completer(string(line), pos)
if len(list) <= 0 {
return line, pos, rune(esc), nil
}
hl := utf8.RuneCountInString(head)
if (len(list) == 1) {
return []rune(head + list[0] + tail), hl + utf8.RuneCountInString(list[0]), rune(esc), nil
}
Doing this will allow multiple successive tab completions. If I'm writing a prompt that can change directories, then I'm going to (possibly) successively tab through directory completions without typing a key other than TAB.
I'm not sure if the current behavior (exiting tabComplete only on another keypress) is expected when there is only a single completion or not.
Thanks!
Andrew
When I'm trying to ctrl+left/right to the next word in my text, instead of moving the cursor, it prints [1;2D
The use case is to colorize the prompt. If the prompt-string input to line.Prompt() is colored, the tab completion moves the cursor much further. The tab works well with regular non-colored strings. I tried different ways to escape the strings but had not luck.
Operating System: Linux Centos
Terminal Emulator: ssh via Mac Terminal.
Here is the issue which is specific to readline/python:
http://wiki.hackzine.org/development/misc/readline-color-prompt.html
I tried escaping my string in the following ways:
// Colorize given string.
func green(s string) string {
// return "\x01\x1b[0;32m\x02" + s + "\x01\x1b[0m\x02"
// return "\001\033[1;32m\002" + s + "\001\033[0m\002"
// return "[1;32m" + s + "[0m"
}
None of the above ways helped.
Hi,
When using the liner, if I type more characters than the width of the terminal, the characters to the left disappear into " { " . Is there a way to wrap the input to the next line ?
Thanks
I know one of the objectives of the project is to keep it simple and limit the configuration options in order to do so. But it would be very useful for some users to be able to change the HistoryLimit and KillRingMax constants. What do you think about it?
It would be great if there was a flag to set either globally or on the call to Prompt to prevent the final newline (that's written on line.go line 515, if I read the code correctly).
I've got an app where I'd really prefer that the whole output didn't shift up by one line once enter is hit after the prompt if it's on the last line.
Would it be possible to add an Abort method so that a call to Prompt could be aborted?
If that's possible, it would also be great if there was a way to know that Prompt was aborted when it returns.
For people using this library in CLI tools, it's always interesting to be able to get the history without needing to re-read the history file(s).
Hello! First of all, thanks for making a great library. I've been happily building a REPL on top of it for a little while now.
Recently, I noticed an issue when pasting text containing newlines into the REPL. Specifically, liner doesn't display the pasted text, however, it seems that liner has received the text and passed it to the REPL.
I only noticed this after recently updating to the tip of master. I manually bisected the history and found that the behaviour changed with 2d7c636 (which fixed #81).
It may be a bit tricky to reproduce this bug in isolation. The key (in my case) seems to be pasting text containing newlines. If the text doesn't contain a newline, it displays fine.
I can offer you a working example (on Mac):
torin:~$ cat >test <<EOF
> p :- true
> EOF
torin:~$ pbcopy < test
torin:~$ docker run -it --rm openpolicyagent/opa:0.2.1
OPA 0.2.1 (commit b3f62a1, built at 2016-11-23T16:33:13Z)
Run 'help' to see a list of commands.
> p :- true
>
Note: the paste happens on the first non-empty line after "Run 'help' to see [...]", i.e., "> p :- true".
When I do the same with openpolicyagent/opa:0.2.2, I only see an empty line:
torin:~$ docker run -it --rm openpolicyagent/opa:0.2.2
OPA 0.2.2 (commit fb9e6c7, built at 2016-12-01T01:41:03Z)
Run 'help' to see a list of commands.
>
>
In v0.2.1 OPA is using 8975875 and in v0.2.2 OPA is using 3c5f577. This is what I get for not pinning dependencies with Glide.
Is there a way to output something to the user while in prompt (from a separate go routine) - so that the output will be printed on a separate line and the prompt will be refreshed on a line below?
I made an ugly hack to make it work by creating a public function InjectString that saves the string to be injected on the State and pushed a marker rune on State.next.
Then, I handle it in State.Prompt by doing:
case inject:
s.cursorPos(0)
s.eraseLine()
fmt.Println(s.injected)
s.refresh(p, line, pos)
But, it is really an ugly hack. I needed to change State.next to a regular channel so that I can write to it and not only read from it...
There must be a better way but I could not find it in a few minutes of looking in the code.
Bug report
-Sample Example :
In the beginning it looked like ->
Connected to : http://localhost:8091/. Type Ctrl-D or \QUIT to exit.
Path to history file for the shell : /Users/isha/.cbq_history
cbq>
After scrolling through history a bit then it eats up a previous line
Connected to : http://localhost:8091/. Type Ctrl-D or \QUIT to exit.
cbq> CREATE INDEX ......
The above Path to ... line is replaced.
Thanks
Isha
Long completions can cause liner to panic when the tab completion style is set to liner.TabPrints.
Run the modified example code below. When prompted for your name, type 'p' and then hit Tab twice.
package main
import (
"log"
"os"
"strings"
"github.com/peterh/liner"
)
var (
history_fn = "/tmp/.liner_history"
names = []string{
"john",
"james",
"mary",
"nancy",
"probably not a very common name but a useful string to demonstrate what currently happens with a completion longer than the terminal width",
"panic appears to happen when tab completion style is TabPrints",
}
)
func main() {
line := liner.NewLiner()
defer line.Close()
line.SetCtrlCAborts(true)
line.SetTabCompletionStyle(liner.TabPrints)
// Remainder unchanged.
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()
}
}
(Sorry for abusing the issue mechanism; I am not overly familiar with Github and didn't find another way to to reach you.)
I just wanted to let me know that I use your "liner" as the input line editor for my Lisp interpreter in Go "lingo" https://github.com/jyrgenn/lingo. Lingo is just a toy project, and I didn't want to put much time into a component that is not so closely related, programming-wise, to what I wanted to do playing around with implementing (yet another) Lisp.
So, thanks for "liner"! It is just what I was looking for, and I was able to put it to good use fast thanks to the good documentation and the example.
Best wishes, Juergen.
(And of course you can close this issue immediately. :–)
Thank you for this amazing pice a code!
I'd like to offer a default text after the prompt that can be corrected/edited by the user. Is that possible? Or is there a workaround? thx
myPrompt> default text for correction
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.