Skip to content
Prev Previous commit
Next Next commit
sofa so gut
  • Loading branch information
juleswritescode committed Mar 24, 2025
commit c898e9d634bd20e30ba9dd6b9e9dc9cdf9f72d48
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/pgt_lsp/src/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub(crate) mod code_actions;
pub(crate) mod completions;
pub(crate) mod text_document;
52 changes: 52 additions & 0 deletions crates/pgt_lsp/src/handlers/code_actions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use crate::session::Session;
use tower_lsp::lsp_types::{self, CodeAction, CodeActionDisabled, CodeActionOrCommand, Command};

use pgt_workspace::code_actions::{CodeActionKind, CommandAction, CommandActionCategory};

pub fn get_actions(
session: &Session,
params: lsp_types::CodeActionParams,
) -> Result<lsp_types::CodeActionResponse> {
let url = params.text_document.uri;
let path = session.file_path(&url)?;

let workspace_actions = session.workspace.pull_code_actions(CodeActionsParams {
path,
range: params.range,
only: vec![],
skip: vec![],
})?;

let actions: Vec<CodeAction> = workspace_actions
.actions
.into_iter()
.filter_map(|action| match action.kind {
CodeActionKind::Command(command) => {
let title = match command.category {
CommandActionCategory::ExecuteStatement(stmt) => {
format!("Execute Statement: {}...", stmt[..50])
}
};

return Some(CodeAction {
title,
command: Some(Command {
title,
command: command.category.into(),
arguments: None,
}),
disabled: action
.disabled_reason
.map(|reason| CodeActionDisabled { reason }),
..Default::default()
});
}
_ => todo!(),
})
.collect();

Ok(actions
.into_iter()
.map(|ac| CodeActionOrCommand::CodeAction(ac))
.collect())
}
5 changes: 5 additions & 0 deletions crates/pgt_lsp/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,11 @@ impl LanguageServer for LSPServer {
Err(e) => LspResult::Err(into_lsp_error(e)),
}
}

#[tracing::instrument(level = "trace", skip(self))]
async fn code_action(&self, params: CodeActionParams) -> Result<Option<CodeActionResponse>> {
let actions = handlers::code_actions::get_actions(session, params);
}
}

impl Drop for LSPServer {
Expand Down
8 changes: 5 additions & 3 deletions crates/pgt_workspace/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ version = "0.0.0"


[dependencies]
biome_deserialize = "0.6.0"
dashmap = "5.5.3"
futures = "0.3.31"
biome_deserialize = "0.6.0"
dashmap = "5.5.3"
futures = "0.3.31"
globset = "0.4.16"

ignore = { workspace = true }
pgt_analyse = { workspace = true, features = ["serde"] }
pgt_analyser = { workspace = true }
Expand Down
38 changes: 29 additions & 9 deletions crates/pgt_workspace/src/code_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ use pgt_configuration::RuleSelector;
use pgt_fs::PgTPath;
use pgt_text_size::TextRange;

use crate::Workspace;

#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct CodeActionsParams {
Expand All @@ -23,20 +21,42 @@ pub struct CodeActionsResult {
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub struct CodeAction {
pub category: CodeActionCategory,
pub kind: CodeActionKind,
pub disabled_reason: Option<String>,
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub enum CodeActionKind {
Edit(EditAction),
Command(CommandAction),
EditAndCommand(EditAction, CommandAction),
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub struct EditAction {}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "camelCase")]
pub struct CommandAction {
pub category: CommandActionCategory,
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub enum CodeActionCategory {
ExecuteCommand(String),
#[serde(rename_all = "camelCase")]
pub enum CommandActionCategory {
ExecuteStatement(String),
}

impl CodeActionCategory {
fn perform(self, workspace: &dyn Workspace) -> Result<(), String> {
impl Into<String> for CommandActionCategory {
fn into(self) -> String {
match self {
Self::ExecuteCommand(stmt) => {}
Self::ExecuteStatement(_) => "pgt.executeStatement".into(),
}
Ok(())
}
}
2 changes: 1 addition & 1 deletion crates/pgt_workspace/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::ops::{Deref, DerefMut};
use pgt_console::Console;
use pgt_fs::{FileSystem, OsFileSystem};

mod code_actions;
pub mod code_actions;
pub mod configuration;
pub mod diagnostics;
pub mod dome;
Expand Down
27 changes: 25 additions & 2 deletions crates/pgt_workspace/src/settings.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use biome_deserialize::StringSet;
use globset::Glob;
use pgt_diagnostics::Category;
use std::{
borrow::Cow,
Expand Down Expand Up @@ -273,6 +274,7 @@ pub struct DatabaseSettings {
pub password: String,
pub database: String,
pub conn_timeout_secs: Duration,
pub allow_statement_executions: bool,
}

impl Default for DatabaseSettings {
Expand All @@ -284,23 +286,44 @@ impl Default for DatabaseSettings {
password: "postgres".to_string(),
database: "postgres".to_string(),
conn_timeout_secs: Duration::from_secs(10),
allow_statement_executions: true,
}
}
}

impl From<PartialDatabaseConfiguration> for DatabaseSettings {
fn from(value: PartialDatabaseConfiguration) -> Self {
let d = DatabaseSettings::default();

let database = value.database.unwrap_or(d.database);
let host = value.host.unwrap_or(d.host);

let allow_statement_executions = value
.allow_statement_executions_against
.map(|stringset| {
stringset.iter().any(|pattern| {
let glob = Glob::new(pattern)
.expect(format!("Invalid pattern: {}", pattern).as_str())
.compile_matcher();

glob.is_match(format!("{}/{}", host, database))
})
})
.unwrap_or(false);

Self {
host: value.host.unwrap_or(d.host),
port: value.port.unwrap_or(d.port),
username: value.username.unwrap_or(d.username),
password: value.password.unwrap_or(d.password),
database: value.database.unwrap_or(d.database),
database,
host,

conn_timeout_secs: value
.conn_timeout_secs
.map(|s| Duration::from_secs(s.into()))
.unwrap_or(d.conn_timeout_secs),

allow_statement_executions,
}
}
}
Expand Down
20 changes: 18 additions & 2 deletions crates/pgt_workspace/src/workspace/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ use tree_sitter::TreeSitterStore;

use crate::{
WorkspaceError,
code_actions::{CodeAction, CodeActionCategory, CodeActionsResult},
code_actions::{
CodeAction, CodeActionKind, CodeActionsResult, CommandAction, CommandActionCategory,
},
configuration::to_analyser_rules,
settings::{Settings, SettingsHandle, SettingsHandleMut},
workspace::PullDiagnosticsResult,
Expand Down Expand Up @@ -274,9 +276,23 @@ impl Workspace for WorkspaceServer {

let mut actions: Vec<CodeAction> = vec![];

let settings = self
.settings
.read()
.expect("Unable to read settings for Code Actions");

let disabled_reason: Option<String> = if settings.db.allow_statement_executions {
None
} else {
Some("Statement execution not allowed against database.".into())
};

for (stmt, range, txt) in eligible_statements {
actions.push(CodeAction {
category: CodeActionCategory::ExecuteCommand(txt.into()),
kind: CodeActionKind::Command(CommandAction {
category: CommandActionCategory::ExecuteStatement(txt.into()),
}),
disabled_reason,
});
}

Expand Down
Loading