@@ -1232,49 +1232,115 @@ pub fn hover(cx: &mut Context) {
1234pub fn rename_symbol(cx: &mut Context) {
1234pub fn rename_symbol(cx: &mut Context) {
1235+ fn get_prefill_from_word_boundary(editor: &Editor) -> String {
1235− let (view, doc) = current_ref!(cx.editor);
1236+ let (view, doc) = current_ref!(editor);
1236− let text = doc.text().slice(..);
1237+ let text = doc.text().slice(..);
1237− let primary_selection = doc.selection(view.id).primary();
1238+ let primary_selection = doc.selection(view.id).primary();
1238− let prefill = if primary_selection.len() > 1 {
1239+ if primary_selection.len() > 1 {
1239− primary_selection
1240+ primary_selection
1240− } else {
1241+ } else {
1241− use helix_core::textobject::{textobject_word, TextObject};
1242+ use helix_core::textobject::{textobject_word, TextObject};
1242− textobject_word(text, primary_selection, TextObject::Inside, 1, false)
1243+ textobject_word(text, primary_selection, TextObject::Inside, 1, false)
1249+ fn get_prefill_from_lsp_response(
1251+ offset_encoding: OffsetEncoding,
1252+ response: Option<lsp::PrepareRenameResponse>,
1253+ ) -> Result<String, &'static str> {
1255+ Some(lsp::PrepareRenameResponse::Range(range)) => {
1256+ let text = doc!(editor).text();
1258+ Ok(lsp_range_to_range(text, range, offset_encoding)
1259+ .ok_or("lsp sent invalid selection range for rename")?
1244− .fragment(text)
1260+ .fragment(text.slice(..))
1246− ui::prompt_with_input(
1248− "rename-to:".into(),
1261+ .into())
1250− None,
1263+ Some(lsp::PrepareRenameResponse::RangeWithPlaceholder { placeholder, .. }) => {
1251− ui::completers::none,
1264+ Ok(placeholder)
1252− move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
1265+ }
1253− if event != PromptEvent::Validate {
1266+ Some(lsp::PrepareRenameResponse::DefaultBehavior { .. }) => {
1254− return;
1267+ Ok(get_prefill_from_word_boundary(editor))
1269+ None => Err("lsp did not respond to prepare rename request"),
1257− let (view, doc) = current!(cx.editor);
1273+ fn create_rename_prompt(editor: &Editor, prefill: String) -> Box<ui::Prompt> {
1258− let language_server = language_server!(cx.editor, doc);
1274+ let prompt = ui::Prompt::new(
1259− let offset_encoding = language_server.offset_encoding();
1275+ "rename-to:".into(),
1277+ ui::completers::none,
1278+ move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
1279+ if event != PromptEvent::Validate {
1283+ let (view, doc) = current!(cx.editor);
1284+ let language_server = language_server!(cx.editor, doc);
1285+ let offset_encoding = language_server.offset_encoding();
1261− let pos = doc.position(view.id, offset_encoding);
1287+ let pos = doc.position(view.id, offset_encoding);
1290+ match language_server.rename_symbol(doc.identifier(), pos, input.to_string()) {
1291+ Some(future) => future,
1294+ .set_error("Language server does not support symbol renaming");
1298+ match block_on(future) {
1299+ Ok(edits) => apply_workspace_edit(cx.editor, offset_encoding, &edits),
1300+ Err(err) => cx.editor.set_error(err.to_string()),
1304+ .with_line(prefill, editor);
1263− let future =
1306+ Box::new(prompt)
1309+ let (view, doc) = current!(cx.editor);
1310+ let language_server = language_server!(cx.editor, doc);
1311+ let offset_encoding = language_server.offset_encoding();
1313+ let pos = doc.position(view.id, offset_encoding);
1264− match language_server.rename_symbol(doc.identifier(), pos, input.to_string()) {
1315+ match language_server.prepare_rename(doc.identifier(), pos) {
1316+ // Language server supports textDocument/prepareRename, use it.
1265− Some(future) => future,
1317+ Some(future) => cx.callback(
1266− None => {
1318+ future,
1319+ move |editor, compositor, response: Option<lsp::PrepareRenameResponse>| {
1320+ let prefill = match get_prefill_from_lsp_response(editor, offset_encoding, response)
1267− cx.editor
1324+ editor.set_error(e);
1268− .set_error("Language server does not support symbol renaming");
1272− match block_on(future) {
1328+
1273− Ok(edits) => apply_workspace_edit(cx.editor, offset_encoding, &edits),
1329+ let prompt = create_rename_prompt(editor, prefill);
1274− Err(err) => cx.editor.set_error(err.to_string()),
1330+
1275− }
1331+ compositor.push(prompt);
1334+ // Language server does not support textDocument/prepareRename, fall back
1335+ // to word boundary selection.
1337+ let prefill = get_prefill_from_word_boundary(cx.editor);
1339+ let prompt = create_rename_prompt(cx.editor, prefill);
1341+ cx.push_layer(prompt);
1280pub fn select_references_to_symbol_under_cursor(cx: &mut Context) {
1346pub fn select_references_to_symbol_under_cursor(cx: &mut Context) {