"ra_hir",
"ra_ide_db",
"ra_syntax",
- "ra_text_edit",
"rustc-hash",
"stdx",
"test_utils",
+ "text_edit",
]
[[package]]
"ra_ide_db",
"ra_ssr",
"ra_syntax",
- "ra_text_edit",
"rustc-hash",
"stdx",
"test_utils",
+ "text_edit",
]
[[package]]
"ra_db",
"ra_hir",
"ra_syntax",
- "ra_text_edit",
"rayon",
"rustc-hash",
"stdx",
"test_utils",
+ "text_edit",
]
[[package]]
"ra_hir",
"ra_ide_db",
"ra_syntax",
- "ra_text_edit",
"rustc-hash",
"test_utils",
+ "text_edit",
]
[[package]]
"itertools",
"once_cell",
"ra_parser",
- "ra_text_edit",
"rayon",
"rowan",
"rustc-ap-rustc_lexer",
"smol_str",
"stdx",
"test_utils",
+ "text_edit",
"walkdir",
]
-[[package]]
-name = "ra_text_edit"
-version = "0.0.0"
-dependencies = [
- "text-size",
-]
-
[[package]]
name = "rayon"
version = "1.3.1"
"ra_project_model",
"ra_ssr",
"ra_syntax",
- "ra_text_edit",
"rayon",
"rustc-hash",
"serde",
"serde_json",
"stdx",
"test_utils",
+ "text_edit",
"threadpool",
"toolchain",
"tt",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f03e7efdedc3bc78cb2337f1e2785c39e45f5ef762d9e4ebb137fff7380a6d8a"
+[[package]]
+name = "text_edit"
+version = "0.0.0"
+dependencies = [
+ "text-size",
+]
+
[[package]]
name = "thin-dst"
version = "1.1.0"
stdx = { path = "../stdx" }
ra_syntax = { path = "../ra_syntax" }
-ra_text_edit = { path = "../ra_text_edit" }
+text_edit = { path = "../text_edit" }
ra_fmt = { path = "../ra_fmt" }
profile = { path = "../profile" }
ra_db = { path = "../ra_db" }
AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize,
TokenAtOffset,
};
-use ra_text_edit::{TextEdit, TextEditBuilder};
+use text_edit::{TextEdit, TextEditBuilder};
use crate::{
assist_config::{AssistConfig, SnippetCap},
// FIXME: rewrite according to the plan, outlined in
// https://github.com/rust-analyzer/rust-analyzer/issues/3301#issuecomment-592931553
+use either::Either;
use hir::{self, ModPath};
use ra_syntax::{
ast::{self, NameOwner, VisibilityOwner},
SyntaxKind::{PATH, PATH_SEGMENT},
SyntaxNode, T,
};
-use ra_text_edit::TextEditBuilder;
+use text_edit::TextEditBuilder;
use crate::assist_context::AssistContext;
-use either::Either;
/// Determines the containing syntax node in which to insert a `use` statement affecting `position`.
pub(crate) fn find_insert_use_container(
stdx = { path = "../stdx" }
ra_syntax = { path = "../ra_syntax" }
-ra_text_edit = { path = "../ra_text_edit" }
+text_edit = { path = "../text_edit" }
ra_db = { path = "../ra_db" }
ra_ide_db = { path = "../ra_ide_db" }
ra_cfg = { path = "../ra_cfg" }
ast::{self, AstNode},
TextRange, TextSize,
};
-use ra_text_edit::TextEdit;
+use text_edit::TextEdit;
use crate::{
completion::{
ast::{self, edit, Impl},
AstNode, SyntaxKind, SyntaxNode, TextRange, T,
};
-use ra_text_edit::TextEdit;
+use text_edit::TextEdit;
use crate::{
completion::{
SyntaxKind::*,
SyntaxNode, SyntaxToken, TextRange, TextSize,
};
-use ra_text_edit::Indel;
+use text_edit::Indel;
use super::patterns::{
has_bind_pat_parent, has_block_expr_parent, has_impl_as_prev_sibling, has_impl_parent,
use hir::Documentation;
use ra_syntax::TextRange;
-use ra_text_edit::TextEdit;
+use text_edit::TextEdit;
use crate::completion::completion_config::SnippetCap;
ast::{self, AstNode},
SyntaxNode, TextRange, T,
};
-use ra_text_edit::TextEdit;
+use text_edit::TextEdit;
use crate::{Diagnostic, FileId, Fix, SourceFileEdit};
RootDatabase,
};
use ra_syntax::{algo, ast, AstNode};
-use ra_text_edit::TextEdit;
+use text_edit::TextEdit;
/// A [Diagnostic] that potentially has a fix available.
///
SyntaxKind::{self, WHITESPACE},
SyntaxNode, SyntaxToken, TextRange, TextSize, T,
};
-use ra_text_edit::{TextEdit, TextEditBuilder};
+use text_edit::{TextEdit, TextEditBuilder};
// Feature: Join Lines
//
RootDatabase,
};
pub use ra_ssr::SsrError;
-pub use ra_text_edit::{Indel, TextEdit};
+pub use text_edit::{Indel, TextEdit};
pub type Cancelable<T> = Result<T, Canceled>;
ast::{self, NameOwner},
lex_single_valid_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken,
};
-use ra_text_edit::TextEdit;
use std::convert::TryInto;
use test_utils::mark;
+use text_edit::TextEdit;
use crate::{
references::find_all_refs, FilePosition, FileSystemEdit, RangeInfo, Reference, ReferenceKind,
#[cfg(test)]
mod tests {
use expect::{expect, Expect};
- use ra_text_edit::TextEditBuilder;
use stdx::trim_indent;
use test_utils::{assert_eq_text, mark};
+ use text_edit::TextEdit;
use crate::{mock_analysis::analysis_and_position, FileId};
TextRange, TextSize,
};
-use ra_text_edit::TextEdit;
+use text_edit::TextEdit;
use crate::SourceChange;
SyntaxKind::*,
SyntaxToken, TextRange, TextSize, TokenAtOffset,
};
-use ra_text_edit::TextEdit;
use test_utils::mark;
+use text_edit::TextEdit;
// Feature: On Enter
//
stdx = { path = "../stdx" }
ra_syntax = { path = "../ra_syntax" }
-ra_text_edit = { path = "../ra_text_edit" }
+text_edit = { path = "../text_edit" }
ra_db = { path = "../ra_db" }
profile = { path = "../profile" }
test_utils = { path = "../test_utils" }
//! It can be viewed as a dual for `AnalysisChange`.
use ra_db::FileId;
-use ra_text_edit::TextEdit;
+use text_edit::TextEdit;
#[derive(Default, Debug, Clone)]
pub struct SourceChange {
doctest = false
[dependencies]
-ra_text_edit = { path = "../ra_text_edit" }
+text_edit = { path = "../text_edit" }
ra_syntax = { path = "../ra_syntax" }
ra_db = { path = "../ra_db" }
ra_ide_db = { path = "../ra_ide_db" }
use crate::{resolving::ResolvedRule, Match, SsrMatches};
use ra_syntax::ast::{self, AstToken};
use ra_syntax::{SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize};
-use ra_text_edit::TextEdit;
use rustc_hash::{FxHashMap, FxHashSet};
+use text_edit::TextEdit;
/// Returns a text edit that will replace each match in `matches` with its corresponding replacement
/// template. Placeholders in the template will have been substituted with whatever they matched to
stdx = { path = "../stdx" }
-ra_text_edit = { path = "../ra_text_edit" }
+text_edit = { path = "../text_edit" }
ra_parser = { path = "../ra_parser" }
# This crate transitively depends on `smol_str` via `rowan`.
[dependencies]
ra_syntax = { path = ".." }
-ra_text_edit = { path = "../../ra_text_edit" }
+text_edit = { path = "../../text_edit" }
libfuzzer-sys = { git = "https://github.com/rust-fuzz/libfuzzer-sys.git" }
# Prevent this from interfering with workspaces
};
use itertools::Itertools;
-use ra_text_edit::TextEditBuilder;
use rustc_hash::FxHashMap;
+use text_edit::TextEditBuilder;
use crate::{
AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr,
str::{self, FromStr},
};
-use ra_text_edit::Indel;
+use text_edit::Indel;
use crate::{validation, AstNode, SourceFile, TextRange};
use std::{marker::PhantomData, sync::Arc};
-use ra_text_edit::Indel;
use stdx::format_to;
+use text_edit::Indel;
pub use crate::{
algo::InsertPosition,
//! and try to parse only this block.
use ra_parser::Reparser;
-use ra_text_edit::Indel;
+use text_edit::Indel;
use crate::{
algo,
+++ /dev/null
-[package]
-name = "ra_text_edit"
-version = "0.0.0"
-license = "MIT OR Apache-2.0"
-authors = ["rust-analyzer developers"]
-edition = "2018"
-
-[lib]
-doctest = false
-
-[dependencies]
-text-size = "1.0.0"
+++ /dev/null
-//! Representation of a `TextEdit`.
-//!
-//! `rust-analyzer` never mutates text itself and only sends diffs to clients,
-//! so `TextEdit` is the ultimate representation of the work done by
-//! rust-analyzer.
-pub use text_size::{TextRange, TextSize};
-
-/// `InsertDelete` -- a single "atomic" change to text
-///
-/// Must not overlap with other `InDel`s
-#[derive(Debug, Clone)]
-pub struct Indel {
- pub insert: String,
- /// Refers to offsets in the original text
- pub delete: TextRange,
-}
-
-#[derive(Default, Debug, Clone)]
-pub struct TextEdit {
- indels: Vec<Indel>,
-}
-
-#[derive(Debug, Default, Clone)]
-pub struct TextEditBuilder {
- indels: Vec<Indel>,
-}
-
-impl Indel {
- pub fn insert(offset: TextSize, text: String) -> Indel {
- Indel::replace(TextRange::empty(offset), text)
- }
- pub fn delete(range: TextRange) -> Indel {
- Indel::replace(range, String::new())
- }
- pub fn replace(range: TextRange, replace_with: String) -> Indel {
- Indel { delete: range, insert: replace_with }
- }
-
- pub fn apply(&self, text: &mut String) {
- let start: usize = self.delete.start().into();
- let end: usize = self.delete.end().into();
- text.replace_range(start..end, &self.insert);
- }
-}
-
-impl TextEdit {
- pub fn builder() -> TextEditBuilder {
- TextEditBuilder::default()
- }
-
- pub fn insert(offset: TextSize, text: String) -> TextEdit {
- let mut builder = TextEdit::builder();
- builder.insert(offset, text);
- builder.finish()
- }
-
- pub fn delete(range: TextRange) -> TextEdit {
- let mut builder = TextEdit::builder();
- builder.delete(range);
- builder.finish()
- }
-
- pub fn replace(range: TextRange, replace_with: String) -> TextEdit {
- let mut builder = TextEdit::builder();
- builder.replace(range, replace_with);
- builder.finish()
- }
-
- pub fn len(&self) -> usize {
- self.indels.len()
- }
-
- pub fn is_empty(&self) -> bool {
- self.indels.is_empty()
- }
-
- pub fn iter(&self) -> std::slice::Iter<'_, Indel> {
- self.into_iter()
- }
-
- pub fn apply(&self, text: &mut String) {
- match self.len() {
- 0 => return,
- 1 => {
- self.indels[0].apply(text);
- return;
- }
- _ => (),
- }
-
- let mut total_len = TextSize::of(&*text);
- for indel in self.indels.iter() {
- total_len += TextSize::of(&indel.insert);
- total_len -= indel.delete.end() - indel.delete.start();
- }
- let mut buf = String::with_capacity(total_len.into());
- let mut prev = 0;
- for indel in self.indels.iter() {
- let start: usize = indel.delete.start().into();
- let end: usize = indel.delete.end().into();
- if start > prev {
- buf.push_str(&text[prev..start]);
- }
- buf.push_str(&indel.insert);
- prev = end;
- }
- buf.push_str(&text[prev..text.len()]);
- assert_eq!(TextSize::of(&buf), total_len);
-
- // FIXME: figure out a way to mutate the text in-place or reuse the
- // memory in some other way
- *text = buf
- }
-
- pub fn union(&mut self, other: TextEdit) -> Result<(), TextEdit> {
- // FIXME: can be done without allocating intermediate vector
- let mut all = self.iter().chain(other.iter()).collect::<Vec<_>>();
- if !check_disjoint(&mut all) {
- return Err(other);
- }
- self.indels.extend(other.indels);
- assert!(check_disjoint(&mut self.indels));
- Ok(())
- }
-
- pub fn apply_to_offset(&self, offset: TextSize) -> Option<TextSize> {
- let mut res = offset;
- for indel in self.indels.iter() {
- if indel.delete.start() >= offset {
- break;
- }
- if offset < indel.delete.end() {
- return None;
- }
- res += TextSize::of(&indel.insert);
- res -= indel.delete.len();
- }
- Some(res)
- }
-}
-
-impl IntoIterator for TextEdit {
- type Item = Indel;
- type IntoIter = std::vec::IntoIter<Indel>;
-
- fn into_iter(self) -> Self::IntoIter {
- self.indels.into_iter()
- }
-}
-
-impl<'a> IntoIterator for &'a TextEdit {
- type Item = &'a Indel;
- type IntoIter = std::slice::Iter<'a, Indel>;
-
- fn into_iter(self) -> Self::IntoIter {
- self.indels.iter()
- }
-}
-
-impl TextEditBuilder {
- pub fn replace(&mut self, range: TextRange, replace_with: String) {
- self.indels.push(Indel::replace(range, replace_with))
- }
- pub fn delete(&mut self, range: TextRange) {
- self.indels.push(Indel::delete(range))
- }
- pub fn insert(&mut self, offset: TextSize, text: String) {
- self.indels.push(Indel::insert(offset, text))
- }
- pub fn finish(self) -> TextEdit {
- let mut indels = self.indels;
- assert!(check_disjoint(&mut indels));
- TextEdit { indels }
- }
- pub fn invalidates_offset(&self, offset: TextSize) -> bool {
- self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset))
- }
-}
-
-fn check_disjoint(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool {
- indels.sort_by_key(|indel| (indel.borrow().delete.start(), indel.borrow().delete.end()));
- indels
- .iter()
- .zip(indels.iter().skip(1))
- .all(|(l, r)| l.borrow().delete.end() <= r.borrow().delete.start())
-}
profile = { path = "../profile" }
ra_project_model = { path = "../ra_project_model" }
ra_syntax = { path = "../ra_syntax" }
-ra_text_edit = { path = "../ra_text_edit" }
+text_edit = { path = "../text_edit" }
vfs = { path = "../vfs" }
vfs-notify = { path = "../vfs-notify" }
ra_cfg = { path = "../ra_cfg" }
--- /dev/null
+[package]
+name = "text_edit"
+version = "0.0.0"
+license = "MIT OR Apache-2.0"
+authors = ["rust-analyzer developers"]
+edition = "2018"
+
+[lib]
+doctest = false
+
+[dependencies]
+text-size = "1.0.0"
--- /dev/null
+//! Representation of a `TextEdit`.
+//!
+//! `rust-analyzer` never mutates text itself and only sends diffs to clients,
+//! so `TextEdit` is the ultimate representation of the work done by
+//! rust-analyzer.
+pub use text_size::{TextRange, TextSize};
+
+/// `InsertDelete` -- a single "atomic" change to text
+///
+/// Must not overlap with other `InDel`s
+#[derive(Debug, Clone)]
+pub struct Indel {
+ pub insert: String,
+ /// Refers to offsets in the original text
+ pub delete: TextRange,
+}
+
+#[derive(Default, Debug, Clone)]
+pub struct TextEdit {
+ indels: Vec<Indel>,
+}
+
+#[derive(Debug, Default, Clone)]
+pub struct TextEditBuilder {
+ indels: Vec<Indel>,
+}
+
+impl Indel {
+ pub fn insert(offset: TextSize, text: String) -> Indel {
+ Indel::replace(TextRange::empty(offset), text)
+ }
+ pub fn delete(range: TextRange) -> Indel {
+ Indel::replace(range, String::new())
+ }
+ pub fn replace(range: TextRange, replace_with: String) -> Indel {
+ Indel { delete: range, insert: replace_with }
+ }
+
+ pub fn apply(&self, text: &mut String) {
+ let start: usize = self.delete.start().into();
+ let end: usize = self.delete.end().into();
+ text.replace_range(start..end, &self.insert);
+ }
+}
+
+impl TextEdit {
+ pub fn builder() -> TextEditBuilder {
+ TextEditBuilder::default()
+ }
+
+ pub fn insert(offset: TextSize, text: String) -> TextEdit {
+ let mut builder = TextEdit::builder();
+ builder.insert(offset, text);
+ builder.finish()
+ }
+
+ pub fn delete(range: TextRange) -> TextEdit {
+ let mut builder = TextEdit::builder();
+ builder.delete(range);
+ builder.finish()
+ }
+
+ pub fn replace(range: TextRange, replace_with: String) -> TextEdit {
+ let mut builder = TextEdit::builder();
+ builder.replace(range, replace_with);
+ builder.finish()
+ }
+
+ pub fn len(&self) -> usize {
+ self.indels.len()
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.indels.is_empty()
+ }
+
+ pub fn iter(&self) -> std::slice::Iter<'_, Indel> {
+ self.into_iter()
+ }
+
+ pub fn apply(&self, text: &mut String) {
+ match self.len() {
+ 0 => return,
+ 1 => {
+ self.indels[0].apply(text);
+ return;
+ }
+ _ => (),
+ }
+
+ let mut total_len = TextSize::of(&*text);
+ for indel in self.indels.iter() {
+ total_len += TextSize::of(&indel.insert);
+ total_len -= indel.delete.end() - indel.delete.start();
+ }
+ let mut buf = String::with_capacity(total_len.into());
+ let mut prev = 0;
+ for indel in self.indels.iter() {
+ let start: usize = indel.delete.start().into();
+ let end: usize = indel.delete.end().into();
+ if start > prev {
+ buf.push_str(&text[prev..start]);
+ }
+ buf.push_str(&indel.insert);
+ prev = end;
+ }
+ buf.push_str(&text[prev..text.len()]);
+ assert_eq!(TextSize::of(&buf), total_len);
+
+ // FIXME: figure out a way to mutate the text in-place or reuse the
+ // memory in some other way
+ *text = buf
+ }
+
+ pub fn union(&mut self, other: TextEdit) -> Result<(), TextEdit> {
+ // FIXME: can be done without allocating intermediate vector
+ let mut all = self.iter().chain(other.iter()).collect::<Vec<_>>();
+ if !check_disjoint(&mut all) {
+ return Err(other);
+ }
+ self.indels.extend(other.indels);
+ assert!(check_disjoint(&mut self.indels));
+ Ok(())
+ }
+
+ pub fn apply_to_offset(&self, offset: TextSize) -> Option<TextSize> {
+ let mut res = offset;
+ for indel in self.indels.iter() {
+ if indel.delete.start() >= offset {
+ break;
+ }
+ if offset < indel.delete.end() {
+ return None;
+ }
+ res += TextSize::of(&indel.insert);
+ res -= indel.delete.len();
+ }
+ Some(res)
+ }
+}
+
+impl IntoIterator for TextEdit {
+ type Item = Indel;
+ type IntoIter = std::vec::IntoIter<Indel>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.indels.into_iter()
+ }
+}
+
+impl<'a> IntoIterator for &'a TextEdit {
+ type Item = &'a Indel;
+ type IntoIter = std::slice::Iter<'a, Indel>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.indels.iter()
+ }
+}
+
+impl TextEditBuilder {
+ pub fn replace(&mut self, range: TextRange, replace_with: String) {
+ self.indels.push(Indel::replace(range, replace_with))
+ }
+ pub fn delete(&mut self, range: TextRange) {
+ self.indels.push(Indel::delete(range))
+ }
+ pub fn insert(&mut self, offset: TextSize, text: String) {
+ self.indels.push(Indel::insert(offset, text))
+ }
+ pub fn finish(self) -> TextEdit {
+ let mut indels = self.indels;
+ assert!(check_disjoint(&mut indels));
+ TextEdit { indels }
+ }
+ pub fn invalidates_offset(&self, offset: TextSize) -> bool {
+ self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset))
+ }
+}
+
+fn check_disjoint(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool {
+ indels.sort_by_key(|indel| (indel.borrow().delete.start(), indel.borrow().delete.end()));
+ indels
+ .iter()
+ .zip(indels.iter().skip(1))
+ .all(|(l, r)| l.borrow().delete.end() <= r.borrow().delete.start())
+}