@@ -1232,49 +1232,115 @@ pub fn hover(cx: &mut Context) {
12321232}
12331233
12341234pub fn rename_symbol(cx: &mut Context) {
1235− let (view, doc) = current_ref!(cx.editor);
1236− let text = doc.text().slice(..);
1237− let primary_selection = doc.selection(view.id).primary();
1238− let prefill = if primary_selection.len() > 1 {
1239− primary_selection
1240− } else {
1241− use helix_core::textobject::{textobject_word, TextObject};
1242− textobject_word(text, primary_selection, TextObject::Inside, 1, false)
1235+ fn get_prefill_from_word_boundary(editor: &Editor) -> String {
1236+ let (view, doc) = current_ref!(editor);
1237+ let text = doc.text().slice(..);
1238+ let primary_selection = doc.selection(view.id).primary();
1239+ if primary_selection.len() > 1 {
1240+ primary_selection
1241+ } else {
1242+ use helix_core::textobject::{textobject_word, TextObject};
1243+ textobject_word(text, primary_selection, TextObject::Inside, 1, false)
1244+ }
1245+ .fragment(text)
1246+ .into()
12431247 }
1244− .fragment(text)
1245− .into();
1246− ui::prompt_with_input(
1247− cx,
1248− "rename-to:".into(),
1249− prefill,
1250− None,
1251− ui::completers::none,
1252− move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
1253− if event != PromptEvent::Validate {
1254− return;
1248+
1249+ fn get_prefill_from_lsp_response(
1250+ editor: &Editor,
1251+ offset_encoding: OffsetEncoding,
1252+ response: Option<lsp::PrepareRenameResponse>,
1253+ ) -> Result<String, &'static str> {
1254+ match response {
1255+ Some(lsp::PrepareRenameResponse::Range(range)) => {
1256+ let text = doc!(editor).text();
1257+
1258+ Ok(lsp_range_to_range(text, range, offset_encoding)
1259+ .ok_or("lsp sent invalid selection range for rename")?
1260+ .fragment(text.slice(..))
1261+ .into())
1262+ }
1263+ Some(lsp::PrepareRenameResponse::RangeWithPlaceholder { placeholder, .. }) => {
1264+ Ok(placeholder)
1265+ }
1266+ Some(lsp::PrepareRenameResponse::DefaultBehavior { .. }) => {
1267+ Ok(get_prefill_from_word_boundary(editor))
12551268 }
1269+ None => Err("lsp did not respond to prepare rename request"),
1270+ }
1271+ }
12561272
1257− let (view, doc) = current!(cx.editor);
1258− let language_server = language_server!(cx.editor, doc);
1259− let offset_encoding = language_server.offset_encoding();
1273+ fn create_rename_prompt(editor: &Editor, prefill: String) -> Box<ui::Prompt> {
1274+ let prompt = ui::Prompt::new(
1275+ "rename-to:".into(),
1276+ None,
1277+ ui::completers::none,
1278+ move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
1279+ if event != PromptEvent::Validate {
1280+ return;
1281+ }
12601282
1261− let pos = doc.position(view.id, offset_encoding);
1283+ let (view, doc) = current!(cx.editor);
1284+ let language_server = language_server!(cx.editor, doc);
1285+ let offset_encoding = language_server.offset_encoding();
1286+
1287+ let pos = doc.position(view.id, offset_encoding);
1288+
1289+ let future =
1290+ match language_server.rename_symbol(doc.identifier(), pos, input.to_string()) {
1291+ Some(future) => future,
1292+ None => {
1293+ cx.editor
1294+ .set_error("Language server does not support symbol renaming");
1295+ return;
1296+ }
1297+ };
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()),
1301+ }
1302+ },
1303+ )
1304+ .with_line(prefill, editor);
12621305
1263− let future =
1264− match language_server.rename_symbol(doc.identifier(), pos, input.to_string()) {
1265− Some(future) => future,
1266− None => {
1267− cx.editor
1268− .set_error("Language server does not support symbol renaming");
1306+ Box::new(prompt)
1307+ }
1308+
1309+ let (view, doc) = current!(cx.editor);
1310+ let language_server = language_server!(cx.editor, doc);
1311+ let offset_encoding = language_server.offset_encoding();
1312+
1313+ let pos = doc.position(view.id, offset_encoding);
1314+
1315+ match language_server.prepare_rename(doc.identifier(), pos) {
1316+ // Language server supports textDocument/prepareRename, use it.
1317+ Some(future) => cx.callback(
1318+ future,
1319+ move |editor, compositor, response: Option<lsp::PrepareRenameResponse>| {
1320+ let prefill = match get_prefill_from_lsp_response(editor, offset_encoding, response)
1321+ {
1322+ Ok(p) => p,
1323+ Err(e) => {
1324+ editor.set_error(e);
12691325 return;
12701326 }
12711327 };
1272− match block_on(future) {
1273− Ok(edits) => apply_workspace_edit(cx.editor, offset_encoding, &edits),
1274− Err(err) => cx.editor.set_error(err.to_string()),
1275− }
1276− },
1277− );
1328+
1329+ let prompt = create_rename_prompt(editor, prefill);
1330+
1331+ compositor.push(prompt);
1332+ },
1333+ ),
1334+ // Language server does not support textDocument/prepareRename, fall back
1335+ // to word boundary selection.
1336+ None => {
1337+ let prefill = get_prefill_from_word_boundary(cx.editor);
1338+
1339+ let prompt = create_rename_prompt(cx.editor, prefill);
1340+
1341+ cx.push_layer(prompt);
1342+ }
1343+ };
12781344}
12791345
12801346pub fn select_references_to_symbol_under_cursor(cx: &mut Context) {