This repository was archived by the owner on Dec 29, 2022. It is now read-only.
This repository was archived by the owner on Dec 29, 2022. It is now read-only.
Provide outline tree #909
Open
Description
We should provide textDocument/documentSymbol outlines that allow showing the symbols in a tree.
Pulled out my comment from #86 into it's own issue as I guess its a larger thing.
Current Status
textDocument/documentSymbol response
[{
"name": "",
"kind": 2,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 1,
"character": 0
},
"end": {
"line": 58,
"character": 1
}
}
},
"containerName": null
}, {
"name": "stuff",
"kind": 2,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 7,
"character": 4
},
"end": {
"line": 7,
"character": 9
}
}
},
"containerName": ""
}, {
"name": "speaks",
"kind": 2,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 8,
"character": 8
},
"end": {
"line": 8,
"character": 14
}
}
},
"containerName": "stuff"
}, {
"name": "Speaks",
"kind": 11,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 9,
"character": 18
},
"end": {
"line": 9,
"character": 24
}
}
},
"containerName": "speaks"
}, {
"name": "speak",
"kind": 6,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 10,
"character": 15
},
"end": {
"line": 10,
"character": 20
}
}
},
"containerName": "Speaks"
}, {
"name": "NUM_A",
"kind": 14,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 14,
"character": 10
},
"end": {
"line": 14,
"character": 15
}
}
},
"containerName": "stuff"
}, {
"name": "Temp",
"kind": 5,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 18,
"character": 11
},
"end": {
"line": 18,
"character": 15
}
}
},
"containerName": "stuff"
}, {
"name": "field",
"kind": 8,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 19,
"character": 8
},
"end": {
"line": 19,
"character": 13
}
}
},
"containerName": "Temp"
}, {
"name": "Another",
"kind": 5,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 21,
"character": 11
},
"end": {
"line": 21,
"character": 18
}
}
},
"containerName": "stuff"
}, {
"name": "AnEnum",
"kind": 10,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 23,
"character": 20
},
"end": {
"line": 23,
"character": 26
}
}
},
"containerName": "stuff"
}, {
"name": "One",
"kind": 8,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 24,
"character": 8
},
"end": {
"line": 24,
"character": 11
}
}
},
"containerName": "AnEnum"
}, {
"name": "Two",
"kind": 8,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 25,
"character": 8
},
"end": {
"line": 25,
"character": 11
}
}
},
"containerName": "AnEnum"
}, {
"name": "name",
"kind": 8,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 25,
"character": 14
},
"end": {
"line": 25,
"character": 18
}
}
},
"containerName": "Two"
}, {
"name": "Three",
"kind": 8,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 26,
"character": 8
},
"end": {
"line": 26,
"character": 13
}
}
},
"containerName": "AnEnum"
}, {
"name": "something",
"kind": 6,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 29,
"character": 11
},
"end": {
"line": 29,
"character": 20
}
}
},
"containerName": null
}, {
"name": "speak",
"kind": 6,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 34,
"character": 11
},
"end": {
"line": 34,
"character": 16
}
}
},
"containerName": "Speaks"
}, {
"name": "self",
"kind": 13,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 34,
"character": 18
},
"end": {
"line": 34,
"character": 22
}
}
},
"containerName": null
}, {
"name": "speak",
"kind": 6,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 39,
"character": 11
},
"end": {
"line": 39,
"character": 16
}
}
},
"containerName": "Speaks"
}, {
"name": "self",
"kind": 13,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 39,
"character": 18
},
"end": {
"line": 39,
"character": 22
}
}
},
"containerName": null
}, {
"name": "fun1",
"kind": 12,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 43,
"character": 7
},
"end": {
"line": 43,
"character": 11
}
}
},
"containerName": "stuff"
}, {
"name": "fun2",
"kind": 12,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 44,
"character": 11
},
"end": {
"line": 44,
"character": 15
}
}
},
"containerName": null
}, {
"name": "m",
"kind": 13,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 50,
"character": 16
},
"end": {
"line": 50,
"character": 17
}
}
},
"containerName": null
}, {
"name": "main",
"kind": 12,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 56,
"character": 3
},
"end": {
"line": 56,
"character": 7
}
}
},
"containerName": ""
}, {
"name": "a",
"kind": 13,
"location": {
"uri": "file:///home/alex/project/rusttmp/src/main.rs",
"range": {
"start": {
"line": 57,
"character": 8
},
"end": {
"line": 57,
"character": 9
}
}
},
"containerName": null
}]
So we can see that we do already set containerName
in a few cases. However, without nested location ranges atom can't construct the proper syntax tree outline & can't connect the containerName
with the actual symbol name
, so both appear separately.
So it looks like we should make the following improvements, that may need enhancements to rls-analysis
:
- Construct test case using above example.
- Extend all location end positions to the end of the owning scope if applicable.
So for example themod stuff
location should change from [7:4, 7:9] -> [7:4, 56:1] - Add missing symbols, ie
impl Temp
(probably just useUnknown
to describe this symbol kind) - Add missing
containerName
s, iefn fun1() { fn fun2() {} }
- Once we have the symbol, rename
impl Speaks for Temp
"Speaks" -> "Speaks for Temp" (remove generics if they exist though?) - Make use of newer LSP symbol kinds struct, etc
- Minor: Remove empty string name symbols &
containerName
s
Later enhancements:
- Outlines for common macro declarations
lazy_static!
,thread_local!
, etc
Test/example code
#![allow(unused)]
#[macro_use]
extern crate lazy_static;
use std::collections::HashMap;
use std::sync::Arc;
mod stuff {
mod speaks {
pub trait Speaks {
fn speak(&self);
}
}
use self::speaks::Speaks;
const NUM_A: usize = 234;
struct Temp {
field: i32,
}
struct Another;
pub(crate) enum AnEnum {
One(u32, u32),
Two { name: &'static str },
Three,
}
impl Temp {
fn something() -> i32 {
1
}
}
impl Speaks for Temp {
fn speak(&self) {
eprintln!("hello");
}
}
impl Speaks for AnEnum {
fn speak(&self) {
eprintln!("hmmmm");
}
}
fn fun1() {
fn fun2() {}
}
}
lazy_static! {
pub static ref MAP: HashMap<u32, &'static str> = {
let mut m = HashMap::new();
m.insert(345, "345");
m
};
}
fn main() {
let a = Arc::new(123);
}