Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
stratact
liner
Commits
0ccda02d
Commit
0ccda02d
authored
Nov 01, 2018
by
Michael Aaron Murphy
Browse files
Merge branch 'optimize' into 'master'
Optimize via Clippy & Thread-Local Buffer See merge request
redox-os/liner!9
parents
29e4434e
2aa8516e
Pipeline
#1647
passed with stage
in 2 minutes and 8 seconds
Changes
7
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/buffer.rs
View file @
0ccda02d
...
...
@@ -158,7 +158,7 @@ impl Buffer {
}
pub
fn
revert
(
&
mut
self
)
->
bool
{
if
self
.actions
.
len
()
==
0
{
if
self
.actions
.
is_empty
()
{
return
false
;
}
...
...
@@ -228,7 +228,7 @@ impl Buffer {
}
pub
fn
range_chars
(
&
self
,
start
:
usize
,
end
:
usize
)
->
Vec
<
char
>
{
self
.data
[
start
..
end
]
.
iter
()
.cloned
()
.collect
()
self
.data
[
start
..
end
]
.
to_owned
()
}
pub
fn
width
(
&
self
)
->
Vec
<
usize
>
{
...
...
@@ -292,13 +292,12 @@ impl Buffer {
pub
fn
starts_with
(
&
self
,
other
:
&
Buffer
)
->
bool
{
let
other_len
=
other
.data
.len
();
let
self_len
=
self
.data
.len
();
if
other
.data
.
len
()
!=
0
&&
self_len
!=
other_len
{
if
!
other
.data
.
is_empty
()
&&
self_len
!=
other_len
{
let
match_let
=
self
.data
.iter
()
.zip
(
&
other
.data
)
.take_while
(|
&
(
s
,
o
)|
*
s
==
*
o
)
.collect
::
<
Vec
<
_
>>
()
.len
();
.count
();
match_let
==
other_len
}
else
{
false
...
...
src/complete.rs
View file @
0ccda02d
...
...
@@ -40,7 +40,7 @@ impl Completer for FilenameCompleter {
let
start_owned
:
String
=
if
start
.starts_with
(
'\"'
)
||
start
.starts_with
(
'\''
)
{
start
=
&
start
[
1
..
];
if
start
.
len
()
>=
1
{
if
!
start
.
is_empty
()
{
start
=
&
start
[
..
start
.len
()
-
1
];
}
start
.into
()
...
...
@@ -64,7 +64,7 @@ impl Completer for FilenameCompleter {
let
completing_dir
;
match
full_path
.parent
()
{
// XXX non-unix separaor
Some
(
parent
)
if
!
start
.is_empty
()
&&
!
start_owned
.ends_with
(
"/"
)
&&
Some
(
parent
)
if
!
start
.is_empty
()
&&
!
start_owned
.ends_with
(
'/'
)
&&
!
full_path
.ends_with
(
".."
)
=>
{
p
=
parent
;
start_name
=
full_path
...
...
@@ -76,7 +76,7 @@ impl Completer for FilenameCompleter {
_
=>
{
p
=
full_path
.as_path
();
start_name
=
""
.into
();
completing_dir
=
start
.is_empty
()
||
start
.ends_with
(
"/"
)
||
full_path
.ends_with
(
".."
);
completing_dir
=
start
.is_empty
()
||
start
.ends_with
(
'/'
)
||
full_path
.ends_with
(
".."
);
}
}
...
...
src/context.rs
View file @
0ccda02d
...
...
@@ -25,10 +25,8 @@ pub fn get_buffer_words(buf: &Buffer) -> Vec<(usize, usize)> {
res
.push
((
start
,
i
));
word_start
=
None
;
}
}
else
{
if
c
!=
' '
{
word_start
=
Some
(
i
);
}
}
else
if
c
!=
' '
{
word_start
=
Some
(
i
);
}
just_had_backslash
=
false
;
...
...
src/editor.rs
View file @
0ccda02d
use
std
::
cell
::
RefCell
;
use
std
::
cmp
;
use
std
::
io
::{
self
,
Write
};
use
termion
::{
self
,
clear
,
color
,
cursor
};
...
...
@@ -8,6 +9,37 @@ use Buffer;
use
event
::
*
;
use
util
;
/// Buffer for prompt writes, meant to be shared between prompt creations.
struct
LocalBuffer
(
pub
RefCell
<
Vec
<
u8
>>
);
impl
LocalBuffer
{
pub
fn
new
()
->
Self
{
LocalBuffer
(
RefCell
::
new
(
Vec
::
with_capacity
(
512
)))
}
pub
fn
append
(
&
self
,
bytes
:
&
[
u8
])
{
self
.0
.borrow_mut
()
.extend_from_slice
(
bytes
);
}
pub
fn
push
(
&
self
,
byte
:
u8
)
{
self
.0
.borrow_mut
()
.push
(
byte
);
}
pub
fn
pop
(
&
self
)
->
Option
<
u8
>
{
self
.0
.borrow_mut
()
.pop
()
}
pub
fn
extract
<
T
>
(
&
self
,
mut
func
:
impl
FnMut
(
&
[
u8
])
->
T
)
->
T
{
let
result
=
func
(
&
self
.0
.borrow
());
self
.0
.borrow_mut
()
.clear
();
result
}
}
thread_local!
{
static
BUFFER
:
LocalBuffer
=
LocalBuffer
::
new
();
}
/// Represents the position of the cursor relative to words in the buffer.
#[derive(Debug,
Clone,
Copy,
PartialEq,
Eq)]
pub
enum
CursorPosition
{
...
...
@@ -73,9 +105,6 @@ pub struct Editor<'a, W: Write> {
// Buffer for the new line (ie. not from editing history)
new_buf
:
Buffer
,
// Store the line to be written here, avoiding allocations & formatting.
output_buf
:
Vec
<
u8
>
,
// None if we're on the new buffer, else the index of history
cur_history_loc
:
Option
<
usize
>
,
...
...
@@ -138,7 +167,6 @@ impl<'a, W: Write> Editor<'a, W> {
out
:
out
,
closure
:
f
,
new_buf
:
buffer
.into
(),
output_buf
:
Vec
::
new
(),
cur_history_loc
:
None
,
context
:
context
,
show_completions_hint
:
None
,
...
...
@@ -195,7 +223,7 @@ impl<'a, W: Write> Editor<'a, W> {
self
.cursor
=
cur_buf!
(
self
)
.num_chars
();
self
.no_newline
=
true
;
self
._display
(
false
)
?
;
self
.out
.write
(
b"
\r\n
"
)
?
;
self
.out
.write
_all
(
b"
\r\n
"
)
?
;
self
.show_completions_hint
=
None
;
Ok
(
true
)
}
...
...
@@ -242,7 +270,7 @@ impl<'a, W: Write> Editor<'a, W> {
Ok
(
did
)
}
fn
print_completion_list
(
output_buf
:
&
mut
Vec
<
u8
>
,
completions
:
&
[
String
],
highlighted
:
Option
<
usize
>
)
->
io
::
Result
<
usize
>
{
fn
print_completion_list
(
completions
:
&
[
String
],
highlighted
:
Option
<
usize
>
)
->
io
::
Result
<
usize
>
{
use
std
::
cmp
::
max
;
let
(
w
,
_
)
=
termion
::
terminal_size
()
?
;
...
...
@@ -255,30 +283,33 @@ impl<'a, W: Write> Editor<'a, W> {
let
mut
lines
=
0
;
let
mut
i
=
0
;
for
(
index
,
com
)
in
completions
.iter
()
.enumerate
()
{
if
i
==
cols
{
output_buf
.write_all
(
b"
\r\n
"
)
?
;
lines
+=
1
;
i
=
0
;
}
else
if
i
>
cols
{
unreachable!
()
}
BUFFER
.with
(|
output_buf
|
{
let
mut
i
=
0
;
for
(
index
,
com
)
in
completions
.iter
()
.enumerate
()
{
if
i
==
cols
{
output_buf
.append
(
b"
\r\n
"
);
lines
+=
1
;
i
=
0
;
}
else
if
i
>
cols
{
unreachable!
()
}
if
Some
(
index
)
==
highlighted
{
output_buf
.extend_from_slice
(
color
::
Black
.fg_str
()
.as_bytes
());
output_buf
.extend_from_slice
(
color
::
White
.bg_str
()
.as_bytes
());
}
write!
(
output_buf
,
"{:<1$}"
,
com
,
col_width
)
?
;
if
Some
(
index
)
==
highlighted
{
output_buf
.extend_from_slice
(
color
::
Reset
.bg_str
()
.as_bytes
());
output_buf
.extend_from_slice
(
color
::
Reset
.fg_str
()
.as_bytes
());
if
Some
(
index
)
==
highlighted
{
output_buf
.append
(
color
::
Black
.fg_str
()
.as_bytes
());
output_buf
.append
(
color
::
White
.bg_str
()
.as_bytes
());
}
write!
(
output_buf
.0
.borrow_mut
(),
"{:<1$}"
,
com
,
col_width
)
?
;
if
Some
(
index
)
==
highlighted
{
output_buf
.append
(
color
::
Reset
.bg_str
()
.as_bytes
());
output_buf
.append
(
color
::
Reset
.fg_str
()
.as_bytes
());
}
i
+=
1
;
}
i
+=
1
;
}
Ok
(
lines
)
}
)
Ok
(
lines
)
}
pub
fn
skip_completions_hint
(
&
mut
self
)
{
...
...
@@ -392,8 +423,11 @@ impl<'a, W: Write> Editor<'a, W> {
/// Clears the screen then prints the prompt and current buffer.
pub
fn
clear
(
&
mut
self
)
->
io
::
Result
<
()
>
{
self
.output_buf
.extend_from_slice
(
clear
::
All
.as_ref
());
self
.output_buf
.extend_from_slice
(
String
::
from
(
cursor
::
Goto
(
1
,
1
))
.as_bytes
());
BUFFER
.with
(|
output_buf
|
{
output_buf
.append
(
clear
::
All
.as_ref
());
output_buf
.append
(
String
::
from
(
cursor
::
Goto
(
1
,
1
))
.as_bytes
());
});
self
.term_cursor_line
=
1
;
self
.no_newline
=
true
;
self
.display
()
...
...
@@ -658,169 +692,173 @@ impl<'a, W: Write> Editor<'a, W> {
}
fn
_display
(
&
mut
self
,
show_autosuggest
:
bool
)
->
io
::
Result
<
()
>
{
fn
calc_width
(
prompt_width
:
usize
,
buf_widths
:
&
[
usize
],
terminal_width
:
usize
)
->
usize
{
let
mut
total
=
0
;
BUFFER
.with
(|
output_buf
|
{
fn
calc_width
(
prompt_width
:
usize
,
buf_widths
:
&
[
usize
],
terminal_width
:
usize
)
->
usize
{
let
mut
total
=
0
;
for
line
in
buf_widths
{
if
total
%
terminal_width
!=
0
{
total
=
((
total
/
terminal_width
)
+
1
)
*
terminal_width
;
for
line
in
buf_widths
{
if
total
%
terminal_width
!=
0
{
total
=
((
total
/
terminal_width
)
+
1
)
*
terminal_width
;
}
total
+=
prompt_width
+
line
;
}
total
+=
prompt_width
+
line
;
total
}
total
}
let
terminal_width
=
util
::
terminal_width
()
?
;
let
prompt_width
=
util
::
last_prompt_line_width
(
&
self
.prompt
);
let
buf
=
cur_buf!
(
self
);
let
buf_width
=
buf
.width
();
let
terminal_width
=
util
::
terminal_width
()
?
;
let
prompt_width
=
util
::
last_prompt_line_width
(
&
self
.prompt
);
// Don't let the cursor go over the end!
let
buf_num_chars
=
buf
.num_chars
();
if
buf_num_chars
<
self
.cursor
{
self
.cursor
=
buf_num_chars
;
}
let
buf
=
cur_buf!
(
self
);
let
buf_width
=
buf
.width
();
// Can't move past the last character in vi normal mode
if
self
.no_eol
&&
self
.cursor
!=
0
&&
self
.cursor
==
buf_num_chars
{
self
.cursor
-=
1
;
}
// Don't let the cursor go over the end!
let
buf_num_chars
=
buf
.num_chars
();
if
buf_num_chars
<
self
.cursor
{
self
.cursor
=
buf_num_chars
;
}
// Width of the current buffer lines (including autosuggestion)
let
buf_widths
=
match
self
.current_autosuggestion
()
{
Some
(
suggestion
)
=>
suggestion
.width
(),
None
=>
buf_width
,
};
// Width of the current buffer lines (including autosuggestion) from the start to the cursor
let
buf_widths_to_cursor
=
match
self
.current_autosuggestion
()
{
Some
(
suggestion
)
=>
suggestion
.range_width
(
0
,
self
.cursor
),
None
=>
buf
.range_width
(
0
,
self
.cursor
),
};
// Can't move past the last character in vi normal mode
if
self
.no_eol
&&
self
.cursor
!=
0
&&
self
.cursor
==
buf_num_chars
{
self
.cursor
-=
1
;
}
// Total number of terminal spaces taken up by prompt and buffer
let
new_total_width
=
calc_width
(
prompt_width
,
&
buf_widths
,
terminal_width
);
let
new_total_width_to_cursor
=
calc_width
(
prompt_width
,
&
buf_widths_to_cursor
,
terminal_width
);
// Width of the current buffer lines (including autosuggestion)
let
buf_widths
=
match
self
.current_autosuggestion
()
{
Some
(
suggestion
)
=>
suggestion
.width
(),
None
=>
buf_width
,
};
// Width of the current buffer lines (including autosuggestion) from the start to the cursor
let
buf_widths_to_cursor
=
match
self
.current_autosuggestion
()
{
Some
(
suggestion
)
=>
suggestion
.range_width
(
0
,
self
.cursor
),
None
=>
buf
.range_width
(
0
,
self
.cursor
),
};
let
new_num_lines
=
(
new_total_width
+
terminal_width
)
/
terminal_width
;
// Total number of terminal spaces taken up by prompt and buffer
let
new_total_width
=
calc_width
(
prompt_width
,
&
buf_widths
,
terminal_width
);
let
new_total_width_to_cursor
=
calc_width
(
prompt_width
,
&
buf_widths_to_cursor
,
terminal_width
);
// Move the term cursor to the same line as the prompt.
if
self
.term_cursor_line
>
1
{
self
.output_buf
.extend_from_slice
(
cursor
::
Up
(
self
.term_cursor_line
as
u16
-
1
)
.to_string
()
.as_bytes
());
}
let
new_num_lines
=
(
new_total_width
+
terminal_width
)
/
terminal_width
;
if
!
self
.no_newline
{
self
.output_buf
.extend_from_slice
(
"⏎"
.as_bytes
());
for
_
in
0
..
(
terminal_width
-
1
)
{
self
.output_buf
.push
(
b' '
);
// Move the term cursor to the same line as the prompt.
if
self
.term_cursor_line
>
1
{
output_buf
.append
(
cursor
::
Up
(
self
.term_cursor_line
as
u16
-
1
)
.to_string
()
.as_bytes
());
}
}
self
.output_buf
.push
(
b'\r'
);
self
.output_buf
.extend_from_slice
(
clear
::
AfterCursor
.as_ref
());
// If we're cycling through completions, show those
let
mut
completion_lines
=
0
;
if
let
Some
((
completions
,
i
))
=
self
.show_completions_hint
.as_ref
()
{
completion_lines
=
1
+
Self
::
print_completion_list
(
&
mut
self
.output_buf
,
completions
,
*
i
)
?
;
self
.output_buf
.extend_from_slice
(
b"
\r\n
"
);
}
// Write the prompt
if
!
self
.no_newline
{
for
line
in
self
.prompt
.split
(
'\n'
)
{
self
.output_buf
.extend_from_slice
(
line
.as_bytes
());
self
.output_buf
.extend_from_slice
(
b"
\r\n
"
);
if
!
self
.no_newline
{
output_buf
.append
(
"⏎"
.as_bytes
());
for
_
in
0
..
(
terminal_width
-
1
)
{
output_buf
.push
(
b' '
);
}
}
self
.output_buf
.pop
();
// pop the '\n'
self
.output_buf
.pop
();
// pop the '\r'
}
else
{
self
.output_buf
.extend_from_slice
(
util
::
handle_prompt
(
&
self
.prompt
)
.as_bytes
());
}
// If we have an autosuggestion, we make the autosuggestion the buffer we print out.
// We get the number of bytes in the buffer (but NOT the autosuggestion).
// Then, we loop and subtract from that number until it's 0, in which case we are printing
// the autosuggestion from here on (in a different color).
let
lines
=
if
show_autosuggest
{
match
self
.current_autosuggestion
()
{
Some
(
suggestion
)
=>
suggestion
.lines
(),
None
=>
buf
.lines
(),
}
}
else
{
buf
.lines
()
};
let
mut
buf_num_remaining_bytes
=
buf
.num_bytes
();
output_buf
.push
(
b'\r'
);
output_buf
.append
(
clear
::
AfterCursor
.as_ref
());
let
lines_len
=
lines
.len
();
for
(
i
,
line
)
in
lines
.into_iter
()
.enumerate
()
{
if
i
>
0
{
self
.output_buf
.extend_from_slice
(
cursor
::
Right
(
prompt_width
as
u16
)
.to_string
()
.as_bytes
());
// If we're cycling through completions, show those
let
mut
completion_lines
=
0
;
if
let
Some
((
completions
,
i
))
=
self
.show_completions_hint
.as_ref
()
{
completion_lines
=
1
+
Self
::
print_completion_list
(
completions
,
*
i
)
?
;
output_buf
.append
(
b"
\r\n
"
);
}
if
buf_num_remaining_bytes
==
0
{
self
.output_buf
.extend_from_slice
(
line
.as_bytes
());
}
else
if
line
.len
()
>
buf_num_remaining_bytes
{
let
start
=
&
line
[
..
buf_num_remaining_bytes
];
let
start
=
match
self
.closure
{
Some
(
ref
f
)
=>
f
(
start
),
None
=>
start
.to_owned
(),
};
self
.output_buf
.extend_from_slice
(
start
.as_bytes
());
self
.output_buf
.extend_from_slice
(
color
::
Yellow
.fg_str
()
.as_bytes
());
self
.output_buf
.extend_from_slice
(
line
[
buf_num_remaining_bytes
..
]
.as_bytes
());
buf_num_remaining_bytes
=
0
;
// Write the prompt
if
!
self
.no_newline
{
for
line
in
self
.prompt
.split
(
'\n'
)
{
output_buf
.append
(
line
.as_bytes
());
output_buf
.append
(
b"
\r\n
"
);
}
output_buf
.pop
();
// pop the '\n'
output_buf
.pop
();
// pop the '\r'
}
else
{
buf_num_remaining_bytes
-=
line
.len
();
let
written_line
=
match
self
.closure
{
Some
(
ref
f
)
=>
f
(
&
line
),
None
=>
line
,
};
self
.output_buf
.extend_from_slice
(
written_line
.as_bytes
());
output_buf
.append
(
util
::
handle_prompt
(
&
self
.prompt
)
.as_bytes
());
}
if
i
+
1
<
lines_len
{
self
.output_buf
.extend_from_slice
(
b"
\r\n
"
);
// If we have an autosuggestion, we make the autosuggestion the buffer we print out.
// We get the number of bytes in the buffer (but NOT the autosuggestion).
// Then, we loop and subtract from that number until it's 0, in which case we are printing
// the autosuggestion from here on (in a different color).
let
lines
=
if
show_autosuggest
{
match
self
.current_autosuggestion
()
{
Some
(
suggestion
)
=>
suggestion
.lines
(),
None
=>
buf
.lines
(),
}
}
else
{
buf
.lines
()
};
let
mut
buf_num_remaining_bytes
=
buf
.num_bytes
();
let
lines_len
=
lines
.len
();
for
(
i
,
line
)
in
lines
.into_iter
()
.enumerate
()
{
if
i
>
0
{
output_buf
.append
(
cursor
::
Right
(
prompt_width
as
u16
)
.to_string
()
.as_bytes
());
}
if
buf_num_remaining_bytes
==
0
{
output_buf
.append
(
line
.as_bytes
());
}
else
if
line
.len
()
>
buf_num_remaining_bytes
{
let
start
=
&
line
[
..
buf_num_remaining_bytes
];
let
start
=
match
self
.closure
{
Some
(
ref
f
)
=>
f
(
start
),
None
=>
start
.to_owned
(),
};
output_buf
.append
(
start
.as_bytes
());
output_buf
.append
(
color
::
Yellow
.fg_str
()
.as_bytes
());
output_buf
.append
(
line
[
buf_num_remaining_bytes
..
]
.as_bytes
());
buf_num_remaining_bytes
=
0
;
}
else
{
buf_num_remaining_bytes
-=
line
.len
();
let
written_line
=
match
self
.closure
{
Some
(
ref
f
)
=>
f
(
&
line
),
None
=>
line
,
};
output_buf
.append
(
written_line
.as_bytes
());
}
if
i
+
1
<
lines_len
{
output_buf
.append
(
b"
\r\n
"
);
}
}
}
if
self
.is_currently_showing_autosuggestion
()
{
self
.
output_buf
.
extend_from_slice
(
color
::
Reset
.fg_str
()
.as_bytes
());
}
if
self
.is_currently_showing_autosuggestion
()
{
output_buf
.
append
(
color
::
Reset
.fg_str
()
.as_bytes
());
}
// at the end of the line, move the cursor down a line
if
new_total_width
%
terminal_width
==
0
{
self
.
output_buf
.
extend_from_slice
(
b"
\r\n
"
);
}
// at the end of the line, move the cursor down a line
if
new_total_width
%
terminal_width
==
0
{
output_buf
.
append
(
b"
\r\n
"
);
}
self
.term_cursor_line
=
(
new_total_width_to_cursor
+
terminal_width
)
/
terminal_width
;
self
.term_cursor_line
=
(
new_total_width_to_cursor
+
terminal_width
)
/
terminal_width
;
// The term cursor is now on the bottom line. We may need to move the term cursor up
// to the line where the true cursor is.
let
cursor_line_diff
=
new_num_lines
as
isize
-
self
.term_cursor_line
as
isize
;
if
cursor_line_diff
>
0
{
self
.
output_buf
.
extend_from_slice
(
cursor
::
Up
(
cursor_line_diff
as
u16
)
.to_string
()
.as_bytes
());
}
else
if
cursor_line_diff
<
0
{
unreachable!
();
}
// The term cursor is now on the bottom line. We may need to move the term cursor up
// to the line where the true cursor is.
let
cursor_line_diff
=
new_num_lines
as
isize
-
self
.term_cursor_line
as
isize
;
if
cursor_line_diff
>
0
{
output_buf
.
append
(
cursor
::
Up
(
cursor_line_diff
as
u16
)
.to_string
()
.as_bytes
());
}
else
if
cursor_line_diff
<
0
{
unreachable!
();
}
// Now that we are on the right line, we must move the term cursor left or right
// to match the true cursor.
let
cursor_col_diff
=
new_total_width
as
isize
-
new_total_width_to_cursor
as
isize
-
cursor_line_diff
*
terminal_width
as
isize
;
if
cursor_col_diff
>
0
{
self
.
output_buf
.
extend_from_slice
(
cursor
::
Left
(
cursor_col_diff
as
u16
)
.to_string
()
.as_bytes
());
}
else
if
cursor_col_diff
<
0
{
self
.
output_buf
.
extend_from_slice
(
cursor
::
Right
((
-
cursor_col_diff
)
as
u16
)
.to_string
()
.as_bytes
());
}
// Now that we are on the right line, we must move the term cursor left or right
// to match the true cursor.
let
cursor_col_diff
=
new_total_width
as
isize
-
new_total_width_to_cursor
as
isize
-
cursor_line_diff
*
terminal_width
as
isize
;
if
cursor_col_diff
>
0
{
output_buf
.
append
(
cursor
::
Left
(
cursor_col_diff
as
u16
)
.to_string
()
.as_bytes
());
}
else
if
cursor_col_diff
<
0
{
output_buf
.
append
(
cursor
::
Right
((
-
cursor_col_diff
)
as
u16
)
.to_string
()
.as_bytes
());
}
self
.term_cursor_line
+=
completion_lines
;
self
.term_cursor_line
+=
completion_lines
;
self
.out
.write_all
(
&
self
.output_buf
)
?
;
self
.output_buf
.clear
();
self
.out
.flush
()
{
let
out
=
&
mut
self
.out
;
output_buf
.extract
(|
b
|
out
.write_all
(
b
))
?
;
out
.flush
()
}
})
}
/// Deletes the displayed prompt and buffer, replacing them with the current prompt and buffer
...
...
@@ -859,7 +897,6 @@ mod tests {
#[test]
fn
move_cursor_left
()
{
let
mut
context
=
Context
::
new
();
let
closure
=
|
s
:
&
str
|
{
String
::
from
(
s
)};
let
out
=
Vec
::
new
();
let
mut
ed
=
Editor
::
new
(
out
,
"prompt"
.to_owned
(),
None
,
&
mut
context
)
.unwrap
();
ed
.insert_str_after_cursor
(
"let"
)
.unwrap
();
...
...
src/history.rs
View file @
0ccda02d
...
...
@@ -4,7 +4,7 @@ use std::{
collections
::{
vec_deque
,
VecDeque
},
io
::{
BufRead
,
BufReader
,
BufWriter
},
fs
::
File
,
io
::{
self
,
Seek
,
SeekFrom
,
Write
},
io
::{
self
,
Write
},
iter
::
IntoIterator
,
ops
::
Index
,
ops
::
IndexMut
,
...
...
@@ -115,7 +115,7 @@ impl History {
curr_position
:
Option
<
usize
>
,
new_buff
:
&
'b
Buffer
,
)
->
Option
<&
'a
Buffer
>
{
let
pos
=
curr_position
.unwrap_or
(
self
.buffers
.len
());
let
pos
=
curr_position
.unwrap_or
_else
(||
self
.buffers
.len
());
for
iter
in
(
0
..
pos
)
.rev
()
{
if
let
Some
(
tested
)
=
self
.buffers
.get
(
iter
)
{
if
tested
.starts_with
(
new_buff
)
{
...
...
src/keymap/vi.rs
View file @
0ccda02d
...
...
@@ -45,7 +45,7 @@ impl ModeStack {
/// If the stack is empty, we are in normal mode.
fn
mode
(
&
self
)
->
Mode
{
self
.0
.last
()
.
map
(|
&
m
|
m
)
.
cloned
(
)
.unwrap_or
(
Mode
::
Normal
)
}
...
...
@@ -92,18 +92,18 @@ enum ViMoveDir {
}
impl
ViMoveDir
{
pub
fn
advance
(
&
self
,
cursor
:
&
mut
usize
,
max
:
usize
)
->
bool
{
self
.move_cursor
(
cursor
,
max
,
*
self
)
pub
fn
advance
(
self
,
cursor
:
&
mut
usize
,
max
:
usize
)
->
bool
{
self
.move_cursor
(
cursor
,
max
,
self
)
}
pub
fn
go_back
(
&
self
,
cursor
:
&
mut
usize
,
max
:
usize
)
->
bool
{
match
*
self
{
pub
fn
go_back
(
self
,
cursor
:
&
mut
usize
,
max
:
usize
)
->
bool
{
match
self
{
ViMoveDir
::
Right
=>
self
.move_cursor
(
cursor
,
max
,
ViMoveDir
::
Left
),
ViMoveDir
::
Left
=>
self
.move_cursor
(
cursor
,
max
,
ViMoveDir
::
Right
),
}
}
fn
move_cursor
(
&
self
,
cursor
:
&
mut
usize
,
max
:
usize
,
dir
:
ViMoveDir
)
->
bool
{
fn
move_cursor
(
self
,
cursor
:
&
mut
usize
,
max
:
usize
,
dir
:
ViMoveDir
)
->
bool
{
if
dir
==
ViMoveDir
::
Right
&&
*
cursor
==
max
{
return
false
;
}
...
...
@@ -272,8 +272,7 @@ fn find_char(buf: &::buffer::Buffer, start: usize, ch: char, count: usize) -> Op
.enumerate
()
.skip
(
start
)
.filter
(|
&
(
_
,
&
c
)|
c
==
ch
)
.skip
(
count
-
1
)
.next
()
.nth
(
count
-
1
)
.map
(|(
i
,
_
)|
i
)
}
...
...
@@ -285,8 +284,7 @@ fn find_char_rev(buf: &::buffer::Buffer, start: usize, ch: char, count: usize) -
.rev
()
.skip
(
rstart
)
.filter
(|
&
(
_
,
&
c
)|
c
==
ch
)
.skip
(
count
-
1
)
.next
()
.nth
(
count
-
1
)
.map
(|(
i
,
_
)|
i
)
}
...
...
src/util.rs
View file @
0ccda02d
...
...
@@ -10,14 +10,14 @@ pub fn last_prompt_line_width<S: AsRef<str>>(s: S) -> usize {
}
pub
fn
find_longest_common_prefix
<
T
:
Clone
+
Eq
>
(
among
:
&
[
Vec
<
T
>
])
->
Option
<
Vec
<
T
>>
{
if
among
.
len
()
==
0
{
if
among
.
is_empty
()
{
<