Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

psl: allow to remove position information from ast #4792

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 26 additions & 15 deletions prisma-fmt/src/code_actions.rs
Expand Up @@ -31,8 +31,13 @@ pub(crate) fn available_actions(schema: String, params: CodeActionParams) -> Vec

let datasource = config.datasources.first();

for source in validated_schema.db.ast().sources() {
relation_mode::edit_referential_integrity(&mut actions, &params, validated_schema.db.source(), source)
for source in validated_schema.db.ast_assert_single().sources() {
relation_mode::edit_referential_integrity(
&mut actions,
&params,
validated_schema.db.source_assert_single(),
source,
)
}

// models AND views
Expand All @@ -45,21 +50,27 @@ pub(crate) fn available_actions(schema: String, params: CodeActionParams) -> Vec
multi_schema::add_schema_block_attribute_model(
&mut actions,
&params,
validated_schema.db.source(),
validated_schema.db.source_assert_single(),
config,
model,
);

multi_schema::add_schema_to_schemas(&mut actions, &params, validated_schema.db.source(), config, model);
multi_schema::add_schema_to_schemas(
&mut actions,
&params,
validated_schema.db.source_assert_single(),
config,
model,
);
}

if matches!(datasource, Some(ds) if ds.active_provider == "mongodb") {
mongodb::add_at_map_for_id(&mut actions, &params, validated_schema.db.source(), model);
mongodb::add_at_map_for_id(&mut actions, &params, validated_schema.db.source_assert_single(), model);

mongodb::add_native_for_auto_id(
&mut actions,
&params,
validated_schema.db.source(),
validated_schema.db.source_assert_single(),
model,
datasource.unwrap(),
);
Expand All @@ -71,7 +82,7 @@ pub(crate) fn available_actions(schema: String, params: CodeActionParams) -> Vec
multi_schema::add_schema_block_attribute_enum(
&mut actions,
&params,
validated_schema.db.source(),
validated_schema.db.source_assert_single(),
config,
enumerator,
)
Expand All @@ -88,15 +99,15 @@ pub(crate) fn available_actions(schema: String, params: CodeActionParams) -> Vec
relations::add_referenced_side_unique(
&mut actions,
&params,
validated_schema.db.source(),
validated_schema.db.source_assert_single(),
complete_relation,
);

if relation.is_one_to_one() {
relations::add_referencing_side_unique(
&mut actions,
&params,
validated_schema.db.source(),
validated_schema.db.source_assert_single(),
complete_relation,
);
}
Expand All @@ -105,7 +116,7 @@ pub(crate) fn available_actions(schema: String, params: CodeActionParams) -> Vec
relations::add_index_for_relation_fields(
&mut actions,
&params,
validated_schema.db.source(),
validated_schema.db.source_assert_single(),
complete_relation.referencing_field(),
);
}
Expand All @@ -114,7 +125,7 @@ pub(crate) fn available_actions(schema: String, params: CodeActionParams) -> Vec
relation_mode::replace_set_default_mysql(
&mut actions,
&params,
validated_schema.db.source(),
validated_schema.db.source_assert_single(),
complete_relation,
config,
)
Expand Down Expand Up @@ -197,15 +208,15 @@ fn create_missing_attribute<'a>(
}

fn range_after_span(schema: &str, span: Span) -> Range {
let start = crate::offset_to_position(span.end - 1, schema);
let end = crate::offset_to_position(span.end, schema);
let start = crate::offset_to_position(span.end() - 1, schema);
let end = crate::offset_to_position(span.end(), schema);

Range { start, end }
}

