Skip to content

Commit 81db324

Browse files
committed
Move the documentation
1 parent 0db773e commit 81db324

File tree

2 files changed

+120
-111
lines changed

2 files changed

+120
-111
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
use crate::{
2+
Document, GotoGoal, InputPosition, Name, ValueName,
3+
format_data::FormatData,
4+
goto::GotoResolver,
5+
inference_state::InferenceState,
6+
name::Range,
7+
type_::{CallableLike, Type},
8+
};
9+
10+
impl<'project> Document<'project> {
11+
pub fn documentation(
12+
&self,
13+
position: InputPosition,
14+
only_docstrings: bool,
15+
) -> anyhow::Result<Option<DocumentationResult<'_>>> {
16+
let mut types = vec![];
17+
let mut class_t = None;
18+
let mut resolver = GotoResolver::new(
19+
self.positional_document(position)?,
20+
GotoGoal::Indifferent,
21+
|n: ValueName| {
22+
if !only_docstrings {
23+
if class_t.is_none()
24+
&& let Type::Type(_) = n.type_
25+
{
26+
class_t = Some(n.type_.clone())
27+
}
28+
types.push(
29+
n.maybe_pretty_function_type()
30+
.unwrap_or_else(|| n.type_description())
31+
.into_string(),
32+
);
33+
}
34+
n.name.documentation().to_string()
35+
},
36+
);
37+
let mut results = resolver.infer_definition();
38+
if results.is_empty() {
39+
return Ok(None);
40+
}
41+
let Some(on_symbol_range) = resolver.on_node_range() else {
42+
// This is probably not reachable
43+
return Ok(None);
44+
};
45+
46+
let resolver = GotoResolver::new(resolver.infos, GotoGoal::Indifferent, |n: Name| {
47+
n.origin_kind()
48+
});
49+
let on_name = resolver.infos.node.on_name();
50+
let declaration_kinds = resolver.goto(true);
51+
results.retain(|doc| !doc.is_empty());
52+
53+
let docs = results.join("\n\n");
54+
let documentation = if only_docstrings {
55+
docs
56+
} else {
57+
let mut out = String::default();
58+
out += "```python\n";
59+
if !declaration_kinds.is_empty() {
60+
out.push('(');
61+
out += &declaration_kinds.join(", ");
62+
out += ") ";
63+
}
64+
if let Some(name) = on_name {
65+
match declaration_kinds.as_slice() {
66+
["class"] => {
67+
// Return the inner part in type[A], because that makes more sense and
68+
// looks nicer
69+
for ty in &mut types {
70+
if ty.starts_with("type[") && ty.ends_with("]") {
71+
ty.drain(..5);
72+
ty.drain(ty.len() - 1..);
73+
}
74+
}
75+
}
76+
["function"] => (),
77+
["type"] => {
78+
out += name.as_code();
79+
out += " = ";
80+
}
81+
_ => {
82+
out += name.as_code();
83+
out += ": ";
84+
}
85+
}
86+
}
87+
let db = &self.project.db;
88+
if let [description] = types.as_slice()
89+
&& let Some(class_t) = class_t
90+
&& let Some(CallableLike::Callable(callable)) =
91+
class_t.maybe_callable(&InferenceState::new_in_unknown_file(db))
92+
{
93+
out += description;
94+
let formatted = callable.format_pretty(&FormatData::new_short(db));
95+
out += "(";
96+
out += formatted.split_once('(').unwrap().1;
97+
} else {
98+
out += &types.join(" | ");
99+
}
100+
out += "\n```";
101+
if !results.is_empty() {
102+
out += "\n---\n";
103+
out += &docs;
104+
}
105+
out
106+
};
107+
Ok(Some(DocumentationResult {
108+
documentation,
109+
on_symbol_range,
110+
}))
111+
}
112+
}
113+
114+
pub struct DocumentationResult<'a> {
115+
pub documentation: String,
116+
pub on_symbol_range: Range<'a>,
117+
}

crates/zuban_python/src/lib.rs

Lines changed: 3 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod code_actions;
66
mod completion;
77
mod database;
88
mod diagnostics;
9+
mod documentation;
910
mod file;
1011
mod format_data;
1112
mod getitem;
@@ -49,6 +50,7 @@ use config::{ProjectOptions, PythonVersion, Settings, TypeCheckerFlags};
4950
pub use database::Mode;
5051
use database::{Database, PythonProject};
5152
pub use diagnostics::Severity;
53+
pub use documentation::DocumentationResult;
5254
use file::File;
5355
use inference_state::InferenceState;
5456
use inferred::Inferred;
@@ -57,10 +59,7 @@ use matching::invalidate_protocol_cache;
5759
pub use name::{Name, NameSymbol, ValueName};
5860
pub use semantic_tokens::{SemanticToken, SemanticTokenProperties};
5961

