From a072fe109c6ebe3e8c2fe108f45d2c316616d56a Mon Sep 17 00:00:00 2001 From: psteinroe Date: Tue, 28 Oct 2025 18:20:37 +0100 Subject: [PATCH 1/2] chore: rename PgTPath --- AGENTS.md | 17 ++++++++++++- crates/pgls_cli/src/execute/process_file.rs | 4 ++-- .../execute/process_file/workspace_file.rs | 4 ++-- crates/pgls_cli/src/execute/walk.rs | 20 ++++++++-------- crates/pgls_cli/src/reporter/mod.rs | 4 ++-- crates/pgls_cli/src/reporter/terminal.rs | 4 ++-- crates/pgls_fs/src/fs.rs | 10 ++++---- crates/pgls_fs/src/fs/memory.rs | 24 +++++++++---------- crates/pgls_fs/src/fs/os.rs | 12 +++++----- crates/pgls_fs/src/lib.rs | 2 +- crates/pgls_fs/src/path.rs | 12 +++++----- crates/pgls_lsp/src/session.rs | 6 ++--- crates/pgls_workspace/src/dome.rs | 18 +++++++------- .../src/features/code_actions.rs | 6 ++--- .../src/features/completions.rs | 4 ++-- .../src/features/diagnostics.rs | 4 ++-- .../pgls_workspace/src/features/on_hover.rs | 4 ++-- crates/pgls_workspace/src/settings.rs | 12 +++++----- crates/pgls_workspace/src/workspace.rs | 16 ++++++------- crates/pgls_workspace/src/workspace/server.rs | 8 +++---- .../src/workspace/server.tests.rs | 24 +++++++++---------- crates/pgls_workspace_macros/src/lib.rs | 2 +- .../backend-jsonrpc/src/workspace.ts | 16 ++++++------- .../backend-jsonrpc/src/workspace.ts | 16 ++++++------- 24 files changed, 132 insertions(+), 117 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 0fd29630d..b3c1d9d1b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -150,6 +150,21 @@ Many parser structures are generated from PostgreSQL's protobuf definitions usin ### Database Schema The `pgls_schema_cache` crate contains SQL queries in `src/queries/` that introspect the database schema to build the in-memory cache. -### Multi-Platform Support +### Code Refactoring Tools +The project has `ast-grep` available for advanced code search and refactoring tasks. ast-grep is a structural search/replace tool that understands code syntax, making it useful for: +- Renaming types, functions, or variables across the codebase +- Finding and replacing code patterns +- Performing structural code transformations + +Example usage: +```bash +# Search for a pattern +ast-grep --pattern 'struct $NAME { $$$FIELDS }' + +# Replace a pattern across files +ast-grep --pattern 'OldType' --rewrite 'NewType' --update-all +``` + +### Multi-Platform Support The project includes platform-specific allocators and build configurations for Windows, macOS, and Linux. - Seeing the Treesitter tree for an SQL query can be helpful to debug and implement features. To do this, create a file with an SQL query, and run `just tree-print `. \ No newline at end of file diff --git a/crates/pgls_cli/src/execute/process_file.rs b/crates/pgls_cli/src/execute/process_file.rs index bd4407066..01c2ca3aa 100644 --- a/crates/pgls_cli/src/execute/process_file.rs +++ b/crates/pgls_cli/src/execute/process_file.rs @@ -5,7 +5,7 @@ use crate::execute::config::ExecutionMode; use crate::execute::walk::TraversalOptions; use check::check_file; use pgls_diagnostics::Error; -use pgls_fs::PgTPath; +use pgls_fs::PgLSPath; use std::marker::PhantomData; use std::ops::Deref; @@ -103,7 +103,7 @@ impl<'ctx, 'app> Deref for SharedTraversalOptions<'ctx, 'app> { /// diagnostics were emitted, or compare the formatted code with the original /// content of the file and emit a diff or write the new content to the disk if /// write mode is enabled -pub(crate) fn process_file(ctx: &TraversalOptions, pgls_path: &PgTPath) -> FileResult { +pub(crate) fn process_file(ctx: &TraversalOptions, pgls_path: &PgLSPath) -> FileResult { tracing::trace_span!("process_file", path = ?pgls_path).in_scope(move || { let shared_context = &SharedTraversalOptions::new(ctx); diff --git a/crates/pgls_cli/src/execute/process_file/workspace_file.rs b/crates/pgls_cli/src/execute/process_file/workspace_file.rs index 86c958423..35b711aba 100644 --- a/crates/pgls_cli/src/execute/process_file/workspace_file.rs +++ b/crates/pgls_cli/src/execute/process_file/workspace_file.rs @@ -1,7 +1,7 @@ use crate::execute::diagnostics::{ResultExt, ResultIoExt}; use crate::execute::process_file::SharedTraversalOptions; use pgls_diagnostics::{Error, category}; -use pgls_fs::{File, OpenOptions, PgTPath}; +use pgls_fs::{File, OpenOptions, PgLSPath}; use pgls_workspace::workspace::{FileGuard, OpenFileParams}; use pgls_workspace::{Workspace, WorkspaceError}; use std::path::{Path, PathBuf}; @@ -24,7 +24,7 @@ impl<'ctx, 'app> WorkspaceFile<'ctx, 'app> { ctx: &SharedTraversalOptions<'ctx, 'app>, path: &Path, ) -> Result { - let pgls_path = PgTPath::new(path); + let pgls_path = PgLSPath::new(path); let open_options = OpenOptions::default() .read(true) .write(ctx.config.allows_writes()); diff --git a/crates/pgls_cli/src/execute/walk.rs b/crates/pgls_cli/src/execute/walk.rs index 7edc8d454..c562b5283 100644 --- a/crates/pgls_cli/src/execute/walk.rs +++ b/crates/pgls_cli/src/execute/walk.rs @@ -5,7 +5,7 @@ use crate::reporter::{Report, TraversalData}; use crate::{CliDiagnostic, CliSession}; use crossbeam::channel::{Receiver, Sender, unbounded}; use pgls_diagnostics::{DiagnosticExt, Error, Resource}; -use pgls_fs::{FileSystem, PathInterner, PgTPath}; +use pgls_fs::{FileSystem, PathInterner, PgLSPath}; use pgls_fs::{TraversalContext, TraversalScope}; use pgls_workspace::dome::Dome; use pgls_workspace::workspace::IsPathIgnoredParams; @@ -133,7 +133,7 @@ fn traverse_inputs( fs: &dyn FileSystem, inputs: Vec, ctx: &TraversalOptions, -) -> (Duration, BTreeSet) { +) -> (Duration, BTreeSet) { let start = Instant::now(); fs.traversal(Box::new(move |scope: &dyn TraversalScope| { for input in inputs { @@ -299,11 +299,11 @@ pub(crate) struct TraversalOptions<'ctx, 'app> { pub(crate) remaining_diagnostics: &'ctx AtomicU32, /// List of paths that should be processed - pub(crate) evaluated_paths: RwLock>, + pub(crate) evaluated_paths: RwLock>, } impl TraversalOptions<'_, '_> { - pub(crate) fn increment_changed(&self, path: &PgTPath) { + pub(crate) fn increment_changed(&self, path: &PgLSPath) { self.changed.fetch_add(1, Ordering::Relaxed); self.evaluated_paths .write() @@ -329,7 +329,7 @@ impl TraversalContext for TraversalOptions<'_, '_> { &self.interner } - fn evaluated_paths(&self) -> BTreeSet { + fn evaluated_paths(&self) -> BTreeSet { self.evaluated_paths.read().unwrap().clone() } @@ -337,7 +337,7 @@ impl TraversalContext for TraversalOptions<'_, '_> { self.push_message(error); } - fn can_handle(&self, pgls_path: &PgTPath) -> bool { + fn can_handle(&self, pgls_path: &PgLSPath) -> bool { let path = pgls_path.as_path(); let is_valid_file = self.fs.path_is_file(path) @@ -372,22 +372,22 @@ impl TraversalContext for TraversalOptions<'_, '_> { true } - fn handle_path(&self, path: PgTPath) { + fn handle_path(&self, path: PgLSPath) { handle_file(self, &path) } - fn store_path(&self, path: PgTPath) { + fn store_path(&self, path: PgLSPath) { self.evaluated_paths .write() .unwrap() - .insert(PgTPath::new(path.as_path())); + .insert(PgLSPath::new(path.as_path())); } } /// This function wraps the [process_file] function implementing the traversal /// in a [catch_unwind] block and emit diagnostics in case of error (either the /// traversal function returns Err or panics) -fn handle_file(ctx: &TraversalOptions, path: &PgTPath) { +fn handle_file(ctx: &TraversalOptions, path: &PgLSPath) { match catch_unwind(move || process_file(ctx, path)) { Ok(Ok(FileStatus::Changed)) => { ctx.increment_changed(path); diff --git a/crates/pgls_cli/src/reporter/mod.rs b/crates/pgls_cli/src/reporter/mod.rs index 40d85a0f4..65df867c1 100644 --- a/crates/pgls_cli/src/reporter/mod.rs +++ b/crates/pgls_cli/src/reporter/mod.rs @@ -7,7 +7,7 @@ use crate::cli_options::{CliOptions, CliReporter}; use crate::diagnostics::CliDiagnostic; use pgls_console::Console; use pgls_diagnostics::{Error, Severity}; -use pgls_fs::PgTPath; +use pgls_fs::PgLSPath; use std::collections::BTreeSet; use std::path::PathBuf; use std::time::Duration; @@ -54,7 +54,7 @@ impl From for ReportMode { #[derive(Debug)] pub struct TraversalData { - pub evaluated_paths: BTreeSet, + pub evaluated_paths: BTreeSet, pub changed: usize, pub unchanged: usize, pub matches: usize, diff --git a/crates/pgls_cli/src/reporter/terminal.rs b/crates/pgls_cli/src/reporter/terminal.rs index c3a58047d..87a135a9b 100644 --- a/crates/pgls_cli/src/reporter/terminal.rs +++ b/crates/pgls_cli/src/reporter/terminal.rs @@ -4,7 +4,7 @@ use pgls_console::fmt::Formatter; use pgls_console::{Console, ConsoleExt, fmt, markup}; use pgls_diagnostics::advice::ListAdvice; use pgls_diagnostics::{Diagnostic, Error, PrintDiagnostic}; -use pgls_fs::PgTPath; +use pgls_fs::PgLSPath; use std::borrow::Cow; use std::collections::BTreeSet; @@ -51,7 +51,7 @@ fn log_diagnostics(console: &mut dyn Console, config: &ReportConfig, diagnostics } } -fn log_evaluated_paths(console: &mut dyn Console, evaluated_paths: &BTreeSet) { +fn log_evaluated_paths(console: &mut dyn Console, evaluated_paths: &BTreeSet) { let evaluated_paths_diagnostic = EvaluatedPathsDiagnostic { advice: ListAdvice { list: evaluated_paths diff --git a/crates/pgls_fs/src/fs.rs b/crates/pgls_fs/src/fs.rs index 0d29dd8c3..169e1bd52 100644 --- a/crates/pgls_fs/src/fs.rs +++ b/crates/pgls_fs/src/fs.rs @@ -1,4 +1,4 @@ -use crate::{PathInterner, PgTPath}; +use crate::{PathInterner, PgLSPath}; pub use memory::{ErrorEntry, MemoryFileSystem}; pub use os::OsFileSystem; use oxc_resolver::{Resolution, ResolveError}; @@ -313,18 +313,18 @@ pub trait TraversalContext: Sync { /// Checks if the traversal context can handle a particular path, used as /// an optimization to bail out of scheduling a file handler if it wouldn't /// be able to process the file anyway - fn can_handle(&self, path: &PgTPath) -> bool; + fn can_handle(&self, path: &PgLSPath) -> bool; /// This method will be called by the traversal for each file it finds /// where [TraversalContext::can_handle] returned true - fn handle_path(&self, path: PgTPath); + fn handle_path(&self, path: PgLSPath); /// This method will be called by the traversal for each file it finds /// where [TraversalContext::store_path] returned true - fn store_path(&self, path: PgTPath); + fn store_path(&self, path: PgLSPath); /// Returns the paths that should be handled - fn evaluated_paths(&self) -> BTreeSet; + fn evaluated_paths(&self) -> BTreeSet; } impl FileSystem for Arc diff --git a/crates/pgls_fs/src/fs/memory.rs b/crates/pgls_fs/src/fs/memory.rs index efd3e6ef7..e7c936c22 100644 --- a/crates/pgls_fs/src/fs/memory.rs +++ b/crates/pgls_fs/src/fs/memory.rs @@ -11,7 +11,7 @@ use parking_lot::{Mutex, RawMutex, RwLock, lock_api::ArcMutexGuard}; use pgls_diagnostics::{Error, Severity}; use crate::fs::OpenOptions; -use crate::{FileSystem, PgTPath, TraversalContext, TraversalScope}; +use crate::{FileSystem, PgLSPath, TraversalContext, TraversalScope}; use super::{BoxedTraversal, ErrorKind, File, FileSystemDiagnostic}; @@ -307,7 +307,7 @@ impl<'scope> TraversalScope<'scope> for MemoryTraversalScope<'scope> { if should_process_file { let _ = ctx.interner().intern_path(path.into()); - let pgls_path = PgTPath::new(path); + let pgls_path = PgLSPath::new(path); if !ctx.can_handle(&pgls_path) { continue; } @@ -338,7 +338,7 @@ impl<'scope> TraversalScope<'scope> for MemoryTraversalScope<'scope> { } fn handle(&self, context: &'scope dyn TraversalContext, path: PathBuf) { - context.handle_path(PgTPath::new(path)); + context.handle_path(PgLSPath::new(path)); } } @@ -354,7 +354,7 @@ mod tests { use parking_lot::Mutex; use pgls_diagnostics::Error; - use crate::{FileSystem, MemoryFileSystem, PathInterner, PgTPath, TraversalContext}; + use crate::{FileSystem, MemoryFileSystem, PathInterner, PgLSPath, TraversalContext}; use crate::{OpenOptions, fs::FileSystemExt}; #[test] @@ -521,7 +521,7 @@ mod tests { struct TestContext { interner: PathInterner, - visited: Mutex>, + visited: Mutex>, } impl TraversalContext for TestContext { @@ -533,19 +533,19 @@ mod tests { panic!("unexpected error {err:?}") } - fn can_handle(&self, _: &PgTPath) -> bool { + fn can_handle(&self, _: &PgLSPath) -> bool { true } - fn handle_path(&self, path: PgTPath) { + fn handle_path(&self, path: PgLSPath) { self.visited.lock().insert(path.to_written()); } - fn store_path(&self, path: PgTPath) { + fn store_path(&self, path: PgLSPath) { self.visited.lock().insert(path); } - fn evaluated_paths(&self) -> BTreeSet { + fn evaluated_paths(&self) -> BTreeSet { let lock = self.visited.lock(); lock.clone() } @@ -566,8 +566,8 @@ mod tests { swap(&mut visited, ctx.visited.get_mut()); assert_eq!(visited.len(), 2); - assert!(visited.contains(&PgTPath::new("dir1/file1"))); - assert!(visited.contains(&PgTPath::new("dir1/file2"))); + assert!(visited.contains(&PgLSPath::new("dir1/file1"))); + assert!(visited.contains(&PgLSPath::new("dir1/file2"))); // Traverse a single file fs.traversal(Box::new(|scope| { @@ -578,6 +578,6 @@ mod tests { swap(&mut visited, ctx.visited.get_mut()); assert_eq!(visited.len(), 1); - assert!(visited.contains(&PgTPath::new("dir2/file2"))); + assert!(visited.contains(&PgLSPath::new("dir2/file2"))); } } diff --git a/crates/pgls_fs/src/fs/os.rs b/crates/pgls_fs/src/fs/os.rs index 44a0c68c7..4308d8c71 100644 --- a/crates/pgls_fs/src/fs/os.rs +++ b/crates/pgls_fs/src/fs/os.rs @@ -2,7 +2,7 @@ use super::{BoxedTraversal, ErrorKind, File, FileSystemDiagnostic}; use crate::fs::OpenOptions; use crate::{ - FileSystem, PgTPath, + FileSystem, PgLSPath, fs::{TraversalContext, TraversalScope}, }; use oxc_resolver::{Resolution, ResolveError, ResolveOptions, Resolver}; @@ -211,7 +211,7 @@ impl<'scope> TraversalScope<'scope> for OsTraversalScope<'scope> { fn handle(&self, context: &'scope dyn TraversalContext, path: PathBuf) { self.scope.spawn(move |_| { - context.handle_path(PgTPath::new(path)); + context.handle_path(PgLSPath::new(path)); }); } } @@ -289,7 +289,7 @@ fn handle_any_file<'scope>( } if file_type.is_symlink() { - if !ctx.can_handle(&PgTPath::new(path.clone())) { + if !ctx.can_handle(&PgLSPath::new(path.clone())) { return; } let Ok((target_path, target_file_type)) = expand_symbolic_link(path.clone(), ctx) else { @@ -320,7 +320,7 @@ fn handle_any_file<'scope>( if let Some(file_name) = path.file_name() { let new_origin_path = old_origin_path.join(file_name); origin_path = Some(new_origin_path.clone()); - PgTPath::new(new_origin_path) + PgLSPath::new(new_origin_path) } else { ctx.push_diagnostic(Error::from(FileSystemDiagnostic { path: path.to_string_lossy().to_string(), @@ -330,7 +330,7 @@ fn handle_any_file<'scope>( return; } } else { - PgTPath::new(&path) + PgLSPath::new(&path) }; // Performing this check here let's us skip unsupported @@ -351,7 +351,7 @@ fn handle_any_file<'scope>( if file_type.is_file() { scope.spawn(move |_| { - ctx.store_path(PgTPath::new(path)); + ctx.store_path(PgLSPath::new(path)); }); return; } diff --git a/crates/pgls_fs/src/lib.rs b/crates/pgls_fs/src/lib.rs index f59a0dd2a..352f40a1a 100644 --- a/crates/pgls_fs/src/lib.rs +++ b/crates/pgls_fs/src/lib.rs @@ -7,7 +7,7 @@ mod path; pub use dir::ensure_cache_dir; pub use interner::PathInterner; -pub use path::PgTPath; +pub use path::PgLSPath; pub use fs::{ AutoSearchResult, ConfigName, ErrorEntry, File, FileSystem, FileSystemDiagnostic, diff --git a/crates/pgls_fs/src/path.rs b/crates/pgls_fs/src/path.rs index ed7f7e16d..071b116f1 100644 --- a/crates/pgls_fs/src/path.rs +++ b/crates/pgls_fs/src/path.rs @@ -85,7 +85,7 @@ impl From for FileKinds { #[derive(Debug, Clone, Eq, PartialEq, Hash, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] -pub struct PgTPath { +pub struct PgLSPath { path: PathBuf, /// Determines the kind of the file inside Postgres Tools. Some files are considered as configuration files, others as manifest files, and others as files to handle kind: FileKinds, @@ -93,7 +93,7 @@ pub struct PgTPath { was_written: bool, } -impl Deref for PgTPath { +impl Deref for PgLSPath { type Target = PathBuf; fn deref(&self) -> &Self::Target { @@ -101,13 +101,13 @@ impl Deref for PgTPath { } } -impl PartialOrd for PgTPath { +impl PartialOrd for PgLSPath { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for PgTPath { +impl Ord for PgLSPath { fn cmp(&self, other: &Self) -> Ordering { match self.kind.cmp(&other.kind) { Ordering::Equal => self.path.cmp(&other.path), @@ -116,7 +116,7 @@ impl Ord for PgTPath { } } -impl PgTPath { +impl PgLSPath { pub fn new(path_to_file: impl Into) -> Self { let path = path_to_file.into(); let kind = path.file_name().map(Self::priority).unwrap_or_default(); @@ -137,7 +137,7 @@ impl PgTPath { } } - /// Creates a new [PgTPath], marked as fixed + /// Creates a new [PgLSPath], marked as fixed pub fn to_written(&self) -> Self { Self { path: self.path.clone(), diff --git a/crates/pgls_lsp/src/session.rs b/crates/pgls_lsp/src/session.rs index 9a983446b..622c3e504 100644 --- a/crates/pgls_lsp/src/session.rs +++ b/crates/pgls_lsp/src/session.rs @@ -9,7 +9,7 @@ use futures::stream::FuturesUnordered; use pgls_analyse::RuleCategoriesBuilder; use pgls_configuration::{ConfigurationPathHint, PartialConfiguration}; use pgls_diagnostics::{DiagnosticExt, Error}; -use pgls_fs::{ConfigName, FileSystem, PgTPath}; +use pgls_fs::{ConfigName, FileSystem, PgLSPath}; use pgls_workspace::PartialConfigurationExt; use pgls_workspace::Workspace; use pgls_workspace::configuration::{LoadedConfiguration, load_configuration}; @@ -349,7 +349,7 @@ impl Session { self.documents.write().unwrap().remove(url); } - pub(crate) fn file_path(&self, url: &lsp_types::Url) -> Result { + pub(crate) fn file_path(&self, url: &lsp_types::Url) -> Result { let path_to_file = match url.to_file_path() { Err(_) => { // If we can't create a path, it's probably because the file doesn't exist. @@ -359,7 +359,7 @@ impl Session { Ok(path) => path, }; - Ok(PgTPath::new(path_to_file)) + Ok(PgLSPath::new(path_to_file)) } /// True if the client supports dynamic registration of "workspace/didChangeConfiguration" requests diff --git a/crates/pgls_workspace/src/dome.rs b/crates/pgls_workspace/src/dome.rs index 7f8259152..b0cfcb5b0 100644 --- a/crates/pgls_workspace/src/dome.rs +++ b/crates/pgls_workspace/src/dome.rs @@ -1,4 +1,4 @@ -use pgls_fs::PgTPath; +use pgls_fs::PgLSPath; use std::collections::BTreeSet; use std::collections::btree_set::Iter; use std::iter::{FusedIterator, Peekable}; @@ -7,16 +7,16 @@ use std::iter::{FusedIterator, Peekable}; /// specific paths like configuration files, manifests and more. #[derive(Debug, Default)] pub struct Dome { - paths: BTreeSet, + paths: BTreeSet, } impl Dome { - pub fn with_path(mut self, path: impl Into) -> Self { + pub fn with_path(mut self, path: impl Into) -> Self { self.paths.insert(path.into()); self } - pub fn new(paths: BTreeSet) -> Self { + pub fn new(paths: BTreeSet) -> Self { Self { paths } } @@ -26,17 +26,17 @@ impl Dome { } } - pub fn to_paths(self) -> BTreeSet { + pub fn to_paths(self) -> BTreeSet { self.paths } } pub struct DomeIterator<'a> { - iter: Peekable>, + iter: Peekable>, } impl<'a> DomeIterator<'a> { - pub fn next_config(&mut self) -> Option<&'a PgTPath> { + pub fn next_config(&mut self) -> Option<&'a PgLSPath> { if let Some(path) = self.iter.peek() { if path.is_config() { self.iter.next() @@ -48,7 +48,7 @@ impl<'a> DomeIterator<'a> { } } - pub fn next_ignore(&mut self) -> Option<&'a PgTPath> { + pub fn next_ignore(&mut self) -> Option<&'a PgLSPath> { if let Some(path) = self.iter.peek() { if path.is_ignore() { self.iter.next() @@ -62,7 +62,7 @@ impl<'a> DomeIterator<'a> { } impl<'a> Iterator for DomeIterator<'a> { - type Item = &'a PgTPath; + type Item = &'a PgLSPath; fn next(&mut self) -> Option { self.iter.next() diff --git a/crates/pgls_workspace/src/features/code_actions.rs b/crates/pgls_workspace/src/features/code_actions.rs index f5bc15017..55a3d0ca0 100644 --- a/crates/pgls_workspace/src/features/code_actions.rs +++ b/crates/pgls_workspace/src/features/code_actions.rs @@ -1,12 +1,12 @@ use crate::workspace::StatementId; use pgls_configuration::RuleSelector; -use pgls_fs::PgTPath; +use pgls_fs::PgLSPath; use pgls_text_size::TextSize; #[derive(Debug, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct CodeActionsParams { - pub path: PgTPath, + pub path: PgLSPath, pub cursor_position: TextSize, pub only: Vec, pub skip: Vec, @@ -54,7 +54,7 @@ pub enum CommandActionCategory { #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct ExecuteStatementParams { pub statement_id: StatementId, - pub path: PgTPath, + pub path: PgLSPath, } #[derive(Debug, serde::Serialize, serde::Deserialize, Default, PartialEq, Eq)] diff --git a/crates/pgls_workspace/src/features/completions.rs b/crates/pgls_workspace/src/features/completions.rs index 4da300907..773803589 100644 --- a/crates/pgls_workspace/src/features/completions.rs +++ b/crates/pgls_workspace/src/features/completions.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use pgls_completions::CompletionItem; -use pgls_fs::PgTPath; +use pgls_fs::PgLSPath; use pgls_text_size::{TextRange, TextSize}; use crate::workspace::{Document, GetCompletionsFilter, StatementId, WithCSTMapper}; @@ -10,7 +10,7 @@ use crate::workspace::{Document, GetCompletionsFilter, StatementId, WithCSTMappe #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct GetCompletionsParams { /// The File for which a completion is requested. - pub path: PgTPath, + pub path: PgLSPath, /// The Cursor position in the file for which a completion is requested. pub position: TextSize, } diff --git a/crates/pgls_workspace/src/features/diagnostics.rs b/crates/pgls_workspace/src/features/diagnostics.rs index 1684cd3a1..ed6eca6da 100644 --- a/crates/pgls_workspace/src/features/diagnostics.rs +++ b/crates/pgls_workspace/src/features/diagnostics.rs @@ -1,11 +1,11 @@ use pgls_analyse::RuleCategories; use pgls_configuration::RuleSelector; -use pgls_fs::PgTPath; +use pgls_fs::PgLSPath; #[derive(Debug, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct PullDiagnosticsParams { - pub path: PgTPath, + pub path: PgLSPath, pub categories: RuleCategories, pub max_diagnostics: u64, pub only: Vec, diff --git a/crates/pgls_workspace/src/features/on_hover.rs b/crates/pgls_workspace/src/features/on_hover.rs index b59303a27..6779a15b9 100644 --- a/crates/pgls_workspace/src/features/on_hover.rs +++ b/crates/pgls_workspace/src/features/on_hover.rs @@ -1,10 +1,10 @@ -use pgls_fs::PgTPath; +use pgls_fs::PgLSPath; use pgls_text_size::TextSize; #[derive(Debug, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct OnHoverParams { - pub path: PgTPath, + pub path: PgLSPath, pub position: TextSize, } diff --git a/crates/pgls_workspace/src/settings.rs b/crates/pgls_workspace/src/settings.rs index 8584a870d..08b29f7e3 100644 --- a/crates/pgls_workspace/src/settings.rs +++ b/crates/pgls_workspace/src/settings.rs @@ -20,7 +20,7 @@ use pgls_configuration::{ migrations::{MigrationsConfiguration, PartialMigrationsConfiguration}, plpgsql_check::PlPgSqlCheckConfiguration, }; -use pgls_fs::PgTPath; +use pgls_fs::PgLSPath; use sqlx::postgres::PgConnectOptions; use crate::{ @@ -33,7 +33,7 @@ use crate::{ /// The information tracked for each project pub struct ProjectData { /// The root path of the project. This path should be **absolute**. - path: PgTPath, + path: PgLSPath, /// The settings of the project, usually inferred from the configuration file e.g. `biome.json`. settings: Settings, } @@ -52,7 +52,7 @@ impl WorkspaceSettings { self.current_project } - pub fn get_current_project_path(&self) -> Option<&PgTPath> { + pub fn get_current_project_path(&self) -> Option<&PgLSPath> { trace!("Current key {:?}", self.current_project); self.data .get(self.current_project) @@ -94,7 +94,7 @@ impl WorkspaceSettings { /// Insert a new project using its folder. Use [WorkspaceSettings::get_current_settings_mut] to retrieve /// a mutable reference to its [Settings] and manipulate them. pub fn insert_project(&mut self, workspace_path: impl Into) -> ProjectKey { - let path = PgTPath::new(workspace_path.into()); + let path = PgLSPath::new(workspace_path.into()); trace!("Insert workspace folder: {:?}", path); self.data.insert(ProjectData { path, @@ -125,7 +125,7 @@ impl WorkspaceSettings { /// Checks if the current path belongs to a registered project. /// /// If there's a match, and the match **isn't** the current project, it returns the new key. - pub fn path_belongs_to_current_workspace(&self, path: &PgTPath) -> Option { + pub fn path_belongs_to_current_workspace(&self, path: &PgLSPath) -> Option { if self.data.is_empty() { return None; } @@ -172,7 +172,7 @@ impl<'a> WorkspaceSettingsHandle<'a> { self.inner.get_current_settings() } - pub(crate) fn path(&self) -> Option<&PgTPath> { + pub(crate) fn path(&self) -> Option<&PgLSPath> { self.inner.get_current_project_path() } } diff --git a/crates/pgls_workspace/src/workspace.rs b/crates/pgls_workspace/src/workspace.rs index b7c45408a..dda370a48 100644 --- a/crates/pgls_workspace/src/workspace.rs +++ b/crates/pgls_workspace/src/workspace.rs @@ -3,7 +3,7 @@ use std::{panic::RefUnwindSafe, path::PathBuf, sync::Arc}; pub use self::client::{TransportRequest, WorkspaceClient, WorkspaceTransport}; use pgls_analyse::RuleCategories; use pgls_configuration::{PartialConfiguration, RuleSelector}; -use pgls_fs::PgTPath; +use pgls_fs::PgLSPath; #[cfg(feature = "schema")] use schemars::{JsonSchema, SchemaGenerator, schema::Schema}; use serde::{Deserialize, Serialize}; @@ -30,7 +30,7 @@ pub(crate) use server::document::*; #[derive(Debug, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct OpenFileParams { - pub path: PgTPath, + pub path: PgLSPath, pub content: String, pub version: i32, } @@ -38,13 +38,13 @@ pub struct OpenFileParams { #[derive(Debug, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct CloseFileParams { - pub path: PgTPath, + pub path: PgLSPath, } #[derive(Debug, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct ChangeFileParams { - pub path: PgTPath, + pub path: PgLSPath, pub version: i32, pub content: String, } @@ -52,7 +52,7 @@ pub struct ChangeFileParams { #[derive(Debug, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct IsPathIgnoredParams { - pub pgls_path: PgTPath, + pub pgls_path: PgLSPath, } #[derive(Debug, serde::Serialize, serde::Deserialize)] @@ -67,7 +67,7 @@ pub struct UpdateSettingsParams { #[derive(Debug, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct GetFileContentParams { - pub path: PgTPath, + pub path: PgLSPath, } #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] @@ -93,7 +93,7 @@ pub struct RegisterProjectFolderParams { #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[serde(rename_all = "camelCase")] pub struct UnregisterProjectFolderParams { - pub path: PgTPath, + pub path: PgLSPath, } pub trait Workspace: Send + Sync + RefUnwindSafe { @@ -183,7 +183,7 @@ where /// automatically on drop pub struct FileGuard<'app, W: Workspace + ?Sized> { workspace: &'app W, - path: PgTPath, + path: PgLSPath, } impl<'app, W: Workspace + ?Sized> FileGuard<'app, W> { diff --git a/crates/pgls_workspace/src/workspace/server.rs b/crates/pgls_workspace/src/workspace/server.rs index eedbaed6d..f7ae3225d 100644 --- a/crates/pgls_workspace/src/workspace/server.rs +++ b/crates/pgls_workspace/src/workspace/server.rs @@ -20,7 +20,7 @@ use pgls_analyser::{Analyser, AnalyserConfig, AnalyserParams}; use pgls_diagnostics::{ Diagnostic, DiagnosticExt, Error, Severity, serde::Diagnostic as SDiagnostic, }; -use pgls_fs::{ConfigName, PgTPath}; +use pgls_fs::{ConfigName, PgLSPath}; use pgls_typecheck::{IdentifierType, TypecheckParams, TypedIdentifier}; use pgls_workspace_macros::ignored_path; use schema_cache_manager::SchemaCacheManager; @@ -71,7 +71,7 @@ pub(super) struct WorkspaceServer { /// Stores the schema cache for this workspace schema_cache: SchemaCacheManager, - documents: RwLock>, + documents: RwLock>, connection: ConnectionManager, } @@ -122,7 +122,7 @@ impl WorkspaceServer { } /// Retrieves the current project path - fn get_current_project_path(&self) -> Option { + fn get_current_project_path(&self) -> Option { self.workspaces().path().cloned() } @@ -136,7 +136,7 @@ impl WorkspaceServer { /// Checks whether the current path belongs to the current project. /// /// If there's a match, and the match **isn't** the current project, it returns the new key. - fn path_belongs_to_current_workspace(&self, path: &PgTPath) -> Option { + fn path_belongs_to_current_workspace(&self, path: &PgLSPath) -> Option { let workspaces = self.workspaces(); workspaces.as_ref().path_belongs_to_current_workspace(path) } diff --git a/crates/pgls_workspace/src/workspace/server.tests.rs b/crates/pgls_workspace/src/workspace/server.tests.rs index c5e2397d1..7c274251d 100644 --- a/crates/pgls_workspace/src/workspace/server.tests.rs +++ b/crates/pgls_workspace/src/workspace/server.tests.rs @@ -10,7 +10,7 @@ use pgls_configuration::{ #[cfg(not(target_os = "windows"))] use pgls_configuration::plpgsql_check::PartialPlPgSqlCheckConfiguration; use pgls_diagnostics::Diagnostic; -use pgls_fs::PgTPath; +use pgls_fs::PgLSPath; use pgls_text_size::TextRange; use sqlx::{Executor, PgPool}; @@ -62,7 +62,7 @@ async fn test_diagnostics(test_db: PgPool) { let workspace = get_test_workspace(Some(conf)).expect("Unable to create test workspace"); - let path = PgTPath::new("test.sql"); + let path = PgLSPath::new("test.sql"); let content = r#" create table users ( id serial primary key, @@ -127,7 +127,7 @@ async fn test_syntax_error(test_db: PgPool) { let workspace = get_test_workspace(Some(conf)).expect("Unable to create test workspace"); - let path = PgTPath::new("test.sql"); + let path = PgLSPath::new("test.sql"); let content = r#" seect 1; "#; @@ -176,7 +176,7 @@ async fn correctly_ignores_files() { let workspace = get_test_workspace(Some(conf)).expect("Unable to create test workspace"); - let path = PgTPath::new("test.sql"); + let path = PgLSPath::new("test.sql"); let content = r#" seect 1; "#; @@ -231,7 +231,7 @@ async fn test_dedupe_diagnostics(test_db: PgPool) { let workspace = get_test_workspace(Some(conf)).expect("Unable to create test workspace"); - let path = PgTPath::new("test.sql"); + let path = PgLSPath::new("test.sql"); let setup_sql = "CREATE EXTENSION IF NOT EXISTS plpgsql_check;"; test_db.execute(setup_sql).await.expect("setup sql failed"); @@ -288,7 +288,7 @@ async fn test_plpgsql_assign_composite_types(test_db: PgPool) { let workspace = get_test_workspace(Some(conf)).expect("Unable to create test workspace"); - let path = PgTPath::new("test.sql"); + let path = PgLSPath::new("test.sql"); let setup_sql = r" create table if not exists _fetch_cycle_continuation_data ( @@ -354,7 +354,7 @@ async fn test_positional_params(test_db: PgPool) { let workspace = get_test_workspace(Some(conf)).expect("Unable to create test workspace"); - let path = PgTPath::new("test.sql"); + let path = PgLSPath::new("test.sql"); let setup_sql = r" create table users ( @@ -409,7 +409,7 @@ async fn test_disable_plpgsql_check(test_db: PgPool) { let workspace = get_test_workspace(Some(conf)).expect("Unable to create test workspace"); - let path = PgTPath::new("test.sql"); + let path = PgLSPath::new("test.sql"); let setup_sql = "CREATE EXTENSION IF NOT EXISTS plpgsql_check;"; test_db.execute(setup_sql).await.expect("setup sql failed"); @@ -508,7 +508,7 @@ async fn test_disable_typecheck(test_db: PgPool) { let workspace = get_test_workspace(Some(conf)).expect("Unable to create test workspace"); - let path = PgTPath::new("test.sql"); + let path = PgLSPath::new("test.sql"); let setup_sql = r" create table users ( @@ -588,7 +588,7 @@ async fn test_named_params(_test_db: PgPool) { let workspace = get_test_workspace(Some(conf)).expect("Unable to create test workspace"); - let path = PgTPath::new("test.sql"); + let path = PgLSPath::new("test.sql"); let content = r#" SELECT @@ -648,7 +648,7 @@ async fn test_cstyle_comments(test_db: PgPool) { let workspace = get_test_workspace(Some(conf)).expect("Unable to create test workspace"); - let path = PgTPath::new("test.sql"); + let path = PgLSPath::new("test.sql"); let content = r#" /* @@ -695,7 +695,7 @@ async fn test_search_path_configuration(test_db: PgPool) { "#; test_db.execute(setup_sql).await.expect("setup sql failed"); - let path_glob = PgTPath::new("test_glob.sql"); + let path_glob = PgLSPath::new("test_glob.sql"); let file_content = r#" select get_user_id(); -- on private schema "#; diff --git a/crates/pgls_workspace_macros/src/lib.rs b/crates/pgls_workspace_macros/src/lib.rs index d46f484da..2f77cd154 100644 --- a/crates/pgls_workspace_macros/src/lib.rs +++ b/crates/pgls_workspace_macros/src/lib.rs @@ -31,7 +31,7 @@ impl syn::parse::Parse for IgnoredPath { /// is ignored by the user's settings. /// /// This will work for any function where &self is in scope and that returns `Result`, `Result<(), E>`, or `T`, where `T: Default`. -/// `path` needs to point at a `&PgTPath`. +/// `path` needs to point at a `&PgLSPath`. /// /// ### Usage /// diff --git a/packages/@postgres-language-server/backend-jsonrpc/src/workspace.ts b/packages/@postgres-language-server/backend-jsonrpc/src/workspace.ts index 24ea5d503..afc6174c4 100644 --- a/packages/@postgres-language-server/backend-jsonrpc/src/workspace.ts +++ b/packages/@postgres-language-server/backend-jsonrpc/src/workspace.ts @@ -1,9 +1,9 @@ // Generated file, do not edit by hand, see `xtask/codegen` import type { Transport } from "./transport"; export interface IsPathIgnoredParams { - pgt_path: PgTPath; + pgt_path: PgLSPath; } -export interface PgTPath { +export interface PgLSPath { /** * Determines the kind of the file inside Postgres Tools. Some files are considered as configuration files, others as manifest files, and others as files to handle */ @@ -25,13 +25,13 @@ export interface RegisterProjectFolderParams { } export type ProjectKey = string; export interface GetFileContentParams { - path: PgTPath; + path: PgLSPath; } export interface PullDiagnosticsParams { categories: RuleCategories; max_diagnostics: number; only: RuleCode[]; - path: PgTPath; + path: PgLSPath; skip: RuleCode[]; } export type RuleCategories = RuleCategory[]; @@ -203,7 +203,7 @@ export interface GetCompletionsParams { /** * The File for which a completion is requested. */ - path: PgTPath; + path: PgLSPath; /** * The Cursor position in the file for which a completion is requested. */ @@ -572,16 +572,16 @@ export interface RuleWithOptions_for_Null { } export interface OpenFileParams { content: string; - path: PgTPath; + path: PgLSPath; version: number; } export interface ChangeFileParams { content: string; - path: PgTPath; + path: PgLSPath; version: number; } export interface CloseFileParams { - path: PgTPath; + path: PgLSPath; } export type Configuration = PartialConfiguration; export interface Workspace { diff --git a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts index 6e1498c2a..19a31550c 100644 --- a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts +++ b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts @@ -1,9 +1,9 @@ // Generated file, do not edit by hand, see `xtask/codegen` import type { Transport } from "./transport"; export interface IsPathIgnoredParams { - pgls_path: PgTPath; + pgls_path: PgLSPath; } -export interface PgTPath { +export interface PgLSPath { /** * Determines the kind of the file inside Postgres Tools. Some files are considered as configuration files, others as manifest files, and others as files to handle */ @@ -25,13 +25,13 @@ export interface RegisterProjectFolderParams { } export type ProjectKey = string; export interface GetFileContentParams { - path: PgTPath; + path: PgLSPath; } export interface PullDiagnosticsParams { categories: RuleCategories; max_diagnostics: number; only: RuleCode[]; - path: PgTPath; + path: PgLSPath; skip: RuleCode[]; } export type RuleCategories = RuleCategory[]; @@ -208,7 +208,7 @@ export interface GetCompletionsParams { /** * The File for which a completion is requested. */ - path: PgTPath; + path: PgLSPath; /** * The Cursor position in the file for which a completion is requested. */ @@ -601,16 +601,16 @@ export interface RuleWithOptions_for_Null { } export interface OpenFileParams { content: string; - path: PgTPath; + path: PgLSPath; version: number; } export interface ChangeFileParams { content: string; - path: PgTPath; + path: PgLSPath; version: number; } export interface CloseFileParams { - path: PgTPath; + path: PgLSPath; } export type Configuration = PartialConfiguration; export interface Workspace { From c5d24120e7236c8f69d9731dc632c1acb1174bcd Mon Sep 17 00:00:00 2001 From: psteinroe Date: Tue, 28 Oct 2025 18:46:31 +0100 Subject: [PATCH 2/2] progress --- .vscode/settings.json | 2 +- AGENTS.md | 8 ++-- crates/pgls_cli/src/commands/mod.rs | 26 ++++++------ crates/pgls_cli/src/lib.rs | 24 +++++------ crates/pgls_cli/src/main.rs | 6 +-- .../src/analyser/linter/rules.rs | 2 +- crates/pgls_fs/src/path.rs | 2 +- docs/codegen/src/cli_doc.rs | 4 +- docs/getting_started.md | 4 +- docs/guides/continuous_integration.md | 2 +- docs/guides/ide_setup.md | 2 +- docs/reference/cli.md | 10 ++--- docs/schema.json | 2 +- .../backend-jsonrpc/src/workspace.ts | 41 ++++++++++++++++--- .../backend-jsonrpc/src/workspace.ts | 4 +- pyproject.toml | 2 +- xtask/codegen/src/generate_bindings.rs | 8 +++- xtask/codegen/src/generate_configuration.rs | 2 +- 18 files changed, 92 insertions(+), 59 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 43994f875..c43946866 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "postgrestools.bin": "./target/debug/postgrestools" + "postgres-language-server.bin": "./target/debug/postgres-language-server" } diff --git a/AGENTS.md b/AGENTS.md index b3c1d9d1b..73fe17907 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -62,11 +62,11 @@ just new-crate ``` ### CLI Usage -The main CLI binary is `postgrestools`: +The main CLI binary is `postgres-language-server` (legacy name: `postgrestools`): ```bash cargo run -p pgls_cli -- check file.sql # or after building: -./target/release/postgrestools check file.sql +./target/release/postgres-language-server check file.sql ``` ## Architecture @@ -103,8 +103,8 @@ The project uses a modular Rust workspace with crates prefixed with `pgls_`: ### TypeScript Packages Located in `packages/` and `editors/`: - VSCode extension in `editors/code/` -- Backend JSON-RPC bridge in `packages/@postgrestools/backend-jsonrpc/` -- Main TypeScript package in `packages/@postgrestools/postgrestools/` +- Backend JSON-RPC bridge in `packages/@postgres-language-server/backend-jsonrpc/` (legacy: `packages/@postgrestools/backend-jsonrpc/`) +- Main TypeScript package in `packages/@postgres-language-server/postgres-language-server/` (legacy: `packages/@postgrestools/postgrestools/`) ### Database Integration The server connects to a Postgres database to build an in-memory schema cache containing tables, columns, functions, and type information. This enables accurate autocompletion and type checking. diff --git a/crates/pgls_cli/src/commands/mod.rs b/crates/pgls_cli/src/commands/mod.rs index 503ed17be..63f9ded37 100644 --- a/crates/pgls_cli/src/commands/mod.rs +++ b/crates/pgls_cli/src/commands/mod.rs @@ -19,7 +19,7 @@ pub(crate) mod version; #[bpaf(options, version(VERSION))] #[allow(clippy::large_enum_variant)] /// Postgres Tools official CLI. Use it to check the health of your project or run it to check single files. -pub enum PgtCommand { +pub enum PgLSCommand { /// Shows the version information and quit. #[bpaf(command)] Version(#[bpaf(external(cli_options), hide_usage)] CliOptions), @@ -218,19 +218,19 @@ pub enum PgtCommand { PrintSocket, } -impl PgtCommand { +impl PgLSCommand { const fn cli_options(&self) -> Option<&CliOptions> { match self { - PgtCommand::Version(cli_options) - | PgtCommand::Check { cli_options, .. } - | PgtCommand::Dblint { cli_options, .. } => Some(cli_options), - PgtCommand::LspProxy { .. } - | PgtCommand::Start { .. } - | PgtCommand::Stop - | PgtCommand::Init - | PgtCommand::RunServer { .. } - | PgtCommand::Clean - | PgtCommand::PrintSocket => None, + PgLSCommand::Version(cli_options) + | PgLSCommand::Check { cli_options, .. } + | PgLSCommand::Dblint { cli_options, .. } => Some(cli_options), + PgLSCommand::LspProxy { .. } + | PgLSCommand::Start { .. } + | PgLSCommand::Stop + | PgLSCommand::Init + | PgLSCommand::RunServer { .. } + | PgLSCommand::Clean + | PgLSCommand::PrintSocket => None, } } @@ -315,6 +315,6 @@ mod tests { /// Tests that all CLI options adhere to the invariants expected by `bpaf`. #[test] fn check_options() { - pgt_command().check_invariants(false); + pg_l_s_command().check_invariants(false); } } diff --git a/crates/pgls_cli/src/lib.rs b/crates/pgls_cli/src/lib.rs index ee93dd759..e867f8e45 100644 --- a/crates/pgls_cli/src/lib.rs +++ b/crates/pgls_cli/src/lib.rs @@ -25,7 +25,7 @@ mod service; mod workspace; use crate::cli_options::ColorsArg; -pub use crate::commands::{PgtCommand, pgt_command}; +pub use crate::commands::{PgLSCommand, pg_l_s_command}; pub use crate::logging::{LoggingLevel, setup_cli_subscriber}; use crate::reporter::Report; pub use diagnostics::CliDiagnostic; @@ -57,19 +57,19 @@ impl<'app> CliSession<'app> { } /// Main function to run the CLI - pub fn run(self, command: PgtCommand) -> Result<(), CliDiagnostic> { + pub fn run(self, command: PgLSCommand) -> Result<(), CliDiagnostic> { let has_metrics = command.has_metrics(); if has_metrics { crate::metrics::init_metrics(); } let result = match command { - PgtCommand::Version(_) => commands::version::version(self), - PgtCommand::Dblint { + PgLSCommand::Version(_) => commands::version::version(self), + PgLSCommand::Dblint { cli_options, configuration, } => commands::dblint::dblint(self, &cli_options, configuration), - PgtCommand::Check { + PgLSCommand::Check { cli_options, configuration, paths, @@ -89,21 +89,21 @@ impl<'app> CliSession<'app> { since, }, ), - PgtCommand::Clean => commands::clean::clean(self), - PgtCommand::Start { + PgLSCommand::Clean => commands::clean::clean(self), + PgLSCommand::Start { config_path, log_path, log_prefix_name, } => commands::daemon::start(self, config_path, Some(log_path), Some(log_prefix_name)), - PgtCommand::Stop => commands::daemon::stop(self), - PgtCommand::Init => commands::init::init(self), - PgtCommand::LspProxy { + PgLSCommand::Stop => commands::daemon::stop(self), + PgLSCommand::Init => commands::init::init(self), + PgLSCommand::LspProxy { config_path, log_path, log_prefix_name, .. } => commands::daemon::lsp_proxy(config_path, Some(log_path), Some(log_prefix_name)), - PgtCommand::RunServer { + PgLSCommand::RunServer { stop_on_disconnect, config_path, log_path, @@ -118,7 +118,7 @@ impl<'app> CliSession<'app> { Some(log_level), Some(log_kind), ), - PgtCommand::PrintSocket => commands::daemon::print_socket(), + PgLSCommand::PrintSocket => commands::daemon::print_socket(), }; if has_metrics { diff --git a/crates/pgls_cli/src/main.rs b/crates/pgls_cli/src/main.rs index f19a16218..75c977487 100644 --- a/crates/pgls_cli/src/main.rs +++ b/crates/pgls_cli/src/main.rs @@ -1,7 +1,7 @@ //! This is the main binary use pgls_cli::{ - CliDiagnostic, CliSession, PgtCommand, open_transport, pgt_command, setup_panic_handler, + CliDiagnostic, CliSession, PgLSCommand, open_transport, pg_l_s_command, setup_panic_handler, to_color_mode, }; use pgls_console::{ConsoleExt, EnvConsole, markup}; @@ -31,7 +31,7 @@ fn main() -> ExitCode { set_bottom_frame(main as usize); let mut console = EnvConsole::default(); - let command = pgt_command().fallback_to_usage().run(); + let command = pg_l_s_command().fallback_to_usage().run(); console.set_color(to_color_mode(command.get_color())); @@ -50,7 +50,7 @@ fn main() -> ExitCode { } } -fn run_workspace(console: &mut EnvConsole, command: PgtCommand) -> Result<(), CliDiagnostic> { +fn run_workspace(console: &mut EnvConsole, command: PgLSCommand) -> Result<(), CliDiagnostic> { // If the `--use-server` CLI flag is set, try to open a connection to an // existing server socket let workspace = if command.should_use_server() { diff --git a/crates/pgls_configuration/src/analyser/linter/rules.rs b/crates/pgls_configuration/src/analyser/linter/rules.rs index 7b2d5018f..78d671b9b 100644 --- a/crates/pgls_configuration/src/analyser/linter/rules.rs +++ b/crates/pgls_configuration/src/analyser/linter/rules.rs @@ -46,7 +46,7 @@ impl std::str::FromStr for RuleGroup { #[cfg_attr(feature = "schema", derive(JsonSchema))] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct Rules { - #[doc = r" It enables the lint rules recommended by Postgres Tools. `true` by default."] + #[doc = r" It enables the lint rules recommended by Postgres Language Server. `true` by default."] #[serde(skip_serializing_if = "Option::is_none")] pub recommended: Option, #[doc = r" It enables ALL rules. The rules that belong to `nursery` won't be enabled."] diff --git a/crates/pgls_fs/src/path.rs b/crates/pgls_fs/src/path.rs index 071b116f1..48ff47f4f 100644 --- a/crates/pgls_fs/src/path.rs +++ b/crates/pgls_fs/src/path.rs @@ -87,7 +87,7 @@ impl From for FileKinds { #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub struct PgLSPath { path: PathBuf, - /// Determines the kind of the file inside Postgres Tools. Some files are considered as configuration files, others as manifest files, and others as files to handle + /// Determines the kind of the file inside Postgres Language Server. Some files are considered as configuration files, others as manifest files, and others as files to handle kind: FileKinds, /// Whether this path (usually a file) was fixed as a result of a format/lint/check command with the `--write` filag. was_written: bool, diff --git a/docs/codegen/src/cli_doc.rs b/docs/codegen/src/cli_doc.rs index 1fd9bdadf..1e9e93253 100644 --- a/docs/codegen/src/cli_doc.rs +++ b/docs/codegen/src/cli_doc.rs @@ -1,4 +1,4 @@ -use pgls_cli::pgt_command; +use pgls_cli::pg_l_s_command; use std::{fs, path::Path}; use crate::utils; @@ -11,7 +11,7 @@ pub fn generate_cli_doc(docs_dir: &Path) -> anyhow::Result<()> { let new_content = utils::replace_section( &content, "CLI_REF", - &pgt_command().render_markdown("postgres-language-server"), + &pg_l_s_command().render_markdown("postgres-language-server"), ); fs::write(file_path, &new_content)?; diff --git a/docs/getting_started.md b/docs/getting_started.md index 165a506f1..6cd7b2b29 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -71,14 +71,14 @@ Run `postgres-language-server --help` for all options. The CLI options take prec The Postgres Language Server is available as an extension in your favorite editors. -- VSCode: The language server is available on the [VSCode Marketplace](https://marketplace.visualstudio.com/items?itemName=Supabase.postgrestools). It's published from [this repo](https://github.com/supabase-community/postgrestools-vscode). +- VSCode: The language server is available on the [VSCode Marketplace](https://marketplace.visualstudio.com/items?itemName=Supabase.postgrestools). It's published from [this repo](https://github.com/supabase-community/postgres-language-server-vscode). - Neovim: You will have to install `nvim-lspconfig`, and follow the [instructions](https://github.com/neovim/nvim-lspconfig/blob/master/doc/configs.md#postgres_lsp). - Emacs: The language client is available through [lsp-mode](https://github.com/emacs-lsp/lsp-mode). For more details, refer to their [manual page](https://emacs-lsp.github.io/lsp-mode/page/lsp-postgres/). - Zed: The language server is available as an Extension. It's published from [this repo](https://github.com/LoamStudios/zed-postgres-language-server). ### Continuous Integration -Run `postgres-language-server check` in your CI pipeline to lint your schema changes and enforce code quality across your team. We provide a [GitHub Action](https://github.com/supabase-community/postgrestools-cli-action) to setup the Postgres Language Server in your runner. +Run `postgres-language-server check` in your CI pipeline to lint your schema changes and enforce code quality across your team. We provide a [GitHub Action](https://github.com/supabase-community/postgres-language-server-cli-action) to setup the Postgres Language Server in your runner. See the [Continuous Integration](/guides/continuous_integration) guide for an example. diff --git a/docs/guides/continuous_integration.md b/docs/guides/continuous_integration.md index 06e1a8e27..e656f5b8b 100644 --- a/docs/guides/continuous_integration.md +++ b/docs/guides/continuous_integration.md @@ -4,7 +4,7 @@ Running the Postgres Language Server in a CI environment can boost your teams co ### GitHub Actions -We provide a first-party [GitHub Action](https://github.com/supabase-community/postgrestools-cli-action) to setup the CLI in your runner. Here's what a simple workflow might look like: +We provide a first-party [GitHub Action](https://github.com/supabase-community/postgres-language-server-cli-action) to setup the CLI in your runner. Here's what a simple workflow might look like: ```yaml jobs: diff --git a/docs/guides/ide_setup.md b/docs/guides/ide_setup.md index 9689705f5..30cd344aa 100644 --- a/docs/guides/ide_setup.md +++ b/docs/guides/ide_setup.md @@ -4,7 +4,7 @@ Th Postgres Language Server has first-class [LSP](https://microsoft.github.io/la ## VSCode -The language server is available on the [VSCode Marketplace](https://marketplace.visualstudio.com/items?itemName=Supabase.postgrestools). It's published from [this repo](https://github.com/supabase-community/postgrestools-vscode). +The language server is available on the [VSCode Marketplace](https://marketplace.visualstudio.com/items?itemName=Supabase.postgrestools). It's published from [this repo](https://github.com/supabase-community/postgres-language-server-vscode). ## Neovim diff --git a/docs/reference/cli.md b/docs/reference/cli.md index b71c616e6..6a7d24b11 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -15,7 +15,7 @@ ## postgres-language-server -PostgresTools official CLI. Use it to check the health of your project or run it to check single files. +Postgres Language Server official CLI. Use it to check the health of your project or run it to check single files. **Usage**: **`postgres-language-server`** _`COMMAND ...`_ @@ -69,7 +69,7 @@ Shows the version information and quit. - **` --no-errors-on-unmatched`** — Silence errors that would be emitted in case no files were processed during the execution of the command. - **` --error-on-warnings`** — - Tell Postgres Tools to exit with an error code if some diagnostics emit warnings. + Tell Postgres Language Server to exit with an error code if some diagnostics emit warnings. - **` --reporter`**=_``_ — Allows to change how diagnostics and summary are reported. - **` --log-level`**=_``_ — @@ -83,7 +83,7 @@ Shows the version information and quit. How the log should look like. [default: pretty] - **` --diagnostic-level`**=_``_ — - The level of diagnostics to show. In order, from the lowest to the most important: info, warn, error. Passing `--diagnostic-level=error` will cause Postgres Tools to print only diagnostics that contain only errors. + The level of diagnostics to show. In order, from the lowest to the most important: info, warn, error. Passing `--diagnostic-level=error` will cause Postgres Language Server to print only diagnostics that contain only errors. [default: info] **Available options:** @@ -154,7 +154,7 @@ Runs everything to the requested files. - **` --no-errors-on-unmatched`** — Silence errors that would be emitted in case no files were processed during the execution of the command. - **` --error-on-warnings`** — - Tell Postgres Tools to exit with an error code if some diagnostics emit warnings. + Tell Postgres Language Server to exit with an error code if some diagnostics emit warnings. - **` --reporter`**=_``_ — Allows to change how diagnostics and summary are reported. - **` --log-level`**=_``_ — @@ -168,7 +168,7 @@ Runs everything to the requested files. How the log should look like. [default: pretty] - **` --diagnostic-level`**=_``_ — - The level of diagnostics to show. In order, from the lowest to the most important: info, warn, error. Passing `--diagnostic-level=error` will cause Postgres Tools to print only diagnostics that contain only errors. + The level of diagnostics to show. In order, from the lowest to the most important: info, warn, error. Passing `--diagnostic-level=error` will cause Postgres Language Server to print only diagnostics that contain only errors. [default: info] **Available positional items:** diff --git a/docs/schema.json b/docs/schema.json index 094078129..52d90b8b0 100644 --- a/docs/schema.json +++ b/docs/schema.json @@ -340,7 +340,7 @@ ] }, "recommended": { - "description": "It enables the lint rules recommended by Postgres Tools. `true` by default.", + "description": "It enables the lint rules recommended by Postgres Language Server. `true` by default.", "type": [ "boolean", "null" diff --git a/packages/@postgres-language-server/backend-jsonrpc/src/workspace.ts b/packages/@postgres-language-server/backend-jsonrpc/src/workspace.ts index afc6174c4..98ce65cb9 100644 --- a/packages/@postgres-language-server/backend-jsonrpc/src/workspace.ts +++ b/packages/@postgres-language-server/backend-jsonrpc/src/workspace.ts @@ -1,11 +1,11 @@ // Generated file, do not edit by hand, see `xtask/codegen` import type { Transport } from "./transport"; export interface IsPathIgnoredParams { - pgt_path: PgLSPath; + pgls_path: PgLSPath; } export interface PgLSPath { /** - * Determines the kind of the file inside Postgres Tools. Some files are considered as configuration files, others as manifest files, and others as files to handle + * Determines the kind of the file inside Postgres Language Server. Some files are considered as configuration files, others as manifest files, and others as files to handle */ kind: FileKind; path: string; @@ -63,6 +63,7 @@ export interface Advices { advices: Advice[]; } export type Category = + | "lint/safety/addSerialColumn" | "lint/safety/addingFieldWithDefault" | "lint/safety/addingForeignKeyConstraint" | "lint/safety/addingNotNullField" @@ -77,7 +78,10 @@ export type Category = | "lint/safety/banTruncateCascade" | "lint/safety/changingColumnType" | "lint/safety/constraintMissingNotValid" + | "lint/safety/creatingEnum" | "lint/safety/disallowUniqueConstraint" + | "lint/safety/lockTimeoutWarning" + | "lint/safety/multipleAlterTable" | "lint/safety/preferBigInt" | "lint/safety/preferBigintOverInt" | "lint/safety/preferBigintOverSmallint" @@ -90,6 +94,7 @@ export type Category = | "lint/safety/renamingTable" | "lint/safety/requireConcurrentIndexCreation" | "lint/safety/requireConcurrentIndexDeletion" + | "lint/safety/runningStatementWhileHoldingAccessExclusive" | "lint/safety/transactionNesting" | "stdin" | "check" @@ -122,7 +127,7 @@ export type DiagnosticTags = DiagnosticTag[]; /** * Serializable representation of a [Diagnostic](super::Diagnostic) advice -See the [Visitor] trait for additional documentation on all the supported advice types. +See the [Visitor] trait for additional documentation on all the supported advice types. */ export type Advice = | { log: [LogCategory, MarkupBuf] } @@ -227,7 +232,7 @@ export interface CompletionItem { /** * The text that the editor should fill in. If `None`, the `label` should be used. Tables, for example, might have different completion_texts: -label: "users", description: "Schema: auth", completion_text: "auth.users". +label: "users", description: "Schema: auth", completion_text: "auth.users". */ export interface CompletionText { is_snippet: boolean; @@ -300,6 +305,10 @@ export interface PartialDatabaseConfiguration { * The connection timeout in seconds. */ connTimeoutSecs?: number; + /** + * A connection string that encodes the full connection setup. When provided, it takes precedence over the individual fields. + */ + connectionString?: string; /** * The name of the database. */ @@ -411,7 +420,7 @@ export interface PartialVcsConfiguration { /** * The folder where we should check for VCS files. By default, we will use the same folder where `postgres-language-server.jsonc` was found. -If we can't find the configuration, it will attempt to use the current working directory. If no current working directory can't be found, we won't use the VCS integration, and a diagnostic will be emitted +If we can't find the configuration, it will attempt to use the current working directory. If no current working directory can't be found, we won't use the VCS integration, and a diagnostic will be emitted */ root?: string; /** @@ -425,7 +434,7 @@ export interface Rules { */ all?: boolean; /** - * It enables the lint rules recommended by Postgres Tools. `true` by default. + * It enables the lint rules recommended by Postgres Language Server. `true` by default. */ recommended?: boolean; safety?: Safety; @@ -435,6 +444,10 @@ export type VcsClientKind = "git"; * A list of rules that belong to this group */ export interface Safety { + /** + * Adding a column with a SERIAL type or GENERATED ALWAYS AS ... STORED causes a full table rewrite. + */ + addSerialColumn?: RuleConfiguration_for_Null; /** * Adding a column with a DEFAULT value may lead to a table rewrite while holding an ACCESS EXCLUSIVE lock. */ @@ -495,10 +508,22 @@ export interface Safety { * Adding constraints without NOT VALID blocks all reads and writes. */ constraintMissingNotValid?: RuleConfiguration_for_Null; + /** + * Creating enum types is not recommended for new applications. + */ + creatingEnum?: RuleConfiguration_for_Null; /** * Disallow adding a UNIQUE constraint without using an existing index. */ disallowUniqueConstraint?: RuleConfiguration_for_Null; + /** + * Taking a dangerous lock without setting a lock timeout can cause indefinite blocking. + */ + lockTimeoutWarning?: RuleConfiguration_for_Null; + /** + * Multiple ALTER TABLE statements on the same table should be combined into a single statement. + */ + multipleAlterTable?: RuleConfiguration_for_Null; /** * Prefer BIGINT over smaller integer types. */ @@ -551,6 +576,10 @@ export interface Safety { * Dropping indexes non-concurrently can lock the table for reads. */ requireConcurrentIndexDeletion?: RuleConfiguration_for_Null; + /** + * Running additional statements while holding an ACCESS EXCLUSIVE lock blocks all table access. + */ + runningStatementWhileHoldingAccessExclusive?: RuleConfiguration_for_Null; /** * Detects problematic transaction nesting that could lead to unexpected behavior. */ diff --git a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts index 19a31550c..98ce65cb9 100644 --- a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts +++ b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts @@ -5,7 +5,7 @@ export interface IsPathIgnoredParams { } export interface PgLSPath { /** - * Determines the kind of the file inside Postgres Tools. Some files are considered as configuration files, others as manifest files, and others as files to handle + * Determines the kind of the file inside Postgres Language Server. Some files are considered as configuration files, others as manifest files, and others as files to handle */ kind: FileKind; path: string; @@ -434,7 +434,7 @@ export interface Rules { */ all?: boolean; /** - * It enables the lint rules recommended by Postgres Tools. `true` by default. + * It enables the lint rules recommended by Postgres Language Server. `true` by default. */ recommended?: boolean; safety?: Safety; diff --git a/pyproject.toml b/pyproject.toml index 41317471b..a7d03d76b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "postgrestools" +name = "postgres-language-server" version = "0.1.0" description = "A collection of language tools and a Language Server Protocol (LSP) implementation for Postgres, focusing on developer experience and reliable SQL tooling." readme = "README.md" diff --git a/xtask/codegen/src/generate_bindings.rs b/xtask/codegen/src/generate_bindings.rs index 5a569a5f8..4b7bb489d 100644 --- a/xtask/codegen/src/generate_bindings.rs +++ b/xtask/codegen/src/generate_bindings.rs @@ -14,8 +14,10 @@ use pgls_workspace::workspace_types::{generate_type, methods, ModuleQueue}; use xtask::{project_root, Mode, Result}; pub fn generate_bindings(mode: Mode) -> Result<()> { - let bindings_path = + let bindings_path_postgrestools = project_root().join("packages/@postgrestools/backend-jsonrpc/src/workspace.ts"); + let bindings_path_postgres_language_server = + project_root().join("packages/@postgres-language-server/backend-jsonrpc/src/workspace.ts"); let methods = methods(); let mut declarations = Vec::new(); @@ -429,7 +431,9 @@ pub fn generate_bindings(mode: Mode) -> Result<()> { let printed = formatted.print().unwrap(); let code = printed.into_code(); - update(&bindings_path, &code, &mode)?; + // Generate for both packages (dual publishing) + update(&bindings_path_postgrestools, &code, &mode)?; + update(&bindings_path_postgres_language_server, &code, &mode)?; Ok(()) } diff --git a/xtask/codegen/src/generate_configuration.rs b/xtask/codegen/src/generate_configuration.rs index 0ec8bb795..741fc8f06 100644 --- a/xtask/codegen/src/generate_configuration.rs +++ b/xtask/codegen/src/generate_configuration.rs @@ -311,7 +311,7 @@ fn generate_for_groups( #[cfg_attr(feature = "schema", derive(JsonSchema))] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct Rules { - /// It enables the lint rules recommended by Postgres Tools. `true` by default. + /// It enables the lint rules recommended by Postgres Language Server. `true` by default. #[serde(skip_serializing_if = "Option::is_none")] pub recommended: Option,