fn span_to_range(schema: &str, span: Span) -> Range {
let start = crate::offset_to_position(span.start, schema);
let end = crate::offset_to_position(span.end, schema);
let start = crate::offset_to_position(span.start(), schema);
let end = crate::offset_to_position(span.end(), schema);

Range { start, end }
}
Expand Down
5 changes: 2 additions & 3 deletions prisma-fmt/src/code_actions/multi_schema.rs
Expand Up @@ -142,13 +142,12 @@ pub(super) fn add_schema_to_schemas(
formatted_attribute,
true,
// todo: update spans so that we can just append to the end of the _inside_ of the array. Instead of needing to re-append the `]` or taking the span end -1
Span::new(span.start, span.end - 1),
Span::new(span.start(), span.end() - 1, psl::parser_database::FileId::ZERO),
params,
)
}
None => {
let has_properties = datasource.provider_defined()
|| datasource.url_defined()
let has_properties = datasource.provider_defined() | datasource.url_defined()
|| datasource.direct_url_defined()
|| datasource.shadow_url_defined()
|| datasource.relation_mode_defined()
Expand Down
4 changes: 2 additions & 2 deletions prisma-fmt/src/lib.rs
Expand Up @@ -225,12 +225,12 @@ pub(crate) fn range_to_span(range: Range, document: &str) -> ast::Span {
let start = position_to_offset(&range.start, document).unwrap();
let end = position_to_offset(&range.end, document).unwrap();

ast::Span::new(start, end)
ast::Span::new(start, end, psl::parser_database::FileId::ZERO)
}

/// Gives the LSP position right after the given span.
pub(crate) fn position_after_span(span: ast::Span, document: &str) -> Position {
offset_to_position(span.end - 1, document)
offset_to_position(span.end() - 1, document)
}

/// Converts a byte offset to an LSP position, if the given offset
Expand Down
8 changes: 4 additions & 4 deletions prisma-fmt/src/lint.rs
Expand Up @@ -16,8 +16,8 @@ pub(crate) fn run(schema: &str) -> String {
.errors()
.iter()
.map(|err: &DatamodelError| MiniError {
start: err.span().start,
end: err.span().end,
start: err.span().start(),
end: err.span().end(),
text: err.message().to_string(),
is_warning: false,
})
Expand All @@ -27,8 +27,8 @@ pub(crate) fn run(schema: &str) -> String {
.warnings()
.iter()
.map(|warn: &DatamodelWarning| MiniError {
start: warn.span().start,
end: warn.span().end,
start: warn.span().start(),
end: warn.span().end(),
text: warn.message().to_owned(),
is_warning: true,
})
Expand Down
6 changes: 3 additions & 3 deletions prisma-fmt/src/text_document_completion.rs
Expand Up @@ -41,7 +41,7 @@ pub(crate) fn completion(schema: String, params: CompletionParams) -> Completion

let db = {
let mut diag = Diagnostics::new();
ParserDatabase::new(source_file, &mut diag)
ParserDatabase::new_single_file(source_file, &mut diag)
};

let ctx = CompletionContext {
Expand Down Expand Up @@ -91,7 +91,7 @@ impl<'a> CompletionContext<'a> {
}

fn push_ast_completions(ctx: CompletionContext<'_>, completion_list: &mut CompletionList) {
match ctx.db.ast().find_at_position(ctx.position) {
match ctx.db.ast_assert_single().find_at_position(ctx.position) {
ast::SchemaPosition::Model(
_model_id,
ast::ModelPosition::Field(_, ast::FieldPosition::Attribute("relation", _, Some(attr_name))),
Expand Down Expand Up @@ -190,7 +190,7 @@ fn ds_has_prop(ctx: CompletionContext<'_>, prop: &str) -> bool {

fn push_namespaces(ctx: CompletionContext<'_>, completion_list: &mut CompletionList) {
for (namespace, _) in ctx.namespaces() {
let insert_text = if add_quotes(ctx.params, ctx.db.source()) {
let insert_text = if add_quotes(ctx.params, ctx.db.source_assert_single()) {
format!(r#""{namespace}""#)
} else {
namespace.to_string()
Expand Down
2 changes: 1 addition & 1 deletion prisma-fmt/src/text_document_completion/datasource.rs
Expand Up @@ -144,7 +144,7 @@ pub(super) fn url_env_db_completion(completion_list: &mut CompletionList, kind:
_ => unreachable!(),
};

let insert_text = if add_quotes(ctx.params, ctx.db.source()) {
let insert_text = if add_quotes(ctx.params, ctx.db.source_assert_single()) {
format!(r#""{text}""#)
} else {
text.to_owned()
Expand Down
8 changes: 4 additions & 4 deletions prisma-fmt/tests/code_actions/test_api.rs
Expand Up @@ -19,8 +19,8 @@ fn parse_schema_diagnostics(file: impl Into<SourceFile>) -> Option<Vec<Diagnosti
severity: Some(DiagnosticSeverity::WARNING),
message: warn.message().to_owned(),
range: lsp_types::Range {
start: offset_to_position(warn.span().start, schema.db.source()),
end: offset_to_position(warn.span().end, schema.db.source()),
start: offset_to_position(warn.span().start(), schema.db.source_assert_single()),
end: offset_to_position(warn.span().end(), schema.db.source_assert_single()),
},
..Default::default()
});
Expand All @@ -31,8 +31,8 @@ fn parse_schema_diagnostics(file: impl Into<SourceFile>) -> Option<Vec<Diagnosti
severity: Some(DiagnosticSeverity::ERROR),
message: error.message().to_owned(),
range: lsp_types::Range {
start: offset_to_position(error.span().start, schema.db.source()),
end: offset_to_position(error.span().end, schema.db.source()),
start: offset_to_position(error.span().start(), schema.db.source_assert_single()),
end: offset_to_position(error.span().end(), schema.db.source_assert_single()),
},
..Default::default()
});
Expand Down
3 changes: 3 additions & 0 deletions psl/diagnostics/Cargo.toml
Expand Up @@ -3,6 +3,9 @@ name = "diagnostics"
version = "0.1.0"
edition = "2021"

[features]
full-spans = []

[dependencies]
colored = "2"
pest = "2.1.3"
Expand Down
2 changes: 1 addition & 1 deletion psl/diagnostics/src/lib.rs
Expand Up @@ -8,5 +8,5 @@ mod warning;
pub use collection::Diagnostics;
pub use error::DatamodelError;
pub use native_type_error_factory::NativeTypeErrorFactory;
pub use span::Span;
pub use span::{FileId, Span};
pub use warning::DatamodelWarning;
8 changes: 4 additions & 4 deletions psl/diagnostics/src/pretty_print.rs
Expand Up @@ -17,8 +17,8 @@ pub(crate) fn pretty_print(
description: &str,
colorer: &'static dyn DiagnosticColorer,
) -> std::io::Result<()> {
let start_line_number = text[..span.start].matches('\n').count();
let end_line_number = text[..span.end].matches('\n').count();
let start_line_number = text[..span.start()].matches('\n').count();
let end_line_number = text[..span.end()].matches('\n').count();
let file_lines = text.split('\n').collect::<Vec<&str>>();

let chars_in_line_before: usize = file_lines[..start_line_number].iter().map(|l| l.len()).sum();
Expand All @@ -27,8 +27,8 @@ pub(crate) fn pretty_print(

let line = &file_lines[start_line_number];

let start_in_line = span.start - chars_in_line_before;
let end_in_line = std::cmp::min(start_in_line + (span.end - span.start), line.len());
let start_in_line = span.start() - chars_in_line_before;
let end_in_line = std::cmp::min(start_in_line + (span.end() - span.start()), line.len());

let prefix = &line[..start_in_line];
let offending = colorer.primary_color(&line[start_in_line..end_in_line]).bold();
Expand Down
46 changes: 9 additions & 37 deletions psl/diagnostics/src/span.rs
@@ -1,37 +1,9 @@
/// Represents a location in a datamodel's text representation.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Span {
pub start: usize,
pub end: usize,
}

impl Span {
/// Constructor.
pub fn new(start: usize, end: usize) -> Span {
Span { start, end }
}

/// Creates a new empty span.
pub fn empty() -> Span {
Span { start: 0, end: 0 }
}

/// Is the given position inside the span? (boundaries included)
pub fn contains(&self, position: usize) -> bool {
position >= self.start && position <= self.end
}

/// Is the given span overlapping with the current span.
pub fn overlaps(self, other: Span) -> bool {
self.contains(other.start) || self.contains(other.end)
}
}

impl From<pest::Span<'_>> for Span {
fn from(s: pest::Span<'_>) -> Self {
Span {
start: s.start(),
end: s.end(),
}
}
}
#[cfg(feature = "full-spans")]
mod full;
#[cfg(not(feature = "full-spans"))]
mod noop;

#[cfg(feature = "full-spans")]
pub use full::{FileId, Span};
#[cfg(not(feature = "full-spans"))]
pub use noop::{FileId, Span};
71 changes: 71 additions & 0 deletions psl/diagnostics/src/span/full.rs
@@ -0,0 +1,71 @@
/// The stable identifier for a PSL file.
#[derive(Debug, PartialEq, Clone, Copy, Hash, Eq, PartialOrd, Ord)]
pub struct FileId(pub u32); // we can't encapsulate because it would be a circular crate
// dependency between diagnostics and parser-database

impl FileId {
pub const ZERO: FileId = FileId(0);
pub const MAX: FileId = FileId(u32::MAX);
}

/// Represents a location in a datamodel's text representation.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Span {
start: usize,
end: usize,
file_id: FileId,
}

impl Span {
/// Constructor.
pub fn new(start: usize, end: usize, file_id: FileId) -> Span {
Span { start, end, file_id }
}

pub fn start(&self) -> usize {
self.start
}
pub fn set_start(&mut self, start: usize) {
self.start = start
}

pub fn end(&self) -> usize {
self.end
}
pub fn set_end(&mut self, end: usize) {
self.end = end
}

pub fn file_id(&self) -> FileId {
self.file_id
}

/// Creates a new empty span.
pub fn empty() -> Span {
Span {
start: 0,
end: 0,
file_id: FileId::ZERO,
}
}

/// Is the given position inside the span? (boundaries included)
pub fn contains(&self, position: usize) -> bool {
position >= self.start && position <= self.end
}

/// Is the given span overlapping with the current span.
pub fn overlaps(self, other: Span) -> bool {
self.contains(other.start) || self.contains(other.end)
}
}

impl From<(FileId, pest::Span<'_>)> for Span {
fn from((file_id, s): (FileId, pest::Span<'_>)) -> Self {
Span {
start: s.start(),
end: s.end(),
file_id,
}
}
}