Skip to content

Commit c8a6082

Browse files
give it a spin
1 parent cf61598 commit c8a6082

File tree

3 files changed

+64
-63
lines changed

3 files changed

+64
-63
lines changed

crates/pgt_workspace/src/features/completions.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
use itertools::Itertools;
12
use pgt_completions::CompletionItem;
23
use pgt_fs::PgTPath;
3-
use pgt_text_size::TextSize;
4+
use pgt_text_size::{TextRange, TextSize};
5+
6+
use crate::workspace::{Document, Statement, StatementId};
47

58
#[derive(Debug, serde::Serialize, serde::Deserialize)]
69
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
@@ -24,3 +27,56 @@ impl IntoIterator for CompletionsResult {
2427
self.items.into_iter()
2528
}
2629
}
30+
31+
pub(crate) fn get_statement_for_completions<'a>(
32+
doc: &'a Document,
33+
position: TextSize,
34+
) -> Option<(Statement, &'a TextRange, &'a str)> {
35+
let count = doc.statement_count();
36+
// no arms no cookies
37+
if count == 0 {
38+
return None;
39+
}
40+
41+
/*
42+
* We allow an offset of two for the statement:
43+
*
44+
* select * from | <-- we want to suggest items for the next token.
45+
*
46+
* However, if the current statement is terminated by a semicolon, we don't apply any
47+
* offset.
48+
*
49+
* select * from users; | <-- no autocompletions here.
50+
*/
51+
let matches_expanding_range = |stmt_id: StatementId, range: &TextRange, position: TextSize| {
52+
let measuring_range = if doc.is_terminated_by_semicolon(stmt_id).unwrap() {
53+
*range
54+
} else {
55+
range.checked_expand_end(2.into()).unwrap_or(*range)
56+
};
57+
measuring_range.contains(position)
58+
};
59+
60+
if count == 1 {
61+
let (stmt, range, txt) = doc.iter_statements_with_text_and_range().next().unwrap();
62+
if matches_expanding_range(stmt.id, range, position) {
63+
Some((stmt, range, txt))
64+
} else {
65+
None
66+
}
67+
} else {
68+
/*
69+
* If we have multiple statements, we want to make sure that we do not overlap
70+
* with the next one.
71+
*
72+
* select 1 |select 1;
73+
*/
74+
let mut stmts = doc.iter_statements_with_text_and_range().tuple_windows();
75+
stmts
76+
.find(|((current_stmt, rcurrent, _), (_, rnext, _))| {
77+
let overlaps_next = rnext.contains(position);
78+
matches_expanding_range(current_stmt.id, rcurrent, position) && !overlaps_next
79+
})
80+
.map(|t| t.0)
81+
}
82+
}

crates/pgt_workspace/src/workspace.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::{
2121
mod client;
2222
mod server;
2323

24-
pub(crate) use server::StatementId;
24+
pub(crate) use server::document::{Document, Statement, StatementId};
2525

2626
#[derive(Debug, serde::Serialize, serde::Deserialize)]
2727
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]

crates/pgt_workspace/src/workspace/server.rs

Lines changed: 6 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,13 @@ use async_helper::run_async;
55
use change::StatementChange;
66
use dashmap::DashMap;
77
use db_connection::DbConnection;
8-
pub(crate) use document::StatementId;
98
use document::{Document, Statement};
109
use futures::{StreamExt, stream};
11-
use itertools::Itertools;
1210
use pg_query::PgQueryStore;
1311
use pgt_analyse::{AnalyserOptions, AnalysisFilter};
1412
use pgt_analyser::{Analyser, AnalyserConfig, AnalyserContext};
1513
use pgt_diagnostics::{Diagnostic, DiagnosticExt, Severity, serde::Diagnostic as SDiagnostic};
1614
use pgt_fs::{ConfigName, PgTPath};
17-
use pgt_text_size::{TextRange, TextSize};
1815
use pgt_typecheck::TypecheckParams;
1916
use schema_cache_manager::SchemaCacheManager;
2017
use sqlx::Executor;
@@ -29,7 +26,7 @@ use crate::{
2926
self, CodeAction, CodeActionKind, CodeActionsResult, CommandAction,
3027
CommandActionCategory, ExecuteStatementParams, ExecuteStatementResult,
3128
},
32-
completions::{CompletionsResult, GetCompletionsParams},
29+
completions::{self, CompletionsResult, GetCompletionsParams},
3330
diagnostics::{PullDiagnosticsParams, PullDiagnosticsResult},
3431
},
3532
settings::{Settings, SettingsHandle, SettingsHandleMut},
@@ -44,7 +41,7 @@ mod analyser;
4441
mod async_helper;
4542
mod change;
4643
mod db_connection;
47-
mod document;
44+
pub(crate) mod document;
4845
mod migration;
4946
mod pg_query;
5047
mod schema_cache_manager;
@@ -540,64 +537,12 @@ impl Workspace for WorkspaceServer {
540537
.get(&params.path)
541538
.ok_or(WorkspaceError::not_found())?;
542539

543-
let count = doc.statement_count();
544-
// no arms no cookies
545-
if count == 0 {
546-
return Ok(CompletionsResult::default());
547-
}
548-
549-
/*
550-
* We allow an offset of two for the statement:
551-
*
552-
* select * from | <-- we want to suggest items for the next token.
553-
*
554-
* However, if the current statement is terminated by a semicolon, we don't apply any
555-
* offset.
556-
*
557-
* select * from users; | <-- no autocompletions here.
558-
*/
559-
let matches_expanding_range =
560-
|stmt_id: StatementId, range: &TextRange, position: TextSize| {
561-
let measuring_range = if doc.is_terminated_by_semicolon(stmt_id).unwrap() {
562-
*range
563-
} else {
564-
range.checked_expand_end(2.into()).unwrap_or(*range)
565-
};
566-
measuring_range.contains(position)
540+
let (statement, stmt_range, text) =
541+
match completions::get_statement_for_completions(&doc, params.position) {
542+
None => return Ok(CompletionsResult::default()),
543+
Some(s) => s,
567544
};
568545

569-
let maybe_statement = if count == 1 {
570-
let (stmt, range, txt) = doc.iter_statements_with_text_and_range().next().unwrap();
571-
if matches_expanding_range(stmt.id, range, params.position) {
572-
Some((stmt, range, txt))
573-
} else {
574-
None
575-
}
576-
} else {
577-
/*
578-
* If we have multiple statements, we want to make sure that we do not overlap
579-
* with the next one.
580-
*
581-
* select 1 |select 1;
582-
*/
583-
let mut stmts = doc.iter_statements_with_text_and_range().tuple_windows();
584-
stmts
585-
.find(|((current_stmt, rcurrent, _), (_, rnext, _))| {
586-
let overlaps_next = rnext.contains(params.position);
587-
matches_expanding_range(current_stmt.id, &rcurrent, params.position)
588-
&& !overlaps_next
589-
})
590-
.map(|t| t.0)
591-
};
592-
593-
let (statement, stmt_range, text) = match maybe_statement {
594-
Some(it) => it,
595-
None => {
596-
tracing::debug!("No matching statement found for completion.");
597-
return Ok(CompletionsResult::default());
598-
}
599-
};
600-
601546
// `offset` is the position in the document,
602547
// but we need the position within the *statement*.
603548
let position = params.position - stmt_range.start();

0 commit comments

Comments
 (0)