60-
use crate::{
61-
select_files::all_typechecked_files,
62-
type_::{CallableLike, Type},
63-
};
62+
use crate::select_files::all_typechecked_files;
6463

6564
pub struct Project {
6665
db: Database,
@@ -389,108 +388,6 @@ impl<'project> Document<'project> {
389388
)
390389
}
391390

392-
pub fn documentation(
393-
&self,
394-
position: InputPosition,
395-
only_docstrings: bool,
396-
) -> anyhow::Result<Option<DocumentationResult<'_>>> {
397-
let mut types = vec![];
398-
let mut class_t = None;
399-
let mut resolver = GotoResolver::new(
400-
self.positional_document(position)?,
401-
GotoGoal::Indifferent,
402-
|n: ValueName| {
403-
if !only_docstrings {
404-
if class_t.is_none()
405-
&& let Type::Type(_) = n.type_
406-
{
407-
class_t = Some(n.type_.clone())
408-
}
409-
types.push(
410-
n.maybe_pretty_function_type()
411-
.unwrap_or_else(|| n.type_description())
412-
.into_string(),
413-
);
414-
}
415-
n.name.documentation().to_string()
416-
},
417-
);
418-
let mut results = resolver.infer_definition();
419-
if results.is_empty() {
420-
return Ok(None);
421-
}
422-
let Some(on_symbol_range) = resolver.on_node_range() else {
423-
// This is probably not reachable
424-
return Ok(None);
425-
};
426-
427-
let resolver = GotoResolver::new(resolver.infos, GotoGoal::Indifferent, |n: Name| {
428-
n.origin_kind()
429-
});
430-
let on_name = resolver.infos.node.on_name();
431-
let declaration_kinds = resolver.goto(true);
432-
results.retain(|doc| !doc.is_empty());
433-
434-
let docs = results.join("\n\n");
435-
let documentation = if only_docstrings {
436-
docs
437-
} else {
438-
let mut out = String::default();
439-
out += "```python\n";
440-
if !declaration_kinds.is_empty() {
441-
out.push('(');
442-
out += &declaration_kinds.join(", ");
443-
out += ") ";
444-
}
445-
if let Some(name) = on_name {
446-
match declaration_kinds.as_slice() {
447-
["class"] => {
448-
// Return the inner part in type[A], because that makes more sense and
449-
// looks nicer
450-
for ty in &mut types {
451-
if ty.starts_with("type[") && ty.ends_with("]") {
452-
ty.drain(..5);
453-
ty.drain(ty.len() - 1..);
454-
}
455-
}
456-
}
457-
["function"] => (),
458-
["type"] => {
459-
out += name.as_code();
460-
out += " = ";
461-
}
462-
_ => {
463-
out += name.as_code();
464-
out += ": ";
465-
}
466-
}
467-
}
468-
let db = &self.project.db;
469-
if let [description] = types.as_slice()
470-
&& let Some(class_t) = class_t
471-
&& let Some(CallableLike::Callable(callable)) =
472-
class_t.maybe_callable(&InferenceState::new_in_unknown_file(db))
473-
{
474-
out += description;
475-
let formatted = callable.format_pretty(&format_data::FormatData::new_short(db));
476-
out += "(";
477-
out += formatted.split_once('(').unwrap().1;
478-
} else {
479-
out += &types.join(" | ");
480-
}
481-
out += "\n```";
482-
if !results.is_empty() {
483-
out += "\n---\n";
484-
out += &docs;
485-
}
486-
out
487-
};
488-
Ok(Some(DocumentationResult {
489-
documentation,
490-
on_symbol_range,
491-
}))
492-
}
493-
494391
pub fn is_valid_rename_location(
495392
&self,
496393
position: InputPosition,
@@ -525,11 +422,6 @@ impl<'project> Document<'project> {
525422
}
526423
}
527424

528-
pub struct DocumentationResult<'a> {
529-
pub documentation: String,
530-
pub on_symbol_range: Range<'a>,
531-
}
532-
533425
#[derive(Debug)]
534426
pub struct SingleFileRenameChanges<'db> {
535427
pub path: &'db PathWithScheme,

0 commit comments

Comments
 (0)