Skip to content
This repository has been archived by the owner on Dec 29, 2022. It is now read-only.

Provide outline tree #909

Open
8 tasks
alexheretic opened this issue Jun 15, 2018 · 3 comments
Open
8 tasks

Provide outline tree #909

alexheretic opened this issue Jun 15, 2018 · 3 comments
Labels
enhancement Indicates new feature requests protocol

Comments

@alexheretic
Copy link
Member

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

atom-outline

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 the mod stuff location should change from [7:4, 7:9] -> [7:4, 56:1]
  • Add missing symbols, ie impl Temp (probably just use Unknown to describe this symbol kind)
  • Add missing containerNames, ie fn 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 & containerNames

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);
}
@norru
Copy link

norru commented Jul 15, 2019

This one blocks eclipse-corrosion/corrosion#268

@norru
Copy link

norru commented Jul 15, 2019

Are there any plans to implement children in documentSymbol, in this fashion? palantir/python-language-server#537

https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol

	/**
	 * Children of this symbol, e.g. properties of a class.
	 */
	children?: DocumentSymbol[];
	/**
	 * The name of the symbol containing this symbol. This information is for
	 * user interface purposes (e.g. to render a qualifier in the user interface
	 * if necessary). It can't be used to re-infer a hierarchy for the document
	 * symbols.
	 */
	containerName?: string;

@Xanewok
Copy link
Member

Xanewok commented Jul 15, 2019

Yes, we definitely plan to implement that! Last time I looked into this it was (somewhat) blocked on #1377

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement Indicates new feature requests protocol
Projects
None yet
Development

No branches or pull requests

3 participants