Skip to content

Commit 884dba1

Browse files
committed
Address some suggestions
1 parent efb08ec commit 884dba1

File tree

10 files changed

+80
-74
lines changed

10 files changed

+80
-74
lines changed

crates/ruff_notebook/src/notebook.rs

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -85,23 +85,6 @@ impl Notebook {
8585
Self::from_reader(Cursor::new(source_code))
8686
}
8787

88-
/// Generate a pseudo-representation of a notebook that can be used
89-
/// for linting by the language server. As this is not generated directly from the raw JSON
90-
/// of a notebook file, writing this back into the file system is a bad idea.
91-
pub fn from_cells(
92-
cells: Vec<Cell>,
93-
metadata: crate::RawNotebookMetadata,
94-
) -> Result<Self, NotebookError> {
95-
let raw_notebook = RawNotebook {
96-
cells,
97-
metadata,
98-
nbformat: 4,
99-
nbformat_minor: 5,
100-
};
101-
102-
Self::from_raw(raw_notebook, false)
103-
}
104-
10588
/// Read a Jupyter Notebook from a [`Read`] implementer.
10689
///
10790
/// See also the black implementation
@@ -130,10 +113,10 @@ impl Notebook {
130113
});
131114
}
132115
};
133-
Self::from_raw(raw_notebook, trailing_newline)
116+
Self::from_raw_notebook(raw_notebook, trailing_newline)
134117
}
135118

