on master help sign in
Merge branch 'master' into great_line_ending_and_cursor_range_cleanup
commit2224a1527ec9592f16131b0aa3923fc3d37592e7 authorNathan Vegdahl <cessen@cessen.com> dateThu 1 Jul 2021, 19:37 (5 years ago) parente7259579f62ad0
28 files changed+383−456
helix-core/src/auto_pairs.rs+1−1 helix-core/src/history.rs+4−6 helix-core/src/indent.rs+6−4 helix-core/src/lib.rs−1 helix-core/src/line_ending.rs+1−1 helix-core/src/match_brackets.rs+2−2 helix-core/src/movement.rs+11−15 helix-core/src/object.rs−1 helix-core/src/position.rs+4−3 helix-core/src/selection.rs+7−8 helix-core/src/syntax.rs+157−158 helix-core/src/transaction.rs+9−9 helix-term/src/application.rs+26−35 helix-term/src/commands.rs+70−81 helix-term/src/compositor.rs+6−8 helix-term/src/config.rs+3−3 helix-term/src/job.rs+1−1 helix-term/src/keymap.rs−4 helix-term/src/lib.rs−2 helix-term/src/ui/completion.rs+6−12 helix-term/src/ui/editor.rs+10−15 helix-term/src/ui/markdown.rs+18−17 helix-term/src/ui/menu.rs+2−9 helix-term/src/ui/mod.rs+11−14 helix-term/src/ui/picker.rs+2−3 helix-term/src/ui/popup.rs+3−9 helix-term/src/ui/prompt.rs+20−22 helix-term/src/ui/text.rs+3−12
helix-core/src/auto_pairs.rs+1−1
@@ -139,7 +139,7 @@ fn handle_close(doc: &Rope, selection: &Selection, _open: char, close: char) ->
139139}
140140
141141// 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> {
143143 // if not cursor but selection, wrap
144144 // let next = next char
145145
helix-core/src/history.rs+4−6
@@ -1,7 +1,6 @@
11use crate::{ChangeSet, Rope, State, Transaction};
22use once_cell::sync::Lazy;
33use regex::Regex;
4−use smallvec::{smallvec, SmallVec};
54use std::num::NonZeroUsize;
65use std::time::{Duration, Instant};
76
@@ -127,7 +126,6 @@ impl History {
127126 let last_child = current_revision.last_child?;
128127 self.current = last_child.get();
129128
130− let last_child_revision = &self.revisions[last_child.get()];
131129 Some(&self.revisions[last_child.get()].transaction)
132130 }
133131
@@ -377,21 +375,21 @@ mod test {
377375 if let Some(transaction) = history.undo() {
378376 transaction.apply(&mut state.doc);
379377 }
380− };
378+ }
381379
382380 fn earlier(history: &mut History, state: &mut State, uk: UndoKind) {
383381 let txns = history.earlier(uk);
384382 for txn in txns {
385383 txn.apply(&mut state.doc);
386384 }
387− };
385+ }
388386
389387 fn later(history: &mut History, state: &mut State, uk: UndoKind) {
390388 let txns = history.later(uk);
391389 for txn in txns {
392390 txn.apply(&mut state.doc);
393391 }
394− };
392+ }
395393
396394 fn commit_change(
397395 history: &mut History,
@@ -402,7 +400,7 @@ mod test {
402400 let txn = Transaction::change(&state.doc, vec![change.clone()].into_iter());
403401 history.commit_revision_at_timestamp(&txn, &state, instant);
404402 txn.apply(&mut state.doc);
405− };
403+ }
406404
407405 let t0 = Instant::now();
408406 let t = |n| t0.checked_add(Duration::from_secs(n)).unwrap();
helix-core/src/indent.rs+6−4
@@ -1,13 +1,13 @@
11use crate::{
22 find_first_non_whitespace_char,
33 syntax::{IndentQuery, LanguageConfiguration, Syntax},
4− tree_sitter::{Node, Tree},
5− Rope, RopeSlice,
4+ tree_sitter::Node,
5+ RopeSlice,
66};
77
88/// To determine indentation of a newly inserted line, figure out the indentation at the last col
99/// of the previous line.
10−
10+#[allow(dead_code)]
1111fn indent_level_for_line(line: RopeSlice, tab_width: usize) -> usize {
1212 let mut len = 0;
1313 for ch in line.chars() {
@@ -98,12 +98,13 @@ fn calculate_indentation(query: &IndentQuery, node: Option<Node>, newline: bool)
9898 increment as usize
9999}
100100
101+#[allow(dead_code)]
101102fn suggested_indent_for_line(
102103 language_config: &LanguageConfiguration,
103104 syntax: Option<&Syntax>,
104105 text: RopeSlice,
105106 line_num: usize,
106− tab_width: usize,
107+ _tab_width: usize,
107108) -> usize {
108109 if let Some(start) = find_first_non_whitespace_char(text.line(line_num)) {
109110 return suggested_indent_for_pos(
@@ -150,6 +151,7 @@ pub fn suggested_indent_for_pos(
150151#[cfg(test)]
151152mod test {
152153 use super::*;
154+ use crate::Rope;
153155
154156 #[test]
155157 fn test_indent_level() {
helix-core/src/lib.rs−1
@@ -1,4 +1,3 @@
1−#![allow(unused)]
21pub mod auto_pairs;
32pub mod chars;
43pub 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};
22
33#[cfg(target_os = "windows")]
44pub 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};
22
33const PAIRS: &[(char, char)] = &[('(', ')'), ('{', '}'), ('[', ']'), ('<', '>')];
44// limit matching pairs to only ( ) { } [ ] < >
@@ -12,7 +12,7 @@ pub fn find(syntax: &Syntax, doc: &Rope, pos: usize) -> Option<usize> {
1212 // most naive implementation: find the innermost syntax node, if we're at the edge of a node,
1313 // return the other edge.
1414
15− let mut node = match tree
15+ let node = match tree
1616 .root_node()
1717 .named_descendant_for_byte_range(byte_pos, byte_pos)
1818 {
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};
22
33use ropey::iter::Chars;
44
55use crate::{
6− chars::{
7− categorize_char, char_is_line_ending, char_is_punctuation, char_is_whitespace,
8− char_is_word, CharCategory,
9− },
6+ chars::{categorize_char, char_is_line_ending, CharCategory},
107 coords_at_pos,
118 graphemes::{nth_next_grapheme_boundary, nth_prev_grapheme_boundary},
129 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) -
116113 word_move(slice, range, count, WordMotionTarget::PrevLongWordStart)
117114}
118115
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 {
120117 (0..count).fold(range, |range, _| {
121118 slice.chars_at(range.head).range_to_target(target, range)
122119 })
@@ -182,7 +179,6 @@ enum WordMotionPhase {
182179
183180impl CharHelpers for Chars<'_> {
184181 fn range_to_target(&mut self, target: WordMotionTarget, origin: Range) -> Range {
185− let range = origin;
186182 // Characters are iterated forward or backwards depending on the motion direction.
187183 let characters: Box<dyn Iterator<Item = char>> = match target {
188184 WordMotionTarget::PrevWordStart | WordMotionTarget::PrevLongWordStart => {
@@ -270,20 +266,20 @@ fn reached_target(target: WordMotionTarget, peek: char, next_peek: Option<&char>
270266
271267 match target {
272268 WordMotionTarget::NextWordStart => {
273− (is_word_boundary(peek, *next_peek)
274− && (char_is_line_ending(*next_peek) || !next_peek.is_whitespace()))
269+ is_word_boundary(peek, *next_peek)
270+ && (char_is_line_ending(*next_peek) || !next_peek.is_whitespace())
275271 }
276272 WordMotionTarget::NextWordEnd | WordMotionTarget::PrevWordStart => {
277− (is_word_boundary(peek, *next_peek)
278− && (!peek.is_whitespace() || char_is_line_ending(*next_peek)))
273+ is_word_boundary(peek, *next_peek)
274+ && (!peek.is_whitespace() || char_is_line_ending(*next_peek))
279275 }
280276 WordMotionTarget::NextLongWordStart => {
281− (is_long_word_boundary(peek, *next_peek)
282− && (char_is_line_ending(*next_peek) || !next_peek.is_whitespace()))
277+ is_long_word_boundary(peek, *next_peek)
278+ && (char_is_line_ending(*next_peek) || !next_peek.is_whitespace())
283279 }
284280 WordMotionTarget::NextLongWordEnd | WordMotionTarget::PrevLongWordStart => {
285− (is_long_word_boundary(peek, *next_peek)
286− && (!peek.is_whitespace() || char_is_line_ending(*next_peek)))
281+ is_long_word_boundary(peek, *next_peek)
282+ && (!peek.is_whitespace() || char_is_line_ending(*next_peek))
287283 }
288284 }
289285}
helix-core/src/object.rs−1
@@ -1,5 +1,4 @@
11use crate::{Range, RopeSlice, Selection, Syntax};
2−use smallvec::smallvec;
32
43// TODO: to contract_selection we'd need to store the previous ranges before expand.
54// Maybe just contract to the first child node?
helix-core/src/position.rs+4−3
@@ -1,7 +1,7 @@
11use crate::{
22 chars::char_is_line_ending,
33 graphemes::{nth_next_grapheme_boundary, RopeGraphemes},
4− Rope, RopeSlice,
4+ RopeSlice,
55};
66
77/// Represents a single point in a text buffer. Zero indexed.
@@ -70,6 +70,7 @@ pub fn pos_at_coords(text: RopeSlice, coords: Position) -> usize {
7070#[cfg(test)]
7171mod test {
7272 use super::*;
73+ use crate::Rope;
7374
7475 #[test]
7576 fn test_ordering() {
@@ -79,8 +80,8 @@ mod test {
7980
8081 #[test]
8182 fn test_coords_at_pos() {
82− let text = Rope::from("ḧëḷḷö\nẅöṛḷḋ");
83− let slice = text.slice(..);
83+ // let text = Rope::from("ḧëḷḷö\nẅöṛḷḋ");
84+ // let slice = text.slice(..);
8485 // assert_eq!(coords_at_pos(slice, 0), (0, 0).into());
8586 // assert_eq!(coords_at_pos(slice, 5), (0, 5).into()); // position on \n
8687 // 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::{
66 graphemes::{
77 ensure_grapheme_boundary_next, ensure_grapheme_boundary_prev, next_grapheme_boundary,
88 },
9− Assoc, ChangeSet, Rope, RopeSlice,
9+ Assoc, ChangeSet, RopeSlice,
1010};
1111use smallvec::{smallvec, SmallVec};
1212use std::borrow::Cow;
@@ -426,10 +426,8 @@ pub fn select_on_matches(
426426 // TODO: can't avoid occasional allocations since Regex can't operate on chunks yet
427427 let fragment = sel.fragment(text);
428428
429− let mut sel_start = sel.from();
430− let sel_end = sel.to();
431−
432− let mut start_byte = text.char_to_byte(sel_start);
429+ let sel_start = sel.from();
430+ let start_byte = text.char_to_byte(sel_start);
433431
434432 for mat in regex.find_iter(&fragment) {
435433 // TODO: retain range direction
@@ -466,10 +464,10 @@ pub fn split_on_matches(
466464 // TODO: can't avoid occasional allocations since Regex can't operate on chunks yet
467465 let fragment = sel.fragment(text);
468466
469− let mut sel_start = sel.from();
467+ let sel_start = sel.from();
470468 let sel_end = sel.to();
471469
472− let mut start_byte = text.char_to_byte(sel_start);
470+ let start_byte = text.char_to_byte(sel_start);
473471
474472 let mut start = sel_start;
475473
@@ -492,11 +490,12 @@ pub fn split_on_matches(
492490#[cfg(test)]
493491mod test {
494492 use super::*;
493+ use crate::Rope;
495494
496495 #[test]
497496 #[should_panic]
498497 fn test_new_empty() {
499− let sel = Selection::new(smallvec![], 0);
498+ let _ = Selection::new(smallvec![], 0);
500499 }
501500
502501 #[test]
helix-core/src/syntax.rs+157−158
@@ -1,4 +1,10 @@
1−use crate::{chars::char_is_line_ending, regex::Regex, Change, Rope, RopeSlice, Transaction};
1+use crate::{
2+ chars::char_is_line_ending,
3+ regex::Regex,
4+ transaction::{ChangeSet, Operation},
5+ Rope, RopeSlice, Tendril,
6+};
7+
28pub use helix_syntax::{get_language, get_language_name, Lang};
39
410use arc_swap::ArcSwap;
@@ -8,7 +14,7 @@ use std::{
814 cell::RefCell,
915 collections::{HashMap, HashSet},
1016 fmt,
11− path::{Path, PathBuf},
17+ path::Path,
1218 sync::Arc,
1319};
1420
@@ -160,7 +166,7 @@ impl LanguageConfiguration {
160166 None
161167 } else {
162168 let language = get_language(self.language_id);
163− let mut config = HighlightConfiguration::new(
169+ let config = HighlightConfiguration::new(
164170 language,
165171 &highlights_query,
166172 &injections_query,
@@ -326,7 +332,8 @@ impl Syntax {
326332
327333 // update root layer
328334 PARSER.with(|ts_parser| {
329− syntax.root_layer.parse(
335+ // TODO: handle the returned `Result` properly.
336+ let _ = syntax.root_layer.parse(
330337 &mut ts_parser.borrow_mut(),
331338 &syntax.config,
332339 source,
@@ -381,7 +388,7 @@ impl Syntax {
381388 source: RopeSlice<'a>,
382389 range: Option<std::ops::Range<usize>>,
383390 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,
385392 ) -> impl Iterator<Item = Result<HighlightEvent, Error>> + 'a {
386393 // The `captures` iterator borrows the `Tree` and the `QueryCursor`, which
387394 // prevents them from being moved. But both of these values are really just
@@ -473,12 +480,6 @@ pub struct LanguageLayer {
473480 pub(crate) tree: Option<Tree>,
474481}
475482
476−use crate::{
477− coords_at_pos,
478− transaction::{ChangeSet, Operation},
479− Tendril,
480−};
481−
482483impl LanguageLayer {
483484 // pub fn new() -> Self {
484485 // Self { tree: None }
@@ -494,8 +495,8 @@ impl LanguageLayer {
494495 ts_parser: &mut TsParser,
495496 config: &HighlightConfiguration,
496497 source: &Rope,
497− mut depth: usize,
498− mut ranges: Vec<Range>,
498+ _depth: usize,
499+ ranges: Vec<Range>,
499500 ) -> Result<(), Error> {
500501 if ts_parser.parser.set_included_ranges(&ranges).is_ok() {
501502 ts_parser
@@ -566,7 +567,6 @@ impl LanguageLayer {
566567 ) -> Vec<tree_sitter::InputEdit> {
567568 use Operation::*;
568569 let mut old_pos = 0;
569− let mut new_pos = 0;
570570
571571 let mut edits = Vec::new();
572572
@@ -610,9 +610,7 @@ impl LanguageLayer {
610610 let mut old_end = old_pos + len;
611611
612612 match change {
613− Retain(_) => {
614− new_pos += len;
615− }
613+ Retain(_) => {}
616614 Delete(_) => {
617615 let (start_byte, start_position) = point_at_pos(old_text, old_pos);
618616 let (old_end_byte, old_end_position) = point_at_pos(old_text, old_end);
@@ -636,8 +634,6 @@ impl LanguageLayer {
636634 Insert(s) => {
637635 let (start_byte, start_position) = point_at_pos(old_text, old_pos);
638636
639− let ins = s.chars().count();
640−
641637 // a subsequent delete means a replace, consume it
642638 if let Some(Delete(len)) = iter.peek() {
643639 old_end = old_pos + len;
@@ -665,8 +661,6 @@ impl LanguageLayer {
665661 new_end_position: traverse(start_position, s), // old pos + chars, newlines matter too (iter over)
666662 });
667663 }
668−
669− new_pos += ins;
670664 }
671665 }
672666 old_pos = old_end;
@@ -1480,7 +1474,6 @@ where
14801474 // local scope at the top of the scope stack.
14811475 else if Some(capture.index) == layer.config.local_def_capture_index {
14821476 reference_highlight = None;
1483− definition_highlight = None;
14841477 let scope = layer.scope_stack.last_mut().unwrap();
14851478
14861479 let mut value_range = 0..0;
@@ -1644,13 +1637,13 @@ fn injection_for_match<'a>(
16441637 (language_name, content_node, include_children)
16451638}
16461639
1647−fn shrink_and_clear<T>(vec: &mut Vec<T>, capacity: usize) {
1648− if vec.len() > capacity {
1649− vec.truncate(capacity);
1650− vec.shrink_to_fit();
1651− }
1652− vec.clear();
1653−}
1640+// fn shrink_and_clear<T>(vec: &mut Vec<T>, capacity: usize) {
1641+// if vec.len() > capacity {
1642+// vec.truncate(capacity);
1643+// vec.shrink_to_fit();
1644+// }
1645+// vec.clear();
1646+// }
16541647
16551648pub struct Merge<I> {
16561649 iter: I,
@@ -1691,7 +1684,7 @@ impl<I: Iterator<Item = HighlightEvent>> Iterator for Merge<I> {
16911684 loop {
16921685 match (self.next_event, &self.next_span) {
16931686 // 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 => {
16951688 if start > range.end {
16961689 self.next_span = self.spans.next();
16971690 } else {
@@ -1711,7 +1704,7 @@ impl<I: Iterator<Item = HighlightEvent>> Iterator for Merge<I> {
17111704 self.next_event = self.iter.next();
17121705 Some(HighlightEnd)
17131706 }
1714− (Some(Source { start, end }), Some((span, range))) if start < range.start => {
1707+ (Some(Source { start, end }), Some((_, range))) if start < range.start => {
17151708 let intersect = range.start.min(end);
17161709 let event = Source {
17171710 start,
@@ -1766,7 +1759,7 @@ impl<I: Iterator<Item = HighlightEvent>> Iterator for Merge<I> {
17661759 Some(event)
17671760 }
17681761 // can happen if deleting and cursor at EOF, and diagnostic reaches past the end
1769− (None, Some((span, range))) => {
1762+ (None, Some((_, _))) => {
17701763 self.next_span = None;
17711764 None
17721765 }
@@ -1776,135 +1769,141 @@ impl<I: Iterator<Item = HighlightEvent>> Iterator for Merge<I> {
17761769 }
17771770}
17781771
1779−#[test]
1780−fn test_parser() {
1781− let highlight_names: Vec<String> = [
1782− "attribute",
1783− "constant",
1784− "function.builtin",
1785− "function",
1786− "keyword",
1787− "operator",
1788− "property",
1789− "punctuation",
1790− "punctuation.bracket",
1791− "punctuation.delimiter",
1792− "string",
1793− "string.special",
1794− "tag",
1795− "type",
1796− "type.builtin",
1797− "variable",
1798− "variable.builtin",
1799− "variable.parameter",
1800− ]
1801− .iter()
1802− .cloned()
1803− .map(String::from)
1804− .collect();
1805−
1806− let language = get_language(Lang::Rust);
1807− let mut config = HighlightConfiguration::new(
1808− language,
1809− &std::fs::read_to_string(
1810− "../helix-syntax/languages/tree-sitter-rust/queries/highlights.scm",
1811− )
1812− .unwrap(),
1813− &std::fs::read_to_string(
1814− "../helix-syntax/languages/tree-sitter-rust/queries/injections.scm",
1815− )
1816− .unwrap(),
1817− "", // 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)))"
1772+#[cfg(test)]
1773+mod test {
1774+ use super::*;
1775+ use crate::{Rope, Transaction};
1776+
1777+ #[test]
1778+ fn test_parser() {
1779+ let highlight_names: Vec<String> = [
1780+ "attribute",
1781+ "constant",
1782+ "function.builtin",
1783+ "function",
1784+ "keyword",
1785+ "operator",
1786+ "property",
1787+ "punctuation",
1788+ "punctuation.bracket",
1789+ "punctuation.delimiter",
1790+ "string",
1791+ "string.special",
1792+ "tag",
1793+ "type",
1794+ "type.builtin",
1795+ "variable",
1796+ "variable.builtin",
1797+ "variable.parameter",
1798+ ]
1799+ .iter()
1800+ .cloned()
1801+ .map(String::from)
1802+ .collect();
1803+
1804+ let language = get_language(Lang::Rust);
1805+ let config = HighlightConfiguration::new(
1806+ language,
1807+ &std::fs::read_to_string(
1808+ "../helix-syntax/languages/tree-sitter-rust/queries/highlights.scm",
1809+ )
1810+ .unwrap(),
1811+ &std::fs::read_to_string(
1812+ "../helix-syntax/languages/tree-sitter-rust/queries/injections.scm",
1813+ )
1814+ .unwrap(),
1815+ "", // locals.scm
18391816 )
1840− );
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+ )
1838+ );
18411839
1842− let struct_node = root.child(0).unwrap();
1843− assert_eq!(struct_node.kind(), "struct_item");
1844−}
1840+ let struct_node = root.child(0).unwrap();
1841+ assert_eq!(struct_node.kind(), "struct_item");
1842+ }
18451843
1846−#[test]
1847−fn test_input_edits() {
1848− use crate::State;
1849− use tree_sitter::InputEdit;
1850−
1851− let mut state = State::new("hello world!\ntest 123".into());
1852− let transaction = Transaction::change(
1853− &state.doc,
1854− vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
1855− );
1856− let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
1857− // transaction.apply(&mut state);
1858−
1859− assert_eq!(
1860− edits,
1861− &[
1862− InputEdit {
1863− start_byte: 6,
1864− old_end_byte: 11,
1865− new_end_byte: 10,
1866− start_position: Point { row: 0, column: 6 },
1867− old_end_position: Point { row: 0, column: 11 },
1868− new_end_position: Point { row: 0, column: 10 }
1869− },
1870− InputEdit {
1871− start_byte: 12,
1872− old_end_byte: 17,
1873− new_end_byte: 12,
1874− start_position: Point { row: 0, column: 12 },
1875− old_end_position: Point { row: 1, column: 4 },
1876− new_end_position: Point { row: 0, column: 12 }
1877− }
1878− ]
1879− );
1880−
1881− // Testing with the official example from tree-sitter
1882− let mut state = State::new("fn test() {}".into());
1883− let transaction =
1884− Transaction::change(&state.doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
1885− let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
1886− transaction.apply(&mut state.doc);
1887−
1888− assert_eq!(state.doc, "fn test(a: u32) {}");
1889− assert_eq!(
1890− edits,
1891− &[InputEdit {
1892− start_byte: 8,
1893− old_end_byte: 8,
1894− new_end_byte: 14,
1895− start_position: Point { row: 0, column: 8 },
1896− old_end_position: Point { row: 0, column: 8 },
1897− new_end_position: Point { row: 0, column: 14 }
1898− }]
1899− );
1900−}
1844+ #[test]
1845+ fn test_input_edits() {
1846+ use crate::State;
1847+ use tree_sitter::InputEdit;
1848+
1849+ let state = State::new("hello world!\ntest 123".into());
1850+ let transaction = Transaction::change(
1851+ &state.doc,
1852+ vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
1853+ );
1854+ let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
1855+ // transaction.apply(&mut state);
1856+
1857+ assert_eq!(
1858+ edits,
1859+ &[
1860+ InputEdit {
1861+ start_byte: 6,
1862+ old_end_byte: 11,
1863+ new_end_byte: 10,
1864+ start_position: Point { row: 0, column: 6 },
1865+ old_end_position: Point { row: 0, column: 11 },
1866+ new_end_position: Point { row: 0, column: 10 }
1867+ },
1868+ InputEdit {
1869+ start_byte: 12,
1870+ old_end_byte: 17,
1871+ new_end_byte: 12,
1872+ start_position: Point { row: 0, column: 12 },
1873+ old_end_position: Point { row: 1, column: 4 },
1874+ new_end_position: Point { row: 0, column: 12 }
1875+ }
1876+ ]
1877+ );
1878+
1879+ // Testing with the official example from tree-sitter
1880+ let mut state = State::new("fn test() {}".into());
1881+ let transaction =
1882+ Transaction::change(&state.doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
1883+ let edits = LanguageLayer::generate_edits(state.doc.slice(..), transaction.changes());
1884+ transaction.apply(&mut state.doc);
1885+
1886+ assert_eq!(state.doc, "fn test(a: u32) {}");
1887+ assert_eq!(
1888+ edits,
1889+ &[InputEdit {
1890+ start_byte: 8,
1891+ old_end_byte: 8,
1892+ new_end_byte: 14,
1893+ start_position: Point { row: 0, column: 8 },
1894+ old_end_position: Point { row: 0, column: 8 },
1895+ new_end_position: Point { row: 0, column: 14 }
1896+ }]
1897+ );
1898+ }
19011899
1902−#[test]
1903−fn test_load_runtime_file() {
1904− // Test to make sure we can load some data from the runtime directory.
1905− let contents = load_runtime_file("rust", "indents.toml").unwrap();
1906− assert!(!contents.is_empty());
1900+ #[test]
1901+ fn test_load_runtime_file() {
1902+ // Test to make sure we can load some data from the runtime directory.
1903+ let contents = load_runtime_file("rust", "indents.toml").unwrap();
1904+ assert!(!contents.is_empty());
19071905
1908− let results = load_runtime_file("rust", "does-not-exist");
1909− assert!(results.is_err());
1906+ let results = load_runtime_file("rust", "does-not-exist");
1907+ assert!(results.is_err());
1908+ }
19101909}
helix-core/src/transaction.rs+9−9
@@ -1,5 +1,5 @@
1−use crate::{Range, Rope, Selection, State, Tendril};
2−use std::{borrow::Cow, convert::TryFrom};
1+use crate::{Range, Rope, Selection, Tendril};
2+use std::borrow::Cow;
33
44/// (from, to, replacement)
55pub type Change = (usize, usize, Option<Tendril>);
@@ -163,7 +163,7 @@ impl ChangeSet {
163163 head_a = a;
164164 head_b = changes_b.next();
165165 }
166− (None, val) | (val, None) => return unreachable!("({:?})", val),
166+ (None, val) | (val, None) => unreachable!("({:?})", val),
167167 (Some(Retain(i)), Some(Retain(j))) => match i.cmp(&j) {
168168 Ordering::Less => {
169169 changes.retain(i);
@@ -202,7 +202,7 @@ impl ChangeSet {
202202 }
203203 }
204204 }
205− (Some(Insert(mut s)), Some(Retain(j))) => {
205+ (Some(Insert(s)), Some(Retain(j))) => {
206206 let len = s.chars().count();
207207 match len.cmp(&j) {
208208 Ordering::Less => {
@@ -274,7 +274,6 @@ impl ChangeSet {
274274 let mut changes = Self::with_capacity(self.changes.len());
275275
276276 let mut pos = 0;
277− let mut len = 0;
278277
279278 for change in &self.changes {
280279 use Operation::*;
@@ -581,6 +580,7 @@ impl<'a> Iterator for ChangeIterator<'a> {
581580#[cfg(test)]
582581mod test {
583582 use super::*;
583+ use crate::State;
584584
585585 #[test]
586586 fn composition() {
@@ -699,7 +699,7 @@ mod test {
699699
700700 #[test]
701701 fn changes_iter() {
702− let mut state = State::new("hello world!\ntest 123".into());
702+ let state = State::new("hello world!\ntest 123".into());
703703 let changes = vec![(6, 11, Some("void".into())), (12, 17, None)];
704704 let transaction = Transaction::change(&state.doc, changes.clone().into_iter());
705705 assert_eq!(transaction.changes_iter().collect::<Vec<_>>(), changes);
@@ -731,7 +731,7 @@ mod test {
731731 // retain 1, e
732732 // retain 2, l
733733
734− let mut changes = t1
734+ let changes = t1
735735 .changes
736736 .compose(t2.changes)
737737 .compose(t3.changes)
@@ -746,7 +746,7 @@ mod test {
746746 #[test]
747747 fn combine_with_empty() {
748748 let empty = Rope::from("");
749− let mut a = ChangeSet::new(&empty);
749+ let a = ChangeSet::new(&empty);
750750
751751 let mut b = ChangeSet::new(&empty);
752752 b.insert("a".into());
@@ -762,7 +762,7 @@ mod test {
762762 const TEST_CASE: &'static str = "Hello, これはヘリックスエディターです!";
763763
764764 let empty = Rope::from("");
765− let mut a = ChangeSet::new(&empty);
765+ let a = ChangeSet::new(&empty);
766766
767767 let mut b = ChangeSet::new(&empty);
768768 b.insert(TEST_CASE.into());
helix-term/src/application.rs+26−35
@@ -1,37 +1,23 @@
11use helix_core::syntax;
2−use helix_lsp::{lsp, LspProgressMap};
3−use helix_view::{document::Mode, graphics::Rect, theme, Document, Editor, Theme, View};
4−
5−use crate::{
6− args::Args,
7− compositor::Compositor,
8− config::Config,
9− job::Jobs,
10− keymap::Keymaps,
11− ui::{self, Spinner},
12−};
2+use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
3+use helix_view::{theme, Editor};
4+
5+use crate::{args::Args, compositor::Compositor, config::Config, job::Jobs, ui};
136
14−use log::{error, info};
7+use log::error;
158
169use std::{
17− collections::HashMap,
18− future::Future,
19− io::{self, stdout, Stdout, Write},
20− path::PathBuf,
21− pin::Pin,
10+ io::{stdout, Write},
2211 sync::Arc,
23− time::Duration,
2412};
2513
26−use anyhow::{Context, Error};
14+use anyhow::Error;
2715
2816use crossterm::{
2917 event::{Event, EventStream},
3018 execute, terminal,
3119};
3220
33−use futures_util::{future, stream::FuturesUnordered};
34−
3521pub struct Application {
3622 compositor: Compositor,
3723 editor: Editor,
@@ -39,7 +25,14 @@ pub struct Application {
3925 // TODO should be separate to take only part of the config
4026 config: Config,
4127
28+ // Currently never read from. Remove the `allow(dead_code)` when
29+ // that changes.
30+ #[allow(dead_code)]
4231 theme_loader: Arc<theme::Loader>,
32+
33+ // Currently never read from. Remove the `allow(dead_code)` when
34+ // that changes.
35+ #[allow(dead_code)]
4336 syn_loader: Arc<syntax::Loader>,
4437
4538 jobs: Jobs,
@@ -47,7 +40,7 @@ pub struct Application {
4740}
4841
4942impl 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> {
5144 use helix_view::editor::Action;
5245 let mut compositor = Compositor::new()?;
5346 let size = compositor.size();
@@ -80,7 +73,7 @@ impl Application {
8073
8174 let mut editor = Editor::new(size, theme_loader.clone(), syn_loader.clone());
8275
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)));
8477 compositor.push(editor_view);
8578
8679 if !args.files.is_empty() {
@@ -105,7 +98,7 @@ impl Application {
10598
10699 editor.set_theme(theme);
107100
108− let mut app = Self {
101+ let app = Self {
109102 compositor,
110103 editor,
111104
@@ -239,10 +232,9 @@ impl Application {
239232 .into_iter()
240233 .filter_map(|diagnostic| {
241234 use helix_core::{
242− diagnostic::{Range, Severity, Severity::*},
235+ diagnostic::{Range, Severity::*},
243236 Diagnostic,
244237 };
245− use helix_lsp::{lsp, util::lsp_pos_to_pos};
246238 use lsp::DiagnosticSeverity;
247239
248240 let language_server = doc.language_server().unwrap();
@@ -372,14 +364,10 @@ impl Application {
372364 self.editor.set_status(status);
373365 }
374366 }
375− _ => unreachable!(),
376367 }
377368 }
378369 Call::MethodCall(helix_lsp::jsonrpc::MethodCall {
379− method,
380− params,
381− jsonrpc,
382− id,
370+ method, params, id, ..
383371 }) => {
384372 let call = match MethodCall::parse(&method, params) {
385373 Some(call) => call,
@@ -459,17 +447,20 @@ impl Application {
459447 // Exit the alternate screen and disable raw mode before panicking
460448 let hook = std::panic::take_hook();
461449 std::panic::set_hook(Box::new(move |info| {
462− execute!(std::io::stdout(), terminal::LeaveAlternateScreen);
463− terminal::disable_raw_mode();
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.
453+ let _ = execute!(std::io::stdout(), terminal::LeaveAlternateScreen);
454+ let _ = terminal::disable_raw_mode();
464455 hook(info);
465456 }));
466457
467458 self.event_loop().await;
468459
469− self.editor.close_language_servers(None).await;
460+ self.editor.close_language_servers(None).await?;
470461
471462 // reset cursor shape
472− write!(stdout, "\x1B[2 q");
463+ write!(stdout, "\x1B[2 q")?;
473464
474465 execute!(stdout, terminal::LeaveAlternateScreen)?;
475466
helix-term/src/commands.rs+70−81
@@ -1,20 +1,21 @@
11use helix_core::{
22 comment, coords_at_pos, find_first_non_whitespace_char, find_root, graphemes, indent,
33 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,
55 str_is_line_ending,
66 },
77 match_brackets,
88 movement::{self, Direction},
99 object, pos_at_coords,
1010 regex::{self, Regex},
11− register::{self, Register, Registers},
12− search, selection, Change, ChangeSet, LineEnding, Position, Range, Rope, RopeGraphemes,
13− RopeSlice, Selection, SmallVec, Tendril, Transaction, DEFAULT_LINE_ENDING,
11+ register::Register,
12+ search, selection, LineEnding, Position, Range, Rope, RopeGraphemes, RopeSlice, Selection,
13+ SmallVec, Tendril, Transaction,
1414};
1515
1616use helix_view::{
1717 document::{IndentStyle, Mode},
18+ editor::Action,
1819 input::KeyEvent,
1920 keyboard::KeyCode,
2021 view::{View, PADDING},
@@ -25,19 +26,19 @@ use anyhow::anyhow;
2526use helix_lsp::{
2627 lsp,
2728 util::{lsp_pos_to_pos, lsp_range_to_range, pos_to_lsp_pos, range_to_lsp_range},
28− LspProgressMap, OffsetEncoding,
29+ OffsetEncoding,
2930};
3031use insert::*;
3132use movement::Movement;
3233
3334use crate::{
34− compositor::{self, Callback, Component, Compositor},
35− ui::{self, Completion, Picker, Popup, Prompt, PromptEvent},
35+ compositor::{self, Component, Compositor},
36+ ui::{self, Picker, Popup, Prompt, PromptEvent},
3637};
3738
38−use crate::job::{self, Job, JobFuture, Jobs};
39+use crate::job::{self, Job, Jobs};
3940use futures_util::{FutureExt, TryFutureExt};
40−use std::{fmt, future::Future, path::Display, str::FromStr};
41+use std::{fmt, future::Future};
4142
4243use std::{
4344 borrow::Cow,
@@ -59,7 +60,7 @@ pub struct Context<'a> {
5960
6061impl<'a> Context<'a> {
6162 /// 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>) {
6364 self.callback = Some(Box::new(|compositor: &mut Compositor| {
6465 compositor.push(component)
6566 }));
@@ -515,7 +516,7 @@ fn extend_next_word_start(cx: &mut Context) {
515516 let (view, doc) = current!(cx.editor);
516517 doc.set_selection(
517518 view.id,
518− doc.selection(view.id).clone().transform(|mut range| {
519+ doc.selection(view.id).clone().transform(|range| {
519520 let word = movement::move_next_word_start(doc.text().slice(..), range, count);
520521 let pos = word.head;
521522 Range::new(range.anchor, pos)
@@ -528,7 +529,7 @@ fn extend_prev_word_start(cx: &mut Context) {
528529 let (view, doc) = current!(cx.editor);
529530 doc.set_selection(
530531 view.id,
531− doc.selection(view.id).clone().transform(|mut range| {
532+ doc.selection(view.id).clone().transform(|range| {
532533 let word = movement::move_prev_word_start(doc.text().slice(..), range, count);
533534 let pos = word.head;
534535 Range::new(range.anchor, pos)
@@ -541,7 +542,7 @@ fn extend_next_word_end(cx: &mut Context) {
541542 let (view, doc) = current!(cx.editor);
542543 doc.set_selection(
543544 view.id,
544− doc.selection(view.id).clone().transform(|mut range| {
545+ doc.selection(view.id).clone().transform(|range| {
545546 let word = movement::move_next_word_end(doc.text().slice(..), range, count);
546547 let pos = word.head;
547548 Range::new(range.anchor, pos)
@@ -592,7 +593,7 @@ where
592593
593594 doc.set_selection(
594595 view.id,
595− doc.selection(view.id).clone().transform(|mut range| {
596+ doc.selection(view.id).clone().transform(|range| {
596597 search_fn(doc.text().slice(..), ch, range.head, count, inclusive).map_or(
597598 range,
598599 |pos| {
@@ -986,7 +987,7 @@ fn search_impl(doc: &mut Document, view: &mut View, contents: &str, regex: &Rege
986987
987988// TODO: use one function for search vs extend
988989fn search(cx: &mut Context) {
989− let (view, doc) = current!(cx.editor);
990+ let (_, doc) = current!(cx.editor);
990991
991992 // TODO: could probably share with select_on_matches?
992993
@@ -994,7 +995,6 @@ fn search(cx: &mut Context) {
994995 // feed chunks into the regex yet
995996 let contents = doc.text().slice(..).to_string();
996997
997− let view_id = view.id;
998998 let prompt = ui::regex_prompt(
999999 cx,
10001000 "search:".to_string(),
@@ -1046,7 +1046,7 @@ fn extend_line(cx: &mut Context) {
10461046 let line_start = text.char_to_line(pos.anchor);
10471047 let start = text.line_to_char(line_start);
10481048 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));
10501050
10511051 if pos.anchor == start && pos.head == end && line_end < (text.len_lines() - 2) {
10521052 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
10651065
10661066 // then delete
10671067 let transaction = Transaction::change_by_selection(doc.text(), &selection, |range| {
1068− let line = text.char_to_line(range.head);
10691068 (range.from(), range.to(), None)
10701069 });
10711070 doc.apply(&transaction, view_id);
@@ -1175,7 +1174,7 @@ mod cmd {
11751174 pub completer: Option<Completer>,
11761175 }
11771176
1178− fn quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1177+ fn quit(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
11791178 // last view and we have unsaved changes
11801179 if cx.editor.tree.views().count() == 1 && buffers_remaining_impl(cx.editor) {
11811180 return;
@@ -1184,16 +1183,16 @@ mod cmd {
11841183 .close(view!(cx.editor).id, /* close_buffer */ false);
11851184 }
11861185
1187− fn force_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1186+ fn force_quit(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
11881187 cx.editor
11891188 .close(view!(cx.editor).id, /* close_buffer */ false);
11901189 }
11911190
1192− fn open(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1191+ fn open(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
11931192 match args.get(0) {
11941193 Some(path) => {
11951194 // TODO: handle error
1196− cx.editor.open(path.into(), Action::Replace);
1195+ let _ = cx.editor.open(path.into(), Action::Replace);
11971196 }
11981197 None => {
11991198 cx.editor.set_error("wrong argument count".to_string());
@@ -1205,9 +1204,8 @@ mod cmd {
12051204 cx: &mut compositor::Context,
12061205 path: Option<P>,
12071206 ) -> Result<tokio::task::JoinHandle<Result<(), anyhow::Error>>, anyhow::Error> {
1208− use anyhow::anyhow;
12091207 let jobs = &mut cx.jobs;
1210− let (view, doc) = current!(cx.editor);
1208+ let (_, doc) = current!(cx.editor);
12111209
12121210 if let Some(path) = path {
12131211 if let Err(err) = doc.set_path(path.as_ref()) {
@@ -1231,7 +1229,7 @@ mod cmd {
12311229 Ok(tokio::spawn(doc.format_and_save(fmt)))
12321230 }
12331231
1234− fn write(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1232+ fn write(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
12351233 match write_impl(cx, args.first()) {
12361234 Err(e) => cx.editor.set_error(e.to_string()),
12371235 Ok(handle) => {
@@ -1241,11 +1239,11 @@ mod cmd {
12411239 };
12421240 }
12431241
1244− fn new_file(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1242+ fn new_file(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
12451243 cx.editor.new_file(Action::Replace);
12461244 }
12471245
1248− fn format(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1246+ fn format(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
12491247 let (_, doc) = current!(cx.editor);
12501248
12511249 if let Some(format) = doc.format() {
@@ -1255,7 +1253,7 @@ mod cmd {
12551253 }
12561254 }
12571255
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) {
12591257 use IndentStyle::*;
12601258
12611259 // If no argument, report current indent style.
@@ -1293,7 +1291,7 @@ mod cmd {
12931291 }
12941292
12951293 /// 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) {
12971295 use LineEnding::*;
12981296
12991297 // If no argument, report current line ending setting.
@@ -1332,7 +1330,7 @@ mod cmd {
13321330 }
13331331 }
13341332
1335− fn earlier(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1333+ fn earlier(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
13361334 let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
13371335 Ok(uk) => uk,
13381336 Err(msg) => {
@@ -1344,7 +1342,7 @@ mod cmd {
13441342 doc.earlier(view.id, uk)
13451343 }
13461344
1347− fn later(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1345+ fn later(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
13481346 let uk = match args.join(" ").parse::<helix_core::history::UndoKind>() {
13491347 Ok(uk) => uk,
13501348 Err(msg) => {
@@ -1372,7 +1370,6 @@ mod cmd {
13721370 }
13731371
13741372 fn force_write_quit(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1375− let (view, doc) = current!(cx.editor);
13761373 match write_impl(cx, args.first()) {
13771374 Ok(handle) => {
13781375 if let Err(e) = helix_lsp::block_on(handle) {
@@ -1414,20 +1411,22 @@ mod cmd {
14141411
14151412 fn write_all_impl(
14161413 editor: &mut Editor,
1417− args: &[&str],
1418− event: PromptEvent,
1414+ _args: &[&str],
1415+ _event: PromptEvent,
14191416 quit: bool,
14201417 force: bool,
14211418 ) {
14221419 let mut errors = String::new();
14231420
14241421 // save all documents
1425− for (id, mut doc) in &mut editor.documents {
1422+ for (_, doc) in &mut editor.documents {
14261423 if doc.path().is_none() {
14271424 errors.push_str("cannot write a buffer without a filename\n");
14281425 continue;
14291426 }
1430− helix_lsp::block_on(tokio::spawn(doc.save()));
1427+
1428+ // TODO: handle error.
1429+ let _ = helix_lsp::block_on(tokio::spawn(doc.save()));
14311430 }
14321431 editor.set_error(errors);
14331432
@@ -1456,7 +1455,7 @@ mod cmd {
14561455 write_all_impl(&mut cx.editor, args, event, true, true)
14571456 }
14581457
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) {
14601459 if !force && buffers_remaining_impl(editor) {
14611460 return;
14621461 }
@@ -1476,7 +1475,7 @@ mod cmd {
14761475 quit_all_impl(&mut cx.editor, args, event, true)
14771476 }
14781477
1479− fn theme(cx: &mut compositor::Context, args: &[&str], event: PromptEvent) {
1478+ fn theme(cx: &mut compositor::Context, args: &[&str], _event: PromptEvent) {
14801479 let theme = if let Some(theme) = args.first() {
14811480 theme
14821481 } else {
@@ -1487,11 +1486,15 @@ mod cmd {
14871486 cx.editor.set_theme_from_name(theme);
14881487 }
14891488
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+ ) {
14911494 yank_main_selection_to_clipboard_impl(&mut cx.editor);
14921495 }
14931496
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) {
14951498 let (_, doc) = current!(cx.editor);
14961499 let separator = args
14971500 .first()
@@ -1500,15 +1503,19 @@ mod cmd {
15001503 yank_joined_to_clipboard_impl(&mut cx.editor, separator);
15011504 }
15021505
1503− fn paste_clipboard_after(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
1506+ fn paste_clipboard_after(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
15041507 paste_clipboard_impl(&mut cx.editor, Paste::After);
15051508 }
15061509
1507− fn paste_clipboard_before(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
1510+ fn paste_clipboard_before(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
15081511 paste_clipboard_impl(&mut cx.editor, Paste::After);
15091512 }
15101513
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+ ) {
15121519 let (view, doc) = current!(cx.editor);
15131520
15141521 match cx.editor.clipboard_provider.get_contents() {
@@ -1529,12 +1536,12 @@ mod cmd {
15291536 }
15301537 }
15311538
1532− fn show_clipboard_provider(cx: &mut compositor::Context, _: &[&str], _: PromptEvent) {
1539+ fn show_clipboard_provider(cx: &mut compositor::Context, _args: &[&str], _event: PromptEvent) {
15331540 cx.editor
15341541 .set_status(cx.editor.clipboard_provider.name().into());
15351542 }
15361543
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) {
15381545 let dir = match args.first() {
15391546 Some(dir) => dir,
15401547 None => {
@@ -1562,7 +1569,7 @@ mod cmd {
15621569 }
15631570 }
15641571
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) {
15661573 match std::env::current_dir() {
15671574 Ok(cwd) => cx
15681575 .editor
@@ -1782,7 +1789,6 @@ fn command_mode(cx: &mut Context) {
17821789 // simple heuristic: if there's no just one part, complete command name.
17831790 // if there's a space, per command completion kicks in.
17841791 if parts.len() <= 1 {
1785− use std::{borrow::Cow, ops::Range};
17861792 let end = 0..;
17871793 cmd::TYPABLE_COMMAND_LIST
17881794 .iter()
@@ -1812,8 +1818,6 @@ fn command_mode(cx: &mut Context) {
18121818 }
18131819 }, // completion
18141820 move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
1815− use helix_view::editor::Action;
1816−
18171821 if event != PromptEvent::Validate {
18181822 return;
18191823 }
@@ -1851,7 +1855,6 @@ fn file_picker(cx: &mut Context) {
18511855}
18521856
18531857fn buffer_picker(cx: &mut Context) {
1854− use std::path::{Path, PathBuf};
18551858 let current = view!(cx.editor).doc;
18561859
18571860 let picker = Picker::new(
@@ -1874,7 +1877,6 @@ fn buffer_picker(cx: &mut Context) {
18741877 }
18751878 },
18761879 |editor: &mut Editor, (id, _path): &(DocumentId, Option<PathBuf>), _action| {
1877− use helix_view::editor::Action;
18781880 editor.switch(*id, Action::Replace);
18791881 },
18801882 );
@@ -1900,7 +1902,7 @@ fn symbol_picker(cx: &mut Context) {
19001902 nested_to_flat(list, file, child);
19011903 }
19021904 }
1903− let (view, doc) = current!(cx.editor);
1905+ let (_, doc) = current!(cx.editor);
19041906
19051907 let language_server = match doc.language_server() {
19061908 Some(language_server) => language_server,
@@ -1993,7 +1995,7 @@ async fn make_format_callback(
19931995 format: impl Future<Output = helix_lsp::util::LspFormatting> + Send + 'static,
19941996) -> anyhow::Result<job::Callback> {
19951997 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| {
19971999 let view_id = view!(editor).id;
19982000 if let Some(doc) = editor.document_mut(doc_id) {
19992001 if doc.version() == doc_version {
@@ -2168,9 +2170,6 @@ fn goto_mode(cx: &mut Context) {
21682170 (_, 't') | (_, 'm') | (_, 'b') => {
21692171 let (view, doc) = current!(cx.editor);
21702172
2171− let pos = doc.selection(view.id).cursor();
2172− let line = doc.text().char_to_line(pos);
2173−
21742173 let scrolloff = PADDING.min(view.area.height as usize / 2); // TODO: user pref
21752174
21762175 let last_line = view.last_line(doc);
@@ -2207,8 +2206,6 @@ fn goto_impl(
22072206 locations: Vec<lsp::Location>,
22082207 offset_encoding: OffsetEncoding,
22092208) {
2210− use helix_view::editor::Action;
2211−
22122209 push_jump(editor);
22132210
22142211 fn jump_to(
@@ -2221,7 +2218,7 @@ fn goto_impl(
22212218 .uri
22222219 .to_file_path()
22232220 .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");
22252222 let (view, doc) = current!(editor);
22262223 let definition_pos = location.range.start;
22272224 // TODO: convert inside server
@@ -2243,7 +2240,7 @@ fn goto_impl(
22432240 editor.set_error("No definition found.".to_string());
22442241 }
22452242 _locations => {
2246− let mut picker = ui::Picker::new(
2243+ let picker = ui::Picker::new(
22472244 locations,
22482245 |location| {
22492246 let file = location.uri.as_str();
@@ -2410,9 +2407,8 @@ fn goto_pos(editor: &mut Editor, pos: usize) {
24102407
24112408fn goto_first_diag(cx: &mut Context) {
24122409 let editor = &mut cx.editor;
2413− let (view, doc) = current!(editor);
2410+ let (_, doc) = current!(editor);
24142411
2415− let cursor_pos = doc.selection(view.id).cursor();
24162412 let diag = if let Some(diag) = doc.diagnostics().first() {
24172413 diag.range.start
24182414 } else {
@@ -2424,9 +2420,8 @@ fn goto_first_diag(cx: &mut Context) {
24242420
24252421fn goto_last_diag(cx: &mut Context) {
24262422 let editor = &mut cx.editor;
2427− let (view, doc) = current!(editor);
2423+ let (_, doc) = current!(editor);
24282424
2429− let cursor_pos = doc.selection(view.id).cursor();
24302425 let diag = if let Some(diag) = doc.diagnostics().last() {
24312426 diag.range.start
24322427 } else {
@@ -2498,8 +2493,8 @@ fn signature_help(cx: &mut Context) {
24982493
24992494 cx.callback(
25002495 future,
2501− move |editor: &mut Editor,
2502− compositor: &mut Compositor,
2496+ move |_editor: &mut Editor,
2497+ _compositor: &mut Compositor,
25032498 response: Option<lsp::SignatureHelp>| {
25042499 if let Some(signature_help) = response {
25052500 log::info!("{:?}", signature_help);
@@ -3080,8 +3075,10 @@ fn format_selections(cx: &mut Context) {
30803075 .map(|range| range_to_lsp_range(doc.text(), *range, language_server.offset_encoding()))
30813076 .collect();
30823077
3083− for range in ranges {
3084− let language_server = match doc.language_server() {
3078+ // TODO: all of the TODO's and commented code inside the loop,
3079+ // to make this actually work.
3080+ for _range in ranges {
3081+ let _language_server = match doc.language_server() {
30853082 Some(language_server) => language_server,
30863083 None => return,
30873084 };
@@ -3129,7 +3126,7 @@ fn join_selections(cx: &mut Context) {
31293126 changes.reserve(lines.len());
31303127
31313128 for line in lines {
3132− let mut start = line_end_char_index(&slice, line);
3129+ let start = line_end_char_index(&slice, line);
31333130 let mut end = text.line_to_char(line + 1);
31343131 end = skip_while(slice, end, |ch| matches!(ch, ' ' | '\t')).unwrap_or(end);
31353132
@@ -3252,7 +3249,6 @@ fn completion(cx: &mut Context) {
32523249 if items.is_empty() {
32533250 return;
32543251 }
3255− use crate::compositor::AnyComponent;
32563252 let size = compositor.size();
32573253 let ui = compositor
32583254 .find(std::any::type_name::<ui::EditorView>())
@@ -3306,7 +3302,7 @@ fn hover(cx: &mut Context) {
33063302 // skip if contents empty
33073303
33083304 let contents = ui::Markdown::new(contents, editor.syn_loader.clone());
3309− let mut popup = Popup::new(contents);
3305+ let popup = Popup::new(contents);
33103306 compositor.push(Box::new(popup));
33113307 }
33123308 },
@@ -3350,7 +3346,7 @@ fn match_brackets(cx: &mut Context) {
33503346
33513347fn jump_forward(cx: &mut Context) {
33523348 let count = cx.count();
3353− let (view, doc) = current!(cx.editor);
3349+ let (view, _doc) = current!(cx.editor);
33543350
33553351 if let Some((id, selection)) = view.jumps.forward(count) {
33563352 view.doc = *id;
@@ -3403,11 +3399,7 @@ fn rotate_view(cx: &mut Context) {
34033399}
34043400
34053401// split helper, clear it later
3406−use helix_view::editor::Action;
3407−
3408−use self::cmd::TypableCommand;
34093402fn split(cx: &mut Context, action: Action) {
3410− use helix_view::editor::Action;
34113403 let (view, doc) = current!(cx.editor);
34123404 let id = doc.id();
34133405 let selection = doc.selection(view.id).clone();
@@ -3563,10 +3555,7 @@ fn match_mode(cx: &mut Context) {
35633555 'm' => match_brackets(cx),
35643556 's' => surround_add(cx),
35653557 'r' => surround_replace(cx),
3566− 'd' => {
3567− surround_delete(cx);
3568− let (view, doc) = current!(cx.editor);
3569− }
3558+ 'd' => surround_delete(cx),
35703559 _ => (),
35713560 }
35723561 }
@@ -3588,7 +3577,7 @@ fn surround_add(cx: &mut Context) {
35883577 let (open, close) = surround::get_pair(ch);
35893578
35903579 let mut changes = Vec::new();
3591− for (i, range) in selection.iter().enumerate() {
3580+ for range in selection.iter() {
35923581 changes.push((range.from(), range.from(), Some(Tendril::from_char(open))));
35933582 changes.push((range.to(), range.to(), Some(Tendril::from_char(close))));
35943583 }
helix-term/src/compositor.rs+6−8
@@ -2,7 +2,6 @@
22// Q: how does this work with popups?
33// cursive does compositor.screen_mut().add_layer_at(pos::absolute(x, y), <component>)
44use helix_core::Position;
5−use helix_lsp::LspProgressMap;
65use helix_view::graphics::{CursorKind, Rect};
76
87use crossterm::event::Event;
@@ -36,7 +35,7 @@ pub struct Context<'a> {
3635
3736pub trait Component: Any + AnyComponent {
3837 /// 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 {
4039 EventResult::Ignored
4140 }
4241 // , args: ()
@@ -50,13 +49,13 @@ pub trait Component: Any + AnyComponent {
5049 fn render(&self, area: Rect, frame: &mut Surface, ctx: &mut Context);
5150
5251 /// 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) {
5453 (None, CursorKind::Hidden)
5554 }
5655
5756 /// May be used by the parent component to compute the child area.
5857 /// 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)> {
6059 // TODO: for scrolling, the scroll wrapper should place a size + offset on the Context
6160 // that way render can use it
6261 None
@@ -80,7 +79,7 @@ pub struct Compositor {
8079impl Compositor {
8180 pub fn new() -> Result<Self, Error> {
8281 let backend = CrosstermBackend::new(stdout());
83− let mut terminal = Terminal::new(backend)?;
82+ let terminal = Terminal::new(backend)?;
8483 Ok(Self {
8584 layers: Vec::new(),
8685 terminal,
@@ -125,8 +124,7 @@ impl Compositor {
125124 }
126125
127126 pub fn render(&mut self, cx: &mut Context) {
128− let area = self
129− .terminal
127+ self.terminal
130128 .autoresize()
131129 .expect("Unable to determine terminal size");
132130
@@ -143,7 +141,7 @@ impl Compositor {
143141 let (pos, kind) = self.cursor(area, cx.editor);
144142 let pos = pos.map(|pos| (pos.col as u16, pos.row as u16));
145143
146− self.terminal.draw(pos, kind);
144+ self.terminal.draw(pos, kind).unwrap();
147145 }
148146
149147 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};
21use serde::Deserialize;
3−use std::collections::HashMap;
42
5−use crate::commands::Command;
63use crate::keymap::Keymaps;
74
5+#[cfg(test)]
6+use crate::commands::Command;
7+
88#[derive(Debug, Default, Clone, PartialEq, Deserialize)]
99pub struct Config {
1010 pub theme: Option<String>,
helix-term/src/job.rs+1−1
@@ -3,7 +3,7 @@ use helix_view::Editor;
33use crate::compositor::Compositor;
44
55use futures_util::future::{self, BoxFuture, Future, FutureExt};
6−use futures_util::stream::{self, FuturesUnordered, Select, StreamExt};
6+use futures_util::stream::{FuturesUnordered, StreamExt};
77
88pub type Callback = Box<dyn FnOnce(&mut Editor, &mut Compositor) + Send>;
99pub type JobFuture = BoxFuture<'static, anyhow::Result<Option<Callback>>>;
helix-term/src/keymap.rs−4
@@ -1,7 +1,5 @@
1−use crate::commands;
21pub use crate::commands::Command;
32use crate::config::Config;
4−use anyhow::{anyhow, Error, Result};
53use helix_core::hashmap;
64use helix_view::{
75 document::Mode,
@@ -11,9 +9,7 @@ use helix_view::{
119use serde::Deserialize;
1210use std::{
1311 collections::HashMap,
14− fmt::Display,
1512 ops::{Deref, DerefMut},
16− str::FromStr,
1713};
1814
1915// Kakoune-inspired:
helix-term/src/lib.rs−2
@@ -1,5 +1,3 @@
1−#![allow(unused)]
2−
31#[macro_use]
42extern crate helix_view;
53
helix-term/src/ui/completion.rs+6−12
@@ -1,19 +1,16 @@
1−use crate::compositor::{Component, Compositor, Context, EventResult};
2−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
1+use crate::compositor::{Component, Context, EventResult};
2+use crossterm::event::{Event, KeyCode, KeyEvent};
33use tui::buffer::Buffer as Surface;
44
55use std::borrow::Cow;
66
7−use helix_core::{Position, Transaction};
8−use helix_view::{
9− graphics::{Color, Rect, Style},
10− Editor,
11−};
7+use helix_core::Transaction;
8+use helix_view::{graphics::Rect, Editor};
129
1310use crate::commands;
1411use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent};
1512
16−use helix_lsp::lsp;
13+use helix_lsp::{lsp, util};
1714use lsp::CompletionItem;
1815
1916impl menu::Item for CompletionItem {
@@ -79,7 +76,7 @@ impl Completion {
7976 trigger_offset: usize,
8077 ) -> Self {
8178 // 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| {
8380 match event {
8481 PromptEvent::Abort => {}
8582 PromptEvent::Validate => {
@@ -88,8 +85,6 @@ impl Completion {
8885 // always present here
8986 let item = item.unwrap();
9087
91− use helix_lsp::{lsp, util};
92−
9388 // if more text was entered, remove it
9489 let cursor = doc.selection(view.id).cursor();
9590 if trigger_offset < cursor {
@@ -100,7 +95,6 @@ impl Completion {
10095 doc.apply(&remove, view.id);
10196 }
10297
103− use helix_lsp::OffsetEncoding;
10498 let transaction = if let Some(edit) = &item.text_edit {
10599 let edit = match edit {
106100 lsp::CompletionTextEdit::Edit(edit) => edit.clone(),
helix-term/src/ui/editor.rs+10−15
@@ -1,32 +1,28 @@
11use crate::{
22 commands,
3− compositor::{Component, Compositor, Context, EventResult},
3+ compositor::{Component, Context, EventResult},
44 key,
5− keymap::{self, Keymaps},
5+ keymap::Keymaps,
66 ui::{Completion, ProgressSpinners},
77};
88
99use helix_core::{
1010 coords_at_pos,
1111 graphemes::ensure_grapheme_boundary_next,
12− syntax::{self, Highlight, HighlightEvent},
12+ syntax::{self, HighlightEvent},
1313 LineEnding, Position, Range,
1414};
15−use helix_lsp::LspProgressMap;
1615use helix_view::{
1716 document::Mode,
18− graphics::{Color, CursorKind, Modifier, Rect, Style},
17+ graphics::{CursorKind, Modifier, Rect, Style},
1918 input::KeyEvent,
2019 keyboard::{KeyCode, KeyModifiers},
2120 Document, Editor, Theme, View,
2221};
2322use std::borrow::Cow;
2423
25−use crossterm::{
26− cursor,
27− event::{read, Event, EventStream},
28−};
29−use tui::{backend::CrosstermBackend, buffer::Buffer as Surface};
24+use crossterm::event::Event;
25+use tui::buffer::Buffer as Surface;
3026
3127pub struct EditorView {
3228 keymaps: Keymaps,
@@ -396,7 +392,7 @@ impl EditorView {
396392 viewport: Rect,
397393 surface: &mut Surface,
398394 theme: &Theme,
399− is_focused: bool,
395+ _is_focused: bool,
400396 ) {
401397 use helix_core::diagnostic::Severity;
402398 use tui::{
@@ -406,7 +402,6 @@ impl EditorView {
406402 };
407403
408404 let cursor = doc.selection(view.id).cursor();
409− let line = doc.text().char_to_line(cursor);
410405
411406 let diagnostics = doc.diagnostics().iter().filter(|diagnostic| {
412407 diagnostic.range.start <= cursor && diagnostic.range.end >= cursor
@@ -612,7 +607,7 @@ impl Component for EditorView {
612607 // clear status
613608 cx.editor.status_msg = None;
614609
615− let (view, doc) = current!(cx.editor);
610+ let (_, doc) = current!(cx.editor);
616611 let mode = doc.mode();
617612
618613 let mut cxt = commands::Context {
@@ -709,7 +704,7 @@ impl Component for EditorView {
709704 }
710705 }
711706
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) {
713708 // clear with background color
714709 surface.set_style(area, cx.editor.theme.get("ui.background"));
715710
@@ -745,7 +740,7 @@ impl Component for EditorView {
745740 }
746741 }
747742
748− fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
743+ fn cursor(&self, _area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
749744 // match view.doc.mode() {
750745 // Mode::Insert => write!(stdout, "\x1B[6 q"),
751746 // 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};
2−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
3−use tui::{buffer::Buffer as Surface, text::Text};
1+use crate::compositor::{Component, Context};
2+use tui::{
3+ buffer::Buffer as Surface,
4+ text::{Span, Spans, Text},
5+};
6+
7+use std::sync::Arc;
48
5−use std::{borrow::Cow, sync::Arc};
9+use pulldown_cmark::{CodeBlockKind, CowStr, Event, Options, Parser, Tag};
610
7−use helix_core::{syntax, Position};
11+use helix_core::{
12+ syntax::{self, HighlightEvent, Syntax},
13+ Rope,
14+};
815use helix_view::{
916 graphics::{Color, Rect, Style},
10− Editor, Theme,
17+ Theme,
1118};
1219
1320pub struct Markdown {
@@ -33,11 +40,8 @@ fn parse<'a>(
3340 theme: Option<&Theme>,
3441 loader: &syntax::Loader,
3542) -> 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}}}
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```";
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}}}
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```";
4145
4246 let mut options = Options::empty();
4347 options.insert(Options::ENABLE_STRIKETHROUGH);
@@ -82,16 +86,13 @@ fn parse<'a>(
8286 // TODO: temp workaround
8387 if let Some(Tag::CodeBlock(CodeBlockKind::Fenced(language))) = tags.last() {
8488 if let Some(theme) = theme {
85− use helix_core::syntax::{self, HighlightEvent, Syntax};
86− use helix_core::Rope;
87−
8889 let rope = Rope::from(text.as_ref());
8990 let syntax = loader
9091 .language_config_for_scope(&format!("source.{}", language))
9192 .and_then(|config| config.highlight_config(theme.scopes()))
9293 .map(|config| Syntax::new(&rope, config));
9394
94− if let Some(mut syntax) = syntax {
95+ if let Some(syntax) = syntax {
9596 // if we have a syntax available, highlight_iter and generate spans
9697 let mut highlights = Vec::new();
9798
@@ -141,13 +142,13 @@ fn parse<'a>(
141142 }
142143 } else {
143144 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);
145146 lines.push(Spans::from(span));
146147 }
147148 }
148149 } else {
149150 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);
151152 lines.push(Spans::from(span));
152153 }
153154 }
helix-term/src/ui/menu.rs+2−9
@@ -4,16 +4,10 @@ use tui::{buffer::Buffer as Surface, widgets::Table};
44
55pub use tui::widgets::{Cell, Row};
66
7−use std::borrow::Cow;
8−
97use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
108use fuzzy_matcher::FuzzyMatcher;
119
12−use helix_core::Position;
13−use helix_view::{
14− graphics::{Color, Rect, Style},
15− Editor,
16−};
10+use helix_view::{graphics::Rect, Editor};
1711
1812pub trait Item {
1913 // TODO: sort_text
@@ -64,7 +58,6 @@ impl<T: Item> Menu<T> {
6458 pub fn score(&mut self, pattern: &str) {
6559 // need to borrow via pattern match otherwise it complains about simultaneous borrow
6660 let Self {
67− ref mut options,
6861 ref mut matcher,
6962 ref mut matches,
7063 ..
@@ -297,7 +290,7 @@ impl<T: Item + 'static> Component for Menu<T> {
297290 // )
298291 // }
299292
300− for (i, option) in (scroll..(scroll + win_height).min(len)).enumerate() {
293+ for (i, _) in (scroll..(scroll + win_height).min(len)).enumerate() {
301294 let is_marked = i >= scroll_line && i < scroll_line + scroll_height;
302295
303296 if is_marked {
helix-term/src/ui/mod.rs+11−14
@@ -20,12 +20,9 @@ pub use text::Text;
2020
2121use helix_core::regex::Regex;
2222use helix_core::register::Registers;
23−use helix_view::{
24− graphics::{Color, Modifier, Rect, Style},
25− Document, Editor, View,
26−};
23+use helix_view::{Document, Editor, View};
2724
28−use std::path::{Path, PathBuf};
25+use std::path::PathBuf;
2926
3027pub fn regex_prompt(
3128 cx: &mut crate::commands::Context,
@@ -38,7 +35,7 @@ pub fn regex_prompt(
3835
3936 Prompt::new(
4037 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
4239 move |cx: &mut crate::compositor::Context, input: &str, event: PromptEvent| {
4340 match event {
4441 PromptEvent::Abort => {
@@ -121,7 +118,7 @@ pub fn file_picker(root: PathBuf) -> Picker<PathBuf> {
121118 .into()
122119 },
123120 move |editor: &mut Editor, path: &PathBuf, action| {
124− let document_id = editor
121+ editor
125122 .open(path.into(), action)
126123 .expect("editor.open failed");
127124 },
@@ -133,8 +130,8 @@ pub mod completers {
133130 use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
134131 use fuzzy_matcher::FuzzyMatcher;
135132 use helix_view::theme;
133+ use std::borrow::Cow;
136134 use std::cmp::Reverse;
137− use std::{borrow::Cow, sync::Arc};
138135
139136 pub type Completer = fn(&str) -> Vec<Completion>;
140137
@@ -154,7 +151,7 @@ pub mod completers {
154151
155152 let mut matches: Vec<_> = names
156153 .into_iter()
157− .filter_map(|(range, name)| {
154+ .filter_map(|(_range, name)| {
158155 matcher.fuzzy_match(&name, input).map(|score| (name, score))
159156 })
160157 .collect();
@@ -208,7 +205,7 @@ pub mod completers {
208205 // Rust's filename handling is really annoying.
209206
210207 use ignore::WalkBuilder;
211− use std::path::{Path, PathBuf};
208+ use std::path::Path;
212209
213210 let is_tilde = input.starts_with('~') && input.len() == 1;
214211 let path = helix_view::document::expand_tilde(Path::new(input));
@@ -229,7 +226,7 @@ pub mod completers {
229226 (path, file_name)
230227 };
231228
232− let end = (input.len()..);
229+ let end = input.len()..;
233230
234231 let mut files: Vec<_> = WalkBuilder::new(dir.clone())
235232 .max_depth(Some(1))
@@ -242,7 +239,7 @@ pub mod completers {
242239 return None;
243240 }
244241
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());
246243
247244 let path = entry.path();
248245 let mut path = if is_tilde {
@@ -274,14 +271,14 @@ pub mod completers {
274271 // inefficient, but we need to calculate the scores, filter out None, then sort.
275272 let mut matches: Vec<_> = files
276273 .into_iter()
277− .filter_map(|(range, file)| {
274+ .filter_map(|(_range, file)| {
278275 matcher
279276 .fuzzy_match(&file, &file_name)
280277 .map(|score| (file, score))
281278 })
282279 .collect();
283280
284− let range = ((input.len().saturating_sub(file_name.len()))..);
281+ let range = (input.len().saturating_sub(file_name.len()))..;
285282
286283 matches.sort_unstable_by_key(|(_file, score)| Reverse(*score));
287284 files = matches
helix-term/src/ui/picker.rs+2−3
@@ -43,8 +43,8 @@ impl<T> Picker<T> {
4343 ) -> Self {
4444 let prompt = Prompt::new(
4545 "".to_string(),
46− |pattern: &str| Vec::new(),
47− |editor: &mut Context, pattern: &str, event: PromptEvent| {
46+ |_pattern: &str| Vec::new(),
47+ |_editor: &mut Context, _pattern: &str, _event: PromptEvent| {
4848 //
4949 },
5050 );
@@ -69,7 +69,6 @@ impl<T> Picker<T> {
6969 pub fn score(&mut self) {
7070 // need to borrow via pattern match otherwise it complains about simultaneous borrow
7171 let Self {
72− ref mut options,
7372 ref mut matcher,
7473 ref mut matches,
7574 ref filters,
helix-term/src/ui/popup.rs+3−9
@@ -2,13 +2,8 @@ use crate::compositor::{Component, Compositor, Context, EventResult};
22use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
33use tui::buffer::Buffer as Surface;
44
5−use std::borrow::Cow;
6−
75use helix_core::Position;
8−use helix_view::{
9− graphics::{Color, Rect, Style},
10− Editor,
11−};
6+use helix_view::graphics::Rect;
127
138// TODO: share logic with Menu, it's essentially Popup(render_fn), but render fn needs to return
149// a width/height hint. maybe Popup(Box<Component>)
@@ -57,7 +52,7 @@ impl<T: Component> Component for Popup<T> {
5752 fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
5853 let key = match event {
5954 Event::Key(event) => event,
60− Event::Resize(width, height) => {
55+ Event::Resize(_, _) => {
6156 // TODO: calculate inner area, call component's handle_event with that area
6257 return EventResult::Ignored;
6358 }
@@ -99,7 +94,7 @@ impl<T: Component> Component for Popup<T> {
9994 // tab/enter/ctrl-k or whatever will confirm the selection/ ctrl-n/ctrl-p for scroll.
10095 }
10196
102− fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
97+ fn required_size(&mut self, _viewport: (u16, u16)) -> Option<(u16, u16)> {
10398 let (width, height) = self
10499 .contents
105100 .required_size((120, 26)) // max width, max height
@@ -135,7 +130,6 @@ impl<T: Component> Component for Popup<T> {
135130 rel_y += 1 // position below point
136131 }
137132
138− let area = Rect::new(rel_x, rel_y, width, height);
139133 // clip to viewport
140134 let area = viewport.intersection(Rect::new(rel_x, rel_y, width, height));
141135
helix-term/src/ui/prompt.rs+20−22
@@ -5,13 +5,11 @@ use std::{borrow::Cow, ops::RangeFrom};
55use tui::buffer::Buffer as Surface;
66
77use helix_core::{
8− unicode::segmentation::{GraphemeCursor, GraphemeIncomplete},
9− unicode::width::UnicodeWidthStr,
10− Position,
8+ unicode::segmentation::GraphemeCursor, unicode::width::UnicodeWidthStr, Position,
119};
1210use helix_view::{
13− graphics::{Color, CursorKind, Margin, Modifier, Rect, Style},
14− Editor, Theme,
11+ graphics::{CursorKind, Margin, Rect},
12+ Editor,
1513};
1614
1715pub type Completion = (RangeFrom<usize>, Cow<'static, str>);
@@ -398,6 +396,22 @@ impl Component for Prompt {
398396 (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
399397 return close_fn;
400398 }
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)),
401415 KeyEvent {
402416 code: KeyCode::Char('f'),
403417 modifiers: KeyModifiers::CONTROL,
@@ -430,22 +444,6 @@ impl Component for Prompt {
430444 code: KeyCode::Char('a'),
431445 modifiers: KeyModifiers::CONTROL,
432446 } => 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)),
449447 KeyEvent {
450448 code: KeyCode::Char('w'),
451449 modifiers: KeyModifiers::CONTROL,
@@ -494,7 +492,7 @@ impl Component for Prompt {
494492 self.render_prompt(area, surface, cx)
495493 }
496494
497− fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
495+ fn cursor(&self, area: Rect, _editor: &Editor) -> (Option<Position>, CursorKind) {
498496 let line = area.height as usize - 1;
499497 (
500498 Some(Position::new(
helix-term/src/ui/text.rs+3−12
@@ -1,14 +1,7 @@
1−use crate::compositor::{Component, Compositor, Context, EventResult};
2−use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
1+use crate::compositor::{Component, Context};
32use tui::buffer::Buffer as Surface;
43
5−use std::borrow::Cow;
6−
7−use helix_core::Position;
8−use helix_view::{
9− graphics::{Color, Rect, Style},
10− Editor,
11−};
4+use helix_view::graphics::Rect;
125
136pub struct Text {
147 contents: String,
@@ -20,12 +13,10 @@ impl Text {
2013 }
2114}
2215impl 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) {
2417 use tui::widgets::{Paragraph, Widget, Wrap};
2518 let contents = tui::text::Text::from(self.contents.clone());
2619
27− let style = cx.editor.theme.get("ui.text");
28−
2920 let par = Paragraph::new(contents).wrap(Wrap { trim: false });
3021 // .scroll(x, y) offsets
3122