1
1
//! Types and utilities for working with text, modifying source files, and `Ruff <-> LSP` type conversion.
2
2
3
3
mod document;
4
+ mod notebook;
4
5
mod range;
5
6
mod replacement;
6
7
7
- use std:: collections:: HashMap ;
8
+ use std:: {
9
+ collections:: HashMap ,
10
+ path:: { Display , PathBuf } ,
11
+ } ;
8
12
9
- pub use document :: Document ;
13
+ use anyhow :: anyhow ;
10
14
pub ( crate ) use document:: DocumentVersion ;
15
+ pub use document:: TextDocument ;
11
16
use lsp_types:: PositionEncodingKind ;
17
+ pub ( crate ) use notebook:: NotebookDocument ;
12
18
pub ( crate ) use range:: { RangeExt , ToRangeExt } ;
13
19
pub ( crate ) use replacement:: Replacement ;
20
+ use ruff_linter:: source_kind:: SourceKind ;
21
+ use ruff_source_file:: LineIndex ;
14
22
15
- use crate :: session:: ResolvedClientCapabilities ;
23
+ use crate :: {
24
+ fix:: Fixes ,
25
+ session:: { DocumentQuery , ResolvedClientCapabilities } ,
26
+ } ;
16
27
17
28
/// A convenient enumeration for supported text encodings. Can be converted to [`lsp_types::PositionEncodingKind`].
18
29
// Please maintain the order from least to greatest priority for the derived `Ord` impl.
@@ -29,6 +40,108 @@ pub enum PositionEncoding {
29
40
UTF8 ,
30
41
}
31
42
43
+ /// A wrapper for a document. Can be either a text document (`.py`)
44
+ /// or a notebook document (`.ipynb`).
45
+ #[ derive( Clone ) ]
46
+ pub ( crate ) enum Document {
47
+ Text ( TextDocument ) ,
48
+ Notebook ( NotebookDocument ) ,
49
+ }
50
+
51
+ #[ derive( Clone , Debug ) ]
52
+ pub ( crate ) enum DocumentKey {
53
+ File ( PathBuf ) ,
54
+ Cell ( lsp_types:: Url ) ,
55
+ }
56
+
57
+ impl Document {
58
+ pub ( crate ) fn version ( & self ) -> DocumentVersion {
59
+ match self {
60
+ Self :: Notebook ( notebook) => notebook. version ( ) ,
61
+ Self :: Text ( py) => py. version ( ) ,
62
+ }
63
+ }
64
+
65
+ pub ( crate ) fn make_source_kind ( & self ) -> SourceKind {
66
+ match self {
67
+ Self :: Notebook ( notebook) => {
68
+ let notebook = SourceKind :: IpyNotebook ( notebook. make_ruff_notebook ( ) ) ;
69
+ tracing:: info!( "{notebook:?}" ) ;
70
+ notebook
71
+ }
72
+ Self :: Text ( text) => SourceKind :: Python ( text. contents ( ) . to_string ( ) ) ,
73
+ }
74
+ }
75
+
76
+ pub ( crate ) fn as_notebook ( & self ) -> Option < & NotebookDocument > {
77
+ match self {
78
+ Self :: Notebook ( notebook) => Some ( & notebook) ,
79
+ Self :: Text ( _) => None ,
80
+ }
81
+ }
82
+
83
+ pub ( crate ) fn as_text ( & self ) -> Option < & TextDocument > {
84
+ match self {
85
+ Self :: Text ( py) => Some ( & py) ,
86
+ Self :: Notebook ( _) => None ,
87
+ }
88
+ }
89
+
90
+ pub ( crate ) fn as_notebook_mut ( & mut self ) -> Option < & mut NotebookDocument > {
91
+ match self {
92
+ Self :: Notebook ( ref mut notebook) => Some ( notebook) ,
93
+ Self :: Text ( _) => None ,
94
+ }
95
+ }
96
+
97
+ pub ( crate ) fn as_text_mut ( & mut self ) -> Option < & mut TextDocument > {
98
+ match self {
99
+ Self :: Notebook ( _) => None ,
100
+ Self :: Text ( ref mut py) => Some ( py) ,
101
+ }
102
+ }
103
+
104
+ pub ( crate ) fn as_notebook_cell ( & self , uri : & lsp_types:: Url ) -> Option < & TextDocument > {
105
+ self . as_notebook ( ) ?. cell_document_by_uri ( uri)
106
+ }
107
+
108
+ pub ( crate ) fn as_notebook_cell_mut (
109
+ & mut self ,
110
+ uri : & lsp_types:: Url ,
111
+ ) -> Option < & mut TextDocument > {
112
+ self . as_notebook_mut ( ) ?. cell_document_by_uri_mut ( uri)
113
+ }
114
+ }
115
+
116
+ impl DocumentKey {
117
+ pub ( crate ) fn from_url ( url : & lsp_types:: Url ) -> Self {
118
+ if url. scheme ( ) != "file" {
119
+ return Self :: Cell ( url. clone ( ) ) ;
120
+ }
121
+ url. to_file_path ( )
122
+ . map ( Self :: File )
123
+ . unwrap_or_else ( |_| Self :: Cell ( url. clone ( ) ) )
124
+ }
125
+
126
+ pub ( crate ) fn to_url ( self ) -> lsp_types:: Url {
127
+ match self {
128
+ Self :: Cell ( url) => url,
129
+ Self :: File ( path) => {
130
+ lsp_types:: Url :: from_file_path ( path) . expect ( "path should convert to file URL" )
131
+ }
132
+ }
133
+ }
134
+ }
135
+
136
+ impl std:: fmt:: Display for DocumentKey {
137
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
138
+ match self {
139
+ Self :: Cell ( url) => url. fmt ( f) ,
140
+ Self :: File ( path) => path. display ( ) . fmt ( f) ,
141
+ }
142
+ }
143
+ }
144
+
32
145
/// Tracks multi-document edits to eventually merge into a `WorkspaceEdit`.
33
146
/// Compatible with clients that don't support `workspace.workspaceEdit.documentChanges`.
34
147
#[ derive( Debug ) ]
@@ -72,6 +185,26 @@ impl WorkspaceEditTracker {
72
185
}
73
186
}
74
187
188
+ pub ( crate ) fn set_fixes_for_document (
189
+ & mut self ,
190
+ document : & DocumentQuery ,
191
+ fixes : Fixes ,
192
+ ) -> crate :: Result < ( ) > {
193
+ for ( cell, edits) in fixes. into_iter ( ) {
194
+ let uri = if let Some ( notebook) = document. as_notebook ( ) {
195
+ notebook
196
+ . cell_uri_by_index ( cell)
197
+ . cloned ( )
198
+ . ok_or_else ( || anyhow ! ( "cell index {cell} does not exist" ) ) ?
199
+ } else {
200
+ document. key ( ) . clone ( ) . to_url ( )
201
+ } ;
202
+
203
+ self . set_edits_for_document ( uri, document. version ( ) , edits) ?;
204
+ }
205
+ Ok ( ( ) )
206
+ }
207
+
75
208
/// Sets the edits made to a specific document. This should only be called
76
209
/// once for each document `uri`, and will fail if this is called for the same `uri`
77
210
/// multiple times.
0 commit comments