136-
fn from_raw(
119+
pub fn from_raw_notebook(
137120
mut raw_notebook: RawNotebook,
138121
trailing_newline: bool,
139122
) -> Result<Self, NotebookError> {

crates/ruff_server/src/edit.rs

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ mod notebook;
55
mod range;
66
mod replacement;
77

8-
use std::{collections::HashMap, ffi::OsStr, path::PathBuf};
8+
use std::{collections::HashMap, path::PathBuf};
99

1010
pub(crate) use document::DocumentVersion;
1111
pub use document::TextDocument;
1212
use lsp_types::PositionEncodingKind;
1313
pub(crate) use notebook::NotebookDocument;
14-
pub(crate) use range::{RangeExt, ToRangeExt};
14+
pub(crate) use range::{NotebookRange, RangeExt, ToRangeExt};
1515
pub(crate) use replacement::Replacement;
1616

1717
use crate::{fix::Fixes, session::ResolvedClientCapabilities};
@@ -41,26 +41,6 @@ pub(crate) enum DocumentKey {
4141
}
4242

4343
impl DocumentKey {
44-
/// Creates a document key from a URL provided in an LSP request.
45-
pub(crate) fn from_url(url: &lsp_types::Url) -> Self {
46-
if url.scheme() != "file" {
47-
return Self::NotebookCell(url.clone());
48-
}
49-
let Some(path) = url.to_file_path().ok() else {
50-
return Self::NotebookCell(url.clone());
51-
};
52-
53-
// figure out whether this is a notebook or a text document
54-
if path.extension() == Some(OsStr::new("ipynb")) {
55-
Self::Notebook(path)
56-
} else {
57-
// Until we support additional document types, we need to confirm
58-
// that any non-notebook file is a Python file
59-
debug_assert_eq!(path.extension(), Some(OsStr::new("py")));
60-
Self::Text(path)
61-
}
62-
}
63-
6444
/// Converts the key back into its original URL.
6545
pub(crate) fn into_url(self) -> lsp_types::Url {
6646
match self {

crates/ruff_server/src/edit/notebook.rs

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use crate::{PositionEncoding, TextDocument};
88

99
use super::DocumentVersion;
1010

11+
pub(super) type CellId = usize;
12+
1113
/// The state of a notebook document in the server. Contains an array of cells whose
1214
/// contents are internally represented by [`TextDocument`]s.
1315
#[derive(Clone, Debug)]
@@ -16,9 +18,10 @@ pub(crate) struct NotebookDocument {
1618
metadata: ruff_notebook::RawNotebookMetadata,
1719
version: DocumentVersion,
1820
// Used to quickly find the index of a cell for a given URL.
19-
cell_index: FxHashMap<lsp_types::Url, usize>,
21+
cell_index: FxHashMap<lsp_types::Url, CellId>,
2022
}
2123

24+
/// A single cell within a notebook, which has text contents represented as a `TextDocument`.
2225
#[derive(Clone, Debug)]
2326
struct NotebookCell {
2427
url: Url,
@@ -82,9 +85,15 @@ impl NotebookDocument {
8285
}
8386
})
8487
.collect();
88+
let raw_notebook = ruff_notebook::RawNotebook {
89+
cells,
90+
metadata: self.metadata.clone(),
91+
nbformat: 4,
92+
nbformat_minor: 5,
93+
};
8594

86-
ruff_notebook::Notebook::from_cells(cells, self.metadata.clone())
87-
.expect("notebook should convert successfully")
95+
ruff_notebook::Notebook::from_raw_notebook(raw_notebook, false)
96+
.unwrap_or_else(|err| panic!("Server notebook document could not be converted to Ruff's notebook document format: {err}"))
8897
}
8998

9099
pub(crate) fn update(
@@ -103,18 +112,22 @@ impl NotebookDocument {
103112
}) = cells
104113
{
105114
if let Some(structure) = structure {
106-
let start = usize::try_from(structure.array.start).unwrap();
107-
let delete = usize::try_from(structure.array.delete_count).unwrap();
115+
let start = structure.array.start as usize;
116+
let delete = structure.array.delete_count as usize;
108117
if delete > 0 {
109-
self.cells.drain(start..start + delete);
118+
for cell in self.cells.drain(start..start + delete) {
119+
self.cell_index.remove(&cell.url);
120+
}
110121
}
111122
for cell in structure.array.cells.into_iter().flatten().rev() {
112123
self.cells
113124
.insert(start, NotebookCell::new(cell, String::new(), version));
114125
}
115126

116-
// the array has been updated - rebuild the cell index
117-
self.rebuild_cell_index();
127+
// register any new cells in the index and update existing ones that came after the insertion
128+
for (i, cell) in self.cells.iter().enumerate().skip(start) {
129+
self.cell_index.insert(cell.url.clone(), i);
130+
}
118131
}
119132
if let Some(cell_data) = data {
120133
for cell in cell_data {
@@ -138,20 +151,24 @@ impl NotebookDocument {
138151
Ok(())
139152
}
140153

154+
/// Get the current version of the notebook document.
141155
pub(crate) fn version(&self) -> DocumentVersion {
142156
self.version
143157
}
144158

145-
pub(crate) fn cell_uri_by_index(&self, index: usize) -> Option<&lsp_types::Url> {
159+
/// Get the URI for a cell by its index within the cell array.
160+
pub(crate) fn cell_uri_by_index(&self, index: CellId) -> Option<&lsp_types::Url> {
146161
self.cells.get(index).map(|cell| &cell.url)
147162
}
148163

164+
/// Get the text document representing the contents of a cell by the cell URI.
149165
pub(crate) fn cell_document_by_uri(&self, uri: &lsp_types::Url) -> Option<&TextDocument> {
150166
self.cells
151167
.get(*self.cell_index.get(uri)?)
152168
.map(|cell| &cell.document)
153169
}
154170

171+
/// Returns a list of cell URIs in the order they appear in the array.
155172
pub(crate) fn urls(&self) -> impl Iterator<Item = &lsp_types::Url> {
156173
self.cells.iter().map(|cell| &cell.url)
157174
}
@@ -160,11 +177,7 @@ impl NotebookDocument {
160177
self.cells.get_mut(*self.cell_index.get(uri)?)
161178
}
162179

163-
fn rebuild_cell_index(&mut self) {
164-
self.cell_index = Self::make_cell_index(&self.cells);
165-
}
166-
167-
fn make_cell_index(cells: &[NotebookCell]) -> FxHashMap<lsp_types::Url, usize> {
180+
fn make_cell_index(cells: &[NotebookCell]) -> FxHashMap<lsp_types::Url, CellId> {
168181
let mut index =
169182
HashMap::with_capacity_and_hasher(cells.len(), BuildHasherDefault::default());
170183
for (i, cell) in cells.iter().enumerate() {

crates/ruff_server/src/edit/range.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
use super::notebook;
12
use super::PositionEncoding;
23
use lsp_types as types;
34
use ruff_notebook::NotebookIndex;
45
use ruff_source_file::OneIndexed;
56
use ruff_source_file::{LineIndex, SourceLocation};
67
use ruff_text_size::{TextRange, TextSize};
78

9+
pub(crate) struct NotebookRange {
10+
pub(crate) cell: notebook::CellId,
11+
pub(crate) range: types::Range,
12+
}
13+
814
pub(crate) trait RangeExt {
915
fn to_text_range(&self, text: &str, index: &LineIndex, encoding: PositionEncoding)
1016
-> TextRange;
@@ -18,7 +24,7 @@ pub(crate) trait ToRangeExt {
1824
source_index: &LineIndex,
1925
notebook_index: &NotebookIndex,
2026
encoding: PositionEncoding,
21-
) -> (usize, types::Range);
27+
) -> NotebookRange;
2228
}
2329

2430
fn u32_index_to_usize(index: u32) -> usize {
@@ -112,7 +118,7 @@ impl ToRangeExt for TextRange {
112118
source_index: &LineIndex,
113119
notebook_index: &NotebookIndex,
114120
encoding: PositionEncoding,
115-
) -> (usize, types::Range) {
121+
) -> NotebookRange {
116122
let start = offset_to_source_location(self.start(), text, source_index, encoding);
117123
let mut end = offset_to_source_location(self.end(), text, source_index, encoding);
118124
let cell = notebook_index.cell(start.row);
@@ -131,10 +137,10 @@ impl ToRangeExt for TextRange {
131137
let start = source_location_to_position(&notebook_index.translate_location(&start));
132138
let end = source_location_to_position(&notebook_index.translate_location(&end));
133139

134-
(
135-
cell.map(OneIndexed::to_zero_indexed).unwrap_or_default(),
136-
types::Range { start, end },
137-
)
140+
NotebookRange {
141+
cell: cell.map(OneIndexed::to_zero_indexed).unwrap_or_default(),
142+
range: types::Range { start, end },
143+
}
138144
}
139145
}
140146

crates/ruff_server/src/lint.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ use ruff_text_size::Ranged;
1919
use rustc_hash::FxHashMap;
2020
use serde::{Deserialize, Serialize};
2121

22-
use crate::{edit::ToRangeExt, session::DocumentQuery, PositionEncoding, DIAGNOSTIC_NAME};
22+
use crate::{
23+
edit::{NotebookRange, ToRangeExt},
24+
session::DocumentQuery,
25+
PositionEncoding, DIAGNOSTIC_NAME,
26+
};
2327

2428
/// This is serialized on the diagnostic `data` field.
2529
#[derive(Serialize, Deserialize, Debug, Clone)]
@@ -214,7 +218,7 @@ fn to_lsp_diagnostic(
214218
notebook_index,
215219
encoding,
216220
)
217-
.1
221+
.range
218222
} else {
219223
edit.range()
220224
.to_range(source_kind.source_code(), index, encoding)
@@ -234,7 +238,7 @@ fn to_lsp_diagnostic(
234238
notebook_index,
235239
encoding,
236240
)
237-
.1
241+
.range
238242
} else {
239243
noqa_edit
240244
.range()
@@ -258,7 +262,7 @@ fn to_lsp_diagnostic(
258262
let cell: usize;
259263

260264
if let Some(notebook_index) = source_kind.as_ipy_notebook().map(Notebook::index) {
261-
(cell, range) = diagnostic_range.to_notebook_range(
265+
NotebookRange { cell, range } = diagnostic_range.to_notebook_range(
262266
source_kind.source_code(),
263267
index,
264268
notebook_index,

crates/ruff_server/src/server/api/notifications/did_change.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::edit::DocumentKey;
21
use crate::server::api::diagnostics::publish_diagnostics_for_document;
32
use crate::server::api::LSPResult;
43
use crate::server::client::{Notifier, Requester};
@@ -27,7 +26,7 @@ impl super::SyncNotificationHandler for DidChange {
2726
content_changes,
2827
}: types::DidChangeTextDocumentParams,
2928
) -> Result<()> {
30-
let key = DocumentKey::from_url(&uri);
29+
let key = session.key_from_url(&uri);
3130

3231
session
3332
.update_text_document(&key, content_changes, new_version)

crates/ruff_server/src/server/api/notifications/did_change_notebook.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::edit::DocumentKey;
21
use crate::server::api::diagnostics::publish_diagnostics_for_document;
32
use crate::server::api::LSPResult;
43
use crate::server::client::{Notifier, Requester};
@@ -24,7 +23,7 @@ impl super::SyncNotificationHandler for DidChangeNotebook {
2423
change: types::NotebookDocumentChangeEvent { cells, metadata },
2524
}: types::DidChangeNotebookDocumentParams,
2625
) -> Result<()> {
27-
let key = DocumentKey::from_url(&uri);
26+
let key = session.key_from_url(&uri);
2827
session
2928
.update_notebook_document(&key, cells, metadata, version)
3029
.with_failure_code(ErrorCode::InternalError)?;

crates/ruff_server/src/server/api/notifications/did_close_notebook.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::edit::DocumentKey;
21
use crate::server::api::LSPResult;
32
use crate::server::client::{Notifier, Requester};
43
use crate::server::Result;
@@ -23,7 +22,7 @@ impl super::SyncNotificationHandler for DidCloseNotebook {
2322
..
2423
}: types::DidCloseNotebookDocumentParams,
2524
) -> Result<()> {
26-
let key = DocumentKey::from_url(&uri);
25+
let key = session.key_from_url(&uri);
2726

2827
session
2928
.close_document(&key)

crates/ruff_server/src/session.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,13 @@ impl Session {
5454
}
5555
}
5656

57+
pub(crate) fn key_from_url(&self, url: &lsp_types::Url) -> DocumentKey {
58+
self.index.key_from_url(url)
59+
}
60+
5761
/// Creates a document snapshot with the URL referencing the document to snapshot.
5862
pub(crate) fn take_snapshot(&self, url: &Url) -> Option<DocumentSnapshot> {
59-
let key = DocumentKey::from_url(url);
63+
let key = self.key_from_url(url);
6064
Some(DocumentSnapshot {
6165
resolved_client_capabilities: self.resolved_client_capabilities.clone(),
6266
client_settings: self.index.client_settings(&key, &self.global_settings),
@@ -67,7 +71,7 @@ impl Session {
6771

6872
/// Updates a text document at the associated `key`.
6973
///
70-
/// The document key must point to a text document.
74+
/// The document key must point to a text document, or this will throw an error.
7175
pub(crate) fn update_text_document(
7276
&mut self,
7377
key: &DocumentKey,
@@ -83,7 +87,8 @@ impl Session {
8387
/// Updates a notebook document at the associated `key` with potentially new
8488
/// cell, metadata, and version values.
8589
///
86-
/// The document key must point to a notebook document or cell.
90+
/// The document key must point to a notebook document or cell, or this will
91+
/// throw an error.
8792
pub(crate) fn update_notebook_document(
8893
&mut self,
8994
key: &DocumentKey,

crates/ruff_server/src/session/index.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,24 @@ impl Index {
116116
Ok(())
117117
}
118118

119+
pub(super) fn key_from_url(&self, url: &lsp_types::Url) -> DocumentKey {
120+
if self.notebook_cells.contains_key(url) {
121+
return DocumentKey::NotebookCell(url.clone());
122+
}
123+
let path = url
124+
.to_file_path()
125+
.expect("non-notebook cell URL should be a valid path");
126+
match path
127+
.extension()
128+
.unwrap_or_default()
129+
.to_str()
130+
.unwrap_or_default()
131+
{
132+
"ipynb" => DocumentKey::Notebook(path),
133+
_ => DocumentKey::Text(path),
134+
}
135+
}
136+
119137
pub(super) fn update_notebook_document(
120138
&mut self,
121139
key: &DocumentKey,

0 commit comments

Comments
 (0)