gutter refactoring
This commit is contained in:
+47
-1
@@ -7,7 +7,7 @@
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
use gpui_kit::component::input::{EditorState, PrepaintCaretGeometry};
|
||||
use gpui_kit::component::input::{EditorState, PrepaintCaretGeometry, Rope};
|
||||
use gpui_kit::{
|
||||
AnyElement, App, AvailableSpace, Bounds, Element, ElementId, GlobalElementId, Hsla,
|
||||
InspectorElementId, IntoElement, LayoutId, Pixels, Point, Size, Style, WeakEntity, Window, px,
|
||||
@@ -196,6 +196,10 @@ fn popup_origin(
|
||||
}
|
||||
|
||||
/// Начало слова под каретой (для замены префикса при вставке).
|
||||
/// Находит начало слова под курсором в обычной строке.
|
||||
///
|
||||
/// Нужен только для тестов: редактор работает с [`word_start_rope`].
|
||||
#[cfg(test)]
|
||||
pub fn word_start(text: &str, cursor: usize) -> usize {
|
||||
let cursor = clamp_offset(text, cursor);
|
||||
let mut start = cursor;
|
||||
@@ -209,6 +213,36 @@ pub fn word_start(text: &str, cursor: usize) -> usize {
|
||||
start
|
||||
}
|
||||
|
||||
/// То же для rope: обходит только символы слова, а не весь документ.
|
||||
pub fn word_start_rope(text: &Rope, cursor: usize) -> usize {
|
||||
let cursor = cursor.min(text.len());
|
||||
let mut start = cursor;
|
||||
let mut char_index = text.byte_to_char_idx(cursor);
|
||||
while char_index > 0 {
|
||||
char_index -= 1;
|
||||
let byte = text.char_to_byte_idx(char_index);
|
||||
let ch = text.char(byte);
|
||||
if ch.is_alphanumeric() || ch == '_' {
|
||||
start = byte;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
start
|
||||
}
|
||||
|
||||
/// Символ перед байтовым смещением `cursor`.
|
||||
pub fn char_before(text: &Rope, cursor: usize) -> Option<char> {
|
||||
let cursor = cursor.min(text.len());
|
||||
let mut char_index = text.byte_to_char_idx(cursor);
|
||||
if char_index == 0 {
|
||||
return None;
|
||||
}
|
||||
char_index -= 1;
|
||||
let byte = text.char_to_byte_idx(char_index);
|
||||
text.get_char(byte).ok()
|
||||
}
|
||||
|
||||
/// Разбирает ответ `textDocument/completion`.
|
||||
pub fn parse_completion_response(value: serde_json::Value) -> Vec<CompletionItem> {
|
||||
if value.is_null() {
|
||||
@@ -501,6 +535,18 @@ mod tests {
|
||||
assert_eq!(word_start("привет", 6), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rope_word_start_matches_string_version() {
|
||||
for text in ["let value", "obj.field", "obj.", "привет"] {
|
||||
let rope = Rope::from(text);
|
||||
for cursor in 0..=text.len() {
|
||||
if text.is_char_boundary(cursor) {
|
||||
assert_eq!(word_start_rope(&rope, cursor), word_start(text, cursor));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snippets_lose_placeholders() {
|
||||
assert_eq!(strip_snippet("println!(${1:value})"), "println!(value)");
|
||||
|
||||
Reference in New Issue
Block a user