Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
2393de5d
Commit
2393de5d
authored
Mar 06, 2015
by
Felix Lange
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Godeps: add github.com/peterh/liner
parent
38f6d60e
Changes
22
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
2579 additions
and
0 deletions
+2579
-0
Godeps.json
Godeps/Godeps.json
+4
-0
COPYING
Godeps/_workspace/src/github.com/peterh/liner/COPYING
+21
-0
README.md
Godeps/_workspace/src/github.com/peterh/liner/README.md
+95
-0
bsdinput.go
Godeps/_workspace/src/github.com/peterh/liner/bsdinput.go
+39
-0
common.go
Godeps/_workspace/src/github.com/peterh/liner/common.go
+219
-0
fallbackinput.go
...s/_workspace/src/github.com/peterh/liner/fallbackinput.go
+57
-0
input.go
Godeps/_workspace/src/github.com/peterh/liner/input.go
+359
-0
input_darwin.go
...ps/_workspace/src/github.com/peterh/liner/input_darwin.go
+39
-0
input_linux.go
Godeps/_workspace/src/github.com/peterh/liner/input_linux.go
+26
-0
input_test.go
Godeps/_workspace/src/github.com/peterh/liner/input_test.go
+61
-0
input_windows.go
...s/_workspace/src/github.com/peterh/liner/input_windows.go
+313
-0
line.go
Godeps/_workspace/src/github.com/peterh/liner/line.go
+864
-0
line_test.go
Godeps/_workspace/src/github.com/peterh/liner/line_test.go
+90
-0
output.go
Godeps/_workspace/src/github.com/peterh/liner/output.go
+63
-0
output_windows.go
.../_workspace/src/github.com/peterh/liner/output_windows.go
+54
-0
prefix_test.go
Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go
+37
-0
race_test.go
Godeps/_workspace/src/github.com/peterh/liner/race_test.go
+44
-0
signal.go
Godeps/_workspace/src/github.com/peterh/liner/signal.go
+12
-0
signal_legacy.go
...s/_workspace/src/github.com/peterh/liner/signal_legacy.go
+11
-0
unixmode.go
Godeps/_workspace/src/github.com/peterh/liner/unixmode.go
+37
-0
width.go
Godeps/_workspace/src/github.com/peterh/liner/width.go
+47
-0
width_test.go
Godeps/_workspace/src/github.com/peterh/liner/width_test.go
+87
-0
No files found.
Godeps/Godeps.json
View file @
2393de5d
...
...
@@ -54,6 +54,10 @@
"ImportPath"
:
"github.com/obscuren/qml"
,
"Rev"
:
"c288002b52e905973b131089a8a7c761d4a2c36a"
},
{
"ImportPath"
:
"github.com/peterh/liner"
,
"Rev"
:
"29f6a646557d83e2b6e9ba05c45fbea9c006dbe8"
},
{
"ImportPath"
:
"github.com/rakyll/globalconf"
,
"Rev"
:
"415abc325023f1a00cd2d9fa512e0e71745791a2"
...
...
Godeps/_workspace/src/github.com/peterh/liner/COPYING
0 → 100644
View file @
2393de5d
Copyright © 2012 Peter Harris
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
Godeps/_workspace/src/github.com/peterh/liner/README.md
0 → 100644
View file @
2393de5d
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 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:
Keystroke | Action
--------- | ------
Ctrl-A, Home | Move cursor to beginning of line
Ctrl-E, End | Move cursor to end of line
Ctrl-B, Left | Move cursor one character left
Ctrl-F, Right| Move cursor one character right
Ctrl-Left | Move cursor to previous word
Ctrl-Right | Move 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-C | Reset input (create new empty prompt)
Ctrl-L | Clear screen (line is unmodified)
Ctrl-T | Transpose previous character with current character
Ctrl-H, BackSpace | Delete character before cursor
Ctrl-W | Delete word leading up to cursor
Ctrl-K | Delete from cursor to end of line
Ctrl-U | Delete from start of line to cursor
Ctrl-P, Up | Previous match from history
Ctrl-N, Down | Next match from history
Ctrl-R | Reverse Search history (Ctrl-S forward, Ctrl-G cancel)
Ctrl-Y | Paste from Yank buffer (Alt-Y to paste next yank instead)
Tab | Next completion
Shift-Tab | (after Tab) Previous completion
Getting started
-----------------
```
go
package
main
import
(
"log"
"os"
"strings"
"github.com/peterh/liner"
)
var
(
history_fn
=
"/tmp/.liner_history"
names
=
[]
string
{
"john"
,
"james"
,
"mary"
,
"nancy"
}
)
func
main
()
{
line
:=
liner
.
NewLiner
()
defer
line
.
Close
()
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
(
"Error reading line: "
,
err
)
}
else
{
log
.
Print
(
"Got: "
,
name
)
line
.
AppendHistory
(
name
)
}
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
Godeps/_workspace/src/github.com/peterh/liner/bsdinput.go
0 → 100644
View file @
2393de5d
// +build openbsd freebsd netbsd
package
liner
import
"syscall"
const
(
getTermios
=
syscall
.
TIOCGETA
setTermios
=
syscall
.
TIOCSETA
)
const
(
// Input flags
inpck
=
0x010
istrip
=
0x020
icrnl
=
0x100
ixon
=
0x200
// Output flags
opost
=
0x1
// Control flags
cs8
=
0x300
// Local flags
isig
=
0x080
icanon
=
0x100
iexten
=
0x400
)
type
termios
struct
{
Iflag
uint32
Oflag
uint32
Cflag
uint32
Lflag
uint32
Cc
[
20
]
byte
Ispeed
int32
Ospeed
int32
}
Godeps/_workspace/src/github.com/peterh/liner/common.go
0 → 100644
View file @
2393de5d
/*
Package liner implements a simple command line editor, inspired by linenoise
(https://github.com/antirez/linenoise/). This package supports WIN32 in
addition to the xterm codes supported by everything else.
*/
package
liner
import
(
"bufio"
"bytes"
"container/ring"
"errors"
"fmt"
"io"
"strings"
"sync"
"unicode/utf8"
)
type
commonState
struct
{
terminalSupported
bool
outputRedirected
bool
inputRedirected
bool
history
[]
string
historyMutex
sync
.
RWMutex
completer
WordCompleter
columns
int
killRing
*
ring
.
Ring
ctrlCAborts
bool
r
*
bufio
.
Reader
tabStyle
TabStyle
}
// TabStyle is used to select how tab completions are displayed.
type
TabStyle
int
// Two tab styles are currently available:
//
// TabCircular cycles through each completion item and displays it directly on
// the prompt
//
// TabPrints prints the list of completion items to the screen after a second
// tab key is pressed. This behaves similar to GNU readline and BASH (which
// uses readline)
const
(
TabCircular
TabStyle
=
iota
TabPrints
)
// ErrPromptAborted is returned from Prompt or PasswordPrompt when the user presses Ctrl-C
// if SetCtrlCAborts(true) has been called on the State
var
ErrPromptAborted
=
errors
.
New
(
"prompt aborted"
)
// ErrNotTerminalOutput is returned from Prompt or PasswordPrompt if the
// platform is normally supported, but stdout has been redirected
var
ErrNotTerminalOutput
=
errors
.
New
(
"standard output is not a terminal"
)
// Max elements to save on the killring
const
KillRingMax
=
60
// HistoryLimit is the maximum number of entries saved in the scrollback history.
const
HistoryLimit
=
1000
// ReadHistory reads scrollback history from r. Returns the number of lines
// read, and any read error (except io.EOF).
func
(
s
*
State
)
ReadHistory
(
r
io
.
Reader
)
(
num
int
,
err
error
)
{
s
.
historyMutex
.
Lock
()
defer
s
.
historyMutex
.
Unlock
()
in
:=
bufio
.
NewReader
(
r
)
num
=
0
for
{
line
,
part
,
err
:=
in
.
ReadLine
()
if
err
==
io
.
EOF
{
break
}
if
err
!=
nil
{
return
num
,
err
}
if
part
{
return
num
,
fmt
.
Errorf
(
"line %d is too long"
,
num
+
1
)
}
if
!
utf8
.
Valid
(
line
)
{
return
num
,
fmt
.
Errorf
(
"invalid string at line %d"
,
num
+
1
)
}
num
++
s
.
history
=
append
(
s
.
history
,
string
(
line
))
if
len
(
s
.
history
)
>
HistoryLimit
{
s
.
history
=
s
.
history
[
1
:
]
}
}
return
num
,
nil
}
// WriteHistory writes scrollback history to w. Returns the number of lines
// successfully written, and any write error.
//
// Unlike the rest of liner's API, WriteHistory is safe to call
// from another goroutine while Prompt is in progress.
// This exception is to facilitate the saving of the history buffer
// during an unexpected exit (for example, due to Ctrl-C being invoked)
func
(
s
*
State
)
WriteHistory
(
w
io
.
Writer
)
(
num
int
,
err
error
)
{
s
.
historyMutex
.
RLock
()
defer
s
.
historyMutex
.
RUnlock
()
for
_
,
item
:=
range
s
.
history
{
_
,
err
:=
fmt
.
Fprintln
(
w
,
item
)
if
err
!=
nil
{
return
num
,
err
}
num
++
}
return
num
,
nil
}
// AppendHistory appends an entry to the scrollback history. AppendHistory
// should be called iff Prompt returns a valid command.
func
(
s
*
State
)
AppendHistory
(
item
string
)
{
s
.
historyMutex
.
Lock
()
defer
s
.
historyMutex
.
Unlock
()
if
len
(
s
.
history
)
>
0
{
if
item
==
s
.
history
[
len
(
s
.
history
)
-
1
]
{
return
}
}
s
.
history
=
append
(
s
.
history
,
item
)
if
len
(
s
.
history
)
>
HistoryLimit
{
s
.
history
=
s
.
history
[
1
:
]
}
}
// Returns the history lines starting with prefix
func
(
s
*
State
)
getHistoryByPrefix
(
prefix
string
)
(
ph
[]
string
)
{
for
_
,
h
:=
range
s
.
history
{
if
strings
.
HasPrefix
(
h
,
prefix
)
{
ph
=
append
(
ph
,
h
)
}
}
return
}
// Returns the history lines matching the inteligent search
func
(
s
*
State
)
getHistoryByPattern
(
pattern
string
)
(
ph
[]
string
,
pos
[]
int
)
{
if
pattern
==
""
{
return
}
for
_
,
h
:=
range
s
.
history
{
if
i
:=
strings
.
Index
(
h
,
pattern
);
i
>=
0
{
ph
=
append
(
ph
,
h
)
pos
=
append
(
pos
,
i
)
}
}
return
}
// Completer takes the currently edited line content at the left of the cursor
// and returns a list of completion candidates.
// If the line is "Hello, wo!!!" and the cursor is before the first '!', "Hello, wo" is passed
// to the completer which may return {"Hello, world", "Hello, Word"} to have "Hello, world!!!".
type
Completer
func
(
line
string
)
[]
string
// WordCompleter takes the currently edited line with the cursor position and
// returns the completion candidates for the partial word to be completed.
// If the line is "Hello, wo!!!" and the cursor is before the first '!', ("Hello, wo!!!", 9) is passed
// to the completer which may returns ("Hello, ", {"world", "Word"}, "!!!") to have "Hello, world!!!".
type
WordCompleter
func
(
line
string
,
pos
int
)
(
head
string
,
completions
[]
string
,
tail
string
)
// SetCompleter sets the completion function that Liner will call to
// fetch completion candidates when the user presses tab.
func
(
s
*
State
)
SetCompleter
(
f
Completer
)
{
if
f
==
nil
{
s
.
completer
=
nil
return
}
s
.
completer
=
func
(
line
string
,
pos
int
)
(
string
,
[]
string
,
string
)
{
return
""
,
f
(
line
[
:
pos
]),
line
[
pos
:
]
}
}
// SetWordCompleter sets the completion function that Liner will call to
// fetch completion candidates when the user presses tab.
func
(
s
*
State
)
SetWordCompleter
(
f
WordCompleter
)
{
s
.
completer
=
f
}
// SetTabCompletionStyle sets the behvavior when the Tab key is pressed
// for auto-completion. TabCircular is the default behavior and cycles
// through the list of candidates at the prompt. TabPrints will print
// the available completion candidates to the screen similar to BASH
// and GNU Readline
func
(
s
*
State
)
SetTabCompletionStyle
(
tabStyle
TabStyle
)
{
s
.
tabStyle
=
tabStyle
}
// ModeApplier is the interface that wraps a representation of the terminal
// mode. ApplyMode sets the terminal to this mode.
type
ModeApplier
interface
{
ApplyMode
()
error
}
// SetCtrlCAborts sets whether Prompt on a supported terminal will return an
// ErrPromptAborted when Ctrl-C is pressed. The default is false (will not
// return when Ctrl-C is pressed). Unsupported terminals typically raise SIGINT
// (and Prompt does not return) regardless of the value passed to SetCtrlCAborts.
func
(
s
*
State
)
SetCtrlCAborts
(
aborts
bool
)
{
s
.
ctrlCAborts
=
aborts
}
func
(
s
*
State
)
promptUnsupported
(
p
string
)
(
string
,
error
)
{
if
!
s
.
inputRedirected
{
fmt
.
Print
(
p
)
}
linebuf
,
_
,
err
:=
s
.
r
.
ReadLine
()
if
err
!=
nil
{
return
""
,
err
}
return
string
(
bytes
.
TrimSpace
(
linebuf
)),
nil
}
Godeps/_workspace/src/github.com/peterh/liner/fallbackinput.go
0 → 100644
View file @
2393de5d
// +build !windows,!linux,!darwin,!openbsd,!freebsd,!netbsd
package
liner
import
(
"bufio"
"errors"
"os"
)
// State represents an open terminal
type
State
struct
{
commonState
}
// Prompt displays p, and then waits for user input. Prompt does not support
// line editing on this operating system.
func
(
s
*
State
)
Prompt
(
p
string
)
(
string
,
error
)
{
return
s
.
promptUnsupported
(
p
)
}
// PasswordPrompt is not supported in this OS.
func
(
s
*
State
)
PasswordPrompt
(
p
string
)
(
string
,
error
)
{
return
""
,
errors
.
New
(
"liner: function not supported in this terminal"
)
}
// NewLiner initializes a new *State
//
// Note that this operating system uses a fallback mode without line
// editing. Patches welcome.
func
NewLiner
()
*
State
{
var
s
State
s
.
r
=
bufio
.
NewReader
(
os
.
Stdin
)
return
&
s
}
// Close returns the terminal to its previous mode
func
(
s
*
State
)
Close
()
error
{
return
nil
}
// TerminalSupported returns false because line editing is not
// supported on this platform.
func
TerminalSupported
()
bool
{
return
false
}
type
noopMode
struct
{}
func
(
n
noopMode
)
ApplyMode
()
error
{
return
nil
}
// TerminalMode returns a noop InputModeSetter on this platform.
func
TerminalMode
()
(
ModeApplier
,
error
)
{
return
noopMode
{},
nil
}
Godeps/_workspace/src/github.com/peterh/liner/input.go
0 → 100644
View file @
2393de5d
// +build linux darwin openbsd freebsd netbsd
package
liner
import
(
"bufio"
"errors"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
)
type
nexter
struct
{
r
rune
err
error
}
// State represents an open terminal
type
State
struct
{
commonState
origMode
termios
defaultMode
termios
next
<-
chan
nexter
winch
chan
os
.
Signal
pending
[]
rune
useCHA
bool
}
// NewLiner initializes a new *State, and sets the terminal into raw mode. To
// restore the terminal to its previous state, call State.Close().
//
// Note if you are still using Go 1.0: NewLiner handles SIGWINCH, so it will
// leak a channel every time you call it. Therefore, it is recommened that you
// upgrade to a newer release of Go, or ensure that NewLiner is only called
// once.
func
NewLiner
()
*
State
{
var
s
State
s
.
r
=
bufio
.
NewReader
(
os
.
Stdin
)
s
.
terminalSupported
=
TerminalSupported
()
if
m
,
err
:=
TerminalMode
();
err
==
nil
{
s
.
origMode
=
*
m
.
(
*
termios
)
}
else
{
s
.
terminalSupported
=
false
s
.
inputRedirected
=
true
}
if
_
,
err
:=
getMode
(
syscall
.
Stdout
);
err
!=
0
{
s
.
terminalSupported
=
false
s
.
outputRedirected
=
true
}
if
s
.
terminalSupported
{
mode
:=
s
.
origMode
mode
.
Iflag
&^=
icrnl
|
inpck
|
istrip
|
ixon
mode
.
Cflag
|=
cs8
mode
.
Lflag
&^=
syscall
.
ECHO
|
icanon
|
iexten
mode
.
ApplyMode
()
winch
:=
make
(
chan
os
.
Signal
,
1
)
signal
.
Notify
(
winch
,
syscall
.
SIGWINCH
)
s
.
winch
=
winch
s
.
checkOutput
()
}
if
!
s
.
outputRedirected
{
s
.
getColumns
()
s
.
outputRedirected
=
s
.
columns
<=
0
}
return
&
s
}
var
errTimedOut
=
errors
.
New
(
"timeout"
)
func
(
s
*
State
)
startPrompt
()
{
if
s
.
terminalSupported
{
if
m
,
err
:=
TerminalMode
();
err
==
nil
{
s
.
defaultMode
=
*
m
.
(
*
termios
)
mode
:=
s
.
defaultMode
mode
.
Lflag
&^=
isig
mode
.
ApplyMode
()
}
}
s
.
restartPrompt
()
}
func
(
s
*
State
)
restartPrompt
()
{
next
:=
make
(
chan
nexter
)
go
func
()
{
for
{
var
n
nexter
n
.
r
,
_
,
n
.
err
=
s
.
r
.
ReadRune
()
next
<-
n
// Shut down nexter loop when an end condition has been reached
if
n
.
err
!=
nil
||
n
.
r
==
'\n'
||
n
.
r
==
'\r'
||
n
.
r
==
ctrlC
||
n
.
r
==
ctrlD
{
close
(
next
)
return
}
}
}()
s
.
next
=
next
}
func
(
s
*
State
)
stopPrompt
()
{
if
s
.
terminalSupported
{
s
.
defaultMode
.
ApplyMode
()
}
}
func
(
s
*
State
)
nextPending
(
timeout
<-
chan
time
.
Time
)
(
rune
,
error
)
{
select
{
case
thing
,
ok
:=
<-
s
.
next
:
if
!
ok
{
return
0
,
errors
.
New
(
"liner: internal error"
)
}
if
thing
.
err
!=
nil
{
return
0
,
thing
.
err
}
s
.
pending
=
append
(
s
.
pending
,
thing
.
r
)
return
thing
.
r
,
nil
case
<-
timeout
:
rv
:=
s
.
pending
[
0
]
s
.
pending
=
s
.
pending
[
1
:
]
return
rv
,
errTimedOut
}
// not reached
return
0
,
nil
}
func
(
s
*
State
)
readNext
()
(
interface
{},
error
)
{
if
len
(
s
.
pending
)
>
0
{
rv
:=
s
.
pending
[
0
]
s
.
pending
=
s
.
pending
[
1
:
]
return
rv
,
nil
}
var
r
rune
select
{
case
thing
,
ok
:=
<-
s
.
next
:
if
!
ok
{
return
0
,
errors
.
New
(
"liner: internal error"
)
}
if
thing
.
err
!=
nil
{
return
nil
,
thing
.
err
}
r
=
thing
.
r
case
<-
s
.
winch
:
s
.
getColumns
()
return
winch
,
nil
}
if
r
!=
esc
{
return
r
,
nil
}
s
.
pending
=
append
(
s
.
pending
,
r
)
// Wait at most 50 ms for the rest of the escape sequence
// If nothing else arrives, it was an actual press of the esc key
timeout
:=
time
.
After
(
50
*
time
.
Millisecond
)
flag
,
err
:=
s
.
nextPending
(
timeout
)
if
err
!=
nil
{
if
err
==
errTimedOut
{
return
flag
,
nil
}
return
unknown
,
err
}
switch
flag
{
case
'['
:
code
,
err
:=
s
.
nextPending
(
timeout
)
if
err
!=
nil
{
if
err
==
errTimedOut
{
return
code
,
nil
}
return
unknown
,
err
}
switch
code
{
case
'A'
:
s
.
pending
=
s
.
pending
[
:
0
]
// escape code complete
return
up
,
nil
case
'B'
:
s
.
pending
=
s
.
pending
[
:
0
]
// escape code complete
return
down
,
nil
case
'C'
:
s
.
pending
=
s
.
pending
[
:
0
]
// escape code complete
return
right
,
nil
case
'D'
:
s
.
pending
=
s
.
pending
[
:
0
]
// escape code complete
return
left
,
nil
case
'F'
:
s
.
pending
=
s
.
pending
[
:
0
]
// escape code complete
return
end
,
nil
case
'H'
:
s
.
pending
=
s
.
pending
[
:
0
]
// escape code complete
return
home
,
nil
case
'Z'
:
s
.
pending
=
s
.
pending
[
:
0
]
// escape code complete
return
shiftTab
,
nil
case
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
:
num
:=
[]
rune
{
code
}
for
{
code
,
err
:=
s
.
nextPending
(
timeout
)
if
err
!=
nil
{
if
err
==
errTimedOut
{
return
code
,
nil
}
return
nil
,
err
}
switch
code
{
case
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
:
num
=
append
(
num
,
code
)
case
';'
:
// Modifier code to follow
// This only supports Ctrl-left and Ctrl-right for now
x
,
_
:=
strconv
.
ParseInt
(
string
(
num
),
10
,
32
)
if
x
!=
1
{
// Can't be left or right
rv
:=
s
.
pending
[
0
]
s
.
pending
=
s
.
pending
[
1
:
]
return
rv
,
nil
}
num
=
num
[
:
0
]
for
{
code
,
err
=
s
.
nextPending
(
timeout
)
if
err
!=
nil
{
if
err
==
errTimedOut
{
rv
:=
s
.
pending
[
0
]
s
.
pending
=
s
.
pending
[
1
:
]
return
rv
,
nil
}
return
nil
,
err
}
switch
code
{
case
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
:
num
=
append
(
num
,
code
)
case
'C'
,
'D'
:
// right, left
mod
,
_
:=
strconv
.
ParseInt
(
string
(
num
),
10
,
32
)
if
mod
!=
5
{
// Not bare Ctrl
rv
:=
s
.
pending
[
0
]
s
.
pending
=
s
.
pending
[
1
:
]
return
rv
,
nil
}
s
.
pending
=
s
.
pending
[
:
0
]
// escape code complete
if
code
==
'C'
{
return
wordRight
,
nil
}
return
wordLeft
,
nil
default
:
// Not left or right
rv
:=
s
.
pending
[
0
]
s
.
pending
=
s
.
pending
[
1
:
]
return
rv
,
nil
}
}
case
'~'
:
s
.
pending
=
s
.
pending
[
:
0
]
// escape code complete
x
,
_
:=
strconv
.
ParseInt
(
string
(
num
),
10
,
32
)
switch
x
{
case
2
:
return
insert
,
nil
case
3
:
return
del
,
nil
case
5
:
return
pageUp
,
nil
case
6
:
return
pageDown
,
nil
case
7
:
return
home
,
nil
case
8
:
return
end
,
nil
case
15
:
return
f5
,
nil
case
17
:
return
f6
,
nil
case
18
:
return
f7
,
nil
case
19
:
return
f8
,
nil
case
20
:
return
f9
,
nil
case
21
:
return
f10
,
nil
case
23
:
return
f11
,
nil
case
24
:
return
f12
,
nil
default
:
return
unknown
,
nil
}
default
:
// unrecognized escape code
rv
:=
s
.
pending
[
0
]
s
.
pending
=
s
.
pending
[
1
:
]
return
rv
,
nil
}
}
}
case
'O'
:
code
,
err
:=
s
.
nextPending
(
timeout
)
if
err
!=
nil
{
if
err
==
errTimedOut
{
return
code
,
nil
}
return
nil
,
err
}
s
.
pending
=
s
.
pending
[
:
0
]
// escape code complete
switch
code
{
case
'c'
:
return
wordRight
,
nil
case
'd'
:
return
wordLeft
,
nil
case
'H'
:
return
home
,
nil
case
'F'
:
return
end
,
nil
case
'P'
:
return
f1
,
nil
case
'Q'
:
return
f2
,
nil
case
'R'
:
return
f3
,
nil
case
'S'
:
return
f4
,
nil
default
:
return
unknown
,
nil
}
case
'y'
:
s
.
pending
=
s
.
pending
[
:
0
]
// escape code complete
return
altY
,
nil
default
:
rv
:=
s
.
pending
[
0
]
s
.
pending
=
s
.
pending
[
1
:
]
return
rv
,
nil
}
// not reached
return
r
,
nil
}
// Close returns the terminal to its previous mode
func
(
s
*
State
)
Close
()
error
{
stopSignal
(
s
.
winch
)
if
s
.
terminalSupported
{
s
.
origMode
.
ApplyMode
()
}
return
nil
}
// TerminalSupported returns true if the current terminal supports
// line editing features, and false if liner will use the 'dumb'
// fallback for input.
func
TerminalSupported
()
bool
{
bad
:=
map
[
string
]
bool
{
""
:
true
,
"dumb"
:
true
,
"cons25"
:
true
}
return
!
bad
[
strings
.
ToLower
(
os
.
Getenv
(
"TERM"
))]
}
Godeps/_workspace/src/github.com/peterh/liner/input_darwin.go
0 → 100644
View file @
2393de5d
// +build darwin
package
liner
import
"syscall"
const
(
getTermios
=
syscall
.
TIOCGETA
setTermios
=
syscall
.
TIOCSETA
)
const
(
// Input flags
inpck
=
0x010
istrip
=
0x020
icrnl
=
0x100
ixon
=
0x200
// Output flags
opost
=
0x1
// Control flags
cs8
=
0x300
// Local flags
isig
=
0x080
icanon
=
0x100
iexten
=
0x400
)
type
termios
struct
{
Iflag
uintptr
Oflag
uintptr
Cflag
uintptr
Lflag
uintptr
Cc
[
20
]
byte
Ispeed
uintptr
Ospeed
uintptr
}
Godeps/_workspace/src/github.com/peterh/liner/input_linux.go
0 → 100644
View file @
2393de5d
// +build linux
package
liner
import
"syscall"
const
(
getTermios
=
syscall
.
TCGETS
setTermios
=
syscall
.
TCSETS
)
const
(
icrnl
=
syscall
.
ICRNL
inpck
=
syscall
.
INPCK
istrip
=
syscall
.
ISTRIP
ixon
=
syscall
.
IXON
opost
=
syscall
.
OPOST
cs8
=
syscall
.
CS8
isig
=
syscall
.
ISIG
icanon
=
syscall
.
ICANON
iexten
=
syscall
.
IEXTEN
)
type
termios
struct
{
syscall
.
Termios
}
Godeps/_workspace/src/github.com/peterh/liner/input_test.go
0 → 100644
View file @
2393de5d
// +build !windows
package
liner
import
(
"bufio"
"bytes"
"testing"
)
func
(
s
*
State
)
expectRune
(
t
*
testing
.
T
,
r
rune
)
{
item
,
err
:=
s
.
readNext
()
if
err
!=
nil
{
t
.
Fatalf
(
"Expected rune '%c', got error %s
\n
"
,
r
,
err
)
}
if
v
,
ok
:=
item
.
(
rune
);
!
ok
{
t
.
Fatalf
(
"Expected rune '%c', got non-rune %v
\n
"
,
r
,
v
)
}
else
{
if
v
!=
r
{
t
.
Fatalf
(
"Expected rune '%c', got rune '%c'
\n
"
,
r
,
v
)
}
}
}
func
(
s
*
State
)
expectAction
(
t
*
testing
.
T
,
a
action
)
{
item
,
err
:=
s
.
readNext
()
if
err
!=
nil
{
t
.
Fatalf
(
"Expected Action %d, got error %s
\n
"
,
a
,
err
)
}
if
v
,
ok
:=
item
.
(
action
);
!
ok
{
t
.
Fatalf
(
"Expected Action %d, got non-Action %v
\n
"
,
a
,
v
)
}
else
{
if
v
!=
a
{
t
.
Fatalf
(
"Expected Action %d, got Action %d
\n
"
,
a
,
v
)
}
}
}
func
TestTypes
(
t
*
testing
.
T
)
{
input
:=
[]
byte
{
'A'
,
27
,
'B'
,
27
,
91
,
68
,
27
,
'['
,
'1'
,
';'
,
'5'
,
'D'
,
'e'
}
var
s
State
s
.
r
=
bufio
.
NewReader
(
bytes
.
NewBuffer
(
input
))
next
:=
make
(
chan
nexter
)
go
func
()
{
for
{
var
n
nexter
n
.
r
,
_
,
n
.
err
=
s
.
r
.
ReadRune
()
next
<-
n
}
}()
s
.
next
=
next
s
.
expectRune
(
t
,
'A'
)
s
.
expectRune
(
t
,
27
)
s
.
expectRune
(
t
,
'B'
)
s
.
expectAction
(
t
,
left
)
s
.
expectAction
(
t
,
wordLeft
)
s
.
expectRune
(
t
,
'e'
)
}
Godeps/_workspace/src/github.com/peterh/liner/input_windows.go
0 → 100644
View file @
2393de5d
package
liner
import
(
"bufio"
"os"
"syscall"
"unsafe"
)
var
(
kernel32
=
syscall
.
NewLazyDLL
(
"kernel32.dll"
)
procGetStdHandle
=
kernel32
.
NewProc
(
"GetStdHandle"
)
procReadConsoleInput
=
kernel32
.
NewProc
(
"ReadConsoleInputW"
)
procGetConsoleMode
=
kernel32
.
NewProc
(
"GetConsoleMode"
)
procSetConsoleMode
=
kernel32
.
NewProc
(
"SetConsoleMode"
)
procSetConsoleCursorPosition
=
kernel32
.
NewProc
(
"SetConsoleCursorPosition"
)
procGetConsoleScreenBufferInfo
=
kernel32
.
NewProc
(
"GetConsoleScreenBufferInfo"
)
procFillConsoleOutputCharacter
=
kernel32
.
NewProc
(
"FillConsoleOutputCharacterW"
)
)
// These names are from the Win32 api, so they use underscores (contrary to
// what golint suggests)
const
(
std_input_handle
=
uint32
(
-
10
&
0xFFFFFFFF
)
std_output_handle
=
uint32
(
-
11
&
0xFFFFFFFF
)
std_error_handle
=
uint32
(
-
12
&
0xFFFFFFFF
)
invalid_handle_value
=
^
uintptr
(
0
)
)
type
inputMode
uint32
// State represents an open terminal
type
State
struct
{
commonState
handle
syscall
.
Handle
hOut
syscall
.
Handle
origMode
inputMode
defaultMode
inputMode
key
interface
{}
repeat
uint16
}
const
(
enableEchoInput
=
0x4
enableInsertMode
=
0x20
enableLineInput
=
0x2
enableMouseInput
=
0x10
enableProcessedInput
=
0x1
enableQuickEditMode
=
0x40
enableWindowInput
=
0x8
)
// NewLiner initializes a new *State, and sets the terminal into raw mode. To
// restore the terminal to its previous state, call State.Close().
func
NewLiner
()
*
State
{
var
s
State
hIn
,
_
,
_
:=
procGetStdHandle
.
Call
(
uintptr
(
std_input_handle
))
s
.
handle
=
syscall
.
Handle
(
hIn
)
hOut
,
_
,
_
:=
procGetStdHandle
.
Call
(
uintptr
(
std_output_handle
))
s
.
hOut
=
syscall
.
Handle
(
hOut
)
s
.
terminalSupported
=
true
if
m
,
err
:=
TerminalMode
();
err
==
nil
{
s
.
origMode
=
m
.
(
inputMode
)
mode
:=
s
.
origMode
mode
&^=
enableEchoInput
mode
&^=
enableInsertMode
mode
&^=
enableLineInput
mode
&^=
enableMouseInput
mode
|=
enableWindowInput
mode
.
ApplyMode
()
}
else
{
s
.
inputRedirected
=
true
s
.
r
=
bufio
.
NewReader
(
os
.
Stdin
)
}
s
.
getColumns
()
s
.
outputRedirected
=
s
.
columns
<=
0
return
&
s
}
// These names are from the Win32 api, so they use underscores (contrary to
// what golint suggests)
const
(
focus_event
=
0x0010
key_event
=
0x0001
menu_event
=
0x0008
mouse_event
=
0x0002
window_buffer_size_event
=
0x0004
)
type
input_record
struct
{
eventType
uint16
pad
uint16
blob
[
16
]
byte
}
type
key_event_record
struct
{
KeyDown
int32
RepeatCount
uint16
VirtualKeyCode
uint16
VirtualScanCode
uint16
Char
int16
ControlKeyState
uint32
}
// These names are from the Win32 api, so they use underscores (contrary to
// what golint suggests)
const
(
vk_tab
=
0x09
vk_prior
=
0x21
vk_next
=
0x22
vk_end
=
0x23
vk_home
=
0x24
vk_left
=
0x25
vk_up
=
0x26
vk_right
=
0x27
vk_down
=
0x28
vk_insert
=
0x2d
vk_delete
=
0x2e
vk_f1
=
0x70
vk_f2
=
0x71
vk_f3
=
0x72
vk_f4
=
0x73
vk_f5
=
0x74
vk_f6
=
0x75
vk_f7
=
0x76
vk_f8
=
0x77
vk_f9
=
0x78
vk_f10
=
0x79
vk_f11
=
0x7a
vk_f12
=
0x7b
yKey
=
0x59
)
const
(
shiftPressed
=
0x0010
leftAltPressed
=
0x0002
leftCtrlPressed
=
0x0008
rightAltPressed
=
0x0001
rightCtrlPressed
=
0x0004
modKeys
=
shiftPressed
|
leftAltPressed
|
rightAltPressed
|
leftCtrlPressed
|
rightCtrlPressed
)
func
(
s
*
State
)
readNext
()
(
interface
{},
error
)
{
if
s
.
repeat
>
0
{
s
.
repeat
--
return
s
.
key
,
nil
}
var
input
input_record
pbuf
:=
uintptr
(
unsafe
.
Pointer
(
&
input
))
var
rv
uint32
prv
:=
uintptr
(
unsafe
.
Pointer
(
&
rv
))
for
{
ok
,
_
,
err
:=
procReadConsoleInput
.
Call
(
uintptr
(
s
.
handle
),
pbuf
,
1
,
prv
)
if
ok
==
0
{
return
nil
,
err
}
if
input
.
eventType
==
window_buffer_size_event
{
xy
:=
(
*
coord
)(
unsafe
.
Pointer
(
&
input
.
blob
[
0
]))
s
.
columns
=
int
(
xy
.
x
)
return
winch
,
nil
}
if
input
.
eventType
!=
key_event
{
continue
}
ke
:=
(
*
key_event_record
)(
unsafe
.
Pointer
(
&
input
.
blob
[
0
]))
if
ke
.
KeyDown
==
0
{
continue
}
if
ke
.
VirtualKeyCode
==
vk_tab
&&
ke
.
ControlKeyState
&
modKeys
==
shiftPressed
{
s
.
key
=
shiftTab
}
else
if
ke
.
VirtualKeyCode
==
yKey
&&
(
ke
.
ControlKeyState
&
modKeys
==
leftAltPressed
||
ke
.
ControlKeyState
&
modKeys
==
rightAltPressed
)
{
s
.
key
=
altY
}
else
if
ke
.
Char
>
0
{
s
.
key
=
rune
(
ke
.
Char
)
}
else
{
switch
ke
.
VirtualKeyCode
{
case
vk_prior
:
s
.
key
=
pageUp
case
vk_next
:
s
.
key
=
pageDown
case
vk_end
:
s
.
key
=
end
case
vk_home
:
s
.
key
=
home
case
vk_left
:
s
.
key
=
left
if
ke
.
ControlKeyState
&
(
leftCtrlPressed
|
rightCtrlPressed
)
!=
0
{
if
ke
.
ControlKeyState
&
modKeys
==
ke
.
ControlKeyState
&
(
leftCtrlPressed
|
rightCtrlPressed
)
{
s
.
key
=
wordLeft
}
}
case
vk_right
:
s
.
key
=
right
if
ke
.
ControlKeyState
&
(
leftCtrlPressed
|
rightCtrlPressed
)
!=
0
{
if
ke
.
ControlKeyState
&
modKeys
==
ke
.
ControlKeyState
&
(
leftCtrlPressed
|
rightCtrlPressed
)
{
s
.
key
=
wordRight
}
}
case
vk_up
:
s
.
key
=
up
case
vk_down
:
s
.
key
=
down
case
vk_insert
:
s
.
key
=
insert
case
vk_delete
:
s
.
key
=
del
case
vk_f1
:
s
.
key
=
f1
case
vk_f2
:
s
.
key
=
f2
case
vk_f3
:
s
.
key
=
f3
case
vk_f4
:
s
.
key
=
f4
case
vk_f5
:
s
.
key
=
f5
case
vk_f6
:
s
.
key
=
f6
case
vk_f7
:
s
.
key
=
f7
case
vk_f8
:
s
.
key
=
f8
case
vk_f9
:
s
.
key
=
f9
case
vk_f10
:
s
.
key
=
f10
case
vk_f11
:
s
.
key
=
f11
case
vk_f12
:
s
.
key
=
f12
default
:
// Eat modifier keys
// TODO: return Action(Unknown) if the key isn't a
// modifier.
continue
}
}
if
ke
.
RepeatCount
>
1
{
s
.
repeat
=
ke
.
RepeatCount
-
1
}
return
s
.
key
,
nil
}
return
unknown
,
nil
}
// Close returns the terminal to its previous mode
func
(
s
*
State
)
Close
()
error
{
s
.
origMode
.
ApplyMode
()
return
nil
}
func
(
s
*
State
)
startPrompt
()
{
if
m
,
err
:=
TerminalMode
();
err
==
nil
{
s
.
defaultMode
=
m
.
(
inputMode
)
mode
:=
s
.
defaultMode
mode
&^=
enableProcessedInput
mode
.
ApplyMode
()
}
}
func
(
s
*
State
)
restartPrompt
()
{
}
func
(
s
*
State
)
stopPrompt
()
{
s
.
defaultMode
.
ApplyMode
()
}
// TerminalSupported returns true because line editing is always
// supported on Windows.
func
TerminalSupported
()
bool
{
return
true
}
func
(
mode
inputMode
)
ApplyMode
()
error
{
hIn
,
_
,
err
:=
procGetStdHandle
.
Call
(
uintptr
(
std_input_handle
))
if
hIn
==
invalid_handle_value
||
hIn
==
0
{
return
err
}
ok
,
_
,
err
:=
procSetConsoleMode
.
Call
(
hIn
,
uintptr
(
mode
))
if
ok
!=
0
{
err
=
nil
}
return
err
}
// TerminalMode returns the current terminal input mode as an InputModeSetter.
//
// This function is provided for convenience, and should
// not be necessary for most users of liner.
func
TerminalMode
()
(
ModeApplier
,
error
)
{
var
mode
inputMode
hIn
,
_
,
err
:=
procGetStdHandle
.
Call
(
uintptr
(
std_input_handle
))
if
hIn
==
invalid_handle_value
||
hIn
==
0
{
return
nil
,
err
}
ok
,
_
,
err
:=
procGetConsoleMode
.
Call
(
hIn
,
uintptr
(
unsafe
.
Pointer
(
&
mode
)))
if
ok
!=
0
{
err
=
nil
}
return
mode
,
err
}
Godeps/_workspace/src/github.com/peterh/liner/line.go
0 → 100644
View file @
2393de5d
This diff is collapsed.
Click to expand it.
Godeps/_workspace/src/github.com/peterh/liner/line_test.go
0 → 100644
View file @
2393de5d
package
liner
import
(
"bytes"
"strings"
"testing"
)
func
TestAppend
(
t
*
testing
.
T
)
{
var
s
State
s
.
AppendHistory
(
"foo"
)
s
.
AppendHistory
(
"bar"
)
var
out
bytes
.
Buffer
num
,
err
:=
s
.
WriteHistory
(
&
out
)
if
err
!=
nil
{
t
.
Fatal
(
"Unexpected error writing history"
,
err
)
}
if
num
!=
2
{
t
.
Fatalf
(
"Expected 2 history entries, got %d"
,
num
)
}
s
.
AppendHistory
(
"baz"
)
num
,
err
=
s
.
WriteHistory
(
&
out
)
if
err
!=
nil
{
t
.
Fatal
(
"Unexpected error writing history"
,
err
)
}
if
num
!=
3
{
t
.
Fatalf
(
"Expected 3 history entries, got %d"
,
num
)
}
s
.
AppendHistory
(
"baz"
)
num
,
err
=
s
.
WriteHistory
(
&
out
)
if
err
!=
nil
{
t
.
Fatal
(
"Unexpected error writing history"
,
err
)
}
if
num
!=
3
{
t
.
Fatalf
(
"Expected 3 history entries after duplicate append, got %d"
,
num
)
}
s
.
AppendHistory
(
"baz"
)
}
func
TestHistory
(
t
*
testing
.
T
)
{
input
:=
`foo
bar
baz
quux
dingle`
var
s
State
num
,
err
:=
s
.
ReadHistory
(
strings
.
NewReader
(
input
))
if
err
!=
nil
{
t
.
Fatal
(
"Unexpected error reading history"
,
err
)
}
if
num
!=
5
{
t
.
Fatal
(
"Wrong number of history entries read"
)
}
var
out
bytes
.
Buffer
num
,
err
=
s
.
WriteHistory
(
&
out
)
if
err
!=
nil
{
t
.
Fatal
(
"Unexpected error writing history"
,
err
)
}
if
num
!=
5
{
t
.
Fatal
(
"Wrong number of history entries written"
)
}
if
strings
.
TrimSpace
(
out
.
String
())
!=
input
{
t
.
Fatal
(
"Round-trip failure"
)
}
// Test reading with a trailing newline present
var
s2
State
num
,
err
=
s2
.
ReadHistory
(
&
out
)
if
err
!=
nil
{
t
.
Fatal
(
"Unexpected error reading history the 2nd time"
,
err
)
}
if
num
!=
5
{
t
.
Fatal
(
"Wrong number of history entries read the 2nd time"
)
}
num
,
err
=
s
.
ReadHistory
(
strings
.
NewReader
(
input
+
"
\n\xff
"
))
if
err
==
nil
{
t
.
Fatal
(
"Unexpected success reading corrupted history"
,
err
)
}
if
num
!=
5
{
t
.
Fatal
(
"Wrong number of history entries read the 3rd time"
)
}
}
Godeps/_workspace/src/github.com/peterh/liner/output.go
0 → 100644
View file @
2393de5d
// +build linux darwin openbsd freebsd netbsd
package
liner
import
(
"fmt"
"os"
"strings"
"syscall"
"unsafe"
)
func
(
s
*
State
)
cursorPos
(
x
int
)
{
if
s
.
useCHA
{
// 'G' is "Cursor Character Absolute (CHA)"
fmt
.
Printf
(
"
\x1b
[%dG"
,
x
+
1
)
}
else
{
// 'C' is "Cursor Forward (CUF)"
fmt
.
Print
(
"
\r
"
)
if
x
>
0
{
fmt
.
Printf
(
"
\x1b
[%dC"
,
x
)
}
}
}
func
(
s
*
State
)
eraseLine
()
{
fmt
.
Print
(
"
\x1b
[0K"
)
}
func
(
s
*
State
)
eraseScreen
()
{
fmt
.
Print
(
"
\x1b
[H
\x1b
[2J"
)
}
type
winSize
struct
{
row
,
col
uint16
xpixel
,
ypixel
uint16
}
func
(
s
*
State
)
getColumns
()
{
var
ws
winSize
ok
,
_
,
_
:=
syscall
.
Syscall
(
syscall
.
SYS_IOCTL
,
uintptr
(
syscall
.
Stdout
),
syscall
.
TIOCGWINSZ
,
uintptr
(
unsafe
.
Pointer
(
&
ws
)))
if
ok
<
0
{
s
.
columns
=
80
}
s
.
columns
=
int
(
ws
.
col
)
}
func
(
s
*
State
)
checkOutput
()
{
// xterm is known to support CHA
if
strings
.
Contains
(
strings
.
ToLower
(
os
.
Getenv
(
"TERM"
)),
"xterm"
)
{
s
.
useCHA
=
true
return
}
// The test for functional ANSI CHA is unreliable (eg the Windows
// telnet command does not support reading the cursor position with
// an ANSI DSR request, despite setting TERM=ansi)
// Assume CHA isn't supported (which should be safe, although it
// does result in occasional visible cursor jitter)
s
.
useCHA
=
false
}
Godeps/_workspace/src/github.com/peterh/liner/output_windows.go
0 → 100644
View file @
2393de5d
package
liner
import
(
"unsafe"
)
type
coord
struct
{
x
,
y
int16
}
type
smallRect
struct
{
left
,
top
,
right
,
bottom
int16
}
type
consoleScreenBufferInfo
struct
{
dwSize
coord
dwCursorPosition
coord
wAttributes
int16
srWindow
smallRect
dwMaximumWindowSize
coord
}
func
(
s
*
State
)
cursorPos
(
x
int
)
{
var
sbi
consoleScreenBufferInfo
procGetConsoleScreenBufferInfo
.
Call
(
uintptr
(
s
.
hOut
),
uintptr
(
unsafe
.
Pointer
(
&
sbi
)))
procSetConsoleCursorPosition
.
Call
(
uintptr
(
s
.
hOut
),
uintptr
(
int
(
x
)
&
0xFFFF
|
int
(
sbi
.
dwCursorPosition
.
y
)
<<
16
))
}
func
(
s
*
State
)
eraseLine
()
{
var
sbi
consoleScreenBufferInfo
procGetConsoleScreenBufferInfo
.
Call
(
uintptr
(
s
.
hOut
),
uintptr
(
unsafe
.
Pointer
(
&
sbi
)))
var
numWritten
uint32
procFillConsoleOutputCharacter
.
Call
(
uintptr
(
s
.
hOut
),
uintptr
(
' '
),
uintptr
(
sbi
.
dwSize
.
x
-
sbi
.
dwCursorPosition
.
x
),
uintptr
(
int
(
sbi
.
dwCursorPosition
.
x
)
&
0xFFFF
|
int
(
sbi
.
dwCursorPosition
.
y
)
<<
16
),
uintptr
(
unsafe
.
Pointer
(
&
numWritten
)))
}
func
(
s
*
State
)
eraseScreen
()
{
var
sbi
consoleScreenBufferInfo
procGetConsoleScreenBufferInfo
.
Call
(
uintptr
(
s
.
hOut
),
uintptr
(
unsafe
.
Pointer
(
&
sbi
)))
var
numWritten
uint32
procFillConsoleOutputCharacter
.
Call
(
uintptr
(
s
.
hOut
),
uintptr
(
' '
),
uintptr
(
sbi
.
dwSize
.
x
)
*
uintptr
(
sbi
.
dwSize
.
y
),
0
,
uintptr
(
unsafe
.
Pointer
(
&
numWritten
)))
procSetConsoleCursorPosition
.
Call
(
uintptr
(
s
.
hOut
),
0
)
}
func
(
s
*
State
)
getColumns
()
{
var
sbi
consoleScreenBufferInfo
procGetConsoleScreenBufferInfo
.
Call
(
uintptr
(
s
.
hOut
),
uintptr
(
unsafe
.
Pointer
(
&
sbi
)))
s
.
columns
=
int
(
sbi
.
dwSize
.
x
)
}
Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go
0 → 100644
View file @
2393de5d
// +build windows linux darwin openbsd freebsd netbsd
package
liner
import
"testing"
type
testItem
struct
{
list
[]
string
prefix
string
}
func
TestPrefix
(
t
*
testing
.
T
)
{
list
:=
[]
testItem
{
{[]
string
{
"food"
,
"foot"
},
"foo"
},
{[]
string
{
"foo"
,
"foot"
},
"foo"
},
{[]
string
{
"food"
,
"foo"
},
"foo"
},
{[]
string
{
"food"
,
"foe"
,
"foot"
},
"fo"
},
{[]
string
{
"food"
,
"foot"
,
"barbeque"
},
""
},
{[]
string
{
"cafeteria"
,
"café"
},
"caf"
},
{[]
string
{
"cafe"
,
"café"
},
"caf"
},
{[]
string
{
"cafè"
,
"café"
},
"caf"
},
{[]
string
{
"cafés"
,
"café"
},
"café"
},
{[]
string
{
"áéíóú"
,
"áéíóú"
},
"áéíóú"
},
{[]
string
{
"éclairs"
,
"éclairs"
},
"éclairs"
},
{[]
string
{
"éclairs are the best"
,
"éclairs are great"
,
"éclairs"
},
"éclairs"
},
{[]
string
{
"éclair"
,
"éclairs"
},
"éclair"
},
{[]
string
{
"éclairs"
,
"éclair"
},
"éclair"
},
{[]
string
{
"éclair"
,
"élan"
},
"é"
},
}
for
_
,
test
:=
range
list
{
lcp
:=
longestCommonPrefix
(
test
.
list
)
if
lcp
!=
test
.
prefix
{
t
.
Errorf
(
"%s != %s for %+v"
,
lcp
,
test
.
prefix
,
test
.
list
)
}
}
}
Godeps/_workspace/src/github.com/peterh/liner/race_test.go
0 → 100644
View file @
2393de5d
// +build race
package
liner
import
(
"io/ioutil"
"os"
"sync"
"testing"
)
func
TestWriteHistory
(
t
*
testing
.
T
)
{
oldout
:=
os
.
Stdout
defer
func
()
{
os
.
Stdout
=
oldout
}()
oldin
:=
os
.
Stdout
defer
func
()
{
os
.
Stdin
=
oldin
}()
newinr
,
newinw
,
err
:=
os
.
Pipe
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
os
.
Stdin
=
newinr
newoutr
,
newoutw
,
err
:=
os
.
Pipe
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
newoutr
.
Close
()
os
.
Stdout
=
newoutw
var
wait
sync
.
WaitGroup
wait
.
Add
(
1
)
s
:=
NewLiner
()
go
func
()
{
s
.
AppendHistory
(
"foo"
)
s
.
AppendHistory
(
"bar"
)
s
.
Prompt
(
""
)
wait
.
Done
()
}()
s
.
WriteHistory
(
ioutil
.
Discard
)
newinw
.
Close
()
wait
.
Wait
()
}
Godeps/_workspace/src/github.com/peterh/liner/signal.go
0 → 100644
View file @
2393de5d
// +build go1.1,!windows
package
liner
import
(
"os"
"os/signal"
)
func
stopSignal
(
c
chan
<-
os
.
Signal
)
{
signal
.
Stop
(
c
)
}
Godeps/_workspace/src/github.com/peterh/liner/signal_legacy.go
0 → 100644
View file @
2393de5d
// +build !go1.1,!windows
package
liner
import
(
"os"
)
func
stopSignal
(
c
chan
<-
os
.
Signal
)
{
// signal.Stop does not exist before Go 1.1
}
Godeps/_workspace/src/github.com/peterh/liner/unixmode.go
0 → 100644
View file @
2393de5d
// +build linux darwin freebsd openbsd netbsd
package
liner
import
(
"syscall"
"unsafe"
)
func
(
mode
*
termios
)
ApplyMode
()
error
{
_
,
_
,
errno
:=
syscall
.
Syscall
(
syscall
.
SYS_IOCTL
,
uintptr
(
syscall
.
Stdin
),
setTermios
,
uintptr
(
unsafe
.
Pointer
(
mode
)))
if
errno
!=
0
{
return
errno
}
return
nil
}
// TerminalMode returns the current terminal input mode as an InputModeSetter.
//
// This function is provided for convenience, and should
// not be necessary for most users of liner.
func
TerminalMode
()
(
ModeApplier
,
error
)
{
mode
,
errno
:=
getMode
(
syscall
.
Stdin
)
if
errno
!=
0
{
return
nil
,
errno
}
return
mode
,
nil
}
func
getMode
(
handle
int
)
(
*
termios
,
syscall
.
Errno
)
{
var
mode
termios
_
,
_
,
errno
:=
syscall
.
Syscall
(
syscall
.
SYS_IOCTL
,
uintptr
(
handle
),
getTermios
,
uintptr
(
unsafe
.
Pointer
(
&
mode
)))
return
&
mode
,
errno
}
Godeps/_workspace/src/github.com/peterh/liner/width.go
0 → 100644
View file @
2393de5d
package
liner
import
"unicode"
// These character classes are mostly zero width (when combined).
// A few might not be, depending on the user's font. Fixing this
// is non-trivial, given that some terminals don't support
// ANSI DSR/CPR
var
zeroWidth
=
[]
*
unicode
.
RangeTable
{
unicode
.
Mn
,
unicode
.
Me
,
unicode
.
Cc
,
unicode
.
Cf
,
}
func
countGlyphs
(
s
[]
rune
)
int
{
n
:=
0
for
_
,
r
:=
range
s
{
if
!
unicode
.
IsOneOf
(
zeroWidth
,
r
)
{
n
++
}
}
return
n
}
func
getPrefixGlyphs
(
s
[]
rune
,
num
int
)
[]
rune
{
p
:=
0
for
n
:=
0
;
n
<
num
&&
p
<
len
(
s
);
p
++
{
if
!
unicode
.
IsOneOf
(
zeroWidth
,
s
[
p
])
{
n
++
}
}
for
p
<
len
(
s
)
&&
unicode
.
IsOneOf
(
zeroWidth
,
s
[
p
])
{
p
++
}
return
s
[
:
p
]
}
func
getSuffixGlyphs
(
s
[]
rune
,
num
int
)
[]
rune
{
p
:=
len
(
s
)
for
n
:=
0
;
n
<
num
&&
p
>
0
;
p
--
{
if
!
unicode
.
IsOneOf
(
zeroWidth
,
s
[
p
-
1
])
{
n
++
}
}
return
s
[
p
:
]
}
Godeps/_workspace/src/github.com/peterh/liner/width_test.go
0 → 100644
View file @
2393de5d
package
liner
import
(
"strconv"
"testing"
)
func
accent
(
in
[]
rune
)
[]
rune
{
var
out
[]
rune
for
_
,
r
:=
range
in
{
out
=
append
(
out
,
r
)
out
=
append
(
out
,
'\u0301'
)
}
return
out
}
var
testString
=
[]
rune
(
"query"
)
func
TestCountGlyphs
(
t
*
testing
.
T
)
{
count
:=
countGlyphs
(
testString
)
if
count
!=
len
(
testString
)
{
t
.
Errorf
(
"ASCII count incorrect. %d != %d"
,
count
,
len
(
testString
))
}
count
=
countGlyphs
(
accent
(
testString
))
if
count
!=
len
(
testString
)
{
t
.
Errorf
(
"Accent count incorrect. %d != %d"
,
count
,
len
(
testString
))
}
}
func
compare
(
a
,
b
[]
rune
,
name
string
,
t
*
testing
.
T
)
{
if
len
(
a
)
!=
len
(
b
)
{
t
.
Errorf
(
`"%s" != "%s" in %s"`
,
string
(
a
),
string
(
b
),
name
)
return
}
for
i
:=
range
a
{
if
a
[
i
]
!=
b
[
i
]
{
t
.
Errorf
(
`"%s" != "%s" in %s"`
,
string
(
a
),
string
(
b
),
name
)
return
}
}
}
func
TestPrefixGlyphs
(
t
*
testing
.
T
)
{
for
i
:=
0
;
i
<=
len
(
testString
);
i
++
{
iter
:=
strconv
.
Itoa
(
i
)
out
:=
getPrefixGlyphs
(
testString
,
i
)
compare
(
out
,
testString
[
:
i
],
"ascii prefix "
+
iter
,
t
)
out
=
getPrefixGlyphs
(
accent
(
testString
),
i
)
compare
(
out
,
accent
(
testString
[
:
i
]),
"accent prefix "
+
iter
,
t
)
}
out
:=
getPrefixGlyphs
(
testString
,
999
)
compare
(
out
,
testString
,
"ascii prefix overflow"
,
t
)
out
=
getPrefixGlyphs
(
accent
(
testString
),
999
)
compare
(
out
,
accent
(
testString
),
"accent prefix overflow"
,
t
)
out
=
getPrefixGlyphs
(
testString
,
-
3
)
if
len
(
out
)
!=
0
{
t
.
Error
(
"ascii prefix negative"
)
}
out
=
getPrefixGlyphs
(
accent
(
testString
),
-
3
)
if
len
(
out
)
!=
0
{
t
.
Error
(
"accent prefix negative"
)
}
}
func
TestSuffixGlyphs
(
t
*
testing
.
T
)
{
for
i
:=
0
;
i
<=
len
(
testString
);
i
++
{
iter
:=
strconv
.
Itoa
(
i
)
out
:=
getSuffixGlyphs
(
testString
,
i
)
compare
(
out
,
testString
[
len
(
testString
)
-
i
:
],
"ascii suffix "
+
iter
,
t
)
out
=
getSuffixGlyphs
(
accent
(
testString
),
i
)
compare
(
out
,
accent
(
testString
[
len
(
testString
)
-
i
:
]),
"accent suffix "
+
iter
,
t
)
}
out
:=
getSuffixGlyphs
(
testString
,
999
)
compare
(
out
,
testString
,
"ascii suffix overflow"
,
t
)
out
=
getSuffixGlyphs
(
accent
(
testString
),
999
)
compare
(
out
,
accent
(
testString
),
"accent suffix overflow"
,
t
)
out
=
getSuffixGlyphs
(
testString
,
-
3
)
if
len
(
out
)
!=
0
{
t
.
Error
(
"ascii suffix negative"
)
}
out
=
getSuffixGlyphs
(
accent
(
testString
),
-
3
)
if
len
(
out
)
!=
0
{
t
.
Error
(
"accent suffix negative"
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment