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

tech(fmt): extract LSPContext struct #4924

Merged
merged 1 commit into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 9 additions & 26 deletions prisma-fmt/src/code_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,23 @@ use crate::offsets::{position_after_span, range_to_span, span_to_range};
use log::warn;
use lsp_types::{CodeActionOrCommand, CodeActionParams, Diagnostic, Range, TextEdit, Url, WorkspaceEdit};
use psl::{
diagnostics::{FileId, Span},
diagnostics::Span,
parser_database::{
ast,
walkers::{ModelWalker, RefinedRelationWalker, ScalarFieldWalker},
ParserDatabase, SourceFile,
SourceFile,
},
schema_ast::ast::{Attribute, IndentationType, NewlineType, WithSpan},
Configuration, Datasource, PreviewFeature,
schema_ast::ast::{self, Attribute, IndentationType, NewlineType, WithSpan},
PreviewFeature,
};
use std::collections::HashMap;

pub(super) struct CodeActionsContext<'a> {
pub(super) db: &'a ParserDatabase,
pub(super) config: &'a Configuration,
pub(super) initiating_file_id: FileId,
pub(super) lsp_params: CodeActionParams,
}
use crate::LSPContext;

impl<'a> CodeActionsContext<'a> {
pub(super) fn initiating_file_source(&self) -> &str {
self.db.source(self.initiating_file_id)
}

pub(super) fn initiating_file_uri(&self) -> &str {
self.db.file_name(self.initiating_file_id)
}
pub(super) type CodeActionsContext<'a> = LSPContext<'a, CodeActionParams>;

impl<'a> CodeActionsContext<'a> {
pub(super) fn diagnostics(&self) -> &[Diagnostic] {
&self.lsp_params.context.diagnostics
}

pub(super) fn datasource(&self) -> Option<&Datasource> {
self.config.datasources.first()
&self.params.context.diagnostics
}

/// A function to find diagnostics matching the given span. Used for
Expand All @@ -55,7 +39,6 @@ impl<'a> CodeActionsContext<'a> {
))
})
}

pub(super) fn diagnostics_for_span_with_message(&self, span: Span, message: &str) -> Vec<Diagnostic> {
self.diagnostics_for_span(span)
.filter(|diag| diag.message.contains(message))
Expand Down Expand Up @@ -89,7 +72,7 @@ pub(crate) fn available_actions(
db: &validated_schema.db,
config,
initiating_file_id,
lsp_params: params,
params: &params,
};

let initiating_ast = validated_schema.db.ast(initiating_file_id);
Expand Down
10 changes: 5 additions & 5 deletions prisma-fmt/src/code_actions/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ pub(super) fn create_missing_block_for_model(
diagnostics.iter().for_each(|diag| {
push_missing_block(
diag,
context.lsp_params.text_document.uri.clone(),
context.params.text_document.uri.clone(),
range,
"model",
actions,
model.newline(),
);
push_missing_block(
diag,
context.lsp_params.text_document.uri.clone(),
context.params.text_document.uri.clone(),
range,
"enum",
actions,
Expand All @@ -52,7 +52,7 @@ pub(super) fn create_missing_block_for_model(
if ds.active_provider == "mongodb" {
push_missing_block(
diag,
context.lsp_params.text_document.uri.clone(),
context.params.text_document.uri.clone(),
range,
"type",
actions,
Expand Down Expand Up @@ -87,15 +87,15 @@ pub(super) fn create_missing_block_for_type(
diagnostics.iter().for_each(|diag| {
push_missing_block(
diag,
context.lsp_params.text_document.uri.clone(),
context.params.text_document.uri.clone(),
range,
"type",
actions,
composite_type.newline(),
);
push_missing_block(
diag,
context.lsp_params.text_document.uri.clone(),
context.params.text_document.uri.clone(),
range,
"enum",
actions,
Expand Down
4 changes: 2 additions & 2 deletions prisma-fmt/src/code_actions/relations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub(super) fn add_referencing_side_unique(
);

let mut changes = HashMap::new();
changes.insert(context.lsp_params.text_document.uri.clone(), vec![text]);
changes.insert(context.params.text_document.uri.clone(), vec![text]);

let edit = WorkspaceEdit {
changes: Some(changes),
Expand Down Expand Up @@ -278,7 +278,7 @@ pub(super) fn add_index_for_relation_fields(
};

let mut changes = HashMap::new();
changes.insert(context.lsp_params.text_document.uri.clone(), vec![text]);
changes.insert(context.params.text_document.uri.clone(), vec![text]);

let edit = WorkspaceEdit {
changes: Some(changes),
Expand Down
36 changes: 36 additions & 0 deletions prisma-fmt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,44 @@ mod validate;

use log::*;
pub use offsets::span_to_range;
use psl::{
datamodel_connector::Connector, diagnostics::FileId, parser_database::ParserDatabase, Configuration, Datasource,
Generator,
};
use schema_file_input::SchemaFileInput;

#[derive(Debug, Clone, Copy)]
pub(crate) struct LSPContext<'a, T> {
pub(crate) db: &'a ParserDatabase,
pub(crate) config: &'a Configuration,
pub(crate) initiating_file_id: FileId,
pub(crate) params: &'a T,
}

impl<'a, T> LSPContext<'a, T> {
pub(crate) fn initiating_file_source(&self) -> &str {
self.db.source(self.initiating_file_id)
}

pub(crate) fn initiating_file_uri(&self) -> &str {
self.db.file_name(self.initiating_file_id)
}

pub(crate) fn datasource(&self) -> Option<&Datasource> {
self.config.datasources.first()
}

pub(crate) fn connector(&self) -> &'static dyn Connector {
self.datasource()
.map(|ds| ds.active_connector)
.unwrap_or(&psl::datamodel_connector::EmptyDatamodelConnector)
}

pub(crate) fn generator(&self) -> Option<&'a Generator> {
self.config.generators.first()
}
}

/// The API is modelled on an LSP [completion
/// request](https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-16.md#textDocument_completion).
/// Input and output are both JSON, the request being a `CompletionParams` object and the response
Expand Down
94 changes: 40 additions & 54 deletions prisma-fmt/src/text_document_completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,36 @@ use enumflags2::BitFlags;
use log::*;
use lsp_types::*;
use psl::{
datamodel_connector::Connector,
diagnostics::{FileId, Span},
diagnostics::Span,
error_tolerant_parse_configuration,
parser_database::{ast, ParserDatabase, SourceFile},
Configuration, Datasource, Diagnostics, Generator, PreviewFeature,
Diagnostics, PreviewFeature,
};

use crate::LSPContext;

mod datasource;

pub(super) type CompletionContext<'a> = LSPContext<'a, CompletionParams>;

impl<'a> CompletionContext<'a> {
pub(super) fn namespaces(&'a self) -> &'a [(String, Span)] {
self.datasource().map(|ds| ds.namespaces.as_slice()).unwrap_or(&[])
}
pub(super) fn preview_features(&self) -> BitFlags<PreviewFeature> {
self.generator()
.and_then(|gen| gen.preview_features)
.unwrap_or_default()
}

pub(super) fn position(&self) -> Option<usize> {
let pos = self.params.text_document_position.position;
let initiating_doc = self.initiating_file_source();

position_to_offset(&pos, initiating_doc)
}
}

pub(crate) fn empty_completion_list() -> CompletionList {
CompletionList {
is_incomplete: true,
Expand All @@ -37,19 +58,10 @@ pub(crate) fn completion(schema_files: Vec<(String, SourceFile)>, params: Comple
return empty_completion_list();
};

let initiating_doc = db.source(initiating_file_id);
let position = if let Some(pos) = position_to_offset(&params.text_document_position.position, initiating_doc) {
pos
} else {
warn!("Received a position outside of the document boundaries in CompletionParams");
return empty_completion_list();
};

let ctx = CompletionContext {
config: &config,
params: &params,
db: &db,
position,
initiating_file_id,
};

Expand All @@ -58,48 +70,22 @@ pub(crate) fn completion(schema_files: Vec<(String, SourceFile)>, params: Comple
list
}

#[derive(Debug, Clone, Copy)]
struct CompletionContext<'a> {
config: &'a Configuration,
params: &'a CompletionParams,
db: &'a ParserDatabase,
position: usize,
initiating_file_id: FileId,
}

impl<'a> CompletionContext<'a> {
pub(crate) fn connector(self) -> &'static dyn Connector {
self.datasource()
.map(|ds| ds.active_connector)
.unwrap_or(&psl::datamodel_connector::EmptyDatamodelConnector)
}

pub(crate) fn namespaces(self) -> &'a [(String, Span)] {
self.datasource().map(|ds| ds.namespaces.as_slice()).unwrap_or(&[])
}

pub(crate) fn preview_features(self) -> BitFlags<PreviewFeature> {
self.generator()
.and_then(|gen| gen.preview_features)
.unwrap_or_default()
}

fn datasource(self) -> Option<&'a Datasource> {
self.config.datasources.first()
}

fn generator(self) -> Option<&'a Generator> {
self.config.generators.first()
}
}

fn push_ast_completions(ctx: CompletionContext<'_>, completion_list: &mut CompletionList) {
let position = match ctx.position() {
Some(pos) => pos,
None => {
warn!("Received a position outside of the document boundaries in CompletionParams");
completion_list.is_incomplete = true;
return;
}
};

let relation_mode = ctx
.config
.relation_mode()
.unwrap_or_else(|| ctx.connector().default_relation_mode());

match ctx.db.ast(ctx.initiating_file_id).find_at_position(ctx.position) {
match ctx.db.ast(ctx.initiating_file_id).find_at_position(position) {
ast::SchemaPosition::Model(
_model_id,
ast::ModelPosition::Field(_, ast::FieldPosition::Attribute("relation", _, Some(attr_name))),
Expand Down Expand Up @@ -130,23 +116,23 @@ fn push_ast_completions(ctx: CompletionContext<'_>, completion_list: &mut Comple
}

ast::SchemaPosition::DataSource(_source_id, ast::SourcePosition::Source) => {
if !ds_has_prop(ctx, "provider") {
if !ds_has_prop(&ctx, "provider") {
datasource::provider_completion(completion_list);
}

if !ds_has_prop(ctx, "url") {
if !ds_has_prop(&ctx, "url") {
datasource::url_completion(completion_list);
}

if !ds_has_prop(ctx, "shadowDatabaseUrl") {
if !ds_has_prop(&ctx, "shadowDatabaseUrl") {
datasource::shadow_db_completion(completion_list);
}

if !ds_has_prop(ctx, "directUrl") {
if !ds_has_prop(&ctx, "directUrl") {
datasource::direct_url_completion(completion_list);
}

if !ds_has_prop(ctx, "relationMode") {
if !ds_has_prop(&ctx, "relationMode") {
datasource::relation_mode_completion(completion_list);
}

Expand Down Expand Up @@ -179,7 +165,7 @@ fn push_ast_completions(ctx: CompletionContext<'_>, completion_list: &mut Comple
}
}

fn ds_has_prop(ctx: CompletionContext<'_>, prop: &str) -> bool {
fn ds_has_prop(ctx: &CompletionContext<'_>, prop: &str) -> bool {
if let Some(ds) = ctx.datasource() {
match prop {
"relationMode" => ds.relation_mode_defined(),
Expand Down
Loading