add symbol picker (#230)
* add symbol picker use the lsp document_symbol request * fix errors from merging in master * add docs for symbol picker
This commit is contained in:
parent
44cc0d8eb0
commit
9baf1ecc90
4 changed files with 97 additions and 1 deletions
|
@ -166,5 +166,6 @@ This layer is a kludge of mappings I had under leader key in neovim.
|
||||||
|-----|-----------|
|
|-----|-----------|
|
||||||
| f | Open file picker |
|
| f | Open file picker |
|
||||||
| b | Open buffer picker |
|
| b | Open buffer picker |
|
||||||
|
| s | Open symbol picker (current document)|
|
||||||
| w | Enter window mode |
|
| w | Enter window mode |
|
||||||
| space | Keep primary selection TODO: it's here because space mode replaced it |
|
| space | Keep primary selection TODO: it's here because space mode replaced it |
|
||||||
|
|
|
@ -660,4 +660,17 @@ impl Client {
|
||||||
|
|
||||||
self.call::<lsp::request::References>(params)
|
self.call::<lsp::request::References>(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn document_symbols(
|
||||||
|
&self,
|
||||||
|
text_document: lsp::TextDocumentIdentifier,
|
||||||
|
) -> impl Future<Output = Result<Value>> {
|
||||||
|
let params = lsp::DocumentSymbolParams {
|
||||||
|
text_document,
|
||||||
|
work_done_progress_params: lsp::WorkDoneProgressParams::default(),
|
||||||
|
partial_result_params: lsp::PartialResultParams::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.call::<lsp::request::DocumentSymbolRequest>(params)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,6 +138,17 @@ pub mod util {
|
||||||
lsp::Range::new(start, end)
|
lsp::Range::new(start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lsp_range_to_range(
|
||||||
|
doc: &Rope,
|
||||||
|
range: lsp::Range,
|
||||||
|
offset_encoding: OffsetEncoding,
|
||||||
|
) -> Option<Range> {
|
||||||
|
let start = lsp_pos_to_pos(doc, range.start, offset_encoding)?;
|
||||||
|
let end = lsp_pos_to_pos(doc, range.end, offset_encoding)?;
|
||||||
|
|
||||||
|
Some(Range::new(start, end))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generate_transaction_from_edits(
|
pub fn generate_transaction_from_edits(
|
||||||
doc: &Rope,
|
doc: &Rope,
|
||||||
edits: Vec<lsp::TextEdit>,
|
edits: Vec<lsp::TextEdit>,
|
||||||
|
|
|
@ -16,7 +16,7 @@ use helix_view::{
|
||||||
|
|
||||||
use helix_lsp::{
|
use helix_lsp::{
|
||||||
lsp,
|
lsp,
|
||||||
util::{lsp_pos_to_pos, pos_to_lsp_pos, range_to_lsp_range},
|
util::{lsp_pos_to_pos, lsp_range_to_range, pos_to_lsp_pos, range_to_lsp_range},
|
||||||
OffsetEncoding,
|
OffsetEncoding,
|
||||||
};
|
};
|
||||||
use movement::Movement;
|
use movement::Movement;
|
||||||
|
@ -1194,6 +1194,76 @@ pub fn buffer_picker(cx: &mut Context) {
|
||||||
cx.push_layer(Box::new(picker));
|
cx.push_layer(Box::new(picker));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn symbol_picker(cx: &mut Context) {
|
||||||
|
fn nested_to_flat(
|
||||||
|
list: &mut Vec<lsp::SymbolInformation>,
|
||||||
|
file: &lsp::TextDocumentIdentifier,
|
||||||
|
symbol: lsp::DocumentSymbol,
|
||||||
|
) {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
list.push(lsp::SymbolInformation {
|
||||||
|
name: symbol.name,
|
||||||
|
kind: symbol.kind,
|
||||||
|
tags: symbol.tags,
|
||||||
|
deprecated: symbol.deprecated,
|
||||||
|
location: lsp::Location::new(file.uri.clone(), symbol.selection_range),
|
||||||
|
container_name: None,
|
||||||
|
});
|
||||||
|
for child in symbol.children.into_iter().flatten() {
|
||||||
|
nested_to_flat(list, file, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let (view, doc) = cx.current();
|
||||||
|
|
||||||
|
let language_server = match doc.language_server() {
|
||||||
|
Some(language_server) => language_server,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
let offset_encoding = language_server.offset_encoding();
|
||||||
|
|
||||||
|
let future = language_server.document_symbols(doc.identifier());
|
||||||
|
|
||||||
|
cx.callback(
|
||||||
|
future,
|
||||||
|
move |editor: &mut Editor,
|
||||||
|
compositor: &mut Compositor,
|
||||||
|
response: Option<lsp::DocumentSymbolResponse>| {
|
||||||
|
if let Some(symbols) = response {
|
||||||
|
// lsp has two ways to represent symbols (flat/nested)
|
||||||
|
// convert the nested variant to flat, so that we have a homogeneous list
|
||||||
|
let symbols = match symbols {
|
||||||
|
lsp::DocumentSymbolResponse::Flat(symbols) => symbols,
|
||||||
|
lsp::DocumentSymbolResponse::Nested(symbols) => {
|
||||||
|
let (_view, doc) = editor.current();
|
||||||
|
let mut flat_symbols = Vec::new();
|
||||||
|
for symbol in symbols {
|
||||||
|
nested_to_flat(&mut flat_symbols, &doc.identifier(), symbol)
|
||||||
|
}
|
||||||
|
flat_symbols
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let picker = Picker::new(
|
||||||
|
symbols,
|
||||||
|
|symbol| (&symbol.name).into(),
|
||||||
|
move |editor: &mut Editor, symbol, _action| {
|
||||||
|
push_jump(editor);
|
||||||
|
let (view, doc) = editor.current();
|
||||||
|
|
||||||
|
if let Some(range) =
|
||||||
|
lsp_range_to_range(doc.text(), symbol.location.range, offset_encoding)
|
||||||
|
{
|
||||||
|
doc.set_selection(view.id, Selection::single(range.to(), range.from()));
|
||||||
|
align_view(doc, view, Align::Center);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
compositor.push(Box::new(picker))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// I inserts at the first nonwhitespace character of each line with a selection
|
// I inserts at the first nonwhitespace character of each line with a selection
|
||||||
pub fn prepend_to_line(cx: &mut Context) {
|
pub fn prepend_to_line(cx: &mut Context) {
|
||||||
move_first_nonwhitespace(cx);
|
move_first_nonwhitespace(cx);
|
||||||
|
@ -2548,6 +2618,7 @@ pub fn space_mode(cx: &mut Context) {
|
||||||
match ch {
|
match ch {
|
||||||
'f' => file_picker(cx),
|
'f' => file_picker(cx),
|
||||||
'b' => buffer_picker(cx),
|
'b' => buffer_picker(cx),
|
||||||
|
's' => symbol_picker(cx),
|
||||||
'w' => window_mode(cx),
|
'w' => window_mode(cx),
|
||||||
// ' ' => toggle_alternate_buffer(cx),
|
// ' ' => toggle_alternate_buffer(cx),
|
||||||
// TODO: temporary since space mode took its old key
|
// TODO: temporary since space mode took its old key
|
||||||
|
|
Loading…
Add table
Reference in a new issue