on master help sign in
Merge branch 'master' into great_line_ending_and_cursor_range_cleanup
2224a15Nathan Vegdahl
helix-core/src/auto_pairs.rs+1−1
@@ -139,7 +139,7 @@ fn handle_close(doc: &Rope, selection: &Selection, _open: char, close: char) ->
139}
139}
140
140
141// handle cases where open and close is the same, or in triples ("""docstring""")
141// handle cases where open and close is the same, or in triples ("""docstring""")
142−fn handle_same(doc: &Rope, selection: &Selection, token: char) -> Option<Transaction> {
142+fn handle_same(_doc: &Rope, _selection: &Selection, _token: char) -> Option<Transaction> {
143 // if not cursor but selection, wrap
143 // if not cursor but selection, wrap
144 // let next = next char
144 // let next = next char
145
145
helix-core/src/history.rs+4−6
@@ -1,7 +1,6 @@
1use crate::{ChangeSet, Rope, State, Transaction};
1use crate::{ChangeSet, Rope, State, Transaction};
2use once_cell::sync::Lazy;
2use once_cell::sync::Lazy;
3use regex::Regex;
3use regex::Regex;
4−use smallvec::{smallvec, SmallVec};
5use std::num::NonZeroUsize;
4use std::num::NonZeroUsize;
6use std::time::{Duration, Instant};
5use std::time::{Duration, Instant};
7
6
@@ -127,7 +126,6 @@ impl History {
127 let last_child = current_revision.last_child?;
126 let last_child = current_revision.last_child?;
128 self.current = last_child.get();
127 self.current = last_child.get();
129
128
130− let last_child_revision = &self.revisions[last_child.get()];
131 Some(&self.revisions[last_child.get()].transaction)
129 Some(&self.revisions[last_child.get()].transaction)
132 }
130 }
133
131
@@ -377,21 +375,21 @@ mod test {
377 if let Some(transaction) = history.undo() {
375 if let Some(transaction) = history.undo() {
378 transaction.apply(&mut state.doc);
376 transaction.apply(&mut state.doc);
379 }
377 }
380− };
378+ }
381
379
382 fn earlier(history: &mut History, state: &mut State, uk: UndoKind) {
380 fn earlier(history: &mut History, state: &mut State, uk: UndoKind) {
383 let txns = history.earlier(uk);
381 let txns = history.earlier(uk);
384 for txn in txns {
382 for txn in txns {
385 txn.apply(&mut state.doc);
383 txn.apply(&mut state.doc);
386 }
384 }
387− };
385+ }
388
386
389 fn later(history: &mut History, state: &mut State, uk: UndoKind) {
387 fn later(history: &mut History, state: &mut State, uk: UndoKind) {
390 let txns = history.later(uk);
388 let txns = history.later(uk);
391 for txn in txns {
389 for txn in txns {
392 txn.apply(&mut state.doc);
390 txn.apply(&mut state.doc);
393 }
391 }
394− };
392+ }
395
393
396 fn commit_change(
394 fn commit_change(
397 history: &mut History,
395 history: &mut History,
@@ -402,7 +400,7 @@ mod test {
402 let txn = Transaction::change(&state.doc, vec![change.clone()].into_iter());
400 let txn = Transaction::change(&state.doc, vec![change.clone()].into_iter());
403 history.commit_revision_at_timestamp(&txn, &state, instant);
401 history.commit_revision_at_timestamp(&txn, &state, instant);
404 txn.apply(&mut state.doc);
402 txn.apply(&mut state.doc);
405− };
403+ }
406
404
407 let t0 = Instant::now();
405 let t0 = Instant::now();
408 let t = |n| t0.checked_add(Duration::from_secs(n)).unwrap();
406 let t = |n| t0.checked_add(Duration::from_secs(n)).unwrap();
helix-core/src/indent.rs+6−4
@@ -1,13 +1,13 @@
1use crate::{
1use crate::{
2 find_first_non_whitespace_char,
2 find_first_non_whitespace_char,
3 syntax::{IndentQuery, LanguageConfiguration, Syntax},
3 syntax::{IndentQuery, LanguageConfiguration, Syntax},
4− tree_sitter::{Node, Tree},
4+ tree_sitter::Node,
5− Rope, RopeSlice,
5+ RopeSlice,
6};
6};
7
7
8/// To determine indentation of a newly inserted line, figure out the indentation at the last col
8/// To determine indentation of a newly inserted line, figure out the indentation at the last col
9/// of the previous line.
9/// of the previous line.
10−
10+#[allow(dead_code)]
11fn indent_level_for_line(line: RopeSlice, tab_width: usize) -> usize {
11fn indent_level_for_line(line: RopeSlice, tab_width: usize) -> usize {
12 let mut len = 0;
12 let mut len = 0;
13 for ch in line.chars() {
13 for ch in line.chars() {
@@ -98,12 +98,13 @@ fn calculate_indentation(query: &IndentQuery, node: Option<Node>, newline: bool)
98 increment as usize
98 increment as usize
99}
99}
100
100
101+#[allow(dead_code)]
101fn suggested_indent_for_line(
102fn suggested_indent_for_line(
102 language_config: &LanguageConfiguration,
103 language_config: &LanguageConfiguration,
103 syntax: Option<&Syntax>,
104 syntax: Option<&Syntax>,
104 text: RopeSlice,
105 text: RopeSlice,
105 line_num: usize,
106 line_num: usize,
106− tab_width: usize,
107+ _tab_width: usize,
107) -> usize {
108) -> usize {
108 if let Some(start) = find_first_non_whitespace_char(text.line(line_num)) {
109 if let Some(start) = find_first_non_whitespace_char(text.line(line_num)) {
109 return suggested_indent_for_pos(
110 return suggested_indent_for_pos(
@@ -150,6 +151,7 @@ pub fn suggested_indent_for_pos(
150#[cfg(test)]
151#[cfg(test)]
151mod test {
152mod test {
152 use super::*;
153 use super::*;
154+ use crate::Rope;
153
155
154 #[test]
156 #[test]
155 fn test_indent_level() {
157 fn test_indent_level() {
helix-core/src/lib.rs−1
@@ -1,4 +1,3 @@
1−#![allow(unused)]
2pub mod auto_pairs;
1pub mod auto_pairs;
3pub mod chars;
2pub mod chars;
4pub mod comment;
3pub mod comment;
helix-core/src/line_ending.rs+1−1
@@ -1,4 +1,4 @@
1−use crate::{Rope, RopeGraphemes, RopeSlice};
1+use crate::{Rope, RopeSlice};
2
2
3#[cfg(target_os = "windows")]
3#[cfg(target_os = "windows")]
4pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::Crlf;
4pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::Crlf;
helix-core/src/match_brackets.rs+2−2
@@ -1,4 +1,4 @@
1−use crate::{Range, Rope, Selection, Syntax};
1+use crate::{Rope, Syntax};
2
2
3const PAIRS: &[(char, char)] = &[('(', ')'), ('{', '}'), ('[', ']'), ('<', '>')];
3const PAIRS: &[(char, char)] = &[('(', ')'), ('{', '}'), ('[', ']'), ('<', '>')];
4// limit matching pairs to only ( ) { } [ ] < >
4// limit matching pairs to only ( ) { } [ ] < >
@@ -12,7 +12,7 @@ pub fn find(syntax: &Syntax, doc: &Rope, pos: usize) -> Option<usize> {
12 // most naive implementation: find the innermost syntax node, if we're at the edge of a node,
12 // most naive implementation: find the innermost syntax node, if we're at the edge of a node,
13 // return the other edge.
13 // return the other edge.
14
14
15− let mut node = match tree
15+ let node = match tree
16 .root_node()
16 .root_node()
17 .named_descendant_for_byte_range(byte_pos, byte_pos)
17 .named_descendant_for_byte_range(byte_pos, byte_pos)
18 {
18 {
helix-core/src/movement.rs+11−15
@@ -1,12 +1,9 @@
1−use std::iter::{self, from_fn, Peekable, SkipWhile};
1+use std::iter::{self, from_fn};
2
2
3use ropey::iter::Chars;
3use ropey::iter::Chars;
4
4
5use crate::{
5use crate::{
6− chars::{
7− categorize_char, char_is_line_ending, char_is_punctuation, char_is_whitespace,
6+ chars::{categorize_char, char_is_line_ending, CharCategory},
8− char_is_word, CharCategory,
9− },
10 coords_at_pos,
7 coords_at_pos,
11 graphemes::{nth_next_grapheme_boundary, nth_prev_grapheme_boundary},
8 graphemes::{nth_next_grapheme_boundary, nth_prev_grapheme_boundary},
12 line_ending::{get_line_ending, line_end_char_index},
9 line_ending::{get_line_ending, line_end_char_index},
@@ -116,7 +113,7 @@ pub fn move_prev_long_word_start(slice: RopeSlice, range: Range, count: usize) -
116 word_move(slice, range, count, WordMotionTarget::PrevLongWordStart)
113 word_move(slice, range, count, WordMotionTarget::PrevLongWordStart)
117}
114}
118
115
119−fn word_move(slice: RopeSlice, mut range: Range, count: usize, target: WordMotionTarget) -> Range {
116+fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTarget) -> Range {
120 (0..count).fold(range, |range, _| {
117 (0..count).fold(range, |range, _| {
121 slice.chars_at(range.head).range_to_target(target, range)
118 slice.chars_at(range.head).range_to_target(target, range)
122 })
119 })
@@ -182,7 +179,6 @@ enum WordMotionPhase {
182
179
183impl CharHelpers for Chars<'_> {
180impl CharHelpers for Chars<'_> {
184 fn range_to_target(&mut self, target: WordMotionTarget, origin: Range) -> Range {
181 fn range_to_target(&mut self, target: WordMotionTarget, origin: Range) -> Range {
185− let range = origin;
186 // Characters are iterated forward or backwards depending on the motion direction.
182 // Characters are iterated forward or backwards depending on the motion direction.
187 let characters: Box<dyn Iterator<Item = char>> = match target {
183 let characters: Box<dyn Iterator<Item = char>> = match target {
188 WordMotionTarget::PrevWordStart | WordMotionTarget::PrevLongWordStart => {
184 WordMotionTarget::PrevWordStart | WordMotionTarget::PrevLongWordStart => {
@@ -270,20 +266,20 @@ fn reached_target(target: WordMotionTarget, peek: char, next_peek: Option<&char>
270
266
271 match target {
267 match target {
272 WordMotionTarget::NextWordStart => {
268 WordMotionTarget::NextWordStart => {
273− (is_word_boundary(peek, *next_peek)
269+ is_word_boundary(peek, *next_peek)
274− && (char_is_line_ending(*next_peek) || !next_peek.is_whitespace()))
270+ && (char_is_line_ending(*next_peek) || !next_peek.is_whitespace())
275 }
271 }
276 WordMotionTarget::NextWordEnd | WordMotionTarget::PrevWordStart => {
272 WordMotionTarget::NextWordEnd | WordMotionTarget::PrevWordStart => {
277− (is_word_boundary(peek, *next_peek)
273+ is_word_boundary(peek, *next_peek)
278− && (!peek.is_whitespace() || char_is_line_ending(*next_peek)))
274+ && (!peek.is_whitespace() || char_is_line_ending(*next_peek))
279 }
275 }
280 WordMotionTarget::NextLongWordStart => {
276 WordMotionTarget::NextLongWordStart => {
281− (is_long_word_boundary(peek, *next_peek)
277+ is_long_word_boundary(peek, *next_peek)
282− && (char_is_line_ending(*next_peek) || !next_peek.is_whitespace()))
278+ && (char_is_line_ending(*next_peek) || !next_peek.is_whitespace())
283 }
279 }
284 WordMotionTarget::NextLongWordEnd | WordMotionTarget::PrevLongWordStart => {
280 WordMotionTarget::NextLongWordEnd | WordMotionTarget::PrevLongWordStart => {
285− (is_long_word_boundary(peek, *next_peek)
281+ is_long_word_boundary(peek, *next_peek)
286− && (!peek.is_whitespace() || char_is_line_ending(*next_peek)))
282+ && (!peek.is_whitespace() || char_is_line_ending(*next_peek))
287 }
283 }
288 }
284 }
289}
285}
helix-core/src/object.rs−1
@@ -1,5 +1,4 @@
1use crate::{Range, RopeSlice, Selection, Syntax};
1use crate::{Range, RopeSlice, Selection, Syntax};
2−use smallvec::smallvec;
3
2
4// TODO: to contract_selection we'd need to store the previous ranges before expand.
3// TODO: to contract_selection we'd need to store the previous ranges before expand.
5// Maybe just contract to the first child node?
4// Maybe just contract to the first child node?
helix-core/src/position.rs+4−3
@@ -1,7 +1,7 @@
1use crate::{
1use crate::{
2 chars::char_is_line_ending,
2 chars::char_is_line_ending,
3 graphemes::{nth_next_grapheme_boundary, RopeGraphemes},
3 graphemes::{nth_next_grapheme_boundary, RopeGraphemes},
4− Rope, RopeSlice,
4+ RopeSlice,
5};
5};
6
6
7/// Represents a single point in a text buffer. Zero indexed.
7/// Represents a single point in a text buffer. Zero indexed.
@@ -70,6 +70,7 @@ pub fn pos_at_coords(text: RopeSlice, coords: Position) -> usize {
70#[cfg(test)]
70#[cfg(test)]
71mod test {
71mod test {
72 use super::*;
72 use super::*;
73+ use crate::Rope;
73
74
74 #[test]
75 #[test]
75 fn test_ordering() {
76 fn test_ordering() {
@@ -79,8 +80,8 @@ mod test {
79
80
80 #[test]
81 #[test]
81 fn test_coords_at_pos() {
82 fn test_coords_at_pos() {
82− let text = Rope::from("ḧëḷḷö\nẅöṛḷḋ");
83+ // let text = Rope::from("ḧëḷḷö\nẅöṛḷḋ");
83− let slice = text.slice(..);
84+ // let slice = text.slice(..);
84 // assert_eq!(coords_at_pos(slice, 0), (0, 0).into());
85 // assert_eq!(coords_at_pos(slice, 0), (0, 0).into());
85 // assert_eq!(coords_at_pos(slice, 5), (0, 5).into()); // position on \n
86 // assert_eq!(coords_at_pos(slice, 5), (0, 5).into()); // position on \n
86 // assert_eq!(coords_at_pos(slice, 6), (1, 0).into()); // position on w
87 // assert_eq!(coords_at_pos(slice, 6), (1, 0).into()); // position on w
helix-core/src/selection.rs+7−8
@@ -6,7 +6,7 @@ use crate::{
6 graphemes::{
6 graphemes::{
7 ensure_grapheme_boundary_next, ensure_grapheme_boundary_prev, next_grapheme_boundary,
7 ensure_grapheme_boundary_next, ensure_grapheme_boundary_prev, next_grapheme_boundary,
8 },
8 },
9− Assoc, ChangeSet, Rope, RopeSlice,
9+ Assoc, ChangeSet, RopeSlice,
10};
10};
11use smallvec::{smallvec, SmallVec};
11use smallvec::{smallvec, SmallVec};
12use std::borrow::Cow;
12use std::borrow::Cow;
@@ -426,10 +426,8 @@ pub fn select_on_matches(
426 // TODO: can't avoid occasional allocations since Regex can't operate on chunks yet
426 // TODO: can't avoid occasional allocations since Regex can't operate on chunks yet
427 let fragment = sel.fragment(text);
427 let fragment = sel.fragment(text);
428
428
429− let mut sel_start = sel.from();
429+ let sel_start = sel.from();
430− let sel_end = sel.to();
431−
432− let mut start_byte = text.char_to_byte(sel_start);
430+ let start_byte = text.char_to_byte(sel_start);
433
431
434 for mat in regex.find_iter(&fragment) {
432 for mat in regex.find_iter(&fragment) {
435 // TODO: retain range direction
433 // TODO: retain range direction
@@ -466,10 +464,10 @@ pub fn split_on_matches(
466 // TODO: can't avoid occasional allocations since Regex can't operate on chunks yet
464 // TODO: can't avoid occasional allocations since Regex can't operate on chunks yet
467 let fragment = sel.fragment(text);
465 let fragment = sel.fragment(text);
468
466
469− let mut sel_start = sel.from();
467+ let sel_start = sel.from();
470 let sel_end = sel.to();
468 let sel_end = sel.to();
471
469
472− let mut start_byte = text.char_to_byte(sel_start);
470+ let start_byte = text.char_to_byte(sel_start);
473
471
474 let mut start = sel_start;
472 let mut start = sel_start;
475
473
@@ -492,11 +490,12 @@ pub fn split_on_matches(
492#[cfg(test)]
490#[cfg(test)]
493mod test {
491mod test {
494 use super::*;
492 use super::*;
493+ use crate::Rope;
495
494
496 #[test]
495 #[test]
497 #[should_panic]
496 #[should_panic]
498 fn test_new_empty() {
497 fn test_new_empty() {
499− let sel = Selection::new(smallvec![], 0);
498+ let _ = Selection::new(smallvec![], 0);
500 }
499 }
501
500
502 #[test]
501 #[test]
helix-core/src/syntax.rs+157−158
@@ -1,4 +1,10 @@
1+use crate::{
1−use crate::{chars::char_is_line_ending, regex::Regex, Change, Rope, RopeSlice, Transaction};
2+ chars::char_is_line_ending,
3+ regex::Regex,
4+ transaction::{ChangeSet, Operation},
5+ Rope, RopeSlice, Tendril,
6+};
7+
2pub use helix_syntax::{get_language, get_language_name, Lang};
8pub use helix_syntax::{get_language, get_language_name, Lang};
3
9
4use arc_swap::ArcSwap;
10use arc_swap::ArcSwap;
@@ -8,7 +14,7 @@ use std::{
8 cell::RefCell,
14 cell::RefCell,
9 collections::{HashMap, HashSet},
15 collections::{HashMap, HashSet},
10 fmt,
16 fmt,
11− path::{Path, PathBuf},
17+ path::Path,
12 sync::Arc,
18 sync::Arc,
13};
19};
14
20
@@ -160,7 +166,7 @@ impl LanguageConfiguration {
160 None
166 None
161 } else {
167 } else {
162 let language = get_language(self.language_id);
168 let language = get_language(self.language_id);
163− let mut config = HighlightConfiguration::new(
169+ let config = HighlightConfiguration::new(
164 language,
170 language,
165 &highlights_query,
171 &highlights_query,
166 &injections_query,
172 &injections_query,
@@ -326,7 +332,8 @@ impl Syntax {
326
332
327 // update root layer
333 // update root layer
328 PARSER.with(|ts_parser| {
334 PARSER.with(|ts_parser| {
335+ // TODO: handle the returned `Result` properly.
329− syntax.root_layer.parse(
336+ let _ = syntax.root_layer.parse(
330 &mut ts_parser.borrow_mut(),
337 &mut ts_parser.borrow_mut(),
331 &syntax.config,
338 &syntax.config,
332 source,
339 source,
@@ -381,7 +388,7 @@ impl Syntax {
381 source: RopeSlice<'a>,
388 source: RopeSlice<'a>,
382 range: Option<std::ops::Range<usize>>,
389 range: Option<std::ops::Range<usize>>,
383 cancellation_flag: Option<&'a AtomicUsize>,
390 cancellation_flag: Option<&'a AtomicUsize>,
384− mut injection_callback: impl FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a,
391+ injection_callback: impl FnMut(&str) -> Option<&'a HighlightConfiguration> + 'a,
385 ) -> impl Iterator<Item = Result<HighlightEvent, Error>> + 'a {
392 ) -> impl Iterator<Item = Result<HighlightEvent, Error>> + 'a {
386 // The `captures` iterator borrows the `Tree` and the `QueryCursor`, which
393 // The `captures` iterator borrows the `Tree` and the `QueryCursor`, which
387 // prevents them from being moved. But both of these values are really just
394 // prevents them from being moved. But both of these values are really just
@@ -473,12 +480,6 @@ pub struct LanguageLayer {
473 pub(crate) tree: Option<Tree>,
480 pub(crate) tree: Option<Tree>,
474}
481}
475
482
476−use crate::{
477− coords_at_pos,
478− transaction::{ChangeSet, Operation},
479− Tendril,
480−};
481−
482impl LanguageLayer {
483impl LanguageLayer {
483 // pub fn new() -> Self {
484 // pub fn new() -> Self {
484 // Self { tree: None }
485 // Self { tree: None }
@@ -494,8 +495,8 @@ impl LanguageLayer {
494 ts_parser: &mut TsParser,
495 ts_parser: &mut TsParser,
495 config: &HighlightConfiguration,
496 config: &HighlightConfiguration,
496 source: &Rope,
497 source: &Rope,
497− mut depth: usize,
498+ _depth: usize,
498− mut ranges: Vec<Range>,
499+ ranges: Vec<Range>,
499 ) -> Result<(), Error> {
500 ) -> Result<(), Error> {
500 if ts_parser.parser.set_included_ranges(&ranges).is_ok() {
501 if ts_parser.parser.set_included_ranges(&ranges).is_ok() {
501 ts_parser
502 ts_parser
@@ -566,7 +567,6 @@ impl LanguageLayer {
566 ) -> Vec<tree_sitter::InputEdit> {
567 ) -> Vec<tree_sitter::InputEdit> {
567 use Operation::*;
568 use Operation::*;
568 let mut old_pos = 0;
569 let mut old_pos = 0;
569− let mut new_pos = 0;
570
570
571 let mut edits = Vec::new();
571 let mut edits = Vec::new();
572
572
@@ -610,9 +610,7 @@ impl LanguageLayer {
610 let mut old_end = old_pos + len;
610 let mut old_end = old_pos + len;
611
611
612 match change {
612 match change {
613− Retain(_) => {
613+ Retain(_) => {}
614− new_pos += len;
615− }
616 Delete(_) => {
614 Delete(_) => {
617 let (start_byte, start_position) = point_at_pos(old_text, old_pos);
615 let (start_byte, start_position) = point_at_pos(old_text, old_pos);
618 let (old_end_byte, old_end_position) = point_at_pos(old_text, old_end);
616 let (old_end_byte, old_end_position) = point_at_pos(old_text, old_end);
@@ -636,8 +634,6 @@ impl LanguageLayer {
636 Insert(s) => {
634 Insert(s) => {
637 let (start_byte, start_position) = point_at_pos(old_text, old_pos);
635 let (start_byte, start_position) = point_at_pos(old_text, old_pos);
638
636
639− let ins = s.chars().count();
640−
641 // a subsequent delete means a replace, consume it
637 // a subsequent delete means a replace, consume it
642 if let Some(Delete(len)) = iter.peek() {
638 if let Some(Delete(len)) = iter.peek() {
643 old_end = old_pos + len;
639 old_end = old_pos + len;
@@ -665,8 +661,6 @@ impl LanguageLayer {
665 new_end_position: traverse(start_position, s), // old pos + chars, newlines matter too (iter over)
661 new_end_position: traverse(start_position, s), // old pos + chars, newlines matter too (iter over)
666 });
662 });
667 }
663 }
668−
669− new_pos += ins;
670 }
664 }
671 }
665 }
672 old_pos = old_end;
666 old_pos = old_end;
@@ -1480,7 +1474,6 @@ where
1480 // local scope at the top of the scope stack.
1474 // local scope at the top of the scope stack.
1481 else if Some(capture.index) == layer.config.local_def_capture_index {
1475 else if Some(capture.index) == layer.config.local_def_capture_index {
1482 reference_highlight = None;
1476 reference_highlight = None;
1483− definition_highlight = None;
1484 let scope = layer.scope_stack.last_mut().unwrap();
1477 let scope = layer.scope_stack.last_mut().unwrap();
1485
1478
1486 let mut value_range = 0..0;
1479 let mut value_range = 0..0;
@@ -1644,13 +1637,13 @@ fn injection_for_match<'a>(
1644 (language_name, content_node, include_children)
1637 (language_name, content_node, include_children)
1645}
1638}
1646
1639
1647−fn shrink_and_clear<T>(vec: &mut Vec<T>, capacity: usize) {
1640+// fn shrink_and_clear<T>(vec: &mut Vec<T>, capacity: usize) {
1648− if vec.len() > capacity {
1641+// if vec.len() > capacity {
1649− vec.truncate(capacity);
1642+// vec.truncate(capacity);
1650− vec.shrink_to_fit();
1643+// vec.shrink_to_fit();
1651− }
1644+// }
1652− vec.clear();
1645+// vec.clear();
1653−}
1646+// }
1654
1647
1655pub struct Merge<I> {
1648pub struct Merge<I> {
1656 iter: I,
1649 iter: I,
@@ -1691,7 +1684,7 @@ impl<I: Iterator<Item = HighlightEvent>> Iterator for Merge<I> {
1691 loop {
1684 loop {
1692 match (self.next_event, &self.next_span) {
1685 match (self.next_event, &self.next_span) {
1693 // this happens when range is partially or fully offscreen
1686 // this happens when range is partially or fully offscreen
1694− (Some(Source { start, end }), Some((span, range))) if start > range.start => {
1687+ (Some(Source { start, .. }), Some((span, range))) if start > range.start => {
1695 if start > range.end {
1688 if start > range.end {
1696 self.next_span = self.spans.next();
1689 self.next_span = self.spans.next();
1697 } else {
1690 } else {
@@ -1711,7 +1704,7 @@ impl<I: Iterator<Item = HighlightEvent>> Iterator for Merge<I> {
1711 self.next_event = self.iter.next();
1704 self.next_event = self.iter.next();
1712 Some(HighlightEnd)
1705 Some(HighlightEnd)
1713 }
1706 }
1714− (Some(Source { start, end }), Some((span, range))) if start < range.start => {
1707+ (Some(Source { start, end }), Some((_, range))) if start < range.start => {
1715 let intersect = range.start.min(end);
1708 let intersect = range.start.min(end);
1716 let event = Source {
1709 let event = Source {
1717 start,
1710 start,
@@ -1766,7 +1759,7 @@ impl<I: Iterator<Item = HighlightEvent>> Iterator for Merge<I> {
1766 Some(event)
1759 Some(event)
1767 }
1760 }
1768 // can happen if deleting and cursor at EOF, and diagnostic reaches past the end
1761 // can happen if deleting and cursor at EOF, and diagnostic reaches past the end
1769− (None, Some((span, range))) => {
1762+ (None, Some((_, _))) => {
1770 self.next_span = None;
1763 self.next_span = None;
1771 None
1764 None
1772 }
1765 }
@@ -1776,135 +1769,141 @@ impl<I: Iterator<Item = HighlightEvent>> Iterator for Merge<I> {
1776 }
1769 }
1777}
1770}
1778
1771
1779−#[test]
1772+#[cfg(test)]
1773+mod test {
1774+ use super::*;
1775+ use crate::{Rope, Transaction};
1776+
1777+ #[test]
1780−fn test_parser() {
1778+ fn test_parser() {
1781− let highlight_names: Vec<String> = [
1779+ let highlight_names: Vec<String> = [
1782− "attribute",
1780+ "attribute",
1783− "constant",
1781+ "constant",
1784− "function.builtin",
1782+ "function.builtin",
1785− "function",
1783+ "function",
1786− "keyword",
1784+ "keyword",
1787− "operator",
1785+ "operator",
1788− "property",
1786+ "property",
1789− "punctuation",
1787+ "punctuation",
1790− "punctuation.bracket",
1788+ "punctuation.bracket",
1791− "punctuation.delimiter",
1789+ "punctuation.delimiter",
1792− "string",
1790+ "string",
1793− "string.special",
1791+ "string.special",
1794− "tag",
1792+ "tag",
1795− "type",
1793+ "type",
1796− "type.builtin",
1794+ "type.builtin",
1797− "variable",
1795+ "variable",
1798− "variable.builtin",
1796+ "variable.builtin",
1799− "variable.parameter",
1797+ "variable.parameter",
1800− ]
1798+ ]
1801− .iter()
1799+ .iter()
1802− .cloned()
1800+ .cloned()
1803− .map(String::from)
1801+ .map(String::from)
1804− .collect();
1802+ .collect();
1805−
1803+
1806− let language = get_language(Lang::Rust);
1804+ let language = get_language(Lang::Rust);
1807− let mut config = HighlightConfiguration::new(
1805+ let config = HighlightConfiguration::new(
1808− language,
1806+ language,
1809− &std::fs::read_to_string(
1807+ &std::fs::read_to_string(
1810− "../helix-syntax/languages/tree-sitter-rust/queries/highlights.scm",
1808+ "../helix-syntax/languages/tree-sitter-rust/queries/highlights.scm",
1811− )
1809+ )
1812− .unwrap(),
1810+ .unwrap(),
1813− &std::fs::read_to_string(
1811+ &std::fs::read_to_string(
1814− "../helix-syntax/languages/tree-sitter-rust/queries/injections.scm",
1812+ "../helix-syntax/languages/tree-sitter-rust/queries/injections.scm",
1815− )
1813+ )
1816− .unwrap(),
1814+ .unwrap(),
1817− "", // locals.scm
1815+ "", // locals.scm
1818− )
1819− .unwrap();
1820− config.configure(&highlight_names);
1821−
1822− let source = Rope::from_str(
1823− "
1824− struct Stuff {}
1825− fn main() {}
1826− ",
1827− );
1828− let syntax = Syntax::new(&source, Arc::new(config));
1829− let tree = syntax.tree();
1830− let root = tree.root_node();
1831− assert_eq!(root.kind(), "source_file");
1832−
1833− assert_eq!(
1834− root.to_sexp(),
1835− concat!(
1836− "(source_file ",
1837− "(struct_item name: (type_identifier) body: (field_declaration_list)) ",
1838− "(function_item name: (identifier) parameters: (parameters) body: (block)))"
1839 )
1816 )
1817+ .unwrap();
1818+ config.configure(&highlight_names);
1819+
1820+ let source = Rope::from_str(
1821+ "
1822+ struct Stuff {}
1823+ fn main() {}
1824+ ",
1825+ );
1826+ let syntax = Syntax::new(&source, Arc::new(config));
1827+ let tree = syntax.tree();
1828+ let root = tree.root_node();
1829+ assert_eq!(root.kind(), "source_file");
1830+
1831+ assert_eq!(
1832+ root.to_sexp(),
1833+ concat!(
1834+ "(source_file ",
1835+ "(struct_item name: (type_identifier) body: (field_declaration_list)) ",
1836+ "(function_item name: (identifier) parameters: (parameters) body: (block)))"
1837+ )
1840− );
1838+ );
1841
1839
1842− let struct_node = root.child(0).unwrap();
1840+ let struct_node = root.child(0).unwrap();
1843− assert_eq!(struct_node.kind(), "struct_item");
1841+ assert_eq!(struct_node.kind(), "struct_item");
1844−}
1842+ }
1845
1843
1846−#[test]
1844+ #[test]
1847−fn test_input_edits() {
1845+ fn test_input_edits() {
1848− use crate::State;
1846+ use crate::State;
1849− use tree_sitter::InputEdit;
1847+ use tree_sitter::InputEdit;
1850−
1848+
1851− let mut state = State::new("hello world!\ntest 123".into());
1849+ let state = State::new("hello world!\ntest 123".into());
1852− let transaction = Transaction::change(
1850+ let transaction = Transaction::change(
1853− &state.doc,
1851+ &state.doc,
1854− vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
1852+ vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
1855− );
1853+ );
1856− let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
1854+ let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
1857− // transaction.apply(&mut state);
1855+ // transaction.apply(&mut state);
1858−
1856+
1859− assert_eq!(
1857+ assert_eq!(
1860− edits,
1858+ edits,
1861− &[
1859+ &[
1862− InputEdit {
1860+ InputEdit {
1863− start_byte: 6,
1861+ start_byte: 6,
1864− old_end_byte: 11,
1862+ old_end_byte: 11,
1865− new_end_byte: 10,
1863+ new_end_byte: 10,
1866− start_position: Point { row: 0, column: 6 },
1864+ start_position: Point { row: 0, column: 6 },
1867− old_end_position: Point { row: 0, column: 11 },
1865+ old_end_position: Point { row: 0, column: 11 },
1868− new_end_position: Point { row: 0, column: 10 }
1866+ new_end_position: Point { row: 0, column: 10 }
1869− },
1867+ },
1870− InputEdit {
1868+ InputEdit {
1871− start_byte: 12,
1869+ start_byte: 12,
1872− old_end_byte: 17,
1870+ old_end_byte: 17,
1873− new_end_byte: 12,
1871+ new_end_byte: 12,
1874− start_position: Point { row: 0, column: 12 },
1872+ start_position: Point { row: 0, column: 12 },
1875− old_end_position: Point { row: 1, column: 4 },
1873+ old_end_position: Point { row: 1, column: 4 },
1876− new_end_position: Point { row: 0, column: 12 }
1874+ new_end_position: Point { row: 0, column: 12 }
1877− }
1875+ }
1878− ]
1876+ ]
1879− );
1877+ );
1880−
1878+
1881− // Testing with the official example from tree-sitter
1879+ // Testing with the official example from tree-sitter
1882− let mut state = State::new("fn test() {}".into());
1880+ let mut state = State::new("fn test() {}".into());
1883− let transaction =
1881+ let transaction =
1884− Transaction::change(&state.doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
1882+ Transaction::change(&state.doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
1885− let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
1883+ let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
1886− transaction.apply(&mut state.doc);
1884+ transaction.apply(&mut state.doc);
1887−
1885+
1888− assert_eq!(state.doc, "fn test(a: u32) {}");
1886+ assert_eq!(state.doc, "fn test(a: u32) {}");
1889− assert_eq!(
1887+ assert_eq!(
1890− edits,
1888+ edits,
1891− &[InputEdit {
1889+ &[InputEdit {
1892− start_byte: 8,
1890+ start_byte: 8,
1893− old_end_byte: 8,
1891+ old_end_byte: 8,
1894− new_end_byte: 14,
1892+ new_end_byte: 14,
1895− start_position: Point { row: 0, column: 8 },
1893+ start_position: Point { row: 0, column: 8 },
1896− old_end_position: Point { row: 0, column: 8 },
1894+ old_end_position: Point { row: 0, column: 8 },
1897− new_end_position: Point { row: 0, column: 14 }
1895+ new_end_position: Point { row: 0, column: 14 }
1898− }]
1896+ }]
1899− );
1897+ );
1900−}
1898+ }
1901
1899
1902−#[test]
1900+ #[test]
1903−fn test_load_runtime_file() {
1901+ fn test_load_runtime_file() {
1904− // Test to make sure we can load some data from the runtime directory.
1902+ // Test to make sure we can load some data from the runtime directory.
1905− let contents = load_runtime_file("rust", "indents.toml").unwrap();
1903+ let contents = load_runtime_file("rust", "indents.toml").unwrap();
1906− assert!(!contents.is_empty());
1904+ assert!(!contents.is_empty());
1907
1905
1908− let results = load_runtime_file("rust", "does-not-exist");
1906+ let results = load_runtime_file("rust", "does-not-exist");
1909− assert!(results.is_err());
1907+ assert!(results.is_err());
1908+ }
1910}
1909}
helix-core/src/transaction.rs+9−9
@@ -1,5 +1,5 @@
1−use crate::{Range, Rope, Selection, State, Tendril};
1+use crate::{Range, Rope, Selection, Tendril};
2−use std::{borrow::Cow, convert::TryFrom};
2+use std::borrow::Cow;
3
3
4/// (from, to, replacement)
4/// (from, to, replacement)
5pub type Change = (usize, usize, Option<Tendril>);
5pub type Change = (usize, usize, Option<Tendril>);
@@ -163,7 +163,7 @@ impl ChangeSet {
163 head_a = a;
163 head_a = a;
164 head_b = changes_b.next();
164 head_b = changes_b.next();
165 }
165 }
166− (None, val) | (val, None) => return unreachable!("({:?})", val),
166+ (None, val) | (val, None) => unreachable!("({:?})", val),
167 (Some(Retain(i)), Some(Retain(j))) => match i.cmp(&j) {
167 (Some(Retain(i)), Some(Retain(j))) => match i.cmp(&j) {
168 Ordering::Less => {
168 Ordering::Less => {
169 changes.retain(i);
169 changes.retain(i);
@@ -202,7 +202,7 @@ impl ChangeSet {
202 }
202 }
203 }
203 }
204 }
204 }
205− (Some(Insert(mut s)), Some(Retain(j))) => {
205+ (Some(Insert(s)), Some(Retain(j))) => {
206 let len = s.chars().count();
206 let len = s.chars().count();
207 match len.cmp(&j) {
207 match len.cmp(&j) {
208 Ordering::Less => {
208 Ordering::Less => {
@@ -274,7 +274,6 @@ impl ChangeSet {
274 let mut changes = Self::with_capacity(self.changes.len());
274 let mut changes = Self::with_capacity(self.changes.len());
275
275
276 let mut pos = 0;
276 let mut pos = 0;
277− let mut len = 0;
278
277
279 for change in &self.changes {
278 for change in &self.changes {
280 use Operation::*;
279 use Operation::*;
@@ -581,6 +580,7 @@ impl<'a> Iterator for ChangeIterator<'a> {
581#[cfg(test)]
580#[cfg(test)]
582mod test {
581mod test {
583 use super::*;
582 use super::*;
583+ use crate::State;
584
584
585 #[test]
585 #[test]
586 fn composition() {
586 fn composition() {
@@ -699,7 +699,7 @@ mod test {
699
699
700 #[test]
700 #[test]
701 fn changes_iter() {
701 fn changes_iter() {
702− let mut state = State::new("hello world!\ntest 123".into());
702+ let state = State::new("hello world!\ntest 123".into());
703 let changes = vec![(6, 11, Some("void".into())), (12, 17, None)];
703 let changes = vec![(6, 11, Some("void".into())), (12, 17, None)];
704 let transaction = Transaction::change(&state.doc, changes.clone().into_iter());
704 let transaction = Transaction::change(&state.doc, changes.clone().into_iter());
705 assert_eq!(transaction.changes_iter().collect::<Vec<_>>(), changes);
705 assert_eq!(transaction.changes_iter().collect::<Vec<_>>(), changes);
@@ -731,7 +731,7 @@ mod test {
731 // retain 1, e
731 // retain 1, e
732 // retain 2, l
732 // retain 2, l
733
733
734− let mut changes = t1
734+ let changes = t1
735 .changes
735 .changes
736 .compose(t2.changes)
736 .compose(t2.changes)
737 .compose(t3.changes)
737 .compose(t3.changes)
@@ -746,7 +746,7 @@ mod test {
746 #[test]
746 #[test]
747 fn combine_with_empty() {
747 fn combine_with_empty() {
748 let empty = Rope::from("");
748 let empty = Rope::from("");
749− let mut a = ChangeSet::new(&empty);
749+ let a = ChangeSet::new(&empty);
750
750
751 let mut b = ChangeSet::new(&empty);
751 let mut b = ChangeSet::new(&empty);
752 b.insert("a".into());
752 b.insert("a".into());
@@ -762,7 +762,7 @@ mod test {
762 const TEST_CASE: &'static str = "Hello, これはヘリックスエディターです!";
762 const TEST_CASE: &'static str = "Hello, これはヘリックスエディターです!";
763
763
764 let empty = Rope::from("");
764 let empty = Rope::from("");
765− let mut a = ChangeSet::new(&empty);
765+ let a = ChangeSet::new(&empty);
766
766
767 let mut b = ChangeSet::new(&empty);
767 let mut b = ChangeSet::new(&empty);
768 b.insert(TEST_CASE.into());
768 b.insert(TEST_CASE.into());
helix-term/src/application.rs+26−35
@@ -1,37 +1,23 @@
1use helix_core::syntax;
1use helix_core::syntax;
2−use helix_lsp::{lsp, LspProgressMap};
2+use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
3−use helix_view::{document::Mode, graphics::Rect, theme, Document, Editor, Theme, View};
3+use helix_view::{theme, Editor};
4−
4+
5−use crate::{
6− args::Args,
7− compositor::Compositor,
5+use crate::{args::Args, compositor::Compositor, config::Config, job::Jobs, ui};
8− config::Config,
9− job::Jobs,
10− keymap::Keymaps,
11− ui::{self, Spinner},
12−};
13
6
14−use log::{error, info};
7+use log::error;
15
8
16use std::{
9use std::{
17− collections::HashMap,
18− future::Future,
19− io::{self, stdout, Stdout, Write},
10+ io::{stdout, Write},
20− path::PathBuf,
21− pin::Pin,
22 sync::Arc,
11 sync::Arc,
23− time::Duration,
24};
12};
25
13
26−use anyhow::{Context, Error};
14+use anyhow::Error;
27
15
28use crossterm::{
16use crossterm::{
29 event::{Event, EventStream},
17 event::{Event, EventStream},
30 execute, terminal,
18 execute, terminal,
31};
19};
32
20
33−use futures_util::{future, stream::FuturesUnordered};
34−
35pub struct Application {
21pub struct Application {
36 compositor: Compositor,
22 compositor: Compositor,
37 editor: Editor,
23 editor: Editor,
@@ -39,7 +25,14 @@ pub struct Application {
39 // TODO should be separate to take only part of the config
25 // TODO should be separate to take only part of the config
40 config: Config,
26 config: Config,
41
27
28+ // Currently never read from. Remove the `allow(dead_code)` when
29+ // that changes.
30+ #[allow(dead_code)]
42 theme_loader: Arc<theme::Loader>,
31 theme_loader: Arc<theme::Loader>,
32+
33+ // Currently never read from. Remove the `allow(dead_code)` when
34+ // that changes.
35+ #[allow(dead_code)]
43 syn_loader: Arc<syntax::Loader>,
36 syn_loader: Arc<syntax::Loader>,
44
37
45 jobs: Jobs,
38 jobs: Jobs,
@@ -47,7 +40,7 @@ pub struct Application {
47}
40}
48
41
49impl Application {
42impl Application {
50− pub fn new(mut args: Args, mut config: Config) -> Result<Self, Error> {
43+ pub fn new(args: Args, mut config: Config) -> Result<Self, Error> {
51 use helix_view::editor::Action;
44 use helix_view::editor::Action;
52 let mut compositor = Compositor::new()?;
45 let mut compositor = Compositor::new()?;
53 let size = compositor.size();
46 let size = compositor.size();
@@ -80,7 +73,7 @@ impl Application {
80
73
81 let mut editor = Editor::new(size, theme_loader.clone(), syn_loader.clone());
74 let mut editor = Editor::new(size, theme_loader.clone(), syn_loader.clone());
82
75
83− let mut editor_view = Box::new(ui::EditorView::new(std::mem::take(&mut config.keys)));
76+ let editor_view = Box::new(ui::EditorView::new(std::mem::take(&mut config.keys)));
84 compositor.push(editor_view);
77 compositor.push(editor_view);
85
78
86 if !args.files.is_empty() {
79 if !args.files.is_empty() {
@@ -105,7 +98,7 @@ impl Application {
105
98
106 editor.set_theme(theme);
99 editor.set_theme(theme);
107
100
108− let mut app = Self {
101+ let app = Self {
109 compositor,
102 compositor,
110 editor,
103 editor,
111
104
@@ -239,10 +232,9 @@ impl Application {
239 .into_iter()
232 .into_iter()
240 .filter_map(|diagnostic| {
233 .filter_map(|diagnostic| {
241 use helix_core::{
234 use helix_core::{
242− diagnostic::{Range, Severity, Severity::*},
235+ diagnostic::{Range, Severity::*},
243 Diagnostic,
236 Diagnostic,
244 };
237 };
245− use helix_lsp::{lsp, util::lsp_pos_to_pos};
246 use lsp::DiagnosticSeverity;
238 use lsp::DiagnosticSeverity;
247
239
248 let language_server = doc.language_server().unwrap();
240 let language_server = doc.language_server().unwrap();
@@ -372,14 +364,10 @@ impl Application {
372 self.editor.set_status(status);
364 self.editor.set_status(status);
373 }
365 }
374 }
366 }
375− _ => unreachable!(),
376 }
367 }
377 }
368 }
378 Call::MethodCall(helix_lsp::jsonrpc::MethodCall {
369 Call::MethodCall(helix_lsp::jsonrpc::MethodCall {
379− method,
370+ method, params, id, ..
380− params,
381− jsonrpc,
382− id,
383 }) => {
371 }) => {
384 let call = match MethodCall::parse(&method, params) {
372 let call = match MethodCall::parse(&method, params) {
385 Some(call) => call,
373 Some(call) => call,
@@ -459,17 +447,20 @@ impl Application {
459 // Exit the alternate screen and disable raw mode before panicking
447 // Exit the alternate screen and disable raw mode before panicking
460 let hook = std::panic::take_hook();
448 let hook = std::panic::take_hook();
461 std::panic::set_hook(Box::new(move |info| {
449 std::panic::set_hook(Box::new(move |info| {
450+ // We can't handle errors properly inside this closure. And it's
451+ // probably not a good idea to `unwrap()` inside a panic handler.
452+ // So we just ignore the `Result`s.
462− execute!(std::io::stdout(), terminal::LeaveAlternateScreen);
453+ let _ = execute!(std::io::stdout(), terminal::LeaveAlternateScreen);
463− terminal::disable_raw_mode();
454+ let _ = terminal::disable_raw_mode();
464 hook(info);
455 hook(info);
465 }));
456 }));
466
457
467 self.event_loop().await;
458 self.event_loop().await;
468
459
469− self.editor.close_language_servers(None).await;
460+ self.editor.close_language_servers(None).await?;
470
461
471 // reset cursor shape
462 // reset cursor shape
472− write!(stdout, "\x1B[2 q");
463+ write!(stdout, "\x1B[2 q")?;
473
464
474 execute!(stdout, terminal::LeaveAlternateScreen)?;
465 execute!(stdout, terminal::LeaveAlternateScreen)?;
475
466
helix-term/src/commands.rs+70−81
@@ -1,20 +1,21 @@
1use helix_core::{
1use helix_core::{
2 comment, coords_at_pos, find_first_non_whitespace_char, find_root, graphemes, indent,
2 comment, coords_at_pos, find_first_non_whitespace_char, find_root, graphemes, indent,
3 line_ending::{
3 line_ending::{
4− get_line_ending, get_line_ending_of_str, line_end_char_index, rope_end_without_line_ending,
4+ get_line_ending_of_str, line_end_char_index, rope_end_without_line_ending,
5 str_is_line_ending,
5 str_is_line_ending,
6 },
6 },
7 match_brackets,
7 match_brackets,
8 movement::{self, Direction},
8 movement::{self, Direction},
9 object, pos_at_coords,
9 object, pos_at_coords,
10 regex::{self, Regex},
10 regex::{self, Regex},
11− register::{self, Register, Registers},
11+ register::Register,
12− search, selection, Change, ChangeSet, LineEnding, Position, Range, Rope, RopeGraphemes,
12+ search, selection, LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, Selection,
13− RopeSlice, Selection, SmallVec, Tendril, Transaction, DEFAULT_LINE_ENDING,
13+ SmallVec, Tendril, Transaction,
14};
14};
15
15
16use helix_view::{
16use helix_view::{
17 document::{IndentStyle, Mode},
17 document::{IndentStyle, Mode},
18+ editor::Action,
18 input::KeyEvent,
19 input::KeyEvent,
19 keyboard::KeyCode,
20 keyboard::KeyCode,
20 view::{View, PADDING},
21 view::{View, PADDING},
@@ -25,19 +26,19 @@ use anyhow::anyhow;
25use helix_lsp::{
26use helix_lsp::{
26 lsp,
27 lsp,
27 util::{lsp_pos_to_pos, lsp_range_to_range, pos_to_lsp_pos, range_to_lsp_range},
28 util::{lsp_pos_to_pos, lsp_range_to_range, pos_to_lsp_pos, range_to_lsp_range},
28− LspProgressMap, OffsetEncoding,
29+ OffsetEncoding,
29};
30};
30use insert::*;
31use insert::*;
31use movement::Movement;
32use movement::Movement;
32
33
33use crate::{
34use crate::{
34− compositor::{self, Callback, Component, Compositor},
35+ compositor::{self, Component, Compositor},
35− ui::{self, Completion, Picker, Popup, Prompt, PromptEvent},
36+ ui::{self, Picker, Popup, Prompt, PromptEvent},
36};
37};
37
38
38−use crate::job::{self, Job, JobFuture, Jobs};
39+use crate::job::{self, Job, Jobs};
39use futures_util::{FutureExt, TryFutureExt};
40use futures_util::{FutureExt, TryFutureExt};
40−use std::{fmt, future::Future, path::Display, str::FromStr};
41+use std::{fmt, future::Future};
41
42
42use std::{
43use std::{
43 borrow::Cow,
44 borrow::Cow,
@@ -59,7 +60,7 @@ pub struct Context<'a> {
59
60
60impl<'a> Context<'a> {
61impl<'a> Context<'a> {
61 /// Push a new component onto the compositor.
62 /// Push a new component onto the compositor.
62− pub fn push_layer(&mut self, mut component: Box<dyn Component>) {
63+ pub fn push_layer(&mut self, component: Box<dyn Component>) {
63 self.callback = Some(Box::new(|compositor: &mut Compositor| {
64 self.callback = Some(Box::new(|compositor: &mut Compositor| {
64 compositor.push(component)
65 compositor.push(component)
65 }));
66 }));
@@ -515,7 +516,7 @@ fn extend_next_word_start(cx: &mut Context) {
515 let (view, doc) = current!(cx.editor);
516 let (view, doc) = current!(cx.editor);
516 doc.set_selection(
517 doc.set_selection(
517 view.id,
518 view.id,
518− doc.selection(view.id).clone().transform(|mut range| {
519+ doc.selection(view.id).clone().transform(|range| {
519 let word = movement::move_next_word_start(doc.text().slice(..), range, count);
520 let word = movement::move_next_word_start(doc.text().slice(..), range, count);
520 let pos = word.head;
521 let pos = word.head;
521 Range::new(range.anchor, pos)
522 Range::new(range.anchor, pos)
@@ -528,7 +529,7 @@ fn extend_prev_word_start(cx: &mut Context) {
528 let (view, doc) = current!(cx.editor);
529 let (view, doc) = current!(cx.editor);
529 doc.set_selection(
530 doc.set_selection(
530 view.id,
531 view.id,
531− doc.selection(view.id).clone().transform(|mut range| {
532+ doc.selection(view.id).clone().transform(|range| {
532 let word = movement::move_prev_word_start(doc.text().slice(..), range, count);
533 let word = movement::move_prev_word_start(doc.text().slice(..), range, count);
533 let pos = word.head;
534 let pos = word.head;
534 Range::new(range.anchor, pos)
535 Range::new(range.anchor, pos)
@@ -541,7 +542,7 @@ fn extend_next_word_end(cx: &mut Context) {
541 let (view, doc) = current!(cx.editor);
542 let (view, doc) = current!(cx.editor);
542 doc.set_selection(
543 doc.set_selection(
543 view.id,
544 view.id,
544− doc.selection(view.id).clone().transform(|mut range| {
545+ doc.selection(view.id).clone().transform(|range| {
545 let word = movement::move_next_word_end(doc.text().slice(..), range, count);
546 let word = movement::move_next_word_end(doc.text().slice(..), range, count);
546 let pos = word.head;
547 let pos = word.head;
547 Range::new(range.anchor, pos)
548 Range::new(range.anchor, pos)
@@ -592,7 +593,7 @@ where
592
593
593 doc.set_selection(
594 doc.set_selection(
594 view.id,
595 view.id,
595− doc.selection(view.id).clone().transform(|mut range| {
596+ doc.selection(view.id).clone().transform(|range| {
596 search_fn(doc.text().slice(..), ch, range.head, count, inclusive).map_or(
597 search_fn(doc.text().slice(..), ch, range.head, count, inclusive).map_or(
597 range,
598 range,
598 |pos| {
599 |pos| {
@@ -986,7 +987,7 @@ fn search_impl(doc: &mut Document, view: &mut View, contents: &str, regex: &Rege
986
987
987// TODO: use one function for search vs extend
988// TODO: use one function for search vs extend
988fn search(cx: &mut Context) {
989fn search(cx: &mut Context) {
989− let (view, doc) = current!(cx.editor);
990+ let (_, doc) = current!(cx.editor);
990
991
991 // TODO: could probably share with select_on_matches?
992 // TODO: could probably share with select_on_matches?
992
993
@@ -994,7 +995,6 @@ fn search(cx: &mut Context) {
994 // feed chunks into the regex yet
995 // feed chunks into the regex yet
995 let contents = doc.text().slice(..).to_string();
996 let contents = doc.text().slice(..).to_string();
996
997
997− let view_id = view.id;
998 let prompt = ui::regex_prompt(
998 let prompt = ui::regex_prompt(
999 cx,
999 cx,
1000 "search:".to_string(),
1000 "search:".to_string(),
@@ -1046,7 +1046,7 @@ fn extend_line(cx: &mut Context) {
1046 let line_start = text.char_to_line(pos.anchor);
1046 let line_start = text.char_to_line(pos.anchor);
1047 let start = text.line_to_char(line_start);
1047 let start = text.line_to_char(line_start);
1048 let line_end = text.char_to_line(pos.head);
1048 let line_end = text.char_to_line(pos.head);
1049− let mut end = line_end_char_index(&text.slice(..), line_end);
1049+ let mut end = line_end_char_index(&text.slice(..), line_end + count.saturating_sub(1));
1050
1050
1051 if pos.anchor == start && pos.head == end && line_end < (text.len_lines() - 2) {
1051 if pos.anchor == start && pos.head == end && line_end < (text.len_lines() - 2) {
1052 end = line_end_char_index(&text.slice(..), line_end + 1);
1052 end = line_end_char_index(&text.slice(..), line_end + 1);
@@ -1065,7 +1065,6 @@ fn delete_selection_impl(reg: &mut Register, doc: &mut Document, view_id: ViewId
1065
1065
1066 // then delete
1066 // then delete
1067 let transaction = Transaction::change_by_selection(doc.text(), &selection, |range| {
1067 let transaction = Transaction::change_by_selection(doc.text(), &selection, |range| {
1068− let line = text.char_to_line(range.head);
1069 (range.from(), range.to(), None)
1068 (range.from(), range.to(), None)
1070 });
1069 });
1071 doc.apply(&transaction, view_id);
1070 doc.apply(&transaction, view_id);
@@ -1175,7 +1174,7 @@ mod cmd {
1175 pub completer: Option<Completer>,
1174 pub completer: Option<Completer>,
1176 }
1175 }
1177
1176
1178− fn quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1177+ fn quit(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1179 // last view and we have unsaved changes
1178 // last view and we have unsaved changes
1180 if cx.editor.tree.views().count() == 1 && buffers_remaining_impl(cx.editor) {
1179 if cx.editor.tree.views().count() == 1 && buffers_remaining_impl(cx.editor) {
1181 return;
1180 return;
@@ -1184,16 +1183,16 @@ mod cmd {
1184 .close(view!(cx.editor).id, /* close_buffer */ false);
1183 .close(view!(cx.editor).id, /* close_buffer */ false);
1185 }
1184 }
1186
1185
1187− fn force_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1186+ fn force_quit(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1188 cx.editor
1187 cx.editor
1189 .close(view!(cx.editor).id, /* close_buffer */ false);
1188 .close(view!(cx.editor).id, /* close_buffer */ false);
1190 }
1189 }
1191
1190
1192− fn open(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1191+ fn open(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1193 match args.get(0) {
1192 match args.get(0) {
1194 Some(path) => {
1193 Some(path) => {
1195 // TODO: handle error
1194 // TODO: handle error
1196− cx.editor.open(path.into(), Action::Replace);
1195+ let _ = cx.editor.open(path.into(), Action::Replace);
1197 }
1196 }
1198 None => {
1197 None => {
1199 cx.editor.set_error("wrong argument count".to_string());
1198 cx.editor.set_error("wrong argument count".to_string());
@@ -1205,9 +1204,8 @@ mod cmd {
1205 cx: &mut compositor::Context,
1204 cx: &mut compositor::Context,
1206 path: Option<P>,
1205 path: Option<P>,
1207 ) -> Result<tokio::task::JoinHandle<Result<(), anyhow::Error>>, anyhow::Error> {
1206 ) -> Result<tokio::task::JoinHandle<Result<(), anyhow::Error>>, anyhow::Error> {
1208− use anyhow::anyhow;
1209 let jobs = &mut cx.jobs;
1207 let jobs = &mut cx.jobs;
1210− let (view, doc) = current!(cx.editor);
1208+ let (_, doc) = current!(cx.editor);
1211
1209
1212 if let Some(path) = path {
1210 if let Some(path) = path {
1213 if let Err(err) = doc.set_path(path.as_ref()) {
1211 if let Err(err) = doc.set_path(path.as_ref()) {
@@ -1231,7 +1229,7 @@ mod cmd {
1231 Ok(tokio::spawn(doc.format_and_save(fmt)))
1229 Ok(tokio::spawn(doc.format_and_save(fmt)))
1232 }
1230 }
1233
1231
1234− fn write(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1232+ fn write(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1235 match write_impl(cx, args.first()) {
1233 match write_impl(cx, args.first()) {
1236 Err(e) => cx.editor.set_error(e.to_string()),
1234 Err(e) => cx.editor.set_error(e.to_string()),
1237 Ok(handle) => {
1235 Ok(handle) => {
@@ -1241,11 +1239,11 @@ mod cmd {
1241 };
1239 };
1242 }
1240 }
1243
1241
1244− fn new_file(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1242+ fn new_file(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1245 cx.editor.new_file(Action::Replace);
1243 cx.editor.new_file(Action::Replace);
1246 }
1244 }
1247
1245
1248− fn format(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1246+ fn format(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1249 let (_, doc) = current!(cx.editor);
1247 let (_, doc) = current!(cx.editor);
1250
1248
1251 if let Some(format) = doc.format() {
1249 if let Some(format) = doc.format() {
@@ -1255,7 +1253,7 @@ mod cmd {
1255 }
1253 }
1256 }
1254 }
1257
1255
1258− fn set_indent_style(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1256+ fn set_indent_style(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1259 use IndentStyle::*;
1257 use IndentStyle::*;
1260
1258
1261 // If no argument, report current indent style.
1259 // If no argument, report current indent style.
@@ -1293,7 +1291,7 @@ mod cmd {
1293 }
1291 }
1294
1292
1295 /// Sets or reports the current document's line ending setting.
1293 /// Sets or reports the current document's line ending setting.
1296− fn set_line_ending(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1294+ fn set_line_ending(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1297 use LineEnding::*;
1295 use LineEnding::*;
1298
1296
1299 // If no argument, report current line ending setting.
1297 // If no argument, report current line ending setting.
@@ -1332,7 +1330,7 @@ mod cmd {
1332 }
1330 }
1333 }
1331 }
1334
1332
1335− fn earlier(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1333+ fn earlier(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1336 let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
1334 let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
1337 Ok(uk) => uk,
1335 Ok(uk) => uk,
1338 Err(msg) => {
1336 Err(msg) => {
@@ -1344,7 +1342,7 @@ mod cmd {
1344 doc.earlier(view.id, uk)
1342 doc.earlier(view.id, uk)
1345 }
1343 }
1346
1344
1347− fn later(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1345+ fn later(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1348 let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
1346 let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
1349 Ok(uk) => uk,
1347 Ok(uk) => uk,
1350 Err(msg) => {
1348 Err(msg) => {
@@ -1372,7 +1370,6 @@ mod cmd {
1372 }
1370 }
1373
1371
1374 fn force_write_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1372 fn force_write_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1375− let (view, doc) = current!(cx.editor);
1376 match write_impl(cx, args.first()) {
1373 match write_impl(cx, args.first()) {
1377 Ok(handle) => {
1374 Ok(handle) => {
1378 if let Err(e) = helix_lsp::block_on(handle) {
1375 if let Err(e) = helix_lsp::block_on(handle) {
@@ -1414,20 +1411,22 @@ mod cmd {
1414
1411
1415 fn write_all_impl(
1412 fn write_all_impl(
1416 editor: &mut Editor,
1413 editor: &mut Editor,
1417− args: &[&str],
1414+ _args: &[&str],
1418− event: PromptEvent,
1415+ _event: PromptEvent,
1419 quit: bool,
1416 quit: bool,
1420 force: bool,
1417 force: bool,
1421 ) {
1418 ) {
1422 let mut errors = String::new();
1419 let mut errors = String::new();
1423
1420
1424 // save all documents
1421 // save all documents
1425− for (id, mut doc) in &mut editor.documents {
1422+ for (_, doc) in &mut editor.documents {
1426 if doc.path().is_none() {
1423 if doc.path().is_none() {
1427 errors.push_str("cannot write a buffer without a filename\n");
1424 errors.push_str("cannot write a buffer without a filename\n");
1428 continue;
1425 continue;
1429 }
1426 }
1427+
1428+ // TODO: handle error.
1430− helix_lsp::block_on(tokio::spawn(doc.save()));
1429+ let _ = helix_lsp::block_on(tokio::spawn(doc.save()));
1431 }
1430 }
1432 editor.set_error(errors);
1431 editor.set_error(errors);
1433
1432
@@ -1456,7 +1455,7 @@ mod cmd {
1456 write_all_impl(&mut cx.editor, args, event, true, true)
1455 write_all_impl(&mut cx.editor, args, event, true, true)
1457 }
1456 }
1458
1457
1459− fn quit_all_impl(editor: &mut Editor, args: &[&str], event: PromptEvent, force: bool) {
1458+ fn quit_all_impl(editor: &mut Editor, _args: &[&str], _event: PromptEvent, force: bool) {
1460 if !force && buffers_remaining_impl(editor) {
1459 if !force && buffers_remaining_impl(editor) {
1461 return;
1460 return;
1462 }
1461 }
@@ -1476,7 +1475,7 @@ mod cmd {
1476 quit_all_impl(&mut cx.editor, args, event, true)
1475 quit_all_impl(&mut cx.editor, args, event, true)
1477 }
1476 }
1478
1477
1479− fn theme(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1478+ fn theme(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1480 let theme = if let Some(theme) = args.first() {
1479 let theme = if let Some(theme) = args.first() {
1481 theme
1480 theme
1482 } else {
1481 } else {
@@ -1487,11 +1486,15 @@ mod cmd {
1487 cx.editor.set_theme_from_name(theme);
1486 cx.editor.set_theme_from_name(theme);
1488 }
1487 }
1489
1488
1490− fn yank_main_selection_to_clipboard(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
1489+ fn yank_main_selection_to_clipboard(
1490+ cx: &mut compositor::Context,
1491+ _args: &[&str],
1492+ _event: PromptEvent,
1493+ ) {
1491 yank_main_selection_to_clipboard_impl(&mut cx.editor);
1494 yank_main_selection_to_clipboard_impl(&mut cx.editor);
1492 }
1495 }
1493
1496
1494− fn yank_joined_to_clipboard(cx: &mut compositor::Context, args: &[&str], _: PromptEvent) {
1497+ fn yank_joined_to_clipboard(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1495 let (_, doc) = current!(cx.editor);
1498 let (_, doc) = current!(cx.editor);
1496 let separator = args
1499 let separator = args
1497 .first()
1500 .first()
@@ -1500,15 +1503,19 @@ mod cmd {
1500 yank_joined_to_clipboard_impl(&mut cx.editor, separator);
1503 yank_joined_to_clipboard_impl(&mut cx.editor, separator);
1501 }
1504 }
1502
1505
1503− fn paste_clipboard_after(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
1506+ fn paste_clipboard_after(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1504 paste_clipboard_impl(&mut cx.editor, Paste::After);
1507 paste_clipboard_impl(&mut cx.editor, Paste::After);
1505 }
1508 }
1506
1509
1507− fn paste_clipboard_before(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
1510+ fn paste_clipboard_before(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1508 paste_clipboard_impl(&mut cx.editor, Paste::After);
1511 paste_clipboard_impl(&mut cx.editor, Paste::After);
1509 }
1512 }
1510
1513
1511− fn replace_selections_with_clipboard(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
1514+ fn replace_selections_with_clipboard(
1515+ cx: &mut compositor::Context,
1516+ _args: &[&str],
1517+ _event: PromptEvent,
1518+ ) {
1512 let (view, doc) = current!(cx.editor);
1519 let (view, doc) = current!(cx.editor);
1513
1520
1514 match cx.editor.clipboard_provider.get_contents() {
1521 match cx.editor.clipboard_provider.get_contents() {
@@ -1529,12 +1536,12 @@ mod cmd {
1529 }
1536 }
1530 }
1537 }
1531
1538
1532− fn show_clipboard_provider(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
1539+ fn show_clipboard_provider(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1533 cx.editor
1540 cx.editor
1534 .set_status(cx.editor.clipboard_provider.name().into());
1541 .set_status(cx.editor.clipboard_provider.name().into());
1535 }
1542 }
1536
1543
1537− fn change_current_directory(cx: &mut compositor::Context, args: &[&str], _: PromptEvent) {
1544+ fn change_current_directory(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
1538 let dir = match args.first() {
1545 let dir = match args.first() {
1539 Some(dir) => dir,
1546 Some(dir) => dir,
1540 None => {
1547 None => {
@@ -1562,7 +1569,7 @@ mod cmd {
1562 }
1569 }
1563 }
1570 }
1564
1571
1565− fn show_current_directory(cx: &mut compositor::Context, args: &[&str], _: PromptEvent) {
1572+ fn show_current_directory(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
1566 match std::env::current_dir() {
1573 match std::env::current_dir() {
1567 Ok(cwd) => cx
1574 Ok(cwd) => cx
1568 .editor
1575 .editor
@@ -1782,7 +1789,6 @@ fn command_mode(cx: &mut Context) {
1782 // simple heuristic: if there's no just one part, complete command name.
1789 // simple heuristic: if there's no just one part, complete command name.
1783 // if there's a space, per command completion kicks in.
1790 // if there's a space, per command completion kicks in.
1784 if parts.len() <= 1 {
1791 if parts.len() <= 1 {
1785− use std::{borrow::Cow, ops::Range};
1786 let end = 0..;
1792 let end = 0..;
1787 cmd::TYPABLE_COMMAND_LIST
1793 cmd::TYPABLE_COMMAND_LIST
1788 .iter()
1794 .iter()
@@ -1812,8 +1818,6 @@ fn command_mode(cx: &mut Context) {
1812 }
1818 }
1813 }, // completion
1819 }, // completion
1814 move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
1820 move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
1815− use helix_view::editor::Action;
1816−
1817 if event != PromptEvent::Validate {
1821 if event != PromptEvent::Validate {
1818 return;
1822 return;
1819 }
1823 }
@@ -1851,7 +1855,6 @@ fn file_picker(cx: &mut Context) {
1851}
1855}
1852
1856
1853fn buffer_picker(cx: &mut Context) {
1857fn buffer_picker(cx: &mut Context) {
1854− use std::path::{Path, PathBuf};
1855 let current = view!(cx.editor).doc;
1858 let current = view!(cx.editor).doc;
1856
1859
1857 let picker = Picker::new(
1860 let picker = Picker::new(
@@ -1874,7 +1877,6 @@ fn buffer_picker(cx: &mut Context) {
1874 }
1877 }
1875 },
1878 },
1876 |editor: &mut Editor, (id, _path): &(DocumentId, Option<PathBuf>), _action| {
1879 |editor: &mut Editor, (id, _path): &(DocumentId, Option<PathBuf>), _action| {
1877− use helix_view::editor::Action;
1878 editor.switch(*id, Action::Replace);
1880 editor.switch(*id, Action::Replace);
1879 },
1881 },
1880 );
1882 );
@@ -1900,7 +1902,7 @@ fn symbol_picker(cx: &mut Context) {
1900 nested_to_flat(list, file, child);
1902 nested_to_flat(list, file, child);
1901 }
1903 }
1902 }
1904 }
1903− let (view, doc) = current!(cx.editor);
1905+ let (_, doc) = current!(cx.editor);
1904
1906
1905 let language_server = match doc.language_server() {
1907 let language_server = match doc.language_server() {
1906 Some(language_server) => language_server,
1908 Some(language_server) => language_server,
@@ -1993,7 +1995,7 @@ async fn make_format_callback(
1993 format: impl Future<Output = helix_lsp::util::LspFormatting> + Send + 'static,
1995 format: impl Future<Output = helix_lsp::util::LspFormatting> + Send + 'static,
1994) -> anyhow::Result<job::Callback> {
1996) -> anyhow::Result<job::Callback> {
1995 let format = format.await;
1997 let format = format.await;
1996− let call: job::Callback = Box::new(move |editor: &mut Editor, compositor: &mut Compositor| {
1998+ let call: job::Callback = Box::new(move |editor: &mut Editor, _compositor: &mut Compositor| {
1997 let view_id = view!(editor).id;
1999 let view_id = view!(editor).id;
1998 if let Some(doc) = editor.document_mut(doc_id) {
2000 if let Some(doc) = editor.document_mut(doc_id) {
1999 if doc.version() == doc_version {
2001 if doc.version() == doc_version {
@@ -2168,9 +2170,6 @@ fn goto_mode(cx: &mut Context) {
2168 (_, 't') | (_, 'm') | (_, 'b') => {
2170 (_, 't') | (_, 'm') | (_, 'b') => {
2169 let (view, doc) = current!(cx.editor);
2171 let (view, doc) = current!(cx.editor);
2170
2172
2171− let pos = doc.selection(view.id).cursor();
2172− let line = doc.text().char_to_line(pos);
2173−
2174 let scrolloff = PADDING.min(view.area.height as usize / 2); // TODO: user pref
2173 let scrolloff = PADDING.min(view.area.height as usize / 2); // TODO: user pref
2175
2174
2176 let last_line = view.last_line(doc);
2175 let last_line = view.last_line(doc);
@@ -2207,8 +2206,6 @@ fn goto_impl(
2207 locations: Vec<lsp::Location>,
2206 locations: Vec<lsp::Location>,
2208 offset_encoding: OffsetEncoding,
2207 offset_encoding: OffsetEncoding,
2209) {
2208) {
2210− use helix_view::editor::Action;
2211−
2212 push_jump(editor);
2209 push_jump(editor);
2213
2210
2214 fn jump_to(
2211 fn jump_to(
@@ -2221,7 +2218,7 @@ fn goto_impl(
2221 .uri
2218 .uri
2222 .to_file_path()
2219 .to_file_path()
2223 .expect("unable to convert URI to filepath");
2220 .expect("unable to convert URI to filepath");
2224− let id = editor.open(path, action).expect("editor.open failed");
2221+ let _id = editor.open(path, action).expect("editor.open failed");
2225 let (view, doc) = current!(editor);
2222 let (view, doc) = current!(editor);
2226 let definition_pos = location.range.start;
2223 let definition_pos = location.range.start;
2227 // TODO: convert inside server
2224 // TODO: convert inside server
@@ -2243,7 +2240,7 @@ fn goto_impl(
2243 editor.set_error("No definition found.".to_string());
2240 editor.set_error("No definition found.".to_string());
2244 }
2241 }
2245 _locations => {
2242 _locations => {
2246− let mut picker = ui::Picker::new(
2243+ let picker = ui::Picker::new(
2247 locations,
2244 locations,
2248 |location| {
2245 |location| {
2249 let file = location.uri.as_str();
2246 let file = location.uri.as_str();
@@ -2410,9 +2407,8 @@ fn goto_pos(editor: &mut Editor, pos: usize) {
2410
2407
2411fn goto_first_diag(cx: &mut Context) {
2408fn goto_first_diag(cx: &mut Context) {
2412 let editor = &mut cx.editor;
2409 let editor = &mut cx.editor;
2413− let (view, doc) = current!(editor);
2410+ let (_, doc) = current!(editor);
2414
2411
2415− let cursor_pos = doc.selection(view.id).cursor();
2416 let diag = if let Some(diag) = doc.diagnostics().first() {
2412 let diag = if let Some(diag) = doc.diagnostics().first() {
2417 diag.range.start
2413 diag.range.start
2418 } else {
2414 } else {
@@ -2424,9 +2420,8 @@ fn goto_first_diag(cx: &mut Context) {
2424
2420
2425fn goto_last_diag(cx: &mut Context) {
2421fn goto_last_diag(cx: &mut Context) {
2426 let editor = &mut cx.editor;
2422 let editor = &mut cx.editor;
2427− let (view, doc) = current!(editor);
2423+ let (_, doc) = current!(editor);
2428
2424
2429− let cursor_pos = doc.selection(view.id).cursor();
2430 let diag = if let Some(diag) = doc.diagnostics().last() {
2425 let diag = if let Some(diag) = doc.diagnostics().last() {
2431 diag.range.start
2426 diag.range.start
2432 } else {
2427 } else {
@@ -2498,8 +2493,8 @@ fn signature_help(cx: &mut Context) {
2498
2493
2499 cx.callback(
2494 cx.callback(
2500 future,
2495 future,
2501− move |editor: &mut Editor,
2496+ move |_editor: &mut Editor,
2502− compositor: &mut Compositor,
2497+ _compositor: &mut Compositor,
2503 response: Option<lsp::SignatureHelp>| {
2498 response: Option<lsp::SignatureHelp>| {
2504 if let Some(signature_help) = response {
2499 if let Some(signature_help) = response {
2505 log::info!("{:?}", signature_help);
2500 log::info!("{:?}", signature_help);
@@ -3080,8 +3075,10 @@ fn format_selections(cx: &mut Context) {
3080 .map(|range| range_to_lsp_range(doc.text(), *range, language_server.offset_encoding()))
3075 .map(|range| range_to_lsp_range(doc.text(), *range, language_server.offset_encoding()))
3081 .collect();
3076 .collect();
3082
3077
3078+ // TODO: all of the TODO's and commented code inside the loop,
3079+ // to make this actually work.
3083− for range in ranges {
3080+ for _range in ranges {
3084− let language_server = match doc.language_server() {
3081+ let _language_server = match doc.language_server() {
3085 Some(language_server) => language_server,
3082 Some(language_server) => language_server,
3086 None => return,
3083 None => return,
3087 };
3084 };
@@ -3129,7 +3126,7 @@ fn join_selections(cx: &mut Context) {
3129 changes.reserve(lines.len());
3126 changes.reserve(lines.len());
3130
3127
3131 for line in lines {
3128 for line in lines {
3132− let mut start = line_end_char_index(&slice, line);
3129+ let start = line_end_char_index(&slice, line);
3133 let mut end = text.line_to_char(line + 1);
3130 let mut end = text.line_to_char(line + 1);
3134 end = skip_while(slice, end, |ch| matches!(ch, ' ' | '\t')).unwrap_or(end);
3131 end = skip_while(slice, end, |ch| matches!(ch, ' ' | '\t')).unwrap_or(end);
3135
3132
@@ -3252,7 +3249,6 @@ fn completion(cx: &mut Context) {
3252 if items.is_empty() {
3249 if items.is_empty() {
3253 return;
3250 return;
3254 }
3251 }
3255− use crate::compositor::AnyComponent;
3256 let size = compositor.size();
3252 let size = compositor.size();
3257 let ui = compositor
3253 let ui = compositor
3258 .find(std::any::type_name::<ui::EditorView>())
3254 .find(std::any::type_name::<ui::EditorView>())
@@ -3306,7 +3302,7 @@ fn hover(cx: &mut Context) {
3306 // skip if contents empty
3302 // skip if contents empty
3307
3303
3308 let contents = ui::Markdown::new(contents, editor.syn_loader.clone());
3304 let contents = ui::Markdown::new(contents, editor.syn_loader.clone());
3309− let mut popup = Popup::new(contents);
3305+ let popup = Popup::new(contents);
3310 compositor.push(Box::new(popup));
3306 compositor.push(Box::new(popup));
3311 }
3307 }
3312 },
3308 },
@@ -3350,7 +3346,7 @@ fn match_brackets(cx: &mut Context) {
3350
3346
3351fn jump_forward(cx: &mut Context) {
3347fn jump_forward(cx: &mut Context) {
3352 let count = cx.count();
3348 let count = cx.count();
3353− let (view, doc) = current!(cx.editor);
3349+ let (view, _doc) = current!(cx.editor);
3354
3350
3355 if let Some((id, selection)) = view.jumps.forward(count) {
3351 if let Some((id, selection)) = view.jumps.forward(count) {
3356 view.doc = *id;
3352 view.doc = *id;
@@ -3403,11 +3399,7 @@ fn rotate_view(cx: &mut Context) {
3403}
3399}
3404
3400
3405// split helper, clear it later
3401// split helper, clear it later
3406−use helix_view::editor::Action;
3407−
3408−use self::cmd::TypableCommand;
3409fn split(cx: &mut Context, action: Action) {
3402fn split(cx: &mut Context, action: Action) {
3410− use helix_view::editor::Action;
3411 let (view, doc) = current!(cx.editor);
3403 let (view, doc) = current!(cx.editor);
3412 let id = doc.id();
3404 let id = doc.id();
3413 let selection = doc.selection(view.id).clone();
3405 let selection = doc.selection(view.id).clone();
@@ -3563,10 +3555,7 @@ fn match_mode(cx: &mut Context) {
3563 'm' => match_brackets(cx),
3555 'm' => match_brackets(cx),
3564 's' => surround_add(cx),
3556 's' => surround_add(cx),
3565 'r' => surround_replace(cx),
3557 'r' => surround_replace(cx),
3566− 'd' => {
3567− surround_delete(cx);
3558+ 'd' => surround_delete(cx),
3568− let (view, doc) = current!(cx.editor);
3569− }
3570 _ => (),
3559 _ => (),
3571 }
3560 }
3572 }
3561 }
@@ -3588,7 +3577,7 @@ fn surround_add(cx: &mut Context) {
3588 let (open, close) = surround::get_pair(ch);
3577 let (open, close) = surround::get_pair(ch);
3589
3578
3590 let mut changes = Vec::new();
3579 let mut changes = Vec::new();
3591− for (i, range) in selection.iter().enumerate() {
3580+ for range in selection.iter() {
3592 changes.push((range.from(), range.from(), Some(Tendril::from_char(open))));
3581 changes.push((range.from(), range.from(), Some(Tendril::from_char(open))));
3593 changes.push((range.to(), range.to(), Some(Tendril::from_char(close))));
3582 changes.push((range.to(), range.to(), Some(Tendril::from_char(close))));
3594 }
3583 }
helix-term/src/compositor.rs+6−8
@@ -2,7 +2,6 @@
2// Q: how does this work with popups?
2// Q: how does this work with popups?
3// cursive does compositor.screen_mut().add_layer_at(pos::absolute(x, y), <component>)
3// cursive does compositor.screen_mut().add_layer_at(pos::absolute(x, y), <component>)
4use helix_core::Position;
4use helix_core::Position;
5−use helix_lsp::LspProgressMap;
6use helix_view::graphics::{CursorKind, Rect};
5use helix_view::graphics::{CursorKind, Rect};
7
6
8use crossterm::event::Event;
7use crossterm::event::Event;
@@ -36,7 +35,7 @@ pub struct Context<'a> {
36
35
37pub trait Component: Any + AnyComponent {
36pub trait Component: Any + AnyComponent {
38 /// Process input events, return true if handled.
37 /// Process input events, return true if handled.
39− fn handle_event(&mut self, event: Event, ctx: &mut Context) -> EventResult {
38+ fn handle_event(&mut self, _event: Event, _ctx: &mut Context) -> EventResult {
40 EventResult::Ignored
39 EventResult::Ignored
41 }
40 }
42 // , args: ()
41 // , args: ()
@@ -50,13 +49,13 @@ pub trait Component: Any + AnyComponent {
50 fn render(&self, area: Rect, frame: &mut Surface, ctx: &mut Context);
49 fn render(&self, area: Rect, frame: &mut Surface, ctx: &mut Context);
51
50
52 /// Get cursor position and cursor kind.
51 /// Get cursor position and cursor kind.
53− fn cursor(&self, area: Rect, ctx: &Editor) -> (Option<Position>, CursorKind) {
52+ fn cursor(&self, _area: Rect, _ctx: &Editor) -> (Option<Position>, CursorKind) {
54 (None, CursorKind::Hidden)
53 (None, CursorKind::Hidden)
55 }
54 }
56
55
57 /// May be used by the parent component to compute the child area.
56 /// May be used by the parent component to compute the child area.
58 /// viewport is the maximum allowed area, and the child should stay within those bounds.
57 /// viewport is the maximum allowed area, and the child should stay within those bounds.
59− fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
58+ fn required_size(&mut self, _viewport: (u16, u16)) -> Option<(u16, u16)> {
60 // TODO: for scrolling, the scroll wrapper should place a size + offset on the Context
59 // TODO: for scrolling, the scroll wrapper should place a size + offset on the Context
61 // that way render can use it
60 // that way render can use it
62 None
61 None
@@ -80,7 +79,7 @@ pub struct Compositor {
80impl Compositor {
79impl Compositor {
81 pub fn new() -> Result<Self, Error> {
80 pub fn new() -> Result<Self, Error> {
82 let backend = CrosstermBackend::new(stdout());
81 let backend = CrosstermBackend::new(stdout());
83− let mut terminal = Terminal::new(backend)?;
82+ let terminal = Terminal::new(backend)?;
84 Ok(Self {
83 Ok(Self {
85 layers: Vec::new(),
84 layers: Vec::new(),
86 terminal,
85 terminal,
@@ -125,8 +124,7 @@ impl Compositor {
125 }
124 }
126
125
127 pub fn render(&mut self, cx: &mut Context) {
126 pub fn render(&mut self, cx: &mut Context) {
128− let area = self
129− .terminal
127+ self.terminal
130 .autoresize()
128 .autoresize()
131 .expect("Unable to determine terminal size");
129 .expect("Unable to determine terminal size");
132
130
@@ -143,7 +141,7 @@ impl Compositor {
143 let (pos, kind) = self.cursor(area, cx.editor);
141 let (pos, kind) = self.cursor(area, cx.editor);
144 let pos = pos.map(|pos| (pos.col as u16, pos.row as u16));
142 let pos = pos.map(|pos| (pos.col as u16, pos.row as u16));
145
143
146− self.terminal.draw(pos, kind);
144+ self.terminal.draw(pos, kind).unwrap();
147 }
145 }
148
146
149 pub fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
147 pub fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
helix-term/src/config.rs+3−3
@@ -1,10 +1,10 @@
1−use anyhow::{Error, Result};
2use serde::Deserialize;
1use serde::Deserialize;
3−use std::collections::HashMap;
4
2
5−use crate::commands::Command;
6use crate::keymap::Keymaps;
3use crate::keymap::Keymaps;
7
4
5+#[cfg(test)]
6+use crate::commands::Command;
7+
8#[derive(Debug, Default, Clone, PartialEq, Deserialize)]
8#[derive(Debug, Default, Clone, PartialEq, Deserialize)]
9pub struct Config {
9pub struct Config {
10 pub theme: Option<String>,
10 pub theme: Option<String>,
helix-term/src/job.rs+1−1
@@ -3,7 +3,7 @@ use helix_view::Editor;
3use crate::compositor::Compositor;
3use crate::compositor::Compositor;
4
4
5use futures_util::future::{self, BoxFuture, Future, FutureExt};
5use futures_util::future::{self, BoxFuture, Future, FutureExt};
6−use futures_util::stream::{self, FuturesUnordered, Select, StreamExt};
6+use futures_util::stream::{FuturesUnordered, StreamExt};
7
7
8pub type Callback = Box<dyn FnOnce(&mut Editor, &mut Compositor) + Send>;
8pub type Callback = Box<dyn FnOnce(&mut Editor, &mut Compositor) + Send>;
9pub type JobFuture = BoxFuture<'static, anyhow::Result<Option<Callback>>>;
9pub type JobFuture = BoxFuture<'static, anyhow::Result<Option<Callback>>>;
helix-term/src/keymap.rs−4
@@ -1,7 +1,5 @@
1−use crate::commands;
2pub use crate::commands::Command;
1pub use crate::commands::Command;
3use crate::config::Config;
2use crate::config::Config;
4−use anyhow::{anyhow, Error, Result};
5use helix_core::hashmap;
3use helix_core::hashmap;
6use helix_view::{
4use helix_view::{
7 document::Mode,
5 document::Mode,
@@ -11,9 +9,7 @@ use helix_view::{
11use serde::Deserialize;
9use serde::Deserialize;
12use std::{
10use std::{
13 collections::HashMap,
11 collections::HashMap,
14− fmt::Display,
15 ops::{Deref, DerefMut},
12 ops::{Deref, DerefMut},
16− str::FromStr,
17};
13};
18
14
19// Kakoune-inspired:
15// Kakoune-inspired:
helix-term/src/lib.rs−2
@@ -1,5 +1,3 @@
1−#![allow(unused)]
2−
3#[macro_use]
1#[macro_use]
4extern crate helix_view;
2extern crate helix_view;
5
3
helix-term/src/ui/completion.rs+6−12
@@ -1,19 +1,16 @@
1−use crate::compositor::{Component, Compositor, Context, EventResult};
1+use crate::compositor::{Component, Context, EventResult};
2−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
2+use crossterm::event::{Event, KeyCode, KeyEvent};
3use tui::buffer::Buffer as Surface;
3use tui::buffer::Buffer as Surface;
4
4
5use std::borrow::Cow;
5use std::borrow::Cow;
6
6
7−use helix_core::{Position, Transaction};
7+use helix_core::Transaction;
8−use helix_view::{
8+use helix_view::{graphics::Rect, Editor};
9− graphics::{Color, Rect, Style},
10− Editor,
11−};
12
9
13use crate::commands;
10use crate::commands;
14use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent};
11use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent};
15
12
16−use helix_lsp::lsp;
13+use helix_lsp::{lsp, util};
17use lsp::CompletionItem;
14use lsp::CompletionItem;
18
15
19impl menu::Item for CompletionItem {
16impl menu::Item for CompletionItem {
@@ -79,7 +76,7 @@ impl Completion {
79 trigger_offset: usize,
76 trigger_offset: usize,
80 ) -> Self {
77 ) -> Self {
81 // let items: Vec<CompletionItem> = Vec::new();
78 // let items: Vec<CompletionItem> = Vec::new();
82− let mut menu = Menu::new(items, move |editor: &mut Editor, item, event| {
79+ let menu = Menu::new(items, move |editor: &mut Editor, item, event| {
83 match event {
80 match event {
84 PromptEvent::Abort => {}
81 PromptEvent::Abort => {}
85 PromptEvent::Validate => {
82 PromptEvent::Validate => {
@@ -88,8 +85,6 @@ impl Completion {
88 // always present here
85 // always present here
89 let item = item.unwrap();
86 let item = item.unwrap();
90
87
91− use helix_lsp::{lsp, util};
92−
93 // if more text was entered, remove it
88 // if more text was entered, remove it
94 let cursor = doc.selection(view.id).cursor();
89 let cursor = doc.selection(view.id).cursor();
95 if trigger_offset < cursor {
90 if trigger_offset < cursor {
@@ -100,7 +95,6 @@ impl Completion {
100 doc.apply(&remove, view.id);
95 doc.apply(&remove, view.id);
101 }
96 }
102
97
103− use helix_lsp::OffsetEncoding;
104 let transaction = if let Some(edit) = &item.text_edit {
98 let transaction = if let Some(edit) = &item.text_edit {
105 let edit = match edit {
99 let edit = match edit {
106 lsp::CompletionTextEdit::Edit(edit) => edit.clone(),
100 lsp::CompletionTextEdit::Edit(edit) => edit.clone(),
helix-term/src/ui/editor.rs+10−15
@@ -1,32 +1,28 @@
1use crate::{
1use crate::{
2 commands,
2 commands,
3− compositor::{Component, Compositor, Context, EventResult},
3+ compositor::{Component, Context, EventResult},
4 key,
4 key,
5− keymap::{self, Keymaps},
5+ keymap::Keymaps,
6 ui::{Completion, ProgressSpinners},
6 ui::{Completion, ProgressSpinners},
7};
7};
8
8
9use helix_core::{
9use helix_core::{
10 coords_at_pos,
10 coords_at_pos,
11 graphemes::ensure_grapheme_boundary_next,
11 graphemes::ensure_grapheme_boundary_next,
12− syntax::{self, Highlight, HighlightEvent},
12+ syntax::{self, HighlightEvent},
13 LineEnding, Position, Range,
13 LineEnding, Position, Range,
14};
14};
15−use helix_lsp::LspProgressMap;
16use helix_view::{
15use helix_view::{
17 document::Mode,
16 document::Mode,
18− graphics::{Color, CursorKind, Modifier, Rect, Style},
17+ graphics::{CursorKind, Modifier, Rect, Style},
19 input::KeyEvent,
18 input::KeyEvent,
20 keyboard::{KeyCode, KeyModifiers},
19 keyboard::{KeyCode, KeyModifiers},
21 Document, Editor, Theme, View,
20 Document, Editor, Theme, View,
22};
21};
23use std::borrow::Cow;
22use std::borrow::Cow;
24
23
25−use crossterm::{
24+use crossterm::event::Event;
26− cursor,
27− event::{read, Event, EventStream},
28−};
29−use tui::{backend::CrosstermBackend, buffer::Buffer as Surface};
25+use tui::buffer::Buffer as Surface;
30
26
31pub struct EditorView {
27pub struct EditorView {
32 keymaps: Keymaps,
28 keymaps: Keymaps,
@@ -396,7 +392,7 @@ impl EditorView {
396 viewport: Rect,
392 viewport: Rect,
397 surface: &mut Surface,
393 surface: &mut Surface,
398 theme: &Theme,
394 theme: &Theme,
399− is_focused: bool,
395+ _is_focused: bool,
400 ) {
396 ) {
401 use helix_core::diagnostic::Severity;
397 use helix_core::diagnostic::Severity;
402 use tui::{
398 use tui::{
@@ -406,7 +402,6 @@ impl EditorView {
406 };
402 };
407
403
408 let cursor = doc.selection(view.id).cursor();
404 let cursor = doc.selection(view.id).cursor();
409− let line = doc.text().char_to_line(cursor);
410
405
411 let diagnostics = doc.diagnostics().iter().filter(|diagnostic| {
406 let diagnostics = doc.diagnostics().iter().filter(|diagnostic| {
412 diagnostic.range.start <= cursor && diagnostic.range.end >= cursor
407 diagnostic.range.start <= cursor && diagnostic.range.end >= cursor
@@ -612,7 +607,7 @@ impl Component for EditorView {
612 // clear status
607 // clear status
613 cx.editor.status_msg = None;
608 cx.editor.status_msg = None;
614
609
615− let (view, doc) = current!(cx.editor);
610+ let (_, doc) = current!(cx.editor);
616 let mode = doc.mode();
611 let mode = doc.mode();
617
612
618 let mut cxt = commands::Context {
613 let mut cxt = commands::Context {
@@ -709,7 +704,7 @@ impl Component for EditorView {
709 }
704 }
710 }
705 }
711
706
712− fn render(&self, mut area: Rect, surface: &mut Surface, cx: &mut Context) {
707+ fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) {
713 // clear with background color
708 // clear with background color
714 surface.set_style(area, cx.editor.theme.get("ui.background"));
709 surface.set_style(area, cx.editor.theme.get("ui.background"));
715
710
@@ -745,7 +740,7 @@ impl Component for EditorView {
745 }
740 }
746 }
741 }
747
742
748− fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
743+ fn cursor(&self, _area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
749 // match view.doc.mode() {
744 // match view.doc.mode() {
750 // Mode::Insert => write!(stdout, "\x1B[6 q"),
745 // Mode::Insert => write!(stdout, "\x1B[6 q"),
751 // mode => write!(stdout, "\x1B[2 q"),
746 // mode => write!(stdout, "\x1B[2 q"),
helix-term/src/ui/markdown.rs+18−17
@@ -1,13 +1,20 @@
1−use crate::compositor::{Component, Compositor, Context, EventResult};
1+use crate::compositor::{Component, Context};
2−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
2+use tui::{
3−use tui::{buffer::Buffer as Surface, text::Text};
3+ buffer::Buffer as Surface,
4+ text::{Span, Spans, Text},
5+};
6+
7+use std::sync::Arc;
4
8
5−use std::{borrow::Cow, sync::Arc};
9+use pulldown_cmark::{CodeBlockKind, CowStr, Event, Options, Parser, Tag};
6
10
7−use helix_core::{syntax, Position};
11+use helix_core::{
12+ syntax::{self, HighlightEvent, Syntax},
13+ Rope,
14+};
8use helix_view::{
15use helix_view::{
9 graphics::{Color, Rect, Style},
16 graphics::{Color, Rect, Style},
10− Editor, Theme,
17+ Theme,
11};
18};
12
19
13pub struct Markdown {
20pub struct Markdown {
@@ -33,11 +40,8 @@ fn parse<'a>(
33 theme: Option<&Theme>,
40 theme: Option<&Theme>,
34 loader: &syntax::Loader,
41 loader: &syntax::Loader,
35) -> tui::text::Text<'a> {
42) -> tui::text::Text<'a> {
36− use pulldown_cmark::{CodeBlockKind, CowStr, Event, Options, Parser, Tag};
37− use tui::text::{Span, Spans, Text};
38−
39− // also 2021-03-04T16:33:58.553 helix_lsp::transport [INFO] <- {"contents":{"kind":"markdown","value":"\n```rust\ncore::num\n```\n\n```rust\npub const fn saturating_sub(self, rhs:Self) ->Self\n```\n\n---\n\n```rust\n```"},"range":{"end":{"character":61,"line":101},"start":{"character":47,"line":101}}}
43+ // // also 2021-03-04T16:33:58.553 helix_lsp::transport [INFO] <- {"contents":{"kind":"markdown","value":"\n```rust\ncore::num\n```\n\n```rust\npub const fn saturating_sub(self, rhs:Self) ->Self\n```\n\n---\n\n```rust\n```"},"range":{"end":{"character":61,"line":101},"start":{"character":47,"line":101}}}
40− let text = "\n```rust\ncore::iter::traits::iterator::Iterator\n```\n\n```rust\nfn collect<B: FromIterator<Self::Item>>(self) -> B\nwhere\n Self: Sized,\n```\n\n---\n\nTransforms an iterator into a collection.\n\n`collect()` can take anything iterable, and turn it into a relevant\ncollection. This is one of the more powerful methods in the standard\nlibrary, used in a variety of contexts.\n\nThe most basic pattern in which `collect()` is used is to turn one\ncollection into another. You take a collection, call [`iter`](https://doc.rust-lang.org/nightly/core/iter/traits/iterator/trait.Iterator.html) on it,\ndo a bunch of transformations, and then `collect()` at the end.\n\n`collect()` can also create instances of types that are not typical\ncollections. For example, a [`String`](https://doc.rust-lang.org/nightly/core/iter/std/string/struct.String.html) can be built from [`char`](type@char)s,\nand an iterator of [`Result<T, E>`](https://doc.rust-lang.org/nightly/core/result/enum.Result.html) items can be collected\ninto `Result<Collection<T>, E>`. See the examples below for more.\n\nBecause `collect()` is so general, it can cause problems with type\ninference. As such, `collect()` is one of the few times you'll see\nthe syntax affectionately known as the 'turbofish': `::<>`. This\nhelps the inference algorithm understand specifically which collection\nyou're trying to collect into.\n\n# Examples\n\nBasic usage:\n\n```rust\nlet a = [1, 2, 3];\n\nlet doubled: Vec<i32> = a.iter()\n .map(|&x| x * 2)\n .collect();\n\nassert_eq!(vec![2, 4, 6], doubled);\n```\n\nNote that we needed the `: Vec<i32>` on the left-hand side. This is because\nwe could collect into, for example, a [`VecDeque<T>`](https://doc.rust-lang.org/nightly/core/iter/std/collections/struct.VecDeque.html) instead:\n\n```rust\nuse std::collections::VecDeque;\n\nlet a = [1, 2, 3];\n\nlet doubled: VecDeque<i32> = a.iter().map(|&x| x * 2).collect();\n\nassert_eq!(2, doubled[0]);\nassert_eq!(4, doubled[1]);\nassert_eq!(6, doubled[2]);\n```\n\nUsing the 'turbofish' instead of annotating `doubled`:\n\n```rust\nlet a = [1, 2, 3];\n\nlet doubled = a.iter().map(|x| x * 2).collect::<Vec<i32>>();\n\nassert_eq!(vec![2, 4, 6], doubled);\n```\n\nBecause `collect()` only cares about what you're collecting into, you can\nstill use a partial type hint, `_`, with the turbofish:\n\n```rust\nlet a = [1, 2, 3];\n\nlet doubled = a.iter().map(|x| x * 2).collect::<Vec<_>>();\n\nassert_eq!(vec![2, 4, 6], doubled);\n```\n\nUsing `collect()` to make a [`String`](https://doc.rust-lang.org/nightly/core/iter/std/string/struct.String.html):\n\n```rust\nlet chars = ['g', 'd', 'k', 'k', 'n'];\n\nlet hello: String = chars.iter()\n .map(|&x| x as u8)\n .map(|x| (x + 1) as char)\n .collect();\n\nassert_eq!(\"hello\", hello);\n```\n\nIf you have a list of [`Result<T, E>`](https://doc.rust-lang.org/nightly/core/result/enum.Result.html)s, you can use `collect()` to\nsee if any of them failed:\n\n```rust\nlet results = [Ok(1), Err(\"nope\"), Ok(3), Err(\"bad\")];\n\nlet result: Result<Vec<_>, &str> = results.iter().cloned().collect();\n\n// gives us the first error\nassert_eq!(Err(\"nope\"), result);\n\nlet results = [Ok(1), Ok(3)];\n\nlet result: Result<Vec<_>, &str> = results.iter().cloned().collect();\n\n// gives us the list of answers\nassert_eq!(Ok(vec![1, 3]), result);\n```";
44+ // let text = "\n```rust\ncore::iter::traits::iterator::Iterator\n```\n\n```rust\nfn collect<B: FromIterator<Self::Item>>(self) -> B\nwhere\n Self: Sized,\n```\n\n---\n\nTransforms an iterator into a collection.\n\n`collect()` can take anything iterable, and turn it into a relevant\ncollection. This is one of the more powerful methods in the standard\nlibrary, used in a variety of contexts.\n\nThe most basic pattern in which `collect()` is used is to turn one\ncollection into another. You take a collection, call [`iter`](https://doc.rust-lang.org/nightly/core/iter/traits/iterator/trait.Iterator.html) on it,\ndo a bunch of transformations, and then `collect()` at the end.\n\n`collect()` can also create instances of types that are not typical\ncollections. For example, a [`String`](https://doc.rust-lang.org/nightly/core/iter/std/string/struct.String.html) can be built from [`char`](type@char)s,\nand an iterator of [`Result<T, E>`](https://doc.rust-lang.org/nightly/core/result/enum.Result.html) items can be collected\ninto `Result<Collection<T>, E>`. See the examples below for more.\n\nBecause `collect()` is so general, it can cause problems with type\ninference. As such, `collect()` is one of the few times you'll see\nthe syntax affectionately known as the 'turbofish': `::<>`. This\nhelps the inference algorithm understand specifically which collection\nyou're trying to collect into.\n\n# Examples\n\nBasic usage:\n\n```rust\nlet a = [1, 2, 3];\n\nlet doubled: Vec<i32> = a.iter()\n .map(|&x| x * 2)\n .collect();\n\nassert_eq!(vec![2, 4, 6], doubled);\n```\n\nNote that we needed the `: Vec<i32>` on the left-hand side. This is because\nwe could collect into, for example, a [`VecDeque<T>`](https://doc.rust-lang.org/nightly/core/iter/std/collections/struct.VecDeque.html) instead:\n\n```rust\nuse std::collections::VecDeque;\n\nlet a = [1, 2, 3];\n\nlet doubled: VecDeque<i32> = a.iter().map(|&x| x * 2).collect();\n\nassert_eq!(2, doubled[0]);\nassert_eq!(4, doubled[1]);\nassert_eq!(6, doubled[2]);\n```\n\nUsing the 'turbofish' instead of annotating `doubled`:\n\n```rust\nlet a = [1, 2, 3];\n\nlet doubled = a.iter().map(|x| x * 2).collect::<Vec<i32>>();\n\nassert_eq!(vec![2, 4, 6], doubled);\n```\n\nBecause `collect()` only cares about what you're collecting into, you can\nstill use a partial type hint, `_`, with the turbofish:\n\n```rust\nlet a = [1, 2, 3];\n\nlet doubled = a.iter().map(|x| x * 2).collect::<Vec<_>>();\n\nassert_eq!(vec![2, 4, 6], doubled);\n```\n\nUsing `collect()` to make a [`String`](https://doc.rust-lang.org/nightly/core/iter/std/string/struct.String.html):\n\n```rust\nlet chars = ['g', 'd', 'k', 'k', 'n'];\n\nlet hello: String = chars.iter()\n .map(|&x| x as u8)\n .map(|x| (x + 1) as char)\n .collect();\n\nassert_eq!(\"hello\", hello);\n```\n\nIf you have a list of [`Result<T, E>`](https://doc.rust-lang.org/nightly/core/result/enum.Result.html)s, you can use `collect()` to\nsee if any of them failed:\n\n```rust\nlet results = [Ok(1), Err(\"nope\"), Ok(3), Err(\"bad\")];\n\nlet result: Result<Vec<_>, &str> = results.iter().cloned().collect();\n\n// gives us the first error\nassert_eq!(Err(\"nope\"), result);\n\nlet results = [Ok(1), Ok(3)];\n\nlet result: Result<Vec<_>, &str> = results.iter().cloned().collect();\n\n// gives us the list of answers\nassert_eq!(Ok(vec![1, 3]), result);\n```";
41
45
42 let mut options = Options::empty();
46 let mut options = Options::empty();
43 options.insert(Options::ENABLE_STRIKETHROUGH);
47 options.insert(Options::ENABLE_STRIKETHROUGH);
@@ -82,16 +86,13 @@ fn parse<'a>(
82 // TODO: temp workaround
86 // TODO: temp workaround
83 if let Some(Tag::CodeBlock(CodeBlockKind::Fenced(language))) = tags.last() {
87 if let Some(Tag::CodeBlock(CodeBlockKind::Fenced(language))) = tags.last() {
84 if let Some(theme) = theme {
88 if let Some(theme) = theme {
85− use helix_core::syntax::{self, HighlightEvent, Syntax};
86− use helix_core::Rope;
87−
88 let rope = Rope::from(text.as_ref());
89 let rope = Rope::from(text.as_ref());
89 let syntax = loader
90 let syntax = loader
90 .language_config_for_scope(&format!("source.{}", language))
91 .language_config_for_scope(&format!("source.{}", language))
91 .and_then(|config| config.highlight_config(theme.scopes()))
92 .and_then(|config| config.highlight_config(theme.scopes()))
92 .map(|config| Syntax::new(&rope, config));
93 .map(|config| Syntax::new(&rope, config));
93
94
94− if let Some(mut syntax) = syntax {
95+ if let Some(syntax) = syntax {
95 // if we have a syntax available, highlight_iter and generate spans
96 // if we have a syntax available, highlight_iter and generate spans
96 let mut highlights = Vec::new();
97 let mut highlights = Vec::new();
97
98
@@ -141,13 +142,13 @@ fn parse<'a>(
141 }
142 }
142 } else {
143 } else {
143 for line in text.lines() {
144 for line in text.lines() {
144− let mut span = Span::styled(line.to_string(), code_style);
145+ let span = Span::styled(line.to_string(), code_style);
145 lines.push(Spans::from(span));
146 lines.push(Spans::from(span));
146 }
147 }
147 }
148 }
148 } else {
149 } else {
149 for line in text.lines() {
150 for line in text.lines() {
150− let mut span = Span::styled(line.to_string(), code_style);
151+ let span = Span::styled(line.to_string(), code_style);
151 lines.push(Spans::from(span));
152 lines.push(Spans::from(span));
152 }
153 }
153 }
154 }
helix-term/src/ui/menu.rs+2−9
@@ -4,16 +4,10 @@ use tui::{buffer::Buffer as Surface, widgets::Table};
4
4
5pub use tui::widgets::{Cell, Row};
5pub use tui::widgets::{Cell, Row};
6
6
7−use std::borrow::Cow;
8−
9use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
7use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
10use fuzzy_matcher::FuzzyMatcher;
8use fuzzy_matcher::FuzzyMatcher;
11
9
12−use helix_core::Position;
13−use helix_view::{
10+use helix_view::{graphics::Rect, Editor};
14− graphics::{Color, Rect, Style},
15− Editor,
16−};
17
11
18pub trait Item {
12pub trait Item {
19 // TODO: sort_text
13 // TODO: sort_text
@@ -64,7 +58,6 @@ impl<T: Item> Menu<T> {
64 pub fn score(&mut self, pattern: &str) {
58 pub fn score(&mut self, pattern: &str) {
65 // need to borrow via pattern match otherwise it complains about simultaneous borrow
59 // need to borrow via pattern match otherwise it complains about simultaneous borrow
66 let Self {
60 let Self {
67− ref mut options,
68 ref mut matcher,
61 ref mut matcher,
69 ref mut matches,
62 ref mut matches,
70 ..
63 ..
@@ -297,7 +290,7 @@ impl<T: Item + 'static> Component for Menu<T> {
297 // )
290 // )
298 // }
291 // }
299
292
300− for (i, option) in (scroll..(scroll + win_height).min(len)).enumerate() {
293+ for (i, _) in (scroll..(scroll + win_height).min(len)).enumerate() {
301 let is_marked = i >= scroll_line && i < scroll_line + scroll_height;
294 let is_marked = i >= scroll_line && i < scroll_line + scroll_height;
302
295
303 if is_marked {
296 if is_marked {
helix-term/src/ui/mod.rs+11−14
@@ -20,12 +20,9 @@ pub use text::Text;
20
20
21use helix_core::regex::Regex;
21use helix_core::regex::Regex;
22use helix_core::register::Registers;
22use helix_core::register::Registers;
23−use helix_view::{
24− graphics::{Color, Modifier, Rect, Style},
25− Document, Editor, View,
23+use helix_view::{Document, Editor, View};
26−};
27
24
28−use std::path::{Path, PathBuf};
25+use std::path::PathBuf;
29
26
30pub fn regex_prompt(
27pub fn regex_prompt(
31 cx: &mut crate::commands::Context,
28 cx: &mut crate::commands::Context,
@@ -38,7 +35,7 @@ pub fn regex_prompt(
38
35
39 Prompt::new(
36 Prompt::new(
40 prompt,
37 prompt,
41− |input: &str| Vec::new(), // this is fine because Vec::new() doesn't allocate
38+ |_input: &str| Vec::new(), // this is fine because Vec::new() doesn't allocate
42 move |cx: &mut crate::compositor::Context, input: &str, event: PromptEvent| {
39 move |cx: &mut crate::compositor::Context, input: &str, event: PromptEvent| {
43 match event {
40 match event {
44 PromptEvent::Abort => {
41 PromptEvent::Abort => {
@@ -121,7 +118,7 @@ pub fn file_picker(root: PathBuf) -> Picker<PathBuf> {
121 .into()
118 .into()
122 },
119 },
123 move |editor: &mut Editor, path: &PathBuf, action| {
120 move |editor: &mut Editor, path: &PathBuf, action| {
124− let document_id = editor
121+ editor
125 .open(path.into(), action)
122 .open(path.into(), action)
126 .expect("editor.open failed");
123 .expect("editor.open failed");
127 },
124 },
@@ -133,8 +130,8 @@ pub mod completers {
133 use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
130 use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
134 use fuzzy_matcher::FuzzyMatcher;
131 use fuzzy_matcher::FuzzyMatcher;
135 use helix_view::theme;
132 use helix_view::theme;
133+ use std::borrow::Cow;
136 use std::cmp::Reverse;
134 use std::cmp::Reverse;
137− use std::{borrow::Cow, sync::Arc};
138
135
139 pub type Completer = fn(&str) -> Vec<Completion>;
136 pub type Completer = fn(&str) -> Vec<Completion>;
140
137
@@ -154,7 +151,7 @@ pub mod completers {
154
151
155 let mut matches: Vec<_> = names
152 let mut matches: Vec<_> = names
156 .into_iter()
153 .into_iter()
157− .filter_map(|(range, name)| {
154+ .filter_map(|(_range, name)| {
158 matcher.fuzzy_match(&name, input).map(|score| (name, score))
155 matcher.fuzzy_match(&name, input).map(|score| (name, score))
159 })
156 })
160 .collect();
157 .collect();
@@ -208,7 +205,7 @@ pub mod completers {
208 // Rust's filename handling is really annoying.
205 // Rust's filename handling is really annoying.
209
206
210 use ignore::WalkBuilder;
207 use ignore::WalkBuilder;
211− use std::path::{Path, PathBuf};
208+ use std::path::Path;
212
209
213 let is_tilde = input.starts_with('~') && input.len() == 1;
210 let is_tilde = input.starts_with('~') && input.len() == 1;
214 let path = helix_view::document::expand_tilde(Path::new(input));
211 let path = helix_view::document::expand_tilde(Path::new(input));
@@ -229,7 +226,7 @@ pub mod completers {
229 (path, file_name)
226 (path, file_name)
230 };
227 };
231
228
232− let end = (input.len()..);
229+ let end = input.len()..;
233
230
234 let mut files: Vec<_> = WalkBuilder::new(dir.clone())
231 let mut files: Vec<_> = WalkBuilder::new(dir.clone())
235 .max_depth(Some(1))
232 .max_depth(Some(1))
@@ -242,7 +239,7 @@ pub mod completers {
242 return None;
239 return None;
243 }
240 }
244
241
245− let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());
242+ //let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());
246
243
247 let path = entry.path();
244 let path = entry.path();
248 let mut path = if is_tilde {
245 let mut path = if is_tilde {
@@ -274,14 +271,14 @@ pub mod completers {
274 // inefficient, but we need to calculate the scores, filter out None, then sort.
271 // inefficient, but we need to calculate the scores, filter out None, then sort.
275 let mut matches: Vec<_> = files
272 let mut matches: Vec<_> = files
276 .into_iter()
273 .into_iter()
277− .filter_map(|(range, file)| {
274+ .filter_map(|(_range, file)| {
278 matcher
275 matcher
279 .fuzzy_match(&file, &file_name)
276 .fuzzy_match(&file, &file_name)
280 .map(|score| (file, score))
277 .map(|score| (file, score))
281 })
278 })
282 .collect();
279 .collect();
283
280
284− let range = ((input.len().saturating_sub(file_name.len()))..);
281+ let range = (input.len().saturating_sub(file_name.len()))..;
285
282
286 matches.sort_unstable_by_key(|(_file, score)| Reverse(*score));
283 matches.sort_unstable_by_key(|(_file, score)| Reverse(*score));
287 files = matches
284 files = matches
helix-term/src/ui/picker.rs+2−3
@@ -43,8 +43,8 @@ impl<T> Picker<T> {
43 ) -> Self {
43 ) -> Self {
44 let prompt = Prompt::new(
44 let prompt = Prompt::new(
45 "".to_string(),
45 "".to_string(),
46− |pattern: &str| Vec::new(),
46+ |_pattern: &str| Vec::new(),
47− |editor: &mut Context, pattern: &str, event: PromptEvent| {
47+ |_editor: &mut Context, _pattern: &str, _event: PromptEvent| {
48 //
48 //
49 },
49 },
50 );
50 );
@@ -69,7 +69,6 @@ impl<T> Picker<T> {
69 pub fn score(&mut self) {
69 pub fn score(&mut self) {
70 // need to borrow via pattern match otherwise it complains about simultaneous borrow
70 // need to borrow via pattern match otherwise it complains about simultaneous borrow
71 let Self {
71 let Self {
72− ref mut options,
73 ref mut matcher,
72 ref mut matcher,
74 ref mut matches,
73 ref mut matches,
75 ref filters,
74 ref filters,
helix-term/src/ui/popup.rs+3−9
@@ -2,13 +2,8 @@ use crate::compositor::{Component, Compositor, Context, EventResult};
2use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
2use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
3use tui::buffer::Buffer as Surface;
3use tui::buffer::Buffer as Surface;
4
4
5−use std::borrow::Cow;
6−
7use helix_core::Position;
5use helix_core::Position;
8−use helix_view::{
6+use helix_view::graphics::Rect;
9− graphics::{Color, Rect, Style},
10− Editor,
11−};
12
7
13// TODO: share logic with Menu, it's essentially Popup(render_fn), but render fn needs to return
8// TODO: share logic with Menu, it's essentially Popup(render_fn), but render fn needs to return
14// a width/height hint. maybe Popup(Box<Component>)
9// a width/height hint. maybe Popup(Box<Component>)
@@ -57,7 +52,7 @@ impl<T: Component> Component for Popup<T> {
57 fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
52 fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
58 let key = match event {
53 let key = match event {
59 Event::Key(event) => event,
54 Event::Key(event) => event,
60− Event::Resize(width, height) => {
55+ Event::Resize(_, _) => {
61 // TODO: calculate inner area, call component's handle_event with that area
56 // TODO: calculate inner area, call component's handle_event with that area
62 return EventResult::Ignored;
57 return EventResult::Ignored;
63 }
58 }
@@ -99,7 +94,7 @@ impl<T: Component> Component for Popup<T> {
99 // tab/enter/ctrl-k or whatever will confirm the selection/ ctrl-n/ctrl-p for scroll.
94 // tab/enter/ctrl-k or whatever will confirm the selection/ ctrl-n/ctrl-p for scroll.
100 }
95 }
101
96
102− fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
97+ fn required_size(&mut self, _viewport: (u16, u16)) -> Option<(u16, u16)> {
103 let (width, height) = self
98 let (width, height) = self
104 .contents
99 .contents
105 .required_size((120, 26)) // max width, max height
100 .required_size((120, 26)) // max width, max height
@@ -135,7 +130,6 @@ impl<T: Component> Component for Popup<T> {
135 rel_y += 1 // position below point
130 rel_y += 1 // position below point
136 }
131 }
137
132
138− let area = Rect::new(rel_x, rel_y, width, height);
139 // clip to viewport
133 // clip to viewport
140 let area = viewport.intersection(Rect::new(rel_x, rel_y, width, height));
134 let area = viewport.intersection(Rect::new(rel_x, rel_y, width, height));
141
135
helix-term/src/ui/prompt.rs+20−22
@@ -5,13 +5,11 @@ use std::{borrow::Cow, ops::RangeFrom};
5use tui::buffer::Buffer as Surface;
5use tui::buffer::Buffer as Surface;
6
6
7use helix_core::{
7use helix_core::{
8− unicode::segmentation::{GraphemeCursor, GraphemeIncomplete},
9− unicode::width::UnicodeWidthStr,
8+ unicode::segmentation::GraphemeCursor, unicode::width::UnicodeWidthStr, Position,
10− Position,
11};
9};
12use helix_view::{
10use helix_view::{
13− graphics::{Color, CursorKind, Margin, Modifier, Rect, Style},
11+ graphics::{CursorKind, Margin, Rect},
14− Editor, Theme,
12+ Editor,
15};
13};
16
14
17pub type Completion = (RangeFrom<usize>, Cow<'static, str>);
15pub type Completion = (RangeFrom<usize>, Cow<'static, str>);
@@ -398,6 +396,22 @@ impl Component for Prompt {
398 (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
396 (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
399 return close_fn;
397 return close_fn;
400 }
398 }
399+ KeyEvent {
400+ code: KeyCode::Left,
401+ modifiers: KeyModifiers::ALT,
402+ }
403+ | KeyEvent {
404+ code: KeyCode::Char('b'),
405+ modifiers: KeyModifiers::ALT,
406+ } => self.move_cursor(Movement::BackwardWord(1)),
407+ KeyEvent {
408+ code: KeyCode::Right,
409+ modifiers: KeyModifiers::ALT,
410+ }
411+ | KeyEvent {
412+ code: KeyCode::Char('f'),
413+ modifiers: KeyModifiers::ALT,
414+ } => self.move_cursor(Movement::ForwardWord(1)),
401 KeyEvent {
415 KeyEvent {
402 code: KeyCode::Char('f'),
416 code: KeyCode::Char('f'),
403 modifiers: KeyModifiers::CONTROL,
417 modifiers: KeyModifiers::CONTROL,
@@ -430,22 +444,6 @@ impl Component for Prompt {
430 code: KeyCode::Char('a'),
444 code: KeyCode::Char('a'),
431 modifiers: KeyModifiers::CONTROL,
445 modifiers: KeyModifiers::CONTROL,
432 } => self.move_start(),
446 } => self.move_start(),
433− KeyEvent {
434− code: KeyCode::Left,
435− modifiers: KeyModifiers::ALT,
436− }
437− | KeyEvent {
438− code: KeyCode::Char('b'),
439− modifiers: KeyModifiers::ALT,
440− } => self.move_cursor(Movement::BackwardWord(1)),
441− KeyEvent {
442− code: KeyCode::Right,
443− modifiers: KeyModifiers::ALT,
444− }
445− | KeyEvent {
446− code: KeyCode::Char('f'),
447− modifiers: KeyModifiers::ALT,
448− } => self.move_cursor(Movement::ForwardWord(1)),
449 KeyEvent {
447 KeyEvent {
450 code: KeyCode::Char('w'),
448 code: KeyCode::Char('w'),
451 modifiers: KeyModifiers::CONTROL,
449 modifiers: KeyModifiers::CONTROL,
@@ -494,7 +492,7 @@ impl Component for Prompt {
494 self.render_prompt(area, surface, cx)
492 self.render_prompt(area, surface, cx)
495 }
493 }
496
494
497− fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
495+ fn cursor(&self, area: Rect, _editor: &Editor) -> (Option<Position>, CursorKind) {
498 let line = area.height as usize - 1;
496 let line = area.height as usize - 1;
499 (
497 (
500 Some(Position::new(
498 Some(Position::new(
helix-term/src/ui/text.rs+3−12
@@ -1,14 +1,7 @@
1−use crate::compositor::{Component, Compositor, Context, EventResult};
1+use crate::compositor::{Component, Context};
2−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
3use tui::buffer::Buffer as Surface;
2use tui::buffer::Buffer as Surface;
4
3
5−use std::borrow::Cow;
6−
7−use helix_core::Position;
8−use helix_view::{
4+use helix_view::graphics::Rect;
9− graphics::{Color, Rect, Style},
10− Editor,
11−};
12
5
13pub struct Text {
6pub struct Text {
14 contents: String,
7 contents: String,
@@ -20,12 +13,10 @@ impl Text {
20 }
13 }
21}
14}
22impl Component for Text {
15impl Component for Text {
23− fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) {
16+ fn render(&self, area: Rect, surface: &mut Surface, _cx: &mut Context) {
24 use tui::widgets::{Paragraph, Widget, Wrap};
17 use tui::widgets::{Paragraph, Widget, Wrap};
25 let contents = tui::text::Text::from(self.contents.clone());
18 let contents = tui::text::Text::from(self.contents.clone());
26
19
27− let style = cx.editor.theme.get("ui.text");
28−
29 let par = Paragraph::new(contents).wrap(Wrap { trim: false });
20 let par = Paragraph::new(contents).wrap(Wrap { trim: false });
30 // .scroll(x, y) offsets
21 // .scroll(x, y) offsets
31
22