This commit is contained in:
Aleksey Kladov 2020-02-06 15:08:31 +01:00
parent 8a39519e1c
commit 355c98fd08
5 changed files with 84 additions and 75 deletions

View File

@ -1,4 +1,5 @@
//! FIXME: write short doc here
//! Defines a unit of change that can applied to a state of IDE to get the next
//! state. Changes are transactional.
use std::{fmt, sync::Arc, time};

View File

@ -1,4 +1,4 @@
//! FIXME: write short doc here
//! See docs for `FeatureFlags`.
use rustc_hash::FxHashMap;

View File

@ -1,10 +1,87 @@
//! FIXME: write short doc here
//! Code actions can specify desirable final position of the cursor.
//!
//! The position is specified as a `TextUnit` in the final file. We need to send
//! it in `(Line, Column)` coordinate though. However, we only have a LineIndex
//! for a file pre-edit!
//!
//! Code in this module applies this "to (Line, Column) after edit"
//! transformation.
use ra_syntax::{TextRange, TextUnit};
use ra_text_edit::{AtomTextEdit, TextEdit};
use crate::line_index::{LineCol, LineIndex, Utf16Char};
pub fn translate_offset_with_edit(
line_index: &LineIndex,
offset: TextUnit,
text_edit: &TextEdit,
) -> LineCol {
let mut state = Edits::from_text_edit(&text_edit);
let mut res = RunningLineCol::new();
macro_rules! test_step {
($x:ident) => {
match &$x {
Step::Newline(n) => {
if offset < *n {
return res.to_line_col(offset);
} else {
res.add_line(*n);
}
}
Step::Utf16Char(x) => {
if offset < x.end() {
// if the offset is inside a multibyte char it's invalid
// clamp it to the start of the char
let clamp = offset.min(x.start());
return res.to_line_col(clamp);
} else {
res.adjust_col(*x);
}
}
}
};
}
for orig_step in LineIndexStepIter::from(line_index) {
loop {
let translated_step = state.translate_step(&orig_step);
match state.next_steps(&translated_step) {
NextSteps::Use => {
test_step!(translated_step);
break;
}
NextSteps::ReplaceMany(ns) => {
for n in ns {
test_step!(n);
}
break;
}
NextSteps::AddMany(ns) => {
for n in ns {
test_step!(n);
}
}
}
}
}
loop {
match state.next_inserted_steps() {
None => break,
Some(ns) => {
for n in ns {
test_step!(n);
}
}
}
}
res.to_line_col(offset)
}
#[derive(Debug, Clone)]
enum Step {
Newline(TextUnit),
@ -55,7 +132,7 @@ struct OffsetStepIter<'a> {
offset: TextUnit,
}
impl<'a> Iterator for OffsetStepIter<'a> {
impl Iterator for OffsetStepIter<'_> {
type Item = Step;
fn next(&mut self) -> Option<Step> {
let (next, next_offset) = self
@ -221,76 +298,6 @@ impl RunningLineCol {
}
}
pub fn translate_offset_with_edit(
line_index: &LineIndex,
offset: TextUnit,
text_edit: &TextEdit,
) -> LineCol {
let mut state = Edits::from_text_edit(&text_edit);
let mut res = RunningLineCol::new();
macro_rules! test_step {
($x:ident) => {
match &$x {
Step::Newline(n) => {
if offset < *n {
return res.to_line_col(offset);
} else {
res.add_line(*n);
}
}
Step::Utf16Char(x) => {
if offset < x.end() {
// if the offset is inside a multibyte char it's invalid
// clamp it to the start of the char
let clamp = offset.min(x.start());
return res.to_line_col(clamp);
} else {
res.adjust_col(*x);
}
}
}
};
}
for orig_step in LineIndexStepIter::from(line_index) {
loop {
let translated_step = state.translate_step(&orig_step);
match state.next_steps(&translated_step) {
NextSteps::Use => {
test_step!(translated_step);
break;
}
NextSteps::ReplaceMany(ns) => {
for n in ns {
test_step!(n);
}
break;
}
NextSteps::AddMany(ns) => {
for n in ns {
test_step!(n);
}
}
}
}
}
loop {
match state.next_inserted_steps() {
None => break,
Some(ns) => {
for n in ns {
test_step!(n);
}
}
}
}
res.to_line_col(offset)
}
#[cfg(test)]
mod test {
use proptest::{prelude::*, proptest};

View File

@ -19,6 +19,7 @@
//! for each library (which is assumed to never change) and an FST for each Rust
//! file in the current workspace, and run a query against the union of all
//! those FSTs.
use std::{
fmt,
hash::{Hash, Hasher},

View File

@ -1,4 +1,4 @@
//! FIXME: write short doc here
//! A version of `std::time::Instant` that doesn't panic in WASM.
#[cfg(not(feature = "wasm"))]
pub use std::time::Instant;