on master help sign in
lsp: support both utf-8 and utf-16 offsets.
3e5f24aBlaž Hrastnik
helix-lsp/src/client.rs+11−6
@@ -1,6 +1,6 @@
1use crate::{
1use crate::{
2 transport::{Payload, Transport},
2 transport::{Payload, Transport},
3− Call, Error, Result,
3+ Call, Error, OffsetEncoding, Result,
4};
4};
5
5
6use helix_core::{ChangeSet, Rope};
6use helix_core::{ChangeSet, Rope};
@@ -29,8 +29,7 @@ pub struct Client {
29 pub request_counter: AtomicU64,
29 pub request_counter: AtomicU64,
30
30
31 capabilities: Option<lsp::ServerCapabilities>,
31 capabilities: Option<lsp::ServerCapabilities>,
32− // TODO: handle PublishDiagnostics Version
32+ offset_encoding: OffsetEncoding,
33− // diagnostics: HashMap<lsp::Url, Vec<lsp::Diagnostic>>,
34}
33}
35
34
36impl Client {
35impl Client {
@@ -70,6 +69,7 @@ impl Client {
70
69
71 capabilities: None,
70 capabilities: None,
72 // diagnostics: HashMap::new(),
71 // diagnostics: HashMap::new(),
72+ offset_encoding: OffsetEncoding::Utf8,
73 };
73 };
74
74
75 // TODO: async client.initialize()
75 // TODO: async client.initialize()
@@ -100,6 +100,10 @@ impl Client {
100 .expect("language server not yet initialized!")
100 .expect("language server not yet initialized!")
101 }
101 }
102
102
103+ pub fn offset_encoding(&self) -> OffsetEncoding {
104+ self.offset_encoding
105+ }
106+
103 /// Execute a RPC request on the language server.
107 /// Execute a RPC request on the language server.
104 pub async fn request<R: lsp::request::Request>(&self, params: R::Params) -> Result<R::Result>
108 pub async fn request<R: lsp::request::Request>(&self, params: R::Params) -> Result<R::Result>
105 where
109 where
@@ -291,6 +295,7 @@ impl Client {
291 old_text: &Rope,
295 old_text: &Rope,
292 new_text: &Rope,
296 new_text: &Rope,
293 changeset: &ChangeSet,
297 changeset: &ChangeSet,
298+ offset_encoding: OffsetEncoding,
294 ) -> Vec<lsp::TextDocumentContentChangeEvent> {
299 ) -> Vec<lsp::TextDocumentContentChangeEvent> {
295 let mut iter = changeset.changes().iter().peekable();
300 let mut iter = changeset.changes().iter().peekable();
296 let mut old_pos = 0;
301 let mut old_pos = 0;
@@ -340,7 +345,7 @@ impl Client {
340 new_pos += i;
345 new_pos += i;
341 }
346 }
342 Delete(_) => {
347 Delete(_) => {
343− let start = pos_to_lsp_pos(new_text, new_pos);
348+ let start = pos_to_lsp_pos(new_text, new_pos, offset_encoding);
344 let end = traverse(start, old_text.slice(old_pos..old_end));
349 let end = traverse(start, old_text.slice(old_pos..old_end));
345
350
346 // deletion
351 // deletion
@@ -351,7 +356,7 @@ impl Client {
351 });
356 });
352 }
357 }
353 Insert(s) => {
358 Insert(s) => {
354− let start = pos_to_lsp_pos(new_text, new_pos);
359+ let start = pos_to_lsp_pos(new_text, new_pos, offset_encoding);
355
360
356 new_pos += s.chars().count();
361 new_pos += s.chars().count();
357
362
@@ -413,7 +418,7 @@ impl Client {
413 }]
418 }]
414 }
419 }
415 lsp::TextDocumentSyncKind::Incremental => {
420 lsp::TextDocumentSyncKind::Incremental => {
416− Self::changeset_to_changes(old_text, new_text, changes)
421+ Self::changeset_to_changes(old_text, new_text, changes, self.offset_encoding)
417 }
422 }
418 lsp::TextDocumentSyncKind::None => return Ok(()),
423 lsp::TextDocumentSyncKind::None => return Ok(()),
419 };
424 };
helix-lsp/src/lib.rs+62−15
@@ -16,6 +16,8 @@ use thiserror::Error;
16
16
17use std::{collections::HashMap, sync::Arc};
17use std::{collections::HashMap, sync::Arc};
18
18
19+use serde::{Deserialize, Serialize};
20+
19#[derive(Error, Debug)]
21#[derive(Error, Debug)]
20pub enum Error {
22pub enum Error {
21 #[error("protocol error: {0}")]
23 #[error("protocol error: {0}")]
@@ -28,31 +30,76 @@ pub enum Error {
28 Other(#[from] anyhow::Error),
30 Other(#[from] anyhow::Error),
29}
31}
30
32
33+#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
34+pub enum OffsetEncoding {
35+ /// UTF-8 code units aka bytes
36+ #[serde(rename = "utf-8")]
37+ Utf8,
38+ /// UTF-16 code units
39+ #[serde(rename = "utf-16")]
40+ Utf16,
41+}
42+
31pub mod util {
43pub mod util {
32 use super::*;
44 use super::*;
33 use helix_core::{Range, Rope, Transaction};
45 use helix_core::{Range, Rope, Transaction};
34
46
35− pub fn lsp_pos_to_pos(doc: &Rope, pos: lsp::Position) -> usize {
47+ pub fn lsp_pos_to_pos(
48+ doc: &Rope,
49+ pos: lsp::Position,
50+ offset_encoding: OffsetEncoding,
51+ ) -> usize {
52+ match offset_encoding {
53+ OffsetEncoding::Utf8 => {
54+ let line = doc.line_to_char(pos.line as usize);
55+ line + pos.character as usize
56+ }
57+ OffsetEncoding::Utf16 => {
36− let line = doc.line_to_char(pos.line as usize);
58+ let line = doc.line_to_char(pos.line as usize);
37− let line_start = doc.char_to_utf16_cu(line);
59+ let line_start = doc.char_to_utf16_cu(line);
38− doc.utf16_cu_to_char(line_start + pos.character as usize)
60+ doc.utf16_cu_to_char(line_start + pos.character as usize)
61+ }
62+ }
39 }
63 }
40− pub fn pos_to_lsp_pos(doc: &Rope, pos: usize) -> lsp::Position {
64+ pub fn pos_to_lsp_pos(
65+ doc: &Rope,
66+ pos: usize,
67+ offset_encoding: OffsetEncoding,
68+ ) -> lsp::Position {
69+ match offset_encoding {
70+ OffsetEncoding::Utf8 => {
71+ let line = doc.char_to_line(pos);
72+ let line_start = doc.line_to_char(line);
73+ let col = pos - line_start;
74+
75+ lsp::Position::new(line as u32, col as u32)
76+ }
77+ OffsetEncoding::Utf16 => {
41− let line = doc.char_to_line(pos);
78+ let line = doc.char_to_line(pos);
42− let line_start = doc.char_to_utf16_cu(doc.line_to_char(line));
79+ let line_start = doc.char_to_utf16_cu(doc.line_to_char(line));
43− let col = doc.char_to_utf16_cu(pos) - line_start;
80+ let col = doc.char_to_utf16_cu(pos) - line_start;
44
81
45− lsp::Position::new(line as u32, col as u32)
82+ lsp::Position::new(line as u32, col as u32)
83+ }
84+ }
46 }
85 }
47
86
48− pub fn range_to_lsp_range(doc: &Rope, range: Range) -> lsp::Range {
87+ pub fn range_to_lsp_range(
88+ doc: &Rope,
89+ range: Range,
90+ offset_encoding: OffsetEncoding,
91+ ) -> lsp::Range {
49− let start = pos_to_lsp_pos(doc, range.from());
92+ let start = pos_to_lsp_pos(doc, range.from(), offset_encoding);
50− let end = pos_to_lsp_pos(doc, range.to());
93+ let end = pos_to_lsp_pos(doc, range.to(), offset_encoding);
51
94
52 lsp::Range::new(start, end)
95 lsp::Range::new(start, end)
53 }
96 }
54
97
55− pub fn generate_transaction_from_edits(doc: &Rope, edits: Vec<lsp::TextEdit>) -> Transaction {
98+ pub fn generate_transaction_from_edits(
99+ doc: &Rope,
100+ edits: Vec<lsp::TextEdit>,
101+ offset_encoding: OffsetEncoding,
102+ ) -> Transaction {
56 Transaction::change(
103 Transaction::change(
57 doc,
104 doc,
58 edits.into_iter().map(|edit| {
105 edits.into_iter().map(|edit| {
@@ -63,8 +110,8 @@ pub mod util {
63 None
110 None
64 };
111 };
65
112
66− let start = lsp_pos_to_pos(doc, edit.range.start);
113+ let start = lsp_pos_to_pos(doc, edit.range.start, offset_encoding);
67− let end = lsp_pos_to_pos(doc, edit.range.end);
114+ let end = lsp_pos_to_pos(doc, edit.range.end, offset_encoding);
68 (start, end, replacement)
115 (start, end, replacement)
69 }),
116 }),
70 )
117 )
helix-term/src/application.rs+14−2
@@ -175,8 +175,20 @@ impl Application {
175 };
175 };
176 use helix_lsp::{lsp, util::lsp_pos_to_pos};
176 use helix_lsp::{lsp, util::lsp_pos_to_pos};
177 use lsp::DiagnosticSeverity;
177 use lsp::DiagnosticSeverity;
178+
179+ let language_server = doc.language_server().unwrap();
180+
181+ // TODO: convert inside server
178− let start = lsp_pos_to_pos(text, diagnostic.range.start);
182+ let start = lsp_pos_to_pos(
183+ text,
184+ diagnostic.range.start,
185+ language_server.offset_encoding(),
186+ );
179− let end = lsp_pos_to_pos(text, diagnostic.range.end);
187+ let end = lsp_pos_to_pos(
188+ text,
189+ diagnostic.range.end,
190+ language_server.offset_encoding(),
191+ );
180
192
181 Diagnostic {
193 Diagnostic {
182 range: Range { start, end },
194 range: Range { start, end },
helix-term/src/commands.rs+59−20
@@ -16,6 +16,7 @@ use helix_view::{
16use helix_lsp::{
16use helix_lsp::{
17 lsp,
17 lsp,
18 util::{lsp_pos_to_pos, pos_to_lsp_pos, range_to_lsp_range},
18 util::{lsp_pos_to_pos, pos_to_lsp_pos, range_to_lsp_range},
19+ OffsetEncoding,
19};
20};
20
21
21use crate::{
22use crate::{
@@ -1117,18 +1118,24 @@ pub fn exit_select_mode(cx: &mut Context) {
1117 cx.doc().mode = Mode::Normal;
1118 cx.doc().mode = Mode::Normal;
1118}
1119}
1119
1120
1120−fn _goto(cx: &mut Context, locations: Vec<lsp::Location>) {
1121+fn _goto(cx: &mut Context, locations: Vec<lsp::Location>, offset_encoding: OffsetEncoding) {
1121 use helix_view::editor::Action;
1122 use helix_view::editor::Action;
1122
1123
1123 push_jump(cx);
1124 push_jump(cx);
1124
1125
1126+ fn jump_to(
1127+ editor: &mut Editor,
1125− fn jump_to(editor: &mut Editor, location: &lsp::Location, action: Action) {
1128+ location: &lsp::Location,
1129+ offset_encoding: OffsetEncoding,
1130+ action: Action,
1131+ ) {
1126 let id = editor
1132 let id = editor
1127 .open(PathBuf::from(location.uri.path()), action)
1133 .open(PathBuf::from(location.uri.path()), action)
1128 .expect("editor.open failed");
1134 .expect("editor.open failed");
1129 let (view, doc) = editor.current();
1135 let (view, doc) = editor.current();
1130 let definition_pos = location.range.start;
1136 let definition_pos = location.range.start;
1137+ // TODO: convert inside server
1131− let new_pos = lsp_pos_to_pos(doc.text(), definition_pos);
1138+ let new_pos = lsp_pos_to_pos(doc.text(), definition_pos, offset_encoding);
1132 doc.set_selection(view.id, Selection::point(new_pos));
1139 doc.set_selection(view.id, Selection::point(new_pos));
1133 let line = doc.text().char_to_line(new_pos);
1140 let line = doc.text().char_to_line(new_pos);
1134 view.first_line = line.saturating_sub(view.area.height as usize / 2);
1141 view.first_line = line.saturating_sub(view.area.height as usize / 2);
@@ -1136,7 +1143,7 @@ fn _goto(cx: &mut Context, locations: Vec<lsp::Location>) {
1136
1143
1137 match locations.as_slice() {
1144 match locations.as_slice() {
1138 [location] => {
1145 [location] => {
1139− jump_to(cx.editor, location, Action::Replace);
1146+ jump_to(cx.editor, location, offset_encoding, Action::Replace);
1140 }
1147 }
1141 [] => (), // maybe show user message that no definition was found?
1148 [] => (), // maybe show user message that no definition was found?
1142 _locations => {
1149 _locations => {
@@ -1147,7 +1154,9 @@ fn _goto(cx: &mut Context, locations: Vec<lsp::Location>) {
1147 let line = location.range.start.line;
1154 let line = location.range.start.line;
1148 format!("{}:{}", file, line).into()
1155 format!("{}:{}", file, line).into()
1149 },
1156 },
1150− move |editor: &mut Editor, location, action| jump_to(editor, location, action),
1157+ move |editor: &mut Editor, location, action| {
1158+ jump_to(editor, location, offset_encoding, action)
1159+ },
1151 );
1160 );
1152 cx.push_layer(Box::new(picker));
1161 cx.push_layer(Box::new(picker));
1153 }
1162 }
@@ -1161,12 +1170,14 @@ pub fn goto_definition(cx: &mut Context) {
1161 None => return,
1170 None => return,
1162 };
1171 };
1163
1172
1173+ let offset_encoding = language_server.offset_encoding();
1174+
1164− let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor());
1175+ let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
1165
1176
1166 // TODO: handle fails
1177 // TODO: handle fails
1167 let res =
1178 let res =
1168 smol::block_on(language_server.goto_definition(doc.identifier(), pos)).unwrap_or_default();
1179 smol::block_on(language_server.goto_definition(doc.identifier(), pos)).unwrap_or_default();
1169− _goto(cx, res);
1180+ _goto(cx, res, offset_encoding);
1170}
1181}
1171
1182
1172pub fn goto_type_definition(cx: &mut Context) {
1183pub fn goto_type_definition(cx: &mut Context) {
@@ -1176,12 +1187,14 @@ pub fn goto_type_definition(cx: &mut Context) {
1176 None => return,
1187 None => return,
1177 };
1188 };
1178
1189
1190+ let offset_encoding = language_server.offset_encoding();
1191+
1179− let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor());
1192+ let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
1180
1193
1181 // TODO: handle fails
1194 // TODO: handle fails
1182 let res = smol::block_on(language_server.goto_type_definition(doc.identifier(), pos))
1195 let res = smol::block_on(language_server.goto_type_definition(doc.identifier(), pos))
1183 .unwrap_or_default();
1196 .unwrap_or_default();
1184− _goto(cx, res);
1197+ _goto(cx, res, offset_encoding);
1185}
1198}
1186
1199
1187pub fn goto_implementation(cx: &mut Context) {
1200pub fn goto_implementation(cx: &mut Context) {
@@ -1191,12 +1204,14 @@ pub fn goto_implementation(cx: &mut Context) {
1191 None => return,
1204 None => return,
1192 };
1205 };
1193
1206
1207+ let offset_encoding = language_server.offset_encoding();
1208+
1194− let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor());
1209+ let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
1195
1210
1196 // TODO: handle fails
1211 // TODO: handle fails
1197 let res = smol::block_on(language_server.goto_implementation(doc.identifier(), pos))
1212 let res = smol::block_on(language_server.goto_implementation(doc.identifier(), pos))
1198 .unwrap_or_default();
1213 .unwrap_or_default();
1199− _goto(cx, res);
1214+ _goto(cx, res, offset_encoding);
1200}
1215}
1201
1216
1202pub fn goto_reference(cx: &mut Context) {
1217pub fn goto_reference(cx: &mut Context) {
@@ -1206,12 +1221,14 @@ pub fn goto_reference(cx: &mut Context) {
1206 None => return,
1221 None => return,
1207 };
1222 };
1208
1223
1224+ let offset_encoding = language_server.offset_encoding();
1225+
1209− let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor());
1226+ let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
1210
1227
1211 // TODO: handle fails
1228 // TODO: handle fails
1212 let res =
1229 let res =
1213 smol::block_on(language_server.goto_reference(doc.identifier(), pos)).unwrap_or_default();
1230 smol::block_on(language_server.goto_reference(doc.identifier(), pos)).unwrap_or_default();
1214− _goto(cx, res);
1231+ _goto(cx, res, offset_encoding);
1215}
1232}
1216
1233
1217pub fn signature_help(cx: &mut Context) {
1234pub fn signature_help(cx: &mut Context) {
@@ -1222,7 +1239,11 @@ pub fn signature_help(cx: &mut Context) {
1222 None => return,
1239 None => return,
1223 };
1240 };
1224
1241
1242+ let pos = pos_to_lsp_pos(
1243+ doc.text(),
1225− let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor());
1244+ doc.selection(view.id).cursor(),
1245+ language_server.offset_encoding(),
1246+ );
1226
1247
1227 // TODO: handle fails
1248 // TODO: handle fails
1228
1249
@@ -1579,10 +1600,15 @@ pub fn format_selections(cx: &mut Context) {
1579 // via lsp if available
1600 // via lsp if available
1580 // else via tree-sitter indentation calculations
1601 // else via tree-sitter indentation calculations
1581
1602
1603+ let language_server = match doc.language_server() {
1604+ Some(language_server) => language_server,
1605+ None => return,
1606+ };
1607+
1582 let ranges: Vec<lsp::Range> = doc
1608 let ranges: Vec<lsp::Range> = doc
1583 .selection(view.id)
1609 .selection(view.id)
1584 .iter()
1610 .iter()
1585− .map(|range| range_to_lsp_range(doc.text(), *range))
1611+ .map(|range| range_to_lsp_range(doc.text(), *range, language_server.offset_encoding()))
1586 .collect();
1612 .collect();
1587
1613
1588 for range in ranges {
1614 for range in ranges {
@@ -1590,7 +1616,6 @@ pub fn format_selections(cx: &mut Context) {
1590 Some(language_server) => language_server,
1616 Some(language_server) => language_server,
1591 None => return,
1617 None => return,
1592 };
1618 };
1593−
1594 // TODO: handle fails
1619 // TODO: handle fails
1595 // TODO: concurrent map
1620 // TODO: concurrent map
1596 let edits = smol::block_on(language_server.text_document_range_formatting(
1621 let edits = smol::block_on(language_server.text_document_range_formatting(
@@ -1600,7 +1625,11 @@ pub fn format_selections(cx: &mut Context) {
1600 ))
1625 ))
1601 .unwrap_or_default();
1626 .unwrap_or_default();
1602
1627
1603− let transaction = helix_lsp::util::generate_transaction_from_edits(doc.text(), edits);
1628+ let transaction = helix_lsp::util::generate_transaction_from_edits(
1629+ doc.text(),
1630+ edits,
1631+ language_server.offset_encoding(),
1632+ );
1604
1633
1605 doc.apply(&transaction, view.id);
1634 doc.apply(&transaction, view.id);
1606 }
1635 }
@@ -1726,7 +1755,13 @@ pub fn completion(cx: &mut Context) {
1726 None => return,
1755 None => return,
1727 };
1756 };
1728
1757
1758+ let offset_encoding = language_server.offset_encoding();
1759+
1760+ let pos = pos_to_lsp_pos(
1761+ doc.text(),
1729− let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor());
1762+ doc.selection(view.id).cursor(),
1763+ language_server.offset_encoding(),
1764+ );
1730
1765
1731 // TODO: handle fails
1766 // TODO: handle fails
1732 let res = smol::block_on(language_server.completion(doc.identifier(), pos)).unwrap();
1767 let res = smol::block_on(language_server.completion(doc.identifier(), pos)).unwrap();
@@ -1754,7 +1789,7 @@ pub fn completion(cx: &mut Context) {
1754 let size = compositor.size();
1789 let size = compositor.size();
1755 let ui = compositor.find("hx::ui::editor::EditorView").unwrap();
1790 let ui = compositor.find("hx::ui::editor::EditorView").unwrap();
1756 if let Some(ui) = ui.as_any_mut().downcast_mut::<ui::EditorView>() {
1791 if let Some(ui) = ui.as_any_mut().downcast_mut::<ui::EditorView>() {
1757− ui.set_completion(items, trigger_offset, size);
1792+ ui.set_completion(items, offset_encoding, trigger_offset, size);
1758 };
1793 };
1759 }
1794 }
1760 },
1795 },
@@ -1779,7 +1814,11 @@ pub fn hover(cx: &mut Context) {
1779
1814
1780 // TODO: blocking here is not ideal, make commands async fn?
1815 // TODO: blocking here is not ideal, make commands async fn?
1781 // not like we can process additional input meanwhile though
1816 // not like we can process additional input meanwhile though
1817+ let pos = pos_to_lsp_pos(
1818+ doc.text(),
1782− let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor());
1819+ doc.selection(view.id).cursor(),
1820+ language_server.offset_encoding(),
1821+ );
1783
1822
1784 // TODO: handle fails
1823 // TODO: handle fails
1785 let res = smol::block_on(language_server.text_document_hover(doc.identifier(), pos))
1824 let res = smol::block_on(language_server.text_document_hover(doc.identifier(), pos))
helix-term/src/ui/completion.rs+11−3
@@ -26,7 +26,11 @@ pub struct Completion {
26}
26}
27
27
28impl Completion {
28impl Completion {
29+ pub fn new(
29− pub fn new(items: Vec<CompletionItem>, trigger_offset: usize) -> Self {
30+ items: Vec<CompletionItem>,
31+ offset_encoding: helix_lsp::OffsetEncoding,
32+ trigger_offset: usize,
33+ ) -> Self {
30 // let items: Vec<CompletionItem> = Vec::new();
34 // let items: Vec<CompletionItem> = Vec::new();
31 let mut menu = Menu::new(
35 let mut menu = Menu::new(
32 items,
36 items,
@@ -99,8 +103,12 @@ impl Completion {
99 doc.apply(&remove, view.id);
103 doc.apply(&remove, view.id);
100 }
104 }
101
105
102− let transaction =
106+ use helix_lsp::OffsetEncoding;
103− util::generate_transaction_from_edits(doc.text(), vec![edit]);
107+ let transaction = util::generate_transaction_from_edits(
108+ doc.text(),
109+ vec![edit],
110+ offset_encoding, // TODO: should probably transcode in Client
111+ );
104 doc.apply(&transaction, view.id);
112 doc.apply(&transaction, view.id);
105 }
113 }
106 _ => (),
114 _ => (),
helix-term/src/ui/editor.rs+2−1
@@ -517,10 +517,11 @@ impl EditorView {
517 pub fn set_completion(
517 pub fn set_completion(
518 &mut self,
518 &mut self,
519 items: Vec<helix_lsp::lsp::CompletionItem>,
519 items: Vec<helix_lsp::lsp::CompletionItem>,
520+ offset_encoding: helix_lsp::OffsetEncoding,
520 trigger_offset: usize,
521 trigger_offset: usize,
521 size: Rect,
522 size: Rect,
522 ) {
523 ) {
523− let mut completion = Completion::new(items, trigger_offset);
524+ let mut completion = Completion::new(items, offset_encoding, trigger_offset);
524 // TODO : propagate required size on resize to completion too
525 // TODO : propagate required size on resize to completion too
525 completion.required_size((size.width, size.height));
526 completion.required_size((size.width, size.height));
526 self.completion = Some(completion);
527 self.completion = Some(completion);
helix-term/src/ui/mod.rs+1−1
@@ -20,7 +20,7 @@ pub use tui::layout::Rect;
20pub use tui::style::{Color, Modifier, Style};
20pub use tui::style::{Color, Modifier, Style};
21
21
22use helix_core::regex::Regex;
22use helix_core::regex::Regex;
23−use helix_view::{View, Document, Editor};
23+use helix_view::{Document, Editor, View};
24
24
25use std::path::{Path, PathBuf};
25use std::path::{Path, PathBuf};
26
26
helix-view/src/document.rs+19−4
@@ -406,7 +406,7 @@ mod test {
406
406
407 #[test]
407 #[test]
408 fn changeset_to_changes() {
408 fn changeset_to_changes() {
409− use helix_lsp::{lsp, Client};
409+ use helix_lsp::{lsp, Client, OffsetEncoding};
410 let text = Rope::from("hello");
410 let text = Rope::from("hello");
411 let mut doc = Document::new(text);
411 let mut doc = Document::new(text);
412 let view = ViewId::default();
412 let view = ViewId::default();
@@ -417,7 +417,12 @@ mod test {
417 let transaction = Transaction::insert(doc.text(), doc.selection(view), " world".into());
417 let transaction = Transaction::insert(doc.text(), doc.selection(view), " world".into());
418 let old_doc = doc.text().clone();
418 let old_doc = doc.text().clone();
419 doc.apply(&transaction, view);
419 doc.apply(&transaction, view);
420− let changes = Client::changeset_to_changes(&old_doc, doc.text(), transaction.changes());
420+ let changes = Client::changeset_to_changes(
421+ &old_doc,
422+ doc.text(),
423+ transaction.changes(),
424+ OffsetEncoding::Utf8,
425+ );
421
426
422 assert_eq!(
427 assert_eq!(
423 changes,
428 changes,
@@ -436,7 +441,12 @@ mod test {
436 let transaction = transaction.invert(&old_doc);
441 let transaction = transaction.invert(&old_doc);
437 let old_doc = doc.text().clone();
442 let old_doc = doc.text().clone();
438 doc.apply(&transaction, view);
443 doc.apply(&transaction, view);
439− let changes = Client::changeset_to_changes(&old_doc, doc.text(), transaction.changes());
444+ let changes = Client::changeset_to_changes(
445+ &old_doc,
446+ doc.text(),
447+ transaction.changes(),
448+ OffsetEncoding::Utf8,
449+ );
440
450
441 // line: 0-based.
451 // line: 0-based.
442 // col: 0-based, gaps between chars.
452 // col: 0-based, gaps between chars.
@@ -468,7 +478,12 @@ mod test {
468 // aeilou
478 // aeilou
469 let old_doc = doc.text().clone();
479 let old_doc = doc.text().clone();
470 doc.apply(&transaction, view);
480 doc.apply(&transaction, view);
471− let changes = Client::changeset_to_changes(&old_doc, doc.text(), transaction.changes());
481+ let changes = Client::changeset_to_changes(
482+ &old_doc,
483+ doc.text(),
484+ transaction.changes(),
485+ OffsetEncoding::Utf8,
486+ );
472
487
473 assert_eq!(
488 assert_eq!(
474 changes,
489 changes,